Port 7.7 - WIP
This commit is contained in:
@@ -20,8 +20,21 @@ namespace Umbraco.Web.Models
|
||||
public string OldPassword { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Set to true if the password is to be reset - only valid when: EnablePasswordReset = true
|
||||
/// Set to true if the password is to be reset
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This operator is different between using ASP.NET Identity APIs and Membership APIs.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// When using Membership APIs, this is only valid when: EnablePasswordReset = true and it will reset the password to something auto generated.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// When using ASP.NET Identity APIs this needs to be set if an administrator user that has access to the Users section is changing another users
|
||||
/// password. This flag is required to indicate that the oldPassword value is not required and that we are in fact performing a password reset and
|
||||
/// then a password change if the executing user has access to do so.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
[DataMember(Name = "reset")]
|
||||
public bool? Reset { get; set; }
|
||||
|
||||
|
||||
@@ -1,15 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http.Formatting;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Web.Http;
|
||||
using System.Web.Http.ModelBinding;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Validation;
|
||||
using Umbraco.Web.Models.Trees;
|
||||
using Umbraco.Web.Trees;
|
||||
|
||||
namespace Umbraco.Web.Models.ContentEditing
|
||||
{
|
||||
@@ -57,6 +49,8 @@ namespace Umbraco.Web.Models.ContentEditing
|
||||
/// </remarks>
|
||||
[DataMember(Name = "allowedActions")]
|
||||
public IEnumerable<string> AllowedActions { get; set; }
|
||||
|
||||
|
||||
[DataMember(Name = "isBlueprint")]
|
||||
public bool IsBlueprint { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,20 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Umbraco.Web.Models.ContentEditing
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Represents a section (application) in the back office
|
||||
/// </summary>
|
||||
[DataContract(Name = "section", Namespace = "")]
|
||||
public class Section
|
||||
{
|
||||
|
||||
[DataMember(Name = "name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
@@ -24,5 +17,11 @@ namespace Umbraco.Web.Models.ContentEditing
|
||||
[DataMember(Name = "alias")]
|
||||
public string Alias { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// In some cases a custom route path can be specified so that when clicking on a section it goes to this
|
||||
/// path instead of the normal dashboard path
|
||||
/// </summary>
|
||||
[DataMember(Name = "routePath")]
|
||||
public string RoutePath { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,10 +27,14 @@ namespace Umbraco.Web.Models.ContentEditing
|
||||
public string EmailHash { get; set; }
|
||||
|
||||
[Obsolete("This should not be used it exists for legacy reasons only, use user groups instead, it will be removed in future versions")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[ReadOnly(true)]
|
||||
[DataMember(Name = "userType")]
|
||||
public string UserType { get; set; }
|
||||
public string UserType { get; set; }
|
||||
|
||||
[ReadOnly(true)]
|
||||
[DataMember(Name = "userGroups")]
|
||||
public string[] UserGroups { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets/sets the number of seconds for the user's auth ticket to expire
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.Runtime.Serialization;
|
||||
@@ -38,6 +39,40 @@ namespace Umbraco.Web.Models.ContentEditing
|
||||
[DataMember(Name = "resetPasswordValue")]
|
||||
[ReadOnly(true)]
|
||||
public string ResetPasswordValue { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A readonly value showing the user's current calculated start content ids
|
||||
/// </summary>
|
||||
[DataMember(Name = "calculatedStartContentIds")]
|
||||
[ReadOnly(true)]
|
||||
public IEnumerable<EntityBasic> CalculatedStartContentIds { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A readonly value showing the user's current calculated start media ids
|
||||
/// </summary>
|
||||
[DataMember(Name = "calculatedStartMediaIds")]
|
||||
[ReadOnly(true)]
|
||||
public IEnumerable<EntityBasic> CalculatedStartMediaIds { get; set; }
|
||||
|
||||
[DataMember(Name = "failedPasswordAttempts")]
|
||||
[ReadOnly(true)]
|
||||
public int FailedPasswordAttempts { get; set; }
|
||||
|
||||
[DataMember(Name = "lastLockoutDate")]
|
||||
[ReadOnly(true)]
|
||||
public DateTime LastLockoutDate { get; set; }
|
||||
|
||||
[DataMember(Name = "lastPasswordChangeDate")]
|
||||
[ReadOnly(true)]
|
||||
public DateTime LastPasswordChangeDate { get; set; }
|
||||
|
||||
[DataMember(Name = "createDate")]
|
||||
[ReadOnly(true)]
|
||||
public DateTime CreateDate { get; set; }
|
||||
|
||||
[DataMember(Name = "updateDate")]
|
||||
[ReadOnly(true)]
|
||||
public DateTime UpdateDate { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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<ValidationResult> 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" });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Web;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Web.Composing;
|
||||
using Umbraco.Web.Security;
|
||||
|
||||
namespace Umbraco.Web.Models
|
||||
@@ -22,9 +23,9 @@ namespace Umbraco.Web.Models
|
||||
|
||||
private LoginStatusModel(bool doLookup)
|
||||
{
|
||||
if (doLookup && HttpContext.Current != null)
|
||||
if (doLookup && Current.UmbracoContext != null)
|
||||
{
|
||||
var helper = new MembershipHelper(new HttpContextWrapper(HttpContext.Current));
|
||||
var helper = new MembershipHelper(Current.UmbracoContext);
|
||||
var model = helper.GetCurrentLoginStatus();
|
||||
if (model != null)
|
||||
{
|
||||
|
||||
@@ -10,8 +10,8 @@ using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.Composing;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
using Umbraco.Web.Trees;
|
||||
using Umbraco.Web.Routing;
|
||||
using Umbraco.Web.Trees;
|
||||
using Umbraco.Web._Legacy.Actions;
|
||||
|
||||
namespace Umbraco.Web.Models.Mapping
|
||||
@@ -31,7 +31,8 @@ namespace Umbraco.Web.Models.Mapping
|
||||
|
||||
//FROM IContent TO ContentItemDisplay
|
||||
CreateMap<IContent, ContentItemDisplay>()
|
||||
.ForMember(dest => dest.Udi, opt => opt.MapFrom(src => Udi.Create(Constants.UdiEntityType.Document, src.Key)))
|
||||
.ForMember(dest => dest.Udi, opt => opt.MapFrom(src =>
|
||||
Udi.Create(src.IsBlueprint ? Constants.UdiEntityType.DocumentBluePrint : Constants.UdiEntityType.Document, src.Key)))
|
||||
.ForMember(dest => dest.Owner, opt => opt.ResolveUsing(src => contentOwnerResolver.Resolve(src)))
|
||||
.ForMember(dest => dest.Updater, opt => opt.ResolveUsing(src => creatorResolver.Resolve(src)))
|
||||
.ForMember(dest => dest.Icon, opt => opt.MapFrom(src => src.ContentType.Icon))
|
||||
@@ -59,7 +60,8 @@ namespace Umbraco.Web.Models.Mapping
|
||||
|
||||
//FROM IContent TO ContentItemBasic<ContentPropertyBasic, IContent>
|
||||
CreateMap<IContent, ContentItemBasic<ContentPropertyBasic, IContent>>()
|
||||
.ForMember(dest => dest.Udi, opt => opt.MapFrom(src => Udi.Create(Constants.UdiEntityType.Document, src.Key)))
|
||||
.ForMember(dest => dest.Udi, opt => opt.MapFrom(src =>
|
||||
Udi.Create(src.IsBlueprint ? Constants.UdiEntityType.DocumentBluePrint : Constants.UdiEntityType.Document, src.Key)))
|
||||
.ForMember(dest => dest.Owner, opt => opt.ResolveUsing(src => contentOwnerResolver.Resolve(src)))
|
||||
.ForMember(dest => dest.Updater, opt => opt.ResolveUsing(src => creatorResolver.Resolve(src)))
|
||||
.ForMember(dest => dest.Icon, opt => opt.MapFrom(src => src.ContentType.Icon))
|
||||
@@ -70,7 +72,8 @@ namespace Umbraco.Web.Models.Mapping
|
||||
|
||||
//FROM IContent TO ContentItemDto<IContent>
|
||||
CreateMap<IContent, ContentItemDto<IContent>>()
|
||||
.ForMember(dest => dest.Udi, opt => opt.MapFrom(src => Udi.Create(Constants.UdiEntityType.Document, src.Key)))
|
||||
.ForMember(dest => dest.Udi, opt => opt.MapFrom(src =>
|
||||
Udi.Create(src.IsBlueprint ? Constants.UdiEntityType.DocumentBluePrint : Constants.UdiEntityType.Document, src.Key)))
|
||||
.ForMember(dest => dest.Owner, opt => opt.ResolveUsing(src => contentOwnerResolver.Resolve(src)))
|
||||
.ForMember(dest => dest.HasPublishedVersion, opt => opt.MapFrom(src => src.HasPublishedVersion))
|
||||
.ForMember(dest => dest.Updater, opt => opt.Ignore())
|
||||
|
||||
@@ -14,9 +14,8 @@ namespace Umbraco.Web.Models.Mapping
|
||||
_textService = textService;
|
||||
|
||||
CreateMap<Core.Models.Section, Section>()
|
||||
.ForMember(
|
||||
dto => dto.Name,
|
||||
expression => expression.MapFrom(section => _textService.Localize("sections/" + section.Alias, (IDictionary<string, string>)null)))
|
||||
.ForMember(dest => dest.RoutePath, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.Name, opt => opt.MapFrom(src => _textService.Localize("sections/" + src.Alias, (IDictionary<string, string>)null)))
|
||||
.ReverseMap(); //backwards too!
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,13 +223,33 @@ namespace Umbraco.Web.Models.Mapping
|
||||
display.AssignedPermissions = allAssignedPermissions;
|
||||
});
|
||||
|
||||
//Important! Currently we are never mapping to multiple UserDisplay objects but if we start doing that
|
||||
// this will cause an N+1 and we'll need to change how this works.
|
||||
CreateMap<IUser, UserDisplay>()
|
||||
.ForMember(dest => dest.Avatars, opt => opt.MapFrom(user => user.GetCurrentUserAvatarUrls(userService, runtimeCache)))
|
||||
.ForMember(dest => dest.Username, opt => opt.MapFrom(user => user.Username))
|
||||
.ForMember(dest => dest.LastLoginDate, opt => opt.MapFrom(user => user.LastLoginDate == default(DateTime) ? null : (DateTime?)user.LastLoginDate))
|
||||
.ForMember(dest => dest.UserGroups, opt => opt.MapFrom(user => user.Groups))
|
||||
.ForMember(dest => dest.StartContentIds, opt => opt.UseValue(Enumerable.Empty<EntityBasic>()))
|
||||
.ForMember(dest => dest.StartMediaIds, opt => opt.UseValue(Enumerable.Empty<EntityBasic>()))
|
||||
.ForMember(
|
||||
dest => dest.CalculatedStartContentIds,
|
||||
opt => opt.MapFrom(src => GetStartNodeValues(
|
||||
src.CalculateContentStartNodeIds(entityService),
|
||||
textService, entityService, UmbracoObjectTypes.Document, "content/contentRoot")))
|
||||
.ForMember(
|
||||
dest => dest.CalculatedStartMediaIds,
|
||||
opt => opt.MapFrom(src => GetStartNodeValues(
|
||||
src.CalculateMediaStartNodeIds(entityService),
|
||||
textService, entityService, UmbracoObjectTypes.Media, "media/mediaRoot")))
|
||||
.ForMember(
|
||||
dest => dest.StartContentIds,
|
||||
opt => opt.MapFrom(src => GetStartNodeValues(
|
||||
src.StartContentIds.ToArray(),
|
||||
textService, entityService, UmbracoObjectTypes.Document, "content/contentRoot")))
|
||||
.ForMember(
|
||||
dest => dest.StartMediaIds,
|
||||
opt => opt.MapFrom(src => GetStartNodeValues(
|
||||
src.StartMediaIds.ToArray(),
|
||||
textService, entityService, UmbracoObjectTypes.Media, "media/mediaRoot")))
|
||||
.ForMember(dest => dest.Culture, opt => opt.MapFrom(user => user.GetUserCulture(textService)))
|
||||
.ForMember(
|
||||
dest => dest.AvailableCultures,
|
||||
@@ -247,40 +267,7 @@ namespace Umbraco.Web.Models.Mapping
|
||||
.ForMember(dest => dest.ResetPasswordValue, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.Alias, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.Trashed, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.AdditionalData, opt => opt.Ignore())
|
||||
.AfterMap((user, display) =>
|
||||
{
|
||||
//Important! Currently we are never mapping to multiple UserDisplay objects but if we start doing that
|
||||
// this will cause an N+1 and we'll need to change how this works.
|
||||
|
||||
var startContentIds = user.StartContentIds.ToArray();
|
||||
if (startContentIds.Length > 0)
|
||||
{
|
||||
//TODO: Update GetAll to be able to pass in a parameter like on the normal Get to NOT load in the entire object!
|
||||
var startNodes = new List<EntityBasic>();
|
||||
if (startContentIds.Contains(-1))
|
||||
{
|
||||
startNodes.Add(RootNode(textService.Localize("content/contentRoot")));
|
||||
}
|
||||
var contentItems = entityService.GetAll(UmbracoObjectTypes.Document, startContentIds);
|
||||
startNodes.AddRange(Mapper.Map<IEnumerable<IUmbracoEntity>, IEnumerable<EntityBasic>>(contentItems));
|
||||
display.StartContentIds = startNodes;
|
||||
|
||||
|
||||
}
|
||||
var startMediaIds = user.StartMediaIds.ToArray();
|
||||
if (startMediaIds.Length > 0)
|
||||
{
|
||||
var startNodes = new List<EntityBasic>();
|
||||
if (startContentIds.Contains(-1))
|
||||
{
|
||||
startNodes.Add(RootNode(textService.Localize("media/mediaRoot")));
|
||||
}
|
||||
var mediaItems = entityService.GetAll(UmbracoObjectTypes.Media, startMediaIds);
|
||||
startNodes.AddRange(Mapper.Map<IEnumerable<IUmbracoEntity>, IEnumerable<EntityBasic>>(mediaItems));
|
||||
display.StartMediaIds = startNodes;
|
||||
}
|
||||
});
|
||||
.ForMember(dest => dest.AdditionalData, opt => opt.Ignore());
|
||||
|
||||
CreateMap<IUser, UserBasic>()
|
||||
//Loading in the user avatar's requires an external request if they don't have a local file avatar, this means that initial load of paging may incur a cost
|
||||
@@ -317,20 +304,23 @@ namespace Umbraco.Web.Models.Mapping
|
||||
dest => dest.EmailHash,
|
||||
opt => opt.MapFrom(user => user.Email.ToLowerInvariant().Trim().GenerateHash()))
|
||||
.ForMember(dest => dest.SecondsUntilTimeout, opt => opt.Ignore())
|
||||
.ForMember(dest => dest.UserGroups, opt => opt.Ignore())
|
||||
.AfterMap((user, detail) =>
|
||||
{
|
||||
//we need to map the legacy UserType
|
||||
//the best we can do here is to return the user's first user group as a IUserType object
|
||||
//but we should attempt to return any group that is the built in ones first
|
||||
var groups = user.Groups.ToArray();
|
||||
detail.UserGroups = user.Groups.Select(x => x.Alias).ToArray();
|
||||
|
||||
if (groups.Length == 0)
|
||||
{
|
||||
//In backwards compatibility land, a user type cannot be null! so we need to return a fake one.
|
||||
//In backwards compatibility land, a user type cannot be null! so we need to return a fake one.
|
||||
detail.UserType = "temp";
|
||||
}
|
||||
else
|
||||
{
|
||||
var builtIns = new[] { Constants.Security.AdminGroupAlias, "writer", "editor", "translator" };
|
||||
var builtIns = new[] { Constants.Security.AdminGroupAlias, "writer", "editor", Constants.Security.TranslatorGroupAlias };
|
||||
var foundBuiltIn = groups.FirstOrDefault(x => builtIns.Contains(x.Alias));
|
||||
if (foundBuiltIn != null)
|
||||
{
|
||||
@@ -361,6 +351,22 @@ namespace Umbraco.Web.Models.Mapping
|
||||
.ForMember(dest => dest.SessionId, opt => opt.MapFrom(user => user.SecurityStamp.IsNullOrWhiteSpace() ? Guid.NewGuid().ToString("N") : user.SecurityStamp));
|
||||
}
|
||||
|
||||
private IEnumerable<EntityBasic> GetStartNodeValues(int[] startNodeIds,
|
||||
ILocalizedTextService textService, IEntityService entityService, UmbracoObjectTypes objectType,
|
||||
string localizedKey)
|
||||
{
|
||||
if (startNodeIds.Length <= 0)
|
||||
return Enumerable.Empty<EntityBasic>();
|
||||
|
||||
var startNodes = new List<EntityBasic>();
|
||||
if (startNodeIds.Contains(-1))
|
||||
startNodes.Add(RootNode(textService.Localize(localizedKey)));
|
||||
|
||||
var mediaItems = entityService.GetAll(objectType, startNodeIds);
|
||||
startNodes.AddRange(Mapper.Map<IEnumerable<IUmbracoEntity>, IEnumerable<EntityBasic>>(mediaItems));
|
||||
return startNodes;
|
||||
}
|
||||
|
||||
private void MapUserGroupBasic(ISectionService sectionService, IEntityService entityService, ILocalizedTextService textService, dynamic group, UserGroupBasic display)
|
||||
{
|
||||
var allSections = sectionService.GetSections();
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
using Umbraco.Web.Composing;
|
||||
using Umbraco.Web.Security;
|
||||
|
||||
namespace Umbraco.Web.Models
|
||||
@@ -24,9 +25,9 @@ namespace Umbraco.Web.Models
|
||||
private ProfileModel(bool doLookup)
|
||||
{
|
||||
MemberProperties = new List<UmbracoProperty>();
|
||||
if (doLookup)
|
||||
if (doLookup && Current.UmbracoContext != null)
|
||||
{
|
||||
var helper = new MembershipHelper(new HttpContextWrapper(HttpContext.Current));
|
||||
var helper = new MembershipHelper(Current.UmbracoContext);
|
||||
var model = helper.GetCurrentMemberProfileModel();
|
||||
MemberProperties = model.MemberProperties;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.ComponentModel.DataAnnotations;
|
||||
using System.Web;
|
||||
using System.Web.Mvc;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Web.Composing;
|
||||
using Umbraco.Web.Security;
|
||||
|
||||
namespace Umbraco.Web.Models
|
||||
@@ -29,9 +30,9 @@ namespace Umbraco.Web.Models
|
||||
MemberProperties = new List<UmbracoProperty>();
|
||||
LoginOnSuccess = true;
|
||||
CreatePersistentLoginCookie = true;
|
||||
if (doLookup && HttpContext.Current != null)
|
||||
if (doLookup && Current.UmbracoContext != null)
|
||||
{
|
||||
var helper = new MembershipHelper(new HttpContextWrapper(HttpContext.Current));
|
||||
var helper = new MembershipHelper(Current.UmbracoContext);
|
||||
var model = helper.CreateRegistrationModel(MemberTypeAlias);
|
||||
MemberProperties = model.MemberProperties;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user