backups: show uploaded backups on-page

backups
Harvey Tindall 11 months ago
parent bc2e9cffda
commit dc2c2f1164
No known key found for this signature in database
GPG Key ID: BBC65952848FB1A2

@ -32,8 +32,8 @@ func (app *appContext) CreateBackup(gc *gin.Context) {
func (app *appContext) GetBackup(gc *gin.Context) {
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.
ok := strings.HasPrefix(fname, BACKUP_PREFIX) && strings.HasSuffix(fname, BACKUP_SUFFIX)
t, err := time.Parse(BACKUP_DATEFMT, strings.TrimSuffix(strings.TrimPrefix(fname, BACKUP_PREFIX), 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(strings.TrimPrefix(fname, BACKUP_UPLOAD_PREFIX), BACKUP_PREFIX), BACKUP_SUFFIX))
if !ok || err != nil || t.IsZero() {
app.debug.Printf("Ignoring backup DL request due to fname: %v\n", err)
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)
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)
app.debug.Printf("Saved to \"%s\"\n", fullpath)
LOADBAK = fullpath

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

@ -1561,11 +1561,11 @@
"order": [],
"meta": {
"name": "Backups",
"description": "Settings for database backups."
"description": "Settings for database backups. Press the \"Backups\" button above to create, download and restore backups."
},
"settings": {
"enabled": {
"name": "Enabled",
"name": "Scheduled Backups",
"required": false,
"requires_restart": true,
"type": "bool",
@ -1593,7 +1593,6 @@
"name": "Number of backups to keep",
"required": false,
"requires_restart": true,
"depends_true": "enabled",
"type": "number",
"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."

@ -8,12 +8,6 @@ import (
"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.
// meant to be called with other such housekeeping functions, so assumes
// the user cache is fresh.

@ -331,14 +331,18 @@
<div id="modal-backups" class="modal">
<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>
<p class="content my-4">{{ .strings.backupsDescription }}</p>
<p class="content my-4">{{ .strings.backupsCopy }}</p>
<p class="content my-4">{{ .strings.backupsFormatNote }}</p>
<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 ~neutral @low mr-2 mt-4 mb-4" id="settings-backups-upload">{{ .strings.backupUpload }}</button>
<div class="content my-4">
{{ .strings.backupsDescription }}
<ul>
<li>{{ .strings.backupsCopy }}</li>
<li>{{ .strings.backupsFormatNote }}</li>
</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>
<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 class="overflow-x-auto">
<table class="table">

@ -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.",
"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",
"backupUpload": "Upload backup",
"backupDownload": "Download backup",
"backupRestore": "Restore backup",
"backupUpload": "Upload Backup",
"backupDownload": "Download Backup",
"backupRestore": "Restore Backup",
"backupNow": "Backup Now",
"backupCreated": "Backup created",
"backupCanBeFound": "The backup can be found on the server at {filepath}.",

Loading…
Cancel
Save