mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-12-25 21:29:37 +00:00
Add:Ability to edit backup location path on backups page #2973
- Added api endpoint PATCH /api/backups/path - Cleanup backup page UI for mobile screens
This commit is contained in:
parent
8498cab842
commit
331d7a41ab
5 changed files with 149 additions and 22 deletions
|
|
@ -1,5 +1,8 @@
|
|||
const Path = require('path')
|
||||
const fs = require('../libs/fsExtra')
|
||||
const Logger = require('../Logger')
|
||||
const { encodeUriPath } = require('../utils/fileUtils')
|
||||
const Database = require('../Database')
|
||||
const fileUtils = require('../utils/fileUtils')
|
||||
|
||||
class BackupController {
|
||||
constructor() {}
|
||||
|
|
@ -31,6 +34,56 @@ class BackupController {
|
|||
this.backupManager.uploadBackup(req, res)
|
||||
}
|
||||
|
||||
/**
|
||||
* PATCH: /api/backups/path
|
||||
* Update the backup path
|
||||
*
|
||||
* @this import('../routers/ApiRouter')
|
||||
*
|
||||
* @param {import('express').Request} req
|
||||
* @param {import('express').Response} res
|
||||
*/
|
||||
async updatePath(req, res) {
|
||||
// Validate path is not empty and is a string
|
||||
if (!req.body.path || !req.body.path?.trim?.()) {
|
||||
Logger.error('[BackupController] Update backup path invalid')
|
||||
return res.status(400).send('Invalid request body. Must include path.')
|
||||
}
|
||||
|
||||
const newBackupPath = fileUtils.filePathToPOSIX(Path.resolve(req.body.path))
|
||||
|
||||
if (newBackupPath === this.backupManager.backupPath) {
|
||||
Logger.debug(`[BackupController] Backup path unchanged: ${newBackupPath}`)
|
||||
return res.status(200).send('Backup path unchanged')
|
||||
}
|
||||
|
||||
Logger.info(`[BackupController] Updating backup path to "${newBackupPath}" from "${this.backupManager.backupPath}"`)
|
||||
|
||||
// Check if backup path is set in environment variable
|
||||
if (process.env.BACKUP_PATH) {
|
||||
Logger.warn(`[BackupController] Backup path is set in environment variable BACKUP_PATH. Backup path will be reverted on server restart.`)
|
||||
}
|
||||
|
||||
// Validate backup path is writable and create folder if it does not exist
|
||||
try {
|
||||
const direxists = await fs.pathExists(newBackupPath)
|
||||
if (!direxists) {
|
||||
// If folder does not exist try to make it
|
||||
await fs.mkdir(newBackupPath)
|
||||
}
|
||||
} catch (error) {
|
||||
Logger.error(`[BackupController] updatePath: Failed to ensure backup path "${newBackupPath}"`, error)
|
||||
return res.status(400).send(`Invalid backup path "${req.body.path}"`)
|
||||
}
|
||||
|
||||
Database.serverSettings.backupPath = newBackupPath
|
||||
await Database.updateServerSettings()
|
||||
|
||||
await this.backupManager.reload()
|
||||
|
||||
res.sendStatus(200)
|
||||
}
|
||||
|
||||
/**
|
||||
* api/backups/:id/download
|
||||
*
|
||||
|
|
@ -39,7 +92,7 @@ class BackupController {
|
|||
*/
|
||||
download(req, res) {
|
||||
if (global.XAccel) {
|
||||
const encodedURI = encodeUriPath(global.XAccel + req.backup.fullPath)
|
||||
const encodedURI = fileUtils.encodeUriPath(global.XAccel + req.backup.fullPath)
|
||||
Logger.debug(`Use X-Accel to serve static file ${encodedURI}`)
|
||||
return res.status(204).header({ 'X-Accel-Redirect': encodedURI }).send()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,6 +51,16 @@ class BackupManager {
|
|||
this.scheduleCron()
|
||||
}
|
||||
|
||||
/**
|
||||
* Reload backups after updating backup path
|
||||
*/
|
||||
async reload() {
|
||||
Logger.info(`[BackupManager] Reloading backups with backup path "${this.backupPath}"`)
|
||||
this.backups = []
|
||||
await this.loadBackups()
|
||||
this.updateCronSchedule()
|
||||
}
|
||||
|
||||
scheduleCron() {
|
||||
if (!this.backupSchedule) {
|
||||
Logger.info(`[BackupManager] Auto Backups are disabled`)
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ class ApiRouter {
|
|||
this.auth = Server.auth
|
||||
this.playbackSessionManager = Server.playbackSessionManager
|
||||
this.abMergeManager = Server.abMergeManager
|
||||
/** @type {import('../managers/BackupManager')} */
|
||||
this.backupManager = Server.backupManager
|
||||
/** @type {import('../Watcher')} */
|
||||
this.watcher = Server.watcher
|
||||
|
|
@ -193,6 +194,7 @@ class ApiRouter {
|
|||
this.router.get('/backups/:id/download', BackupController.middleware.bind(this), BackupController.download.bind(this))
|
||||
this.router.get('/backups/:id/apply', BackupController.middleware.bind(this), BackupController.apply.bind(this))
|
||||
this.router.post('/backups/upload', BackupController.middleware.bind(this), BackupController.upload.bind(this))
|
||||
this.router.patch('/backups/path', BackupController.middleware.bind(this), BackupController.updatePath.bind(this))
|
||||
|
||||
//
|
||||
// File System Routes
|
||||
|
|
@ -308,7 +310,6 @@ class ApiRouter {
|
|||
this.router.post('/custom-metadata-providers', CustomMetadataProviderController.middleware.bind(this), CustomMetadataProviderController.create.bind(this))
|
||||
this.router.delete('/custom-metadata-providers/:id', CustomMetadataProviderController.middleware.bind(this), CustomMetadataProviderController.delete.bind(this))
|
||||
|
||||
|
||||
//
|
||||
// Misc Routes
|
||||
//
|
||||
|
|
@ -567,10 +568,13 @@ class ApiRouter {
|
|||
}
|
||||
}
|
||||
// Remove authors without an id
|
||||
mediaMetadata.authors = mediaMetadata.authors.filter(au => !!au.id)
|
||||
mediaMetadata.authors = mediaMetadata.authors.filter((au) => !!au.id)
|
||||
if (newAuthors.length) {
|
||||
await Database.createBulkAuthors(newAuthors)
|
||||
SocketAuthority.emitter('authors_added', newAuthors.map(au => au.toJSON()))
|
||||
SocketAuthority.emitter(
|
||||
'authors_added',
|
||||
newAuthors.map((au) => au.toJSON())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -611,10 +615,13 @@ class ApiRouter {
|
|||
}
|
||||
}
|
||||
// Remove series without an id
|
||||
mediaMetadata.series = mediaMetadata.series.filter(se => se.id)
|
||||
mediaMetadata.series = mediaMetadata.series.filter((se) => se.id)
|
||||
if (newSeries.length) {
|
||||
await Database.createBulkSeries(newSeries)
|
||||
SocketAuthority.emitter('multiple_series_added', newSeries.map(se => se.toJSON()))
|
||||
SocketAuthority.emitter(
|
||||
'multiple_series_added',
|
||||
newSeries.map((se) => se.toJSON())
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue