diff --git a/dashboard/src/components/app/Backups.vue b/dashboard/src/components/app/Backups.vue index 7ad3dc5e7..fdf3dbe06 100644 --- a/dashboard/src/components/app/Backups.vue +++ b/dashboard/src/components/app/Backups.vue @@ -14,10 +14,12 @@ import AppRestoreDialog from '../AppRestoreDialog.vue'; import SettingsItem from '../SettingsItem.vue'; import AppsModel from '../../models/AppsModel.js'; import BackupsModel from '../../models/BackupsModel.js'; +import BackupTargetsModel from '../../models/BackupTargetsModel.js'; import TasksModel from '../../models/TasksModel.js'; const appsModel = AppsModel.create(); const backupsModel = BackupsModel.create(); +const backupTargetsModel = BackupTargetsModel.create(); const tasksModel = TasksModel.create(); const props = defineProps([ 'app' ]); @@ -154,26 +156,21 @@ function getDownloadLink(backup) { } async function onDownloadConfig(backup) { - const [error, backupConfig] = await backupsModel.getConfig(); + const [error, backupTarget] = await backupTargetsModel.get(backup.targetId); if (error) return console.error(error); // secrets and tokens already come with placeholder characters we remove them const tmp = { remotePath: backup.remotePath, - encrypted: !!backupConfig.password // we add this just to help the import UI + encrypted: !!backupTarget.password, // we add this just to help the import UI + encryptedFilenames: !!backupTarget.encryptedFilenames }; - Object.keys(backupConfig).forEach(k => { - const v = backupConfig[k]; - if (v && typeof v === 'object') { // to hide mountOptions.password and the likes - tmp[k] = {}; - Object.keys(v).forEach(function (j) { - if (v[j] !== SECRET_PLACEHOLDER) tmp[k][j] = v[j]; - }); - } else { - if (backupConfig[k] !== SECRET_PLACEHOLDER) tmp[k] = v; - } - }); + console.log(backupTarget); + + for (const k of ['provider', 'config', 'limits', 'format']) { + tmp[k] = backupTarget[k]; + } const filename = `${props.app.fqdn}-backup-config-${(new Date(backup.creationTime)).toISOString().split('T')[0]}.json`; download(filename, JSON.stringify(tmp, null, 4)); diff --git a/dashboard/src/models/BackupTargetsModel.js b/dashboard/src/models/BackupTargetsModel.js new file mode 100644 index 000000000..90e75787d --- /dev/null +++ b/dashboard/src/models/BackupTargetsModel.js @@ -0,0 +1,161 @@ + +import { fetcher } from '@cloudron/pankow'; +import { API_ORIGIN } from '../constants.js'; + +function create() { + const accessToken = localStorage.token; + + return { + async list() { + const page = 1; + const per_page = 1000; + + let error, result; + try { + result = await fetcher.get(`${API_ORIGIN}/api/v1/backup_targets`, { page, per_page, access_token: accessToken }); + } catch (e) { + error = e; + } + + if (error || result.status !== 200) return [error || result]; + return [null, result.body.backupTargets]; + }, + async add(label, format, provider, config) { + let error, result; + try { + result = await fetcher.post(`${API_ORIGIN}/api/v1/backup_targets`, { label, format, provider, config }, { access_token: accessToken }); + } catch (e) { + error = e; + } + + if (error || result.status !== 200) return [error || result]; + return [null, result.body.id]; + }, + async get(id) { + let error, result; + try { + result = await fetcher.get(`${API_ORIGIN}/api/v1/backup_targets/${id}`, { access_token: accessToken }); + } catch (e) { + error = e; + } + + if (error || result.status !== 200) return [error || result]; + + return [null, result.body]; + }, + async del(id) { + let error, result; + try { + result = await fetcher.del(`${API_ORIGIN}/api/v1/backup_targets/${id}`, {}, { access_token: accessToken }); + } catch (e) { + error = e; + } + + if (error || result.status !== 204) return [error || result]; + return [null]; + }, + async createBackup(id) { + let error, result; + try { + result = await fetcher.post(`${API_ORIGIN}/api/v1/backup_targets/${id}/create_backup`, {}, { access_token: accessToken }); + } catch (e) { + error = e; + } + + if (error || result.status !== 202) return [error || result]; + return [null, result.body.taskId]; + }, + async setPrimary(id) { + let error, result; + try { + result = await fetcher.post(`${API_ORIGIN}/api/v1/backup_targets/${id}/primary`, {}, { access_token: accessToken }); + } catch (e) { + error = e; + } + + if (error || result.status !== 200) return [error || result]; + return [null]; + }, + async setRetention(id, retention) { + let error, result; + try { + result = await fetcher.post(`${API_ORIGIN}/api/v1/backup_targets/${id}/retention`, { retention }, { access_token: accessToken }); + } catch (e) { + error = e; + } + + if (error || result.status !== 200) return [error || result]; + return [null]; + }, + async setLimits(id, limits) { + let error, result; + try { + result = await fetcher.post(`${API_ORIGIN}/api/v1/backup_targets/${id}/limits`, { limits }, { access_token: accessToken }); + } catch (e) { + error = e; + } + + if (error || result.status !== 200) return [error || result]; + return [null]; + }, + async setSchedule(id, schedule) { + let error, result; + try { + result = await fetcher.post(`${API_ORIGIN}/api/v1/backup_targets/${id}/schedule`, { schedule }, { access_token: accessToken }); + } catch (e) { + error = e; + } + + if (error || result.status !== 200) return [error || result]; + return [null]; + }, + async setConfig(id, config) { + let error, result; + try { + result = await fetcher.post(`${API_ORIGIN}/api/v1/backup_targets/${id}/config`, { config }, { access_token: accessToken }); + } catch (e) { + error = e; + } + + if (error || result.status !== 200) return [error || result]; + return [null]; + }, + async cleanup(id) { + let error, result; + try { + result = await fetcher.post(`${API_ORIGIN}/api/v1/backup_targets/${id}/cleanup`, {}, { access_token: accessToken }); + } catch (e) { + error = e; + } + + if (error || result.status !== 202) return [error || result]; + return [null, result.body.taskId]; + }, + async mountStatus(id) { + let error, result; + try { + result = await fetcher.get(`${API_ORIGIN}/api/v1/backup_targets/${id}/mount_status`, { access_token: accessToken }); + } catch (e) { + error = e; + } + + if (error || result.status !== 200) return [error || result]; + return [null, result.body]; + }, + async remount(id) { + let error, result; + try { + result = await fetcher.post(`${API_ORIGIN}/api/v1/backup_targets/${id}/remount`, {}, { access_token: accessToken }); + } catch (e) { + error = e; + } + + if (error || result.status !== 202) return [error || result]; + return [null, result.body]; + }, + }; +} + +export default { + create, +}; diff --git a/dashboard/src/models/BackupsModel.js b/dashboard/src/models/BackupsModel.js index 17053e15a..7618b88f9 100644 --- a/dashboard/src/models/BackupsModel.js +++ b/dashboard/src/models/BackupsModel.js @@ -20,18 +20,7 @@ function create() { if (error || result.status !== 200) return [error || result]; return [null, result.body.backups]; }, - async create() { - let error, result; - try { - result = await fetcher.post(`${API_ORIGIN}/api/v1/backups/create`, {}, { access_token: accessToken }); - } catch (e) { - error = e; - } - - if (error || result.status !== 202) return [error || result]; - return [null, result.body.taskId]; - }, - async edit(id, label, preserveSecs) { + async update(id, label, preserveSecs) { // if preserveSecs === -1 we will keep it let error, result; try { @@ -43,94 +32,15 @@ function create() { if (error || result.status !== 200) return [error || result]; return [null]; }, - async getConfig() { + async get(id) { let error, result; try { - result = await fetcher.get(`${API_ORIGIN}/api/v1/backups/config`, { access_token: accessToken }); + result = await fetcher.get(`${API_ORIGIN}/api/v1/backups/${id}`, { access_token: accessToken }); } catch (e) { error = e; } if (error || result.status !== 200) return [error || result]; - - // ensure we have objects - if (!result.body.mountOptions) result.body.mountOptions = {}; - if (!result.body.limits) result.body.limits = {}; - - return [null, result.body]; - }, - async setConfig(config, limits) { - let error, result; - try { - result = await fetcher.post(`${API_ORIGIN}/api/v1/backups/config/storage`, config, { access_token: accessToken }); - } catch (e) { - error = e; - } - - if (error || result.status !== 200) return [error || result]; - - try { - result = await fetcher.post(`${API_ORIGIN}/api/v1/backups/config/limits`, limits, { access_token: accessToken }); - } catch (e) { - error = e; - } - - if (error || result.status !== 200) return [error || result]; - return [null]; - }, - async getPolicy() { - let error, result; - try { - result = await fetcher.get(`${API_ORIGIN}/api/v1/backups/policy`, { access_token: accessToken }); - } catch (e) { - error = e; - } - - if (error || result.status !== 200) return [error || result]; - return [null, result.body.policy]; - }, - async setPolicy(policy) { - let error, result; - try { - result = await fetcher.post(`${API_ORIGIN}/api/v1/backups/policy`, policy, { access_token: accessToken }); - } catch (e) { - error = e; - } - - if (error || result.status !== 200) return [error || result]; - return [null]; - }, - async cleanup() { - let error, result; - try { - result = await fetcher.post(`${API_ORIGIN}/api/v1/backups/cleanup`, {}, { access_token: accessToken }); - } catch (e) { - error = e; - } - - if (error || result.status !== 202) return [error || result]; - return [null, result.body.taskId]; - }, - async mountStatus() { - let error, result; - try { - result = await fetcher.get(`${API_ORIGIN}/api/v1/backups/mount_status`, { access_token: accessToken }); - } catch (e) { - error = e; - } - - if (error || result.status !== 200) return [error || result]; - return [null, result.body]; - }, - async remount() { - let error, result; - try { - result = await fetcher.post(`${API_ORIGIN}/api/v1/backups/remount`, {}, { access_token: accessToken }); - } catch (e) { - error = e; - } - - if (error || result.status !== 202) return [error || result]; return [null, result.body]; }, }; diff --git a/src/backuptargets.js b/src/backuptargets.js index a936c0104..d799f89c8 100644 --- a/src/backuptargets.js +++ b/src/backuptargets.js @@ -78,10 +78,10 @@ function postProcess(result) { result.config.rootPath = getRootPath(result.provider, result.config, paths.MANAGED_BACKUP_MOUNT_DIR); result.config.provider = result.provider; // this allows api backends to identify the real provider - result.limits = result.limitsJson ? safe.JSON.parse(result.limitsJson) : {}; + result.limits = safe.JSON.parse(result.limitsJson) || {}; delete result.limitsJson; - result.retention = result.retentionJson ? safe.JSON.parse(result.retentionJson) : {}; + result.retention = safe.JSON.parse(result.retentionJson) || {}; delete result.retentionJson; result.encryption = result.encryptionJson ? safe.JSON.parse(result.encryptionJson) : null;