diff --git a/src/Umbraco.Web.UI.Client/src/views/users/user.html b/src/Umbraco.Web.UI.Client/src/views/users/user.html index b91aec14ae..e043b50d2c 100644 --- a/src/Umbraco.Web.UI.Client/src/views/users/user.html +++ b/src/Umbraco.Web.UI.Client/src/views/users/user.html @@ -47,7 +47,7 @@ + + + Required + + + diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml index 5d0779f8b6..77615cf11a 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml @@ -81,14 +81,14 @@ Domain '%0%' has been updated Edit Current Domains - Inherit Culture - or inherit culture from parent nodes. Will also apply
+ or inherit culture from parent nodes. Will also apply
to the current node, unless a domain below applies too.]]>
Domains @@ -339,11 +339,11 @@ Number of columns Number of rows - Set a placeholder id by setting an ID on your placeholder you can inject content into this template from child templates, + Set a placeholder id by setting an ID on your placeholder you can inject content into this template from child templates, by referring this ID using a <asp:content /> element.]]> - Select a placeholder id from the list below. You can only + Select a placeholder id from the list below. You can only choose Id's from the current template's master.]]> Click on the image to see full size @@ -380,15 +380,15 @@ - %0%' below
You can add additional languages under the 'languages' in the menu on the left + %0%' below
You can add additional languages under the 'languages' in the menu on the left ]]>
Culture Name Edit the key of the dictionary item. - @@ -398,6 +398,8 @@ Confirm your password Name the %0%... Enter a name... + Enter an email... + Enter a username... Label... Enter a description... Type to search... diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml b/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml index ed0edf8b6d..70e738ffeb 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml @@ -400,6 +400,7 @@ Name the %0%... Enter a name... Enter an email... + Enter a username... Label... Enter a description... Type to search... diff --git a/src/Umbraco.Web/Editors/UsersController.cs b/src/Umbraco.Web/Editors/UsersController.cs index cb2963124f..3ca2041ea5 100644 --- a/src/Umbraco.Web/Editors/UsersController.cs +++ b/src/Umbraco.Web/Editors/UsersController.cs @@ -265,13 +265,18 @@ namespace Umbraco.Web.Editors { throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState)); } - - var existing = Services.UserService.GetByEmail(userSave.Email); - if (existing != null) + + if (UmbracoConfig.For.UmbracoSettings().Security.UsernameIsEmail) { - ModelState.AddModelError("Email", "A user with the email already exists"); - throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState)); + //ensure they are the same if we're using it + userSave.Username = userSave.Email; } + else + { + //first validate the username if were showing it + CheckUniqueUsername(userSave.Username, null); + } + CheckUniqueEmail(userSave.Email, null); //Perform authorization here to see if the current user can actually save this user with the info being requested var authHelper = new UserEditorAuthorizationHelper(Services.ContentService, Services.MediaService, Services.UserService, Services.EntityService); @@ -283,7 +288,7 @@ namespace Umbraco.Web.Editors //we want to create the user with the UserManager, this ensures the 'empty' (special) password //format is applied without us having to duplicate that logic - var identityUser = BackOfficeIdentityUser.CreateNew(userSave.Email, userSave.Email, GlobalSettings.DefaultUILanguage); + var identityUser = BackOfficeIdentityUser.CreateNew(userSave.Username, userSave.Email, GlobalSettings.DefaultUILanguage); identityUser.Name = userSave.Name; var created = await UserManager.CreateAsync(identityUser); @@ -345,7 +350,7 @@ namespace Umbraco.Web.Editors { throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState)); } - + var hasSmtp = GlobalSettings.HasSmtpServerConfigured(RequestContext.VirtualPathRoot); if (hasSmtp == false) { @@ -353,13 +358,19 @@ namespace Umbraco.Web.Editors Request.CreateNotificationValidationErrorResponse("No Email server is configured")); } - var user = Services.UserService.GetByEmail(userSave.Email); - if (user != null && (user.LastLoginDate != default(DateTime) || user.EmailConfirmedDate.HasValue)) + IUser user; + if (UmbracoConfig.For.UmbracoSettings().Security.UsernameIsEmail) { - ModelState.AddModelError("Email", "A user with the email already exists"); - throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState)); + //ensure it's the same + userSave.Username = userSave.Email; } - + else + { + //first validate the username if we're showing it + user = CheckUniqueUsername(userSave.Username, u => u.LastLoginDate != default(DateTime) || u.EmailConfirmedDate.HasValue); + } + user = CheckUniqueEmail(userSave.Email, u => u.LastLoginDate != default(DateTime) || u.EmailConfirmedDate.HasValue); + //Perform authorization here to see if the current user can actually save this user with the info being requested var authHelper = new UserEditorAuthorizationHelper(Services.ContentService, Services.MediaService, Services.UserService, Services.EntityService); var canSaveUser = authHelper.IsAuthorized(Security.CurrentUser, user, null, null, userSave.UserGroups); @@ -372,7 +383,7 @@ namespace Umbraco.Web.Editors { //we want to create the user with the UserManager, this ensures the 'empty' (special) password //format is applied without us having to duplicate that logic - var identityUser = BackOfficeIdentityUser.CreateNew(userSave.Email, userSave.Email, GlobalSettings.DefaultUILanguage); + var identityUser = BackOfficeIdentityUser.CreateNew(userSave.Username, userSave.Email, GlobalSettings.DefaultUILanguage); identityUser.Name = userSave.Name; var created = await UserManager.CreateAsync(identityUser); @@ -402,7 +413,31 @@ namespace Umbraco.Web.Editors return display; } - + + private IUser CheckUniqueEmail(string email, Func extraCheck) + { + var user = Services.UserService.GetByEmail(email); + if (user != null && (extraCheck == null || extraCheck(user))) + { + ModelState.AddModelError("Email", "A user with the email already exists"); + throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState)); + } + return user; + } + + private IUser CheckUniqueUsername(string username, Func extraCheck) + { + var user = Services.UserService.GetByUsername(username); + if (user != null && (extraCheck == null || extraCheck(user))) + { + ModelState.AddModelError( + UmbracoConfig.For.UmbracoSettings().Security.UsernameIsEmail ? "Email" : "Username", + "A user with the username already exists"); + throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState)); + } + return user; + } + private HttpContextBase EnsureHttpContext() { var attempt = this.TryGetHttpContext(); diff --git a/src/Umbraco.Web/Models/ContentEditing/UserInvite.cs b/src/Umbraco.Web/Models/ContentEditing/UserInvite.cs index 06895ccc68..368067814d 100644 --- a/src/Umbraco.Web/Models/ContentEditing/UserInvite.cs +++ b/src/Umbraco.Web/Models/ContentEditing/UserInvite.cs @@ -2,6 +2,8 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Linq; using System.Runtime.Serialization; +using Umbraco.Core; +using Umbraco.Core.Configuration; namespace Umbraco.Web.Models.ContentEditing { @@ -18,7 +20,10 @@ namespace Umbraco.Web.Models.ContentEditing [DataMember(Name = "email", IsRequired = true)] [Required] [EmailAddress] - public string Email { get; set; } + public string Email { get; set; } + + [DataMember(Name = "username")] + public string Username { get; set; } [DataMember(Name = "message")] public string Message { get; set; } @@ -26,7 +31,10 @@ namespace Umbraco.Web.Models.ContentEditing public IEnumerable Validate(ValidationContext validationContext) { if (UserGroups.Any() == false) - yield return new ValidationResult("A user must be assigned to at least one group", new[] { "UserGroups" }); + yield return new ValidationResult("A user must be assigned to at least one group", new[] { "UserGroups" }); + + if (UmbracoConfig.For.UmbracoSettings().Security.UsernameIsEmail == false && Username.IsNullOrWhiteSpace()) + yield return new ValidationResult("A username cannot be empty", new[] { "Username" }); } } } \ No newline at end of file