2018-03-27 10:04:07 +02:00
using System ;
2018-03-27 16:18:51 +02:00
using System.Collections.Generic ;
2018-08-14 20:21:33 +10:00
using System.Globalization ;
2018-03-27 10:04:07 +02:00
using System.Net.Http ;
2017-09-13 17:35:20 +02:00
using System.Threading.Tasks ;
2013-11-12 18:07:10 +11:00
using System.Web.Http ;
2017-09-12 16:22:16 +02:00
using Umbraco.Core.Services ;
2013-11-12 18:07:10 +11:00
using Umbraco.Web.Models ;
using Umbraco.Web.Models.ContentEditing ;
using Umbraco.Web.Mvc ;
using Umbraco.Web.WebApi ;
2018-03-27 10:04:07 +02:00
using System.Linq ;
using Newtonsoft.Json ;
using Umbraco.Core ;
2019-12-18 13:05:34 +01:00
using Umbraco.Core.Cache ;
using Umbraco.Core.Configuration ;
using Umbraco.Core.IO ;
using Umbraco.Core.Logging ;
using Umbraco.Core.Persistence ;
2019-12-18 18:55:00 +01:00
using Umbraco.Core.Strings ;
2018-04-05 23:10:51 +10:00
using Umbraco.Web.Security ;
2017-09-12 16:22:16 +02:00
using Umbraco.Web.WebApi.Filters ;
2020-01-20 14:15:54 -08:00
using Umbraco.Core.Mapping ;
2020-01-21 17:03:46 -08:00
using Umbraco.Core.Configuration.UmbracoSettings ;
2020-02-11 11:43:54 -08:00
using Umbraco.Core.Models ;
2020-02-14 13:04:49 +01:00
using Umbraco.Web.Routing ;
2013-11-12 18:07:10 +11:00
namespace Umbraco.Web.Editors
{
/// <summary>
/// Controller to back the User.Resource service, used for fetching user data when already authenticated. user.service is currently used for handling authentication
/// </summary>
[PluginController("UmbracoApi")]
public class CurrentUserController : UmbracoAuthorizedJsonController
{
2019-12-18 13:05:34 +01:00
private readonly IMediaFileSystem _mediaFileSystem ;
2020-03-12 15:30:22 +01:00
private readonly IContentSettings _contentSettings ;
2020-02-10 11:23:23 +01:00
private readonly IIOHelper _ioHelper ;
2020-02-11 11:43:54 -08:00
private readonly IImageUrlGenerator _imageUrlGenerator ;
2019-12-18 13:05:34 +01:00
public CurrentUserController (
IGlobalSettings globalSettings ,
IUmbracoContextAccessor umbracoContextAccessor ,
ISqlContext sqlContext ,
ServiceContext services ,
AppCaches appCaches ,
IProfilingLogger logger ,
IRuntimeState runtimeState ,
2019-12-18 18:55:00 +01:00
IMediaFileSystem mediaFileSystem ,
2020-01-20 14:15:54 -08:00
IShortStringHelper shortStringHelper ,
2020-01-21 17:03:46 -08:00
UmbracoMapper umbracoMapper ,
2020-03-12 15:30:22 +01:00
IContentSettings contentSettings ,
2020-02-11 11:43:54 -08:00
IIOHelper ioHelper ,
2020-02-14 13:04:49 +01:00
IImageUrlGenerator imageUrlGenerator ,
IPublishedUrlProvider publishedUrlProvider )
2020-03-03 11:59:17 +01:00
: base ( globalSettings , umbracoContextAccessor , sqlContext , services , appCaches , logger , runtimeState , shortStringHelper , umbracoMapper , publishedUrlProvider )
2019-12-18 13:05:34 +01:00
{
_mediaFileSystem = mediaFileSystem ;
2020-03-12 15:30:22 +01:00
_contentSettings = contentSettings ? ? throw new ArgumentNullException ( nameof ( contentSettings ) ) ;
2020-02-10 11:23:23 +01:00
_ioHelper = ioHelper ? ? throw new ArgumentNullException ( nameof ( ioHelper ) ) ;
2020-02-11 11:43:54 -08:00
_imageUrlGenerator = imageUrlGenerator ;
2019-12-18 13:05:34 +01:00
}
2018-08-14 20:21:33 +10:00
/// <summary>
/// Returns permissions for all nodes passed in for the current user
/// </summary>
/// <param name="nodeIds"></param>
/// <returns></returns>
[HttpPost]
public Dictionary < int , string [ ] > GetPermissions ( int [ ] nodeIds )
{
var permissions = Services . UserService
. GetPermissions ( Security . CurrentUser , nodeIds ) ;
var permissionsDictionary = new Dictionary < int , string [ ] > ( ) ;
foreach ( var nodeId in nodeIds )
{
var aggregatePerms = permissions . GetAllPermissions ( nodeId ) . ToArray ( ) ;
permissionsDictionary . Add ( nodeId , aggregatePerms ) ;
}
return permissionsDictionary ;
}
/// <summary>
/// Checks a nodes permission for the current user
/// </summary>
/// <param name="permissionToCheck"></param>
/// <param name="nodeId"></param>
/// <returns></returns>
[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 ;
}
2018-03-27 10:04:07 +02:00
/// <summary>
/// Saves a tour status for the current user
/// </summary>
/// <param name="status"></param>
/// <returns></returns>
public IEnumerable < UserTourStatus > PostSetUserTour ( UserTourStatus status )
{
2018-03-28 16:38:10 +02:00
if ( status = = null ) throw new ArgumentNullException ( nameof ( status ) ) ;
2018-03-27 10:04:07 +02:00
List < UserTourStatus > userTours ;
if ( Security . CurrentUser . TourData . IsNullOrWhiteSpace ( ) )
{
2018-03-28 16:38:10 +02:00
userTours = new List < UserTourStatus > { status } ;
2018-03-27 10:04:07 +02:00
Security . CurrentUser . TourData = JsonConvert . SerializeObject ( userTours ) ;
Services . UserService . Save ( Security . CurrentUser ) ;
return userTours ;
}
userTours = JsonConvert . DeserializeObject < IEnumerable < UserTourStatus > > ( 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 ;
}
/// <summary>
/// Returns the user's tours
/// </summary>
/// <returns></returns>
public IEnumerable < UserTourStatus > GetUserTours ( )
{
if ( Security . CurrentUser . TourData . IsNullOrWhiteSpace ( ) )
return Enumerable . Empty < UserTourStatus > ( ) ;
var userTours = JsonConvert . DeserializeObject < IEnumerable < UserTourStatus > > ( Security . CurrentUser . TourData ) ;
return userTours ;
}
2017-09-12 16:22:16 +02:00
2013-11-12 18:07:10 +11:00
/// <summary>
2017-09-12 16:22:16 +02:00
/// 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
2013-11-12 18:07:10 +11:00
/// </summary>
2017-09-12 16:22:16 +02:00
/// <param name="newPassword"></param>
2013-11-12 18:07:10 +11:00
/// <returns></returns>
2017-09-12 16:22:16 +02:00
/// <remarks>
/// This only works when the user is logged in (partially)
/// </remarks>
[WebApi.UmbracoAuthorize(requireApproval: false)]
[OverrideAuthorization]
public async Task < UserDetail > PostSetInvitedUserPassword ( [ FromBody ] string newPassword )
2013-11-12 18:07:10 +11:00
{
2018-03-02 15:48:21 +01:00
var result = await UserManager . AddPasswordAsync ( Security . GetUserId ( ) . ResultOr ( 0 ) , newPassword ) ;
2017-09-12 16:22:16 +02:00
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 ;
2019-05-09 10:31:44 +02:00
//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 ;
2017-09-12 16:22:16 +02:00
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 < UserDetail > ( 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 < HttpResponseMessage > PostSetAvatar ( )
{
//borrow the logic from the user controller
2020-03-12 15:30:22 +01:00
return await UsersController . PostSetAvatarInternal ( Request , Services . UserService , AppCaches . RuntimeCache , _mediaFileSystem , ShortStringHelper , _contentSettings , _ioHelper , _imageUrlGenerator , Security . GetUserId ( ) . ResultOr ( 0 ) ) ;
2016-09-01 19:06:08 +02:00
}
2013-11-12 18:07:10 +11:00
/// <summary>
/// Changes the users password
/// </summary>
/// <param name="data"></param>
/// <returns>
/// If the password is being reset it will return the newly reset password, otherwise will return an empty value
/// </returns>
2017-09-12 16:22:16 +02:00
public async Task < ModelWithNotifications < string > > PostChangePassword ( ChangingPasswordModel data )
2013-11-12 18:07:10 +11:00
{
2019-12-03 15:28:55 +11:00
var passwordChanger = new PasswordChanger ( Logger ) ;
2017-09-19 15:51:47 +02:00
var passwordChangeResult = await passwordChanger . ChangePasswordWithIdentityAsync ( Security . CurrentUser , Security . CurrentUser , data , UserManager ) ;
2013-11-12 18:07:10 +11:00
if ( passwordChangeResult . Success )
{
2017-09-19 16:46:49 +02:00
var userMgr = this . TryGetOwinContext ( ) . Result . GetBackOfficeUserManager ( ) ;
2013-11-12 18:07:10 +11:00
//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 < string > ( passwordChangeResult . Result . ResetPassword ) ;
2016-03-11 15:43:34 +01:00
result . AddSuccessNotification ( Services . TextService . Localize ( "user/password" ) , Services . TextService . Localize ( "user/passwordChanged" ) ) ;
2013-11-12 18:07:10 +11:00
return result ;
}
2017-09-19 15:51:47 +02:00
foreach ( var memberName in passwordChangeResult . Result . ChangeError . MemberNames )
{
ModelState . AddModelError ( memberName , passwordChangeResult . Result . ChangeError . ErrorMessage ) ;
}
2013-11-12 18:07:10 +11:00
throw new HttpResponseException ( Request . CreateValidationErrorResponse ( ModelState ) ) ;
}
}
}