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 updatedEdit Current Domains
-
InheritCulture
- 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 columnsNumber 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 NameEdit the key of the dictionary item.
-
@@ -398,6 +398,8 @@
Confirm your passwordName 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