diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/content.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/content.resource.js index e629bb0beb..49c3745970 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/content.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/content.resource.js @@ -40,6 +40,8 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) { return { + + getRecycleBin: function () { return umbRequestHelper.resourcePromise( $http.get( @@ -554,6 +556,15 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) { 'Failed to check permission for item ' + id); }, + getDetailedPermissions: function (contentId) { + return umbRequestHelper.resourcePromise( + $http.get( + umbRequestHelper.getApiUrl( + "contentApiBaseUrl", + "GetDetailedPermissions", { contentId: contentId })), + 'Failed to retrieve permissions for content item ' + contentId); + }, + getPermissions: function (nodeIds) { return umbRequestHelper.resourcePromise( $http.post( diff --git a/src/Umbraco.Web.UI.Client/src/views/content/content.rights.controller.js b/src/Umbraco.Web.UI.Client/src/views/content/content.rights.controller.js index 614be714f5..764aaac3ca 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/content.rights.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/content/content.rights.controller.js @@ -1,7 +1,7 @@ (function () { "use strict"; - function ContentRightsController($scope, usersResource) { + function ContentRightsController($scope, contentResource) { var vm = this; @@ -19,106 +19,9 @@ function onInit() { vm.loading = true; - usersResource.getUserGroups().then(function (userGroups) { + contentResource.getDetailedPermissions($scope.currentNode.id).then(function (userGroups) { vm.availableUserGroups = userGroups; - vm.loading = false; - - // fake permissions - angular.forEach(vm.availableUserGroups, function(userGroup){ - userGroup.permissions = [ - { - "groupName": "Content", - "permissions": [ - { - "name": "Edit content (save)", - "description": "Lorem ipsum dolor sit amet", - "checked": false - }, - { - "name": "Browse content", - "description": "Nullam egestas porta mi, quis finibus nisl commodo a", - "checked": true - }, - { - "name": "Publish", - "description": "Aliquam molestie consequat felis", - "checked": true - }, - { - "name": "Send to publish", - "description": "Sed pharetra sodales enim quis molestie", - "checked": true - }, - { - "name": "Delete", - "description": "Vitae porta mauris turpis sit amet ligula", - "checked": true - }, - { - "name": "Create", - "description": "Vestibulum pretium sapien id turpis elementum viverra", - "checked": true - }, - ] - }, - { - "groupName": "Structure", - "permissions": [ - { - "name": "Move", - "description": "Vestibulum pretium sapien id turpis elementum viverra", - "checked": true - }, - { - "name": "Copy", - "description": "Phasellus sagittis, dolor vel accumsan porttitor", - "checked": false - }, - { - "name": "Sort", - "description": "Aliquam erat volutpat", - "checked": false - } - ] - }, - { - "groupName": "Administration", - "permissions": [ - { - "name": "Culture and Hostnames", - "description": "Lorem ipsum dolor sit amet", - "checked": true - }, - { - "name": "Audit Trail", - "description": "Lorem ipsum dolor sit amet", - "checked": true - }, - { - "name": "Translate", - "description": "Lorem ipsum dolor sit amet", - "checked": true - }, - { - "name": "Change document type", - "description": "Lorem ipsum dolor sit amet", - "checked": true - }, - { - "name": "Public access", - "description": "Lorem ipsum dolor sit amet", - "checked": true - }, - { - "name": "Rollback", - "description": "Lorem ipsum dolor sit amet", - "checked": true - } - ] - } - ]; - - }); + vm.loading = false; }); } diff --git a/src/Umbraco.Web.UI.Client/src/views/content/rights.html b/src/Umbraco.Web.UI.Client/src/views/content/rights.html index defedb550e..2f58f8618b 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/rights.html +++ b/src/Umbraco.Web.UI.Client/src/views/content/rights.html @@ -59,11 +59,11 @@
Set permissions for {{ vm.selectedUserGroup.name }}

Nam tellus purus, malesuada sed purus ut, semper sollicitudin odio.

-
+
-
{{ group.groupName }}
+
{{ category }}
-
+
); } + + /// + /// Returns the user group permissions for user groups assigned to this node + /// + /// + /// + /// + /// Permission check is done for letter 'R' which is for which the user must have access to to view + /// + [EnsureUserPermissionForContent("contentId", 'R')] + public IEnumerable GetDetailedPermissions(int contentId) + { + if (contentId <= 0) throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound)); + var found = Services.ContentService.GetById(contentId); + if (found == null) throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound)); + + + //get all user groups and map their default permissions to the AssignedUserGroupPermissions model. + //we do this because not all groups will have true assigned permissions for this node so if they don't have assigned permissions, we need to show the defaults. + var allUserGroups = Services.UserService.GetAllUserGroups(); + var defaultPermissionsByGroup = Mapper.Map>(allUserGroups) + .ToDictionary(x => Convert.ToInt32(x.Id), x => x); + + //get the actual assigned permissions + var assignedPermissionsByGroup = Services.ContentService.GetPermissionsForEntity(found).ToArray(); + + //iterate over assigned and update the defaults with the real values + foreach (var assignedGroupPermission in assignedPermissionsByGroup) + { + var defaultUserGroupPermissions = defaultPermissionsByGroup[assignedGroupPermission.UserGroupId]; + + //iterate each assigned permission for this group, the permission is essentially the letter of the action + foreach (var assignedPermission in assignedGroupPermission.AssignedPermissions) + { + //find this permission letter in the default model + + //iterate through the dictionary + foreach (var defaultUserGroupPermissionByGroup in defaultUserGroupPermissions.AssignedPermissions) + { + //iterate through the key/value pair values + foreach (var permissionInGroup in defaultUserGroupPermissionByGroup.Value) + { + //assigned the checked parameter based on the actual assigned permission + permissionInGroup.Checked = permissionInGroup.Letter == assignedPermission; + } + } + } + } + + return defaultPermissionsByGroup.Values; + } /// /// Returns an item to be used to display the recycle bin for content @@ -303,6 +355,7 @@ namespace Umbraco.Web.Editors /// /// Returns permissions for all nodes passed in for the current user + /// TODO: This should be moved to the CurrentUserController? /// /// /// @@ -312,8 +365,15 @@ namespace Umbraco.Web.Editors return Services.UserService .GetPermissions(Security.CurrentUser, nodeIds) .ToDictionary(x => x.EntityId, x => x.AssignedPermissions); - } + } + /// + /// Checks a nodes permission for the current user + /// TODO: This should be moved to the CurrentUserController? + /// + /// + /// + /// [HttpGet] public bool HasPermission(string permissionToCheck, int nodeId) { diff --git a/src/Umbraco.Web/Models/ContentEditing/AssignedUserGroupPermissions.cs b/src/Umbraco.Web/Models/ContentEditing/AssignedUserGroupPermissions.cs new file mode 100644 index 0000000000..8875550454 --- /dev/null +++ b/src/Umbraco.Web/Models/ContentEditing/AssignedUserGroupPermissions.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using System.Runtime.Serialization; + +namespace Umbraco.Web.Models.ContentEditing +{ + /// + /// The user group permissions assigned to a content node + /// + [DataContract(Name = "contentPermission", Namespace = "")] + public class AssignedUserGroupPermissions : EntityBasic + { + /// + /// The default permissions for the user group organized by permission group name + /// + [DataMember(Name = "permissions")] + public IDictionary> AssignedPermissions { get; set; } + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/Models/ContentEditing/Permission.cs b/src/Umbraco.Web/Models/ContentEditing/Permission.cs index c2b76c9ca7..a47a1d5c33 100644 --- a/src/Umbraco.Web/Models/ContentEditing/Permission.cs +++ b/src/Umbraco.Web/Models/ContentEditing/Permission.cs @@ -22,5 +22,11 @@ namespace Umbraco.Web.Models.ContentEditing /// [IgnoreDataMember] internal string Category { get; set; } + + /// + /// Used internall to carry the permission letter from the IAction + /// + [IgnoreDataMember] + internal string Letter { get; set; } } } \ No newline at end of file diff --git a/src/Umbraco.Web/Models/ContentEditing/UserGroupBasic.cs b/src/Umbraco.Web/Models/ContentEditing/UserGroupBasic.cs index df39a9fdab..e610eec7e0 100644 --- a/src/Umbraco.Web/Models/ContentEditing/UserGroupBasic.cs +++ b/src/Umbraco.Web/Models/ContentEditing/UserGroupBasic.cs @@ -4,16 +4,6 @@ using System.Runtime.Serialization; namespace Umbraco.Web.Models.ContentEditing { - [DataContract(Name = "userGroup", Namespace = "")] - public class UserGroupPermission : EntityBasic - { - /// - /// The default permissions for the user group organized by permission group name - /// - [DataMember(Name = "permissions")] - public IDictionary> DefaultPermissions { get; set; } - } - [DataContract(Name = "userGroup", Namespace = "")] public class UserGroupBasic : EntityBasic, INotificationModel { diff --git a/src/Umbraco.Web/Models/Mapping/PermissionsResolver.cs b/src/Umbraco.Web/Models/Mapping/PermissionsResolver.cs index f4be88c39a..5bbee5acf5 100644 --- a/src/Umbraco.Web/Models/Mapping/PermissionsResolver.cs +++ b/src/Umbraco.Web/Models/Mapping/PermissionsResolver.cs @@ -46,9 +46,8 @@ namespace Umbraco.Web.Models.Mapping : attribute.Name; 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); return result; } } diff --git a/src/Umbraco.Web/Models/Mapping/UserModelMapper.cs b/src/Umbraco.Web/Models/Mapping/UserModelMapper.cs index 41dd6ade35..4436f79d7f 100644 --- a/src/Umbraco.Web/Models/Mapping/UserModelMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/UserModelMapper.cs @@ -27,18 +27,18 @@ namespace Umbraco.Web.Models.Mapping .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)) + .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)) .AfterMap((save, userGroup) => { userGroup.ClearAllowedSections(); foreach (var section in save.Sections) - { + { userGroup.AddAllowedSection(section); } - }); + }); //Used for merging existing UserSave to an existing IUser instance - this will not create an IUser instance! config.CreateMap() @@ -100,6 +100,22 @@ namespace Umbraco.Web.Models.Mapping MapUserGroupBasic(applicationContext.Services, group, display); }); + //create a map to assign a user group's default permissions to the AssignedUserGroupPermissions instance + config.CreateMap() + .ForMember(detail => detail.Udi, opt => opt.Ignore()) + .ForMember(detail => detail.Trashed, opt => opt.Ignore()) + .ForMember(detail => detail.AdditionalData, opt => opt.Ignore()) + .ForMember(detail => detail.Id, opt => opt.MapFrom(group => group.Id)) + .ForMember(detail => detail.ParentId, opt => opt.UseValue(-1)) + .ForMember(detail => detail.Path, opt => opt.MapFrom(userGroup => "-1," + userGroup.Id)) + .ForMember(detail => detail.AssignedPermissions, expression => expression.ResolveUsing(new PermissionsResolver(applicationContext.Services.TextService))) + .AfterMap((group, display) => + { + if (display.Icon.IsNullOrWhiteSpace()) + { + display.Icon = "icon-users"; + } + }); config.CreateMap() .ForMember(detail => detail.StartContentId, opt => opt.Ignore()) .ForMember(detail => detail.StartMediaId, opt => opt.Ignore()) @@ -110,7 +126,7 @@ namespace Umbraco.Web.Models.Mapping .ForMember(detail => detail.ParentId, opt => opt.UseValue(-1)) .ForMember(detail => detail.Path, opt => opt.MapFrom(userGroup => "-1," + userGroup.Id)) .ForMember(detail => detail.AdditionalData, opt => opt.Ignore()) - .ForMember(detail => detail.Users, opt => opt.Ignore()) + .ForMember(detail => detail.Users, opt => opt.Ignore()) .ForMember(detail => detail.DefaultPermissions, expression => expression.ResolveUsing(new PermissionsResolver(applicationContext.Services.TextService))) .AfterMap((group, display) => { @@ -138,6 +154,7 @@ namespace Umbraco.Web.Models.Mapping .ForMember(detail => detail.Notifications, opt => opt.Ignore()) .ForMember(detail => detail.Udi, opt => opt.Ignore()) .ForMember(detail => detail.Icon, opt => opt.Ignore()) + .ForMember(detail => detail.IsCurrentUser, opt => opt.Ignore()) .ForMember(detail => detail.Trashed, opt => opt.Ignore()) .ForMember(detail => detail.ResetPasswordValue, opt => opt.Ignore()) .ForMember(detail => detail.Alias, opt => opt.Ignore()) diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 857a4e38af..9a512b2b92 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -367,6 +367,7 @@ +