mirror of
				https://github.com/advplyr/audiobookshelf.git
				synced 2025-11-03 19:07:00 -05:00 
			
		
		
		
	New data model backups and move backups to API endpoints
This commit is contained in:
		
							parent
							
								
									eea3e2583c
								
							
						
					
					
						commit
						c9ea5dd2d7
					
				@ -23,7 +23,7 @@
 | 
				
			|||||||
            <div class="w-full flex flex-row items-center justify-center">
 | 
					            <div class="w-full flex flex-row items-center justify-center">
 | 
				
			||||||
              <ui-btn small color="primary" @click="applyBackup(backup)">Apply</ui-btn>
 | 
					              <ui-btn small color="primary" @click="applyBackup(backup)">Apply</ui-btn>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
              <a :href="`/metadata/${backup.path.replace(/%/g, '%25').replace(/#/g, '%23')}?token=${userToken}`" class="mx-1 pt-1 hover:text-opacity-100 text-opacity-70 text-white" download><span class="material-icons text-xl">download</span></a>
 | 
					              <a :href="`/metadata/${$encodeUriPath(backup.path)}?token=${userToken}`" class="mx-1 pt-1 hover:text-opacity-100 text-opacity-70 text-white" download><span class="material-icons text-xl">download</span></a>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
              <span class="material-icons text-xl hover:text-error hover:text-opacity-100 text-opacity-70 text-white cursor-pointer mx-1" @click="deleteBackupClick(backup)">delete</span>
 | 
					              <span class="material-icons text-xl hover:text-error hover:text-opacity-100 text-opacity-70 text-white cursor-pointer mx-1" @click="deleteBackupClick(backup)">delete</span>
 | 
				
			||||||
            </div>
 | 
					            </div>
 | 
				
			||||||
@ -42,7 +42,7 @@
 | 
				
			|||||||
      <div v-if="selectedBackup" class="px-4 w-full text-sm py-6 rounded-lg bg-bg shadow-lg border border-black-300">
 | 
					      <div v-if="selectedBackup" class="px-4 w-full text-sm py-6 rounded-lg bg-bg shadow-lg border border-black-300">
 | 
				
			||||||
        <p class="text-error text-lg font-semibold">Important Notice!</p>
 | 
					        <p class="text-error text-lg font-semibold">Important Notice!</p>
 | 
				
			||||||
        <p class="text-base py-1">Applying a backup will overwrite users, user progress, book details, settings, and covers stored in metadata with the backed up data.</p>
 | 
					        <p class="text-base py-1">Applying a backup will overwrite users, user progress, book details, settings, and covers stored in metadata with the backed up data.</p>
 | 
				
			||||||
        <p class="text-base py-1">Backups <strong>do not</strong> modify any files in your library folders, only data in the audiobookshelf created <span class="font-mono">/config</span> and <span class="font-mono">/metadata</span> directories.</p>
 | 
					        <p class="text-base py-1">Backups <strong>do not</strong> modify any files in your library folders, only data in the audiobookshelf created <span class="font-mono">/config</span> and <span class="font-mono">/metadata</span> directories. If you have enabled server settings to store cover art and metadata in your library folders then those are not backup up or overwritten.</p>
 | 
				
			||||||
        <p class="text-base py-1">All clients using your server will be automatically refreshed.</p>
 | 
					        <p class="text-base py-1">All clients using your server will be automatically refreshed.</p>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        <p class="text-lg text-center my-8">Are you sure you want to apply the backup created on {{ selectedBackup.datePretty }}?</p>
 | 
					        <p class="text-lg text-center my-8">Are you sure you want to apply the backup created on {{ selectedBackup.datePretty }}?</p>
 | 
				
			||||||
@ -77,14 +77,24 @@ export default {
 | 
				
			|||||||
  methods: {
 | 
					  methods: {
 | 
				
			||||||
    confirm() {
 | 
					    confirm() {
 | 
				
			||||||
      this.showConfirmApply = false
 | 
					      this.showConfirmApply = false
 | 
				
			||||||
      this.$root.socket.once('apply_backup_complete', this.applyBackupComplete)
 | 
					
 | 
				
			||||||
      this.$root.socket.emit('apply_backup', this.selectedBackup.id)
 | 
					      this.$axios
 | 
				
			||||||
 | 
					        .$get(`/api/backups/${this.selectedBackup.id}/apply`)
 | 
				
			||||||
 | 
					        .then(() => {
 | 
				
			||||||
 | 
					          this.isBackingUp = false
 | 
				
			||||||
 | 
					          location.replace('/config/backups?backup=1')
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        .catch((error) => {
 | 
				
			||||||
 | 
					          this.isBackingUp = false
 | 
				
			||||||
 | 
					          console.error('Failed', error)
 | 
				
			||||||
 | 
					          this.$toast.error('Failed to apply backup')
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    deleteBackupClick(backup) {
 | 
					    deleteBackupClick(backup) {
 | 
				
			||||||
      if (confirm(`Are you sure you want to delete backup for ${backup.datePretty}?`)) {
 | 
					      if (confirm(`Are you sure you want to delete backup for ${backup.datePretty}?`)) {
 | 
				
			||||||
        this.processing = true
 | 
					        this.processing = true
 | 
				
			||||||
        this.$axios
 | 
					        this.$axios
 | 
				
			||||||
          .$delete(`/api/backup/${backup.id}`)
 | 
					          .$delete(`/api/backups/${backup.id}`)
 | 
				
			||||||
          .then((backups) => {
 | 
					          .then((backups) => {
 | 
				
			||||||
            console.log('Backup deleted', backups)
 | 
					            console.log('Backup deleted', backups)
 | 
				
			||||||
            this.$store.commit('setBackups', backups)
 | 
					            this.$store.commit('setBackups', backups)
 | 
				
			||||||
@ -98,29 +108,24 @@ export default {
 | 
				
			|||||||
          })
 | 
					          })
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    applyBackupComplete(success) {
 | 
					 | 
				
			||||||
      if (success) {
 | 
					 | 
				
			||||||
        // this.$toast.success('Backup Applied, refresh the page')
 | 
					 | 
				
			||||||
        location.replace('/config/backups?backup=1')
 | 
					 | 
				
			||||||
      } else {
 | 
					 | 
				
			||||||
        this.$toast.error('Failed to apply backup')
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    applyBackup(backup) {
 | 
					    applyBackup(backup) {
 | 
				
			||||||
      this.selectedBackup = backup
 | 
					      this.selectedBackup = backup
 | 
				
			||||||
      this.showConfirmApply = true
 | 
					      this.showConfirmApply = true
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    backupComplete(backups) {
 | 
					 | 
				
			||||||
      this.isBackingUp = false
 | 
					 | 
				
			||||||
      if (backups) {
 | 
					 | 
				
			||||||
        this.$toast.success('Backup Successful')
 | 
					 | 
				
			||||||
        this.$store.commit('setBackups', backups)
 | 
					 | 
				
			||||||
      } else this.$toast.error('Backup Failed')
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    clickCreateBackup() {
 | 
					    clickCreateBackup() {
 | 
				
			||||||
      this.isBackingUp = true
 | 
					      this.isBackingUp = true
 | 
				
			||||||
      this.$root.socket.once('backup_complete', this.backupComplete)
 | 
					      this.$axios
 | 
				
			||||||
      this.$root.socket.emit('create_backup')
 | 
					        .$post('/api/backups')
 | 
				
			||||||
 | 
					        .then((backups) => {
 | 
				
			||||||
 | 
					          this.isBackingUp = false
 | 
				
			||||||
 | 
					          this.$toast.success('Backup Successful')
 | 
				
			||||||
 | 
					          this.$store.commit('setBackups', backups)
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					        .catch((error) => {
 | 
				
			||||||
 | 
					          this.isBackingUp = false
 | 
				
			||||||
 | 
					          console.error('Failed', error)
 | 
				
			||||||
 | 
					          this.$toast.error('Backup Failed')
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    backupUploaded(file) {
 | 
					    backupUploaded(file) {
 | 
				
			||||||
      var form = new FormData()
 | 
					      var form = new FormData()
 | 
				
			||||||
@ -129,7 +134,7 @@ export default {
 | 
				
			|||||||
      this.processing = true
 | 
					      this.processing = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      this.$axios
 | 
					      this.$axios
 | 
				
			||||||
        .$post('/api/backup/upload', form)
 | 
					        .$post('/api/backups/upload', form)
 | 
				
			||||||
        .then((result) => {
 | 
					        .then((result) => {
 | 
				
			||||||
          console.log('Upload backup result', result)
 | 
					          console.log('Upload backup result', result)
 | 
				
			||||||
          this.$store.commit('setBackups', result)
 | 
					          this.$store.commit('setBackups', result)
 | 
				
			||||||
 | 
				
			|||||||
@ -40,8 +40,8 @@
 | 
				
			|||||||
            <div class="flex items-center mb-1">
 | 
					            <div class="flex items-center mb-1">
 | 
				
			||||||
              <p class="text-sm font-book text-white text-opacity-70 w-6 truncate">{{ index + 1 }}. </p>
 | 
					              <p class="text-sm font-book text-white text-opacity-70 w-6 truncate">{{ index + 1 }}. </p>
 | 
				
			||||||
              <div class="w-56">
 | 
					              <div class="w-56">
 | 
				
			||||||
                <p class="text-sm font-book text-white text-opacity-80 truncate">{{ item.mediaMetadata.title }}</p>
 | 
					                <p class="text-sm font-book text-white text-opacity-80 truncate">{{ item.mediaMetadata ? item.mediaMetadata.title : '' }}</p>
 | 
				
			||||||
                <p class="text-xs text-white text-opacity-50">{{ $dateDistanceFromNow(item.lastUpdate) }}</p>
 | 
					                <p class="text-xs text-white text-opacity-50">{{ $dateDistanceFromNow(item.updatedAt) }}</p>
 | 
				
			||||||
              </div>
 | 
					              </div>
 | 
				
			||||||
              <div class="flex-grow" />
 | 
					              <div class="flex-grow" />
 | 
				
			||||||
              <div class="w-18 text-right">
 | 
					              <div class="w-18 text-right">
 | 
				
			||||||
 | 
				
			|||||||
@ -13,11 +13,12 @@ const Logger = require('./Logger')
 | 
				
			|||||||
const Backup = require('./objects/Backup')
 | 
					const Backup = require('./objects/Backup')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class BackupManager {
 | 
					class BackupManager {
 | 
				
			||||||
  constructor(db) {
 | 
					  constructor(db, emitter) {
 | 
				
			||||||
    this.BackupPath = Path.join(global.MetadataPath, 'backups')
 | 
					    this.BackupPath = Path.join(global.MetadataPath, 'backups')
 | 
				
			||||||
    this.MetadataBooksPath = Path.join(global.MetadataPath, 'books')
 | 
					    this.MetadataBooksPath = Path.join(global.MetadataPath, 'books')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.db = db
 | 
					    this.db = db
 | 
				
			||||||
 | 
					    this.emitter = emitter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.scheduleTask = null
 | 
					    this.scheduleTask = null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -104,59 +105,20 @@ class BackupManager {
 | 
				
			|||||||
    return res.json(this.backups.map(b => b.toJSON()))
 | 
					    return res.json(this.backups.map(b => b.toJSON()))
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  async requestCreateBackup(socket) {
 | 
					  async requestCreateBackup(res) {
 | 
				
			||||||
    // Only Root User allowed
 | 
					 | 
				
			||||||
    var client = socket.sheepClient
 | 
					 | 
				
			||||||
    if (!client || !client.user) {
 | 
					 | 
				
			||||||
      Logger.error(`[BackupManager] Invalid user attempting to create backup`)
 | 
					 | 
				
			||||||
      socket.emit('backup_complete', false)
 | 
					 | 
				
			||||||
      return
 | 
					 | 
				
			||||||
    } else if (!client.user.isRoot) {
 | 
					 | 
				
			||||||
      Logger.error(`[BackupManager] Non-Root user attempting to create backup`)
 | 
					 | 
				
			||||||
      socket.emit('backup_complete', false)
 | 
					 | 
				
			||||||
      return
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    var backupSuccess = await this.runBackup()
 | 
					    var backupSuccess = await this.runBackup()
 | 
				
			||||||
    socket.emit('backup_complete', backupSuccess ? this.backups.map(b => b.toJSON()) : false)
 | 
					    if (backupSuccess) res.json(this.backups.map(b => b.toJSON()))
 | 
				
			||||||
 | 
					    else res.sendStatus(500)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  async requestApplyBackup(socket, id) {
 | 
					  async requestApplyBackup(backup) {
 | 
				
			||||||
    // Only Root User allowed
 | 
					 | 
				
			||||||
    var client = socket.sheepClient
 | 
					 | 
				
			||||||
    if (!client || !client.user) {
 | 
					 | 
				
			||||||
      Logger.error(`[BackupManager] Invalid user attempting to create backup`)
 | 
					 | 
				
			||||||
      socket.emit('apply_backup_complete', false)
 | 
					 | 
				
			||||||
      return
 | 
					 | 
				
			||||||
    } else if (!client.user.isRoot) {
 | 
					 | 
				
			||||||
      Logger.error(`[BackupManager] Non-Root user attempting to create backup`)
 | 
					 | 
				
			||||||
      socket.emit('apply_backup_complete', false)
 | 
					 | 
				
			||||||
      return
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    var backup = this.backups.find(b => b.id === id)
 | 
					 | 
				
			||||||
    if (!backup) {
 | 
					 | 
				
			||||||
      socket.emit('apply_backup_complete', false)
 | 
					 | 
				
			||||||
      return
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    const zip = new StreamZip.async({ file: backup.fullPath })
 | 
					    const zip = new StreamZip.async({ file: backup.fullPath })
 | 
				
			||||||
    await zip.extract('config/', global.ConfigPath)
 | 
					    await zip.extract('config/', global.ConfigPath)
 | 
				
			||||||
    if (backup.backupMetadataCovers) {
 | 
					    if (backup.backupMetadataCovers) {
 | 
				
			||||||
      await zip.extract('metadata-books/', this.MetadataBooksPath)
 | 
					      await zip.extract('metadata-books/', this.MetadataBooksPath)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    await this.db.reinit()
 | 
					    await this.db.reinit()
 | 
				
			||||||
    socket.emit('apply_backup_complete', true)
 | 
					    this.emitter('backup_applied')
 | 
				
			||||||
    socket.broadcast.emit('backup_applied')
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  async setLastBackup() {
 | 
					 | 
				
			||||||
    this.backups.sort((a, b) => b.createdAt - a.createdAt)
 | 
					 | 
				
			||||||
    var lastBackup = this.backups.shift()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    const zip = new StreamZip.async({ file: lastBackup.fullPath })
 | 
					 | 
				
			||||||
    await zip.extract('config/', global.ConfigPath)
 | 
					 | 
				
			||||||
    console.log('Set Last Backup')
 | 
					 | 
				
			||||||
    await this.db.reinit()
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  async loadBackups() {
 | 
					  async loadBackups() {
 | 
				
			||||||
@ -179,7 +141,6 @@ class BackupManager {
 | 
				
			|||||||
            this.backups.push(backup)
 | 
					            this.backups.push(backup)
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
          Logger.debug(`[BackupManager] Backup found "${backup.id}"`)
 | 
					          Logger.debug(`[BackupManager] Backup found "${backup.id}"`)
 | 
				
			||||||
          zip.close()
 | 
					          zip.close()
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -304,12 +265,14 @@ class BackupManager {
 | 
				
			|||||||
      // pipe archive data to the file
 | 
					      // pipe archive data to the file
 | 
				
			||||||
      archive.pipe(output)
 | 
					      archive.pipe(output)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      archive.directory(this.db.AudiobooksPath, 'config/audiobooks')
 | 
					      archive.directory(this.db.LibraryItemsPath, 'config/libraryItems')
 | 
				
			||||||
      archive.directory(this.db.LibrariesPath, 'config/libraries')
 | 
					 | 
				
			||||||
      archive.directory(this.db.SettingsPath, 'config/settings')
 | 
					 | 
				
			||||||
      archive.directory(this.db.UsersPath, 'config/users')
 | 
					      archive.directory(this.db.UsersPath, 'config/users')
 | 
				
			||||||
      archive.directory(this.db.SessionsPath, 'config/sessions')
 | 
					      archive.directory(this.db.SessionsPath, 'config/sessions')
 | 
				
			||||||
 | 
					      archive.directory(this.db.LibrariesPath, 'config/libraries')
 | 
				
			||||||
 | 
					      archive.directory(this.db.SettingsPath, 'config/settings')
 | 
				
			||||||
      archive.directory(this.db.CollectionsPath, 'config/collections')
 | 
					      archive.directory(this.db.CollectionsPath, 'config/collections')
 | 
				
			||||||
 | 
					      archive.directory(this.db.AuthorsPath, 'config/authors')
 | 
				
			||||||
 | 
					      archive.directory(this.db.SeriesPath, 'config/series')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (metadataBooksPath) {
 | 
					      if (metadataBooksPath) {
 | 
				
			||||||
        Logger.debug(`[BackupManager] Backing up Metadata Books "${metadataBooksPath}"`)
 | 
					        Logger.debug(`[BackupManager] Backing up Metadata Books "${metadataBooksPath}"`)
 | 
				
			||||||
 | 
				
			|||||||
@ -49,7 +49,7 @@ class Server {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    this.db = new Db()
 | 
					    this.db = new Db()
 | 
				
			||||||
    this.auth = new Auth(this.db)
 | 
					    this.auth = new Auth(this.db)
 | 
				
			||||||
    this.backupManager = new BackupManager(this.db)
 | 
					    this.backupManager = new BackupManager(this.db, this.emitter.bind(this))
 | 
				
			||||||
    this.logManager = new LogManager(this.db)
 | 
					    this.logManager = new LogManager(this.db)
 | 
				
			||||||
    this.cacheManager = new CacheManager()
 | 
					    this.cacheManager = new CacheManager()
 | 
				
			||||||
    this.watcher = new Watcher()
 | 
					    this.watcher = new Watcher()
 | 
				
			||||||
@ -158,9 +158,11 @@ class Server {
 | 
				
			|||||||
    const distPath = Path.join(global.appRoot, '/client/dist')
 | 
					    const distPath = Path.join(global.appRoot, '/client/dist')
 | 
				
			||||||
    app.use(express.static(distPath))
 | 
					    app.use(express.static(distPath))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // TODO: Are these necessary?
 | 
					
 | 
				
			||||||
    // Metadata folder static path
 | 
					    // Metadata folder static path
 | 
				
			||||||
    // app.use('/metadata', this.authMiddleware.bind(this), express.static(global.MetadataPath))
 | 
					    app.use('/metadata', this.authMiddleware.bind(this), express.static(global.MetadataPath))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // TODO: Are these necessary?
 | 
				
			||||||
    // Downloads folder static path
 | 
					    // Downloads folder static path
 | 
				
			||||||
    // app.use('/downloads', this.authMiddleware.bind(this), express.static(this.downloadManager.downloadDirPath))
 | 
					    // app.use('/downloads', this.authMiddleware.bind(this), express.static(this.downloadManager.downloadDirPath))
 | 
				
			||||||
    // Static folder
 | 
					    // Static folder
 | 
				
			||||||
@ -222,9 +224,6 @@ class Server {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      socket.on('auth', (token) => this.authenticateSocket(socket, token))
 | 
					      socket.on('auth', (token) => this.authenticateSocket(socket, token))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // TODO: Most of these web socket listeners will be moved to API routes instead
 | 
					 | 
				
			||||||
      //         with the goal of the web socket connection being a nice-to-have not need-to-have
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      // Scanning
 | 
					      // Scanning
 | 
				
			||||||
      socket.on('cancel_scan', this.cancelScan.bind(this))
 | 
					      socket.on('cancel_scan', this.cancelScan.bind(this))
 | 
				
			||||||
      socket.on('save_metadata', (libraryItemId) => this.saveMetadata(socket, libraryItemId))
 | 
					      socket.on('save_metadata', (libraryItemId) => this.saveMetadata(socket, libraryItemId))
 | 
				
			||||||
@ -237,10 +236,6 @@ class Server {
 | 
				
			|||||||
      socket.on('set_log_listener', (level) => Logger.addSocketListener(socket, level))
 | 
					      socket.on('set_log_listener', (level) => Logger.addSocketListener(socket, level))
 | 
				
			||||||
      socket.on('fetch_daily_logs', () => this.logManager.socketRequestDailyLogs(socket))
 | 
					      socket.on('fetch_daily_logs', () => this.logManager.socketRequestDailyLogs(socket))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // Backups
 | 
					 | 
				
			||||||
      socket.on('create_backup', () => this.backupManager.requestCreateBackup(socket))
 | 
					 | 
				
			||||||
      socket.on('apply_backup', (id) => this.backupManager.requestApplyBackup(socket, id))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      socket.on('disconnect', () => {
 | 
					      socket.on('disconnect', () => {
 | 
				
			||||||
        Logger.removeSocketListener(socket.id)
 | 
					        Logger.removeSocketListener(socket.id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -3,6 +3,14 @@ const Logger = require('../Logger')
 | 
				
			|||||||
class BackupController {
 | 
					class BackupController {
 | 
				
			||||||
  constructor() { }
 | 
					  constructor() { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async create(req, res) {
 | 
				
			||||||
 | 
					    if (!req.user.isRoot) {
 | 
				
			||||||
 | 
					      Logger.error(`[BackupController] Non-Root user attempting to craete backup`, req.user)
 | 
				
			||||||
 | 
					      return res.sendStatus(403)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    this.backupManager.requestCreateBackup(res)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  async delete(req, res) {
 | 
					  async delete(req, res) {
 | 
				
			||||||
    if (!req.user.isRoot) {
 | 
					    if (!req.user.isRoot) {
 | 
				
			||||||
      Logger.error(`[BackupController] Non-Root user attempting to delete backup`, req.user)
 | 
					      Logger.error(`[BackupController] Non-Root user attempting to delete backup`, req.user)
 | 
				
			||||||
@ -27,5 +35,18 @@ class BackupController {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    this.backupManager.uploadBackup(req, res)
 | 
					    this.backupManager.uploadBackup(req, res)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async apply(req, res) {
 | 
				
			||||||
 | 
					    if (!req.user.isRoot) {
 | 
				
			||||||
 | 
					      Logger.error(`[BackupController] Non-Root user attempting to apply backup`, req.user)
 | 
				
			||||||
 | 
					      return res.sendStatus(403)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    var backup = this.backupManager.backups.find(b => b.id === req.params.id)
 | 
				
			||||||
 | 
					    if (!backup) {
 | 
				
			||||||
 | 
					      return res.sendStatus(404)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    await this.backupManager.requestApplyBackup(backup)
 | 
				
			||||||
 | 
					    res.sendStatus(200)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
module.exports = new BackupController()
 | 
					module.exports = new BackupController()
 | 
				
			||||||
@ -142,8 +142,10 @@ class ApiRouter {
 | 
				
			|||||||
    //
 | 
					    //
 | 
				
			||||||
    // Backup Routes
 | 
					    // Backup Routes
 | 
				
			||||||
    //
 | 
					    //
 | 
				
			||||||
    this.router.delete('/backup/:id', BackupController.delete.bind(this))
 | 
					    this.router.post('/backups', BackupController.create.bind(this))
 | 
				
			||||||
    this.router.post('/backup/upload', BackupController.upload.bind(this))
 | 
					    this.router.delete('/backups/:id', BackupController.delete.bind(this))
 | 
				
			||||||
 | 
					    this.router.get('/backups/:id/apply', BackupController.apply.bind(this))
 | 
				
			||||||
 | 
					    this.router.post('/backups/upload', BackupController.upload.bind(this))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //
 | 
					    //
 | 
				
			||||||
    // File System Routes
 | 
					    // File System Routes
 | 
				
			||||||
 | 
				
			|||||||
@ -373,7 +373,7 @@ function cleanSessionObj(db, userListeningSession) {
 | 
				
			|||||||
  bookMetadata.title = userListeningSession.audiobookTitle || ''
 | 
					  bookMetadata.title = userListeningSession.audiobookTitle || ''
 | 
				
			||||||
  newPlaybackSession.mediaMetadata = bookMetadata
 | 
					  newPlaybackSession.mediaMetadata = bookMetadata
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return db.sessionsDb.update((record) => record.id === newPlaybackSession.id, () => newPlaybackSession).then((results) => true).catch((error) => {
 | 
					  return db.sessionsDb.update((record) => record.id === userListeningSession.id, () => newPlaybackSession).then((results) => true).catch((error) => {
 | 
				
			||||||
    Logger.error(`[dbMigration] Update Session Failed: ${error}`)
 | 
					    Logger.error(`[dbMigration] Update Session Failed: ${error}`)
 | 
				
			||||||
    return false
 | 
					    return false
 | 
				
			||||||
  })
 | 
					  })
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user