archive: implement unarchive
made a separate route instead of reusing install route. this was because we want to copy over all the old app config as much as possible.
This commit is contained in:
@@ -6,15 +6,18 @@ exports = module.exports = {
|
||||
add,
|
||||
list,
|
||||
listBackupIds,
|
||||
del
|
||||
del,
|
||||
unarchive
|
||||
};
|
||||
|
||||
const assert = require('assert'),
|
||||
const apps = require('./apps.js'),
|
||||
assert = require('assert'),
|
||||
BoxError = require('./boxerror.js'),
|
||||
database = require('./database.js'),
|
||||
eventlog = require('./eventlog.js'),
|
||||
safe = require('safetydance'),
|
||||
uuid = require('uuid');
|
||||
uuid = require('uuid'),
|
||||
_ = require('underscore');
|
||||
|
||||
const ARCHIVE_FIELDS = [ 'id', 'backupId', 'creationTime', 'appConfigJson', '(icon IS NOT NULL) AS hasIcon', '(appStoreIcon IS NOT NULL) AS hasAppStoreIcon' ];
|
||||
|
||||
@@ -104,3 +107,32 @@ async function del(archive, auditSource) {
|
||||
|
||||
await eventlog.add(eventlog.ACTION_ARCHIVES_DEL, auditSource, { id: archive.id, backupId: archive.backupId });
|
||||
}
|
||||
|
||||
async function unarchive(archive, data, auditSource) {
|
||||
assert.strictEqual(typeof archive, 'object');
|
||||
assert.strictEqual(typeof data, 'object');
|
||||
assert(auditSource && typeof auditSource === 'object');
|
||||
|
||||
const appConfig = archive.appConfig;
|
||||
|
||||
const dolly = _.pick(appConfig, 'appStoreId', 'manifest', 'memoryLimit', 'cpuQuota', 'crontab', 'reverseProxyConfig', 'env', 'servicesConfig',
|
||||
'tags', 'label', 'enableMailbox', 'mailboxDisplayName', 'mailboxName', 'mailboxDomain', 'enableInbox', 'inboxName', 'inboxDomain', 'devices',
|
||||
'enableTurn', 'enableRedis', 'mounts', 'enableBackup', 'enableAutomaticUpdate', 'accessRestriction', 'operators', 'sso');
|
||||
|
||||
// intentionally not filled up: redirectDomain, aliasDomains, mailboxDomain
|
||||
const newAppData = Object.assign(dolly, {
|
||||
// from request
|
||||
subdomain: data.subdomain,
|
||||
domain: data.domain,
|
||||
secondaryDomains: data.secondaryDomains || {},
|
||||
ports: data.ports || null,
|
||||
overwriteDns: 'overwriteDns' in data ? data.overwriteDns : false,
|
||||
mailboxDomain: data.domain, // archive's mailboxDomain may not exist
|
||||
|
||||
// from the archive
|
||||
icon: archive.icon,
|
||||
backupId: archive.backupId,
|
||||
});
|
||||
|
||||
return await apps.install(newAppData, auditSource);
|
||||
}
|
||||
|
||||
@@ -185,8 +185,6 @@ async function install(req, res, next) {
|
||||
|
||||
if ('enableTurn' in data && typeof data.enableTurn !== 'boolean') return next(new HttpError(400, 'enableTurn must be boolean'));
|
||||
|
||||
if ('backupId' in data && typeof data.backupId !== 'string') return next(new HttpError(400, 'backupId must be non-empty string'));
|
||||
|
||||
let [error, result] = await safe(appstore.downloadManifest(data.appStoreId, data.manifest));
|
||||
if (error) return next(BoxError.toHttpError(error));
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ exports = module.exports = {
|
||||
get,
|
||||
getIcon,
|
||||
del,
|
||||
unarchive
|
||||
};
|
||||
|
||||
const assert = require('assert'),
|
||||
@@ -67,3 +68,28 @@ async function del(req, res, next) {
|
||||
|
||||
next(new HttpSuccess(204));
|
||||
}
|
||||
|
||||
async function unarchive(req, res, next) {
|
||||
assert.strictEqual(typeof req.params.id, 'string');
|
||||
assert.strictEqual(typeof req.resource, 'object');
|
||||
assert.strictEqual(typeof req.body, 'object');
|
||||
|
||||
const data = req.body;
|
||||
|
||||
// required
|
||||
if (typeof data.subdomain !== 'string') return next(new HttpError(400, 'subdomain is required'));
|
||||
if (typeof data.domain !== 'string') return next(new HttpError(400, 'domain is required'));
|
||||
|
||||
// optional
|
||||
if (('ports' in data) && typeof data.ports !== 'object') return next(new HttpError(400, 'ports must be an object'));
|
||||
|
||||
if ('secondaryDomains' in data) {
|
||||
if (!data.secondaryDomains || typeof data.secondaryDomains !== 'object') return next(new HttpError(400, 'secondaryDomains must be an object'));
|
||||
if (Object.keys(data.secondaryDomains).some(function (key) { return typeof data.secondaryDomains[key].domain !== 'string' || typeof data.secondaryDomains[key].subdomain !== 'string'; })) return next(new HttpError(400, 'secondaryDomain object must contain domain and subdomain strings'));
|
||||
}
|
||||
|
||||
const [error, result] = await safe(archives.unarchive(req.resource, req.body, AuditSource.fromRequest(req)));
|
||||
if (error) return next(BoxError.toHttpError(error));
|
||||
|
||||
next(new HttpSuccess(202, { id: result.id, taskId: result.taskId }));
|
||||
}
|
||||
|
||||
@@ -162,10 +162,11 @@ async function initializeExpressSync() {
|
||||
router.post('/api/v1/backups/:backupId', json, token, authorizeAdmin, routes.backups.update);
|
||||
|
||||
// app archive routes
|
||||
router.get ('/api/v1/archives', token, authorizeAdmin, routes.archives.list);
|
||||
router.get ('/api/v1/archives/:id', token, authorizeAdmin, routes.archives.load, routes.archives.get);
|
||||
router.del ('/api/v1/archives/:id', token, authorizeAdmin, routes.archives.load, routes.archives.del);
|
||||
router.get ('/api/v1/archives/:id/icon', routes.archives.load, routes.archives.getIcon);
|
||||
router.get ('/api/v1/archives', token, authorizeAdmin, routes.archives.list);
|
||||
router.get ('/api/v1/archives/:id', token, authorizeAdmin, routes.archives.load, routes.archives.get);
|
||||
router.del ('/api/v1/archives/:id', token, authorizeAdmin, routes.archives.load, routes.archives.del);
|
||||
router.post('/api/v1/archives/:id/unarchive', json, token, authorizeAdmin, routes.archives.load, routes.archives.unarchive);
|
||||
router.get ('/api/v1/archives/:id/icon', routes.archives.load, routes.archives.getIcon);
|
||||
|
||||
// working off the user behind the provided token
|
||||
router.get ('/api/v1/profile', token, authorizeUser, routes.profile.get);
|
||||
|
||||
Reference in New Issue
Block a user