Files
cloudron-box/webadmin/src/views/settings.js

603 lines
21 KiB
JavaScript
Raw Normal View History

'use strict';
2016-06-28 13:45:50 -05:00
angular.module('Application').controller('SettingsController', ['$scope', '$location', '$rootScope', 'Client', 'AppStore', function ($scope, $location, $rootScope, Client, AppStore) {
Client.onReady(function () { if (!Client.getUserInfo().admin) $location.path('/'); });
$scope.client = Client;
$scope.user = Client.getUserInfo();
$scope.config = Client.getConfig();
2016-09-22 16:09:52 +02:00
$scope.backupConfig = {};
$scope.dnsConfig = {};
$scope.expectedDnsRecords = {};
$scope.expectedDnsRecordsTypes = [
{ name: 'DKIM', value: 'dkim' },
{ name: 'SPF', value: 'spf' }
];
2016-07-26 15:23:10 +02:00
$scope.appstoreConfig = {};
2016-08-30 22:12:07 -07:00
$scope.mailConfig = null;
$scope.lastBackup = null;
$scope.backups = [];
2016-06-30 17:40:18 -05:00
$scope.currency = null;
2016-06-28 13:45:50 -05:00
$scope.availableRegions = [];
$scope.currentRegionSlug = null;
2016-06-28 14:36:19 -05:00
$scope.availablePlans = [];
$scope.currentPlan = null;
2016-06-28 13:45:50 -05:00
2016-10-28 15:28:48 +02:00
// List is from http://docs.aws.amazon.com/general/latest/gr/rande.html#s3_region
$scope.s3Regions = [
{ name: 'US East (N. Virginia)', value: 'us-east-1' },
{ name: 'US East (Ohio)', value: 'us-east-2' },
{ name: 'US West (N. California)', value: 'us-west-1' },
{ name: 'US West (Oregon)', value: 'us-west-2' },
{ name: 'Asia Pacific (Mumbai)', value: 'ap-south-1' },
{ name: 'Asia Pacific (Seoul)', value: 'ap-northeast-2' },
{ name: 'Asia Pacific (Singapore)', value: 'ap-southeast-1' },
{ name: 'Asia Pacific (Sydney)', value: 'ap-southeast-2' },
{ name: 'Asia Pacific (Tokyo)', value: 'ap-northeast-1' },
{ name: 'EU (Frankfurt)', value: 'eu-central-1' },
{ name: 'EU (Ireland)', value: 'eu-west-1' },
{ name: 'South America (São Paulo)', value: 'sa-east-1' }
];
2016-06-28 14:36:19 -05:00
$scope.planChange = {
2016-06-28 13:45:50 -05:00
busy: false,
2016-06-28 14:02:45 -05:00
error: {},
2016-06-30 10:27:29 -05:00
password: '',
requestedPlan: null,
showChangePlan: function () {
$('#planChangeModal').modal('show');
},
planChangeReset: function () {
$scope.planChange.error.password = null;
$scope.planChange.password = '';
$scope.planChangeForm.$setPristine();
$scope.planChangeForm.$setUntouched();
},
doChangePlan: function () {
$scope.planChange.busy = true;
var options = {
size: $scope.planChange.requestedPlan.slug,
name: $scope.planChange.requestedPlan.name,
price: $scope.planChange.requestedPlan.price,
region: $scope.currentRegionSlug
};
Client.migrate(options, $scope.planChange.password, function (error) {
$scope.planChange.busy = false;
if (error) {
if (error.statusCode === 403) {
$scope.planChange.error.password = true;
$scope.planChange.password = '';
$scope.planChangeForm.password.$setPristine();
$('#inputPlanChangePassword').focus();
} else {
console.error('Unable to change plan.', error);
}
} else {
$scope.planChange.planChangeReset();
$('#planChangeModal').modal('hide');
window.location.href = '/update.html';
}
$scope.planChange.busy = false;
});
}
2016-06-28 13:45:50 -05:00
};
$scope.createBackup = {
2015-07-28 14:28:53 -07:00
busy: false,
percent: 100,
errorMessage: '',
doCreateBackup: function () {
$scope.createBackup.busy = true;
$scope.createBackup.percent = 0;
$scope.createBackup.errorMessage = '';
Client.backup(function (error) {
if (error) {
if (error.statusCode === 409 && error.message.indexOf('full_backup') !== -1) {
$scope.createBackup.errorMessage = 'Backup already in progress. Please retry later.';
} else if (error.statusCode === 409) {
$scope.createBackup.errorMessage = 'App task is currently in progress. Please retry later.';
} else {
console.error(error);
$scope.createBackup.errorMessage = error.message;
}
$scope.createBackup.busy = false;
$('#createBackupFailedModal').modal('show');
return;
}
function checkIfDone() {
Client.progress(function (error, data) {
if (error) return window.setTimeout(checkIfDone, 250);
// check if we are done
if (!data.backup || data.backup.percent >= 100) {
if (data.backup && data.backup.message) console.error('Backup message: ' + data.backup.message); // backup error message
fetchBackups();
$scope.createBackup.busy = false;
return;
}
$scope.createBackup.percent = data.backup.percent;
window.setTimeout(checkIfDone, 250);
});
}
checkIfDone();
});
}
};
$scope.avatarChange = {
busy: false,
error: {},
avatar: null,
availableAvatars: [{
file: null,
data: null,
url: '/img/avatars/avatar_0.png',
}, {
file: null,
data: null,
2015-07-29 11:06:33 +02:00
url: '/img/avatars/rubber-duck.png'
}, {
file: null,
data: null,
2015-07-29 11:06:33 +02:00
url: '/img/avatars/carrot.png'
}, {
file: null,
data: null,
2015-07-29 11:06:33 +02:00
url: '/img/avatars/cup.png'
}, {
file: null,
data: null,
2015-07-29 11:06:33 +02:00
url: '/img/avatars/football.png'
}, {
file: null,
data: null,
2015-07-29 11:06:33 +02:00
url: '/img/avatars/owl.png'
}, {
file: null,
data: null,
2015-07-29 11:06:33 +02:00
url: '/img/avatars/space-rocket.png'
}, {
file: null,
data: null,
url: '/img/avatars/armchair.png'
}, {
file: null,
data: null,
url: '/img/avatars/cap.png'
}, {
file: null,
data: null,
url: '/img/avatars/pan.png'
}, {
file: null,
data: null,
url: '/img/avatars/meat.png'
}, {
file: null,
data: null,
url: '/img/avatars/umbrella.png'
}, {
file: null,
data: null,
url: '/img/avatars/jar.png'
}],
getBlobFromImg: function (img, callback) {
var size = 256;
var canvas = document.createElement('canvas');
canvas.width = size;
canvas.height = size;
var imageDimensionRatio = img.width / img.height;
var canvasDimensionRatio = canvas.width / canvas.height;
var renderableHeight, renderableWidth, xStart, yStart;
if (imageDimensionRatio > canvasDimensionRatio) {
renderableHeight = canvas.height;
renderableWidth = img.width * (renderableHeight / img.height);
xStart = (canvas.width - renderableWidth) / 2;
yStart = 0;
} else if (imageDimensionRatio < canvasDimensionRatio) {
renderableWidth = canvas.width;
renderableHeight = img.height * (renderableWidth / img.width);
xStart = 0;
yStart = (canvas.height - renderableHeight) / 2;
} else {
renderableHeight = canvas.height;
renderableWidth = canvas.width;
xStart = 0;
yStart = 0;
}
var ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(img, xStart, yStart, renderableWidth, renderableHeight);
canvas.toBlob(callback);
},
doChangeAvatar: function () {
$scope.avatarChange.error.avatar = null;
$scope.avatarChange.busy = true;
var img = document.getElementById('previewAvatar');
$scope.avatarChange.avatar.file = $scope.avatarChange.getBlobFromImg(img, function (blob) {
Client.changeCloudronAvatar(blob, function (error) {
if (error) {
console.error('Unable to change cloudron avatar.', error);
} else {
Client.resetAvatar();
}
$('#avatarChangeModal').modal('hide');
$scope.avatarChange.avatarChangeReset();
});
});
},
setPreviewAvatar: function (avatar) {
$scope.avatarChange.avatar = avatar;
},
avatarChangeReset: function () {
$scope.avatarChange.error.avatar = null;
$scope.avatarChange.avatar = null;
$scope.avatarChange.busy = false;
},
showChangeAvatar: function () {
$scope.avatarChange.avatarChangeReset();
$('#avatarChangeModal').modal('show');
},
showCustomAvatarSelector: function () {
$('#avatarFileInput').click();
}
};
$scope.email = {
refreshBusy: false,
toggle: function () {
if ($scope.mailConfig.enabled) return $scope.email.disable();
// show warning first
$('#enableEmailModal').modal('show');
},
enable: function () {
$('#enableEmailModal').modal('hide');
Client.setMailConfig({ enabled: true }, function (error) {
if (error) return console.error(error);
$scope.mailConfig.enabled = true;
});
},
disable: function () {
Client.setMailConfig({ enabled: false }, function (error) {
if (error) return console.error(error);
$scope.mailConfig.enabled = false;
});
},
refresh: function () {
$scope.email.refreshBusy = true;
showExpectedDnsRecords(function (error) {
if (error) console.error(error);
$scope.email.refreshBusy = false;
});
}
};
$scope.configureBackup = {
busy: false,
error: {},
provider: 's3',
bucket: '',
prefix: '',
accessKeyId: '',
secretAccessKey: '',
2016-10-11 14:20:31 +02:00
region: '',
endpoint: '',
show: function () {
$scope.configureBackup.error = {};
$scope.configureBackup.busy = false;
$scope.configureBackup.bucket = $scope.backupConfig.bucket;
$scope.configureBackup.prefix = $scope.backupConfig.prefix;
2016-10-11 14:20:31 +02:00
$scope.configureBackup.region = $scope.backupConfig.region;
$scope.configureBackup.accessKeyId = $scope.backupConfig.accessKeyId;
$scope.configureBackup.secretAccessKey = $scope.backupConfig.secretAccessKey;
$scope.configureBackup.endpoint = $scope.backupConfig.endpoint;
2016-12-19 12:41:35 -08:00
$scope.configureBackup.key = $scope.backupConfig.key;
$('#configureBackupModal').modal('show');
},
submit: function () {
$scope.configureBackup.error = {};
$scope.configureBackup.busy = true;
var backupConfig = {
provider: $scope.configureBackup.provider,
bucket: $scope.configureBackup.bucket,
prefix: $scope.configureBackup.prefix,
accessKeyId: $scope.configureBackup.accessKeyId,
2016-12-19 12:41:35 -08:00
secretAccessKey: $scope.configureBackup.secretAccessKey,
key: $scope.configureBackup.key
};
2016-10-11 14:20:31 +02:00
if ($scope.configureBackup.region) backupConfig.region = $scope.configureBackup.region;
if ($scope.configureBackup.endpoint) backupConfig.endpoint = $scope.configureBackup.endpoint;
2016-10-11 14:20:31 +02:00
Client.setBackupConfig(backupConfig, function (error) {
$scope.configureBackup.busy = false;
if (error) {
if (error.statusCode === 402) {
$scope.configureBackup.error.generic = error.message;
if (error.message.indexOf('AWS Access Key Id') !== -1) {
$scope.configureBackup.error.accessKeyId = true;
$scope.configureBackup.accessKeyId = '';
$scope.configureBackupForm.accessKeyId.$setPristine();
$('#inputConfigureBackupAccessKeyId').focus();
} else if (error.message.indexOf('not match the signature') !== -1 ) {
$scope.configureBackup.error.secretAccessKey = true;
$scope.configureBackup.secretAccessKey = '';
$scope.configureBackupForm.secretAccessKey.$setPristine();
$('#inputConfigureBackupSecretAccessKey').focus();
} else if (error.message.toLowerCase() === 'access denied') {
$scope.configureBackup.error.bucket = true;
$scope.configureBackup.bucket = '';
$scope.configureBackupForm.bucket.$setPristine();
$('#inputConfigureBackupBucket').focus();
2016-10-11 14:20:31 +02:00
} else if (error.message.indexOf('ECONNREFUSED') !== -1) {
$scope.configureBackup.error.generic = 'Unknown region';
$scope.configureBackup.error.region = true;
$scope.configureBackupForm.region.$setPristine();
$('#inputConfigureBackupRegion').focus();
} else if (error.message.toLowerCase() === 'wrong region') {
$scope.configureBackup.error.generic = 'Wrong S3 Region';
$scope.configureBackup.error.region = true;
2016-10-11 14:20:31 +02:00
$scope.configureBackupForm.region.$setPristine();
$('#inputConfigureBackupRegion').focus();
} else {
$('#inputConfigureBackupBucket').focus();
}
} else {
console.error('Unable to change name.', error);
}
return;
}
// $scope.configureBackup.reset();
$('#configureBackupModal').modal('hide');
// TODO: be smarter and create new backup only when required
$scope.createBackup.doCreateBackup();
2016-10-11 14:20:31 +02:00
// now refresh the ui
Client.refreshConfig();
2016-10-11 14:20:31 +02:00
getBackupConfig();
});
}
};
function fetchBackups() {
Client.getBackups(function (error, backups) {
if (error) return console.error(error);
$scope.backups = backups;
if ($scope.backups.length > 0) {
$scope.lastBackup = backups[0];
} else {
$scope.lastBackup = null;
}
});
}
2016-08-30 22:12:07 -07:00
function getMailConfig() {
Client.getMailConfig(function (error, mailConfig) {
if (error) return console.error(error);
$scope.mailConfig = mailConfig;
showExpectedDnsRecords();
2016-08-30 22:12:07 -07:00
});
}
2016-09-22 16:09:52 +02:00
function getBackupConfig() {
Client.getBackupConfig(function (error, backupConfig) {
if (error) return console.error(error);
$scope.backupConfig = backupConfig;
});
}
function getDnsConfig() {
Client.getDnsConfig(function (error, dnsConfig) {
if (error) return console.error(error);
$scope.dnsConfig = dnsConfig;
});
}
function showExpectedDnsRecords(callback) {
callback = callback || function (error) { if (error) console.error(error); };
// nothing to check if mail is not enabled
if (!$scope.mailConfig.enabled) return;
Client.getExpectedDnsRecords(function (error, dnsRecords) {
if (error) return callback(error);
$scope.expectedDnsRecords = dnsRecords;
callback(null);
});
}
2016-06-28 14:36:19 -05:00
function getPlans() {
2016-06-28 13:45:50 -05:00
AppStore.getSizes(function (error, result) {
if (error) return console.error(error);
var found = false;
2016-11-02 10:24:32 +01:00
var SIZE_SLUGS = [ '512mb', '1gb', '2gb', '4gb', '8gb', '16gb', '32gb', '48gb', '64gb' ];
2016-06-28 13:45:50 -05:00
result = result.filter(function (size) {
// only show plans bigger than the current size
if (found) return true;
found = SIZE_SLUGS.indexOf(size.slug) > SIZE_SLUGS.indexOf($scope.config.plan.slug);
return found;
2016-06-28 13:45:50 -05:00
});
2016-06-28 14:36:19 -05:00
angular.copy(result, $scope.availablePlans);
2016-06-30 17:10:18 -05:00
// prepend the current plan
$scope.availablePlans.unshift($scope.config.plan);
2016-06-30 17:10:18 -05:00
$scope.planChange.requestedPlan = $scope.availablePlans[0]; // need the reference to preselect
2016-06-28 13:45:50 -05:00
AppStore.getRegions(function (error, result) {
if (error) return console.error(error);
angular.copy(result, $scope.availableRegions);
$scope.currentRegionSlug = $scope.config.region;
});
});
}
$('#avatarFileInput').get(0).onchange = function (event) {
var fr = new FileReader();
fr.onload = function () {
$scope.$apply(function () {
var tmp = {
file: event.target.files[0],
data: fr.result,
url: null
};
$scope.avatarChange.availableAvatars.push(tmp);
$scope.avatarChange.setPreviewAvatar(tmp);
});
};
fr.readAsDataURL(event.target.files[0]);
};
$scope.cloudronNameChange = {
busy: false,
error: {},
name: '',
reset: function () {
$scope.cloudronNameChange.busy = false;
$scope.cloudronNameChange.error.name = null;
$scope.cloudronNameChange.name = '';
$scope.cloudronNameChangeForm.$setUntouched();
$scope.cloudronNameChangeForm.$setPristine();
},
show: function () {
$scope.cloudronNameChange.reset();
$scope.cloudronNameChange.name = $scope.config.cloudronName;
$('#cloudronNameChangeModal').modal('show');
},
submit: function () {
$scope.cloudronNameChange.error.name = null;
$scope.cloudronNameChange.busy = true;
Client.changeCloudronName($scope.cloudronNameChange.name, function (error) {
$scope.cloudronNameChange.busy = false;
if (error) {
if (error.statusCode === 400) {
$scope.cloudronNameChange.error.name = 'Invalid name';
$scope.cloudronNameChange.name = '';
$('#inputCloudronName').focus();
$scope.cloudronNameChangeForm.password.$setPristine();
} else {
console.error('Unable to change name.', error);
return;
}
}
$scope.cloudronNameChange.reset();
$('#cloudronNameChangeModal').modal('hide');
Client.refreshConfig();
});
}
};
Client.onReady(function () {
fetchBackups();
2016-08-30 22:12:07 -07:00
getMailConfig();
2016-09-22 16:09:52 +02:00
getBackupConfig();
getDnsConfig();
2016-06-30 10:27:29 -05:00
2016-07-04 15:58:47 +02:00
if ($scope.config.provider === 'caas') {
getPlans();
$scope.currentPlan = $scope.config.plan;
$scope.currency = $scope.config.currency === 'eur' ? '€' : '$';
2016-07-26 15:23:10 +02:00
} else {
Client.getAppstoreConfig(function (error, result) {
if (error) return console.error(error);
if (result.token) {
$scope.appstoreConfig = result;
AppStore.getProfile(result.token, function (error, result) {
if (error) return console.error(error);
$scope.appstoreConfig.profile = result;
});
}
2016-07-26 15:23:10 +02:00
});
2016-07-04 15:58:47 +02:00
}
});
// setup all the dialog focus handling
['planChangeModal', 'appstoreLoginModal', 'cloudronNameChangeModal', 'configureBackupModal'].forEach(function (id) {
$('#' + id).on('shown.bs.modal', function () {
$(this).find("[autofocus]:first").focus();
});
});
$('.modal-backdrop').remove();
}]);