Merge branch 'netcore/netcore' into netcore/members-userstore
# Conflicts: # src/Umbraco.Web.BackOffice/Controllers/ContentControllerBase.cs # src/Umbraco.Web.BackOffice/Controllers/MemberController.cs
This commit is contained in:
@@ -14,7 +14,6 @@ using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Configuration.Models;
|
||||
using Umbraco.Core.Hosting;
|
||||
using Umbraco.Core.IO;
|
||||
@@ -36,13 +35,9 @@ using Umbraco.Web.BackOffice.Security;
|
||||
using Umbraco.Web.Common.ActionsResults;
|
||||
using Umbraco.Web.Common.Attributes;
|
||||
using Umbraco.Web.Common.Authorization;
|
||||
using Umbraco.Web.Common.Exceptions;
|
||||
using Umbraco.Web.Editors;
|
||||
using Umbraco.Web.Models;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
using Constants = Umbraco.Core.Constants;
|
||||
using IUser = Umbraco.Core.Models.Membership.IUser;
|
||||
using Task = System.Threading.Tasks.Task;
|
||||
|
||||
namespace Umbraco.Web.BackOffice.Controllers
|
||||
{
|
||||
@@ -123,27 +118,27 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
/// Returns a list of the sizes of gravatar URLs for the user or null if the gravatar server cannot be reached
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public string[] GetCurrentUserAvatarUrls()
|
||||
public ActionResult<string[]> GetCurrentUserAvatarUrls()
|
||||
{
|
||||
var urls = _backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser.GetUserAvatarUrls(_appCaches.RuntimeCache, _mediaFileSystem, _imageUrlGenerator);
|
||||
if (urls == null)
|
||||
throw new HttpResponseException(HttpStatusCode.BadRequest, "Could not access Gravatar endpoint");
|
||||
return new ValidationErrorResult("Could not access Gravatar endpoint");
|
||||
|
||||
return urls;
|
||||
}
|
||||
|
||||
[AppendUserModifiedHeader("id")]
|
||||
[Authorize(Policy = AuthorizationPolicies.AdminUserEditsRequireAdmin)]
|
||||
public IActionResult PostSetAvatar(int id, IList<IFormFile> files)
|
||||
public IActionResult PostSetAvatar(int id, IList<IFormFile> file)
|
||||
{
|
||||
return PostSetAvatarInternal(files, _userService, _appCaches.RuntimeCache, _mediaFileSystem, _shortStringHelper, _contentSettings, _hostingEnvironment, _imageUrlGenerator, id);
|
||||
return PostSetAvatarInternal(file, _userService, _appCaches.RuntimeCache, _mediaFileSystem, _shortStringHelper, _contentSettings, _hostingEnvironment, _imageUrlGenerator, id);
|
||||
}
|
||||
|
||||
internal static IActionResult PostSetAvatarInternal(IList<IFormFile> files, IUserService userService, IAppCache cache, IMediaFileSystem mediaFileSystem, IShortStringHelper shortStringHelper, ContentSettings contentSettings, IHostingEnvironment hostingEnvironment, IImageUrlGenerator imageUrlGenerator, int id)
|
||||
{
|
||||
if (files is null)
|
||||
{
|
||||
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
|
||||
return new UnsupportedMediaTypeResult();
|
||||
}
|
||||
|
||||
var root = hostingEnvironment.MapPathContentRoot(Constants.SystemDirectories.TempFileUploads);
|
||||
@@ -161,7 +156,7 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
return new NotFoundResult();
|
||||
|
||||
if (files.Count > 1)
|
||||
throw HttpResponseException.CreateValidationErrorResponse("The request was not formatted correctly, only one file can be attached to the request");
|
||||
return new ValidationErrorResult("The request was not formatted correctly, only one file can be attached to the request");
|
||||
|
||||
//get the file info
|
||||
var file = files.First();
|
||||
@@ -226,12 +221,12 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
/// <returns></returns>
|
||||
[OutgoingEditorModelEvent]
|
||||
[Authorize(Policy = AuthorizationPolicies.AdminUserEditsRequireAdmin)]
|
||||
public UserDisplay GetById(int id)
|
||||
public ActionResult<UserDisplay> GetById(int id)
|
||||
{
|
||||
var user = _userService.GetUserById(id);
|
||||
if (user == null)
|
||||
{
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
return NotFound();
|
||||
}
|
||||
var result = _umbracoMapper.Map<IUser, UserDisplay>(user);
|
||||
return result;
|
||||
@@ -244,20 +239,20 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
/// <returns></returns>
|
||||
[OutgoingEditorModelEvent]
|
||||
[Authorize(Policy = AuthorizationPolicies.AdminUserEditsRequireAdmin)]
|
||||
public IEnumerable<UserDisplay> GetByIds([FromJsonPath]int[] ids)
|
||||
public ActionResult<IEnumerable<UserDisplay>> GetByIds([FromJsonPath]int[] ids)
|
||||
{
|
||||
if (ids == null)
|
||||
{
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
if (ids.Length == 0)
|
||||
return Enumerable.Empty<UserDisplay>();
|
||||
return Enumerable.Empty<UserDisplay>().ToList();
|
||||
|
||||
var users = _userService.GetUsersById(ids);
|
||||
if (users == null)
|
||||
{
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
var result = _umbracoMapper.MapEnumerable<IUser, UserDisplay>(users);
|
||||
@@ -338,13 +333,13 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
/// </summary>
|
||||
/// <param name="userSave"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<UserDisplay> PostCreateUser(UserInvite userSave)
|
||||
public async Task<ActionResult<UserDisplay>> PostCreateUser(UserInvite userSave)
|
||||
{
|
||||
if (userSave == null) throw new ArgumentNullException("userSave");
|
||||
|
||||
if (ModelState.IsValid == false)
|
||||
{
|
||||
throw new HttpResponseException(HttpStatusCode.BadRequest, ModelState);
|
||||
return new ValidationErrorResult(new SimpleValidationModel(ModelState.ToErrorDictionary()));
|
||||
}
|
||||
|
||||
if (_securitySettings.UsernameIsEmail)
|
||||
@@ -359,11 +354,16 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
}
|
||||
CheckUniqueEmail(userSave.Email, null);
|
||||
|
||||
if (ModelState.IsValid == false)
|
||||
{
|
||||
return new ValidationErrorResult(new SimpleValidationModel(ModelState.ToErrorDictionary()));
|
||||
}
|
||||
|
||||
//Perform authorization here to see if the current user can actually save this user with the info being requested
|
||||
var canSaveUser = _userEditorAuthorizationHelper.IsAuthorized(_backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser, null, null, null, userSave.UserGroups);
|
||||
if (canSaveUser == false)
|
||||
{
|
||||
throw new HttpResponseException(HttpStatusCode.Unauthorized, canSaveUser.Result);
|
||||
return Unauthorized(canSaveUser.Result);
|
||||
}
|
||||
|
||||
//we want to create the user with the UserManager, this ensures the 'empty' (special) password
|
||||
@@ -374,7 +374,7 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
var created = await _userManager.CreateAsync(identityUser);
|
||||
if (created.Succeeded == false)
|
||||
{
|
||||
throw HttpResponseException.CreateNotificationValidationErrorResponse(created.Errors.ToErrorMessage());
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult(created.Errors.ToErrorMessage());
|
||||
}
|
||||
|
||||
string resetPassword;
|
||||
@@ -383,7 +383,7 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
var result = await _userManager.AddPasswordAsync(identityUser, password);
|
||||
if (result.Succeeded == false)
|
||||
{
|
||||
throw HttpResponseException.CreateNotificationValidationErrorResponse(created.Errors.ToErrorMessage());
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult(created.Errors.ToErrorMessage());
|
||||
}
|
||||
|
||||
resetPassword = password;
|
||||
@@ -419,11 +419,6 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
if (userSave.Message.IsNullOrWhiteSpace())
|
||||
ModelState.AddModelError("Message", "Message cannot be empty");
|
||||
|
||||
if (ModelState.IsValid == false)
|
||||
{
|
||||
return new ValidationErrorResult(ModelState);
|
||||
}
|
||||
|
||||
IUser user;
|
||||
if (_securitySettings.UsernameIsEmail)
|
||||
{
|
||||
@@ -433,10 +428,21 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
else
|
||||
{
|
||||
//first validate the username if we're showing it
|
||||
user = CheckUniqueUsername(userSave.Username, u => u.LastLoginDate != default || u.EmailConfirmedDate.HasValue);
|
||||
var userResult = CheckUniqueUsername(userSave.Username, u => u.LastLoginDate != default || u.EmailConfirmedDate.HasValue);
|
||||
if (!(userResult.Result is null))
|
||||
{
|
||||
return userResult.Result;
|
||||
}
|
||||
|
||||
user = userResult.Value;
|
||||
}
|
||||
user = CheckUniqueEmail(userSave.Email, u => u.LastLoginDate != default || u.EmailConfirmedDate.HasValue);
|
||||
|
||||
if (ModelState.IsValid == false)
|
||||
{
|
||||
return new ValidationErrorResult(new SimpleValidationModel(ModelState.ToErrorDictionary()));
|
||||
}
|
||||
|
||||
if (!EmailSender.CanSendRequiredEmail(_globalSettings) && !_userManager.HasSendingUserInviteEventHandler)
|
||||
{
|
||||
return new ValidationErrorResult("No Email server is configured");
|
||||
@@ -520,12 +526,11 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
if (user != null && (extraCheck == null || extraCheck(user)))
|
||||
{
|
||||
ModelState.AddModelError("Email", "A user with the email already exists");
|
||||
throw new HttpResponseException(HttpStatusCode.BadRequest, ModelState);
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
private IUser CheckUniqueUsername(string username, Func<IUser, bool> extraCheck)
|
||||
private ActionResult<IUser> CheckUniqueUsername(string username, Func<IUser, bool> extraCheck)
|
||||
{
|
||||
var user = _userService.GetByUsername(username);
|
||||
if (user != null && (extraCheck == null || extraCheck(user)))
|
||||
@@ -533,9 +538,10 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
ModelState.AddModelError(
|
||||
_securitySettings.UsernameIsEmail ? "Email" : "Username",
|
||||
"A user with the username already exists");
|
||||
throw new HttpResponseException(HttpStatusCode.BadRequest, ModelState);
|
||||
return new ValidationErrorResult(new SimpleValidationModel(ModelState.ToErrorDictionary()));
|
||||
}
|
||||
return user;
|
||||
|
||||
return new ActionResult<IUser>(user);
|
||||
}
|
||||
|
||||
private async Task SendUserInviteEmailAsync(UserBasic userDisplay, string from, string fromEmail, IUser to, string message)
|
||||
@@ -549,9 +555,12 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
token.ToUrlBase64());
|
||||
|
||||
// Get an mvc helper to get the URL
|
||||
var action = _linkGenerator.GetPathByAction("VerifyInvite", "BackOffice", new
|
||||
var action = _linkGenerator.GetPathByAction(
|
||||
nameof(BackOfficeController.VerifyInvite),
|
||||
ControllerExtensions.GetControllerName<BackOfficeController>(),
|
||||
new
|
||||
{
|
||||
area = _globalSettings.GetUmbracoMvcArea(_hostingEnvironment),
|
||||
area = Constants.Web.Mvc.BackOfficeArea,
|
||||
invite = inviteToken
|
||||
});
|
||||
|
||||
@@ -578,28 +587,29 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
/// <param name="userSave"></param>
|
||||
/// <returns></returns>
|
||||
[OutgoingEditorModelEvent]
|
||||
public UserDisplay PostSaveUser(UserSave userSave)
|
||||
public ActionResult<UserDisplay> PostSaveUser(UserSave userSave)
|
||||
{
|
||||
if (userSave == null) throw new ArgumentNullException(nameof(userSave));
|
||||
|
||||
if (ModelState.IsValid == false)
|
||||
{
|
||||
throw new HttpResponseException(HttpStatusCode.BadRequest, ModelState);
|
||||
return new ValidationErrorResult(new SimpleValidationModel(ModelState.ToErrorDictionary()));
|
||||
}
|
||||
|
||||
var intId = userSave.Id.TryConvertTo<int>();
|
||||
if (intId.Success == false)
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
return NotFound();
|
||||
|
||||
|
||||
var found = _userService.GetUserById(intId.Result);
|
||||
if (found == null)
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
return NotFound();
|
||||
|
||||
//Perform authorization here to see if the current user can actually save this user with the info being requested
|
||||
var canSaveUser = _userEditorAuthorizationHelper.IsAuthorized(_backofficeSecurityAccessor.BackOfficeSecurity.CurrentUser, found, userSave.StartContentIds, userSave.StartMediaIds, userSave.UserGroups);
|
||||
if (canSaveUser == false)
|
||||
{
|
||||
throw new HttpResponseException(HttpStatusCode.Unauthorized, canSaveUser.Result);
|
||||
return Unauthorized(canSaveUser.Result);
|
||||
}
|
||||
|
||||
var hasErrors = false;
|
||||
@@ -646,7 +656,7 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
}
|
||||
|
||||
if (hasErrors)
|
||||
throw new HttpResponseException(HttpStatusCode.BadRequest, ModelState);
|
||||
return new ValidationErrorResult(new SimpleValidationModel(ModelState.ToErrorDictionary()));
|
||||
|
||||
//merge the save data onto the user
|
||||
var user = _umbracoMapper.Map(userSave, found);
|
||||
@@ -664,25 +674,25 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
/// </summary>
|
||||
/// <param name="changingPasswordModel"></param>
|
||||
/// <returns></returns>
|
||||
public async Task<ModelWithNotifications<string>> PostChangePassword(ChangingPasswordModel changingPasswordModel)
|
||||
public async Task<ActionResult<ModelWithNotifications<string>>> PostChangePassword(ChangingPasswordModel changingPasswordModel)
|
||||
{
|
||||
changingPasswordModel = changingPasswordModel ?? throw new ArgumentNullException(nameof(changingPasswordModel));
|
||||
|
||||
if (ModelState.IsValid == false)
|
||||
{
|
||||
throw new HttpResponseException(HttpStatusCode.BadRequest, ModelState);
|
||||
return new ValidationErrorResult(new SimpleValidationModel(ModelState.ToErrorDictionary()));
|
||||
}
|
||||
|
||||
var intId = changingPasswordModel.Id.TryConvertTo<int>();
|
||||
if (intId.Success == false)
|
||||
{
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
var found = _userService.GetUserById(intId.Result);
|
||||
if (found == null)
|
||||
{
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
return NotFound();
|
||||
}
|
||||
|
||||
// TODO: Why don't we inject this? Then we can just inject a logger
|
||||
@@ -701,7 +711,7 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
ModelState.AddModelError(memberName, passwordChangeResult.Result.ChangeError.ErrorMessage);
|
||||
}
|
||||
|
||||
throw HttpResponseException.CreateValidationErrorResponse(ModelState);
|
||||
return new ValidationErrorResult(new SimpleValidationModel(ModelState.ToErrorDictionary()));
|
||||
}
|
||||
|
||||
|
||||
@@ -715,7 +725,7 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
var tryGetCurrentUserId = _backofficeSecurityAccessor.BackOfficeSecurity.GetUserId();
|
||||
if (tryGetCurrentUserId && userIds.Contains(tryGetCurrentUserId.Result))
|
||||
{
|
||||
throw HttpResponseException.CreateNotificationValidationErrorResponse("The current user cannot disable itself");
|
||||
return ValidationErrorResult.CreateNotificationValidationErrorResult("The current user cannot disable itself");
|
||||
}
|
||||
|
||||
var users = _userService.GetUsersById(userIds).ToArray();
|
||||
@@ -782,8 +792,8 @@ namespace Umbraco.Web.BackOffice.Controllers
|
||||
var unlockResult = await _userManager.SetLockoutEndDateAsync(user, DateTimeOffset.Now);
|
||||
if (unlockResult.Succeeded == false)
|
||||
{
|
||||
throw HttpResponseException.CreateValidationErrorResponse(
|
||||
string.Format("Could not unlock for user {0} - error {1}", u, unlockResult.Errors.ToErrorMessage()));
|
||||
return new ValidationErrorResult(
|
||||
$"Could not unlock for user {u} - error {unlockResult.Errors.ToErrorMessage()}");
|
||||
}
|
||||
|
||||
if (userIds.Length == 1)
|
||||
|
||||
Reference in New Issue
Block a user