1
0
mirror of https://github.com/hrfee/jfa-go.git synced 2024-12-22 09:00:10 +00:00

backups: show uploaded backups on-page

This commit is contained in:
Harvey Tindall 2023-12-21 21:11:40 +00:00
parent bc2e9cffda
commit dc2c2f1164
Signed by: hrfee
GPG Key ID: BBC65952848FB1A2
6 changed files with 27 additions and 23 deletions

View File

@ -32,8 +32,8 @@ func (app *appContext) CreateBackup(gc *gin.Context) {
func (app *appContext) GetBackup(gc *gin.Context) { func (app *appContext) GetBackup(gc *gin.Context) {
fname := gc.Param("fname") fname := gc.Param("fname")
// Hopefully this is enough to ensure the path isn't malicious. Hidden behind bearer auth anyway so shouldn't matter too much I guess. // Hopefully this is enough to ensure the path isn't malicious. Hidden behind bearer auth anyway so shouldn't matter too much I guess.
ok := strings.HasPrefix(fname, BACKUP_PREFIX) && strings.HasSuffix(fname, BACKUP_SUFFIX) ok := (strings.HasPrefix(fname, BACKUP_PREFIX) || strings.HasPrefix(fname, BACKUP_UPLOAD_PREFIX+BACKUP_PREFIX)) && strings.HasSuffix(fname, BACKUP_SUFFIX)
t, err := time.Parse(BACKUP_DATEFMT, strings.TrimSuffix(strings.TrimPrefix(fname, BACKUP_PREFIX), BACKUP_SUFFIX)) t, err := time.Parse(BACKUP_DATEFMT, strings.TrimSuffix(strings.TrimPrefix(strings.TrimPrefix(fname, BACKUP_UPLOAD_PREFIX), BACKUP_PREFIX), BACKUP_SUFFIX))
if !ok || err != nil || t.IsZero() { if !ok || err != nil || t.IsZero() {
app.debug.Printf("Ignoring backup DL request due to fname: %v\n", err) app.debug.Printf("Ignoring backup DL request due to fname: %v\n", err)
respondBool(400, false, gc) respondBool(400, false, gc)
@ -109,7 +109,7 @@ func (app *appContext) RestoreBackup(gc *gin.Context) {
} }
app.debug.Printf("Got uploaded file \"%s\"\n", file.Filename) app.debug.Printf("Got uploaded file \"%s\"\n", file.Filename)
path := app.config.Section("backups").Key("path").String() path := app.config.Section("backups").Key("path").String()
fullpath := filepath.Join(path, "jfa-go-upload-bak-"+time.Now().Local().Format(BACKUP_DATEFMT)+BACKUP_SUFFIX) fullpath := filepath.Join(path, BACKUP_UPLOAD_PREFIX+BACKUP_PREFIX+time.Now().Local().Format(BACKUP_DATEFMT)+BACKUP_SUFFIX)
gc.SaveUploadedFile(file, fullpath) gc.SaveUploadedFile(file, fullpath)
app.debug.Printf("Saved to \"%s\"\n", fullpath) app.debug.Printf("Saved to \"%s\"\n", fullpath)
LOADBAK = fullpath LOADBAK = fullpath

View File

@ -9,6 +9,13 @@ import (
"time" "time"
) )
const (
BACKUP_PREFIX = "jfa-go-db-"
BACKUP_UPLOAD_PREFIX = "upload-"
BACKUP_DATEFMT = "2006-01-02T15-04-05"
BACKUP_SUFFIX = ".bak"
)
type BackupList struct { type BackupList struct {
files []os.DirEntry files []os.DirEntry
dates []time.Time dates []time.Time
@ -69,7 +76,7 @@ func (app *appContext) getBackups() *BackupList {
if item.IsDir() || !(strings.HasSuffix(item.Name(), BACKUP_SUFFIX)) { if item.IsDir() || !(strings.HasSuffix(item.Name(), BACKUP_SUFFIX)) {
continue continue
} }
t, err := time.Parse(BACKUP_DATEFMT, strings.TrimSuffix(strings.TrimPrefix(item.Name(), BACKUP_PREFIX), BACKUP_SUFFIX)) t, err := time.Parse(BACKUP_DATEFMT, strings.TrimSuffix(strings.TrimPrefix(strings.TrimPrefix(item.Name(), BACKUP_UPLOAD_PREFIX), BACKUP_PREFIX), BACKUP_SUFFIX))
if err != nil { if err != nil {
app.debug.Printf("Failed to parse backup filename \"%s\": %v\n", item.Name(), err) app.debug.Printf("Failed to parse backup filename \"%s\": %v\n", item.Name(), err)
continue continue

View File

@ -1561,11 +1561,11 @@
"order": [], "order": [],
"meta": { "meta": {
"name": "Backups", "name": "Backups",
"description": "Settings for database backups." "description": "Settings for database backups. Press the \"Backups\" button above to create, download and restore backups."
}, },
"settings": { "settings": {
"enabled": { "enabled": {
"name": "Enabled", "name": "Scheduled Backups",
"required": false, "required": false,
"requires_restart": true, "requires_restart": true,
"type": "bool", "type": "bool",
@ -1593,7 +1593,6 @@
"name": "Number of backups to keep", "name": "Number of backups to keep",
"required": false, "required": false,
"requires_restart": true, "requires_restart": true,
"depends_true": "enabled",
"type": "number", "type": "number",
"value": 20, "value": 20,
"description": "Number of most recent backups to keep. Once this is hit, the oldest backup will be deleted before doing a new one." "description": "Number of most recent backups to keep. Once this is hit, the oldest backup will be deleted before doing a new one."

View File

@ -8,12 +8,6 @@ import (
"github.com/timshannon/badgerhold/v4" "github.com/timshannon/badgerhold/v4"
) )
const (
BACKUP_PREFIX = "jfa-go-db-"
BACKUP_DATEFMT = "2006-01-02T15-04-05"
BACKUP_SUFFIX = ".bak"
)
// clearEmails removes stored emails for users which no longer exist. // clearEmails removes stored emails for users which no longer exist.
// meant to be called with other such housekeeping functions, so assumes // meant to be called with other such housekeeping functions, so assumes
// the user cache is fresh. // the user cache is fresh.

View File

@ -331,14 +331,18 @@
<div id="modal-backups" class="modal"> <div id="modal-backups" class="modal">
<div class="card relative mx-auto my-[10%] w-4/5 lg:w-1/3"> <div class="card relative mx-auto my-[10%] w-4/5 lg:w-1/3">
<span class="heading">{{ .strings.backups }} <span class="modal-close">&times;</span></span> <span class="heading">{{ .strings.backups }} <span class="modal-close">&times;</span></span>
<p class="content my-4">{{ .strings.backupsDescription }}</p> <div class="content my-4">
<p class="content my-4">{{ .strings.backupsCopy }}</p> {{ .strings.backupsDescription }}
<p class="content my-4">{{ .strings.backupsFormatNote }}</p> <ul>
<div class="row col flex"> <li>{{ .strings.backupsCopy }}</li>
<button class="button ~info @low mr-2 mt-4 mb-4" id="settings-backups-backup">{{ .strings.backupNow }}</button> <li>{{ .strings.backupsFormatNote }}</li>
<button class="button ~neutral @low mr-2 mt-4 mb-4" id="settings-backups-upload">{{ .strings.backupUpload }}</button> </ul>
</div>
<div class="flex flex-row flex-wrap my-2">
<button class="button ~info @low mr-2 mb-2" id="settings-backups-backup">{{ .strings.backupNow }}</button>
<button class="button ~neutral @low mr-2 mb-2" id="settings-backups-upload">{{ .strings.backupUpload }}</button>
<input id="backups-file" name="backups-file" type="file" hidden> <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 mb-2" id="settings-backups-sort-direction">{{ .strings.sortDirection }}</button>
</div> </div>
<div class="overflow-x-auto"> <div class="overflow-x-auto">
<table class="table"> <table class="table">

View File

@ -186,9 +186,9 @@
"backupsFormatNote": "Only backup files with the standard name format will be shown here. To use any other, upload the backup manually.", "backupsFormatNote": "Only backup files with the standard name format will be shown here. To use any other, upload the backup manually.",
"backupsCopy": "When applying a backup, a copy of the original \"db\" folder will be made next to it, in case anything goes wrong.", "backupsCopy": "When applying a backup, a copy of the original \"db\" folder will be made next to it, in case anything goes wrong.",
"backupDownloadRestore": "Download / Restore", "backupDownloadRestore": "Download / Restore",
"backupUpload": "Upload backup", "backupUpload": "Upload Backup",
"backupDownload": "Download backup", "backupDownload": "Download Backup",
"backupRestore": "Restore backup", "backupRestore": "Restore Backup",
"backupNow": "Backup Now", "backupNow": "Backup Now",
"backupCreated": "Backup created", "backupCreated": "Backup created",
"backupCanBeFound": "The backup can be found on the server at {filepath}.", "backupCanBeFound": "The backup can be found on the server at {filepath}.",