Move all app configure tasks to separate view
This commit is contained in:
464
src/views/app.js
Normal file
464
src/views/app.js
Normal file
@@ -0,0 +1,464 @@
|
||||
'use strict';
|
||||
|
||||
/* global angular */
|
||||
/* global $ */
|
||||
/* global asyncSeries */
|
||||
|
||||
angular.module('Application').controller('AppController', ['$scope', '$location', '$timeout', '$interval', 'Client', function ($scope, $location, $timeout, $interval, Client) {
|
||||
Client.onReady(function () { if (!Client.getUserInfo().admin) $location.path('/'); });
|
||||
|
||||
var appId = $location.path().slice('/app/'.length);
|
||||
|
||||
$scope.app = null;
|
||||
$scope.ready = false;
|
||||
$scope.HOST_PORT_MIN = 1024;
|
||||
$scope.HOST_PORT_MAX = 65535;
|
||||
$scope.config = Client.getConfig();
|
||||
$scope.user = Client.getUserInfo();
|
||||
$scope.domains = [];
|
||||
$scope.groups = [];
|
||||
$scope.users = [];
|
||||
$scope.backupsEnabled = true;
|
||||
$scope.disableIndexingTemplate = '# Disable search engine indexing\n\nUser-agent: *\nDisallow: /';
|
||||
|
||||
$scope.display = {
|
||||
busy: false,
|
||||
error: {},
|
||||
success: false,
|
||||
|
||||
tags: '',
|
||||
label: '',
|
||||
icon: { data: null },
|
||||
|
||||
iconUrl: function () {
|
||||
if (!$scope.app) return '';
|
||||
|
||||
if ($scope.display.icon.data === '__original__') { // user clicked reset
|
||||
return $scope.app.iconUrl + '&original=true';
|
||||
} else if ($scope.display.icon.data) { // user uploaded icon
|
||||
return $scope.display.icon.data;
|
||||
} else { // current icon
|
||||
return $scope.app.iconUrl;
|
||||
}
|
||||
},
|
||||
|
||||
resetCustomIcon: function () {
|
||||
$scope.display.icon.data = '__original__';
|
||||
},
|
||||
|
||||
showCustomIconSelector: function () {
|
||||
$('#iconFileInput').click();
|
||||
},
|
||||
|
||||
show: function () {
|
||||
var app = $scope.app;
|
||||
|
||||
// translate for tag-input
|
||||
$scope.display.tags = app.tags ? app.tags.join(',') : '';
|
||||
|
||||
$scope.display.label = $scope.app.label || '';
|
||||
$scope.display.icon = { data: null };
|
||||
|
||||
$('#iconFileInput').get(0).onchange = function (event) {
|
||||
var fr = new FileReader();
|
||||
fr.onload = function () {
|
||||
$scope.$apply(function () {
|
||||
// var file = event.target.files[0];
|
||||
$scope.display.icon.data = fr.result;
|
||||
});
|
||||
};
|
||||
fr.readAsDataURL(event.target.files[0]);
|
||||
};
|
||||
},
|
||||
|
||||
submit: function () {
|
||||
$scope.display.busy = true;
|
||||
$scope.display.error = {};
|
||||
|
||||
// TODO break those apart
|
||||
Client.configureApp($scope.app.id, 'label', { label: $scope.display.label }, function (error) {
|
||||
if (error) return Client.error(error);
|
||||
|
||||
var tags = $scope.display.tags.split(',').map(function (t) { return t.trim(); }).filter(function (t) { return !!t; });
|
||||
|
||||
Client.configureApp($scope.app.id, 'tags', { tags: tags }, function (error) {
|
||||
if (error) return Client.error(error);
|
||||
|
||||
// skip if icon is unchanged
|
||||
if ($scope.display.icon.data === null) {
|
||||
$scope.display.busy = false;
|
||||
$scope.display.success = true;
|
||||
return;
|
||||
}
|
||||
|
||||
var icon;
|
||||
if ($scope.display.icon.data === '__original__') { // user reset the icon
|
||||
icon = '';
|
||||
} else if ($scope.display.icon.data) { // user loaded custom icon
|
||||
icon = $scope.display.icon.data.replace(/^data:image\/[a-z]+;base64,/, '');
|
||||
}
|
||||
|
||||
Client.configureApp($scope.app.id, 'icon', { icon: icon }, function (error) {
|
||||
if (error) return Client.error(error);
|
||||
|
||||
$scope.display.busy = false;
|
||||
$scope.display.success = true;
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
$scope.location = {
|
||||
busy: false,
|
||||
error: {},
|
||||
success: false,
|
||||
|
||||
domain: null,
|
||||
location: '',
|
||||
alternateDomains: [],
|
||||
portBindings: {},
|
||||
portBindingsEnabled: {},
|
||||
portBindingsInfo: {},
|
||||
|
||||
addAlternateDomain: function (event) {
|
||||
event.preventDefault();
|
||||
$scope.location.alternateDomains.push({
|
||||
domain: $scope.domains[0],
|
||||
subdomain: ''
|
||||
});
|
||||
},
|
||||
|
||||
delAlternateDomain: function (event, index) {
|
||||
event.preventDefault();
|
||||
$scope.location.alternateDomains.splice(index, 1);
|
||||
},
|
||||
|
||||
show: function () {
|
||||
var app = $scope.app;
|
||||
|
||||
$scope.location.location = app.location;
|
||||
$scope.location.domain = $scope.domains.filter(function (d) { return d.domain === app.domain; })[0];
|
||||
$scope.location.portBindingsInfo = angular.extend({}, app.manifest.tcpPorts, app.manifest.udpPorts); // Portbinding map only for information
|
||||
$scope.location.alternateDomains = app.alternateDomains.map(function (a) { return { subdomain: a.subdomain, domain: $scope.domains.filter(function (d) { return d.domain === a.domain; })[0] };});
|
||||
|
||||
// fill the portBinding structures. There might be holes in the app.portBindings, which signalizes a disabled port
|
||||
for (var env in $scope.location.portBindingsInfo) {
|
||||
if (app.portBindings && app.portBindings[env]) {
|
||||
$scope.location.portBindings[env] = app.portBindings[env];
|
||||
$scope.location.portBindingsEnabled[env] = true;
|
||||
} else {
|
||||
$scope.location.portBindings[env] = $scope.location.portBindingsInfo[env].defaultValue || 0;
|
||||
$scope.location.portBindingsEnabled[env] = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
submit: function () {
|
||||
$scope.location.busy = true;
|
||||
$scope.location.error = {};
|
||||
|
||||
// only use enabled ports from portBindings
|
||||
var portBindings = {};
|
||||
for (var env in $scope.location.portBindings) {
|
||||
if ($scope.location.portBindingsEnabled[env]) {
|
||||
portBindings[env] = $scope.location.portBindings[env];
|
||||
}
|
||||
}
|
||||
|
||||
var data = {
|
||||
location: $scope.location.location,
|
||||
domain: $scope.location.domain.domain,
|
||||
portBindings: portBindings,
|
||||
alternateDomains: $scope.location.alternateDomains.map(function (a) { return { subdomain: a.subdomain, domain: a.domain.domain };})
|
||||
};
|
||||
|
||||
Client.configureApp($scope.app.id, 'location', data, function (error) {
|
||||
if (error) return Client.error(error);
|
||||
|
||||
$scope.location.success = true;
|
||||
$scope.location.busy = false;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
$scope.access = {
|
||||
busy: false,
|
||||
error: {},
|
||||
success: false,
|
||||
|
||||
ftp: false,
|
||||
ssoAuth: false,
|
||||
accessRestrictionOption: 'any',
|
||||
accessRestriction: { users: [], groups: [] },
|
||||
|
||||
isAccessRestrictionValid: function () {
|
||||
var tmp = $scope.access.accessRestriction;
|
||||
return !!(tmp.users.length || tmp.groups.length);
|
||||
},
|
||||
|
||||
show: function () {
|
||||
var app = $scope.app;
|
||||
|
||||
$scope.access.ftp = app.manifest.addons.localstorage && app.manifest.addons.localstorage.ftp;
|
||||
$scope.access.ssoAuth = (app.manifest.addons['ldap'] || app.manifest.addons['oauth']) && app.sso;
|
||||
$scope.access.accessRestrictionOption = app.accessRestriction ? 'groups' : 'any';
|
||||
$scope.access.accessRestriction = { users: [], groups: [] };
|
||||
|
||||
if (app.accessRestriction) {
|
||||
var userSet = { };
|
||||
app.accessRestriction.users.forEach(function (uid) { userSet[uid] = true; });
|
||||
$scope.users.forEach(function (u) { if (userSet[u.id] === true) $scope.access.accessRestriction.users.push(u); });
|
||||
|
||||
var groupSet = { };
|
||||
app.accessRestriction.groups.forEach(function (gid) { groupSet[gid] = true; });
|
||||
$scope.groups.forEach(function (g) { if (groupSet[g.id] === true) $scope.access.accessRestriction.groups.push(g); });
|
||||
}
|
||||
},
|
||||
|
||||
submit: function () {
|
||||
$scope.access.busy = true;
|
||||
$scope.access.error = {};
|
||||
|
||||
var accessRestriction = null;
|
||||
if ($scope.access.accessRestrictionOption === 'groups') {
|
||||
accessRestriction = { users: [], groups: [] };
|
||||
accessRestriction.users = $scope.access.accessRestriction.users.map(function (u) { return u.id; });
|
||||
accessRestriction.groups = $scope.access.accessRestriction.groups.map(function (g) { return g.id; });
|
||||
}
|
||||
|
||||
Client.configureApp($scope.app.id, 'access_restriction', { accessRestriction: accessRestriction }, function (error) {
|
||||
if (error) return Client.error(error);
|
||||
|
||||
$scope.access.success = true;
|
||||
$scope.access.busy = false;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
$scope.resources = {
|
||||
busy: false,
|
||||
error: {},
|
||||
success: false,
|
||||
|
||||
memoryLimit: 0,
|
||||
memoryTicks: [],
|
||||
dataDir: null,
|
||||
dataDirEnabled: false,
|
||||
|
||||
show: function () {
|
||||
var app = $scope.app;
|
||||
|
||||
$scope.resources.memoryLimit = app.memoryLimit || app.manifest.memoryLimit || (256 * 1024 * 1024);
|
||||
$scope.resources.dataDirEnabled = !!app.dataDir;
|
||||
$scope.resources.dataDir = app.dataDir;
|
||||
|
||||
// create ticks starting from manifest memory limit. the memory limit here is currently split into ram+swap (and thus *2 below)
|
||||
// TODO: the *2 will overallocate since 4GB is max swap that cloudron itself allocates
|
||||
$scope.resources.memoryTicks = [];
|
||||
var npow2 = Math.pow(2, Math.ceil(Math.log($scope.config.memory)/Math.log(2)));
|
||||
for (var i = 256; i <= (npow2*2/1024/1024); i *= 2) {
|
||||
if (i >= (app.manifest.memoryLimit/1024/1024 || 0)) $scope.resources.memoryTicks.push(i * 1024 * 1024);
|
||||
}
|
||||
if (app.manifest.memoryLimit && $scope.resources.memoryTicks[0] !== app.manifest.memoryLimit) {
|
||||
$scope.resources.memoryTicks.unshift(app.manifest.memoryLimit);
|
||||
}
|
||||
},
|
||||
|
||||
submit: function () {
|
||||
$scope.resources.busy = true;
|
||||
$scope.resources.error = {};
|
||||
|
||||
var memoryLimit = $scope.resources.memoryLimit === $scope.resources.memoryTicks[0] ? 0 : $scope.resources.memoryLimit;
|
||||
|
||||
Client.configureApp($scope.app.id, 'memory_limit', { memoryLimit: memoryLimit }, function (error) {
|
||||
if (error) return Client.error(error);
|
||||
|
||||
$scope.resources.success = true;
|
||||
$scope.resources.busy = false;
|
||||
|
||||
// TODO handle data dir once we show it
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
$scope.email = {
|
||||
busy: false,
|
||||
error: {},
|
||||
success: false,
|
||||
|
||||
mailboxNameEnabled: false,
|
||||
mailboxName: '',
|
||||
domain: '',
|
||||
|
||||
show: function () {
|
||||
var app = $scope.app;
|
||||
|
||||
$scope.email.mailboxNameEnabled = app.mailboxName && (app.mailboxName.match(/\.app$/) === null);
|
||||
$scope.email.mailboxName = app.mailboxName || '';
|
||||
$scope.email.domain = $scope.domains.filter(function (d) { return d.domain === app.domain; })[0];
|
||||
},
|
||||
|
||||
submit: function () {
|
||||
$scope.email.busy = true;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.security = {
|
||||
busy: false,
|
||||
error: {},
|
||||
success: false,
|
||||
|
||||
robotsTxt: '',
|
||||
|
||||
show: function () {
|
||||
var app = $scope.app;
|
||||
|
||||
$scope.security.robotsTxt = app.robotsTxt;
|
||||
},
|
||||
|
||||
submit: function () {
|
||||
$scope.security.busy = true;
|
||||
$scope.security.error = {};
|
||||
|
||||
Client.configureApp($scope.app.id, 'robots_txt', { robotsTxt: $scope.security.robotsTxt }, function (error) {
|
||||
if (error) return Client.error(error);
|
||||
|
||||
$scope.security.success = true;
|
||||
$scope.security.busy = false;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
$scope.updates = {
|
||||
busy: false,
|
||||
error: {},
|
||||
success: false,
|
||||
|
||||
enableAutomaticUpdate: false,
|
||||
|
||||
show: function () {
|
||||
var app = $scope.app;
|
||||
|
||||
$scope.updates.enableAutomaticUpdate = app.enableAutomaticUpdate;
|
||||
},
|
||||
|
||||
submit: function () {
|
||||
$scope.updates.busy = true;
|
||||
$scope.updates.error = {};
|
||||
|
||||
Client.configureApp($scope.app.id, 'automatic_update', { enable: $scope.updates.enableAutomaticUpdate }, function (error) {
|
||||
if (error) return Client.error(error);
|
||||
|
||||
$scope.updates.success = true;
|
||||
$scope.updates.busy = false;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
$scope.backups = {
|
||||
busy: false,
|
||||
error: {},
|
||||
success: false,
|
||||
|
||||
enableBackup: false,
|
||||
|
||||
show: function () {
|
||||
var app = $scope.app;
|
||||
|
||||
$scope.backups.enableBackup = app.enableBackup;
|
||||
},
|
||||
|
||||
submit: function () {
|
||||
$scope.backups.busy = true;
|
||||
$scope.backups.error = {};
|
||||
|
||||
Client.configureApp($scope.app.id, 'automatic_backup', { enable: $scope.backups.enableBackup }, function (error) {
|
||||
if (error) return Client.error(error);
|
||||
|
||||
$scope.backups.success = true;
|
||||
$scope.backups.busy = false;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
function fetchUsers(callback) {
|
||||
Client.getUsers(function (error, users) {
|
||||
if (error) return callback(error);
|
||||
|
||||
// ensure we have something to work with in the access restriction dropdowns
|
||||
users.forEach(function (user) { user.display = user.username || user.email; });
|
||||
|
||||
$scope.users = users;
|
||||
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
function fetchGroups(callback) {
|
||||
Client.getGroups(function (error, groups) {
|
||||
if (error) return callback(error);
|
||||
|
||||
$scope.groups = groups;
|
||||
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
function getDomains(callback) {
|
||||
Client.getDomains(function (error, result) {
|
||||
if (error) return callback(error);
|
||||
|
||||
$scope.domains = result;
|
||||
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
function getBackupConfig(callback) {
|
||||
Client.getBackupConfig(function (error, backupConfig) {
|
||||
if (error) return callback(error);
|
||||
|
||||
$scope.backupEnabled = backupConfig.provider !== 'noop';
|
||||
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
||||
Client.onReady(function () {
|
||||
$scope.app = Client.getApp(appId, function (error, app) {
|
||||
if (error) return Client.error(error);
|
||||
|
||||
$scope.app = app;
|
||||
|
||||
asyncSeries([
|
||||
fetchUsers,
|
||||
fetchGroups,
|
||||
getDomains,
|
||||
getBackupConfig
|
||||
], function (error) {
|
||||
if (error) return Client.error(error);
|
||||
|
||||
$scope.display.show();
|
||||
$scope.location.show();
|
||||
$scope.resources.show();
|
||||
$scope.access.show();
|
||||
$scope.email.show();
|
||||
$scope.security.show();
|
||||
$scope.backups.show();
|
||||
$scope.updates.show();
|
||||
|
||||
$scope.ready = true;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// setup all the dialog focus handling
|
||||
['appConfigureModal', 'appUninstallModal', 'appUpdateModal', 'appRestoreModal', 'appInfoModal', 'appErrorModal'].forEach(function (id) {
|
||||
$('#' + id).on('shown.bs.modal', function () {
|
||||
$(this).find("[autofocus]:first").focus();
|
||||
});
|
||||
});
|
||||
|
||||
$('.modal-backdrop').remove();
|
||||
}]);
|
||||
Reference in New Issue
Block a user