using System; using System.Collections; using System.Net.Http; using System.Threading.Tasks; using System.Web.Http; using AutoMapper; using Umbraco.Core.Composing; using Umbraco.Core.Services; using Umbraco.Web.Models; using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Mvc; using Umbraco.Web.WebApi; using System.Linq; using Newtonsoft.Json; using Umbraco.Core; using Umbraco.Core.Security; using Umbraco.Web.WebApi.Filters; namespace Umbraco.Web.Editors { /// /// Controller to back the User.Resource service, used for fetching user data when already authenticated. user.service is currently used for handling authentication /// [PluginController("UmbracoApi")] public class CurrentUserController : UmbracoAuthorizedJsonController { /// /// Saves a tour status for the current user /// /// /// public IEnumerable PostSetUserTour(UserTourStatus status) { if (status == null) throw new ArgumentNullException("status"); List userTours; if (Security.CurrentUser.TourData.IsNullOrWhiteSpace()) { userTours = new List {status}; Security.CurrentUser.TourData = JsonConvert.SerializeObject(userTours); Services.UserService.Save(Security.CurrentUser); return userTours; } userTours = JsonConvert.DeserializeObject>(Security.CurrentUser.TourData).ToList(); var found = userTours.FirstOrDefault(x => x.Alias == status.Alias); if (found != null) { //remove it and we'll replace it next userTours.Remove(found); } userTours.Add(status); Security.CurrentUser.TourData = JsonConvert.SerializeObject(userTours); Services.UserService.Save(Security.CurrentUser); return userTours; } /// /// Returns the user's tours /// /// public IEnumerable GetUserTours() { if (Security.CurrentUser.TourData.IsNullOrWhiteSpace()) return Enumerable.Empty(); var userTours = JsonConvert.DeserializeObject>(Security.CurrentUser.TourData); return userTours; } /// /// When a user is invited and they click on the invitation link, they will be partially logged in /// where they can set their username/password /// /// /// /// /// This only works when the user is logged in (partially) /// [WebApi.UmbracoAuthorize(requireApproval: false)] [OverrideAuthorization] public async Task PostSetInvitedUserPassword([FromBody]string newPassword) { var result = await UserManager.AddPasswordAsync(Security.GetUserId().ResultOr(0), newPassword); if (result.Succeeded == false) { //it wasn't successful, so add the change error to the model state, we've name the property alias _umb_password on the form // so that is why it is being used here. ModelState.AddModelError( "value", string.Join(", ", result.Errors)); throw new HttpResponseException(Request.CreateValidationErrorResponse(ModelState)); } //They've successfully set their password, we can now update their user account to be approved Security.CurrentUser.IsApproved = true; Services.UserService.Save(Security.CurrentUser); //now we can return their full object since they are now really logged into the back office var userDisplay = Mapper.Map(Security.CurrentUser); var httpContextAttempt = TryGetHttpContext(); if (httpContextAttempt.Success) { //set their remaining seconds userDisplay.SecondsUntilTimeout = httpContextAttempt.Result.GetRemainingAuthSeconds(); } return userDisplay; } [AppendUserModifiedHeader] [FileUploadCleanupFilter(false)] public async Task PostSetAvatar() { //borrow the logic from the user controller return await UsersController.PostSetAvatarInternal(Request, Services.UserService, Current.ApplicationCache.StaticCache, Security.GetUserId().ResultOr(0)); } /// /// Changes the users password /// /// /// /// If the password is being reset it will return the newly reset password, otherwise will return an empty value /// public async Task> PostChangePassword(ChangingPasswordModel data) { var passwordChanger = new PasswordChanger(Logger, Services.UserService, UmbracoContext.HttpContext); var passwordChangeResult = await passwordChanger.ChangePasswordWithIdentityAsync(Security.CurrentUser, Security.CurrentUser, data, UserManager); if (passwordChangeResult.Success) { var userMgr = this.TryGetOwinContext().Result.GetBackOfficeUserManager(); //raise the reset event //TODO: I don't think this is required anymore since from 7.7 we no longer display the reset password checkbox since that didn't make sense. if (data.Reset.HasValue && data.Reset.Value) { userMgr.RaisePasswordResetEvent(Security.CurrentUser.Id); } //even if we weren't resetting this, it is the correct value (null), otherwise if we were resetting then it will contain the new pword var result = new ModelWithNotifications(passwordChangeResult.Result.ResetPassword); result.AddSuccessNotification(Services.TextService.Localize("user/password"), Services.TextService.Localize("user/passwordChanged")); return result; } foreach (var memberName in passwordChangeResult.Result.ChangeError.MemberNames) { ModelState.AddModelError(memberName, passwordChangeResult.Result.ChangeError.ErrorMessage); } throw new HttpResponseException(Request.CreateValidationErrorResponse(ModelState)); } } }