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:
@@ -185,7 +185,7 @@
|
||||
<h4 class="modal-title">{{ 'app.archiveDialog.title' | tr:{ app: (app.label || app.fqdn) } }}</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p ng-bind-html="'app.archiveDialog.description' | tr:{ date: (uninstall.latestBackup.creationTime | prettyDate) }"></p>
|
||||
<p ng-bind-html="'app.archiveDialog.description' | tr:{ date: (uninstall.latestBackup.creationTime | prettyLongDate) }"></p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">{{ 'main.dialog.cancel' | tr }}</button>
|
||||
@@ -1744,7 +1744,7 @@
|
||||
<div class="col-md-12">
|
||||
<label class="control-label">{{ 'app.archive.title' | tr }}</label>
|
||||
<p>{{ 'app.archive.description' | tr }}</p>
|
||||
<p class="text-bold text-success" ng-show="uninstall.latestBackup" ng-bind-html="'app.archive.latestBackupInfo' | tr:{ date: (uninstall.latestBackup.creationTime | prettyDate) }"></p>
|
||||
<p class="text-bold text-success" ng-show="uninstall.latestBackup" ng-bind-html="'app.archive.latestBackupInfo' | tr:{ date: (uninstall.latestBackup.creationTime | prettyLongDate) }"></p>
|
||||
<p class="text-bold text-warning" ng-show="!uninstall.latestBackup" ng-bind-html="'app.archive.noBackup' | tr"></p>
|
||||
<button ng-disabled="!uninstall.latestBackup" class="btn btn-default pull-right" ng-click="uninstall.ask('archive')">{{ 'app.archive.action' | tr }}</button>
|
||||
</div>
|
||||
|
||||
@@ -451,39 +451,39 @@
|
||||
</div>
|
||||
|
||||
<!-- Modal archive restore -->
|
||||
<div class="modal fade" id="appCloneModal" tabindex="-1" role="dialog">
|
||||
<div class="modal fade" id="restoreArchiveModal" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title">{{ 'app.cloneDialog.title' | tr:{ app: app.fqdn } }}</h4>
|
||||
<h4 class="modal-title">{{ 'backups.restoreArchiveDialog.title' | tr }}</h4>
|
||||
</div>
|
||||
<div class="modal-body" style="padding: 0 15px">
|
||||
<p ng-bind-html="'app.cloneDialog.description' | tr:{ creationTime: (clone.archive.creationTime | prettyDate) }"></p>
|
||||
<form role="form" ng-submit="clone.submit()" autocomplete="off">
|
||||
<p ng-bind-html="'backups.restoreArchiveDialog.description' | tr:{ appId: archiveRestore.app.manifest.id, fqdn: archiveRestore.app.fqdn, creationTime: (archiveRestore.archive.creationTime | prettyLongDate) }"></p>
|
||||
<form role="form" ng-submit="archiveRestore.submit()" autocomplete="off">
|
||||
<fieldset>
|
||||
<div class="form-group" ng-class="{ 'has-error': clone.error.location.fqdn === clone.subdomain + '.' + clone.domain.domain }">
|
||||
<div class="form-group" ng-class="{ 'has-error': archiveRestore.error.location.fqdn === archiveRestore.subdomain + '.' + archiveRestore.domain.domain }">
|
||||
<label class="control-label" for="cloneLocationInput">{{ 'app.cloneDialog.location' | tr }}</label>
|
||||
<div ng-show="clone.error.location.fqdn === clone.subdomain + '.' + clone.domain.domain"><small>{{ clone.error.location.message }}</small></div>
|
||||
<div ng-show="archiveRestore.error.location.fqdn === archiveRestore.subdomain + '.' + archiveRestore.domain.domain"><small>{{ archiveRestore.error.location.message }}</small></div>
|
||||
<div class="input-group form-inline">
|
||||
<input type="text" class="form-control" ng-model="clone.subdomain" id="cloneLocationInput" name="location" placeholder="{{ 'appstore.installDialog.locationPlaceholder' | tr }}" autofocus>
|
||||
<input type="text" class="form-control" ng-model="archiveRestore.subdomain" id="cloneLocationInput" name="location" placeholder="{{ 'appstore.installDialog.locationPlaceholder' | tr }}" autofocus>
|
||||
<div class="input-group-btn">
|
||||
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
|
||||
<span>{{ '.' + clone.domain.domain }}</span>
|
||||
<span>{{ '.' + archiveRestore.domain.domain }}</span>
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-menu-right" role="menu">
|
||||
<li ng-repeat="domain in domains">
|
||||
<a href="" ng-click="clone.domain = domain">{{ domain.domain }}</a>
|
||||
<a href="" ng-click="archiveRestore.domain = domain">{{ domain.domain }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="has-error text-center" ng-show="clone.error.secondaryDomain">{{ clone.error.secondaryDomain }}</div>
|
||||
<div ng-repeat="(env, info) in clone.backup.manifest.httpPorts">
|
||||
<div class="has-error text-center" ng-show="archiveRestore.error.secondaryDomain">{{ archiveRestore.error.secondaryDomain }}</div>
|
||||
<div ng-repeat="(env, info) in archiveRestore.app.manifest.httpPorts">
|
||||
<ng-form name="secondaryDomainInfo_form">
|
||||
<div class="form-group" ng-class="{ 'has-error': (!secondaryDomainInfo_form.itemName{{$index}}.$dirty && clone.error.secondaryDomain) || (secondaryDomainInfo_form.itemName{{$index}}.$dirty && secondaryDomainInfo_form.itemName{{$index}}.$invalid) || (clone.error.location.fqdn === clone.secondaryDomains[env].subdomain + '.' + clone.secondaryDomains[env].domain.domain) }">
|
||||
<div class="form-group" ng-class="{ 'has-error': (!secondaryDomainInfo_form.itemName{{$index}}.$dirty && archiveRestore.error.secondaryDomain) || (secondaryDomainInfo_form.itemName{{$index}}.$dirty && secondaryDomainInfo_form.itemName{{$index}}.$invalid) || (archiveRestore.error.location.fqdn === archiveRestore.secondaryDomains[env].subdomain + '.' + archiveRestore.secondaryDomains[env].domain.domain) }">
|
||||
<label class="control-label" for="secondaryDomainInput{{env}}">
|
||||
{{ info.title }}
|
||||
<sup>
|
||||
@@ -491,18 +491,18 @@
|
||||
</sup>
|
||||
</label>
|
||||
|
||||
<div ng-show="clone.error.location.fqdn === clone.secondaryDomains[env].subdomain + '.' + clone.secondaryDomains[env].domain.domain"><small>{{ clone.error.location.message }}</small></div>
|
||||
<div ng-show="archiveRestore.error.location.fqdn === archiveRestore.secondaryDomains[env].subdomain + '.' + archiveRestore.secondaryDomains[env].domain.domain"><small>{{ archiveRestore.error.location.message }}</small></div>
|
||||
<div class="input-group form-inline">
|
||||
<input type="text" class="form-control" ng-model="clone.secondaryDomains[env].subdomain" name="location{{$index}}" placeholder="{{ 'app.location.locationPlaceholder' | tr }}" autofocus>
|
||||
<input type="text" class="form-control" ng-model="archiveRestore.secondaryDomains[env].subdomain" name="location{{$index}}" placeholder="{{ 'app.location.locationPlaceholder' | tr }}" autofocus>
|
||||
|
||||
<div class="input-group-btn">
|
||||
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
|
||||
<span>.{{ clone.secondaryDomains[env].domain.domain }}</span>
|
||||
<span>.{{ archiveRestore.secondaryDomains[env].domain.domain }}</span>
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-menu-right" role="menu">
|
||||
<li ng-repeat="domain in domains">
|
||||
<a href="" ng-click="clone.secondaryDomains[env].domain = domain">{{ domain.domain }}</a>
|
||||
<a href="" ng-click="archiveRestore.secondaryDomains[env].domain = domain">{{ domain.domain }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -511,21 +511,21 @@
|
||||
</ng-form>
|
||||
</div>
|
||||
|
||||
<p class="text-small text-warning" ng-show="clone.domain.provider === 'noop' || clone.domain.provider === 'manual'" ng-bind-html="'appstore.installDialog.manualWarning' | tr:{ location: ((clone.subdomain ? clone.subdomain + '.' : '') + clone.domain.domain) }"></p>
|
||||
<p class="text-small text-warning" ng-show="archiveRestore.domain.provider === 'noop' || archiveRestore.domain.provider === 'manual'" ng-bind-html="'appstore.installDialog.manualWarning' | tr:{ location: ((archiveRestore.subdomain ? archiveRestore.subdomain + '.' : '') + archiveRestore.domain.domain) }"></p>
|
||||
|
||||
<div class="has-error text-center" ng-show="clone.error.port">{{ clone.error.port }}</div>
|
||||
<div ng-repeat="(env, info) in clone.portInfo">
|
||||
<div class="has-error text-center" ng-show="archiveRestore.error.port">{{ archiveRestore.error.port }}</div>
|
||||
<div ng-repeat="(env, info) in archiveRestore.portInfo">
|
||||
<ng-form name="portInfo_form">
|
||||
<div class="form-group" ng-class="{ 'has-error': (!clone.itemName{{$index}}.$dirty && clone.error.port) || (portInfo_form.itemName{{$index}}.$dirty && portInfo_form.itemName{{$index}}.$invalid) }">
|
||||
<label class="control-label" for="inputPortInfo{{env}}"><input type="checkbox" ng-model="clone.portsEnabled[env]">
|
||||
<div class="form-group" ng-class="{ 'has-error': (!archiveRestore.itemName{{$index}}.$dirty && archiveRestore.error.port) || (portInfo_form.itemName{{$index}}.$dirty && portInfo_form.itemName{{$index}}.$invalid) }">
|
||||
<label class="control-label" for="inputPortInfo{{env}}"><input type="checkbox" ng-model="archiveRestore.portsEnabled[env]">
|
||||
{{ info.title }}
|
||||
<sup>
|
||||
<a popover-placement="top-right" popover-trigger="outsideClick" uib-popover="{{info.description}}"><i class="fa fa-question-circle"></i></a>
|
||||
</sup>
|
||||
<small style="padding-left: 5px;" ng-show="info.readOnly">{{ 'appstore.installDialog.portReadOnly' | tr }}</small>
|
||||
</label>
|
||||
<input type="number" class="form-control" ng-model="clone.ports[env]" ng-disabled="!clone.portsEnabled[env]" ng-readonly="info.readOnly" id="inputPortInfo{{env}}" later-name="itemName{{$index}}" min="{{hostPortMin}}" max="{{hostPortMax}}" required>
|
||||
<p class="text-small text-warning text-bold" ng-show="clone.domain.provider === 'cloudflare'">{{ 'appstore.installDialog.cloudflarePortWarning' | tr }} </p>
|
||||
<input type="number" class="form-control" ng-model="archiveRestore.ports[env]" ng-disabled="!archiveRestore.portsEnabled[env]" ng-readonly="info.readOnly" id="inputPortInfo{{env}}" later-name="itemName{{$index}}" min="{{hostPortMin}}" max="{{hostPortMax}}" required>
|
||||
<p class="text-small text-warning text-bold" ng-show="archiveRestore.domain.provider === 'cloudflare'">{{ 'appstore.installDialog.cloudflarePortWarning' | tr }} </p>
|
||||
</div>
|
||||
</ng-form>
|
||||
</div>
|
||||
@@ -535,7 +535,7 @@
|
||||
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">{{ 'main.dialog.cancel' | tr }}</button>
|
||||
<button type="button" class="btn btn-success" ng-click="clone.submit()"><i class="far fa-clone" ng-hide="clone.busy"></i><i class="fa fa-circle-notch fa-spin" ng-show="clone.busy"></i> {{ 'app.cloneDialog.cloneAction' | tr:{ dnsOverwrite: clone.needsOverwrite } }}</button>
|
||||
<button type="button" class="btn btn-success" ng-click="archiveRestore.submit()"><i class="fas fa-history" ng-hide="archiveRestore.busy"></i><i class="fa fa-circle-notch fa-spin" ng-show="archiveRestore.busy"></i> {{ 'backups.restoreArchiveDialog.restoreAction' | tr:{ dnsOverwrite: archiveRestore.needsOverwrite } }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -546,7 +546,7 @@
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title">{{ 'backups.deleteArchiveDialog.title' | tr:{ appTitle: archiveDelete.archive.appConfig.manifest.title, fqdn: archiveDelete.archive.appConfig.fqdn } }}</h4>
|
||||
<h4 class="modal-title">{{ 'backups.deleteArchiveDialog.title' | tr:{ appTitle: archiveDelete.app.manifest.title, fqdn: archiveDelete.app.fqdn } }}</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>{{ 'backups.deleteArchiveDialog.description' | tr }}</p>
|
||||
@@ -761,12 +761,12 @@
|
||||
<p ng-bind-html=" 'backups.archive.description' | tr "></p>
|
||||
|
||||
<div class="grid-item-top">
|
||||
<div class="row ng-hide" ng-show="!listArchives.ready">
|
||||
<div class="row ng-hide" ng-show="!archiveList.ready">
|
||||
<div class="col-lg-12 text-center">
|
||||
<h2><i class="fa fa-circle-notch fa-spin"></i></h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row animateMeOpacity ng-hide" ng-show="listArchives.ready">
|
||||
<div class="row animateMeOpacity ng-hide" ng-show="archiveList.ready">
|
||||
<div class="col-lg-12">
|
||||
<table class="table table-hover" style="margin: 0;">
|
||||
<thead>
|
||||
@@ -779,21 +779,21 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="archive in listArchives.archives">
|
||||
<tr ng-repeat="archive in archiveList.archives">
|
||||
<td>
|
||||
<img ng-src="{{ archive.iconUrl || 'img/appicon_fallback.png' }}" fallback-icon="img/appicon_fallback.png" onerror="imageErrorHandler(this)" height="48" width="48"/>
|
||||
</td>
|
||||
<td class="hand elide-table-cell" style="text-overflow: ellipsis; white-space: nowrap;" ng-click="clone.show(archive)">
|
||||
<td class="hand elide-table-cell" style="text-overflow: ellipsis; white-space: nowrap;" ng-click="archiveRestore.show(archive)">
|
||||
{{ archive.appConfig.fqdn }}
|
||||
</td>
|
||||
<td class="hand elide-table-cell" style="text-overflow: ellipsis; white-space: nowrap;" ng-click="clone.show(archive)">
|
||||
<td class="hand elide-table-cell" style="text-overflow: ellipsis; white-space: nowrap;" ng-click="archiveRestore.show(archive)">
|
||||
<span uib-tooltip="{{ archive.appConfig.manifest.id }}@{{ archive.appConfig.manifest.version }}">{{ archive.appConfig.manifest.title }}</span>
|
||||
</td>
|
||||
<td class="hand elide-table-cell" style="text-overflow: ellipsis; white-space: nowrap;" ng-click="clone.show(archive)">
|
||||
<td class="hand elide-table-cell" style="text-overflow: ellipsis; white-space: nowrap;" ng-click="archiveRestore.show(archive)">
|
||||
{{ archive.creationTime | prettyDate }}
|
||||
</td>
|
||||
<td class="text-right no-wrap" style="vertical-align: middle;">
|
||||
<button class="btn btn-xs btn-default" ng-click="clone.show(archive)" uib-tooltip="Restore Archive"><i class="fas fa-history"></i></button>
|
||||
<button class="btn btn-xs btn-default" ng-click="archiveRestore.show(archive)" uib-tooltip="Restore from Archive"><i class="fas fa-history"></i></button>
|
||||
<button class="btn btn-xs btn-danger" ng-click="archiveDelete.ask(archive)" uib-tooltip="Delete Archive"><i class="fa fa-trash-alt"></i></button>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -268,18 +268,18 @@ angular.module('Application').controller('BackupsController', ['$scope', '$locat
|
||||
}
|
||||
};
|
||||
|
||||
$scope.listArchives = {
|
||||
$scope.archiveList = {
|
||||
ready: false,
|
||||
archives: [],
|
||||
|
||||
fetch: function () {
|
||||
Client.listArchives(function (error, archives) {
|
||||
if (error) Client.error(error);
|
||||
$scope.listArchives.archives = archives;
|
||||
$scope.listArchives.ready = true;
|
||||
$scope.archiveList.archives = archives;
|
||||
$scope.archiveList.ready = true;
|
||||
|
||||
// ensure we use the full api oprigin
|
||||
$scope.listArchives.archives.forEach(a => {
|
||||
$scope.archiveList.archives.forEach(a => {
|
||||
a.iconUrl = window.cloudronApiOrigin + a.iconUrl;
|
||||
});
|
||||
});
|
||||
@@ -290,11 +290,13 @@ angular.module('Application').controller('BackupsController', ['$scope', '$locat
|
||||
busy: false,
|
||||
error: {},
|
||||
archive: null,
|
||||
app: null, // just for simpler access . it's a fake app object!
|
||||
|
||||
ask: function (archive) {
|
||||
$scope.archiveDelete.busy = false;
|
||||
$scope.archiveDelete.error = {};
|
||||
$scope.archiveDelete.archive = archive;
|
||||
$scope.archiveDelete.app = archive.appConfig;
|
||||
$('#archiveDeleteModal').modal('show');
|
||||
},
|
||||
|
||||
@@ -305,18 +307,20 @@ angular.module('Application').controller('BackupsController', ['$scope', '$locat
|
||||
Client.deleteArchive($scope.archiveDelete.archive.id, function (error) {
|
||||
$scope.archiveDelete.busy = false;
|
||||
if (error) return console.error('Unable to delete archive.', error.statusCode, error.message);
|
||||
$scope.listArchives.fetch();
|
||||
$scope.archiveList.fetch();
|
||||
$('#archiveDeleteModal').modal('hide');
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// keep in sync with app.js
|
||||
$scope.clone = {
|
||||
$scope.archiveRestore = {
|
||||
busy: false,
|
||||
error: {},
|
||||
|
||||
archive: null,
|
||||
app: null, // just for simpler access . it's a fake app object!
|
||||
|
||||
subdomain: '',
|
||||
domain: null,
|
||||
secondaryDomains: {},
|
||||
@@ -325,6 +329,7 @@ angular.module('Application').controller('BackupsController', ['$scope', '$locat
|
||||
ports: {},
|
||||
portsEnabled: {},
|
||||
portInfo: {},
|
||||
accessRestriction: { users: [], groups: [] },
|
||||
|
||||
init: function () {
|
||||
Client.getDomains(function (error, domains) {
|
||||
@@ -334,61 +339,69 @@ angular.module('Application').controller('BackupsController', ['$scope', '$locat
|
||||
},
|
||||
|
||||
show: function (archive) {
|
||||
$scope.clone.error = {};
|
||||
$scope.clone.archive = archive;
|
||||
const app = archive.appConfig;
|
||||
$scope.archiveRestore.error = {};
|
||||
$scope.archiveRestore.archive = archive;
|
||||
const manifest = archive.appConfig.manifest;
|
||||
$scope.clone.domain = $scope.domains.find(function (d) { return app.domain === d.domain; }); // pre-select the app's domain
|
||||
|
||||
$scope.clone.needsOverwrite = false;
|
||||
$scope.clone.overwriteDns = false;
|
||||
$scope.archiveRestore.app = archive.appConfig;
|
||||
$scope.archiveRestore.subdomain = $scope.archiveRestore.app.subdomain;
|
||||
$scope.archiveRestore.domain = $scope.domains.find(function (d) { return $scope.archiveRestore.app.domain === d.domain; }); // try to pre-select the app's domain
|
||||
|
||||
$scope.clone.secondaryDomains = {};
|
||||
$scope.archiveRestore.needsOverwrite = false;
|
||||
$scope.archiveRestore.overwriteDns = false;
|
||||
|
||||
$scope.archiveRestore.secondaryDomains = {};
|
||||
|
||||
var httpPorts = manifest.httpPorts || {};
|
||||
for (var env2 in httpPorts) {
|
||||
$scope.clone.secondaryDomains[env2] = {
|
||||
$scope.archiveRestore.secondaryDomains[env2] = {
|
||||
subdomain: httpPorts[env2].defaultValue || '',
|
||||
domain: $scope.clone.domain
|
||||
domain: $scope.archiveRestore.domain
|
||||
};
|
||||
}
|
||||
|
||||
$scope.clone.portInfo = angular.extend({}, manifest.tcpPorts, manifest.udpPorts); // Portbinding map only for information
|
||||
$scope.archiveRestore.portInfo = angular.extend({}, manifest.tcpPorts, manifest.udpPorts); // Portbinding map only for information
|
||||
// set default ports
|
||||
for (var env in $scope.clone.portInfo) {
|
||||
$scope.clone.ports[env] = $scope.clone.portInfo[env].defaultValue || 0;
|
||||
$scope.clone.portsEnabled[env] = true;
|
||||
for (var env in $scope.archiveRestore.portInfo) {
|
||||
if ($scope.archiveRestore.app.portBindings[env]) { // was enabled in the app
|
||||
$scope.archiveRestore.ports[env] = $scope.archiveRestore.app.portBindings[env].hostPort;
|
||||
$scope.archiveRestore.portsEnabled[env] = true;
|
||||
} else {
|
||||
$scope.archiveRestore.ports[env] = $scope.archiveRestore.portInfo[env].defaultValue || 0;
|
||||
$scope.archiveRestore.portsEnabled[env] = false;
|
||||
}
|
||||
}
|
||||
|
||||
$('#appCloneModal').modal('show');
|
||||
$('#restoreArchiveModal').modal('show');
|
||||
},
|
||||
|
||||
submit: function () {
|
||||
$scope.clone.busy = true;
|
||||
$scope.archiveRestore.busy = true;
|
||||
|
||||
const app = $scope.archiveRestore.archive.appConfig;
|
||||
|
||||
var secondaryDomains = {};
|
||||
for (var env2 in $scope.clone.secondaryDomains) {
|
||||
for (var env2 in $scope.archiveRestore.secondaryDomains) {
|
||||
secondaryDomains[env2] = {
|
||||
subdomain: $scope.clone.secondaryDomains[env2].subdomain,
|
||||
domain: $scope.clone.secondaryDomains[env2].domain.domain
|
||||
subdomain: $scope.archiveRestore.secondaryDomains[env2].subdomain,
|
||||
domain: $scope.archiveRestore.secondaryDomains[env2].domain.domain
|
||||
};
|
||||
}
|
||||
|
||||
// only use enabled ports
|
||||
var finalPorts = {};
|
||||
for (var env in $scope.clone.ports) {
|
||||
if ($scope.clone.portsEnabled[env]) {
|
||||
finalPorts[env] = $scope.clone.ports[env];
|
||||
for (var env in $scope.archiveRestore.ports) {
|
||||
if ($scope.archiveRestore.portsEnabled[env]) {
|
||||
finalPorts[env] = $scope.archiveRestore.ports[env];
|
||||
}
|
||||
}
|
||||
|
||||
var data = {
|
||||
subdomain: $scope.clone.subdomain,
|
||||
domain: $scope.clone.domain.domain,
|
||||
subdomain: $scope.archiveRestore.subdomain,
|
||||
domain: $scope.archiveRestore.domain.domain,
|
||||
secondaryDomains: secondaryDomains,
|
||||
ports: finalPorts,
|
||||
backupId: $scope.clone.archive.backupId,
|
||||
overwriteDns: $scope.clone.overwriteDns
|
||||
overwriteDns: $scope.archiveRestore.overwriteDns,
|
||||
};
|
||||
|
||||
var allDomains = [{ domain: data.domain, subdomain: data.subdomain }].concat(Object.keys(secondaryDomains).map(function (k) {
|
||||
@@ -398,7 +411,7 @@ angular.module('Application').controller('BackupsController', ['$scope', '$locat
|
||||
};
|
||||
}));
|
||||
async.eachSeries(allDomains, function (domain, callback) {
|
||||
if ($scope.clone.overwriteDns) return callback();
|
||||
if ($scope.archiveRestore.overwriteDns) return callback();
|
||||
|
||||
Client.checkDNSRecords(domain.domain, domain.subdomain, function (error, result) {
|
||||
if (error) return callback(error);
|
||||
@@ -410,8 +423,8 @@ angular.module('Application').controller('BackupsController', ['$scope', '$locat
|
||||
return callback({ type: 'provider', fqdn: fqdn, message: result.error.message });
|
||||
}
|
||||
if (result.needsOverwrite) {
|
||||
$scope.clone.needsOverwrite = true;
|
||||
$scope.clone.overwriteDns = true;
|
||||
$scope.archiveRestore.needsOverwrite = true;
|
||||
$scope.archiveRestore.overwriteDns = true;
|
||||
return callback({ type: 'externally_exists', fqdn: fqdn, message: 'DNS Record already exists. Confirm that the domain is not in use for services external to Cloudron' });
|
||||
}
|
||||
|
||||
@@ -420,29 +433,27 @@ angular.module('Application').controller('BackupsController', ['$scope', '$locat
|
||||
}, function (error) {
|
||||
if (error) {
|
||||
if (error.type) {
|
||||
$scope.clone.error.location = error;
|
||||
$scope.clone.busy = false;
|
||||
$scope.archiveRestore.error.location = error;
|
||||
$scope.archiveRestore.busy = false;
|
||||
} else {
|
||||
Client.error(error);
|
||||
}
|
||||
|
||||
$scope.clone.error.location = error;
|
||||
$scope.clone.busy = false;
|
||||
$scope.archiveRestore.error.location = error;
|
||||
$scope.archiveRestore.busy = false;
|
||||
return;
|
||||
}
|
||||
|
||||
const app = $scope.clone.archive.appConfig;
|
||||
|
||||
Client.installApp(app.manifest.id, app.manifest, data, function (error/*, clonedApp */) {
|
||||
$scope.clone.busy = false;
|
||||
Client.unarchiveApp($scope.archiveRestore.archive.id, data, function (error/*, newApp */) {
|
||||
$scope.archiveRestore.busy = false;
|
||||
|
||||
if (error) {
|
||||
var errorMessage = error.message.toLowerCase();
|
||||
if (errorMessage.indexOf('port') !== -1) {
|
||||
$scope.clone.error.port = error.message;
|
||||
$scope.archiveRestore.error.port = error.message;
|
||||
} else if (error.message.indexOf('location') !== -1 || error.message.indexOf('subdomain') !== -1) {
|
||||
// TODO extract fqdn from error message, currently we just set it always to the main location
|
||||
$scope.clone.error.location = { type: 'internally_exists', fqdn: data.subdomain + '.' + data.domain, message: error.message };
|
||||
$scope.archiveRestore.error.location = { type: 'internally_exists', fqdn: data.subdomain + '.' + data.domain, message: error.message };
|
||||
$('#cloneLocationInput').focus();
|
||||
} else {
|
||||
Client.error(error);
|
||||
@@ -450,7 +461,7 @@ angular.module('Application').controller('BackupsController', ['$scope', '$locat
|
||||
return;
|
||||
}
|
||||
|
||||
$('#appCloneModal').modal('hide');
|
||||
$('#restoreArchiveModal').modal('hide');
|
||||
|
||||
$location.path('/apps');
|
||||
});
|
||||
@@ -1049,7 +1060,7 @@ angular.module('Application').controller('BackupsController', ['$scope', '$locat
|
||||
fetchBackups();
|
||||
getBackupConfig();
|
||||
|
||||
$scope.listArchives.fetch();
|
||||
$scope.archiveList.fetch();
|
||||
|
||||
$scope.manualBackupApps = Client.getInstalledApps().filter(function (app) { return app.type !== APP_TYPES.LINK && !app.enableBackup; });
|
||||
|
||||
@@ -1057,7 +1068,7 @@ angular.module('Application').controller('BackupsController', ['$scope', '$locat
|
||||
$scope.createBackup.init();
|
||||
$scope.cleanupBackups.init();
|
||||
$scope.backupPolicy.init();
|
||||
$scope.clone.init();
|
||||
$scope.archiveRestore.init();
|
||||
|
||||
getBackupTasks();
|
||||
getCleanupTasks();
|
||||
|
||||
Reference in New Issue
Block a user