mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2026-01-19 17:51:45 +08:00
Adding Securable metadata
This commit is contained in:
@@ -38,11 +38,11 @@ namespace Orchard.Core.Contents {
|
||||
}
|
||||
|
||||
public IEnumerable<Permission> GetPermissions() {
|
||||
// manage rights only for Creatable types
|
||||
var creatableTypes = _contentDefinitionManager.ListTypeDefinitions()
|
||||
.Where(ctd => ctd.Settings.GetModel<ContentTypeSettings>().Creatable);
|
||||
// manage rights only for Securable types
|
||||
var securableTypes = _contentDefinitionManager.ListTypeDefinitions()
|
||||
.Where(ctd => ctd.Settings.GetModel<ContentTypeSettings>().Securable);
|
||||
|
||||
foreach (var typeDefinition in creatableTypes) {
|
||||
foreach (var typeDefinition in securableTypes) {
|
||||
foreach (var permissionTemplate in PermissionTemplates.Values) {
|
||||
yield return CreateDynamicPermission(permissionTemplate, typeDefinition);
|
||||
}
|
||||
|
||||
@@ -15,6 +15,10 @@ namespace Orchard.Core.Contents.Extensions {
|
||||
return builder.WithSetting("ContentTypeSettings.Draftable", draftable.ToString());
|
||||
}
|
||||
|
||||
public static ContentTypeDefinitionBuilder Securable(this ContentTypeDefinitionBuilder builder, bool securable = true) {
|
||||
return builder.WithSetting("ContentTypeSettings.Securable", securable.ToString());
|
||||
}
|
||||
|
||||
public static ContentPartDefinitionBuilder Attachable(this ContentPartDefinitionBuilder builder, bool attachable = true) {
|
||||
return builder.WithSetting("ContentPartSettings.Attachable", attachable.ToString());
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace Orchard.Core.Contents.Security {
|
||||
var typeDefinition = context.Content.ContentItem.TypeDefinition;
|
||||
|
||||
// replace permission if a content type specific version exists
|
||||
if (typeDefinition.Settings.GetModel<ContentTypeSettings>().Creatable) {
|
||||
if (typeDefinition.Settings.GetModel<ContentTypeSettings>().Securable) {
|
||||
var permission = GetContentTypeVariation(context.Permission);
|
||||
|
||||
if (permission != null) {
|
||||
|
||||
@@ -16,5 +16,9 @@
|
||||
/// Defines the stereotype of the type
|
||||
/// </summary>
|
||||
public string Stereotype { get; set; }
|
||||
/// <summary>
|
||||
/// Used to determine if this content type supports custom permissions
|
||||
/// </summary>
|
||||
public bool Securable { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -18,5 +18,11 @@ namespace Orchard.ContentPermissions {
|
||||
|
||||
return 2;
|
||||
}
|
||||
|
||||
public int UpdateFrom2() {
|
||||
|
||||
// auto-upgrade to 3 as UpdateFrom1 is incorrectly returning 2
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,4 +10,4 @@ Features:
|
||||
Name: Content Item Permissions
|
||||
Description: Allows item-level front end view permissions.
|
||||
Dependencies: Orchard.Roles
|
||||
Category: Security
|
||||
Category: Security
|
||||
|
||||
@@ -71,6 +71,7 @@
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="ViewModels\SecurableContentItemsSettingsViewModel.cs" />
|
||||
<Content Include="Styles\Images\lock.gif" />
|
||||
<Content Include="Styles\orchard-contentpermissions-admin.css" />
|
||||
<Content Include="Web.config" />
|
||||
@@ -95,9 +96,13 @@
|
||||
<Compile Include="Drivers\ContentPermissionsPartDriver.cs" />
|
||||
<Compile Include="Models\ContentPermissionsPart.cs" />
|
||||
<Compile Include="Permissions.cs" />
|
||||
<Compile Include="Security\AuthorizationEventHandler.cs" />
|
||||
<Compile Include="Security\SecurableContentItemsAuthorizationEventHandler.cs" />
|
||||
<Compile Include="Security\ContentPermissionsPartAuthorizationEventHandler.cs" />
|
||||
<Compile Include="Migrations.cs" />
|
||||
<Compile Include="Services\DynamicPermissions.cs" />
|
||||
<Compile Include="Settings\ContentPermissionsPartSettings.cs" />
|
||||
<Compile Include="Settings\ContentPermissionsTypeSettings.cs" />
|
||||
<Compile Include="Settings\SecurableContentItemsEditorEvents.cs" />
|
||||
<Compile Include="ViewModels\ContentPermissionsPartViewModel.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@@ -120,6 +125,9 @@
|
||||
<ItemGroup>
|
||||
<Folder Include="Handlers\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Views\DefinitionTemplates\SecurableContentItemsSettingsViewModel.cshtml" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
|
||||
@@ -1,137 +1,137 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.ContentManagement.Aspects;
|
||||
using Orchard.Roles.Models;
|
||||
using Orchard.Security;
|
||||
using Orchard.ContentPermissions.Models;
|
||||
using Orchard.Security.Permissions;
|
||||
|
||||
namespace Orchard.ContentPermissions.Security {
|
||||
public class AuthorizationEventHandler : IAuthorizationServiceEventHandler {
|
||||
private readonly IWorkContextAccessor _workContextAccessor;
|
||||
private static readonly string[] AnonymousRole = new[] { "Anonymous" };
|
||||
private static readonly string[] AuthenticatedRole = new[] { "Authenticated" };
|
||||
|
||||
public AuthorizationEventHandler(IWorkContextAccessor workContextAccessor) {
|
||||
_workContextAccessor = workContextAccessor;
|
||||
}
|
||||
|
||||
public void Checking(CheckAccessContext context) { }
|
||||
public void Adjust(CheckAccessContext context) { }
|
||||
|
||||
public void Complete(CheckAccessContext context) {
|
||||
|
||||
if (!String.IsNullOrEmpty(_workContextAccessor.GetContext().CurrentSite.SuperUser)
|
||||
&& context.User != null
|
||||
&& String.Equals(context.User.UserName, _workContextAccessor.GetContext().CurrentSite.SuperUser, StringComparison.Ordinal)) {
|
||||
context.Granted = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (context.Content == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var part = context.Content.As<ContentPermissionsPart>();
|
||||
|
||||
// if the content item has no right attached, check on the container
|
||||
if (part == null || !part.Enabled) {
|
||||
var commonPart = context.Content.As<ICommonPart>();
|
||||
if(commonPart != null && commonPart.Container != null) {
|
||||
part = commonPart.Container.As<ContentPermissionsPart>();
|
||||
}
|
||||
}
|
||||
|
||||
if (part == null || !part.Enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
var hasOwnership = HasOwnership(context.User, context.Content);
|
||||
|
||||
IEnumerable<string> authorizedRoles;
|
||||
|
||||
var grantingPermissions = PermissionNames(context.Permission, Enumerable.Empty<string>()).Distinct().ToArray();
|
||||
|
||||
if (grantingPermissions.Any(grantingPermission => String.Equals(Core.Contents.Permissions.ViewContent.Name, grantingPermission, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
authorizedRoles = (hasOwnership ? part.ViewOwnContent : part.ViewContent).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
else if (grantingPermissions.Any(grantingPermission => String.Equals(Core.Contents.Permissions.EditContent.Name, grantingPermission, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
authorizedRoles = (hasOwnership ? part.EditOwnContent : part.EditContent).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
else if (grantingPermissions.Any(grantingPermission => String.Equals(Core.Contents.Permissions.PublishContent.Name, grantingPermission, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
authorizedRoles = (hasOwnership ? part.PublishOwnContent : part.PublishContent).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
else if (grantingPermissions.Any(grantingPermission => String.Equals(Core.Contents.Permissions.DeleteContent.Name, grantingPermission, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
authorizedRoles = (hasOwnership ? part.DeleteOwnContent : part.DeleteContent).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// determine what set of roles should be examined by the access check
|
||||
IEnumerable<string> rolesToExamine;
|
||||
if (context.User == null) {
|
||||
rolesToExamine = AnonymousRole;
|
||||
}
|
||||
else if (context.User.Has<IUserRoles>()) {
|
||||
// the current user is not null, so get his roles and add "Authenticated" to it
|
||||
rolesToExamine = context.User.As<IUserRoles>().Roles;
|
||||
|
||||
// when it is a simulated anonymous user in the admin
|
||||
if (!rolesToExamine.Contains(AnonymousRole[0])) {
|
||||
rolesToExamine = rolesToExamine.Concat(AuthenticatedRole);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// the user is not null and has no specific role, then it's just "Authenticated"
|
||||
rolesToExamine = AuthenticatedRole;
|
||||
}
|
||||
|
||||
context.Granted = rolesToExamine.Any(x => authorizedRoles.Contains(x, StringComparer.OrdinalIgnoreCase));
|
||||
context.Adjusted = true;
|
||||
}
|
||||
|
||||
private static bool HasOwnership(IUser user, IContent content) {
|
||||
if (user == null || content == null)
|
||||
return false;
|
||||
|
||||
var common = content.As<ICommonPart>();
|
||||
if (common == null || common.Owner == null)
|
||||
return false;
|
||||
|
||||
return user.Id == common.Owner.Id;
|
||||
}
|
||||
|
||||
private static IEnumerable<string> PermissionNames(Permission permission, IEnumerable<string> stack)
|
||||
{
|
||||
// the given name is tested
|
||||
yield return permission.Name;
|
||||
|
||||
// iterate implied permissions to grant, it present
|
||||
if (permission.ImpliedBy != null && permission.ImpliedBy.Any())
|
||||
{
|
||||
foreach (var impliedBy in permission.ImpliedBy)
|
||||
{
|
||||
// avoid potential recursion
|
||||
if (stack.Contains(impliedBy.Name))
|
||||
continue;
|
||||
|
||||
// otherwise accumulate the implied permission names recursively
|
||||
foreach (var impliedName in PermissionNames(impliedBy, stack.Concat(new[] { permission.Name })))
|
||||
{
|
||||
yield return impliedName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
yield return StandardPermissions.SiteOwner.Name;
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.ContentManagement.Aspects;
|
||||
using Orchard.Roles.Models;
|
||||
using Orchard.Security;
|
||||
using Orchard.ContentPermissions.Models;
|
||||
using Orchard.Security.Permissions;
|
||||
|
||||
namespace Orchard.ContentPermissions.Security {
|
||||
public class ContentPermissionsPartAuthorizationEventHandler : IAuthorizationServiceEventHandler {
|
||||
private readonly IWorkContextAccessor _workContextAccessor;
|
||||
private static readonly string[] AnonymousRole = new[] { "Anonymous" };
|
||||
private static readonly string[] AuthenticatedRole = new[] { "Authenticated" };
|
||||
|
||||
public ContentPermissionsPartAuthorizationEventHandler(IWorkContextAccessor workContextAccessor) {
|
||||
_workContextAccessor = workContextAccessor;
|
||||
}
|
||||
|
||||
public void Checking(CheckAccessContext context) { }
|
||||
public void Adjust(CheckAccessContext context) { }
|
||||
|
||||
public void Complete(CheckAccessContext context) {
|
||||
|
||||
if (!String.IsNullOrEmpty(_workContextAccessor.GetContext().CurrentSite.SuperUser)
|
||||
&& context.User != null
|
||||
&& String.Equals(context.User.UserName, _workContextAccessor.GetContext().CurrentSite.SuperUser, StringComparison.Ordinal)) {
|
||||
context.Granted = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (context.Content == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
var part = context.Content.As<ContentPermissionsPart>();
|
||||
|
||||
// if the content item has no right attached, check on the container
|
||||
if (part == null || !part.Enabled) {
|
||||
var commonPart = context.Content.As<ICommonPart>();
|
||||
if(commonPart != null && commonPart.Container != null) {
|
||||
part = commonPart.Container.As<ContentPermissionsPart>();
|
||||
}
|
||||
}
|
||||
|
||||
if (part == null || !part.Enabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
var hasOwnership = HasOwnership(context.User, context.Content);
|
||||
|
||||
IEnumerable<string> authorizedRoles;
|
||||
|
||||
var grantingPermissions = PermissionNames(context.Permission, Enumerable.Empty<string>()).Distinct().ToArray();
|
||||
|
||||
if (grantingPermissions.Any(grantingPermission => String.Equals(Core.Contents.Permissions.ViewContent.Name, grantingPermission, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
authorizedRoles = (hasOwnership ? part.ViewOwnContent : part.ViewContent).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
else if (grantingPermissions.Any(grantingPermission => String.Equals(Core.Contents.Permissions.EditContent.Name, grantingPermission, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
authorizedRoles = (hasOwnership ? part.EditOwnContent : part.EditContent).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
else if (grantingPermissions.Any(grantingPermission => String.Equals(Core.Contents.Permissions.PublishContent.Name, grantingPermission, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
authorizedRoles = (hasOwnership ? part.PublishOwnContent : part.PublishContent).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
else if (grantingPermissions.Any(grantingPermission => String.Equals(Core.Contents.Permissions.DeleteContent.Name, grantingPermission, StringComparison.OrdinalIgnoreCase)))
|
||||
{
|
||||
authorizedRoles = (hasOwnership ? part.DeleteOwnContent : part.DeleteContent).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// determine what set of roles should be examined by the access check
|
||||
IEnumerable<string> rolesToExamine;
|
||||
if (context.User == null) {
|
||||
rolesToExamine = AnonymousRole;
|
||||
}
|
||||
else if (context.User.Has<IUserRoles>()) {
|
||||
// the current user is not null, so get his roles and add "Authenticated" to it
|
||||
rolesToExamine = context.User.As<IUserRoles>().Roles;
|
||||
|
||||
// when it is a simulated anonymous user in the admin
|
||||
if (!rolesToExamine.Contains(AnonymousRole[0])) {
|
||||
rolesToExamine = rolesToExamine.Concat(AuthenticatedRole);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// the user is not null and has no specific role, then it's just "Authenticated"
|
||||
rolesToExamine = AuthenticatedRole;
|
||||
}
|
||||
|
||||
context.Granted = rolesToExamine.Any(x => authorizedRoles.Contains(x, StringComparer.OrdinalIgnoreCase));
|
||||
context.Adjusted = true;
|
||||
}
|
||||
|
||||
private static bool HasOwnership(IUser user, IContent content) {
|
||||
if (user == null || content == null)
|
||||
return false;
|
||||
|
||||
var common = content.As<ICommonPart>();
|
||||
if (common == null || common.Owner == null)
|
||||
return false;
|
||||
|
||||
return user.Id == common.Owner.Id;
|
||||
}
|
||||
|
||||
private static IEnumerable<string> PermissionNames(Permission permission, IEnumerable<string> stack)
|
||||
{
|
||||
// the given name is tested
|
||||
yield return permission.Name;
|
||||
|
||||
// iterate implied permissions to grant, it present
|
||||
if (permission.ImpliedBy != null && permission.ImpliedBy.Any())
|
||||
{
|
||||
foreach (var impliedBy in permission.ImpliedBy)
|
||||
{
|
||||
// avoid potential recursion
|
||||
if (stack.Contains(impliedBy.Name))
|
||||
continue;
|
||||
|
||||
// otherwise accumulate the implied permission names recursively
|
||||
foreach (var impliedName in PermissionNames(impliedBy, stack.Concat(new[] { permission.Name })))
|
||||
{
|
||||
yield return impliedName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
yield return StandardPermissions.SiteOwner.Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
using System;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.ContentManagement.Aspects;
|
||||
using Orchard.ContentManagement.MetaData.Models;
|
||||
using Orchard.Localization;
|
||||
using Orchard.Security;
|
||||
using Orchard.Security.Permissions;
|
||||
using System.Linq;
|
||||
using Orchard.ContentPermissions.Settings;
|
||||
using Orchard.ContentPermissions.Services;
|
||||
|
||||
namespace Orchard.ContentPermissions.Security {
|
||||
public class SecurableContentItemsAuthorizationEventHandler : IAuthorizationServiceEventHandler {
|
||||
private readonly IContentManager _contentManager;
|
||||
|
||||
public SecurableContentItemsAuthorizationEventHandler(IContentManager contentManager) {
|
||||
_contentManager = contentManager;
|
||||
}
|
||||
|
||||
public Localizer T { get; set; }
|
||||
|
||||
public void Checking(CheckAccessContext context) { }
|
||||
public void Complete(CheckAccessContext context) { }
|
||||
|
||||
public void Adjust(CheckAccessContext context) {
|
||||
if (!context.Granted &&
|
||||
context.Content.Is<ICommonPart>()) {
|
||||
|
||||
if (OwnerVariationExists(context.Permission) &&
|
||||
HasOwnership(context.User, context.Content)) {
|
||||
|
||||
context.Adjusted = true;
|
||||
context.Permission = GetOwnerVariation(context.Permission);
|
||||
}
|
||||
|
||||
var typeDefinition = context.Content.ContentItem.TypeDefinition;
|
||||
|
||||
if (typeDefinition.Settings.GetModel<ContentPermissionsTypeSettings>().SecurableContentItems) {
|
||||
// replace permission if a content item specific version exists
|
||||
var permission = GetContentTypeVariation(context.Permission);
|
||||
|
||||
if (permission != null) {
|
||||
context.Adjusted = true;
|
||||
context.Permission = DynamicPermissions.CreateItemPermission(permission, context.Content, T, _contentManager);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static bool HasOwnership(IUser user, IContent content) {
|
||||
if (user == null || content == null)
|
||||
return false;
|
||||
|
||||
var common = content.As<ICommonPart>();
|
||||
if (common == null || common.Owner == null)
|
||||
return false;
|
||||
|
||||
return user.Id == common.Owner.Id;
|
||||
}
|
||||
|
||||
private static bool OwnerVariationExists(Permission permission) {
|
||||
return GetOwnerVariation(permission) != null;
|
||||
}
|
||||
|
||||
private static Permission GetOwnerVariation(Permission permission) {
|
||||
if (permission.Name == Orchard.Core.Contents.Permissions.PublishContent.Name)
|
||||
return Orchard.Core.Contents.Permissions.PublishOwnContent;
|
||||
if (permission.Name == Orchard.Core.Contents.Permissions.EditContent.Name)
|
||||
return Orchard.Core.Contents.Permissions.EditOwnContent;
|
||||
if (permission.Name == Orchard.Core.Contents.Permissions.DeleteContent.Name)
|
||||
return Orchard.Core.Contents.Permissions.DeleteOwnContent;
|
||||
if (permission.Name == Orchard.Core.Contents.Permissions.ViewContent.Name)
|
||||
return Orchard.Core.Contents.Permissions.ViewOwnContent;
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Permission GetContentTypeVariation(Permission permission) {
|
||||
return DynamicPermissions.ConvertToDynamicPermission(permission);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using Orchard.ContentManagement.MetaData;
|
||||
using Orchard.ContentPermissions.Settings;
|
||||
using Orchard.Environment.Extensions.Models;
|
||||
using Orchard.Security.Permissions;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.Localization;
|
||||
|
||||
namespace Orchard.ContentPermissions.Services {
|
||||
public class DynamicPermissions : IPermissionProvider {
|
||||
private static readonly Permission PublishContent = new Permission { Description = "Publish or unpublish {0} for others", Name = "Publish_{0}", ImpliedBy = new[] { Orchard.Core.Contents.Permissions.PublishContent } };
|
||||
private static readonly Permission PublishOwnContent = new Permission { Description = "Publish or unpublish {0}", Name = "PublishOwn_{0}", ImpliedBy = new[] { PublishContent, Orchard.Core.Contents.Permissions.PublishOwnContent } };
|
||||
private static readonly Permission EditContent = new Permission { Description = "Edit {0} for others", Name = "Edit_{0}", ImpliedBy = new[] { PublishContent, Orchard.Core.Contents.Permissions.EditContent } };
|
||||
private static readonly Permission EditOwnContent = new Permission { Description = "Edit {0}", Name = "EditOwn_{0}", ImpliedBy = new[] { EditContent, PublishOwnContent, Orchard.Core.Contents.Permissions.EditOwnContent } };
|
||||
private static readonly Permission DeleteContent = new Permission { Description = "Delete {0} for others", Name = "Delete_{0}", ImpliedBy = new[] { Orchard.Core.Contents.Permissions.DeleteContent } };
|
||||
private static readonly Permission DeleteOwnContent = new Permission { Description = "Delete {0}", Name = "DeleteOwn_{0}", ImpliedBy = new[] { DeleteContent, Orchard.Core.Contents.Permissions.DeleteOwnContent } };
|
||||
private static readonly Permission ViewContent = new Permission { Description = "View {0} by others", Name = "View_{0}", ImpliedBy = new[] { EditContent, Orchard.Core.Contents.Permissions.ViewContent } };
|
||||
private static readonly Permission ViewOwnContent = new Permission { Description = "View own {0}", Name = "ViewOwn_{0}", ImpliedBy = new[] { ViewContent, Orchard.Core.Contents.Permissions.ViewOwnContent } };
|
||||
|
||||
public static readonly Dictionary<string, Permission> PermissionTemplates = new Dictionary<string, Permission> {
|
||||
{Orchard.Core.Contents.Permissions.PublishContent.Name, PublishContent},
|
||||
{Orchard.Core.Contents.Permissions.PublishOwnContent.Name, PublishOwnContent},
|
||||
{Orchard.Core.Contents.Permissions.EditContent.Name, EditContent},
|
||||
{Orchard.Core.Contents.Permissions.EditOwnContent.Name, EditOwnContent},
|
||||
{Orchard.Core.Contents.Permissions.DeleteContent.Name, DeleteContent},
|
||||
{Orchard.Core.Contents.Permissions.DeleteOwnContent.Name, DeleteOwnContent},
|
||||
{Orchard.Core.Contents.Permissions.ViewContent.Name, ViewContent},
|
||||
{Orchard.Core.Contents.Permissions.ViewOwnContent.Name, ViewOwnContent}
|
||||
};
|
||||
|
||||
private readonly IContentDefinitionManager _contentDefinitionManager;
|
||||
private readonly IContentManager _contentManager;
|
||||
|
||||
public virtual Feature Feature { get; set; }
|
||||
public Localizer T { get; set; }
|
||||
|
||||
public DynamicPermissions(IContentDefinitionManager contentDefinitionManager, IContentManager contentManager) {
|
||||
_contentDefinitionManager = contentDefinitionManager;
|
||||
_contentManager = contentManager;
|
||||
|
||||
T = NullLocalizer.Instance;
|
||||
}
|
||||
|
||||
public IEnumerable<Permission> GetPermissions() {
|
||||
|
||||
// manage rights only for Securable types
|
||||
var securableTypes = _contentDefinitionManager.ListTypeDefinitions()
|
||||
.Where(ctd => ctd.Settings.GetModel<ContentPermissionsTypeSettings>().SecurableContentItems)
|
||||
.ToList();
|
||||
|
||||
foreach (var typeDefinition in securableTypes) {
|
||||
foreach (var content in _contentManager.Query(typeDefinition.Name).List()) {
|
||||
foreach (var permissionTemplate in PermissionTemplates.Values) {
|
||||
yield return CreateItemPermission(permissionTemplate, content, T, _contentManager);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<PermissionStereotype> GetDefaultStereotypes() {
|
||||
return Enumerable.Empty<PermissionStereotype>();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Generates a permission dynamically for a content item
|
||||
/// </summary>
|
||||
public static Permission CreateItemPermission(Permission template, IContent content, Localizer T, IContentManager contentManager) {
|
||||
var identity = contentManager.GetItemMetadata(content).Identity.ToString();
|
||||
var displayText = contentManager.GetItemMetadata(content).DisplayText;
|
||||
var typeDefinition = content.ContentItem.TypeDefinition;
|
||||
|
||||
return new Permission {
|
||||
Name = String.Format(template.Name, identity),
|
||||
Description = String.Format(template.Description, typeDefinition.DisplayName),
|
||||
Category = T("{0} - {1}", typeDefinition.DisplayName, displayText).ToString(),
|
||||
ImpliedBy = (template.ImpliedBy ?? new Permission[0]).Select(t => CreateItemPermission(t, content, T, contentManager))
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a dynamic permission for a content type, based on a global content permission template
|
||||
/// </summary>
|
||||
public static Permission ConvertToDynamicPermission(Permission permission) {
|
||||
if (PermissionTemplates.ContainsKey(permission.Name)) {
|
||||
return PermissionTemplates[permission.Name];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace Orchard.ContentPermissions.Settings {
|
||||
public class ContentPermissionsTypeSettings {
|
||||
/// <summary>
|
||||
/// Used to determine if instances of this content type supports custom permissions
|
||||
/// </summary>
|
||||
public bool SecurableContentItems { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
using System.Collections.Generic;
|
||||
using Orchard.ContentManagement;
|
||||
using Orchard.ContentManagement.MetaData;
|
||||
using Orchard.ContentManagement.MetaData.Builders;
|
||||
using Orchard.ContentManagement.MetaData.Models;
|
||||
using Orchard.ContentManagement.ViewModels;
|
||||
using Orchard.ContentPermissions.ViewModels;
|
||||
|
||||
namespace Orchard.ContentPermissions.Settings {
|
||||
public class SecurableContentItemsEditorEvents : ContentDefinitionEditorEventsBase {
|
||||
|
||||
public override IEnumerable<TemplateViewModel> TypeEditor(ContentTypeDefinition definition) {
|
||||
var settings = definition.Settings.GetModel<ContentPermissionsTypeSettings>();
|
||||
var model = new SecurableContentItemsSettingsViewModel {
|
||||
SecurableContentItems = settings.SecurableContentItems,
|
||||
};
|
||||
|
||||
yield return DefinitionTemplate(model);
|
||||
}
|
||||
|
||||
public override IEnumerable<TemplateViewModel> TypeEditorUpdate(ContentTypeDefinitionBuilder builder, IUpdateModel updateModel) {
|
||||
var model = new SecurableContentItemsSettingsViewModel();
|
||||
updateModel.TryUpdateModel(model, "SecurableContentItemsSettingsViewModel", null, null);
|
||||
|
||||
builder.WithSetting("ContentPermissionsTypeSettings.SecurableContentItems", model.SecurableContentItems.ToString());
|
||||
|
||||
yield return DefinitionTemplate(model);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
namespace Orchard.ContentPermissions.ViewModels {
|
||||
public class SecurableContentItemsSettingsViewModel {
|
||||
public bool SecurableContentItems { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
@model Orchard.ContentPermissions.ViewModels.SecurableContentItemsSettingsViewModel
|
||||
|
||||
<fieldset>
|
||||
@Html.EditorFor(m => m.SecurableContentItems)
|
||||
<label for="@Html.FieldIdFor(m => m.SecurableContentItems)" class="forcheckbox">@T("Securable Content Items")</label>
|
||||
@Html.ValidationMessageFor(m => m.SecurableContentItems)
|
||||
<span class="hint">@T("Determines if an instance of this content type can have custom permissions.")</span>
|
||||
</fieldset>
|
||||
@@ -22,5 +22,15 @@ namespace Orchard.ContentTypes {
|
||||
return 1;
|
||||
}
|
||||
|
||||
public int UpgradeFrom1() {
|
||||
foreach (var typeDefinition in _contentDefinitionManager.ListTypeDefinitions()) {
|
||||
if (typeDefinition.Settings.ContainsKey("ContentTypeSettings.Creatable") && Convert.ToBoolean(typeDefinition.Settings["ContentTypeSettings.Creatable"], CultureInfo.InvariantCulture)) {
|
||||
typeDefinition.Settings["ContentTypeSettings.Securable"] = "True";
|
||||
_contentDefinitionManager.StoreTypeDefinition(typeDefinition);
|
||||
}
|
||||
}
|
||||
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -87,7 +87,7 @@ namespace Orchard.ContentTypes.Services {
|
||||
|
||||
var contentTypeDefinition = new ContentTypeDefinition(name, displayName);
|
||||
_contentDefinitionManager.StoreTypeDefinition(contentTypeDefinition);
|
||||
_contentDefinitionManager.AlterTypeDefinition(name, cfg => cfg.Creatable().Draftable().Listable());
|
||||
_contentDefinitionManager.AlterTypeDefinition(name, cfg => cfg.Creatable().Draftable().Listable().Securable());
|
||||
_contentDefinitionEventHandlers.ContentTypeCreated(new ContentTypeCreatedContext { ContentTypeDefinition = contentTypeDefinition});
|
||||
|
||||
return contentTypeDefinition;
|
||||
|
||||
@@ -18,6 +18,7 @@ namespace Orchard.ContentTypes.Settings {
|
||||
Creatable = settings.Creatable,
|
||||
Listable = settings.Listable,
|
||||
Draftable = settings.Draftable,
|
||||
Securable = settings.Securable,
|
||||
};
|
||||
|
||||
if(definition.Settings.ContainsKey("Stereotype")) {
|
||||
@@ -34,6 +35,7 @@ namespace Orchard.ContentTypes.Settings {
|
||||
builder.Creatable(model.Creatable);
|
||||
builder.Listable(model.Listable);
|
||||
builder.Draftable(model.Draftable);
|
||||
builder.Securable(model.Securable);
|
||||
builder.WithSetting("Stereotype", model.Stereotype);
|
||||
|
||||
yield return DefinitionTemplate(model);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
public bool Creatable { get; set; }
|
||||
public bool Listable { get; set; }
|
||||
public bool Draftable { get; set; }
|
||||
public bool Securable { get; set; }
|
||||
public string Stereotype { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,13 @@
|
||||
<span class="hint">@T("Determines if this content type supports draft versions.")</span>
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
@Html.EditorFor(m => m.Securable)
|
||||
<label for="@Html.FieldIdFor(m => m.Securable)" class="forcheckbox">@T("Securable")</label>
|
||||
@Html.ValidationMessageFor(m => m.Securable)
|
||||
<span class="hint">@T("Determines if this content type can have custom permissions.")</span>
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
<label for="@Html.FieldIdFor(m => m.Stereotype)">@T("Stereotype")</label>
|
||||
@Html.TextBoxFor(m => m.Stereotype, new { @class = "text medium"})
|
||||
|
||||
@@ -17,7 +17,9 @@ namespace Orchard.Pages {
|
||||
.WithSetting("AutorouteSettings.PatternDefinitions", "[{\"Name\":\"Title\",\"Pattern\":\"{Content.Slug}\",\"Description\":\"my-page\"}]")
|
||||
.WithSetting("AutorouteSettings.DefaultPatternIndex", "0"))
|
||||
.WithPart("BodyPart")
|
||||
.Creatable());
|
||||
.Creatable()
|
||||
.Listable()
|
||||
.Securable());
|
||||
|
||||
return 3;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user