From 2f6c5963c5076c246de1591ae41b92b26ab00932 Mon Sep 17 00:00:00 2001 From: Ponkhy Date: Wed, 1 Sep 2021 17:09:32 +0200 Subject: [PATCH 01/11] Added import and export function --- server/server.js | 74 ++++++++++++++++++++++++++++++++++++++++++ src/mixins/socket.js | 3 ++ src/pages/Settings.vue | 54 ++++++++++++++++++++++++++++++ 3 files changed, 131 insertions(+) diff --git a/server/server.js b/server/server.js index d4fe668b3..8485c3841 100644 --- a/server/server.js +++ b/server/server.js @@ -552,6 +552,80 @@ let indexHTML = fs.readFileSync("./dist/index.html").toString(); } }); + socket.on("uploadBackup", async (uploadedJSON, callback) => { + try { + checkLogin(socket) + + console.log(`Import Backup User ID: ${socket.userID}`) + + let notificationList = uploadedJSON[0]; + let monitorList = uploadedJSON[1]; + + monitorList = JSON.stringify(monitorList); + monitorList = JSON.parse(monitorList); + monitorList = Object.values(monitorList); + + if (notificationList.length >= 1) { + for (let i = 0; i < notificationList.length; i++) { + let notification = JSON.parse(notificationList[i].config); + await Notification.save(notification, null, socket.userID) + } + } + + if (monitorList.length >= 1) { + for (let i = 0; i < monitorList.length; i++) { + let monitor = { + name: monitorList[i].name, + type: monitorList[i].type, + url: monitorList[i].url, + interval: monitorList[i].interval, + hostname: monitorList[i].hostname, + maxretries: monitorList[i].maxretries, + port: monitorList[i].port, + keyword: monitorList[i].keyword, + ignoreTls: monitorList[i].ignoreTls, + upsideDown: monitorList[i].upsideDown, + maxredirects: monitorList[i].maxredirects, + accepted_statuscodes: monitorList[i].accepted_statuscodes, + dns_resolve_type: monitorList[i].dns_resolve_type, + dns_resolve_server: monitorList[i].dns_resolve_server, + notificationIDList: {}, + } + + let bean = R.dispense("monitor") + + let notificationIDList = monitor.notificationIDList; + delete monitor.notificationIDList; + + monitor.accepted_statuscodes_json = JSON.stringify(monitor.accepted_statuscodes); + delete monitor.accepted_statuscodes; + + bean.import(monitor) + bean.user_id = socket.userID + await R.store(bean) + + await updateMonitorNotification(bean.id, notificationIDList) + + await startMonitor(socket.userID, bean.id); + } + + await sendNotificationList(socket) + await sendMonitorList(socket); + } + + callback({ + ok: true, + msg: "Backup successfully restored.", + }); + + } catch (e) { + callback({ + ok: false, + msg: e.message, + }); + } + }); + debug("added all socket handlers") // *************************** diff --git a/src/mixins/socket.js b/src/mixins/socket.js index 454422e94..867abfd01 100644 --- a/src/mixins/socket.js +++ b/src/mixins/socket.js @@ -254,6 +254,9 @@ export default { this.importantHeartbeatList = {} }, + uploadBackup(uploadedJSON, callback) { + socket.emit("uploadBackup", uploadedJSON, callback) + }, }, computed: { diff --git a/src/pages/Settings.vue b/src/pages/Settings.vue index d71ec109b..c15b1410a 100644 --- a/src/pages/Settings.vue +++ b/src/pages/Settings.vue @@ -120,6 +120,14 @@ +

{{ $t("Import/Export Backup") }}

+ +
+ + + +
+

{{ $t("Advanced") }}

@@ -293,6 +301,41 @@ export default { this.$root.storage().removeItem("token"); }, + downloadBackup() { + let time = dayjs().format("YYYY_MM_DD-hh_mm_ss"); + let fileName = `Uptime_Kuma_Backup_${time}.json`; + let exportData = { + notificationList: this.$root.notificationList, + monitorList: this.$root.monitorList, + } + exportData = JSON.stringify(exportData); + let downloadItem = document.createElement("a"); + downloadItem.setAttribute("href", `data:application/json;charset=utf-8, ${exportData}`); + downloadItem.setAttribute("download", fileName); + downloadItem.click(); + }, + + importBackup() { + let uploadItem = document.getElementById("importBackup").files; + if (uploadItem.length <= 0) { + return false; + } + + let fileReader = new FileReader(); + fileReader.readAsText(uploadItem.item(0)); + + fileReader.onload = item => { + let resultParse = JSON.parse(item.target.result); + let result = Object.values(resultParse); + this.$root.uploadBackup(result, (res) => { + if (res.ok) { + toast.success(res.msg); + } else { + toast.error(res.msg); + } + }) + } + }, }, } @@ -321,6 +364,17 @@ export default { .btn-check:hover + .btn-outline-primary { color: #000; } + + input[type=file]::file-selector-button { + color: $primary; + background-color: $dark-bg; + } + + //Does not work for some reason + input[type=file]::file-selector-button:hover { + color: $dark-font-color; + background-color: $primary; + } } footer { From 8e1e4b9204f0799d8d1504c93eb0bfbd8daceea5 Mon Sep 17 00:00:00 2001 From: LouisLam Date: Thu, 2 Sep 2021 01:51:51 +0800 Subject: [PATCH 02/11] override file-selector-button hover color --- src/pages/Settings.vue | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/pages/Settings.vue b/src/pages/Settings.vue index c15b1410a..881b7aa5a 100644 --- a/src/pages/Settings.vue +++ b/src/pages/Settings.vue @@ -365,15 +365,16 @@ export default { color: #000; } - input[type=file]::file-selector-button { - color: $primary; - background-color: $dark-bg; - } + #importBackup { + &::file-selector-button { + color: $primary; + background-color: $dark-bg; + } - //Does not work for some reason - input[type=file]::file-selector-button:hover { - color: $dark-font-color; - background-color: $primary; + &:hover:not(:disabled):not([readonly])::file-selector-button { + color: $dark-font-color2; + background-color: $primary; + } } } From c13cc62d3d06f931b755250536e97ffebb5d2d74 Mon Sep 17 00:00:00 2001 From: Ponkhy Date: Wed, 1 Sep 2021 21:32:33 +0200 Subject: [PATCH 03/11] Update server/server.js Co-authored-by: Adam Stachowicz --- server/server.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/server.js b/server/server.js index 8485c3841..ec8aad6a9 100644 --- a/server/server.js +++ b/server/server.js @@ -556,7 +556,7 @@ let indexHTML = fs.readFileSync("./dist/index.html").toString(); try { checkLogin(socket) - console.log(`Import Backup User ID: ${socket.userID}`) + console.log(`Importing Backup, User ID: ${socket.userID}`) let notificationList = uploadedJSON[0]; let monitorList = uploadedJSON[1]; From 2dd392e609757fd3b0bec7841ac7d4c97ef96afa Mon Sep 17 00:00:00 2001 From: Ponkhy Date: Thu, 2 Sep 2021 10:15:25 +0200 Subject: [PATCH 04/11] Added uptime kuma version to backup file --- server/server.js | 6 +++--- src/pages/Settings.vue | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/server/server.js b/server/server.js index ec8aad6a9..a795e2187 100644 --- a/server/server.js +++ b/server/server.js @@ -556,10 +556,10 @@ let indexHTML = fs.readFileSync("./dist/index.html").toString(); try { checkLogin(socket) - console.log(`Importing Backup, User ID: ${socket.userID}`) + console.log(`Importing Backup, User ID: ${socket.userID}, Version: ${uploadedJSON[0]}`) - let notificationList = uploadedJSON[0]; - let monitorList = uploadedJSON[1]; + let notificationList = uploadedJSON[1]; + let monitorList = uploadedJSON[2]; monitorList = JSON.stringify(monitorList); monitorList = JSON.parse(monitorList); diff --git a/src/pages/Settings.vue b/src/pages/Settings.vue index 881b7aa5a..c82a170c5 100644 --- a/src/pages/Settings.vue +++ b/src/pages/Settings.vue @@ -305,6 +305,7 @@ export default { let time = dayjs().format("YYYY_MM_DD-hh_mm_ss"); let fileName = `Uptime_Kuma_Backup_${time}.json`; let exportData = { + version: this.$root.info.version, notificationList: this.$root.notificationList, monitorList: this.$root.monitorList, } From 7d70c4d8cdff782613c12b4c96a36f878b6e9051 Mon Sep 17 00:00:00 2001 From: Ponkhy Date: Thu, 2 Sep 2021 16:13:31 +0200 Subject: [PATCH 05/11] Code optimizations --- server/server.js | 10 ++++------ src/pages/Settings.vue | 7 +++---- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/server/server.js b/server/server.js index a795e2187..e1f24ae1f 100644 --- a/server/server.js +++ b/server/server.js @@ -556,14 +556,12 @@ let indexHTML = fs.readFileSync("./dist/index.html").toString(); try { checkLogin(socket) - console.log(`Importing Backup, User ID: ${socket.userID}, Version: ${uploadedJSON[0]}`) + let backupData = JSON.parse(uploadedJSON); - let notificationList = uploadedJSON[1]; - let monitorList = uploadedJSON[2]; + console.log(`Importing Backup, User ID: ${socket.userID}, Version: ${backupData.version}`) - monitorList = JSON.stringify(monitorList); - monitorList = JSON.parse(monitorList); - monitorList = Object.values(monitorList); + let notificationList = backupData.notificationList; + let monitorList = backupData.monitorList; if (notificationList.length >= 1) { for (let i = 0; i < notificationList.length; i++) { diff --git a/src/pages/Settings.vue b/src/pages/Settings.vue index c82a170c5..ff6920cba 100644 --- a/src/pages/Settings.vue +++ b/src/pages/Settings.vue @@ -304,10 +304,11 @@ export default { downloadBackup() { let time = dayjs().format("YYYY_MM_DD-hh_mm_ss"); let fileName = `Uptime_Kuma_Backup_${time}.json`; + let monitorList = Object.values(this.$root.monitorList); let exportData = { version: this.$root.info.version, notificationList: this.$root.notificationList, - monitorList: this.$root.monitorList, + monitorList: monitorList, } exportData = JSON.stringify(exportData); let downloadItem = document.createElement("a"); @@ -326,9 +327,7 @@ export default { fileReader.readAsText(uploadItem.item(0)); fileReader.onload = item => { - let resultParse = JSON.parse(item.target.result); - let result = Object.values(resultParse); - this.$root.uploadBackup(result, (res) => { + this.$root.uploadBackup(item.target.result, (res) => { if (res.ok) { toast.success(res.msg); } else { From b98ec0c3d4efa70510538b5bed61c9abe6076db6 Mon Sep 17 00:00:00 2001 From: Ponkhy Date: Sat, 4 Sep 2021 01:26:06 +0200 Subject: [PATCH 06/11] Added i18n keys if necessary for some languages --- src/languages/de-DE.js | 5 ++++- src/languages/en.js | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/languages/de-DE.js b/src/languages/de-DE.js index 7a8cb52a4..0a0411dcb 100644 --- a/src/languages/de-DE.js +++ b/src/languages/de-DE.js @@ -106,5 +106,8 @@ export default { pauseMonitorMsg: "Bist du sicher das du den Monitor pausieren möchtest?", "Create your admin account": "Erstelle dein Admin Konto", "Repeat Password": "Wiederhole das Passwort", - "Resource Record Type": "Resource Record Type" + "Resource Record Type": "Resource Record Type", + "Import/Export Backup": "Import/Export Backup", + "Export": "Export", + "Import": "Import", } diff --git a/src/languages/en.js b/src/languages/en.js index 2781ba819..fbb70d7eb 100644 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -106,5 +106,8 @@ export default { "Resource Record Type": "Resource Record Type", "Last Result": "Last Result", "Create your admin account": "Create your admin account", - "Repeat Password": "Repeat Password" + "Repeat Password": "Repeat Password", + "Import/Export Backup": "Import/Export Backup", + "Export": "Export", + "Import": "Import", } From 1a5ffd4755d85bdefc42ecd0ce563412048140b7 Mon Sep 17 00:00:00 2001 From: LouisLam Date: Wed, 8 Sep 2021 00:46:48 +0800 Subject: [PATCH 07/11] add description for export/import --- src/languages/en.js | 5 ++++- src/pages/Settings.vue | 7 +++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/languages/en.js b/src/languages/en.js index b35892857..8b5d66b82 100644 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -119,5 +119,8 @@ export default { "Clear Data": "Clear Data", Events: "Events", Heartbeats: "Heartbeats", - "Auto Get": "Auto Get" + "Auto Get": "Auto Get", + backupDescription: "You can backup all monitors and all notifications into a JSON file.", + backupDescription2: "PS: History and event data is not included.", + backupDescription3: "Sensitive data such as notification tokens is included in the export file, please keep it carefully.", } diff --git a/src/pages/Settings.vue b/src/pages/Settings.vue index 394e605fe..55de2d541 100644 --- a/src/pages/Settings.vue +++ b/src/pages/Settings.vue @@ -122,12 +122,19 @@

{{ $t("Import/Export Backup") }}

+

+ {{ $t("backupDescription") }}
+ ({{ $t("backupDescription2") }})
+

+
+

{{ $t("backupDescription3") }}

+

{{ $t("Advanced") }}

From f4e885982d0e90ec9329aa3e213383596e23a50d Mon Sep 17 00:00:00 2001 From: Ponkhy Date: Tue, 7 Sep 2021 21:10:47 +0200 Subject: [PATCH 08/11] Added export/import description for de-DE --- src/languages/de-DE.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/languages/de-DE.js b/src/languages/de-DE.js index 45f642aa4..10c55b28f 100644 --- a/src/languages/de-DE.js +++ b/src/languages/de-DE.js @@ -119,5 +119,8 @@ export default { respTime: "Antw. Zeit (ms)", notAvailableShort: "N/A", Create: "Erstellen", - "Auto Get": "Auto Get" + "Auto Get": "Auto Get", + backupDescription: "Es können alle Monitore und alle Benachrichtigungen in einer JSON-Datei gesichert werden.", + backupDescription2: "PS: Verlaufs- und Ereignisdaten sind nicht enthalten.", + backupDescription3: "Sensible Daten wie Benachrichtigungstoken sind in der Exportdatei enthalten, bitte bewahre sie sorgfältig auf.", } From 69a7c4dab4ebbef9048b81a14e47b23ffb4e1ca3 Mon Sep 17 00:00:00 2001 From: Ponkhy Date: Tue, 7 Sep 2021 23:14:44 +0200 Subject: [PATCH 09/11] Improved importBackup handling --- src/languages/de-DE.js | 2 ++ src/languages/en.js | 2 ++ src/pages/Settings.vue | 24 +++++++++++++++++++++--- 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/languages/de-DE.js b/src/languages/de-DE.js index 10c55b28f..e1b1daa5a 100644 --- a/src/languages/de-DE.js +++ b/src/languages/de-DE.js @@ -123,4 +123,6 @@ export default { backupDescription: "Es können alle Monitore und alle Benachrichtigungen in einer JSON-Datei gesichert werden.", backupDescription2: "PS: Verlaufs- und Ereignisdaten sind nicht enthalten.", backupDescription3: "Sensible Daten wie Benachrichtigungstoken sind in der Exportdatei enthalten, bitte bewahre sie sorgfältig auf.", + alertNoFile: "Bitte wähle eine Datei zum importieren aus.", + alertWrongFileType: "Bitte wähle eine JSON Datei aus.", } diff --git a/src/languages/en.js b/src/languages/en.js index 8b5d66b82..7dd7addde 100644 --- a/src/languages/en.js +++ b/src/languages/en.js @@ -123,4 +123,6 @@ export default { backupDescription: "You can backup all monitors and all notifications into a JSON file.", backupDescription2: "PS: History and event data is not included.", backupDescription3: "Sensitive data such as notification tokens is included in the export file, please keep it carefully.", + alertNoFile: "Please select a file to import.", + alertWrongFileType: "Please select a JSON file.", } diff --git a/src/pages/Settings.vue b/src/pages/Settings.vue index 55de2d541..faad4914c 100644 --- a/src/pages/Settings.vue +++ b/src/pages/Settings.vue @@ -129,8 +129,14 @@
- - + + +
+
+ {{ importAlert }}

{{ $t("backupDescription3") }}

@@ -276,6 +282,8 @@ export default { }, loaded: false, + importAlert: null, + processing: false, } }, watch: { @@ -369,9 +377,17 @@ export default { }, importBackup() { + this.processing = true; let uploadItem = document.getElementById("importBackup").files; + if (uploadItem.length <= 0) { - return false; + this.processing = false; + return this.importAlert = this.$t("alertNoFile") + } + + if (uploadItem.item(0).type !== "application/json") { + this.processing = false; + return this.importAlert = this.$t("alertWrongFileType") } let fileReader = new FileReader(); @@ -379,6 +395,8 @@ export default { fileReader.onload = item => { this.$root.uploadBackup(item.target.result, (res) => { + this.processing = false; + if (res.ok) { toast.success(res.msg); } else { From 1ef45629053b150df6d5ccd6851c7934cc28e869 Mon Sep 17 00:00:00 2001 From: Ponkhy Date: Tue, 7 Sep 2021 23:32:25 +0200 Subject: [PATCH 10/11] Paused monitors stay paused after import --- server/server.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/server/server.js b/server/server.js index 31efc9bbb..bfebb89fc 100644 --- a/server/server.js +++ b/server/server.js @@ -645,7 +645,11 @@ let indexHTML = fs.readFileSync("./dist/index.html").toString(); await updateMonitorNotification(bean.id, notificationIDList) - await startMonitor(socket.userID, bean.id); + if (monitorList[i].active == 1) { + await startMonitor(socket.userID, bean.id); + } else { + await pauseMonitor(socket.userID, bean.id); + } } await sendNotificationList(socket) From acf6f1883b829449cd0883185b301f3e599ecb39 Mon Sep 17 00:00:00 2001 From: Ponkhy Date: Wed, 8 Sep 2021 09:02:24 +0200 Subject: [PATCH 11/11] Fixed missing spaces in backup file --- src/pages/Settings.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/Settings.vue b/src/pages/Settings.vue index faad4914c..79b67e523 100644 --- a/src/pages/Settings.vue +++ b/src/pages/Settings.vue @@ -371,7 +371,7 @@ export default { } exportData = JSON.stringify(exportData); let downloadItem = document.createElement("a"); - downloadItem.setAttribute("href", `data:application/json;charset=utf-8, ${exportData}`); + downloadItem.setAttribute("href", "data:application/json;charset=utf-8," + encodeURI(exportData)); downloadItem.setAttribute("download", fileName); downloadItem.click(); },