mirror of
https://github.com/louislam/uptime-kuma.git
synced 2024-11-28 01:04:05 +00:00
Merge pull request #306 from Ponkhy/import-export
Added import and export function
This commit is contained in:
commit
331ae5ec20
5 changed files with 179 additions and 2 deletions
|
@ -593,6 +593,82 @@ let indexHTML = fs.readFileSync("./dist/index.html").toString();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
socket.on("uploadBackup", async (uploadedJSON, callback) => {
|
||||||
|
try {
|
||||||
|
checkLogin(socket)
|
||||||
|
|
||||||
|
let backupData = JSON.parse(uploadedJSON);
|
||||||
|
|
||||||
|
console.log(`Importing Backup, User ID: ${socket.userID}, Version: ${backupData.version}`)
|
||||||
|
|
||||||
|
let notificationList = backupData.notificationList;
|
||||||
|
let monitorList = backupData.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)
|
||||||
|
|
||||||
|
if (monitorList[i].active == 1) {
|
||||||
|
await startMonitor(socket.userID, bean.id);
|
||||||
|
} else {
|
||||||
|
await pauseMonitor(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,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
socket.on("clearEvents", async (monitorID, callback) => {
|
socket.on("clearEvents", async (monitorID, callback) => {
|
||||||
try {
|
try {
|
||||||
checkLogin(socket)
|
checkLogin(socket)
|
||||||
|
|
|
@ -113,11 +113,19 @@ export default {
|
||||||
"Create your admin account": "Erstelle dein Admin Konto",
|
"Create your admin account": "Erstelle dein Admin Konto",
|
||||||
"Repeat Password": "Wiederhole das Passwort",
|
"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",
|
||||||
respTime: "Antw. Zeit (ms)",
|
respTime: "Antw. Zeit (ms)",
|
||||||
notAvailableShort: "N/A",
|
notAvailableShort: "N/A",
|
||||||
"Default enabled": "Standardmäßig aktiviert",
|
"Default enabled": "Standardmäßig aktiviert",
|
||||||
"Also apply to existing monitors": "Auch für alle existierenden Monitore aktivieren",
|
"Also apply to existing monitors": "Auch für alle existierenden Monitore aktivieren",
|
||||||
enableDefaultNotificationDescription: "Für jeden neuen Monitor wird diese Benachrichtigung standardmäßig aktiviert. Die Benachrichtigung kann weiterhin für jeden Monitor separat deaktiviert werden.",
|
enableDefaultNotificationDescription: "Für jeden neuen Monitor wird diese Benachrichtigung standardmäßig aktiviert. Die Benachrichtigung kann weiterhin für jeden Monitor separat deaktiviert werden.",
|
||||||
Create: "Erstellen",
|
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.",
|
||||||
|
alertNoFile: "Bitte wähle eine Datei zum importieren aus.",
|
||||||
|
alertWrongFileType: "Bitte wähle eine JSON Datei aus.",
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,6 +111,9 @@ export default {
|
||||||
"Last Result": "Last Result",
|
"Last Result": "Last Result",
|
||||||
"Create your admin account": "Create your admin account",
|
"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",
|
||||||
respTime: "Resp. Time (ms)",
|
respTime: "Resp. Time (ms)",
|
||||||
notAvailableShort: "N/A",
|
notAvailableShort: "N/A",
|
||||||
"Default enabled": "Default enabled",
|
"Default enabled": "Default enabled",
|
||||||
|
@ -119,5 +122,10 @@ export default {
|
||||||
"Clear Data": "Clear Data",
|
"Clear Data": "Clear Data",
|
||||||
Events: "Events",
|
Events: "Events",
|
||||||
Heartbeats: "Heartbeats",
|
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.",
|
||||||
|
alertNoFile: "Please select a file to import.",
|
||||||
|
alertWrongFileType: "Please select a JSON file.",
|
||||||
}
|
}
|
||||||
|
|
|
@ -254,6 +254,10 @@ export default {
|
||||||
this.importantHeartbeatList = {}
|
this.importantHeartbeatList = {}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
uploadBackup(uploadedJSON, callback) {
|
||||||
|
socket.emit("uploadBackup", uploadedJSON, callback)
|
||||||
|
},
|
||||||
|
|
||||||
clearEvents(monitorID, callback) {
|
clearEvents(monitorID, callback) {
|
||||||
socket.emit("clearEvents", monitorID, callback)
|
socket.emit("clearEvents", monitorID, callback)
|
||||||
},
|
},
|
||||||
|
|
|
@ -120,6 +120,27 @@
|
||||||
</form>
|
</form>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<h2 class="mt-5 mb-2">{{ $t("Import/Export Backup") }}</h2>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
{{ $t("backupDescription") }} <br />
|
||||||
|
({{ $t("backupDescription2") }}) <br />
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="input-group mb-3">
|
||||||
|
<button class="btn btn-outline-primary" @click="downloadBackup">{{ $t("Export") }}</button>
|
||||||
|
<button type="button" class="btn btn-outline-primary" :disabled="processing" @click="importBackup">
|
||||||
|
<div v-if="processing" class="spinner-border spinner-border-sm me-1"></div>
|
||||||
|
{{ $t("Import") }}
|
||||||
|
</button>
|
||||||
|
<input id="importBackup" type="file" class="form-control" accept="application/json">
|
||||||
|
</div>
|
||||||
|
<div v-if="importAlert" class="alert alert-danger mt-3" style="padding: 6px 16px;">
|
||||||
|
{{ importAlert }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p><strong>{{ $t("backupDescription3") }}</strong></p>
|
||||||
|
|
||||||
<h2 class="mt-5 mb-2">{{ $t("Advanced") }}</h2>
|
<h2 class="mt-5 mb-2">{{ $t("Advanced") }}</h2>
|
||||||
|
|
||||||
<div class="mb-3">
|
<div class="mb-3">
|
||||||
|
@ -275,6 +296,8 @@ export default {
|
||||||
|
|
||||||
},
|
},
|
||||||
loaded: false,
|
loaded: false,
|
||||||
|
importAlert: null,
|
||||||
|
processing: false,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
|
@ -351,6 +374,52 @@ export default {
|
||||||
this.$root.storage().removeItem("token");
|
this.$root.storage().removeItem("token");
|
||||||
},
|
},
|
||||||
|
|
||||||
|
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: monitorList,
|
||||||
|
}
|
||||||
|
exportData = JSON.stringify(exportData);
|
||||||
|
let downloadItem = document.createElement("a");
|
||||||
|
downloadItem.setAttribute("href", "data:application/json;charset=utf-8," + encodeURI(exportData));
|
||||||
|
downloadItem.setAttribute("download", fileName);
|
||||||
|
downloadItem.click();
|
||||||
|
},
|
||||||
|
|
||||||
|
importBackup() {
|
||||||
|
this.processing = true;
|
||||||
|
let uploadItem = document.getElementById("importBackup").files;
|
||||||
|
|
||||||
|
if (uploadItem.length <= 0) {
|
||||||
|
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();
|
||||||
|
fileReader.readAsText(uploadItem.item(0));
|
||||||
|
|
||||||
|
fileReader.onload = item => {
|
||||||
|
this.$root.uploadBackup(item.target.result, (res) => {
|
||||||
|
this.processing = false;
|
||||||
|
|
||||||
|
if (res.ok) {
|
||||||
|
toast.success(res.msg);
|
||||||
|
} else {
|
||||||
|
toast.error(res.msg);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
clearStatistics() {
|
clearStatistics() {
|
||||||
this.$root.clearStatistics((res) => {
|
this.$root.clearStatistics((res) => {
|
||||||
if (res.ok) {
|
if (res.ok) {
|
||||||
|
@ -388,6 +457,18 @@ export default {
|
||||||
.btn-check:hover + .btn-outline-primary {
|
.btn-check:hover + .btn-outline-primary {
|
||||||
color: #000;
|
color: #000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#importBackup {
|
||||||
|
&::file-selector-button {
|
||||||
|
color: $primary;
|
||||||
|
background-color: $dark-bg;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover:not(:disabled):not([readonly])::file-selector-button {
|
||||||
|
color: $dark-font-color2;
|
||||||
|
background-color: $primary;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
footer {
|
footer {
|
||||||
|
|
Loading…
Reference in a new issue