Files
cloudron-box/src/views/profile.js
2020-06-03 23:17:06 +02:00

605 lines
21 KiB
JavaScript

'use strict';
/* global async */
/* global angular */
/* global $ */
angular.module('Application').controller('ProfileController', ['$scope', '$location', 'Client', function ($scope, $location, Client) {
$scope.user = Client.getUserInfo();
$scope.config = Client.getConfig();
$scope.apps = Client.getInstalledApps();
$scope.twoFactorAuthentication = {
busy: false,
error: null,
password: '',
totpToken: '',
secret: '',
qrcode: '',
reset: function () {
$scope.twoFactorAuthentication.busy = false;
$scope.twoFactorAuthentication.error = null;
$scope.twoFactorAuthentication.password = '';
$scope.twoFactorAuthentication.totpToken = '';
$scope.twoFactorAuthentication.secret = '';
$scope.twoFactorAuthentication.qrcode = '';
$scope.twoFactorAuthenticationEnableForm.$setUntouched();
$scope.twoFactorAuthenticationEnableForm.$setPristine();
$scope.twoFactorAuthenticationDisableForm.$setUntouched();
$scope.twoFactorAuthenticationDisableForm.$setPristine();
},
show: function () {
$scope.twoFactorAuthentication.reset();
if ($scope.user.twoFactorAuthenticationEnabled) {
$('#twoFactorAuthenticationDisableModal').modal('show');
} else {
$('#twoFactorAuthenticationEnableModal').modal('show');
Client.setTwoFactorAuthenticationSecret(function (error, result) {
if (error) return console.error(error);
$scope.twoFactorAuthentication.secret = result.secret;
$scope.twoFactorAuthentication.qrcode = result.qrcode;
});
}
},
enable: function() {
$scope.twoFactorAuthentication.busy = true;
Client.enableTwoFactorAuthentication($scope.twoFactorAuthentication.totpToken, function (error) {
$scope.twoFactorAuthentication.busy = false;
if (error) {
$scope.twoFactorAuthentication.error = error.message;
$scope.twoFactorAuthentication.totpToken = '';
$scope.twoFactorAuthenticationEnableForm.totpToken.$setPristine();
$('#twoFactorAuthenticationTotpTokenInput').focus();
return;
}
Client.refreshUserInfo();
$('#twoFactorAuthenticationEnableModal').modal('hide');
});
},
disable: function () {
$scope.twoFactorAuthentication.busy = true;
Client.disableTwoFactorAuthentication($scope.twoFactorAuthentication.password, function (error) {
$scope.twoFactorAuthentication.busy = false;
if (error) {
$scope.twoFactorAuthentication.error = error.message;
$scope.twoFactorAuthentication.password = '';
$scope.twoFactorAuthenticationDisableForm.password.$setPristine();
$('#twoFactorAuthenticationPasswordInput').focus();
return;
}
Client.refreshUserInfo();
$('#twoFactorAuthenticationDisableModal').modal('hide');
});
}
};
$scope.avatarChange = {
busy: false,
error: {},
avatar: null,
useGravatar: '',
useGravatarOrig: '',
pictureChanged: false,
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;
function done(error) {
if (error) return console.error('Unable to change avatar.', error);
Client.refreshUserInfo(function (error) {
if (error) return console.error(error);
$('#avatarChangeModal').modal('hide');
$scope.avatarChange.avatarChangeReset();
});
}
if ($scope.avatarChange.useGravatar) {
Client.clearAvatar(done);
} else {
var img = document.getElementById('previewAvatar');
$scope.avatarChange.getBlobFromImg(img, function (blob) {
Client.changeAvatar(blob, done);
});
}
},
setPreviewAvatar: function (avatar) {
$scope.avatarChange.pictureChanged = true;
$scope.avatarChange.avatar = avatar;
document.getElementById('previewAvatar').src = avatar.data;
},
avatarChangeReset: function () {
$scope.avatarChange.error.avatar = null;
$scope.avatarChange.useGravatar = $scope.user.avatarUrl.indexOf('https://www.gravatar.com') === 0 ? 'true_string' : '';
$scope.avatarChange.useGravatarOrig = $scope.avatarChange.useGravatar;
$scope.avatarChange.pictureChanged = false;
document.getElementById('previewAvatar').src = $scope.avatarChange.useGravatar ? '' : $scope.user.avatarUrl;
$scope.avatarChange.avatar = $scope.avatarChange.useGravatar ? {} : {
url: $scope.user.avatarUrl
};
$scope.avatarChange.busy = false;
},
showChangeAvatar: function () {
$scope.avatarChange.avatarChangeReset();
$('#avatarChangeModal').modal('show');
},
showCustomAvatarSelector: function () {
$('#avatarFileInput').click();
}
};
$scope.passwordchange = {
busy: false,
error: {},
password: '',
newPassword: '',
newPasswordRepeat: '',
reset: function () {
$scope.passwordchange.error.password = null;
$scope.passwordchange.error.newPassword = null;
$scope.passwordchange.error.newPasswordRepeat = null;
$scope.passwordchange.password = '';
$scope.passwordchange.newPassword = '';
$scope.passwordchange.newPasswordRepeat = '';
$scope.passwordChangeForm.$setUntouched();
$scope.passwordChangeForm.$setPristine();
},
show: function () {
$scope.passwordchange.reset();
$('#passwordChangeModal').modal('show');
},
submit: function () {
$scope.passwordchange.error.password = null;
$scope.passwordchange.error.newPassword = null;
$scope.passwordchange.error.newPasswordRepeat = null;
$scope.passwordchange.busy = true;
Client.changePassword($scope.passwordchange.password, $scope.passwordchange.newPassword, function (error) {
$scope.passwordchange.busy = false;
if (error) {
if (error.statusCode === 412) {
$scope.passwordchange.error.password = true;
$scope.passwordchange.password = '';
$('#inputPasswordChangePassword').focus();
$scope.passwordChangeForm.password.$setPristine();
} else if (error.statusCode === 400) {
$scope.passwordchange.error.newPassword = error.message;
$scope.passwordchange.newPassword = '';
$scope.passwordchange.newPasswordRepeat = '';
$scope.passwordChangeForm.newPassword.$setPristine();
$scope.passwordChangeForm.newPasswordRepeat.$setPristine();
$('#inputPasswordChangeNewPassword').focus();
} else {
console.error('Unable to change password.', error);
}
return;
}
$scope.passwordchange.reset();
$('#passwordChangeModal').modal('hide');
});
}
};
$scope.emailchange = {
busy: false,
error: {},
email: '',
reset: function () {
$scope.emailchange.busy = false;
$scope.emailchange.error.email = null;
$scope.emailchange.email = '';
$scope.emailChangeForm.$setUntouched();
$scope.emailChangeForm.$setPristine();
},
show: function () {
$scope.emailchange.reset();
$('#emailChangeModal').modal('show');
},
submit: function () {
$scope.emailchange.error.email = null;
$scope.emailchange.busy = true;
var data = {
email: $scope.emailchange.email
};
Client.updateProfile(data, function (error) {
$scope.emailchange.busy = false;
if (error) {
if (error.statusCode === 409) {
$scope.emailchange.error.email = 'Email already taken';
$scope.emailChangeForm.email.$setPristine();
$('#inputEmailChangeEmail').focus();
} else {
console.error('Unable to change email.', error);
}
return;
}
// update user info in the background
Client.refreshUserInfo();
$scope.emailchange.reset();
$('#emailChangeModal').modal('hide');
});
}
};
$scope.fallbackEmailChange = {
busy: false,
error: {},
email: '',
reset: function () {
$scope.fallbackEmailChange.busy = false;
$scope.fallbackEmailChange.error.email = null;
$scope.fallbackEmailChange.email = '';
$scope.fallbackEmailChangeForm.$setUntouched();
$scope.fallbackEmailChangeForm.$setPristine();
},
show: function () {
$scope.fallbackEmailChange.reset();
$('#fallbackEmailChangeModal').modal('show');
},
submit: function () {
$scope.fallbackEmailChange.error.email = null;
$scope.fallbackEmailChange.busy = true;
var data = {
fallbackEmail: $scope.fallbackEmailChange.email
};
Client.updateProfile(data, function (error) {
$scope.fallbackEmailChange.busy = false;
if (error) return console.error('Unable to change fallback email.', error);
// update user info in the background
Client.refreshUserInfo();
$scope.fallbackEmailChange.reset();
$('#fallbackEmailChangeModal').modal('hide');
});
}
};
$scope.appPasswordAdd = {
password: null,
name: '',
identifier: '',
busy: false,
error: {},
reset: function () {
$scope.appPasswordAdd.busy = false;
$scope.appPasswordAdd.password = null;
$scope.appPasswordAdd.error.name = null;
$scope.appPasswordAdd.name = '';
$scope.appPasswordAdd.identifier = '';
$scope.appPasswordAddForm.$setUntouched();
$scope.appPasswordAddForm.$setPristine();
},
show: function () {
$scope.appPasswordAdd.reset();
$('#appPasswordAddModal').modal('show');
},
submit: function () {
$scope.appPasswordAdd.busy = true;
Client.addAppPassword($scope.appPasswordAdd.identifier, $scope.appPasswordAdd.name, function (error, result) {
$scope.appPasswordAdd.busy = false;
if (error) {
if (error.statusCode === 400 || error.statusCode === 409) {
$scope.appPasswordAdd.error.name = error.message;
$scope.appPasswordAddForm.name.$setPristine();
$('#inputAppPasswordName').focus();
} else {
console.error('Unable to create password.', error);
}
return;
}
$scope.appPasswordAdd.password = result;
$scope.appPassword.refresh();
});
}
};
$scope.appPassword = {
busy: false,
error: {},
passwords: [],
identifiers: [],
refresh: function () {
Client.getAppPasswords(function (error, result) {
if (error) console.error(error);
$scope.appPassword.passwords = result.appPasswords || [];
$scope.appPassword.identifiers = [];
var appsById = {};
$scope.apps.forEach(function (app) {
if (!app.manifest.addons) return;
var ftp = app.manifest.addons.localstorage && app.manifest.addons.localstorage.ftp;
// ignore apps without ftp and ldap or email
if (!ftp && (!app.manifest.addons.ldap || app.manifest.addons.email || !app.sso)) return;
appsById[app.id] = app;
var labelSuffix = ftp ? ' - SFTP' : '';
var label = app.label ? app.label + ' (' + app.fqdn + ')' + labelSuffix : app.fqdn + labelSuffix;
$scope.appPassword.identifiers.push({ id: app.id, label: label });
});
$scope.appPassword.identifiers.push({ id: 'mail', label: 'Mail client' });
// setup label for the table UI
$scope.appPassword.passwords.forEach(function (password) {
if (password.identifier === 'mail') return password.label = password.identifier;
var app = appsById[password.identifier];
if (!app) return password.label = password.identifier + ' (App not found)';
var ftp = app.manifest.addons && app.manifest.addons.localstorage && app.manifest.addons.localstorage.ftp;
var labelSuffix = ftp ? ' - SFTP' : '';
password.label = app.label ? app.label + ' (' + app.fqdn + ')' + labelSuffix : app.fqdn + labelSuffix;
});
});
},
del: function (id) {
Client.delAppPassword(id, function (error) {
if (error) console.error(error);
$scope.appPassword.refresh();
});
}
};
$scope.displayNameChange = {
busy: false,
error: {},
displayName: '',
reset: function () {
$scope.displayNameChange.busy = false;
$scope.displayNameChange.error.displayName = null;
$scope.displayNameChange.displayName = '';
$scope.displayNameChangeForm.$setUntouched();
$scope.displayNameChangeForm.$setPristine();
},
show: function () {
$scope.displayNameChange.reset();
$scope.displayNameChange.displayName = $scope.user.displayName;
$('#displayNameChangeModal').modal('show');
},
submit: function () {
$scope.displayNameChange.error.displayName = null;
$scope.displayNameChange.busy = true;
var user = {
displayName: $scope.displayNameChange.displayName
};
Client.updateProfile(user, function (error) {
$scope.displayNameChange.busy = false;
if (error) {
if (error.statusCode === 400) {
$scope.displayNameChange.error.displayName = 'Invalid display name';
$scope.displayNameChangeForm.email.$setPristine();
$('#inputDisplayNameChangeDisplayName').focus();
} else {
console.error('Unable to change email.', error);
}
return;
}
// update user info in the background
Client.refreshUserInfo();
$scope.displayNameChange.reset();
$('#displayNameChangeModal').modal('hide');
});
}
};
$scope.tokens = {
busy: false,
error: {},
allTokens: [],
webadminTokens: [],
cliTokens: [],
apiTokens: [],
refresh: function () {
$scope.tokens.busy = true;
Client.getTokens(function (error, result) {
if (error) return console.error(error);
$scope.tokens.busy = false;
$scope.tokens.allTokens = result;
$scope.tokens.webadminTokens = result.filter(function (c) { return c.clientId === 'cid-webadmin'; });
$scope.tokens.cliTokens = result.filter(function (c) { return c.clientId === 'cid-cli'; });
$scope.tokens.apiTokens = result.filter(function (c) { return c.clientId === 'cid-sdk'; });
});
},
revokeAllWebAndCliTokens: function () {
$scope.tokens.busy = true;
async.eachSeries($scope.tokens.webadminTokens.concat($scope.tokens.cliTokens), function (token, callback) {
// do not revoke token for this session, will do at the end with logout
if (token.accessToken === Client.getToken()) return callback();
Client.delToken(token.id, callback);
}, function (error) {
if (error) console.error(error);
Client.logout();
});
},
add: {
busy: false,
error: null,
name: '',
accessToken: '',
show: function () {
$scope.tokens.add.name = '';
$scope.tokens.add.accessToken = '';
$scope.tokens.add.busy = false;
$scope.tokens.add.error = null;
$scope.apiTokenAddForm.name.$setPristine();
$('#apiTokenAddModal').modal('show');
},
submit: function () {
$scope.tokens.add.busy = true;
Client.createToken($scope.tokens.add.name, function (error, result) {
if (error) {
if (error.statusCode === 400) {
$scope.tokens.add.error = error.message;
$scope.apiTokenAddForm.name.$setPristine();
$('#inputApiTokenName').focus();
} else {
console.error('Unable to create password.', error);
}
return;
}
$scope.tokens.add.busy = false;
$scope.tokens.add.accessToken = result.accessToken;
$scope.tokens.refresh();
});
}
},
revokeToken: function (token) {
Client.delToken(token.id, function (error) {
if (error) console.error(error);
$scope.tokens.refresh();
});
}
};
Client.onReady(function () {
$scope.appPassword.refresh();
$scope.tokens.refresh();
});
$('#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.avatar = tmp;
$scope.avatarChange.setPreviewAvatar(tmp);
});
};
fr.readAsDataURL(event.target.files[0]);
};
// setup all the dialog focus handling
['passwordChangeModal', 'apiTokenAddModal', 'appPasswordAddModal', 'emailChangeModal', 'fallbackEmailChangeModal', 'displayNameChangeModal', 'twoFactorAuthenticationEnableModal', 'twoFactorAuthenticationDisableModal'].forEach(function (id) {
$('#' + id).on('shown.bs.modal', function () {
$(this).find("[autofocus]:first").focus();
});
});
$('.modal-backdrop').remove();
}]);