using System;
using System.Collections.Generic;
using System.Globalization;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web.Http;
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.Cache;
using Umbraco.Core.Configuration;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence;
using Umbraco.Core.Strings;
using Umbraco.Web.Security;
using Umbraco.Web.WebApi.Filters;
using Umbraco.Core.Mapping;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.Models;
using Umbraco.Web.Routing;
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
{
private readonly IMediaFileSystem _mediaFileSystem;
private readonly IContentSettings _contentSettings;
private readonly IIOHelper _ioHelper;
private readonly IImageUrlGenerator _imageUrlGenerator;
public CurrentUserController(
IGlobalSettings globalSettings,
IUmbracoContextAccessor umbracoContextAccessor,
ISqlContext sqlContext,
ServiceContext services,
AppCaches appCaches,
IProfilingLogger logger,
IRuntimeState runtimeState,
IMediaFileSystem mediaFileSystem,
IShortStringHelper shortStringHelper,
UmbracoMapper umbracoMapper,
IContentSettings contentSettings,
IIOHelper ioHelper,
IImageUrlGenerator imageUrlGenerator,
IPublishedUrlProvider publishedUrlProvider)
: base(globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, shortStringHelper, umbracoMapper, publishedUrlProvider)
{
_mediaFileSystem = mediaFileSystem;
_contentSettings = contentSettings ?? throw new ArgumentNullException(nameof(contentSettings));
_ioHelper = ioHelper ?? throw new ArgumentNullException(nameof(ioHelper));
_imageUrlGenerator = imageUrlGenerator;
}
///
/// Returns permissions for all nodes passed in for the current user
///
///
///
[HttpPost]
public Dictionary GetPermissions(int[] nodeIds)
{
var permissions = Services.UserService
.GetPermissions(Security.CurrentUser, nodeIds);
var permissionsDictionary = new Dictionary();
foreach (var nodeId in nodeIds)
{
var aggregatePerms = permissions.GetAllPermissions(nodeId).ToArray();
permissionsDictionary.Add(nodeId, aggregatePerms);
}
return permissionsDictionary;
}
///
/// Checks a nodes permission for the current user
///
///
///
///
[HttpGet]
public bool HasPermission(string permissionToCheck, int nodeId)
{
var p = Services.UserService.GetPermissions(Security.CurrentUser, nodeId).GetAllPermissions();
if (p.Contains(permissionToCheck.ToString(CultureInfo.InvariantCulture)))
{
return true;
}
return false;
}
///
/// Saves a tour status for the current user
///
///
///
public IEnumerable PostSetUserTour(UserTourStatus status)
{
if (status == null) throw new ArgumentNullException(nameof(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;
//They've successfully set their password, and will now get fully logged into the back office, so the lastlogindate is set so the backoffice shows they have logged in
Security.CurrentUser.LastLoginDate = DateTime.UtcNow;
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, AppCaches.RuntimeCache, _mediaFileSystem, ShortStringHelper, _contentSettings, _ioHelper, _imageUrlGenerator, 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);
var passwordChangeResult = await passwordChanger.ChangePasswordWithIdentityAsync(Security.CurrentUser, Security.CurrentUser, data, UserManager);
if (passwordChangeResult.Success)
{
var userMgr = this.TryGetOwinContext().Result.GetBackOfficeUserManager();
//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));
}
}
}