diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/usergroups.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/usergroups.resource.js new file mode 100644 index 0000000000..a48806f48c --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/common/resources/usergroups.resource.js @@ -0,0 +1,75 @@ +/** + * @ngdoc service + * @name umbraco.resources.usersResource + * @function + * + * @description + * Used by the users section to get users and send requests to create, invite, delete, etc. users. + */ +(function () { + 'use strict'; + + function userGroupsResource($http, umbRequestHelper, $q, umbDataFormatter) { + + function getUserGroupScaffold() { + + return umbRequestHelper.resourcePromise( + $http.get( + umbRequestHelper.getApiUrl( + "userGroupsApiBaseUrl", + "GetEmptyUserGroup")), + 'Failed to get the user group scaffold'); + } + + function saveUserGroup(userGroup, isNew) { + if (!userGroup) { + throw "userGroup not specified"; + } + + //need to convert the user data into the correctly formatted save data - it is *not* the same and we don't want to over-post + var formattedSaveData = umbDataFormatter.formatUserGroupPostData(userGroup, "save" + (isNew ? "New" : "")); + + return umbRequestHelper.resourcePromise( + $http.post( + umbRequestHelper.getApiUrl( + "userGroupsApiBaseUrl", + "PostSaveUserGroup"), + formattedSaveData), + "Failed to save user group"); + } + + function getUserGroup(id) { + + return umbRequestHelper.resourcePromise( + $http.get( + umbRequestHelper.getApiUrl( + "userGroupsApiBaseUrl", + "GetUserGroup", + { id: id })), + "Failed to retrieve data for user group " + id); + + } + + function getUserGroups() { + return umbRequestHelper.resourcePromise( + $http.get( + umbRequestHelper.getApiUrl( + "userGroupsApiBaseUrl", + "GetUserGroups")), + "Failed to retrieve user groups"); + } + + var resource = { + saveUserGroup: saveUserGroup, + getUserGroup: getUserGroup, + getUserGroups: getUserGroups, + getUserGroupScaffold: getUserGroupScaffold + }; + + return resource; + + } + + angular.module('umbraco.resources').factory('userGroupsResource', userGroupsResource); + +})(); diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/users.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/users.resource.js index 100b5a398c..7631fda31f 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/users.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/users.resource.js @@ -20,17 +20,7 @@ "PostClearAvatar", { id: userId })), 'Failed to clear the user avatar ' + userId); - } - - function getUserGroupScaffold() { - - return umbRequestHelper.resourcePromise( - $http.get( - umbRequestHelper.getApiUrl( - "userApiBaseUrl", - "GetEmptyUserGroup")), - 'Failed to get the user group scaffold'); - } + } function disableUsers(userIds) { if (!userIds) { @@ -173,44 +163,7 @@ formattedSaveData), "Failed to save user"); } - - function saveUserGroup(userGroup, isNew) { - if (!userGroup) { - throw "userGroup not specified"; - } - - //need to convert the user data into the correctly formatted save data - it is *not* the same and we don't want to over-post - var formattedSaveData = umbDataFormatter.formatUserGroupPostData(userGroup, "save" + (isNew ? "New" : "")); - - return umbRequestHelper.resourcePromise( - $http.post( - umbRequestHelper.getApiUrl( - "userApiBaseUrl", - "PostSaveUserGroup"), - formattedSaveData), - "Failed to save user group"); - } - - function getUserGroup(id) { - - return umbRequestHelper.resourcePromise( - $http.get( - umbRequestHelper.getApiUrl( - "userApiBaseUrl", - "GetUserGroup", - { id: id })), - "Failed to retrieve data for user group " + id); - - } - - function getUserGroups() { - return umbRequestHelper.resourcePromise( - $http.get( - umbRequestHelper.getApiUrl( - "userApiBaseUrl", - "GetUserGroups")), - "Failed to retrieve user groups"); - } + var resource = { disableUsers: disableUsers, @@ -219,12 +172,8 @@ getUser: getUser, createUser: createUser, inviteUser: inviteUser, - saveUser: saveUser, - saveUserGroup: saveUserGroup, - getUserGroup: getUserGroup, - getUserGroups: getUserGroups, - clearAvatar: clearAvatar, - getUserGroupScaffold: getUserGroupScaffold + saveUser: saveUser, + clearAvatar: clearAvatar }; return resource; diff --git a/src/Umbraco.Web.UI.Client/src/common/services/umbdataformatter.service.js b/src/Umbraco.Web.UI.Client/src/common/services/umbdataformatter.service.js index e4c72f5c9c..ea9b390c8b 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/umbdataformatter.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/umbdataformatter.service.js @@ -117,13 +117,25 @@ formatUserGroupPostData: function (displayModel, action) { //create the save model from the display model - var saveModel = _.pick(displayModel, 'id', 'alias', 'name', 'icon', 'sections', 'users', 'startContentId', 'startMediaId'); + var saveModel = _.pick(displayModel, 'id', 'alias', 'name', 'icon', 'sections', 'users', 'startContentId', 'startMediaId', 'permissions'); //set the action on the save model saveModel.action = action; if (!saveModel.id) { saveModel.id = 0; } + //the permissions need to just be the array of permission letters, currently it will be a dictionary of an array + var currPermissions = saveModel.permissions; + var savePermissions = []; + _.each(currPermissions, function(value, key, list) { + _.each(value, function (element, index, list) { + if (element.checked) { + savePermissions.push(element.permissionCode); + } + }); + }); + saveModel.permissions = savePermissions; + //make sure the sections are just a string array var currSections = saveModel.sections; var formattedSections = []; diff --git a/src/Umbraco.Web.UI.Client/src/views/users/group.controller.js b/src/Umbraco.Web.UI.Client/src/views/users/group.controller.js index 009f0849cb..5d44dd4387 100644 --- a/src/Umbraco.Web.UI.Client/src/views/users/group.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/users/group.controller.js @@ -1,7 +1,7 @@ (function () { "use strict"; - function UserGroupEditController($scope, $location, $routeParams, usersResource, localizationService, contentEditingHelper) { + function UserGroupEditController($scope, $location, $routeParams, userGroupsResource, localizationService, contentEditingHelper) { var vm = this; var localizeSaving = localizationService.localize("general_saving"); @@ -30,7 +30,7 @@ if ($routeParams.create) { // get user group scaffold - usersResource.getUserGroupScaffold().then(function (userGroup) { + userGroupsResource.getUserGroupScaffold().then(function (userGroup) { vm.userGroup = userGroup; setSectionIcon(vm.userGroup.sections); makeBreadcrumbs(); @@ -38,7 +38,7 @@ }); } else { // get user group - usersResource.getUserGroup($routeParams.id).then(function (userGroup) { + userGroupsResource.getUserGroup($routeParams.id).then(function (userGroup) { vm.userGroup = userGroup; setSectionIcon(vm.userGroup.sections); makeBreadcrumbs(); @@ -53,7 +53,7 @@ contentEditingHelper.contentEditorPerformSave({ statusMessage: localizeSaving, - saveMethod: usersResource.saveUserGroup, + saveMethod: userGroupsResource.saveUserGroup, scope: $scope, content: vm.userGroup, // We do not redirect on failure for users - this is because it is not possible to actually save a user diff --git a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs index 479b1852f9..ab41246753 100644 --- a/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs +++ b/src/Umbraco.Web/Editors/BackOfficeServerVariables.cs @@ -125,6 +125,10 @@ namespace Umbraco.Web.Editors "userApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl( controller => controller.PostSaveUser(null)) }, + { + "userGroupsApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl( + controller => controller.PostSaveUserGroup(null)) + }, { "contentApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl( controller => controller.PostSave(null)) diff --git a/src/Umbraco.Web/Editors/ContentController.cs b/src/Umbraco.Web/Editors/ContentController.cs index 675684ca0a..098cabf74e 100644 --- a/src/Umbraco.Web/Editors/ContentController.cs +++ b/src/Umbraco.Web/Editors/ContentController.cs @@ -125,7 +125,7 @@ namespace Umbraco.Web.Editors foreach (var permissionInGroup in defaultUserGroupPermissionByGroup.Value) { //assigned the checked parameter based on the actual assigned permission - permissionInGroup.Checked = permissionInGroup.Letter == assignedPermission; + permissionInGroup.Checked = permissionInGroup.PermissionCode == assignedPermission; } } } diff --git a/src/Umbraco.Web/Editors/UserGroupsController.cs b/src/Umbraco.Web/Editors/UserGroupsController.cs new file mode 100644 index 0000000000..498e792446 --- /dev/null +++ b/src/Umbraco.Web/Editors/UserGroupsController.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Web.Http; +using AutoMapper; +using Umbraco.Core.Models.Membership; +using Umbraco.Core.Services; +using Umbraco.Web.Models.ContentEditing; +using Umbraco.Web.Mvc; +using Umbraco.Web.WebApi; +using Umbraco.Web.WebApi.Filters; +using Constants = Umbraco.Core.Constants; + +namespace Umbraco.Web.Editors +{ + [PluginController("UmbracoApi")] + [UmbracoApplicationAuthorize(Constants.Applications.Users)] + [PrefixlessBodyModelValidator] + public class UserGroupsController : UmbracoAuthorizedJsonController + { + [UserGroupValidate] + public UserGroupDisplay PostSaveUserGroup(UserGroupSave userGroupSave) + { + if (userGroupSave == null) throw new ArgumentNullException("userGroupSave"); + + Services.UserService.Save(userGroupSave.PersistedUserGroup, userGroupSave.Users.ToArray()); + + var display = Mapper.Map(userGroupSave.PersistedUserGroup); + + display.AddSuccessNotification(Services.TextService.Localize("speechBubbles/operationSavedHeader"), Services.TextService.Localize("speechBubbles/editUserGroupSaved")); + return display; + } + + /// + /// Returns the scaffold for creating a new user group + /// + /// + public UserGroupDisplay GetEmptyUserGroup() + { + return new UserGroupDisplay(); + } + + /// + /// Returns all user groups + /// + /// + public IEnumerable GetUserGroups() + { + return Mapper.Map, IEnumerable>(Services.UserService.GetAllUserGroups()); + } + + /// + /// Return a user group + /// + /// + public UserGroupDisplay GetUserGroup(int id) + { + var found = Services.UserService.GetUserGroupById(id); + if (found == null) + throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound)); + + return Mapper.Map(found); + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/Editors/UsersController.cs b/src/Umbraco.Web/Editors/UsersController.cs index 9f26c51674..3a10f88abd 100644 --- a/src/Umbraco.Web/Editors/UsersController.cs +++ b/src/Umbraco.Web/Editors/UsersController.cs @@ -174,27 +174,7 @@ namespace Umbraco.Web.Editors return Mapper.Map(user); } - /// - /// Returns all user groups - /// - /// - public IEnumerable GetUserGroups() - { - return Mapper.Map, IEnumerable>(Services.UserService.GetAllUserGroups()); - } - - /// - /// Return a user group - /// - /// - public UserGroupDisplay GetUserGroup(int id) - { - var found = Services.UserService.GetUserGroupById(id); - if (found == null) - throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound)); - - return Mapper.Map(found); - } + /// /// Returns a paged users collection @@ -374,14 +354,7 @@ namespace Umbraco.Web.Editors return display; } - /// - /// Returns the scaffold for creating a new user group - /// - /// - public UserGroupDisplay GetEmptyUserGroup() - { - return new UserGroupDisplay(); - } + private HttpContextBase EnsureHttpContext() { @@ -502,20 +475,7 @@ namespace Umbraco.Web.Editors display.AddSuccessNotification(Services.TextService.Localize("speechBubbles/operationSavedHeader"), Services.TextService.Localize("speechBubbles/editUserSaved")); return display; - } - - [UserGroupValidate] - public UserGroupDisplay PostSaveUserGroup(UserGroupSave userGroupSave) - { - if (userGroupSave == null) throw new ArgumentNullException("userGroupSave"); - - Services.UserService.Save(userGroupSave.PersistedUserGroup, userGroupSave.Users.ToArray()); - - var display = Mapper.Map(userGroupSave.PersistedUserGroup); - - display.AddSuccessNotification(Services.TextService.Localize("speechBubbles/operationSavedHeader"), Services.TextService.Localize("speechBubbles/editUserGroupSaved")); - return display; - } + } /// /// Disables the users with the given user ids diff --git a/src/Umbraco.Web/Models/ContentEditing/ContentItemBasic.cs b/src/Umbraco.Web/Models/ContentEditing/ContentItemBasic.cs index f4f6b5a2e0..18229d94d8 100644 --- a/src/Umbraco.Web/Models/ContentEditing/ContentItemBasic.cs +++ b/src/Umbraco.Web/Models/ContentEditing/ContentItemBasic.cs @@ -89,7 +89,7 @@ namespace Umbraco.Web.Models.ContentEditing /// /// This is not used for outgoing model information. /// - [JsonIgnore] + [IgnoreDataMember] internal TPersisted PersistedContent { get; set; } /// @@ -100,7 +100,7 @@ namespace Umbraco.Web.Models.ContentEditing /// instead of having to look up all the data individually. /// This is not used for outgoing model information. /// - [JsonIgnore] + [IgnoreDataMember] internal ContentItemDto ContentDto { get; set; } diff --git a/src/Umbraco.Web/Models/ContentEditing/DataTypeSave.cs b/src/Umbraco.Web/Models/ContentEditing/DataTypeSave.cs index 16c7cade0b..9b6c0df110 100644 --- a/src/Umbraco.Web/Models/ContentEditing/DataTypeSave.cs +++ b/src/Umbraco.Web/Models/ContentEditing/DataTypeSave.cs @@ -31,13 +31,13 @@ namespace Umbraco.Web.Models.ContentEditing /// /// The real persisted data type /// - [JsonIgnore] + [IgnoreDataMember] internal IDataTypeDefinition PersistedDataType { get; set; } /// /// The PropertyEditor assigned /// - [JsonIgnore] + [IgnoreDataMember] internal PropertyEditor PropertyEditor { get; set; } } diff --git a/src/Umbraco.Web/Models/ContentEditing/Permission.cs b/src/Umbraco.Web/Models/ContentEditing/Permission.cs index a47a1d5c33..81b85f093f 100644 --- a/src/Umbraco.Web/Models/ContentEditing/Permission.cs +++ b/src/Umbraco.Web/Models/ContentEditing/Permission.cs @@ -24,9 +24,9 @@ namespace Umbraco.Web.Models.ContentEditing internal string Category { get; set; } /// - /// Used internall to carry the permission letter from the IAction + /// The letter from the IAction /// - [IgnoreDataMember] - internal string Letter { get; set; } + [DataMember(Name = "permissionCode")] + public string PermissionCode { get; set; } } } \ No newline at end of file diff --git a/src/Umbraco.Web/Models/ContentEditing/TabbedContentItem.cs b/src/Umbraco.Web/Models/ContentEditing/TabbedContentItem.cs index b18118d8c2..13c52d2a3a 100644 --- a/src/Umbraco.Web/Models/ContentEditing/TabbedContentItem.cs +++ b/src/Umbraco.Web/Models/ContentEditing/TabbedContentItem.cs @@ -29,7 +29,7 @@ namespace Umbraco.Web.Models.ContentEditing /// /// This property cannot be set /// - [JsonIgnore] + [IgnoreDataMember] public override IEnumerable Properties { get { return Tabs.SelectMany(x => x.Properties); } diff --git a/src/Umbraco.Web/Models/ContentEditing/UserGroupSave.cs b/src/Umbraco.Web/Models/ContentEditing/UserGroupSave.cs index fdb9aced0f..f18c863b77 100644 --- a/src/Umbraco.Web/Models/ContentEditing/UserGroupSave.cs +++ b/src/Umbraco.Web/Models/ContentEditing/UserGroupSave.cs @@ -36,10 +36,16 @@ namespace Umbraco.Web.Models.ContentEditing [DataMember(Name = "startMediaId")] public int StartMediaId { get; set; } + /// + /// The list of letters (permission codes) to assign as the default for the user group + /// + [DataMember(Name = "permissions")] + public IEnumerable Permissions { get; set; } + /// /// The real persisted user group /// - [JsonIgnore] + [IgnoreDataMember] internal IUserGroup PersistedUserGroup { get; set; } public IEnumerable Validate(ValidationContext validationContext) diff --git a/src/Umbraco.Web/Models/Mapping/CodeFileDisplayMapper.cs b/src/Umbraco.Web/Models/Mapping/CodeFileDisplayMapper.cs index dec0930c07..b997653844 100644 --- a/src/Umbraco.Web/Models/Mapping/CodeFileDisplayMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/CodeFileDisplayMapper.cs @@ -28,12 +28,10 @@ namespace Umbraco.Web.Models.Mapping .ForMember(x => x.Snippet, exp => exp.Ignore()); config.CreateMap() - .ForMember(x => x.DeletedDate, exp => exp.Ignore()) + .IgnoreDeletableEntityCommonProperties() .ForMember(x => x.Id, exp => exp.Ignore()) .ForMember(x => x.Key, exp => exp.Ignore()) .ForMember(x => x.Path, exp => exp.Ignore()) - .ForMember(x => x.CreateDate, exp => exp.Ignore()) - .ForMember(x => x.UpdateDate, exp => exp.Ignore()) .ForMember(x => x.Path, exp => exp.Ignore()) .ForMember(x => x.Alias, exp => exp.Ignore()) .ForMember(x => x.Name, exp => exp.Ignore()) @@ -41,12 +39,10 @@ namespace Umbraco.Web.Models.Mapping .ForMember(x => x.HasIdentity, exp => exp.Ignore()); config.CreateMap() - .ForMember(x => x.DeletedDate, exp => exp.Ignore()) + .IgnoreDeletableEntityCommonProperties() .ForMember(x => x.Id, exp => exp.Ignore()) .ForMember(x => x.Key, exp => exp.Ignore()) .ForMember(x => x.Path, exp => exp.Ignore()) - .ForMember(x => x.CreateDate, exp => exp.Ignore()) - .ForMember(x => x.UpdateDate, exp => exp.Ignore()) .ForMember(x => x.Path, exp => exp.Ignore()) .ForMember(x => x.Alias, exp => exp.Ignore()) .ForMember(x => x.Name, exp => exp.Ignore()) diff --git a/src/Umbraco.Web/Models/Mapping/ContentTypeModelMapper.cs b/src/Umbraco.Web/Models/Mapping/ContentTypeModelMapper.cs index 1d9b4fedda..515104d02c 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentTypeModelMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentTypeModelMapper.cs @@ -38,6 +38,7 @@ namespace Umbraco.Web.Models.Mapping config.CreateMap() .ConstructUsing(basic => new PropertyType(applicationContext.Services.DataTypeService.GetDataTypeDefinitionById(basic.DataTypeId))) + .IgnoreEntityCommonProperties() .ForMember(type => type.ValidationRegExp, expression => expression.ResolveUsing(basic => basic.Validation.Pattern)) .ForMember(type => type.Mandatory, expression => expression.ResolveUsing(basic => basic.Validation.Mandatory)) .ForMember(type => type.Name, expression => expression.ResolveUsing(basic => basic.Label)) @@ -45,10 +46,8 @@ namespace Umbraco.Web.Models.Mapping .ForMember(type => type.DataTypeId, expression => expression.Ignore()) .ForMember(type => type.PropertyEditorAlias, expression => expression.Ignore()) .ForMember(type => type.HelpText, expression => expression.Ignore()) - .ForMember(type => type.Key, expression => expression.Ignore()) - .ForMember(type => type.CreateDate, expression => expression.Ignore()) - .ForMember(type => type.UpdateDate, expression => expression.Ignore()) - .ForMember(type => type.DeletedDate, expression => expression.Ignore()) + .ForMember(type => type.Key, expression => expression.Ignore()) + .ForMember(type => type.DeletedDate, expression => expression.Ignore()) .ForMember(type => type.HasIdentity, expression => expression.Ignore()); config.CreateMap() diff --git a/src/Umbraco.Web/Models/Mapping/ContentTypeModelMapperExtensions.cs b/src/Umbraco.Web/Models/Mapping/ContentTypeModelMapperExtensions.cs index 00923c8655..fea46ddedb 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentTypeModelMapperExtensions.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentTypeModelMapperExtensions.cs @@ -22,15 +22,14 @@ namespace Umbraco.Web.Models.Mapping public static IMappingExpression MapPropertyGroupBasicToPropertyGroupPersistence( this IMappingExpression mapping) - where TSource : PropertyGroupBasic + where TSource : PropertyGroupBasic where TPropertyTypeBasic : PropertyTypeBasic { return mapping + .IgnoreEntityCommonProperties() .ForMember(dest => dest.Id, map => map.Condition(source => source.Id > 0)) .ForMember(dest => dest.Key, map => map.Ignore()) - .ForMember(dest => dest.HasIdentity, map => map.Ignore()) - .ForMember(dest => dest.CreateDate, map => map.Ignore()) - .ForMember(dest => dest.UpdateDate, map => map.Ignore()) + .ForMember(dest => dest.HasIdentity, map => map.Ignore()) .ForMember(dest => dest.DeletedDate, map => map.Ignore()) .ForMember(dest => dest.PropertyTypes, map => map.Ignore()); } @@ -38,7 +37,7 @@ namespace Umbraco.Web.Models.Mapping public static IMappingExpression> MapPropertyGroupBasicToPropertyGroupDisplay( this IMappingExpression> mapping) where TSource : PropertyGroupBasic - where TPropertyTypeBasic : PropertyTypeBasic + where TPropertyTypeBasic : PropertyTypeBasic where TPropertyTypeDisplay : PropertyTypeDisplay { return mapping @@ -106,8 +105,8 @@ namespace Umbraco.Web.Models.Mapping public static IMappingExpression MapBaseContentTypeSaveToDisplay( this IMappingExpression mapping) where TSource : ContentTypeSave - where TDestination : ContentTypeCompositionDisplay - where TPropertyTypeDestination : PropertyTypeDisplay + where TDestination : ContentTypeCompositionDisplay + where TPropertyTypeDestination : PropertyTypeDisplay where TPropertyTypeSource : PropertyTypeBasic { return mapping @@ -139,7 +138,7 @@ namespace Umbraco.Web.Models.Mapping .ForMember( dto => dto.AllowedContentTypes, expression => expression.MapFrom(dto => dto.AllowedContentTypes.Select(x => x.Id.Value))) - + .ForMember( dto => dto.CompositeContentTypes, expression => expression.MapFrom(dto => dto.ContentTypeComposition)) @@ -166,7 +165,7 @@ namespace Umbraco.Web.Models.Mapping this IMappingExpression mapping, ApplicationContext applicationContext) //where TSource : ContentTypeCompositionDisplay where TSource : ContentTypeSave - where TDestination : IContentTypeComposition + where TDestination : IContentTypeComposition where TSourcePropertyType : PropertyTypeBasic { return mapping @@ -175,9 +174,7 @@ namespace Umbraco.Web.Models.Mapping .ForMember(dto => dto.Id, expression => expression.MapFrom(display => Convert.ToInt32(display.Id))) //These get persisted as part of the saving procedure, nothing to do with the display model - .ForMember(dto => dto.CreateDate, expression => expression.Ignore()) - .ForMember(dto => dto.UpdateDate, expression => expression.Ignore()) - .ForMember(dto => dto.DeletedDate, expression => expression.Ignore()) + .IgnoreDeletableEntityCommonProperties() .ForMember(dto => dto.AllowedAsRoot, expression => expression.MapFrom(display => display.AllowAsRoot)) .ForMember(dto => dto.CreatorId, expression => expression.Ignore()) @@ -188,7 +185,7 @@ namespace Umbraco.Web.Models.Mapping .ForMember(dto => dto.NoGroupPropertyTypes, expression => expression.Ignore()) // ignore, composition is managed in AfterMapContentTypeSaveToEntity .ForMember(dest => dest.ContentTypeComposition, opt => opt.Ignore()) - + .ForMember( dto => dto.AllowedContentTypes, expression => expression.MapFrom(dto => dto.AllowedContentTypes.Select((t, i) => new ContentTypeSort(t, i)))) @@ -266,7 +263,7 @@ namespace Umbraco.Web.Models.Mapping } private static PropertyGroup MapSaveGroup(PropertyGroupBasic sourceGroup, IEnumerable destOrigGroups) - where TPropertyType: PropertyTypeBasic + where TPropertyType : PropertyTypeBasic { PropertyGroup destGroup; if (sourceGroup.Id > 0) diff --git a/src/Umbraco.Web/Models/Mapping/DataTypeModelMapper.cs b/src/Umbraco.Web/Models/Mapping/DataTypeModelMapper.cs index 7e9a00f760..32d25028e4 100644 --- a/src/Umbraco.Web/Models/Mapping/DataTypeModelMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/DataTypeModelMapper.cs @@ -96,6 +96,7 @@ namespace Umbraco.Web.Models.Mapping config.CreateMap() .ConstructUsing(save => new DataTypeDefinition(save.SelectedEditor) {CreateDate = DateTime.Now}) + .IgnoreDeletableEntityCommonProperties() .ForMember(definition => definition.Id, expression => expression.MapFrom(save => Convert.ToInt32(save.Id))) //we have to ignore the Key otherwise this will reset the UniqueId field which should never change! // http://issues.umbraco.org/issue/U4-3911 @@ -106,10 +107,7 @@ namespace Umbraco.Web.Models.Mapping .ForMember(x => x.ControlId, expression => expression.Ignore()) .ForMember(x => x.CreatorId, expression => expression.Ignore()) .ForMember(x => x.Level, expression => expression.Ignore()) - .ForMember(x => x.SortOrder, expression => expression.Ignore()) - .ForMember(x => x.CreateDate, expression => expression.Ignore()) - .ForMember(x => x.DeletedDate, expression => expression.Ignore()) - .ForMember(x => x.UpdateDate, expression => expression.Ignore()); + .ForMember(x => x.SortOrder, expression => expression.Ignore()); //Converts a property editor to a new list of pre-value fields - used when creating a new data type or changing a data type with new pre-vals config.CreateMap>() diff --git a/src/Umbraco.Web/Models/Mapping/EntityModelMapperExtensions.cs b/src/Umbraco.Web/Models/Mapping/EntityModelMapperExtensions.cs new file mode 100644 index 0000000000..39f92af5d2 --- /dev/null +++ b/src/Umbraco.Web/Models/Mapping/EntityModelMapperExtensions.cs @@ -0,0 +1,42 @@ +using AutoMapper; +using Umbraco.Core.Models.EntityBase; +using Umbraco.Web.Models.ContentEditing; + +namespace Umbraco.Web.Models.Mapping +{ + /// + /// Mapping extension methods for re-use with other mappers (saves code duplication) + /// + internal static class EntityModelMapperExtensions + { + /// + /// Ignores readonly properties and the date values + /// + /// + /// + public static IMappingExpression IgnoreDeletableEntityCommonProperties( + this IMappingExpression mapping) + where TDest: IDeletableEntity + { + return mapping + .IgnoreEntityCommonProperties() + .ForMember(dest => dest.DeletedDate, map => map.Ignore()); + } + + /// + /// Ignores readonly properties and the date values + /// + /// + /// + public static IMappingExpression IgnoreEntityCommonProperties( + this IMappingExpression mapping) + where TDest : IEntity + { + return mapping + .IgnoreAllPropertiesWithAnInaccessibleSetter() + .ForMember(dest => dest.CreateDate, map => map.Ignore()) + .ForMember(dest => dest.UpdateDate, map => map.Ignore()); + } + + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/Models/Mapping/PermissionsResolver.cs b/src/Umbraco.Web/Models/Mapping/PermissionsResolver.cs index 5bbee5acf5..297b4092cb 100644 --- a/src/Umbraco.Web/Models/Mapping/PermissionsResolver.cs +++ b/src/Umbraco.Web/Models/Mapping/PermissionsResolver.cs @@ -47,7 +47,7 @@ namespace Umbraco.Web.Models.Mapping result.Description = _textService.Localize(String.Format("actionDescriptions/{0}", action.Alias)); result.Icon = action.Icon; result.Checked = source.Permissions.Contains(action.Letter.ToString(CultureInfo.InvariantCulture)); - result.Letter = action.Letter.ToString(CultureInfo.InvariantCulture); + result.PermissionCode = action.Letter.ToString(CultureInfo.InvariantCulture); return result; } } diff --git a/src/Umbraco.Web/Models/Mapping/TemplateModelMapper.cs b/src/Umbraco.Web/Models/Mapping/TemplateModelMapper.cs index 6111941084..43c75f416b 100644 --- a/src/Umbraco.Web/Models/Mapping/TemplateModelMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/TemplateModelMapper.cs @@ -14,10 +14,8 @@ namespace Umbraco.Web.Models.Mapping .ForMember(x => x.Notifications, exp => exp.Ignore()); config.CreateMap() - .ForMember(x => x.DeletedDate, exp => exp.Ignore()) - .ForMember(x => x.Path, exp => exp.Ignore()) - .ForMember(x => x.CreateDate, exp => exp.Ignore()) - .ForMember(x => x.UpdateDate, exp => exp.Ignore()) + .IgnoreDeletableEntityCommonProperties() + .ForMember(x => x.Path, exp => exp.Ignore()) .ForMember(x => x.VirtualPath, exp => exp.Ignore()) .ForMember(x => x.Path, exp => exp.Ignore()) .ForMember(x => x.MasterTemplateId, exp => exp.Ignore()) // ok, assigned when creating the template diff --git a/src/Umbraco.Web/Models/Mapping/UserModelMapper.cs b/src/Umbraco.Web/Models/Mapping/UserModelMapper.cs index f0375855ef..1fbe28ecc3 100644 --- a/src/Umbraco.Web/Models/Mapping/UserModelMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/UserModelMapper.cs @@ -25,12 +25,9 @@ namespace Umbraco.Web.Models.Mapping config.CreateMap() .ConstructUsing((UserGroupSave save) => new UserGroup() { CreateDate = DateTime.Now }) - .IgnoreAllUnmapped() - .ForMember(user => user.Alias, expression => expression.MapFrom(save => save.Alias)) - .ForMember(user => user.Name, expression => expression.MapFrom(save => save.Name)) - .ForMember(user => user.Icon, expression => expression.MapFrom(save => save.Icon)) - .ForMember(user => user.StartMediaId, expression => expression.MapFrom(save => save.StartMediaId)) - .ForMember(user => user.StartContentId, expression => expression.MapFrom(save => save.StartContentId)) + .IgnoreDeletableEntityCommonProperties() + .ForMember(dest => dest.Id, map => map.Condition(source => GetIntId(source.Id) > 0)) + .ForMember(dest => dest.Id, map => map.MapFrom(source => GetIntId(source.Id))) .AfterMap((save, userGroup) => { userGroup.ClearAllowedSections(); @@ -42,7 +39,24 @@ namespace Umbraco.Web.Models.Mapping //Used for merging existing UserSave to an existing IUser instance - this will not create an IUser instance! config.CreateMap() - .IgnoreAllUnmapped() + .IgnoreDeletableEntityCommonProperties() + .ForMember(dest => dest.Id, map => map.Condition(source => GetIntId(source.Id) > 0)) + .ForMember(detail => detail.SessionTimeout, opt => opt.Ignore()) + .ForMember(detail => detail.EmailConfirmedDate, opt => opt.Ignore()) + .ForMember(detail => detail.InvitedDate, opt => opt.Ignore()) + .ForMember(detail => detail.SecurityStamp, opt => opt.Ignore()) + .ForMember(detail => detail.Avatar, opt => opt.Ignore()) + .ForMember(detail => detail.ProviderUserKey, opt => opt.Ignore()) + .ForMember(detail => detail.RawPasswordValue, opt => opt.Ignore()) + .ForMember(detail => detail.RawPasswordAnswerValue, opt => opt.Ignore()) + .ForMember(detail => detail.PasswordQuestion, opt => opt.Ignore()) + .ForMember(detail => detail.Comments, opt => opt.Ignore()) + .ForMember(detail => detail.IsApproved, opt => opt.Ignore()) + .ForMember(detail => detail.IsLockedOut, opt => opt.Ignore()) + .ForMember(detail => detail.LastLoginDate, opt => opt.Ignore()) + .ForMember(detail => detail.LastPasswordChangeDate, opt => opt.Ignore()) + .ForMember(detail => detail.LastLockoutDate, opt => opt.Ignore()) + .ForMember(detail => detail.FailedPasswordAttempts, opt => opt.Ignore()) .ForMember(user => user.Language, expression => expression.MapFrom(save => save.Culture)) .AfterMap((save, user) => { @@ -54,9 +68,30 @@ namespace Umbraco.Web.Models.Mapping } }); - config.CreateMap() - .IgnoreAllUnmapped() - //all invited users will not be approved, completing the invite will approve the user + config.CreateMap() + .IgnoreDeletableEntityCommonProperties() + .ForMember(detail => detail.Id, opt => opt.Ignore()) + .ForMember(detail => detail.StartContentIds, opt => opt.Ignore()) + .ForMember(detail => detail.StartMediaIds, opt => opt.Ignore()) + .ForMember(detail => detail.Language, opt => opt.Ignore()) + .ForMember(detail => detail.Username, opt => opt.Ignore()) + .ForMember(detail => detail.PasswordQuestion, opt => opt.Ignore()) + .ForMember(detail => detail.SessionTimeout, opt => opt.Ignore()) + .ForMember(detail => detail.EmailConfirmedDate, opt => opt.Ignore()) + .ForMember(detail => detail.InvitedDate, opt => opt.Ignore()) + .ForMember(detail => detail.SecurityStamp, opt => opt.Ignore()) + .ForMember(detail => detail.Avatar, opt => opt.Ignore()) + .ForMember(detail => detail.ProviderUserKey, opt => opt.Ignore()) + .ForMember(detail => detail.RawPasswordValue, opt => opt.Ignore()) + .ForMember(detail => detail.RawPasswordAnswerValue, opt => opt.Ignore()) + .ForMember(detail => detail.Comments, opt => opt.Ignore()) + .ForMember(detail => detail.IsApproved, opt => opt.Ignore()) + .ForMember(detail => detail.IsLockedOut, opt => opt.Ignore()) + .ForMember(detail => detail.LastLoginDate, opt => opt.Ignore()) + .ForMember(detail => detail.LastPasswordChangeDate, opt => opt.Ignore()) + .ForMember(detail => detail.LastLockoutDate, opt => opt.Ignore()) + .ForMember(detail => detail.FailedPasswordAttempts, opt => opt.Ignore()) + //all invited users will not be approved, completing the invite will approve the user .ForMember(user => user.IsApproved, expression => expression.UseValue(false)) .AfterMap((invite, user) => { diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 9a512b2b92..c275de8e92 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -337,6 +337,7 @@ + @@ -406,6 +407,7 @@ +