mirror of
https://github.com/hrfee/jfa-go.git
synced 2024-12-22 09:00:10 +00:00
backups: upload and restore backup in-app
This commit is contained in:
parent
eff313be41
commit
ade032241a
26
api.go
26
api.go
@ -611,8 +611,7 @@ func (app *appContext) GetBackups(gc *gin.Context) {
|
|||||||
|
|
||||||
// @Summary Restore a backup file stored locally to the server.
|
// @Summary Restore a backup file stored locally to the server.
|
||||||
// @Param fname path string true "backup filename"
|
// @Param fname path string true "backup filename"
|
||||||
// @Router /backups/restore/{fname} [get]
|
// @Router /backups/restore/{fname} [post]
|
||||||
// @Produce octet-stream
|
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Failure 400 {object} boolResponse
|
// @Failure 400 {object} boolResponse
|
||||||
// @Security Bearer
|
// @Security Bearer
|
||||||
@ -632,3 +631,26 @@ func (app *appContext) RestoreLocalBackup(gc *gin.Context) {
|
|||||||
LOADBAK = fullpath
|
LOADBAK = fullpath
|
||||||
app.restart(gc)
|
app.restart(gc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @Summary Restore a backup file uploaded by the user.
|
||||||
|
// @Param file formData file true ".bak file"
|
||||||
|
// @Router /backups/restore [post]
|
||||||
|
// @Produce json
|
||||||
|
// @Failure 400 {object} boolResponse
|
||||||
|
// @Security Bearer
|
||||||
|
// @tags Other
|
||||||
|
func (app *appContext) RestoreBackup(gc *gin.Context) {
|
||||||
|
file, err := gc.FormFile("backups-file")
|
||||||
|
if err != nil {
|
||||||
|
app.err.Printf("Failed to get file from form data: %v\n", err)
|
||||||
|
respondBool(400, false, gc)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
app.debug.Printf("Got uploaded file \"%s\"\n", file.Filename)
|
||||||
|
path := app.config.Section("backups").Key("path").String()
|
||||||
|
fullpath := filepath.Join(path, "jfa-go-upload-bak-"+time.Now().Local().Format(BACKUP_DATEFMT)+BACKUP_SUFFIX)
|
||||||
|
gc.SaveUploadedFile(file, fullpath)
|
||||||
|
app.debug.Printf("Saved to \"%s\"\n", fullpath)
|
||||||
|
LOADBAK = fullpath
|
||||||
|
app.restart(gc)
|
||||||
|
}
|
||||||
|
@ -336,6 +336,7 @@
|
|||||||
<div class="row col flex">
|
<div class="row col flex">
|
||||||
<button class="button ~info @low mr-2 mt-4 mb-4" id="settings-backups-backup">{{ .strings.backupNow }}</button>
|
<button class="button ~info @low mr-2 mt-4 mb-4" id="settings-backups-backup">{{ .strings.backupNow }}</button>
|
||||||
<button class="button ~neutral @low mr-2 mt-4 mb-4" id="settings-backups-upload">{{ .strings.backupUpload }}</button>
|
<button class="button ~neutral @low mr-2 mt-4 mb-4" id="settings-backups-upload">{{ .strings.backupUpload }}</button>
|
||||||
|
<input id="backups-file" name="backups-file" type="file" hidden>
|
||||||
<button class="button ~neutral @low mr-2 mt-4 mb-4" id="settings-backups-sort-direction">{{ .strings.sortDirection }}</button>
|
<button class="button ~neutral @low mr-2 mt-4 mb-4" id="settings-backups-sort-direction">{{ .strings.sortDirection }}</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="overflow-x-auto">
|
<div class="overflow-x-auto">
|
||||||
|
@ -212,6 +212,7 @@ func (app *appContext) loadRoutes(router *gin.Engine) {
|
|||||||
api.GET(p+"/backups/:fname", app.GetBackup)
|
api.GET(p+"/backups/:fname", app.GetBackup)
|
||||||
api.GET(p+"/backups", app.GetBackups)
|
api.GET(p+"/backups", app.GetBackups)
|
||||||
api.POST(p+"/backups/restore/:fname", app.RestoreLocalBackup)
|
api.POST(p+"/backups/restore/:fname", app.RestoreLocalBackup)
|
||||||
|
api.POST(p+"/backups/restore", app.RestoreBackup)
|
||||||
if telegramEnabled || discordEnabled || matrixEnabled {
|
if telegramEnabled || discordEnabled || matrixEnabled {
|
||||||
api.GET(p+"/telegram/pin", app.TelegramGetPin)
|
api.GET(p+"/telegram/pin", app.TelegramGetPin)
|
||||||
api.GET(p+"/telegram/verified/:pin", app.TelegramVerified)
|
api.GET(p+"/telegram/verified/:pin", app.TelegramVerified)
|
||||||
|
@ -56,6 +56,15 @@ export const _download = (url: string, fname: string): void => {
|
|||||||
req.send();
|
req.send();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const _upload = (url: string, formData: FormData): void => {
|
||||||
|
let req = new XMLHttpRequest();
|
||||||
|
if (window.URLBase) { url = window.URLBase + url; }
|
||||||
|
req.open("POST", url, true);
|
||||||
|
req.setRequestHeader("Authorization", "Bearer " + window.token);
|
||||||
|
// req.setRequestHeader('Content-Type', 'multipart/form-data');
|
||||||
|
req.send(formData);
|
||||||
|
};
|
||||||
|
|
||||||
export const _post = (url: string, data: Object, onreadystatechange: (req: XMLHttpRequest) => void, response?: boolean, statusHandler?: (req: XMLHttpRequest) => void): void => {
|
export const _post = (url: string, data: Object, onreadystatechange: (req: XMLHttpRequest) => void, response?: boolean, statusHandler?: (req: XMLHttpRequest) => void): void => {
|
||||||
let req = new XMLHttpRequest();
|
let req = new XMLHttpRequest();
|
||||||
req.open("POST", window.URLBase + url, true);
|
req.open("POST", window.URLBase + url, true);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { _get, _post, _delete, _download, toggleLoader, addLoader, removeLoader, insertText, toClipboard, toDateString } from "../modules/common.js";
|
import { _get, _post, _delete, _download, _upload, toggleLoader, addLoader, removeLoader, insertText, toClipboard, toDateString } from "../modules/common.js";
|
||||||
import { Marked } from "@ts-stack/markdown";
|
import { Marked } from "@ts-stack/markdown";
|
||||||
import { stripMarkdown } from "../modules/stripmd.js";
|
import { stripMarkdown } from "../modules/stripmd.js";
|
||||||
|
|
||||||
@ -830,6 +830,21 @@ export class settingsList {
|
|||||||
};
|
};
|
||||||
this._backupSortDirection.onclick = () => this.setBackupSort(!(this._backupSortAscending));
|
this._backupSortDirection.onclick = () => this.setBackupSort(!(this._backupSortAscending));
|
||||||
const advancedEnableToggle = document.getElementById("settings-advanced-enabled") as HTMLInputElement;
|
const advancedEnableToggle = document.getElementById("settings-advanced-enabled") as HTMLInputElement;
|
||||||
|
|
||||||
|
const filedlg = document.getElementById("backups-file") as HTMLInputElement;
|
||||||
|
document.getElementById("settings-backups-upload").onclick = () => {
|
||||||
|
filedlg.click();
|
||||||
|
};
|
||||||
|
filedlg.addEventListener("change", () => {
|
||||||
|
if (filedlg.files.length == 0) return;
|
||||||
|
const form = new FormData();
|
||||||
|
form.append("backups-file", filedlg.files[0], filedlg.files[0].name);
|
||||||
|
_upload("/backups/restore", form);
|
||||||
|
window.modals.backups.close();
|
||||||
|
window.modals.settingsRefresh.modal.querySelector("span.heading").textContent = window.lang.strings("settingsRestarting");
|
||||||
|
window.modals.settingsRefresh.show();
|
||||||
|
});
|
||||||
|
|
||||||
advancedEnableToggle.onchange = () => {
|
advancedEnableToggle.onchange = () => {
|
||||||
document.dispatchEvent(new CustomEvent("settings-advancedState", { detail: advancedEnableToggle.checked }));
|
document.dispatchEvent(new CustomEvent("settings-advancedState", { detail: advancedEnableToggle.checked }));
|
||||||
const parent = advancedEnableToggle.parentElement;
|
const parent = advancedEnableToggle.parentElement;
|
||||||
|
Loading…
Reference in New Issue
Block a user