Merge branch '1.10.x' into dev

# Conflicts:
#	src/Orchard.Web/Core/Contents/Controllers/AdminController.cs
#	src/Orchard.Web/Modules/Orchard.MediaLibrary/Scripts/media-library.js
This commit is contained in:
Benedek Farkas
2019-08-13 17:38:13 +02:00
33 changed files with 587 additions and 264 deletions

View File

@@ -30,7 +30,11 @@ namespace Orchard.Core.Common {
.Column<DateTime>("PublishedUtc")
.Column<DateTime>("ModifiedUtc")
.Column<int>("Container_id")
);
).AlterTable(nameof(CommonPartRecord), table => {
table.CreateIndex($"IDX_{nameof(CommonPartRecord)}_{nameof(CommonPartRecord.CreatedUtc)}", nameof(CommonPartRecord.CreatedUtc));
table.CreateIndex($"IDX_{nameof(CommonPartRecord)}_{nameof(CommonPartRecord.ModifiedUtc)}", nameof(CommonPartRecord.ModifiedUtc));
table.CreateIndex($"IDX_{nameof(CommonPartRecord)}_{nameof(CommonPartRecord.PublishedUtc)}", nameof(CommonPartRecord.PublishedUtc));
});
SchemaBuilder.CreateTable("CommonPartVersionRecord",
table => table
@@ -39,7 +43,11 @@ namespace Orchard.Core.Common {
.Column<DateTime>("PublishedUtc")
.Column<DateTime>("ModifiedUtc")
.Column<string>("ModifiedBy")
);
).AlterTable(nameof(CommonPartVersionRecord), table => {
table.CreateIndex($"IDX_{nameof(CommonPartVersionRecord)}_{nameof(CommonPartVersionRecord.CreatedUtc)}", nameof(CommonPartVersionRecord.CreatedUtc));
table.CreateIndex($"IDX_{nameof(CommonPartVersionRecord)}_{nameof(CommonPartVersionRecord.ModifiedUtc)}", nameof(CommonPartVersionRecord.ModifiedUtc));
table.CreateIndex($"IDX_{nameof(CommonPartVersionRecord)}_{nameof(CommonPartVersionRecord.PublishedUtc)}", nameof(CommonPartVersionRecord.PublishedUtc));
});
SchemaBuilder.CreateTable("IdentityPartRecord",
table => table
@@ -59,7 +67,7 @@ namespace Orchard.Core.Common {
.Attachable()
.WithDescription("Automatically generates a unique identity for the content item, which is required in import/export scenarios where one content item references another."));
return 5;
return 6;
}
public int UpdateFrom1() {
@@ -112,5 +120,21 @@ namespace Orchard.Core.Common {
SchemaBuilder.AlterTable("CommonPartVersionRecord", table => table.AddColumn<string>("ModifiedBy", command => command.Nullable()));
return 5;
}
public int UpdateFrom5() {
SchemaBuilder.AlterTable(nameof(CommonPartRecord), table => {
table.CreateIndex($"IDX_{nameof(CommonPartRecord)}_{nameof(CommonPartRecord.CreatedUtc)}", nameof(CommonPartRecord.CreatedUtc));
table.CreateIndex($"IDX_{nameof(CommonPartRecord)}_{nameof(CommonPartRecord.ModifiedUtc)}", nameof(CommonPartRecord.ModifiedUtc));
table.CreateIndex($"IDX_{nameof(CommonPartRecord)}_{nameof(CommonPartRecord.PublishedUtc)}", nameof(CommonPartRecord.PublishedUtc));
});
SchemaBuilder.AlterTable(nameof(CommonPartVersionRecord), table => {
table.CreateIndex($"IDX_{nameof(CommonPartVersionRecord)}_{nameof(CommonPartVersionRecord.CreatedUtc)}", nameof(CommonPartVersionRecord.CreatedUtc));
table.CreateIndex($"IDX_{nameof(CommonPartVersionRecord)}_{nameof(CommonPartVersionRecord.ModifiedUtc)}", nameof(CommonPartVersionRecord.ModifiedUtc));
table.CreateIndex($"IDX_{nameof(CommonPartVersionRecord)}_{nameof(CommonPartVersionRecord.PublishedUtc)}", nameof(CommonPartVersionRecord.PublishedUtc));
});
return 6;
}
}
}

View File

@@ -14,20 +14,19 @@ using Orchard.Core.Containers.Models;
using Orchard.Core.Contents.Settings;
using Orchard.Core.Contents.ViewModels;
using Orchard.Data;
using Orchard.DisplayManagement;
using Orchard.Localization;
using Orchard.Localization.Services;
using Orchard.Logging;
using Orchard.Mvc.Extensions;
using Orchard.Mvc.Html;
using Orchard.Settings;
using Orchard.UI.Navigation;
using Orchard.UI.Notify;
using Orchard.Settings;
using Orchard.Utility.Extensions;
using Orchard.Localization.Services;
namespace Orchard.Core.Contents.Controllers {
[ValidateInput(false)]
public class AdminController : Controller, IUpdateModel {
public class AdminController : ContentControllerBase, IUpdateModel {
private readonly IContentManager _contentManager;
private readonly IContentDefinitionManager _contentDefinitionManager;
private readonly ITransactionManager _transactionManager;
@@ -37,24 +36,21 @@ namespace Orchard.Core.Contents.Controllers {
public AdminController(
IOrchardServices orchardServices,
IContentManager contentManager,
IContentDefinitionManager contentDefinitionManager,
ITransactionManager transactionManager,
ISiteService siteService,
IShapeFactory shapeFactory,
ICultureManager cultureManager,
ICultureFilter cultureFilter) {
ICultureFilter cultureFilter) : base(orchardServices.ContentManager) {
Services = orchardServices;
_contentManager = contentManager;
_contentManager = orchardServices.ContentManager;
_transactionManager = orchardServices.TransactionManager;
_contentDefinitionManager = contentDefinitionManager;
_transactionManager = transactionManager;
_siteService = siteService;
_cultureManager = cultureManager;
_cultureFilter = cultureFilter;
T = NullLocalizer.Instance;
Logger = NullLogger.Instance;
Shape = shapeFactory;
Shape = orchardServices.New;
}
dynamic Shape { get; set; }
@@ -248,6 +244,11 @@ namespace Orchard.Core.Contents.Controllers {
var contentItem = _contentManager.New(id);
var customRouteRedirection = GetCustomContentItemRouteRedirection(contentItem, ContentItemRoute.Create);
if (customRouteRedirection != null) {
return customRouteRedirection;
}
if (!Services.Authorizer.Authorize(Permissions.CreateContent, contentItem, T("Cannot create content")))
return new HttpUnauthorizedResult();
@@ -323,6 +324,11 @@ namespace Orchard.Core.Contents.Controllers {
public ActionResult Edit(int id) {
var contentItem = _contentManager.Get(id, VersionOptions.Latest);
var customRouteRedirection = GetCustomContentItemRouteRedirection(contentItem, ContentItemRoute.Editor);
if (customRouteRedirection != null) {
return customRouteRedirection;
}
if (contentItem == null)
return HttpNotFound();
@@ -416,6 +422,10 @@ namespace Orchard.Core.Contents.Controllers {
// pass a dummy content to the authorization check to check for "own" variations
var dummyContent = _contentManager.New(originalContentItem.ContentType);
if (!Services.Authorizer.Authorize(Permissions.EditContent, dummyContent, T("You do not have permission to edit (or create) content.")))
return new HttpUnauthorizedResult();
if (!Services.Authorizer.Authorize(Permissions.EditContent, dummyContent, T("You do not have permission to edit (or create) content.")))
return new HttpUnauthorizedResult();

View File

@@ -0,0 +1,52 @@
using System;
using System.Web.Mvc;
using System.Web.Routing;
using Orchard.ContentManagement;
using Orchard.Mvc.Extensions;
namespace Orchard.Core.Contents.Controllers {
public abstract class ContentControllerBase : Controller {
private readonly IContentManager _contentManager;
public ContentControllerBase(IContentManager contentManager) {
_contentManager = contentManager;
}
public RedirectToRouteResult GetCustomContentItemRouteRedirection(IContent content, ContentItemRoute contentItemRoute) {
if (content == null) return null;
var itemMetadata = _contentManager.GetItemMetadata(content);
var currentRoute = RouteData.Values;
bool isCustomRoute(RouteValueDictionary routeValues) =>
!currentRoute.ToRouteString().Equals(routeValues.ToRouteString(), StringComparison.InvariantCultureIgnoreCase);
switch (contentItemRoute) {
case ContentItemRoute.Admin:
if (isCustomRoute(itemMetadata.AdminRouteValues))
return RedirectToRoute(itemMetadata.AdminRouteValues);
break;
case ContentItemRoute.Editor:
if (isCustomRoute(itemMetadata.EditorRouteValues))
return RedirectToRoute(itemMetadata.EditorRouteValues);
break;
case ContentItemRoute.Create:
if (isCustomRoute(itemMetadata.CreateRouteValues))
return RedirectToRoute(itemMetadata.CreateRouteValues);
break;
case ContentItemRoute.Display:
if (isCustomRoute(itemMetadata.DisplayRouteValues))
return RedirectToRoute(itemMetadata.DisplayRouteValues);
break;
}
return null;
}
}
}

View File

@@ -1,28 +1,25 @@
using System.Web.Mvc;
using Orchard.ContentManagement;
using Orchard.DisplayManagement;
using Orchard.Localization;
using Orchard.Mvc;
using Orchard.Themes;
namespace Orchard.Core.Contents.Controllers {
[Themed]
public class ItemController : Controller {
public class ItemController : ContentControllerBase {
private readonly IContentManager _contentManager;
private readonly IHttpContextAccessor _hca;
public ItemController(IContentManager contentManager,
IShapeFactory shapeFactory,
IOrchardServices services,
IHttpContextAccessor hca) {
_contentManager = contentManager;
public ItemController(
IOrchardServices orchardServices,
IHttpContextAccessor hca) : base(orchardServices.ContentManager) {
_contentManager = orchardServices.ContentManager;
_hca = hca;
Shape = shapeFactory;
Services = services;
Services = orchardServices;
T = NullLocalizer.Instance;
}
dynamic Shape { get; set; }
public IOrchardServices Services { get; private set; }
public Localizer T { get; set; }
@@ -36,6 +33,11 @@ namespace Orchard.Core.Contents.Controllers {
var contentItem = _contentManager.Get(id.Value, VersionOptions.Published);
var customRouteRedirection = GetCustomContentItemRouteRedirection(contentItem, ContentItemRoute.Display);
if (customRouteRedirection != null) {
return customRouteRedirection;
}
if (contentItem == null)
return HttpNotFound();

View File

@@ -1,5 +1,26 @@
@{ Layout.Title = T("Create New Content").ToString(); }
@using Orchard;
@using Orchard.ContentManagement;
@using Orchard.Core.Contents;
@{
IOrchardServices _orchardServices;
WorkContext.TryResolve<IOrchardServices>(out _orchardServices);
Layout.Title = T("Create New Content");
}
@foreach (var type in Model.ContentTypes) {
<p>@Html.ActionLink((string)type.DisplayName, "Create", new { Area = "Contents", Id = (string)type.Name, ContainerId = Model.ContainerId, ReturnUrl = Request.QueryString["ReturnUrl"] })</p>
var content = _orchardServices.ContentManager.New(type.Name);
if (Authorizer.Authorize(Permissions.CreateContent, content)) {
ContentItemMetadata metadata = _orchardServices.ContentManager.GetItemMetadata(content);
RouteValueDictionary createRouteValues = metadata.CreateRouteValues;
createRouteValues.Add("ContainerId", Model.ContainerId);
createRouteValues.Add("ReturnUrl", Request.QueryString["ReturnUrl"]);
var url = Url.RouteUrl(createRouteValues);
<p><a href="@url">@type.DisplayName</a></p>
}
}

View File

@@ -1,8 +1,13 @@
@using Orchard.Core.Contents;
@using Orchard;
@using Orchard.ContentManagement;
@using Orchard.Core.Contents;
@using Orchard.Core.Contents.ViewModels;
@using Orchard.Security;
@using Orchard.Security.Permissions;
@{
IOrchardServices _orchardServices;
WorkContext.TryResolve<IOrchardServices>(out _orchardServices);
var typeDisplayName = Model.TypeDisplayName;
var pageTitle = T("Manage Content");
var createLinkText = T("Create New Content");
@@ -28,7 +33,17 @@
}
@if (showCreateContentButton) {
<div class="manage">
@Html.ActionLink(createLinkText.Text, "Create", new { Area = "Contents", Id = (string)Model.Options.SelectedFilter }, new { @class = "button primaryAction" })
@{
if (!String.IsNullOrWhiteSpace((string)Model.Options.SelectedFilter)) {
var content = _orchardServices.ContentManager.New(Model.Options.SelectedFilter);
ContentItemMetadata metadata = _orchardServices.ContentManager.GetItemMetadata(content);
var url = Url.RouteUrl(metadata.CreateRouteValues);
<a class="button primaryAction" href="@url">@createLinkText.Text</a>
} else {
@Html.ActionLink(createLinkText.Text, "Create", new { Area = "Contents", Id = (string)Model.Options.SelectedFilter }, new { @class = "button primaryAction" });
}
}
</div>
}
@using (Html.BeginFormAntiForgeryPost()) {

View File

@@ -153,6 +153,7 @@
<Compile Include="Containers\ViewModels\ContainerViewModel.cs" />
<Compile Include="Containers\ViewModels\ContainerTypePartSettingsViewModel.cs" />
<Compile Include="Containers\ViewModels\ContainerWidgetViewModel.cs" />
<Compile Include="Contents\Controllers\ContentControllerBase.cs" />
<Compile Include="Contents\ControlWrapper.cs" />
<Compile Include="Contents\Security\AuthorizationEventHandler.cs" />
<Compile Include="Common\Services\BbcodeFilter.cs" />

View File

@@ -17,8 +17,7 @@ namespace Orchard.Autoroute {
}
public int Create() {
SchemaBuilder.CreateTable("AutoroutePartRecord",
table => table
SchemaBuilder.CreateTable("AutoroutePartRecord", table => table
.ContentPartVersionRecord()
.Column<string>("CustomPattern", c => c.WithLength(2048))
.Column<bool>("UseCustomPattern", c => c.WithDefault(false))
@@ -30,75 +29,75 @@ namespace Orchard.Autoroute {
.WithDescription("Adds advanced url configuration options to your content type to completely customize the url pattern for a content item."));
SchemaBuilder.AlterTable("AutoroutePartRecord", table => table
.CreateIndex("IDX_AutoroutePartRecord_DisplayAlias", "DisplayAlias")
);
.CreateIndex("IDX_AutoroutePartRecord_DisplayAlias", "DisplayAlias"));
return 4;
CreateCulturePatterns();
return 5;
}
public int UpdateFrom1() {
ContentDefinitionManager.AlterPartDefinition("AutoroutePart", part => part
.WithDescription("Adds advanced url configuration options to your content type to completely customize the url pattern for a content item."));
return 2;
}
public int UpdateFrom2() {
SchemaBuilder.AlterTable("AutoroutePartRecord", table => table
.CreateIndex("IDX_AutoroutePartRecord_DisplayAlias", "DisplayAlias")
);
.CreateIndex("IDX_AutoroutePartRecord_DisplayAlias", "DisplayAlias"));
return 3;
}
public int UpdateFrom3() {
SchemaBuilder.AlterTable("AutoroutePartRecord", table => table
.AddColumn<bool>("UseCulturePattern", c => c.WithDefault(false))
);
.AddColumn<bool>("UseCulturePattern", c => c.WithDefault(false)));
return 4;
}
public int UpdateFrom4() {
// Adding some culture neutral patterns if they don't exist
var autoroutePartDefinitions = ContentDefinitionManager.ListTypeDefinitions()
.Where(t => t.Parts.Any(p => p.PartDefinition.Name.Equals(typeof(AutoroutePart).Name)))
.Select(s => new { contentTypeName = s.Name, autoroutePart = s.Parts.First(x => x.PartDefinition.Name == "AutoroutePart") });
foreach (var partDefinition in autoroutePartDefinitions) {
var settingsDictionary = partDefinition.autoroutePart.Settings;
var settings = settingsDictionary.GetModel<AutorouteSettings>();
if (!settings.Patterns.Any(x => String.IsNullOrWhiteSpace(x.Culture))) {
string siteCulture = _cultureManager.GetSiteCulture();
List<string> newPatterns = new List<string>();
if (settings.Patterns.Any(x => String.Equals(x.Culture, siteCulture, StringComparison.OrdinalIgnoreCase))) {
var siteCulturePatterns = settings.Patterns.Where(x => String.Equals(x.Culture, siteCulture, StringComparison.OrdinalIgnoreCase)).ToList();
foreach (RoutePattern pattern in siteCulturePatterns) {
newPatterns.Add(String.Format("{{\"Name\":\"{0}\",\"Pattern\":\"{1}\",\"Description\":\"{2}\"}}", pattern.Name, pattern.Pattern, pattern.Description));
}
}
else {
newPatterns.Add(String.Format("{{\"Name\":\"{0}\",\"Pattern\":\"{1}\",\"Description\":\"{2}\"}}", "Title", "{Content.Slug}", "my-title"));
}
if (settingsDictionary.ContainsKey("AutorouteSettings.PatternDefinitions")) {
string oldPatterns = settingsDictionary["AutorouteSettings.PatternDefinitions"];
if (oldPatterns.StartsWith("[") && oldPatterns.EndsWith("]"))
newPatterns.Add(oldPatterns.Substring(1, oldPatterns.Length - 2));
}
ContentDefinitionManager.AlterTypeDefinition(partDefinition.contentTypeName, cfg => cfg
.WithPart("AutoroutePart", builder => builder
.WithSetting("AutorouteSettings.PatternDefinitions", "[" + String.Join(",", newPatterns) + "]")
));
}
}
CreateCulturePatterns();
return 5;
}
private void CreateCulturePatterns() {
var autoroutePartDefinitions = ContentDefinitionManager.ListTypeDefinitions()
.Where(type => type.Parts.Any(p => p.PartDefinition.Name == nameof(AutoroutePart)))
.Select(type => new { ContentTypeName = type.Name, AutoroutePart = type.Parts.First(x => x.PartDefinition.Name == nameof(AutoroutePart)) });
foreach (var partDefinition in autoroutePartDefinitions) {
var settingsDictionary = partDefinition.AutoroutePart.Settings;
var settings = settingsDictionary.GetModel<AutorouteSettings>();
if (!settings.Patterns.Any(pattern => string.IsNullOrWhiteSpace(pattern.Culture))) {
var siteCulture = _cultureManager.GetSiteCulture();
List<string> newPatterns = new List<string>();
var siteCulturePatterns = settings.Patterns
.Where(pattern => string.Equals(pattern.Culture, siteCulture, StringComparison.OrdinalIgnoreCase)).ToList();
if (siteCulturePatterns.Any()) {
foreach (RoutePattern pattern in siteCulturePatterns) {
newPatterns.Add($"{{\"Name\":\"{pattern.Name}\",\"Pattern\":\"{pattern.Pattern}\",\"Description\":\"{pattern.Description}\"}}");
}
}
else {
newPatterns.Add("{{\"Name\":\"Title\",\"Pattern\":\"{Content.Slug}\",\"Description\":\"my-title\"}}");
}
if (settingsDictionary.TryGetValue("AutorouteSettings.PatternDefinitions", out var oldPatterns) &&
oldPatterns.StartsWith("[") && oldPatterns.EndsWith("]")) {
newPatterns.Add(oldPatterns.Substring(1, oldPatterns.Length - 2));
}
ContentDefinitionManager.AlterTypeDefinition(partDefinition.ContentTypeName, type => type
.WithPart(nameof(AutoroutePart), builder => builder
.WithSetting("AutorouteSettings.PatternDefinitions", "[" + string.Join(",", newPatterns) + "]")));
}
}
}
}
}

View File

@@ -1,4 +1,5 @@
using System;
using System.Linq;
using System.Reflection;
using System.Web.Mvc;
using Orchard.Blogs.Extensions;
@@ -98,6 +99,18 @@ namespace Orchard.Blogs.Controllers {
return Redirect(Url.BlogPostEdit(blogPost));
}
public ActionResult CreateWithoutBlog() {
var blogs = _blogService.Get().ToArray();
if (blogs.Count() == 0) {
Services.Notifier.Warning(T("To create a BlogPost you need to create a blog first. You have been redirected to the Blog creation page."));
return RedirectToAction("Create", "BlogAdmin", new { area = "Orchard.Blogs" });
} else {
Services.Notifier.Warning(T("To create a BlogPost you need to choose a blog first. You have been redirected to the Blog selection page."));
return RedirectToAction("List", "BlogAdmin", new { area = "Orchard.Blogs" });
}
}
//todo: the content shape template has extra bits that the core contents module does not (remove draft functionality)
//todo: - move this extra functionality there or somewhere else that's appropriate?
public ActionResult Edit(int blogId, int postId) {

View File

@@ -5,13 +5,18 @@ using Orchard.Blogs.Services;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Handlers;
using Orchard.Core.Common.Models;
using Orchard.Security;
namespace Orchard.Blogs.Handlers {
public class BlogPostPartHandler : ContentHandler {
private readonly IAuthorizationService _authorizationService;
private readonly IBlogService _blogService;
private readonly IWorkContextAccessor _workContextAccessor;
public BlogPostPartHandler(IBlogService blogService, IBlogPostService blogPostService, RequestContext requestContext) {
public BlogPostPartHandler(IAuthorizationService authorizationService, IBlogService blogService, IBlogPostService blogPostService, RequestContext requestContext, IWorkContextAccessor workContextAccessor) {
_authorizationService = authorizationService;
_blogService = blogService;
_workContextAccessor = workContextAccessor;
OnGetDisplayShape<BlogPostPart>(SetModelProperties);
OnGetEditorShape<BlogPostPart>(SetModelProperties);
@@ -45,8 +50,29 @@ namespace Orchard.Blogs.Handlers {
protected override void GetItemMetadata(GetContentItemMetadataContext context) {
var blogPost = context.ContentItem.As<BlogPostPart>();
if (blogPost == null) {
return;
}
int blogId = 0;
// BlogPart can be null if this is a new Blog Post item.
if (blogPost == null || blogPost.BlogPart == null) {
if (blogPost.BlogPart == null) {
var blogs = _blogService.Get().Where(x => _authorizationService.TryCheckAccess(Permissions.MetaListBlogs, _workContextAccessor.GetContext().CurrentUser, x)).ToArray();
if (blogs.Count() == 1) {
var singleBlog = blogs.ElementAt(0);
if (singleBlog != null) blogId = singleBlog.Id;
}
} else {
blogId = blogPost.BlogPart.Id;
}
if (blogId == 0) {
context.Metadata.CreateRouteValues = new RouteValueDictionary {
{"Area", "Orchard.Blogs"},
{"Controller", "BlogPostAdmin"},
{"Action", "CreateWithoutBlog"}
};
return;
}
@@ -54,21 +80,21 @@ namespace Orchard.Blogs.Handlers {
{"Area", "Orchard.Blogs"},
{"Controller", "BlogPostAdmin"},
{"Action", "Create"},
{"blogId", blogPost.BlogPart.Id}
{"blogId", blogId}
};
context.Metadata.EditorRouteValues = new RouteValueDictionary {
{"Area", "Orchard.Blogs"},
{"Controller", "BlogPostAdmin"},
{"Action", "Edit"},
{"postId", context.ContentItem.Id},
{"blogId", blogPost.BlogPart.Id}
{"blogId", blogId}
};
context.Metadata.RemoveRouteValues = new RouteValueDictionary {
{"Area", "Orchard.Blogs"},
{"Controller", "BlogPostAdmin"},
{"Action", "Delete"},
{"postId", context.ContentItem.Id},
{"blogId", blogPost.BlogPart.Id}
{"blogId", blogId}
};
}
}

View File

@@ -88,6 +88,20 @@ namespace Orchard.Blogs {
},
new MvcRouteHandler())
},
new RouteDescriptor {
Route = new Route(
"Admin/Blogs/Posts/CreateWithoutBlog",
new RouteValueDictionary {
{"area", "Orchard.Blogs"},
{"controller", "BlogPostAdmin"},
{"action", "CreateWithoutBlog"}
},
new RouteValueDictionary (),
new RouteValueDictionary {
{"area", "Orchard.Blogs"}
},
new MvcRouteHandler())
},
new RouteDescriptor {
Route = new Route(
"Admin/Blogs/{blogId}/Posts/{postId}/Edit",

View File

@@ -160,6 +160,7 @@ namespace Orchard.ContentPicker.Controllers {
RouteData.Values["Options.SelectedFilter"] = model.Options.SelectedFilter;
RouteData.Values["Options.OrderBy"] = model.Options.OrderBy.ToString();
RouteData.Values["Options.ContentsStatus"] = model.Options.ContentsStatus.ToString();
RouteData.Values["Options.SelectedCulture"] = model.Options.SelectedCulture;
return new ShapeResult(this, Services.New.ContentPicker().Tab(tab));
}

View File

@@ -1,12 +1,18 @@
jQuery(function ($) {
Initialize = function () {
$('.content-picker-itemCheck').each(function () {
var related = $(this).siblings('.content-picker-item').children('.related');
$('.button.addSelected').on('click', function () {
var selectedItems = $('.content-picker-itemCheck:checked');
var itemsToAdd = new Array();
$.each(selectedItems, function (index, item) {
var related = $(item).siblings('.content-picker-item').children('.related');
if (window.sessionStorage.getItem(related.data("id")) != null) {
$(this).prop('checked', true);
}
});
$('.content-picker-itemCheck').change(function () {
var related = $(this).siblings('.content-picker-item').children('.related');
if (this.checked) {
var data = {
id: related.data("id"),
displayText: related.data("display-text"),
@@ -16,13 +22,27 @@
displayLink: related.data("display-link"),
published: related.data("published")
};
return itemsToAdd.push(data);
window.sessionStorage.setItem(related.data("id"), JSON.stringify(data));
} else {
window.sessionStorage.removeItem(related.data("id"));
}
});
$('.button.addSelected').on('click', function () {
var itemsToAdd = new Array();
for (var i = 0; i < sessionStorage.length; i++) {
var data = window.sessionStorage.getItem(sessionStorage.key(i));
itemsToAdd.push(JSON.parse(data));
}
window.sessionStorage.clear();
window.opener.jQuery[query("callback")](itemsToAdd);
window.close();
});
$('.content-picker-SelectAll').on('click', function () {
$('.content-picker-itemCheck').prop('checked', $(this).prop("checked"));
$('.content-picker-itemCheck').change();
});
};

View File

@@ -50,7 +50,7 @@
<tr>
<td>&nbsp;</td>
<td>
<span data-id="@contentItem.Id" data-fieldid="@idsFieldId" class="content-picker-item">@Html.ItemAdminLink(contentItem) @if (!contentItem.HasPublished()){<text> - </text>@T("Not Published")}</span>
<span data-id="@contentItem.Id" data-fieldid="@idsFieldId" class="content-picker-item">@Html.ItemAdminLink(null, contentItem, new { ReturnUrl = @Request.Url.ToString()}) @if (!contentItem.HasPublished()){<text> - </text>@T("Not Published")}</span>
</td>
<td>
<span data-id="@contentItem.Id" class="content-picker-remove button grey">@T("Remove")</span>

View File

@@ -5,7 +5,9 @@ using Orchard.ContentManagement;
using Orchard.ContentManagement.Handlers;
using Orchard.DisplayManagement;
using Orchard.DisplayManagement.Descriptors;
using Orchard.Environment.Configuration;
using Orchard.FileSystems.VirtualPath;
using Orchard.Mvc.Routes;
using Orchard.UI.Zones;
namespace Orchard.Layouts.Services {
@@ -30,9 +32,9 @@ namespace Orchard.Layouts.Services {
_requestContext = requestContext;
_virtualPathProvider = virtualPathProvider;
_workContextAccessor = workContextAccessor;
}
public abstract UrlPrefix TenantUrlPrefix { get; }
public abstract string DefaultStereotype { get; }
public BuildDisplayContext BuildDisplayContext(IContent content, string displayType, string groupId) {
@@ -145,7 +147,12 @@ namespace Orchard.Layouts.Services {
/// Gets the current app-relative path, i.e. ~/my-blog/foo.
/// </summary>
private string GetPath() {
return VirtualPathUtility.AppendTrailingSlash(_virtualPathProvider.ToAppRelative(_requestContext.HttpContext.Request.Path));
var appRelativePath = _virtualPathProvider.ToAppRelative(_requestContext.HttpContext.Request.Path);
// If the tenant has a prefix, we strip the tenant prefix away.
if (TenantUrlPrefix != null)
appRelativePath = TenantUrlPrefix.RemoveLeadingSegments(appRelativePath);
return VirtualPathUtility.AppendTrailingSlash(appRelativePath);
}
}
}

View File

@@ -6,24 +6,39 @@ using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers;
using Orchard.DisplayManagement;
using Orchard.DisplayManagement.Descriptors;
using Orchard.Environment.Configuration;
using Orchard.FileSystems.VirtualPath;
using Orchard.Mvc.Routes;
namespace Orchard.Layouts.Services {
public class ContentFieldDisplay : ContentDisplayBase, IContentFieldDisplay {
private readonly IEnumerable<IContentFieldDriver> _contentFieldDrivers;
private readonly ShellSettings _shellSettings;
public ContentFieldDisplay(
IShapeFactory shapeFactory,
Lazy<IShapeTableLocator> shapeTableLocator,
RequestContext requestContext,
IVirtualPathProvider virtualPathProvider,
IWorkContextAccessor workContextAccessor,
ShellSettings shellSettings,
IEnumerable<IContentFieldDriver> contentFieldDrivers)
: base(shapeFactory, shapeTableLocator, requestContext, virtualPathProvider, workContextAccessor) {
_shellSettings = shellSettings;
_contentFieldDrivers = contentFieldDrivers;
}
public override UrlPrefix TenantUrlPrefix {
get {
if (!string.IsNullOrEmpty(_shellSettings.RequestUrlPrefix)) {
return new UrlPrefix(_shellSettings.RequestUrlPrefix);
}
else {
return null;
}
}
}
public override string DefaultStereotype {
get { return "ContentField"; }
}

View File

@@ -6,11 +6,15 @@ using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers;
using Orchard.DisplayManagement;
using Orchard.DisplayManagement.Descriptors;
using Orchard.Environment.Configuration;
using Orchard.FileSystems.VirtualPath;
using Orchard.Mvc.Routes;
namespace Orchard.Layouts.Services {
public class ContentPartDisplay : ContentDisplayBase, IContentPartDisplay {
private readonly IEnumerable<IContentPartDriver> _contentPartDrivers;
private readonly ShellSettings _shellSettings;
public ContentPartDisplay(
IShapeFactory shapeFactory,
@@ -18,11 +22,22 @@ namespace Orchard.Layouts.Services {
RequestContext requestContext,
IVirtualPathProvider virtualPathProvider,
IWorkContextAccessor workContextAccessor,
ShellSettings shellSettings,
IEnumerable<IContentPartDriver> contentPartDrivers)
: base(shapeFactory, shapeTableLocator, requestContext, virtualPathProvider, workContextAccessor) {
_shellSettings = shellSettings;
_contentPartDrivers = contentPartDrivers;
}
public override UrlPrefix TenantUrlPrefix {
get {
if (!string.IsNullOrEmpty(_shellSettings.RequestUrlPrefix)) {
return new UrlPrefix(_shellSettings.RequestUrlPrefix);
}
else {
return null;
}
}
}
public override string DefaultStereotype {
get { return "ContentPart"; }

View File

@@ -1,4 +1,6 @@
@{
@using System.Globalization
@{
var currentCulture = WorkContext.CurrentCulture;
var supportedCultures = (IList<string>)Model.SupportedCultures;
}
@@ -6,15 +8,20 @@
<div id="culture-selection">
<ul>
@foreach (var supportedCulture in supportedCultures) {
var culture = CultureInfo.GetCultureInfo(supportedCulture);
if (culture is object)
{
var url = Url.Action("ChangeCulture", "AdminCultureSelector", new { area = "Orchard.Localization", culture = supportedCulture, returnUrl = Html.ViewContext.HttpContext.Request.RawUrl });
<li>
@if (supportedCulture.Equals(currentCulture)) {
<a href="@url">@T("{0} (current)", supportedCulture)</a>
<a href="@url">@T("{0} (current)", culture.DisplayName)</a>
} else {
<a href="@url">@supportedCulture</a>
<a href="@url">@culture.DisplayName</a>
}
</li>
}
}
</ul>
</div>

View File

@@ -3,6 +3,7 @@
@using Orchard.ContentManagement
@using Orchard.ContentManagement.Aspects
@using Orchard.Localization.Services
@{
var localizableAspects = Enumerable.Empty<ILocalizableAspect>();
var homePage = WorkContext.Resolve<IHomeAliasService>().GetHomePage();
@@ -12,26 +13,24 @@
localizableAspects = localizationService.GetLocalizations(homePage).Concat(new[] { homePage.As<ILocalizableAspect>() });
}
}
@if (localizableAspects.Any()) {
<div>
<ul>
@foreach (var localization in localizableAspects) {
if (localization.Culture == null) {
continue;
}
@foreach (var localization in localizableAspects.Where(localization => !string.IsNullOrEmpty(localization.Culture))) {
var culture = CultureInfo.GetCultureInfo(localization.Culture);
if (culture is object) {
<li>
@if (localization.Culture.Equals(WorkContext.CurrentCulture, StringComparison.InvariantCultureIgnoreCase)) {
<a href="@Url.ItemDisplayUrl(localization)">@T("{0} (current)", culture.DisplayName)</a>
}
else {
<a href="@Url.ItemDisplayUrl(localization)">@T("{0}", culture.DisplayName)</a>
<a href="@Url.ItemDisplayUrl(localization)">@culture.DisplayName</a>
}
</li>
}
}
</ul>
</div>
}

View File

@@ -47,7 +47,7 @@ $(function () {
folderPath: folderPath,
mediaItemIds: ids,
__RequestVerificationToken: settings.antiForgeryToken
},
}
}).done(function (result) {
if (result) {
if (viewModel.displayed()) {
@@ -67,7 +67,7 @@ $(function () {
});
}
});
};
}
var listWidth = $('#media-library-main-list').width();
var listHeight = $('#media-library-main-list').height();
@@ -118,7 +118,7 @@ $(function () {
return css;
});
self.mediaInfos = ko.computed(function () {
self.publicationStatus = ko.computed(function () {
var pubStatus = self.data.published ? "" : draftText;
var localization = (self.data.localization != "" ? "(" + self.data.localization + ")" : "");
return pubStatus + " " + localization;
@@ -142,6 +142,11 @@ $(function () {
self.focus = ko.observable();
self.results = ko.observableArray();
self.displayed = ko.observable();
self.isEveryItemSelected = ko.computed({
read: function () {
return self.selection().length === self.results().length;
}
});
self.mediaItemsCount = 0;
self.orderMedia = ko.observableArray(['created']);
self.mediaType = ko.observableArray([]);
@@ -150,7 +155,7 @@ $(function () {
self.mediaFoldersRequestCount = ko.observable(0);
self.mediaFoldersPendingRequest = ko.computed({
read: function () {
return (self.mediaFoldersRequestCount() > 0);
return self.mediaFoldersRequestCount() > 0;
},
write: function (value) {
if (value === true) {
@@ -164,7 +169,7 @@ $(function () {
self.mediaPendingRequest = ko.observable(false);
self.pendingRequest = ko.computed({
read: function () {
return (self.mediaFoldersPendingRequest() || self.mediaPendingRequest());
return self.mediaFoldersPendingRequest() || self.mediaPendingRequest();
},
write: function (value) {
self.mediaPendingRequest(value);
@@ -189,7 +194,6 @@ $(function () {
self.pendingRequest(true);
var url = self.loadMediaItemsUrl(folderPath, self.results().length, count, self.orderMedia(), self.mediaType());
console.log(url);
$.ajax({
type: "GET",
@@ -216,6 +220,8 @@ $(function () {
}
}
}
self.updateSelectAllText();
}).fail(function (data) {
console.error(data);
}).always(function () {
@@ -223,6 +229,29 @@ $(function () {
});
};
self.updateSelectAllText = function () {
var element = $("#select-all-button");
element.html(self.isEveryItemSelected() ? element.data("select-none-text") : element.data("select-all-text"));
};
self.updateAllSelection = function () {
if (self.isEveryItemSelected()) {
self.clearSelection();
}
else {
self.selectAll();
}
self.updateSelectAllText();
};
self.selectAll = function () {
self.results().forEach(function (item) {
viewModel.toggleSelect(item, true);
});
};
self.clearSelection = function () {
this.focus(null);
// unselect previous elements
@@ -339,7 +368,8 @@ $(function () {
viewModel.selection().forEach(function (item) { ids.push(item.data.id); });
var actionurl = url + '?folderPath=' + encodeURIComponent(folder) + "&replaceId=" + encodeURIComponent(ids[0]);
window.location = actionurl;
}
};
var selectFolderOrRecent = function () {
if (self.displayed()) {
self.selectFolder(self.displayed());
@@ -515,13 +545,17 @@ $(function () {
}
parent.$.colorbox.selectedData = selectedData;
parent.$.colorbox.close();
};
}
};
$("#media-library-main-selection-select > .button-select").on('click', function () {
pickAndClose();
});
$("#select-all-button").on('click', function () {
viewModel.updateAllSelection();
});
$("#media-library-main-list").on('dblclick', function () {
pickAndClose();
});
@@ -531,7 +565,6 @@ $(function () {
parent.$.colorbox.selectedData = null;
parent.$.colorbox.close();
}
;
});
$("#media-library-main-list").on("mouseover", ".media-thumbnail", function () {
@@ -632,4 +665,4 @@ $(function () {
});
})(window.mediaLibrarySettings);
})
});

View File

@@ -95,7 +95,8 @@ namespace Orchard.MediaLibrary.Services {
if (!String.IsNullOrEmpty(folderPath)) {
if (recursive) {
query = query.Join<MediaPartRecord>().Where(m => m.FolderPath.StartsWith(folderPath));
var subfolderSearch = folderPath.EndsWith(Path.DirectorySeparatorChar.ToString()) ? folderPath : folderPath + Path.DirectorySeparatorChar;
query = query.Join<MediaPartRecord>().Where(m => (m.FolderPath == folderPath || m.FolderPath.StartsWith(subfolderSearch)));
}
else {
query = query.Join<MediaPartRecord>().Where(m => m.FolderPath == folderPath);

View File

@@ -22,6 +22,11 @@
<a href="#" data-bind="attr: { href: '@HttpUtility.JavaScriptStringEncode(Url.Action("Create", "Folder", new { area = "Orchard.MediaLibrary"}))?folderPath=' + encodeURIComponent(displayed() ? displayed() : '') }" class="button" id="button-create-folder">@T("Create Folder")</a>
@Display(Model.CustomActionsShapes)
<button class="button" id="select-all-button"
data-select-all-text="@T("Select All")" data-select-none-text="@T("Select None")"
data-bind="visible: results().length > 0">
@T("Select All")
</button>
</div>
<div id="media-library-main">
<div id="media-library-main-navigation">
@@ -43,7 +48,7 @@
</div>
<div class="media-library-main-list-overlay">
<p class="title" data-bind="text: data.title, attr: { title: data.title }"></p>
<p class="publication-status" data-bind="text: mediaInfos"></p>
<p class="publication-status" data-bind="text: publicationStatus"></p>
</div>
</li>
</ul>

View File

@@ -47,7 +47,7 @@
@Display(BuildDisplay(contentItem, "Thumbnail"))
<div class="overlay">
<h3>@Html.ItemDisplayText(contentItem)</h3>
<p class="publication-status" data-bind="text: mediaInfos">
<p class="publication-status" data-bind="text: publicationStatus">
@(contentItem.IsPublished() ? "" : T("Draft").Text)
@{
var localizationPart = contentItem.As<LocalizationPart>();

View File

@@ -54,7 +54,9 @@ namespace Orchard.Packaging.Services {
var packageVersion = String.IsNullOrEmpty(version) ? null : new Version(version);
var package = packageRepository.FindPackage(packageId, packageVersion);
if (package == null) {
throw new ArgumentException(T("The specified package could not be found, id:{0} version:{1}", packageId, String.IsNullOrEmpty(version) ? T("No version").Text : version).Text);
var message = T("The specified package could not be found: ID: {0}, version: {1}.",
packageId, string.IsNullOrEmpty(version) ? T("No version").Text : version);
throw new OrchardException(message);
}
return InstallPackage(package, packageRepository, location, applicationPath);
@@ -181,7 +183,8 @@ namespace Orchard.Packaging.Services {
if (packageId.StartsWith(PackagingSourceManager.GetExtensionPrefix(DefaultExtensionTypes.Theme))) {
extensionFullPath = _virtualPathProvider.MapPath("~/Themes/" + packageId.Substring(PackagingSourceManager.GetExtensionPrefix(DefaultExtensionTypes.Theme).Length));
} else if (packageId.StartsWith(PackagingSourceManager.GetExtensionPrefix(DefaultExtensionTypes.Module))) {
}
else if (packageId.StartsWith(PackagingSourceManager.GetExtensionPrefix(DefaultExtensionTypes.Module))) {
extensionFullPath = _virtualPathProvider.MapPath("~/Modules/" + packageId.Substring(PackagingSourceManager.GetExtensionPrefix(DefaultExtensionTypes.Module).Length));
}

View File

@@ -1,9 +1,7 @@
using System;
using System.IO;
using System.Linq;
using NuGet;
using Orchard.Environment.Extensions;
using Orchard.Environment.Extensions.Folders;
using Orchard.Environment.Extensions.Models;
using Orchard.Environment.Features;
using Orchard.Environment.State;

View File

@@ -49,6 +49,10 @@ namespace Orchard.Projections.FilterEditors.Forms {
f._Operator.Add(new SelectListItem { Value = Convert.ToString(StringOperator.Ends), Text = T("Ends with").Text });
f._Operator.Add(new SelectListItem { Value = Convert.ToString(StringOperator.NotEnds), Text = T("Does not end with").Text });
f._Operator.Add(new SelectListItem { Value = Convert.ToString(StringOperator.NotContains), Text = T("Does not contain").Text });
f._Operator.Add(new SelectListItem {
Value = Convert.ToString(StringOperator.ContainsAnyIfProvided),
Text = T("Contains any word (if any is provided)").Text
});
return f;
};
@@ -88,6 +92,14 @@ namespace Orchard.Projections.FilterEditors.Forms {
return y => y.Not(x => x.Like(property, Convert.ToString(value), HqlMatchMode.End));
case StringOperator.NotContains:
return y => y.Not(x => x.Like(property, Convert.ToString(value), HqlMatchMode.Anywhere));
case StringOperator.ContainsAnyIfProvided:
if (string.IsNullOrWhiteSpace((string)value))
return x => x.IsNotEmpty("Id"); // basically, return every possible ContentItem
var values3 = Convert.ToString(value)
.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
var predicates3 = values3.Skip(1)
.Select<string, Action<IHqlExpressionFactory>>(x => y => y.Like(property, x, HqlMatchMode.Anywhere)).ToArray();
return x => x.Disjunction(y => y.Like(property, values3[0], HqlMatchMode.Anywhere), predicates3);
default:
throw new ArgumentOutOfRangeException();
}
@@ -118,6 +130,11 @@ namespace Orchard.Projections.FilterEditors.Forms {
return T("{0} does not end with '{1}'", fieldName, value);
case StringOperator.NotContains:
return T("{0} does not contain '{1}'", fieldName, value);
case StringOperator.ContainsAnyIfProvided:
return T("{0} contains any of '{1}' (or '{1}' is empty)",
fieldName,
new LocalizedString(string.Join("', '",
value.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries))));
default:
throw new ArgumentOutOfRangeException();
}
@@ -135,5 +152,6 @@ namespace Orchard.Projections.FilterEditors.Forms {
Ends,
NotEnds,
NotContains,
ContainsAnyIfProvided
}
}

View File

@@ -1,4 +1,5 @@
@using System.Globalization
@{
var currentCulture = WorkContext.CurrentCulture;
var supportedCultures = (IList<string>)Model.SupportedCultures;
@@ -8,14 +9,17 @@
<select>
@foreach (var supportedCulture in supportedCultures) {
var cultureInfo = CultureInfo.GetCultureInfo(supportedCulture);
var url = Url.Action("ChangeCulture", "AdminCultureSelector", new { area = "Orchard.Localization", culture = supportedCulture, returnUrl = Html.ViewContext.HttpContext.Request.RawUrl });
<option @if (supportedCulture.Equals(currentCulture)) { <text> selected="selected" </text> } value="@url">
@cultureInfo.DisplayName&#x200E;
</option>
if (cultureInfo is object) {
var url = Url.Action("ChangeCulture", "AdminCultureSelector", new { area = "Orchard.Localization", culture = supportedCulture, returnUrl = Html.ViewContext.HttpContext.Request.RawUrl });
var selected = supportedCulture.Equals(currentCulture) ? "selected" : "";
<option @selected value="@url">@cultureInfo.DisplayName</option>
}
}
</select>
</div>
@using (Script.Foot()) {
<script type="text/javascript">
//<![CDATA[

View File

@@ -24,4 +24,12 @@ namespace Orchard.ContentManagement {
public readonly IList<GroupInfo> DisplayGroupInfo = new List<GroupInfo>();
public readonly IList<GroupInfo> EditorGroupInfo = new List<GroupInfo>();
}
public enum ContentItemRoute {
Admin,
Create,
Editor,
Remove,
Display
}
}

View File

@@ -5,8 +5,10 @@ using System.Web.Routing;
using Orchard.ContentManagement.Handlers;
using Orchard.DisplayManagement;
using Orchard.DisplayManagement.Descriptors;
using Orchard.Environment.Configuration;
using Orchard.FileSystems.VirtualPath;
using Orchard.Logging;
using Orchard.Mvc.Routes;
using Orchard.UI.Zones;
namespace Orchard.ContentManagement {
@@ -18,6 +20,8 @@ namespace Orchard.ContentManagement {
private readonly RequestContext _requestContext;
private readonly IVirtualPathProvider _virtualPathProvider;
private readonly IWorkContextAccessor _workContextAccessor;
private readonly ShellSettings _shellSettings;
private readonly UrlPrefix _urlPrefix;
public DefaultContentDisplay(
Lazy<IEnumerable<IContentHandler>> handlers,
@@ -25,15 +29,19 @@ namespace Orchard.ContentManagement {
Lazy<IShapeTableLocator> shapeTableLocator,
RequestContext requestContext,
IVirtualPathProvider virtualPathProvider,
IWorkContextAccessor workContextAccessor) {
IWorkContextAccessor workContextAccessor,
ShellSettings shellSettings) {
_handlers = handlers;
_shapeFactory = shapeFactory;
_shapeTableLocator = shapeTableLocator;
_requestContext = requestContext;
_virtualPathProvider = virtualPathProvider;
_workContextAccessor = workContextAccessor;
_shellSettings = shellSettings;
if (!string.IsNullOrEmpty(_shellSettings.RequestUrlPrefix))
_urlPrefix = new UrlPrefix(_shellSettings.RequestUrlPrefix);
Logger = NullLogger.Instance;
}
public ILogger Logger { get; set; }
@@ -158,7 +166,12 @@ namespace Orchard.ContentManagement {
/// Gets the current app-relative path, i.e. ~/my-blog/foo.
/// </summary>
private string GetPath() {
return VirtualPathUtility.AppendTrailingSlash(_virtualPathProvider.ToAppRelative(_requestContext.HttpContext.Request.Path));
var appRelativePath = _virtualPathProvider.ToAppRelative(_requestContext.HttpContext.Request.Path);
// If the tenant has a prefix, we strip the tenant prefix away.
if (_urlPrefix != null)
appRelativePath = _urlPrefix.RemoveLeadingSegments(appRelativePath);
return VirtualPathUtility.AppendTrailingSlash(appRelativePath);
}
}
}

View File

@@ -1,29 +0,0 @@
using System.Web.Routing;
using System.Web.Mvc;
namespace Orchard.Mvc.Extensions {
public static class RouteExtension{
public static string GetAreaName(this RouteBase route){
var routeWithArea = route as IRouteWithArea;
if (routeWithArea != null) {
return routeWithArea.Area;
}
var castRoute = route as Route;
if (castRoute != null && castRoute.DataTokens != null) {
return castRoute.DataTokens["area"] as string;
}
return null;
}
public static string GetAreaName(this RouteData routeData){
object area;
if (routeData.DataTokens.TryGetValue("area", out area)) {
return area as string;
}
return GetAreaName(routeData.Route);
}
}
}

View File

@@ -0,0 +1,25 @@
using System.Web.Mvc;
using System.Web.Routing;
namespace Orchard.Mvc.Extensions {
public static class RouteExtensions {
public static string GetAreaName(this RouteBase route) {
if (route is IRouteWithArea routeWithArea) {
return routeWithArea.Area;
}
if (route is Route castRoute && castRoute.DataTokens != null) {
return castRoute.DataTokens["area"] as string;
}
return null;
}
public static string GetAreaName(this RouteData routeData) =>
routeData.DataTokens.TryGetValue("area", out object area) ?
area as string : GetAreaName(routeData.Route);
public static string ToRouteString(this RouteValueDictionary route) =>
string.Join("/", route["Area"], route["Controller"], route["Action"]);
}
}

View File

@@ -401,7 +401,7 @@
<Compile Include="Mvc\DataAnnotations\LocalizedRangeAttribute.cs" />
<Compile Include="Mvc\DataAnnotations\LocalizedModelValidatorProvider.cs" />
<Compile Include="Mvc\DataAnnotations\LocalizedRequiredAttribute.cs" />
<Compile Include="Mvc\Extensions\RouteExtension.cs" />
<Compile Include="Mvc\Extensions\RouteExtensions.cs" />
<Compile Include="Mvc\Extensions\HttpContextBaseExtensions.cs" />
<Compile Include="Mvc\FormValueRequiredAttribute.cs" />
<Compile Include="Mvc\HttpContextAccessor.cs" />

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
namespace Orchard.Security.Permissions {
public class Permission {
@@ -7,10 +8,12 @@ namespace Orchard.Security.Permissions {
public string Category { get; set; }
public IEnumerable<Permission> ImpliedBy { get; set; }
public bool RequiresOwnership { get; set; }
public static Permission Named(string name) {
return new Permission { Name = name };
}
[Obsolete("This property is not used anywhere, so it shouldn't be referenced.")]
public bool RequiresOwnership { get; set; }
}
}