Merge branch 'U4-10883' of git://github.com/mathiasrando/Umbraco-CMS into mathiasrando-U4-10883
This commit is contained in:
@@ -1,403 +1,412 @@
|
||||
angular.module("umbraco").controller("Umbraco.Dialogs.LoginController",
|
||||
function ($scope, $cookies, $location, currentUserResource, formHelper, mediaHelper, umbRequestHelper, Upload, localizationService, userService, externalLoginInfo, resetPasswordCodeInfo, $timeout, authResource, dialogService, $q) {
|
||||
function ($scope, $cookies, $location, currentUserResource, formHelper, mediaHelper, umbRequestHelper, Upload, localizationService, userService, externalLoginInfo, resetPasswordCodeInfo, $timeout, authResource, dialogService, $q) {
|
||||
|
||||
$scope.invitedUser = null;
|
||||
$scope.invitedUserPasswordModel = {
|
||||
password: "",
|
||||
confirmPassword: "",
|
||||
buttonState: "",
|
||||
passwordPolicies: null,
|
||||
passwordPolicyText: ""
|
||||
}
|
||||
$scope.avatarFile = {
|
||||
filesHolder: null,
|
||||
uploadStatus: null,
|
||||
uploadProgress: 0,
|
||||
maxFileSize: Umbraco.Sys.ServerVariables.umbracoSettings.maxFileSize + "KB",
|
||||
acceptedFileTypes: mediaHelper.formatFileTypes(Umbraco.Sys.ServerVariables.umbracoSettings.imageFileTypes),
|
||||
uploaded: false
|
||||
}
|
||||
$scope.togglePassword = function () {
|
||||
var elem = $("form[name='loginForm'] input[name='password']");
|
||||
elem.attr("type", (elem.attr("type") === "text" ? "password" : "text"));
|
||||
}
|
||||
$scope.invitedUser = null;
|
||||
$scope.invitedUserPasswordModel = {
|
||||
password: "",
|
||||
confirmPassword: "",
|
||||
buttonState: "",
|
||||
passwordPolicies: null,
|
||||
passwordPolicyText: ""
|
||||
}
|
||||
$scope.loginStates = {
|
||||
submitButton: "init"
|
||||
}
|
||||
$scope.avatarFile = {
|
||||
filesHolder: null,
|
||||
uploadStatus: null,
|
||||
uploadProgress: 0,
|
||||
maxFileSize: Umbraco.Sys.ServerVariables.umbracoSettings.maxFileSize + "KB",
|
||||
acceptedFileTypes: mediaHelper.formatFileTypes(Umbraco.Sys.ServerVariables.umbracoSettings.imageFileTypes),
|
||||
uploaded: false
|
||||
}
|
||||
$scope.togglePassword = function () {
|
||||
var elem = $("form[name='loginForm'] input[name='password']");
|
||||
elem.attr("type", (elem.attr("type") === "text" ? "password" : "text"));
|
||||
}
|
||||
|
||||
function init() {
|
||||
// Check if it is a new user
|
||||
var inviteVal = $location.search().invite;
|
||||
if (inviteVal && (inviteVal === "1" || inviteVal === "2")) {
|
||||
function init() {
|
||||
// Check if it is a new user
|
||||
var inviteVal = $location.search().invite;
|
||||
if (inviteVal && (inviteVal === "1" || inviteVal === "2")) {
|
||||
|
||||
$q.all([
|
||||
//get the current invite user
|
||||
authResource.getCurrentInvitedUser().then(function (data) {
|
||||
$scope.invitedUser = data;
|
||||
},
|
||||
function() {
|
||||
//it failed so we should remove the search
|
||||
$location.search('invite', null);
|
||||
}),
|
||||
//get the membership provider config for password policies
|
||||
authResource.getMembershipProviderConfig().then(function (data) {
|
||||
$scope.invitedUserPasswordModel.passwordPolicies = data;
|
||||
$q.all([
|
||||
//get the current invite user
|
||||
authResource.getCurrentInvitedUser().then(function (data) {
|
||||
$scope.invitedUser = data;
|
||||
},
|
||||
function () {
|
||||
//it failed so we should remove the search
|
||||
$location.search('invite', null);
|
||||
}),
|
||||
//get the membership provider config for password policies
|
||||
authResource.getMembershipProviderConfig().then(function (data) {
|
||||
$scope.invitedUserPasswordModel.passwordPolicies = data;
|
||||
|
||||
//localize the text
|
||||
localizationService.localize("errorHandling_errorInPasswordFormat",
|
||||
[
|
||||
$scope.invitedUserPasswordModel.passwordPolicies.minPasswordLength,
|
||||
$scope.invitedUserPasswordModel.passwordPolicies.minNonAlphaNumericChars
|
||||
]).then(function(data) {
|
||||
$scope.invitedUserPasswordModel.passwordPolicyText = data;
|
||||
//localize the text
|
||||
localizationService.localize("errorHandling_errorInPasswordFormat",
|
||||
[
|
||||
$scope.invitedUserPasswordModel.passwordPolicies.minPasswordLength,
|
||||
$scope.invitedUserPasswordModel.passwordPolicies.minNonAlphaNumericChars
|
||||
]).then(function (data) {
|
||||
$scope.invitedUserPasswordModel.passwordPolicyText = data;
|
||||
});
|
||||
})
|
||||
]).then(function () {
|
||||
|
||||
$scope.inviteStep = Number(inviteVal);
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$scope.changeAvatar = function (files, event) {
|
||||
if (files && files.length > 0) {
|
||||
upload(files[0]);
|
||||
}
|
||||
};
|
||||
|
||||
$scope.getStarted = function () {
|
||||
$location.search('invite', null);
|
||||
$scope.submit(true);
|
||||
}
|
||||
|
||||
function upload(file) {
|
||||
|
||||
$scope.avatarFile.uploadProgress = 0;
|
||||
|
||||
Upload.upload({
|
||||
url: umbRequestHelper.getApiUrl("currentUserApiBaseUrl", "PostSetAvatar"),
|
||||
fields: {},
|
||||
file: file
|
||||
}).progress(function (evt) {
|
||||
|
||||
if ($scope.avatarFile.uploadStatus !== "done" && $scope.avatarFile.uploadStatus !== "error") {
|
||||
// set uploading status on file
|
||||
$scope.avatarFile.uploadStatus = "uploading";
|
||||
|
||||
// calculate progress in percentage
|
||||
var progressPercentage = parseInt(100.0 * evt.loaded / evt.total, 10);
|
||||
|
||||
// set percentage property on file
|
||||
$scope.avatarFile.uploadProgress = progressPercentage;
|
||||
}
|
||||
|
||||
}).success(function (data, status, headers, config) {
|
||||
|
||||
$scope.avatarFile.uploadProgress = 100;
|
||||
|
||||
// set done status on file
|
||||
$scope.avatarFile.uploadStatus = "done";
|
||||
|
||||
$scope.invitedUser.avatars = data;
|
||||
|
||||
$scope.avatarFile.uploaded = true;
|
||||
|
||||
}).error(function (evt, status, headers, config) {
|
||||
|
||||
// set status done
|
||||
$scope.avatarFile.uploadStatus = "error";
|
||||
|
||||
// If file not found, server will return a 404 and display this message
|
||||
if (status === 404) {
|
||||
$scope.avatarFile.serverErrorMessage = "File not found";
|
||||
}
|
||||
else if (status == 400) {
|
||||
//it's a validation error
|
||||
$scope.avatarFile.serverErrorMessage = evt.message;
|
||||
}
|
||||
else {
|
||||
//it's an unhandled error
|
||||
//if the service returns a detailed error
|
||||
if (evt.InnerException) {
|
||||
$scope.avatarFile.serverErrorMessage = evt.InnerException.ExceptionMessage;
|
||||
|
||||
//Check if its the common "too large file" exception
|
||||
if (evt.InnerException.StackTrace && evt.InnerException.StackTrace.indexOf("ValidateRequestEntityLength") > 0) {
|
||||
$scope.avatarFile.serverErrorMessage = "File too large to upload";
|
||||
}
|
||||
|
||||
} else if (evt.Message) {
|
||||
$scope.avatarFile.serverErrorMessage = evt.Message;
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
]).then(function () {
|
||||
|
||||
$scope.inviteStep = Number(inviteVal);
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$scope.changeAvatar = function (files, event) {
|
||||
if (files && files.length > 0) {
|
||||
upload(files[0]);
|
||||
}
|
||||
};
|
||||
|
||||
$scope.getStarted = function() {
|
||||
$location.search('invite', null);
|
||||
$scope.submit(true);
|
||||
}
|
||||
|
||||
function upload(file) {
|
||||
|
||||
$scope.avatarFile.uploadProgress = 0;
|
||||
|
||||
Upload.upload({
|
||||
url: umbRequestHelper.getApiUrl("currentUserApiBaseUrl", "PostSetAvatar"),
|
||||
fields: {},
|
||||
file: file
|
||||
}).progress(function (evt) {
|
||||
|
||||
if ($scope.avatarFile.uploadStatus !== "done" && $scope.avatarFile.uploadStatus !== "error") {
|
||||
// set uploading status on file
|
||||
$scope.avatarFile.uploadStatus = "uploading";
|
||||
|
||||
// calculate progress in percentage
|
||||
var progressPercentage = parseInt(100.0 * evt.loaded / evt.total, 10);
|
||||
|
||||
// set percentage property on file
|
||||
$scope.avatarFile.uploadProgress = progressPercentage;
|
||||
}
|
||||
|
||||
}).success(function (data, status, headers, config) {
|
||||
$scope.inviteSavePassword = function () {
|
||||
|
||||
$scope.avatarFile.uploadProgress = 100;
|
||||
if (formHelper.submitForm({ scope: $scope, statusMessage: "Saving..." })) {
|
||||
|
||||
// set done status on file
|
||||
$scope.avatarFile.uploadStatus = "done";
|
||||
$scope.invitedUserPasswordModel.buttonState = "busy";
|
||||
|
||||
$scope.invitedUser.avatars = data;
|
||||
currentUserResource.performSetInvitedUserPassword($scope.invitedUserPasswordModel.password)
|
||||
.then(function (data) {
|
||||
|
||||
$scope.avatarFile.uploaded = true;
|
||||
//success
|
||||
formHelper.resetForm({ scope: $scope, notifications: data.notifications });
|
||||
$scope.invitedUserPasswordModel.buttonState = "success";
|
||||
//set the user and set them as logged in
|
||||
$scope.invitedUser = data;
|
||||
userService.setAuthenticationSuccessful(data);
|
||||
|
||||
}).error(function (evt, status, headers, config) {
|
||||
$scope.inviteStep = 2;
|
||||
|
||||
// set status done
|
||||
$scope.avatarFile.uploadStatus = "error";
|
||||
}, function (err) {
|
||||
|
||||
// If file not found, server will return a 404 and display this message
|
||||
if (status === 404) {
|
||||
$scope.avatarFile.serverErrorMessage = "File not found";
|
||||
//error
|
||||
formHelper.handleError(err);
|
||||
|
||||
$scope.invitedUserPasswordModel.buttonState = "error";
|
||||
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
var setFieldFocus = function (form, field) {
|
||||
$timeout(function () {
|
||||
$("form[name='" + form + "'] input[name='" + field + "']").focus();
|
||||
});
|
||||
}
|
||||
else if (status == 400) {
|
||||
//it's a validation error
|
||||
$scope.avatarFile.serverErrorMessage = evt.message;
|
||||
}
|
||||
else {
|
||||
//it's an unhandled error
|
||||
//if the service returns a detailed error
|
||||
if (evt.InnerException) {
|
||||
$scope.avatarFile.serverErrorMessage = evt.InnerException.ExceptionMessage;
|
||||
|
||||
//Check if its the common "too large file" exception
|
||||
if (evt.InnerException.StackTrace && evt.InnerException.StackTrace.indexOf("ValidateRequestEntityLength") > 0) {
|
||||
$scope.avatarFile.serverErrorMessage = "File too large to upload";
|
||||
var twoFactorloginDialog = null;
|
||||
function show2FALoginDialog(view, callback) {
|
||||
if (!twoFactorloginDialog) {
|
||||
twoFactorloginDialog = dialogService.open({
|
||||
|
||||
//very special flag which means that global events cannot close this dialog
|
||||
manualClose: true,
|
||||
template: view,
|
||||
modalClass: "login-overlay",
|
||||
animation: "slide",
|
||||
show: true,
|
||||
callback: callback,
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function resetInputValidation() {
|
||||
$scope.confirmPassword = "";
|
||||
$scope.password = "";
|
||||
$scope.login = "";
|
||||
if ($scope.loginForm) {
|
||||
$scope.loginForm.username.$setValidity('auth', true);
|
||||
$scope.loginForm.password.$setValidity('auth', true);
|
||||
}
|
||||
if ($scope.requestPasswordResetForm) {
|
||||
$scope.requestPasswordResetForm.email.$setValidity("auth", true);
|
||||
}
|
||||
if ($scope.setPasswordForm) {
|
||||
$scope.setPasswordForm.password.$setValidity('auth', true);
|
||||
$scope.setPasswordForm.confirmPassword.$setValidity('auth', true);
|
||||
}
|
||||
}
|
||||
|
||||
$scope.allowPasswordReset = Umbraco.Sys.ServerVariables.umbracoSettings.allowPasswordReset;
|
||||
|
||||
$scope.showLogin = function () {
|
||||
$scope.errorMsg = "";
|
||||
resetInputValidation();
|
||||
$scope.view = "login";
|
||||
setFieldFocus("loginForm", "username");
|
||||
}
|
||||
|
||||
$scope.showRequestPasswordReset = function () {
|
||||
$scope.errorMsg = "";
|
||||
resetInputValidation();
|
||||
$scope.view = "request-password-reset";
|
||||
$scope.showEmailResetConfirmation = false;
|
||||
setFieldFocus("requestPasswordResetForm", "email");
|
||||
}
|
||||
|
||||
$scope.showSetPassword = function () {
|
||||
$scope.errorMsg = "";
|
||||
resetInputValidation();
|
||||
$scope.view = "set-password";
|
||||
setFieldFocus("setPasswordForm", "password");
|
||||
}
|
||||
|
||||
var d = new Date();
|
||||
var konamiGreetings = new Array("Suze Sunday", "Malibu Monday", "Tequila Tuesday", "Whiskey Wednesday", "Negroni Day", "Fernet Friday", "Sancerre Saturday");
|
||||
var konamiMode = $cookies.konamiLogin;
|
||||
if (konamiMode == "1") {
|
||||
$scope.greeting = "Happy " + konamiGreetings[d.getDay()];
|
||||
} else {
|
||||
localizationService.localize("login_greeting" + d.getDay()).then(function (label) {
|
||||
$scope.greeting = label;
|
||||
}); // weekday[d.getDay()];
|
||||
}
|
||||
$scope.errorMsg = "";
|
||||
|
||||
$scope.externalLoginFormAction = Umbraco.Sys.ServerVariables.umbracoUrls.externalLoginsUrl;
|
||||
$scope.externalLoginProviders = externalLoginInfo.providers;
|
||||
$scope.externalLoginInfo = externalLoginInfo;
|
||||
$scope.resetPasswordCodeInfo = resetPasswordCodeInfo;
|
||||
$scope.backgroundImage = Umbraco.Sys.ServerVariables.umbracoSettings.loginBackgroundImage;
|
||||
|
||||
$scope.activateKonamiMode = function () {
|
||||
if ($cookies.konamiLogin == "1") {
|
||||
// somehow I can't update the cookie value using $cookies, so going native
|
||||
document.cookie = "konamiLogin=; expires=Thu, 01 Jan 1970 00:00:01 GMT;";
|
||||
document.location.reload();
|
||||
} else {
|
||||
document.cookie = "konamiLogin=1; expires=Tue, 01 Jan 2030 00:00:01 GMT;";
|
||||
$scope.$apply(function () {
|
||||
$scope.greeting = "Happy " + konamiGreetings[d.getDay()];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$scope.loginSubmit = function (login, password) {
|
||||
|
||||
//TODO: Do validation properly like in the invite password update
|
||||
|
||||
//if the login and password are not empty we need to automatically
|
||||
// validate them - this is because if there are validation errors on the server
|
||||
// then the user has to change both username & password to resubmit which isn't ideal,
|
||||
// so if they're not empty, we'll just make sure to set them to valid.
|
||||
if (login && password && login.length > 0 && password.length > 0) {
|
||||
$scope.loginForm.username.$setValidity('auth', true);
|
||||
$scope.loginForm.password.$setValidity('auth', true);
|
||||
}
|
||||
|
||||
} else if (evt.Message) {
|
||||
$scope.avatarFile.serverErrorMessage = evt.Message;
|
||||
}
|
||||
if ($scope.loginForm.$invalid) {
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.loginStates.submitButton = "busy";
|
||||
|
||||
userService.authenticate(login, password)
|
||||
.then(function (data) {
|
||||
$scope.loginStates.submitButton = "success";
|
||||
$scope.submit(true);
|
||||
},
|
||||
function (reason) {
|
||||
|
||||
//is Two Factor required?
|
||||
if (reason.status === 402) {
|
||||
$scope.errorMsg = "Additional authentication required";
|
||||
show2FALoginDialog(reason.data.twoFactorView, $scope.submit);
|
||||
}
|
||||
else {
|
||||
$scope.loginStates.submitButton = "error";
|
||||
$scope.errorMsg = reason.errorMsg;
|
||||
|
||||
//set the form inputs to invalid
|
||||
$scope.loginForm.username.$setValidity("auth", false);
|
||||
$scope.loginForm.password.$setValidity("auth", false);
|
||||
}
|
||||
});
|
||||
|
||||
//setup a watch for both of the model values changing, if they change
|
||||
// while the form is invalid, then revalidate them so that the form can
|
||||
// be submitted again.
|
||||
$scope.loginForm.username.$viewChangeListeners.push(function () {
|
||||
if ($scope.loginForm.$invalid) {
|
||||
$scope.loginForm.username.$setValidity('auth', true);
|
||||
$scope.loginForm.password.$setValidity('auth', true);
|
||||
}
|
||||
});
|
||||
$scope.loginForm.password.$viewChangeListeners.push(function () {
|
||||
if ($scope.loginForm.$invalid) {
|
||||
$scope.loginForm.username.$setValidity('auth', true);
|
||||
$scope.loginForm.password.$setValidity('auth', true);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.requestPasswordResetSubmit = function (email) {
|
||||
|
||||
//TODO: Do validation properly like in the invite password update
|
||||
|
||||
if (email && email.length > 0) {
|
||||
$scope.requestPasswordResetForm.email.$setValidity('auth', true);
|
||||
}
|
||||
|
||||
$scope.showEmailResetConfirmation = false;
|
||||
|
||||
if ($scope.requestPasswordResetForm.$invalid) {
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.errorMsg = "";
|
||||
|
||||
authResource.performRequestPasswordReset(email)
|
||||
.then(function () {
|
||||
//remove the email entered
|
||||
$scope.email = "";
|
||||
$scope.showEmailResetConfirmation = true;
|
||||
}, function (reason) {
|
||||
$scope.errorMsg = reason.errorMsg;
|
||||
$scope.requestPasswordResetForm.email.$setValidity("auth", false);
|
||||
});
|
||||
|
||||
$scope.requestPasswordResetForm.email.$viewChangeListeners.push(function () {
|
||||
if ($scope.requestPasswordResetForm.email.$invalid) {
|
||||
$scope.requestPasswordResetForm.email.$setValidity('auth', true);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.setPasswordSubmit = function (password, confirmPassword) {
|
||||
|
||||
$scope.showSetPasswordConfirmation = false;
|
||||
|
||||
if (password && confirmPassword && password.length > 0 && confirmPassword.length > 0) {
|
||||
$scope.setPasswordForm.password.$setValidity('auth', true);
|
||||
$scope.setPasswordForm.confirmPassword.$setValidity('auth', true);
|
||||
}
|
||||
|
||||
if ($scope.setPasswordForm.$invalid) {
|
||||
return;
|
||||
}
|
||||
|
||||
//TODO: All of this logic can/should be shared! We should do validation the nice way instead of all of this manual stuff, see: inviteSavePassword
|
||||
authResource.performSetPassword($scope.resetPasswordCodeInfo.resetCodeModel.userId, password, confirmPassword, $scope.resetPasswordCodeInfo.resetCodeModel.resetCode)
|
||||
.then(function () {
|
||||
$scope.showSetPasswordConfirmation = true;
|
||||
$scope.resetComplete = true;
|
||||
|
||||
//reset the values in the resetPasswordCodeInfo angular so if someone logs out the change password isn't shown again
|
||||
resetPasswordCodeInfo.resetCodeModel = null;
|
||||
|
||||
}, function (reason) {
|
||||
if (reason.data && reason.data.Message) {
|
||||
$scope.errorMsg = reason.data.Message;
|
||||
}
|
||||
else {
|
||||
$scope.errorMsg = reason.errorMsg;
|
||||
}
|
||||
$scope.setPasswordForm.password.$setValidity("auth", false);
|
||||
$scope.setPasswordForm.confirmPassword.$setValidity("auth", false);
|
||||
});
|
||||
|
||||
$scope.setPasswordForm.password.$viewChangeListeners.push(function () {
|
||||
if ($scope.setPasswordForm.password.$invalid) {
|
||||
$scope.setPasswordForm.password.$setValidity('auth', true);
|
||||
}
|
||||
});
|
||||
$scope.setPasswordForm.confirmPassword.$viewChangeListeners.push(function () {
|
||||
if ($scope.setPasswordForm.confirmPassword.$invalid) {
|
||||
$scope.setPasswordForm.confirmPassword.$setValidity('auth', true);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$scope.inviteSavePassword = function () {
|
||||
|
||||
if (formHelper.submitForm({ scope: $scope, statusMessage: "Saving..." })) {
|
||||
|
||||
$scope.invitedUserPasswordModel.buttonState = "busy";
|
||||
|
||||
currentUserResource.performSetInvitedUserPassword($scope.invitedUserPasswordModel.password)
|
||||
.then(function (data) {
|
||||
//Now, show the correct panel:
|
||||
|
||||
//success
|
||||
formHelper.resetForm({ scope: $scope, notifications: data.notifications });
|
||||
$scope.invitedUserPasswordModel.buttonState = "success";
|
||||
//set the user and set them as logged in
|
||||
$scope.invitedUser = data;
|
||||
userService.setAuthenticationSuccessful(data);
|
||||
|
||||
$scope.inviteStep = 2;
|
||||
|
||||
}, function(err) {
|
||||
|
||||
//error
|
||||
formHelper.handleError(err);
|
||||
|
||||
$scope.invitedUserPasswordModel.buttonState = "error";
|
||||
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
var setFieldFocus = function (form, field) {
|
||||
$timeout(function () {
|
||||
$("form[name='" + form + "'] input[name='" + field + "']").focus();
|
||||
});
|
||||
}
|
||||
|
||||
var twoFactorloginDialog = null;
|
||||
function show2FALoginDialog(view, callback) {
|
||||
if (!twoFactorloginDialog) {
|
||||
twoFactorloginDialog = dialogService.open({
|
||||
|
||||
//very special flag which means that global events cannot close this dialog
|
||||
manualClose: true,
|
||||
template: view,
|
||||
modalClass: "login-overlay",
|
||||
animation: "slide",
|
||||
show: true,
|
||||
callback: callback,
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function resetInputValidation() {
|
||||
$scope.confirmPassword = "";
|
||||
$scope.password = "";
|
||||
$scope.login = "";
|
||||
if ($scope.loginForm) {
|
||||
$scope.loginForm.username.$setValidity('auth', true);
|
||||
$scope.loginForm.password.$setValidity('auth', true);
|
||||
}
|
||||
if ($scope.requestPasswordResetForm) {
|
||||
$scope.requestPasswordResetForm.email.$setValidity("auth", true);
|
||||
}
|
||||
if ($scope.setPasswordForm) {
|
||||
$scope.setPasswordForm.password.$setValidity('auth', true);
|
||||
$scope.setPasswordForm.confirmPassword.$setValidity('auth', true);
|
||||
}
|
||||
}
|
||||
|
||||
$scope.allowPasswordReset = Umbraco.Sys.ServerVariables.umbracoSettings.allowPasswordReset;
|
||||
|
||||
$scope.showLogin = function () {
|
||||
$scope.errorMsg = "";
|
||||
resetInputValidation();
|
||||
$scope.view = "login";
|
||||
setFieldFocus("loginForm", "username");
|
||||
}
|
||||
|
||||
$scope.showRequestPasswordReset = function () {
|
||||
$scope.errorMsg = "";
|
||||
resetInputValidation();
|
||||
$scope.view = "request-password-reset";
|
||||
$scope.showEmailResetConfirmation = false;
|
||||
setFieldFocus("requestPasswordResetForm", "email");
|
||||
}
|
||||
|
||||
$scope.showSetPassword = function () {
|
||||
$scope.errorMsg = "";
|
||||
resetInputValidation();
|
||||
$scope.view = "set-password";
|
||||
setFieldFocus("setPasswordForm", "password");
|
||||
}
|
||||
|
||||
var d = new Date();
|
||||
var konamiGreetings = new Array("Suze Sunday", "Malibu Monday", "Tequila Tuesday", "Whiskey Wednesday", "Negroni Day", "Fernet Friday", "Sancerre Saturday");
|
||||
var konamiMode = $cookies.konamiLogin;
|
||||
if (konamiMode == "1") {
|
||||
$scope.greeting = "Happy " + konamiGreetings[d.getDay()];
|
||||
} else {
|
||||
localizationService.localize("login_greeting" + d.getDay()).then(function (label) {
|
||||
$scope.greeting = label;
|
||||
}); // weekday[d.getDay()];
|
||||
}
|
||||
$scope.errorMsg = "";
|
||||
|
||||
$scope.externalLoginFormAction = Umbraco.Sys.ServerVariables.umbracoUrls.externalLoginsUrl;
|
||||
$scope.externalLoginProviders = externalLoginInfo.providers;
|
||||
$scope.externalLoginInfo = externalLoginInfo;
|
||||
$scope.resetPasswordCodeInfo = resetPasswordCodeInfo;
|
||||
$scope.backgroundImage = Umbraco.Sys.ServerVariables.umbracoSettings.loginBackgroundImage;
|
||||
|
||||
$scope.activateKonamiMode = function () {
|
||||
if ($cookies.konamiLogin == "1") {
|
||||
// somehow I can't update the cookie value using $cookies, so going native
|
||||
document.cookie = "konamiLogin=; expires=Thu, 01 Jan 1970 00:00:01 GMT;";
|
||||
document.location.reload();
|
||||
} else {
|
||||
document.cookie = "konamiLogin=1; expires=Tue, 01 Jan 2030 00:00:01 GMT;";
|
||||
$scope.$apply(function () {
|
||||
$scope.greeting = "Happy " + konamiGreetings[d.getDay()];
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$scope.loginSubmit = function (login, password) {
|
||||
|
||||
//TODO: Do validation properly like in the invite password update
|
||||
|
||||
//if the login and password are not empty we need to automatically
|
||||
// validate them - this is because if there are validation errors on the server
|
||||
// then the user has to change both username & password to resubmit which isn't ideal,
|
||||
// so if they're not empty, we'll just make sure to set them to valid.
|
||||
if (login && password && login.length > 0 && password.length > 0) {
|
||||
$scope.loginForm.username.$setValidity('auth', true);
|
||||
$scope.loginForm.password.$setValidity('auth', true);
|
||||
}
|
||||
|
||||
if ($scope.loginForm.$invalid) {
|
||||
return;
|
||||
}
|
||||
|
||||
userService.authenticate(login, password)
|
||||
.then(function (data) {
|
||||
$scope.submit(true);
|
||||
},
|
||||
function (reason) {
|
||||
|
||||
//is Two Factor required?
|
||||
if (reason.status === 402) {
|
||||
$scope.errorMsg = "Additional authentication required";
|
||||
show2FALoginDialog(reason.data.twoFactorView, $scope.submit);
|
||||
}
|
||||
else {
|
||||
$scope.errorMsg = reason.errorMsg;
|
||||
|
||||
//set the form inputs to invalid
|
||||
$scope.loginForm.username.$setValidity("auth", false);
|
||||
$scope.loginForm.password.$setValidity("auth", false);
|
||||
}
|
||||
});
|
||||
|
||||
//setup a watch for both of the model values changing, if they change
|
||||
// while the form is invalid, then revalidate them so that the form can
|
||||
// be submitted again.
|
||||
$scope.loginForm.username.$viewChangeListeners.push(function () {
|
||||
if ($scope.loginForm.username.$invalid) {
|
||||
$scope.loginForm.username.$setValidity('auth', true);
|
||||
if ($scope.resetPasswordCodeInfo.resetCodeModel) {
|
||||
$scope.showSetPassword();
|
||||
}
|
||||
});
|
||||
$scope.loginForm.password.$viewChangeListeners.push(function () {
|
||||
if ($scope.loginForm.password.$invalid) {
|
||||
$scope.loginForm.password.$setValidity('auth', true);
|
||||
else if ($scope.resetPasswordCodeInfo.errors.length > 0) {
|
||||
$scope.view = "password-reset-code-expired";
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.requestPasswordResetSubmit = function (email) {
|
||||
|
||||
//TODO: Do validation properly like in the invite password update
|
||||
|
||||
if (email && email.length > 0) {
|
||||
$scope.requestPasswordResetForm.email.$setValidity('auth', true);
|
||||
}
|
||||
|
||||
$scope.showEmailResetConfirmation = false;
|
||||
|
||||
if ($scope.requestPasswordResetForm.$invalid) {
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.errorMsg = "";
|
||||
|
||||
authResource.performRequestPasswordReset(email)
|
||||
.then(function () {
|
||||
//remove the email entered
|
||||
$scope.email = "";
|
||||
$scope.showEmailResetConfirmation = true;
|
||||
}, function (reason) {
|
||||
$scope.errorMsg = reason.errorMsg;
|
||||
$scope.requestPasswordResetForm.email.$setValidity("auth", false);
|
||||
});
|
||||
|
||||
$scope.requestPasswordResetForm.email.$viewChangeListeners.push(function () {
|
||||
if ($scope.requestPasswordResetForm.email.$invalid) {
|
||||
$scope.requestPasswordResetForm.email.$setValidity('auth', true);
|
||||
else {
|
||||
$scope.showLogin();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.setPasswordSubmit = function (password, confirmPassword) {
|
||||
init();
|
||||
|
||||
$scope.showSetPasswordConfirmation = false;
|
||||
|
||||
if (password && confirmPassword && password.length > 0 && confirmPassword.length > 0) {
|
||||
$scope.setPasswordForm.password.$setValidity('auth', true);
|
||||
$scope.setPasswordForm.confirmPassword.$setValidity('auth', true);
|
||||
}
|
||||
|
||||
if ($scope.setPasswordForm.$invalid) {
|
||||
return;
|
||||
}
|
||||
|
||||
//TODO: All of this logic can/should be shared! We should do validation the nice way instead of all of this manual stuff, see: inviteSavePassword
|
||||
authResource.performSetPassword($scope.resetPasswordCodeInfo.resetCodeModel.userId, password, confirmPassword, $scope.resetPasswordCodeInfo.resetCodeModel.resetCode)
|
||||
.then(function () {
|
||||
$scope.showSetPasswordConfirmation = true;
|
||||
$scope.resetComplete = true;
|
||||
|
||||
//reset the values in the resetPasswordCodeInfo angular so if someone logs out the change password isn't shown again
|
||||
resetPasswordCodeInfo.resetCodeModel = null;
|
||||
|
||||
}, function (reason) {
|
||||
if (reason.data && reason.data.Message) {
|
||||
$scope.errorMsg = reason.data.Message;
|
||||
}
|
||||
else {
|
||||
$scope.errorMsg = reason.errorMsg;
|
||||
}
|
||||
$scope.setPasswordForm.password.$setValidity("auth", false);
|
||||
$scope.setPasswordForm.confirmPassword.$setValidity("auth", false);
|
||||
});
|
||||
|
||||
$scope.setPasswordForm.password.$viewChangeListeners.push(function () {
|
||||
if ($scope.setPasswordForm.password.$invalid) {
|
||||
$scope.setPasswordForm.password.$setValidity('auth', true);
|
||||
}
|
||||
});
|
||||
$scope.setPasswordForm.confirmPassword.$viewChangeListeners.push(function () {
|
||||
if ($scope.setPasswordForm.confirmPassword.$invalid) {
|
||||
$scope.setPasswordForm.confirmPassword.$setValidity('auth', true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
//Now, show the correct panel:
|
||||
|
||||
if ($scope.resetPasswordCodeInfo.resetCodeModel) {
|
||||
$scope.showSetPassword();
|
||||
}
|
||||
else if ($scope.resetPasswordCodeInfo.errors.length > 0) {
|
||||
$scope.view = "password-reset-code-expired";
|
||||
}
|
||||
else {
|
||||
$scope.showLogin();
|
||||
}
|
||||
|
||||
init();
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,244 +1,249 @@
|
||||
<div ng-controller="Umbraco.Dialogs.LoginController">
|
||||
|
||||
<div id="login" class="umb-modalcolumn umb-dialog" ng-class="{'show-validation': loginForm.$invalid}" ng-cloak konami-code="activateKonamiMode()">
|
||||
<div id="login" class="umb-modalcolumn umb-dialog" ng-class="{'show-validation': loginForm.$invalid}" ng-cloak konami-code="activateKonamiMode()">
|
||||
|
||||
<div class="login-overlay__background-image" ng-if="backgroundImage" ng-style="{'background-image':'url(' + backgroundImage + ')'}"></div>
|
||||
<div class="login-overlay__background-image" ng-if="backgroundImage" ng-style="{'background-image':'url(' + backgroundImage + ')'}"></div>
|
||||
|
||||
<div class="login-overlay__logo">
|
||||
<img ng-src="assets/img/application/logo.png" ng-srcset="assets/img/application/logo@2x.png 2x, assets/img/application/logo@3x.png 3x">
|
||||
</div>
|
||||
|
||||
<div ng-show="invitedUser != null" class="umb-login-container">
|
||||
|
||||
<form name="inviteUserPasswordForm" novalidate="" ng-submit="inviteSavePassword()" val-form-manager>
|
||||
<div class="form" ng-if="inviteStep === 1">
|
||||
<h1 style="margin-bottom: 10px; text-align: left;">Hi, {{invitedUser.name}}</h1>
|
||||
<p style="line-height: 1.6; margin-bottom: 25px;">
|
||||
<localize key="user_userinviteWelcomeMessage">Welcome to Umbraco! Just need to get your password and avatar setup and then you're good to go</localize>
|
||||
</p>
|
||||
|
||||
<div class="control-group" ng-class="{error: setPasswordForm.password.$invalid}">
|
||||
<label>
|
||||
<localize key="user_newPassword">New password</localize>
|
||||
<small style="font-size: 13px;">{{invitedUserPasswordModel.passwordPolicyText}}</small>
|
||||
</label>
|
||||
<input type="password" ng-model="invitedUserPasswordModel.password" name="password" class="-full-width-input" umb-auto-focus required val-server-field="value" autocomplete="off" ng-minlength="{{invitedUserPasswordModel.passwordPolicies.minPasswordLength}}" />
|
||||
<span class="help-inline" val-msg-for="password" val-toggle-msg="required"><localize key="user_passwordIsBlank">Your new password cannot be blank!</localize></span>
|
||||
<span class="help-inline" val-msg-for="password" val-toggle-msg="minlength">Minimum {{invitedUserPasswordModel.passwordPolicies.minPasswordLength}} characters</span>
|
||||
<span class="help-inline" val-msg-for="password" val-toggle-msg="valServerField"></span>
|
||||
</div>
|
||||
|
||||
<div class="control-group" ng-class="{error: setPasswordForm.confirmPassword.$invalid}">
|
||||
<label><localize key="user_confirmNewPassword">Confirm new password</localize></label>
|
||||
<input type="password" ng-model="invitedUserPasswordModel.confirmPassword" name="confirmPassword" class="-full-width-input" required val-compare="password" autocomplete="off"/>
|
||||
<span class="help-inline" val-msg-for="confirmPassword" val-toggle-msg="required"><localize key="general_required">Required</localize></span>
|
||||
<span class="help-inline" val-msg-for="confirmPassword" val-toggle-msg="valCompare"><localize key="user_passwordMismatch">The confirmed password doesn't match the new password!</localize></span>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-between items-center">
|
||||
<umb-button type="submit"
|
||||
button-style="success"
|
||||
state="invitedUserPasswordModel.buttonState"
|
||||
label="Save password">
|
||||
</umb-button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="form" ng-if="inviteStep === 2">
|
||||
|
||||
<div class="flex justify-center items-center">
|
||||
|
||||
<ng-form name="avatarForm">
|
||||
|
||||
<umb-progress-bar style="max-width: 100px; margin-bottom: 5px;"
|
||||
ng-show="avatarFile.uploadStatus === 'uploading'"
|
||||
progress="{{ avatarFile.uploadProgress }}"
|
||||
size="s">
|
||||
</umb-progress-bar>
|
||||
|
||||
<div class="umb-info-local-item text-error mt3" ng-if="avatarFile.uploadStatus === 'error'">
|
||||
{{ avatarFile.serverErrorMessage }}
|
||||
</div>
|
||||
|
||||
<a class="umb-avatar-btn"
|
||||
ngf-select
|
||||
ng-model="avatarFile.filesHolder"
|
||||
ngf-change="changeAvatar($files, $event)"
|
||||
ngf-multiple="false"
|
||||
ngf-pattern="{{avatarFile.acceptedFileTypes}}"
|
||||
ngf-max-size="{{ avatarFile.maxFileSize }}">
|
||||
|
||||
<umb-avatar color="gray"
|
||||
size="xl"
|
||||
unknown-char="+"
|
||||
img-src="{{invitedUser.avatars[3]}}"
|
||||
img-srcset="{{invitedUser.avatars[4]}} 2x, {{invitedUser.avatars[4]}} 3x">
|
||||
</umb-avatar>
|
||||
</a>
|
||||
|
||||
</ng-form>
|
||||
<div class="login-overlay__logo">
|
||||
<img ng-src="assets/img/application/logo.png" ng-srcset="assets/img/application/logo@2x.png 2x, assets/img/application/logo@3x.png 3x">
|
||||
</div>
|
||||
|
||||
<h1 style="margin-bottom: 10px;">Upload a photo</h1>
|
||||
<p style="text-align: center; margin-bottom: 25px; line-height: 1.6em;">
|
||||
<localize key="user_userinviteAvatarMessage"></localize>
|
||||
</p>
|
||||
<div class="flex justify-center items-center">
|
||||
<umb-button type="button"
|
||||
button-style="success"
|
||||
label="Get started"
|
||||
action="getStarted()">
|
||||
</umb-button>
|
||||
<umb-button ng-if="!avatarFile.uploaded"
|
||||
type="button"
|
||||
button-style="link"
|
||||
label="Skip"
|
||||
action="getStarted()">
|
||||
</umb-button>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-show="invitedUser != null" class="umb-login-container">
|
||||
|
||||
</div>
|
||||
<form name="inviteUserPasswordForm" novalidate="" ng-submit="inviteSavePassword()" val-form-manager>
|
||||
<div class="form" ng-if="inviteStep === 1">
|
||||
<h1 style="margin-bottom: 10px; text-align: left;">Hi, {{invitedUser.name}}</h1>
|
||||
<p style="line-height: 1.6; margin-bottom: 25px;">
|
||||
<localize key="user_userinviteWelcomeMessage">Welcome to Umbraco! Just need to get your password and avatar setup and then you're good to go</localize>
|
||||
</p>
|
||||
|
||||
<div ng-show="invitedUser == null" class="umb-login-container">
|
||||
<div class="control-group" ng-class="{error: setPasswordForm.password.$invalid}">
|
||||
<label>
|
||||
<localize key="user_newPassword">New password</localize>
|
||||
<small style="font-size: 13px;">{{invitedUserPasswordModel.passwordPolicyText}}</small>
|
||||
</label>
|
||||
<input type="password" ng-model="invitedUserPasswordModel.password" name="password" class="-full-width-input" umb-auto-focus required val-server-field="value" autocomplete="off" ng-minlength="{{invitedUserPasswordModel.passwordPolicies.minPasswordLength}}" />
|
||||
<span class="help-inline" val-msg-for="password" val-toggle-msg="required"><localize key="user_passwordIsBlank">Your new password cannot be blank!</localize></span>
|
||||
<span class="help-inline" val-msg-for="password" val-toggle-msg="minlength">Minimum {{invitedUserPasswordModel.passwordPolicies.minPasswordLength}} characters</span>
|
||||
<span class="help-inline" val-msg-for="password" val-toggle-msg="valServerField"></span>
|
||||
</div>
|
||||
|
||||
<div class="form">
|
||||
<h1>{{greeting}}</h1>
|
||||
<div class="control-group" ng-class="{error: setPasswordForm.confirmPassword.$invalid}">
|
||||
<label><localize key="user_confirmNewPassword">Confirm new password</localize></label>
|
||||
<input type="password" ng-model="invitedUserPasswordModel.confirmPassword" name="confirmPassword" class="-full-width-input" required val-compare="password" autocomplete="off" />
|
||||
<span class="help-inline" val-msg-for="confirmPassword" val-toggle-msg="required"><localize key="general_required">Required</localize></span>
|
||||
<span class="help-inline" val-msg-for="confirmPassword" val-toggle-msg="valCompare"><localize key="user_passwordMismatch">The confirmed password doesn't match the new password!</localize></span>
|
||||
</div>
|
||||
|
||||
<div ng-show="view == 'login'">
|
||||
<div class="flex justify-between items-center">
|
||||
<umb-button type="submit"
|
||||
button-style="success"
|
||||
state="invitedUserPasswordModel.buttonState"
|
||||
label="Save password">
|
||||
</umb-button>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
<span ng-show="dialogData.isTimedOut"><localize key="login_timeout">Log in below</localize>.</span>
|
||||
</p>
|
||||
|
||||
<div class="external-logins" ng-if="externalLoginProviders.length > 0">
|
||||
|
||||
<div class="text-error" ng-repeat="error in externalLoginInfo.errors">
|
||||
<span>{{error}}</span>
|
||||
</div>
|
||||
|
||||
<form method="POST" name="externalLoginForm" action="{{externalLoginFormAction}}">
|
||||
|
||||
<div ng-repeat="login in externalLoginProviders">
|
||||
|
||||
<button type="submit" class="btn btn-block btn-social"
|
||||
ng-class="login.properties.SocialStyle"
|
||||
id="{{login.authType}}" name="provider" value="{{login.authType}}"
|
||||
title="Log in using your {{login.caption}} account">
|
||||
<i class="fa" ng-class="login.properties.SocialIcon"></i>
|
||||
<localize key="login_signInWith">Sign in with</localize> {{login.caption}}
|
||||
</button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
<div class="form" ng-if="inviteStep === 2">
|
||||
|
||||
<form method="POST" name="loginForm" ng-submit="loginSubmit(login, password)">
|
||||
<div class="flex justify-center items-center">
|
||||
|
||||
<div class="control-group" ng-show="loginForm.$invalid">
|
||||
<div class="text-error">{{errorMsg}}</div>
|
||||
<ng-form name="avatarForm">
|
||||
|
||||
<umb-progress-bar style="max-width: 100px; margin-bottom: 5px;"
|
||||
ng-show="avatarFile.uploadStatus === 'uploading'"
|
||||
progress="{{ avatarFile.uploadProgress }}"
|
||||
size="s">
|
||||
</umb-progress-bar>
|
||||
|
||||
<div class="umb-info-local-item text-error mt3" ng-if="avatarFile.uploadStatus === 'error'">
|
||||
{{ avatarFile.serverErrorMessage }}
|
||||
</div>
|
||||
|
||||
<a class="umb-avatar-btn"
|
||||
ngf-select
|
||||
ng-model="avatarFile.filesHolder"
|
||||
ngf-change="changeAvatar($files, $event)"
|
||||
ngf-multiple="false"
|
||||
ngf-pattern="{{avatarFile.acceptedFileTypes}}"
|
||||
ngf-max-size="{{ avatarFile.maxFileSize }}">
|
||||
|
||||
<umb-avatar color="gray"
|
||||
size="xl"
|
||||
unknown-char="+"
|
||||
img-src="{{invitedUser.avatars[3]}}"
|
||||
img-srcset="{{invitedUser.avatars[4]}} 2x, {{invitedUser.avatars[4]}} 3x">
|
||||
</umb-avatar>
|
||||
</a>
|
||||
|
||||
</ng-form>
|
||||
</div>
|
||||
|
||||
<h1 style="margin-bottom: 10px;">Upload a photo</h1>
|
||||
<p style="text-align: center; margin-bottom: 25px; line-height: 1.6em;">
|
||||
<localize key="user_userinviteAvatarMessage"></localize>
|
||||
</p>
|
||||
<div class="flex justify-center items-center">
|
||||
<umb-button type="button"
|
||||
button-style="success"
|
||||
label="Get started"
|
||||
action="getStarted()">
|
||||
</umb-button>
|
||||
<umb-button ng-if="!avatarFile.uploaded"
|
||||
type="button"
|
||||
button-style="link"
|
||||
label="Skip"
|
||||
action="getStarted()">
|
||||
</umb-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group" ng-class="{error: loginForm.username.$invalid}">
|
||||
<label><localize key="general_username">Username</localize></label>
|
||||
<input type="text" ng-model="login" name="username" class="-full-width-input" localize="placeholder" placeholder="@placeholders_usernameHint" />
|
||||
</div>
|
||||
|
||||
<div class="control-group" ng-class="{error: loginForm.password.$invalid}">
|
||||
<label><localize key="general_password">Password</localize></label>
|
||||
<div class="password-toggle">
|
||||
<input type="password" ng-model="password" name="password" class="-full-width-input" localize="placeholder" placeholder="@placeholders_password" autocomplete="off" /><a ng-click="togglePassword()">Toggle</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-between items-center">
|
||||
<button type="submit" class="btn btn-success" val-trigger-change="#login .form input"><localize key="general_login">Login</localize></button>
|
||||
<div ng-show="allowPasswordReset">
|
||||
<a class="muted" style="text-decoration: underline;" href="#" prevent-default ng-click="showRequestPasswordReset()"><localize key="login_forgottenPassword">Forgotten password?</localize></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div ng-show="view == 'request-password-reset'">
|
||||
<p>
|
||||
<localize key="login_forgottenPasswordInstruction">An email will be sent to the address specified with a link to reset your password</localize>
|
||||
</p>
|
||||
<div ng-show="invitedUser == null" class="umb-login-container">
|
||||
|
||||
<form method="POST" name="requestPasswordResetForm" ng-submit="requestPasswordResetSubmit(email)">
|
||||
<div class="control-group" ng-class="{error: requestPasswordResetForm.email.$invalid}">
|
||||
<label><localize key="general_email">Email</localize></label>
|
||||
<input type="email" ng-model="email" name="email" class="-full-width-input" localize="placeholder" placeholder="@placeholders_email" />
|
||||
<div class="form">
|
||||
<h1>{{greeting}}</h1>
|
||||
|
||||
<div ng-show="view == 'login'">
|
||||
|
||||
<p>
|
||||
<span ng-show="dialogData.isTimedOut"><localize key="login_timeout">Log in below</localize>.</span>
|
||||
</p>
|
||||
|
||||
<div class="external-logins" ng-if="externalLoginProviders.length > 0">
|
||||
|
||||
<div class="text-error" ng-repeat="error in externalLoginInfo.errors">
|
||||
<span>{{error}}</span>
|
||||
</div>
|
||||
|
||||
<form method="POST" name="externalLoginForm" action="{{externalLoginFormAction}}">
|
||||
|
||||
<div ng-repeat="login in externalLoginProviders">
|
||||
|
||||
<button type="submit" class="btn btn-block btn-social"
|
||||
ng-class="login.properties.SocialStyle"
|
||||
id="{{login.authType}}" name="provider" value="{{login.authType}}"
|
||||
title="Log in using your {{login.caption}} account">
|
||||
<i class="fa" ng-class="login.properties.SocialIcon"></i>
|
||||
<localize key="login_signInWith">Sign in with</localize> {{login.caption}}
|
||||
</button>
|
||||
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
<form method="POST" name="loginForm" ng-submit="loginSubmit(login, password)">
|
||||
|
||||
<div class="control-group" ng-show="loginForm.$invalid">
|
||||
<div class="text-error">{{errorMsg}}</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group" ng-class="{error: loginForm.username.$invalid}">
|
||||
<label><localize key="general_username">Username</localize></label>
|
||||
<input type="text" ng-model="login" name="username" class="-full-width-input" localize="placeholder" placeholder="@placeholders_usernameHint" />
|
||||
</div>
|
||||
|
||||
<div class="control-group" ng-class="{error: loginForm.password.$invalid}">
|
||||
<label><localize key="general_password">Password</localize></label>
|
||||
<div class="password-toggle">
|
||||
<input type="password" ng-model="password" name="password" class="-full-width-input" localize="placeholder" placeholder="@placeholders_password" autocomplete="off" /><a ng-click="togglePassword()">Toggle</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-between items-center">
|
||||
<umb-button button-style="success"
|
||||
disabled="loginForm.$invalid"
|
||||
label-key="general_login"
|
||||
state="loginStates.submitButton"
|
||||
type="submit">
|
||||
</umb-button>
|
||||
<div ng-show="allowPasswordReset">
|
||||
<a class="muted" style="text-decoration: underline;" href="#" prevent-default ng-click="showRequestPasswordReset()"><localize key="login_forgottenPassword">Forgotten password?</localize></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div ng-show="view == 'request-password-reset'">
|
||||
<p>
|
||||
<localize key="login_forgottenPasswordInstruction">An email will be sent to the address specified with a link to reset your password</localize>
|
||||
</p>
|
||||
|
||||
<form method="POST" name="requestPasswordResetForm" ng-submit="requestPasswordResetSubmit(email)">
|
||||
<div class="control-group" ng-class="{error: requestPasswordResetForm.email.$invalid}">
|
||||
<label><localize key="general_email">Email</localize></label>
|
||||
<input type="email" ng-model="email" name="email" class="-full-width-input" localize="placeholder" placeholder="@placeholders_email" />
|
||||
</div>
|
||||
|
||||
<div class="control-group" ng-show="requestPasswordResetForm.$invalid">
|
||||
<div class="text-error">{{errorMsg}}</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group" ng-show="showEmailResetConfirmation">
|
||||
<div class="text-info">
|
||||
<localize key="login_requestPasswordResetConfirmation">An email with password reset instructions will be sent to the specified address if it matched our records</localize>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-between items-center">
|
||||
<button type="submit" class="btn btn-success" val-trigger-change="#login .form input"><localize key="general_submit">Submit</localize></button>
|
||||
<a class="muted" href="#" prevent-default ng-click="showLogin()" style="text-decoration: underline;"><localize key="login_returnToLogin">Return to login form</localize></a>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div ng-show="view == 'set-password'">
|
||||
|
||||
<p ng-hide="resetComplete">
|
||||
<localize key="login_setPasswordInstruction">Please provide a new password.</localize>
|
||||
</p>
|
||||
|
||||
<form method="POST" name="setPasswordForm" ng-submit="setPasswordSubmit(password, confirmPassword)">
|
||||
|
||||
<div ng-hide="resetComplete" class="control-group" ng-class="{error: setPasswordForm.password.$invalid}">
|
||||
<label><localize key="user_newPassword">New password</localize></label>
|
||||
<input type="password" ng-model="password" name="password" class="-full-width-input" localize="placeholder" placeholder="@placeholders_password" />
|
||||
</div>
|
||||
|
||||
<div ng-hide="resetComplete" class="control-group" ng-class="{error: setPasswordForm.confirmPassword.$invalid}">
|
||||
<label><localize key="user_confirmNewPassword">Confirm new password</localize></label>
|
||||
<input type="password" ng-model="confirmPassword" name="confirmPassword" class="-full-width-input" localize="placeholder" placeholder="@placeholders_confirmPassword" />
|
||||
</div>
|
||||
|
||||
<div ng-hide="resetComplete" class="control-group" ng-show="setPasswordForm.$invalid">
|
||||
<div class="text-error">{{errorMsg}}</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group" ng-show="showSetPasswordConfirmation">
|
||||
<div class="text-info">
|
||||
<localize key="login_setPasswordConfirmation">Your new password has been set and you may now use it to log in.</localize>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-between items-center">
|
||||
<button ng-hide="resetComplete" type="submit" class="btn btn-success" val-trigger-change="#login .form input"><localize key="general_submit">Submit</localize></button>
|
||||
<a class="muted" href="#" prevent-default ng-click="showLogin()"><localize key="login_returnToLogin">Return to login form</localize></a>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div ng-show="view == 'password-reset-code-expired'">
|
||||
<div class="text-error" ng-repeat="error in resetPasswordCodeInfo.errors">
|
||||
<span>{{error}}</span>
|
||||
</div>
|
||||
|
||||
<div class="switch-view">
|
||||
<a class="muted" href="#" prevent-default ng-click="showLogin()"><localize key="login_returnToLogin">Return to login form</localize></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group" ng-show="requestPasswordResetForm.$invalid">
|
||||
<div class="text-error">{{errorMsg}}</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group" ng-show="showEmailResetConfirmation">
|
||||
<div class="text-info">
|
||||
<localize key="login_requestPasswordResetConfirmation">An email with password reset instructions will be sent to the specified address if it matched our records</localize>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-between items-center">
|
||||
<button type="submit" class="btn btn-success" val-trigger-change="#login .form input"><localize key="general_submit">Submit</localize></button>
|
||||
<a class="muted" href="#" prevent-default ng-click="showLogin()" style="text-decoration: underline;"><localize key="login_returnToLogin">Return to login form</localize></a>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div ng-show="view == 'set-password'">
|
||||
|
||||
<p ng-hide="resetComplete">
|
||||
<localize key="login_setPasswordInstruction">Please provide a new password.</localize>
|
||||
</p>
|
||||
|
||||
<form method="POST" name="setPasswordForm" ng-submit="setPasswordSubmit(password, confirmPassword)">
|
||||
|
||||
<div ng-hide="resetComplete" class="control-group" ng-class="{error: setPasswordForm.password.$invalid}">
|
||||
<label><localize key="user_newPassword">New password</localize></label>
|
||||
<input type="password" ng-model="password" name="password" class="-full-width-input" localize="placeholder" placeholder="@placeholders_password" />
|
||||
</div>
|
||||
|
||||
<div ng-hide="resetComplete" class="control-group" ng-class="{error: setPasswordForm.confirmPassword.$invalid}">
|
||||
<label><localize key="user_confirmNewPassword">Confirm new password</localize></label>
|
||||
<input type="password" ng-model="confirmPassword" name="confirmPassword" class="-full-width-input" localize="placeholder" placeholder="@placeholders_confirmPassword" />
|
||||
</div>
|
||||
|
||||
<div ng-hide="resetComplete" class="control-group" ng-show="setPasswordForm.$invalid">
|
||||
<div class="text-error">{{errorMsg}}</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group" ng-show="showSetPasswordConfirmation">
|
||||
<div class="text-info">
|
||||
<localize key="login_setPasswordConfirmation">Your new password has been set and you may now use it to log in.</localize>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex justify-between items-center">
|
||||
<button ng-hide="resetComplete" type="submit" class="btn btn-success" val-trigger-change="#login .form input"><localize key="general_submit">Submit</localize></button>
|
||||
<a class="muted" href="#" prevent-default ng-click="showLogin()"><localize key="login_returnToLogin">Return to login form</localize></a>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div ng-show="view == 'password-reset-code-expired'">
|
||||
<div class="text-error" ng-repeat="error in resetPasswordCodeInfo.errors">
|
||||
<span>{{error}}</span>
|
||||
</div>
|
||||
|
||||
<div class="switch-view">
|
||||
<a class="muted" href="#" prevent-default ng-click="showLogin()"><localize key="login_returnToLogin">Return to login form</localize></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user