Merge branch 'v8/8.9' into v8/dev

# Conflicts:
#	src/Umbraco.Web.UI/Umbraco/config/lang/en.xml
This commit is contained in:
Sebastiaan Janssen
2020-10-05 20:58:47 +02:00
70 changed files with 1742 additions and 571 deletions

View File

@@ -13,7 +13,10 @@
}
});
function UmbLoginController($scope, $location, currentUserResource, formHelper, mediaHelper, umbRequestHelper, Upload, localizationService, userService, externalLoginInfo, resetPasswordCodeInfo, $timeout, authResource, $q, $route) {
function UmbLoginController($scope, $location, currentUserResource, formHelper,
mediaHelper, umbRequestHelper, Upload, localizationService,
userService, externalLoginInfo, externalLoginInfoService,
resetPasswordCodeInfo, $timeout, authResource, $q, $route) {
const vm = this;
@@ -43,7 +46,15 @@
vm.allowPasswordReset = Umbraco.Sys.ServerVariables.umbracoSettings.canSendRequiredEmail && Umbraco.Sys.ServerVariables.umbracoSettings.allowPasswordReset;
vm.errorMsg = "";
vm.externalLoginFormAction = Umbraco.Sys.ServerVariables.umbracoUrls.externalLoginsUrl;
vm.externalLoginProviders = externalLoginInfo.providers;
vm.externalLoginProviders = externalLoginInfoService.getLoginProviders();
vm.externalLoginProviders.forEach(x => {
x.customView = externalLoginInfoService.getLoginProviderView(x);
// if there are errors set for this specific provider than assign them directly to the model
if (externalLoginInfo.errorProvider === x.authType) {
x.errors = externalLoginInfo.errors;
}
});
vm.denyLocalLogin = externalLoginInfoService.hasDenyLocalLogin();
vm.externalLoginInfo = externalLoginInfo;
vm.resetPasswordCodeInfo = resetPasswordCodeInfo;
vm.backgroundImage = Umbraco.Sys.ServerVariables.umbracoSettings.loginBackgroundImage;
@@ -62,7 +73,7 @@
vm.setPasswordSubmit = setPasswordSubmit;
vm.labels = {};
localizationService.localizeMany([
vm.usernameIsEmail ? "general_email" : "general_username",
vm.usernameIsEmail ? "general_email" : "general_username",
vm.usernameIsEmail ? "placeholders_email" : "placeholders_usernameHint",
vm.usernameIsEmail ? "placeholders_emptyEmail" : "placeholders_emptyUsername",
"placeholders_emptyPassword"]
@@ -72,9 +83,11 @@
vm.labels.usernameError = data[2];
vm.labels.passwordError = data[3];
});
vm.twoFactor = {};
vm.loginSuccess = loginSuccess;
function onInit() {
// Check if it is a new user
@@ -98,11 +111,11 @@
//localize the text
localizationService.localize("errorHandling_errorInPasswordFormat", [
vm.invitedUserPasswordModel.passwordPolicies.minPasswordLength,
vm.invitedUserPasswordModel.passwordPolicies.minNonAlphaNumericChars
]).then(function (data) {
vm.invitedUserPasswordModel.passwordPolicyText = data;
});
vm.invitedUserPasswordModel.passwordPolicies.minPasswordLength,
vm.invitedUserPasswordModel.passwordPolicies.minNonAlphaNumericChars
]).then(function (data) {
vm.invitedUserPasswordModel.passwordPolicyText = data;
});
})
]).then(function () {
vm.inviteStep = Number(inviteVal);
@@ -144,12 +157,12 @@
function getStarted() {
$location.search('invite', null);
if(vm.onLogin) {
if (vm.onLogin) {
vm.onLogin();
}
}
function inviteSavePassword () {
function inviteSavePassword() {
if (formHelper.submitForm({ scope: $scope })) {
@@ -197,37 +210,41 @@
SetTitle();
}
function loginSuccess() {
vm.loginStates.submitButton = "success";
userService._retryRequestQueue(true);
if (vm.onLogin) {
vm.onLogin();
}
}
function loginSubmit() {
if (formHelper.submitForm({ scope: $scope })) {
if (formHelper.submitForm({ scope: $scope, formCtrl: vm.loginForm })) {
//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 (vm.login && vm.password && vm.login.length > 0 && vm.password.length > 0) {
if (vm.login && vm.password && vm.login.length > 0 && vm.password.length > 0) {
vm.loginForm.username.$setValidity('auth', true);
vm.loginForm.password.$setValidity('auth', true);
}
if (vm.loginForm.$invalid) {
SetTitle();
return;
}
// make sure that we are returning to the login view.
vm.view = "login";
vm.loginStates.submitButton = "busy";
userService.authenticate(vm.login, vm.password)
.then(function(data) {
vm.loginStates.submitButton = "success";
userService._retryRequestQueue(true);
if (vm.onLogin) {
vm.onLogin();
}
},
function(reason) {
.then(function (data) {
loginSuccess();
},
function (reason) {
//is Two Factor required?
if (reason.status === 402) {
@@ -249,13 +266,13 @@
//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.
vm.loginForm.username.$viewChangeListeners.push(function() {
vm.loginForm.username.$viewChangeListeners.push(function () {
if (vm.loginForm.$invalid) {
vm.loginForm.username.$setValidity('auth', true);
vm.loginForm.password.$setValidity('auth', true);
}
});
vm.loginForm.password.$viewChangeListeners.push(function() {
vm.loginForm.password.$viewChangeListeners.push(function () {
if (vm.loginForm.$invalid) {
vm.loginForm.username.$setValidity('auth', true);
vm.loginForm.password.$setValidity('auth', true);
@@ -460,7 +477,7 @@
case "2fa-login":
title = "Two Factor Authentication";
break;
}
}
$scope.$emit("$changeTitle", title);
}

View File

@@ -86,6 +86,7 @@ Use this directive to render an umbraco button. The directive can be used to gen
bindings: {
action: "&?",
href: "@?",
hrefTarget: "@?",
type: "@",
buttonStyle: "@?",
state: "<?",
@@ -123,6 +124,10 @@ Use this directive to render an umbraco button. The directive can be used to gen
vm.innerState = "init";
vm.generalActions = vm.labelKey === "general_actions";
if (!vm.type) {
vm.type = "button"; // set the default
}
vm.buttonLabel = vm.label;
// is this a primary button style (i.e. anything but an 'info' button)?
vm.isPrimaryButtonStyle = vm.buttonStyle && vm.buttonStyle !== 'info';
@@ -166,7 +171,7 @@ Use this directive to render an umbraco button. The directive can be used to gen
vm.innerState = changes.state.currentValue;
}
if (changes.state.currentValue === 'success' || changes.state.currentValue === 'error') {
// set the state back to 'init' after a success or error
// set the state back to 'init' after a success or error
$timeout(function () {
vm.innerState = 'init';
}, 2000);
@@ -191,6 +196,13 @@ Use this directive to render an umbraco button. The directive can be used to gen
setButtonLabel();
}
// watch for type changes
if(changes.type) {
if (!vm.type) {
vm.type = "button";// set the default
}
}
}
function clickButton(event) {

View File

@@ -6,6 +6,7 @@ angular.module('umbraco.interceptors', [])
$httpProvider.interceptors.push('securityInterceptor');
$httpProvider.interceptors.push('debugRequestInterceptor');
$httpProvider.interceptors.push('requiredHeadersInterceptor');
$httpProvider.interceptors.push('doNotPostDollarVariablesOnPostRequestInterceptor');
$httpProvider.interceptors.push('cultureRequestInterceptor');

View File

@@ -0,0 +1,28 @@
(function () {
'use strict';
/**
* Used to set required headers on all requests where necessary
* @param {any} $q
* @param {any} urlHelper
*/
function requiredHeadersInterceptor($q, urlHelper) {
return {
//dealing with requests:
'request': function (config) {
// This is a standard header that should be sent for all ajax requests and is required for
// how the server handles auth rejections, etc... see
// https://github.com/aspnet/AspNetKatana/blob/e2b18ec84ceab7ffa29d80d89429c9988ab40144/src/Microsoft.Owin.Security.Cookies/Provider/DefaultBehavior.cs
// https://brockallen.com/2013/10/27/using-cookie-authentication-middleware-with-web-api-and-401-response-codes/
config.headers["X-Requested-With"] = "XMLHttpRequest";
return config;
}
};
}
angular.module('umbraco.interceptors').factory('requiredHeadersInterceptor', requiredHeadersInterceptor);
})();

View File

@@ -0,0 +1,67 @@
/**
* @ngdoc service
* @name umbraco.services.externalLoginInfoService
* @description A service for working with external login providers
**/
function externalLoginInfoService(externalLoginInfo, umbRequestHelper) {
function getLoginProvider(provider) {
if (provider) {
var found = _.find(externalLoginInfo.providers, x => x.authType == provider);
return found;
}
return null;
}
function getLoginProviderView(provider) {
if (provider && provider.properties.UmbracoBackOfficeExternalLoginOptions && provider.properties.UmbracoBackOfficeExternalLoginOptions.CustomBackOfficeView) {
return umbRequestHelper.convertVirtualToAbsolutePath(provider.properties.UmbracoBackOfficeExternalLoginOptions.CustomBackOfficeView);
}
return null;
}
/**
* Returns true if any provider denies local login if `provider` is null, else whether the passed
* @param {any} provider
*/
function hasDenyLocalLogin(provider) {
if (!provider) {
return _.some(externalLoginInfo.providers, x => x.properties.UmbracoBackOfficeExternalLoginOptions.DenyLocalLogin === true);
}
else {
return provider.properties.UmbracoBackOfficeExternalLoginOptions.DenyLocalLogin;
}
}
/**
* Returns all login providers
*/
function getLoginProviders() {
return externalLoginInfo.providers;
}
/** Returns all logins providers that have options that the user can interact with */
function getLoginProvidersWithOptions() {
// only include providers that allow manual linking or ones that provide a custom view
var providers = _.filter(externalLoginInfo.providers, x => {
// transform the data and also include the custom view as a nicer property
x.customView = getLoginProviderView(x);
if (x.customView) {
return true;
}
else {
return x.properties.ExternalSignInAutoLinkOptions.AllowManualLinking;
}
});
return providers;
}
return {
hasDenyLocalLogin: hasDenyLocalLogin,
getLoginProvider: getLoginProvider,
getLoginProviders: getLoginProviders,
getLoginProvidersWithOptions: getLoginProvidersWithOptions,
getLoginProviderView: getLoginProviderView
};
}
angular.module('umbraco.services').factory('externalLoginInfoService', externalLoginInfoService);

View File

@@ -5,11 +5,15 @@
var elementToInert = document.querySelector('#mainwrapper');
function addInertAttribute() {
elementToInert.setAttribute('inert', true);
if (elementToInert) {
elementToInert.setAttribute('inert', true);
}
}
function removeInertAttribute() {
elementToInert.removeAttribute('inert');
if (elementToInert) {
elementToInert.removeAttribute('inert');
}
}
var service = {

View File

@@ -1,5 +1,5 @@
angular.module('umbraco.services')
.factory('userService', function ($rootScope, eventsService, $q, $location, requestRetryQueue, authResource, emailMarketingResource, $timeout, angularHelper) {
.factory('userService', function ($rootScope, eventsService, $q, $location, $window, requestRetryQueue, authResource, emailMarketingResource, $timeout, angularHelper) {
var currentUser = null;
var lastUserId = null;
@@ -166,7 +166,7 @@ angular.module('umbraco.services')
},
/** Internal method to retry all request after sucessfull login */
_retryRequestQueue: function(success) {
_retryRequestQueue: function (success) {
retryRequestQueue(success)
},
@@ -185,18 +185,22 @@ angular.module('umbraco.services')
authenticate: function (login, password) {
return authResource.performLogin(login, password)
.then(function(data) {
.then(function (data) {
// Check if user has a start node set.
if(data.startContentIds.length === 0 && data.startMediaIds.length === 0){
if (data.startContentIds.length === 0 && data.startMediaIds.length === 0) {
var errorMsg = "User has no start-nodes";
var result = { errorMsg: errorMsg, user: data, authenticated: false, lastUserId: lastUserId, loginType: "credentials" };
eventsService.emit("app.notAuthenticated", result);
// TODO: How does this make sense? How can you throw from a promise? Does this get caught by the rejection?
// If so then return $q.reject should be used.
throw result;
}
return data;
}, function (err) {
return $q.reject(err);
}).then(this.setAuthenticationSuccessful);
},
setAuthenticationSuccessful: function (data) {
@@ -218,8 +222,14 @@ angular.module('umbraco.services')
return authResource.performLogout()
.then(function (data) {
userAuthExpired();
//done!
return null;
if (data && data.signOutRedirectUrl) {
$window.location.replace(data.signOutRedirectUrl);
}
else {
//done!
return null;
}
});
},
@@ -235,9 +245,9 @@ angular.module('umbraco.services')
setCurrentUser(data);
deferred.resolve(currentUser);
}, function () {
}, function (err) {
//it failed, so they are not logged in
deferred.reject();
deferred.reject(err);
});
return deferred.promise;
@@ -245,7 +255,7 @@ angular.module('umbraco.services')
/** Returns the current user object in a promise */
getCurrentUser: function (args) {
if (!currentUser) {
return authResource.getCurrentUser()
.then(function (data) {
@@ -260,9 +270,9 @@ angular.module('umbraco.services')
setCurrentUser(data);
return $q.when(currentUser);
}, function () {
}, function (err) {
//it failed, so they are not logged in
return $q.reject(currentUser);
return $q.reject(err);
});
}

View File

@@ -1,5 +1,8 @@
angular.module("umbraco")
.controller("Umbraco.Overlays.UserController", function ($scope, $location, $timeout, dashboardResource, userService, historyService, eventsService, externalLoginInfo, authResource, currentUserResource, formHelper, localizationService) {
.controller("Umbraco.Overlays.UserController", function ($scope, $location, $timeout,
dashboardResource, userService, historyService, eventsService,
externalLoginInfo, externalLoginInfoService, authResource,
currentUserResource, formHelper, localizationService) {
$scope.history = historyService.getCurrent();
//$scope.version = Umbraco.Sys.ServerVariables.application.version + " assembly: " + Umbraco.Sys.ServerVariables.application.assemblyVersion;
@@ -14,7 +17,12 @@ angular.module("umbraco")
});
}
*/
$scope.externalLoginProviders = externalLoginInfo.providers;
// Set flag if any have deny local login, in which case we must disable all password functionality
$scope.denyLocalLogin = externalLoginInfoService.hasDenyLocalLogin();
// Only include login providers that have editable options
$scope.externalLoginProviders = externalLoginInfoService.getLoginProvidersWithOptions();
$scope.externalLinkLoginFormAction = Umbraco.Sys.ServerVariables.umbracoUrls.externalLinkLoginsUrl;
var evts = [];
evts.push(eventsService.on("historyService.add", function (e, args) {
@@ -72,10 +80,9 @@ angular.module("umbraco")
//updateTimeout();
authResource.getCurrentUserLinkedLogins().then(function(logins) {
//reset all to be un-linked
for (var provider in $scope.externalLoginProviders) {
$scope.externalLoginProviders[provider].linkedProviderKey = undefined;
}
$scope.externalLoginProviders.forEach(provider => provider.linkedProviderKey = undefined);
//set the linked logins
for (var login in logins) {

View File

@@ -21,6 +21,7 @@
</umb-button>
<umb-button
ng-if="!denyLocalLogin"
alias="changePassword"
type="button"
action="togglePasswordFields()"
@@ -49,27 +50,32 @@
<div ng-repeat="login in externalLoginProviders">
<form ng-submit="linkProvider($event)" ng-if="login.linkedProviderKey == undefined" method="POST" action="{{externalLinkLoginFormAction}}" name="oauthloginform" id="oauthloginform-{{login.authType}}">
<input type="hidden" name="provider" value="{{login.authType}}" />
<button class="btn btn-block btn-social"
<div ng-if="login.customView" ng-include="login.customView"></div>
<div ng-if="!login.customView && login.properties.ExternalSignInAutoLinkOptions.AllowManualLinking">
<form ng-submit="linkProvider($event)" ng-if="login.linkedProviderKey == undefined" method="POST" action="{{externalLinkLoginFormAction}}" name="oauthloginform" id="oauthloginform-{{login.authType}}">
<input type="hidden" name="provider" value="{{login.authType}}" />
<button class="btn btn-block btn-social"
ng-class="login.properties.SocialStyle"
id="{{login.authType}}">
<i class="fa" ng-class="login.properties.SocialIcon"></i>
<localize key="defaultdialogs_linkYour">Link your</localize>&nbsp;{{login.caption}}&nbsp;<localize key="defaultdialogs_account">account</localize>
</button>
</form>
<button ng-if="login.linkedProviderKey != undefined"
ng-click="unlink($event, login.authType, login.linkedProviderKey)"
class="btn btn-block btn-social"
ng-class="login.properties.SocialStyle"
id="{{login.authType}}">
id="{{login.authType}}"
name="provider"
value="{{login.authType}}">
<i class="fa" ng-class="login.properties.SocialIcon"></i>
<localize key="defaultdialogs_linkYour">Link your</localize>&nbsp;{{login.caption}}&nbsp;<localize key="defaultdialogs_account">account</localize>
<localize key="defaultdialogs_unLinkYour">Un-link your</localize>&nbsp;{{login.caption}}&nbsp;<localize key="defaultdialogs_account">account</localize>
</button>
</form>
<button ng-if="login.linkedProviderKey != undefined"
ng-click="unlink($event, login.authType, login.linkedProviderKey)"
class="btn btn-block btn-social"
ng-class="login.properties.SocialStyle"
id="{{login.authType}}"
name="provider"
value="{{login.authType}}">
<i class="fa" ng-class="login.properties.SocialIcon"></i>
<localize key="defaultdialogs_unLinkYour">Un-link your</localize>&nbsp;{{login.caption}}&nbsp;<localize key="defaultdialogs_account">account</localize>
</button>
</div>
</div>
</div>
@@ -86,7 +92,8 @@
</ul>
</div>
<div ng-if="showPasswordFields">
<div ng-if="showPasswordFields && !denyLocalLogin">
<h5>
<localize key="general_changePassword">Change password</localize>

View File

@@ -8,7 +8,7 @@
<img src="assets/img/application/umbraco_logo_white.svg">
</div>
<div ng-show="vm.invitedUser != null" class="umb-login-container">
<div ng-if="!vm.denyLocalLogin" ng-show="vm.invitedUser != null" class="umb-login-container">
<form name="inviteUserPasswordForm" novalidate="" ng-submit="vm.inviteSavePassword()" val-form-manager>
<div class="form" ng-if="vm.inviteStep === 1">
@@ -100,7 +100,7 @@
</div>
</div>
<div ng-show="vm.invitedUser == null && vm.inviteStep === 3" ng-if="vm.inviteStep === 3" class="umb-login-container">
<div ng-show="vm.invitedUser == null && vm.inviteStep === 3" ng-if="!vm.denyLocalLogin && vm.inviteStep === 3" class="umb-login-container">
<div class="form">
<h1 style="margin-bottom: 10px; text-align: left;">Hi there</h1>
<p style="line-height: 1.6; margin-bottom: 25px;">
@@ -120,29 +120,31 @@
</p>
<div class="external-logins" ng-if="vm.externalLoginProviders.length > 0">
<div ng-repeat="login in vm.externalLoginProviders">
<div class="text-error" ng-repeat="error in vm.externalLoginInfo.errors">
<span>{{error}}</span>
</div>
<form method="POST" name="vm.externalLoginForm" action="{{vm.externalLoginFormAction}}">
<div ng-repeat="login in vm.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>&nbsp;{{login.caption}}
</button>
<div ng-if="!login.customView">
<form method="POST" action="{{vm.externalLoginFormAction}}">
<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>&nbsp;{{login.caption}}
</button>
</form>
<div ng-if="login.errors">
<div class="text-error" ng-repeat="error in login.errors">
<span>{{error}}</span>
</div>
</div>
</div>
</form>
<div ng-if="login.customView" ng-include="login.customView"></div>
</div>
</div>
<form method="POST" name="vm.loginForm" ng-submit="vm.loginSubmit()">
<form ng-if="!vm.denyLocalLogin" method="POST" name="vm.loginForm" ng-submit="vm.loginSubmit()">
<div ng-messages="vm.loginForm.$error" class="control-group" aria-live="assertive">
<p ng-message="auth" class="text-error" role="alert" tabindex="0">{{vm.errorMsg}}</p>
@@ -178,7 +180,7 @@
</form>
</div>
<div ng-show="vm.view == 'request-password-reset'">
<div ng-if="!vm.denyLocalLogin" ng-show="vm.view == 'request-password-reset'">
<p tabindex="0">
<localize key="login_forgottenPasswordInstruction">An email will be sent to the address specified with a link to reset your password</localize>
</p>
@@ -209,7 +211,7 @@
</form>
</div>
<div ng-show="vm.view == 'set-password'">
<div ng-if="!vm.denyLocalLogin" ng-show="vm.view == 'set-password'">
<p ng-hide="vm.resetComplete">
<localize key="login_setPasswordInstruction">Please provide a new password.</localize>
@@ -245,7 +247,7 @@
</form>
</div>
<div ng-show="vm.view == 'password-reset-code-expired'">
<div ng-if="!vm.denyLocalLogin" ng-show="vm.view == 'password-reset-code-expired'">
<div class="text-error" ng-repeat="error in vm.resetPasswordCodeInfo.errors">
<p class="text-error">{{error}}</p>
</div>
@@ -255,7 +257,7 @@
</div>
</div>
<div ng-show="vm.view == '2fa-login'">
<div ng-if="!vm.denyLocalLogin" ng-show="vm.view == '2fa-login'">
<div ng-include='vm.twoFactor.view'></div>
</div>

View File

@@ -1,10 +1,12 @@
<div class="btn-group umb-button-group" ng-class="{ 'dropup': direction === 'up', '-with-button-group-toggle': subButtons.length > 0 }">
<umb-button
type="button"
ng-if="defaultButton"
alias="{{defaultButton.alias ? defaultButton.alias : 'groupPrimary' }}"
type="{{defaultButton.type}}"
action="defaultButton.handler()"
href="{{defaultButton.href}}"
href-target="{{defaultButton.hrefTarget}}"
button-style="{{buttonStyle}}"
state="state"
label="{{defaultButton.labelKey}}"

View File

@@ -9,6 +9,7 @@
<a ng-if="vm.type === 'link'"
ng-href="{{vm.href}}"
ng-attr-target="{{(vm.hrefTarget) ? vm.hrefTarget : undefined}}"
class="btn umb-button__button {{vm.style}} umb-button--{{vm.size}} umb-outline"
ng-click="vm.clickButton($event)"
hotkey="{{vm.shortcut}}"

View File

@@ -1,7 +1,9 @@
(function () {
"use strict";
function UserEditController($scope, eventsService, $q, $location, $routeParams, formHelper, usersResource, userService, contentEditingHelper, localizationService, mediaHelper, Upload, umbRequestHelper, usersHelper, authResource, dateHelper, editorService, overlayService) {
function UserEditController($scope, eventsService, $q, $location, $routeParams, formHelper, usersResource,
userService, contentEditingHelper, localizationService, mediaHelper, Upload, umbRequestHelper,
usersHelper, authResource, dateHelper, editorService, overlayService, externalLoginInfoService) {
var currentLoggedInUser = null;
@@ -46,6 +48,8 @@
vm.changePassword = changePassword;
vm.toggleChangePassword = toggleChangePassword;
vm.denyLocalLogin = externalLoginInfoService.hasDenyLocalLogin();
function init() {
vm.loading = true;

View File

@@ -7,6 +7,7 @@
<umb-editor-view>
<umb-editor-header name="vm.user.name"
name-locked="vm.denyLocalLogin"
hide-icon="true"
hide-description="true"
hide-alias="true"

View File

@@ -0,0 +1,13 @@
(function () {
"use strict";
function DetailsController($scope, externalLoginInfoService) {
var vm = this;
vm.denyLocalLogin = externalLoginInfoService.hasDenyLocalLogin();
}
angular.module("umbraco").controller("Umbraco.Editors.Users.DetailsController", DetailsController);
})();

View File

@@ -1,4 +1,4 @@
<div class="umb-user-details-details">
<div ng-controller="Umbraco.Editors.Users.DetailsController as vm" class="umb-user-details-details">
<div class="umb-user-details-details__main-content">
@@ -10,22 +10,31 @@
<umb-control-group label="@general_email" required="true" alias="email">
<input type="email"
localize="placeholder"
placeholder="@placeholders_enteremail"
class="input-block-level"
ng-model="model.user.email"
umb-auto-focus
name="email"
id="email"
val-email
ng-required="true"
val-server-field="Email" />
<span ng-messages="userProfileForm.email.$error" show-validation-on-submit>
<span class="help-inline" ng-message="required"><localize key="general_required">Required</localize></span>
<span class="help-inline" ng-message="valEmail"><localize key="validation_invalidEmail">Invalid email</localize></span>
<span class="help-inline" ng-message="valServerField">{{userProfileForm.email.errorMsg}}</span>
</span>
<div ng-if="!vm.denyLocalLogin">
<input type="email"
localize="placeholder"
placeholder="@placeholders_enteremail"
class="input-block-level"
ng-model="model.user.email"
umb-auto-focus
name="email"
id="email"
val-email
ng-required="true"
val-server-field="Email" />
<span ng-messages="userProfileForm.email.$error" show-validation-on-submit>
<span class="help-inline" ng-message="required"><localize key="general_required">Required</localize></span>
<span class="help-inline" ng-message="valEmail"><localize key="validation_invalidEmail">Invalid email</localize></span>
<span class="help-inline" ng-message="valServerField">{{userProfileForm.email.errorMsg}}</span>
</span>
</div>
<div ng-if="vm.denyLocalLogin">
<input type="email"
class="input-block-level"
ng-model="model.user.email"
id="email"
disabled />
</div>
</umb-control-group>
<umb-control-group label="@general_username" ng-if="!model.usernameIsEmail" required="true">
@@ -254,7 +263,7 @@
size="s">
</umb-button>
</div>
<div>
<div ng-if="!vm.denyLocalLogin">
<umb-button type="button" ng-if="model.user.userDisplayState.key !== 'Invited'"
button-style="[action,block]"
@@ -276,7 +285,7 @@
</umb-button>
</div>
<div ng-if="model.user.resetPasswordValue">
<div ng-if="!vm.denyLocalLogin && model.user.resetPasswordValue">
<p><br />Password reset to value: <strong>{{model.user.resetPasswordValue}}</strong></p>
</div>

View File

@@ -4,7 +4,7 @@
function UsersController($scope, $timeout, $location, $routeParams, usersResource,
userGroupsResource, userService, localizationService,
usersHelper, formHelper, dateHelper, editorService,
listViewHelper) {
listViewHelper, externalLoginInfoService) {
var vm = this;
@@ -69,32 +69,43 @@
// Get last selected layout for "users" (defaults to first layout = card layout)
vm.activeLayout = listViewHelper.getLayout("users", vm.layouts);
vm.denyLocalLogin = externalLoginInfoService.hasDenyLocalLogin();
// returns the object representing the user create button, returns null if deny local login is true
function getCreateUserButton() {
if (!vm.denyLocalLogin) {
return {
type: "button",
labelKey: "user_createUser",
handler: function () {
vm.setUsersViewState('createUser');
}
};
}
return null;
}
// No default buttons with denyLocalLogin
// Don't show the invite button if no email is configured
if (Umbraco.Sys.ServerVariables.umbracoSettings.showUserInvite) {
vm.defaultButton = {
type: "button",
labelKey: "user_inviteUser",
handler: function () {
vm.setUsersViewState('inviteUser');
}
};
vm.subButtons = [
{
labelKey: "user_createUser",
handler: function () {
vm.setUsersViewState('createUser');
}
}
];
var createUserBtn = getCreateUserButton();
if (createUserBtn) {
vm.subButtons = [createUserBtn];
}
}
else {
vm.defaultButton = {
labelKey: "user_createUser",
handler: function () {
vm.setUsersViewState('createUser');
}
};
vm.defaultButton = getCreateUserButton();
}
vm.toggleFilter = toggleFilter;
vm.setUsersViewState = setUsersViewState;
vm.selectLayout = selectLayout;

View File

@@ -502,7 +502,7 @@
</umb-checkmark>
<h3 class="bold" style="margin: 0 0 0 10px;">
{{vm.newUser.name | umbWordLimit:1}}
<localize key="user_userInvited">has been created</localize>
<localize key="user_userInvited">has been invited</localize>
</h3>
</div>
@@ -517,6 +517,7 @@
size="m">
</umb-button>
<umb-button
ng-if="vm.newUser.id"
type="button"
button-style="action"
label-key="user_goToProfile"