[8030] Adds "Create content" permission (#8048)

Fixes #8030
This commit is contained in:
Hermes Sbicego
2018-05-11 21:19:49 +02:00
committed by Sébastien Ros
parent c1522d5b03
commit de52d82955
7 changed files with 118 additions and 32 deletions

View File

@@ -45,8 +45,8 @@ namespace Orchard.Core.Contents {
// review: the display name should be a LocalizedString
if (createRouteValues.Any())
menu.Add(T(contentTypeDefinition.DisplayName), "5", item => item.Action(cim.CreateRouteValues["Action"] as string, cim.CreateRouteValues["Controller"] as string, cim.CreateRouteValues)
// Apply "PublishOwn" permission for the content type
.Permission(DynamicPermissions.CreateDynamicPermission(DynamicPermissions.PermissionTemplates[Permissions.PublishOwnContent.Name], contentTypeDefinition)));
// Apply "CreateContent" permission for the content type
.Permission(DynamicPermissions.CreateDynamicPermission(DynamicPermissions.PermissionTemplates[Permissions.CreateContent.Name], contentTypeDefinition)));
}
});
}

View File

@@ -81,9 +81,9 @@ namespace Orchard.Core.Contents.Controllers {
}
var query = _contentManager.Query(versionOptions, GetListableTypes(false).Select(ctd => ctd.Name).ToArray());
ContentTypeDefinition contentTypeDefinition = null;
if (!string.IsNullOrEmpty(model.TypeName)) {
var contentTypeDefinition = _contentDefinitionManager.GetTypeDefinition(model.TypeName);
contentTypeDefinition = _contentDefinitionManager.GetTypeDefinition(model.TypeName);
if (contentTypeDefinition == null)
return HttpNotFound();
@@ -110,11 +110,11 @@ namespace Orchard.Core.Contents.Controllers {
break;
}
if(!String.IsNullOrWhiteSpace(model.Options.SelectedCulture)) {
if (!String.IsNullOrWhiteSpace(model.Options.SelectedCulture)) {
query = _cultureFilter.FilterCulture(query, model.Options.SelectedCulture);
}
if(model.Options.ContentsStatus == ContentsStatus.Owner) {
if (model.Options.ContentsStatus == ContentsStatus.Owner) {
query = query.Where<CommonPartRecord>(cr => cr.OwnerId == Services.WorkContext.CurrentUser.Id);
}
@@ -134,7 +134,7 @@ namespace Orchard.Core.Contents.Controllers {
var list = Shape.List();
list.AddRange(pageOfContentItems.Select(ci => _contentManager.BuildDisplay(ci, "SummaryAdmin")));
var viewModel = Shape.ViewModel()
var viewModel = Shape.ViewModel(ContentType: contentTypeDefinition)
.ContentItems(list)
.Pager(pagerShape)
.Options(model.Options)
@@ -145,7 +145,7 @@ namespace Orchard.Core.Contents.Controllers {
private IEnumerable<ContentTypeDefinition> GetCreatableTypes(bool andContainable) {
return _contentDefinitionManager.ListTypeDefinitions().Where(ctd =>
Services.Authorizer.Authorize(Permissions.EditContent, _contentManager.New(ctd.Name)) &&
Services.Authorizer.Authorize(Permissions.CreateContent, _contentManager.New(ctd.Name)) &&
ctd.Settings.GetModel<ContentTypeSettings>().Creatable &&
(!andContainable || ctd.Parts.Any(p => p.PartDefinition.Name == "ContainablePart")));
}
@@ -247,7 +247,7 @@ namespace Orchard.Core.Contents.Controllers {
var contentItem = _contentManager.New(id);
if (!Services.Authorizer.Authorize(Permissions.EditContent, contentItem, T("Cannot create content")))
if (!Services.Authorizer.Authorize(Permissions.CreateContent, contentItem, T("Cannot create content")))
return new HttpUnauthorizedResult();
if (containerId.HasValue && contentItem.Is<ContainablePart>()) {
@@ -393,7 +393,7 @@ namespace Orchard.Core.Contents.Controllers {
if (contentItem == null)
return HttpNotFound();
if (!Services.Authorizer.Authorize(Permissions.EditContent, contentItem, T("Couldn't clone content")))
if (!Services.Authorizer.Authorize(Permissions.CreateContent, contentItem, T("Couldn't clone content")))
return new HttpUnauthorizedResult();
try {

View File

@@ -9,10 +9,11 @@ using Orchard.Security.Permissions;
namespace Orchard.Core.Contents {
public class DynamicPermissions : IPermissionProvider {
private static readonly Permission CreateContent = new Permission { Description = "Create {0}", Name = "Create_{0}", ImpliedBy = new[] { Permissions.CreateContent } };
private static readonly Permission PublishContent = new Permission { Description = "Publish or unpublish {0} for others", Name = "Publish_{0}", ImpliedBy = new[] { Permissions.PublishContent } };
private static readonly Permission PublishOwnContent = new Permission { Description = "Publish or unpublish {0}", Name = "PublishOwn_{0}", ImpliedBy = new[] { PublishContent, Permissions.PublishOwnContent } };
private static readonly Permission EditContent = new Permission { Description = "Edit {0} for others", Name = "Edit_{0}", ImpliedBy = new[] { PublishContent, Permissions.EditContent } };
private static readonly Permission EditOwnContent = new Permission { Description = "Edit {0}", Name = "EditOwn_{0}", ImpliedBy = new[] { EditContent, PublishOwnContent, Permissions.EditOwnContent } };
private static readonly Permission EditOwnContent = new Permission { Description = "Edit {0}", Name = "EditOwn_{0}", ImpliedBy = new[] { CreateContent, EditContent, PublishOwnContent, Permissions.EditOwnContent } };
private static readonly Permission DeleteContent = new Permission { Description = "Delete {0} for others", Name = "Delete_{0}", ImpliedBy = new[] { Permissions.DeleteContent } };
private static readonly Permission DeleteOwnContent = new Permission { Description = "Delete {0}", Name = "DeleteOwn_{0}", ImpliedBy = new[] { DeleteContent, Permissions.DeleteOwnContent } };
private static readonly Permission ViewContent = new Permission { Description = "View {0} by others", Name = "View_{0}", ImpliedBy = new[] { EditContent, Permissions.ViewContent } };
@@ -30,7 +31,8 @@ namespace Orchard.Core.Contents {
{Permissions.ViewContent.Name, ViewContent},
{Permissions.ViewOwnContent.Name, ViewOwnContent},
{Permissions.PreviewContent.Name, PreviewContent},
{Permissions.PreviewOwnContent.Name, PreviewOwnContent}
{Permissions.PreviewOwnContent.Name, PreviewOwnContent},
{Permissions.CreateContent.Name, CreateContent}
};
private readonly IContentDefinitionManager _contentDefinitionManager;

View File

@@ -8,10 +8,11 @@ namespace Orchard.Core.Contents {
// Note - in code you should demand PublishContent, EditContent, or DeleteContent
// Do not demand the "Own" variations - those are applied automatically when you demand the main ones
public static readonly Permission CreateContent = new Permission { Description = "Create content", Name = "CreateContent" };
public static readonly Permission PublishContent = new Permission { Description = "Publish or unpublish content for others", Name = "PublishContent" };
public static readonly Permission PublishOwnContent = new Permission { Description = "Publish or unpublish own content", Name = "PublishOwnContent", ImpliedBy = new[] { PublishContent } };
public static readonly Permission EditContent = new Permission { Description = "Edit content for others", Name = "EditContent", ImpliedBy = new[] { PublishContent } };
public static readonly Permission EditOwnContent = new Permission { Description = "Edit own content", Name = "EditOwnContent", ImpliedBy = new[] { EditContent, PublishOwnContent } };
public static readonly Permission EditOwnContent = new Permission { Description = "Edit own content", Name = "EditOwnContent", ImpliedBy = new[] { CreateContent, EditContent, PublishOwnContent } };
public static readonly Permission DeleteContent = new Permission { Description = "Delete content for others", Name = "DeleteContent" };
public static readonly Permission DeleteOwnContent = new Permission { Description = "Delete own content", Name = "DeleteOwnContent", ImpliedBy = new[] { DeleteContent } };
public static readonly Permission ViewContent = new Permission { Description = "View all content", Name = "ViewContent", ImpliedBy = new[] { EditContent } };
@@ -35,7 +36,8 @@ namespace Orchard.Core.Contents {
ViewContent,
ViewOwnContent,
PreviewOwnContent,
PreviewContent
PreviewContent,
CreateContent
};
}
@@ -43,22 +45,22 @@ namespace Orchard.Core.Contents {
return new[] {
new PermissionStereotype {
Name = "Administrator",
Permissions = new[] {PublishContent,EditContent,DeleteContent,PreviewContent}
Permissions = new[] {PublishContent,EditContent,DeleteContent,PreviewContent, CreateContent }
},
new PermissionStereotype {
Name = "Editor",
Permissions = new[] {PublishContent,EditContent,DeleteContent,PreviewContent}
Permissions = new[] {PublishContent,EditContent,DeleteContent, PreviewContent, CreateContent }
},
new PermissionStereotype {
Name = "Moderator"
},
new PermissionStereotype {
Name = "Author",
Permissions = new[] {PublishOwnContent,EditOwnContent,DeleteOwnContent,PreviewOwnContent}
Permissions = new[] {PublishOwnContent,EditOwnContent,DeleteOwnContent,PreviewOwnContent, CreateContent }
},
new PermissionStereotype {
Name = "Contributor",
Permissions = new[] {EditOwnContent,PreviewOwnContent}
Permissions = new[] {EditOwnContent,PreviewOwnContent, CreateContent }
},
new PermissionStereotype {
Name = "Authenticated",

View File

@@ -1,22 +1,33 @@
@using Orchard.Core.Contents.ViewModels;
@using Orchard.Core.Contents;
@using Orchard.Core.Contents.ViewModels;
@using Orchard.Security;
@using Orchard.Security.Permissions;
@{
var typeDisplayName = Model.TypeDisplayName;
var pageTitle = T("Manage Content");
var createLinkText = T("Create New Content");
var userCanCreateContent = false;
IAuthorizationService _authorizationService;
WorkContext.TryResolve<IAuthorizationService>(out _authorizationService);
if (!string.IsNullOrWhiteSpace(typeDisplayName)) {
pageTitle = T("Manage {0} Content", Html.Raw(typeDisplayName));
createLinkText = T("Create New {0}", Html.Raw(typeDisplayName));
var permission = DynamicPermissions.CreateDynamicPermission(DynamicPermissions.PermissionTemplates[Permissions.CreateContent.Name], Model.ContentType);
if (_authorizationService.TryCheckAccess(permission, WorkContext.CurrentUser, null)) {
userCanCreateContent = true;
}
}
IEnumerable<string> cultures = Model.Options.Cultures;
Layout.Title = pageTitle.Text;
}
@if (userCanCreateContent) {
<div class="manage">
@Html.ActionLink(createLinkText.Text, "Create", new { Area = "Contents", Id = (string)Model.Options.SelectedFilter }, new { @class = "button primaryAction" })
</div>
}
@using (Html.BeginFormAntiForgeryPost()) {
<fieldset class="bulk-actions">
<label><input type="checkbox" class="check-all" />@T("Select all")</label>@T(" | ")
@@ -65,7 +76,7 @@
<button type="submit" name="submit.Filter" value="yes please">@T("Apply")</button>
</fieldset>
<fieldset class="contentItems bulk-items">
@Display(Model.ContentItems)
@Display(Model.ContentItems)
</fieldset>
@Display(Model.Pager)
}
@Display(Model.Pager)
}

View File

@@ -4,7 +4,7 @@
@{
ContentPart contentPart = Model.ContentPart;
}
@if (Authorizer.Authorize(Permissions.EditContent, contentPart)) {
@if (Authorizer.Authorize(Permissions.CreateContent, contentPart)) {
<a href="@Url.Action("Clone", "Admin", new { Id = Model.ContentItem.Id, ReturnUrl = Request.ToUrlString(), Area = "Contents" })" itemprop="UnsafeUrl">@T("Clone")</a>
@T(" | ")
}

View File

@@ -1,16 +1,29 @@
using Orchard.Data.Migration;
using System.Collections.Generic;
using System.Linq;
using Orchard.ContentManagement.MetaData;
using Orchard.Core.Contents;
using Orchard.Core.Contents.Settings;
using Orchard.Data.Migration;
using Orchard.Roles.Models;
using Orchard.Roles.Services;
using Orchard.Security;
namespace Orchard.Roles {
public class RolesDataMigration : DataMigrationImpl {
private readonly IAuthorizationService _authorizationService;
private readonly IContentDefinitionManager _contentDefinitionManager;
private readonly IRoleService _roleService;
public RolesDataMigration(IRoleService roleService) {
public RolesDataMigration(IRoleService roleService,
IAuthorizationService authorizationService,
IContentDefinitionManager contentDefinitionManager) {
_authorizationService = authorizationService;
_contentDefinitionManager = contentDefinitionManager;
_roleService = roleService;
}
public int Create() {
SchemaBuilder.CreateTable("PermissionRecord",
SchemaBuilder.CreateTable("PermissionRecord",
table => table
.Column<int>("Id", column => column.PrimaryKey().Identity())
.Column<string>("Name")
@@ -18,13 +31,13 @@ namespace Orchard.Roles {
.Column<string>("Description")
);
SchemaBuilder.CreateTable("RoleRecord",
SchemaBuilder.CreateTable("RoleRecord",
table => table
.Column<int>("Id", column => column.PrimaryKey().Identity())
.Column<string>("Name")
);
SchemaBuilder.CreateTable("RolesPermissionsRecord",
SchemaBuilder.CreateTable("RolesPermissionsRecord",
table => table
.Column<int>("Id", column => column.PrimaryKey().Identity())
.Column<int>("Role_id")
@@ -32,7 +45,7 @@ namespace Orchard.Roles {
.Column<int>("RoleRecord_Id")
);
SchemaBuilder.CreateTable("UserRolesPartRecord",
SchemaBuilder.CreateTable("UserRolesPartRecord",
table => table
.Column<int>("Id", column => column.PrimaryKey().Identity())
.Column<int>("UserId")
@@ -50,5 +63,63 @@ namespace Orchard.Roles {
return 2;
}
public int UpdateFrom2() {
//Assigns the "Create Permission" to all roles able to create contents
var contentEditPermissions = new[] {
Core.Contents.Permissions.EditContent,
Core.Contents.Permissions.EditOwnContent
};
var dynamicPermissions = new Orchard.Core.Contents.DynamicPermissions(_contentDefinitionManager);
var securableTypes = _contentDefinitionManager.ListTypeDefinitions()
.Where(ctd => ctd.Settings.GetModel<ContentTypeSettings>().Securable);
var permissionTemplates = Core.Contents.DynamicPermissions.PermissionTemplates;
List<object> dynContentPermissions = new List<object>();
foreach (var typeDefinition in securableTypes) {
dynContentPermissions.Add(new {
Permission = DynamicPermissions.CreateDynamicPermission(permissionTemplates[Core.Contents.Permissions.EditContent.Name], typeDefinition),
CreatePermission = DynamicPermissions.CreateDynamicPermission(permissionTemplates[Core.Contents.Permissions.CreateContent.Name], typeDefinition)
});
dynContentPermissions.Add(new {
Permission = DynamicPermissions.CreateDynamicPermission(permissionTemplates[Core.Contents.Permissions.EditOwnContent.Name], typeDefinition),
CreatePermission = DynamicPermissions.CreateDynamicPermission(permissionTemplates[Core.Contents.Permissions.CreateContent.Name], typeDefinition)
});
}
var roles = _roleService.GetRoles();
foreach (var role in roles) {
var existingPermissionsNames = role.RolesPermissions.Select(x => x.Permission.Name).ToList();
var checkForDynamicPermissions = true;
var updateRole = false;
if (existingPermissionsNames.Any(x => x == Core.Contents.Permissions.CreateContent.Name)) {
continue; // Skipping this role cause it already has the Create content permission
}
var simulation = UserSimulation.Create(role.Name);
foreach (var contentEditPermission in contentEditPermissions) {
if (_authorizationService.TryCheckAccess(contentEditPermission, simulation, null)) {
existingPermissionsNames.Add(Core.Contents.Permissions.CreateContent.Name);
checkForDynamicPermissions = false;
updateRole = true;
break;
}
}
if (checkForDynamicPermissions) {
foreach (var dynContentPermission in dynContentPermissions) {
if (!existingPermissionsNames.Contains(((dynamic)dynContentPermission).CreatePermission.Name)) { // Skipping this permission cause it already has the Create content variation
if (_authorizationService.TryCheckAccess(((dynamic)dynContentPermission).Permission, simulation, null)) {
existingPermissionsNames.Add(((dynamic)dynContentPermission).CreatePermission.Name);
updateRole = true;
}
}
}
}
if (updateRole) {
var rolePermissionsNames = existingPermissionsNames;
_roleService.UpdateRole(role.Id, role.Name, rolePermissionsNames);
}
}
return 3;
}
}
}