diff --git a/src/OrchardCore.Modules/OrchardCore.ContentFields/Assets/js/vue-multiselect-wrapper.js b/src/OrchardCore.Modules/OrchardCore.ContentFields/Assets/js/vue-multiselect-wrapper.js index 829f21f50b4..5c5a45968d3 100644 --- a/src/OrchardCore.Modules/OrchardCore.ContentFields/Assets/js/vue-multiselect-wrapper.js +++ b/src/OrchardCore.Modules/OrchardCore.ContentFields/Assets/js/vue-multiselect-wrapper.js @@ -17,6 +17,8 @@ function initVueMultiselect(element) { if (element) { var elementId = element.id; var selectedItems = JSON.parse(element.dataset.selectedItems || "[]"); + var editUrl = element.dataset.editUrl; + var viewUrl = element.dataset.viewUrl; var searchUrl = element.dataset.searchUrl; var multiple = JSON.parse(element.dataset.multiple); @@ -99,6 +101,10 @@ function initVueMultiselect(element) { // a single content item and we've just selected that one item. this.searchBoxContainer.css("display", multiple ? "block" : "none"); }, + url: function(item) { + var url = item.isEditable ? editUrl : viewUrl; + return url.replace('contentItemId', item.id); + }, remove: function (item) { this.arrayOfItems.splice(this.arrayOfItems.indexOf(item), 1); diff --git a/src/OrchardCore.Modules/OrchardCore.ContentFields/Controllers/ContentPickerAdminController.cs b/src/OrchardCore.Modules/OrchardCore.ContentFields/Controllers/ContentPickerAdminController.cs index 6b83767828a..e46628f75fd 100644 --- a/src/OrchardCore.Modules/OrchardCore.ContentFields/Controllers/ContentPickerAdminController.cs +++ b/src/OrchardCore.Modules/OrchardCore.ContentFields/Controllers/ContentPickerAdminController.cs @@ -2,6 +2,8 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using OrchardCore.Admin; using OrchardCore.ContentFields.Settings; @@ -9,6 +11,7 @@ using OrchardCore.ContentManagement; using OrchardCore.ContentManagement.Metadata; using OrchardCore.ContentManagement.Metadata.Models; +using OrchardCore.Contents; namespace OrchardCore.ContentFields.Controllers { @@ -16,15 +19,23 @@ namespace OrchardCore.ContentFields.Controllers public class ContentPickerAdminController : Controller { private readonly IContentDefinitionManager _contentDefinitionManager; + private readonly IContentManager _contentManager; private readonly IEnumerable _resultProviders; + private readonly IAuthorizationService _authorizationService; + private readonly IHttpContextAccessor _httpContextAccessor; public ContentPickerAdminController( IContentDefinitionManager contentDefinitionManager, - IEnumerable resultProviders - ) + IContentManager contentManager, + IEnumerable resultProviders, + IAuthorizationService authorizationService, + IHttpContextAccessor httpContextAccessor) { _contentDefinitionManager = contentDefinitionManager; + _contentManager = contentManager; _resultProviders = resultProviders; + _authorizationService = authorizationService; + _httpContextAccessor = httpContextAccessor; } [Admin("ContentFields/SearchContentItems", "ContentPicker")] @@ -76,7 +87,23 @@ public async Task SearchContentItems(string part, string field, s PartFieldDefinition = partFieldDefinition, }); - return new ObjectResult(results.Select(r => new VueMultiselectItemViewModel() { Id = r.ContentItemId, DisplayText = r.DisplayText, HasPublished = r.HasPublished })); + var contentItems = await _contentManager + .GetAsync(results.Select(r => r.ContentItemId)); + + var selectedItems = new List(); + foreach (var contentItem in contentItems) + { + selectedItems.Add(new VueMultiselectItemViewModel() + { + Id = contentItem.ContentItemId, + DisplayText = contentItem.ToString(), + HasPublished = contentItem.IsPublished(), + IsViewable = await _authorizationService.AuthorizeAsync(_httpContextAccessor.HttpContext?.User, + CommonPermissions.EditContent, contentItem) + }); + } + + return new ObjectResult(selectedItems); } } } diff --git a/src/OrchardCore.Modules/OrchardCore.ContentFields/Drivers/ContentPickerFieldDisplayDriver.cs b/src/OrchardCore.Modules/OrchardCore.ContentFields/Drivers/ContentPickerFieldDisplayDriver.cs index fa03ef66b58..5dbb80e836d 100644 --- a/src/OrchardCore.Modules/OrchardCore.ContentFields/Drivers/ContentPickerFieldDisplayDriver.cs +++ b/src/OrchardCore.Modules/OrchardCore.ContentFields/Drivers/ContentPickerFieldDisplayDriver.cs @@ -3,6 +3,8 @@ using System.Threading.Tasks; using Fluid; using Fluid.Values; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Localization; using OrchardCore.ContentFields.Fields; using OrchardCore.ContentFields.Settings; @@ -12,6 +14,7 @@ using OrchardCore.ContentManagement.Display.ContentDisplay; using OrchardCore.ContentManagement.Display.Models; using OrchardCore.ContentManagement.Metadata.Models; +using OrchardCore.Contents; using OrchardCore.DisplayManagement.ModelBinding; using OrchardCore.DisplayManagement.Views; using OrchardCore.Liquid; @@ -25,15 +28,21 @@ public class ContentPickerFieldDisplayDriver : ContentFieldDisplayDriver localizer, - ILiquidTemplateManager templateManager) + ILiquidTemplateManager templateManager, + IAuthorizationService authorizationService, + IHttpContextAccessor httpContextAccessor) { _contentManager = contentManager; S = localizer; _templateManager = templateManager; + _authorizationService = authorizationService; + _httpContextAccessor = httpContextAccessor; } public override IDisplayResult Display(ContentPickerField field, BuildFieldDisplayContext fieldDisplayContext) @@ -79,9 +88,12 @@ public override IDisplayResult Edit(ContentPickerField field, BuildFieldEditorCo Id = contentItemId, DisplayText = await _templateManager.RenderStringAsync(settings.TitlePattern, NullEncoder.Default, contentItem, new Dictionary() { [nameof(ContentItem)] = new ObjectValue(contentItem) }), - HasPublished = await _contentManager.HasPublishedVersionAsync(contentItem) + HasPublished = await _contentManager.HasPublishedVersionAsync(contentItem), + IsEditable = await _authorizationService.AuthorizeAsync(_httpContextAccessor.HttpContext!.User, CommonPermissions.EditContent, contentItem), + IsViewable = await _authorizationService.AuthorizeAsync(_httpContextAccessor.HttpContext!.User, CommonPermissions.ViewContent, contentItem) }); } + } }); } diff --git a/src/OrchardCore.Modules/OrchardCore.ContentFields/ViewModels/VueMultiselectItemViewModel.cs b/src/OrchardCore.Modules/OrchardCore.ContentFields/ViewModels/VueMultiselectItemViewModel.cs index d896ddc1e9d..0b87f027d56 100644 --- a/src/OrchardCore.Modules/OrchardCore.ContentFields/ViewModels/VueMultiselectItemViewModel.cs +++ b/src/OrchardCore.Modules/OrchardCore.ContentFields/ViewModels/VueMultiselectItemViewModel.cs @@ -5,5 +5,8 @@ public class VueMultiselectItemViewModel public string Id { get; set; } public string DisplayText { get; set; } public bool HasPublished { get; set; } + public bool IsViewable { get; set; } + public bool IsEditable { get; set; } + public bool IsClickable => IsEditable || IsViewable; } } diff --git a/src/OrchardCore.Modules/OrchardCore.ContentFields/Views/ContentPickerField.Edit.cshtml b/src/OrchardCore.Modules/OrchardCore.ContentFields/Views/ContentPickerField.Edit.cshtml index c5cfae40470..712431b2f8b 100644 --- a/src/OrchardCore.Modules/OrchardCore.ContentFields/Views/ContentPickerField.Edit.cshtml +++ b/src/OrchardCore.Modules/OrchardCore.ContentFields/Views/ContentPickerField.Edit.cshtml @@ -7,6 +7,8 @@ var selectedItems = JConvert.SerializeObject(Model.SelectedItems, JOptions.CamelCase); var partName = Model.PartFieldDefinition.PartDefinition.Name; var fieldName = Model.PartFieldDefinition.Name; + var editUrl = Url.RouteUrl(new { area = "OrchardCore.Contents", controller = "Admin", action = "Edit", contentItemId = "contentItemId", returnUrl = FullRequestPath }); + var viewUrl = Url.RouteUrl(new { area = "OrchardCore.Contents", controller = "Admin", action = "Display", contentItemId = "contentItemId" }); var searchUrl = Url.RouteUrl(new { area = "OrchardCore.ContentFields", controller = "ContentPickerAdmin", action = "SearchContentItems", part = partName, field = fieldName }); var vueElementId = $"ContentPicker_{partName}_{fieldName}_{Guid.NewGuid().ToString("n")}"; var multiple = settings.Multiple.ToString().ToLowerInvariant(); @@ -18,15 +20,21 @@
-
+
  • -
    {{ item.displayText }} (@T["Not published"])
    - +
    + + {{ item.displayText }} (@T["Not published"]) + + + {{ item.displayText }} (@T["Not published"]) + +
    diff --git a/src/OrchardCore.Modules/OrchardCore.ContentFields/wwwroot/Scripts/vue-multiselect-wrapper.js b/src/OrchardCore.Modules/OrchardCore.ContentFields/wwwroot/Scripts/vue-multiselect-wrapper.js index cbcb39be679..cccdaf2fd5a 100644 --- a/src/OrchardCore.Modules/OrchardCore.ContentFields/wwwroot/Scripts/vue-multiselect-wrapper.js +++ b/src/OrchardCore.Modules/OrchardCore.ContentFields/wwwroot/Scripts/vue-multiselect-wrapper.js @@ -24,6 +24,8 @@ function initVueMultiselect(element) { if (element) { var elementId = element.id; var selectedItems = JSON.parse(element.dataset.selectedItems || "[]"); + var editUrl = element.dataset.editUrl; + var viewUrl = element.dataset.viewUrl; var searchUrl = element.dataset.searchUrl; var multiple = JSON.parse(element.dataset.multiple); var debouncedSearch = debounce(function (vm, query) { @@ -107,6 +109,10 @@ function initVueMultiselect(element) { // a single content item and we've just selected that one item. this.searchBoxContainer.css("display", multiple ? "block" : "none"); }, + url: function url(item) { + var url = item.isEditable ? editUrl : viewUrl; + return url.replace('contentItemId', item.id); + }, remove: function remove(item) { this.arrayOfItems.splice(this.arrayOfItems.indexOf(item), 1); diff --git a/src/OrchardCore.Modules/OrchardCore.ContentFields/wwwroot/Scripts/vue-multiselect-wrapper.min.js b/src/OrchardCore.Modules/OrchardCore.ContentFields/wwwroot/Scripts/vue-multiselect-wrapper.min.js index 685de5be821..ab5ecce2c99 100644 --- a/src/OrchardCore.Modules/OrchardCore.ContentFields/wwwroot/Scripts/vue-multiselect-wrapper.min.js +++ b/src/OrchardCore.Modules/OrchardCore.ContentFields/wwwroot/Scripts/vue-multiselect-wrapper.min.js @@ -1 +1 @@ -function debounce(e,t,n){var i;return function(){var s=this,a=arguments,o=n&&!i;clearTimeout(i),i=setTimeout((function(){i=null,n||e.apply(s,a)}),t),o&&e.apply(s,a)}}function initVueMultiselect(e){if(e){var t=e.id,n=JSON.parse(e.dataset.selectedItems||"[]"),s=e.dataset.searchUrl,a=JSON.parse(e.dataset.multiple),o=debounce((function(e,t){e.isLoading=!0;var n=s;t&&(n+="&query="+t),fetch(n).then((function(t){t.json().then((function(t){e.options=t,e.isLoading=!1}))}))}),250),r=Vue.component("vue-multiselect",window.VueMultiselect.default),c=new Vue({el:"#"+t,components:{"vue-multiselect":r},data:{value:null,arrayOfItems:n,options:[]},computed:{selectedIds:function(){return this.arrayOfItems.map((function(e){return e.id})).join(",")},isDisabled:function(){return this.arrayOfItems.length>0&&!a}},watch:{selectedIds:function(){setTimeout((function(){$(document).trigger("contentpreview:render")}),100)}},created:function(){this.asyncFind()},mounted:function(){this.searchBoxContainer=$(this.$el).children().last(),this.searchBoxContainer.css("display",a||0===this.arrayOfItems.length?"block":"none")},methods:{asyncFind:function(e){o(this,e)},onSelect:function(e,t){var n=this;for(i=0;i0&&!o}},watch:{selectedIds:function(){setTimeout((function(){$(document).trigger("contentpreview:render")}),100)}},created:function(){this.asyncFind()},mounted:function(){this.searchBoxContainer=$(this.$el).children().last(),this.searchBoxContainer.css("display",o||0===this.arrayOfItems.length?"block":"none")},methods:{asyncFind:function(e){c(this,e)},onSelect:function(e,t){var n=this;for(i=0;i