Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Some improvements around building common shapes #15652

Merged
merged 7 commits into from
Apr 4, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace OrchardCore.Contents.Drivers
{
public class ContentOptionsDisplayDriver : DisplayDriver<ContentOptionsViewModel>
{
// Maintain the Options prefix for compatability with binding.
// Maintain the Options prefix for compatibility with binding.
protected override void BuildPrefix(ContentOptionsViewModel model, string htmlFieldPrefix)
{
Prefix = "Options";
Expand Down Expand Up @@ -36,7 +36,6 @@ public override IDisplayResult Edit(ContentOptionsViewModel model)
Initialize<ContentOptionsViewModel>("ContentsAdminListSummary", m => BuildContentOptionsViewModel(m, model)).Location("Summary:10"),
Initialize<ContentOptionsViewModel>("ContentsAdminListFilters", m => BuildContentOptionsViewModel(m, model)).Location("Actions:10.1"),
Initialize<ContentOptionsViewModel>("ContentsAdminList_Fields_BulkActions", m => BuildContentOptionsViewModel(m, model)).Location("Actions:10.1")

);
}

Expand All @@ -45,7 +44,7 @@ public override Task<IDisplayResult> UpdateAsync(ContentOptionsViewModel model,
// Map the incoming values from a form post to the filter result.
model.FilterResult.MapFrom(model);

return Task.FromResult<IDisplayResult>(Edit(model));
return Task.FromResult(Edit(model));
}

private static void BuildContentOptionsViewModel(ContentOptionsViewModel m, ContentOptionsViewModel model)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,21 @@ public override async Task<IDisplayResult> DisplayAsync(ContentItem contentItem,
// We add custom alternates. This could be done generically to all shapes coming from ContentDisplayDriver but right now it's
// only necessary on this shape. Otherwise c.f. ContentPartDisplayDriver

var context = _httpContextAccessor.HttpContext;
var results = new List<IDisplayResult>();
var contentItemViewModel = new ContentItemViewModel(contentItem);

var results = new List<IDisplayResult>()
{
Shape("ContentsTags_SummaryAdmin", contentItemViewModel).Location("SummaryAdmin", "Tags:10"),
Shape("ContentsMeta_SummaryAdmin", contentItemViewModel).Location("SummaryAdmin", "Meta:20"),
};

var contentTypeDefinition = await _contentDefinitionManager.GetTypeDefinitionAsync(contentItem.ContentType);
var contentsMetadataShape = Shape("ContentsMetadata",
new ContentItemViewModel(contentItem))
.Location("Detail", "Content:before");

if (contentTypeDefinition != null)
{
var contentsMetadataShape = Shape("ContentsMetadata", contentItemViewModel)
.Location("Detail", "Content:before");

contentsMetadataShape.Displaying(ctx =>
{
var hasStereotype = contentTypeDefinition.TryGetStereotype(out var stereotype);
Expand All @@ -65,60 +71,47 @@ public override async Task<IDisplayResult> DisplayAsync(ContentItem contentItem,
}
});

var user = _httpContextAccessor.HttpContext.User;

results.Add(contentsMetadataShape);
results.Add(Shape("ContentsButtonEdit_SummaryAdmin", new ContentItemViewModel(contentItem)).Location("SummaryAdmin", "Actions:10"));
results.Add(Shape("ContentsButtonActions_SummaryAdmin", new ContentItemViewModel(contentItem)).Location("SummaryAdmin", "ActionsMenu:10")
.RenderWhen(async () =>
{
var hasPublishPermission = await _authorizationService.AuthorizeAsync(context.User, CommonPermissions.PublishContent, contentItem);
var hasDeletePermission = await _authorizationService.AuthorizeAsync(context.User, CommonPermissions.DeleteContent, contentItem);
var hasPreviewPermission = await _authorizationService.AuthorizeAsync(context.User, CommonPermissions.PreviewContent, contentItem);
var hasClonePermission = await _authorizationService.AuthorizeAsync(context.User, CommonPermissions.CloneContent, contentItem);
var hasPublishPermission = await _authorizationService.AuthorizeAsync(user, CommonPermissions.PublishContent, contentItem);
var hasDeletePermission = await _authorizationService.AuthorizeAsync(user, CommonPermissions.DeleteContent, contentItem);
var hasPreviewPermission = await _authorizationService.AuthorizeAsync(user, CommonPermissions.PreviewContent, contentItem);
var hasClonePermission = await _authorizationService.AuthorizeAsync(user, CommonPermissions.CloneContent, contentItem);

if (hasPublishPermission || hasDeletePermission || hasPreviewPermission || hasClonePermission)
{
return true;
}

return false;
return hasPublishPermission || hasDeletePermission || hasPreviewPermission || hasClonePermission;
})
);
}

results.Add(Shape("ContentsTags_SummaryAdmin", new ContentItemViewModel(contentItem)).Location("SummaryAdmin", "Tags:10"));
results.Add(Shape("ContentsMeta_SummaryAdmin", new ContentItemViewModel(contentItem)).Location("SummaryAdmin", "Meta:20"));

return Combine(results.ToArray());
return Combine(results);
}

public override async Task<IDisplayResult> EditAsync(ContentItem contentItem, IUpdateModel updater)
{
var context = _httpContextAccessor.HttpContext;
var contentTypeDefinition = await _contentDefinitionManager.GetTypeDefinitionAsync(contentItem.ContentType);
var results = new List<IDisplayResult>();

if (contentTypeDefinition == null)
{
return null;
}

results.Add(Dynamic("Content_PublishButton").Location("Actions:10")
.RenderWhen(() => _authorizationService.AuthorizeAsync(context.User, CommonPermissions.PublishContent, contentItem)));
var context = _httpContextAccessor.HttpContext;

results.Add(Dynamic("Content_SaveDraftButton").Location("Actions:20")
.RenderWhen(async () =>
{
if (contentTypeDefinition.IsDraftable() &&
await _authorizationService.AuthorizeAsync(context.User, CommonPermissions.EditContent, contentItem))
return Combine(
Dynamic("Content_PublishButton").Location("Actions:10")
.RenderWhen(() => _authorizationService.AuthorizeAsync(context.User, CommonPermissions.PublishContent, contentItem)),
Dynamic("Content_SaveDraftButton").Location("Actions:20")
.RenderWhen(async () =>
{
return true;
}

return false;
})
);

return Combine(results.ToArray());
return contentTypeDefinition.IsDraftable()
&& await _authorizationService.AuthorizeAsync(context.User, CommonPermissions.EditContent, contentItem);
})
);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using System;
using System.Threading.Tasks;
using OrchardCore.ContentManagement.Display.ContentDisplay;
using OrchardCore.ContentManagement.Display.Models;
Expand Down Expand Up @@ -28,7 +27,7 @@ public override IDisplayResult Edit(CommonPart part, BuildPartEditorContext cont
return Initialize<DateEditorViewModel>("CommonPart_Edit__Date", async model =>
{
model.LocalDateTime = part.ContentItem.CreatedUtc.HasValue
? (DateTime?)(await _localClock.ConvertToLocalAsync(part.ContentItem.CreatedUtc.Value)).DateTime
? (await _localClock.ConvertToLocalAsync(part.ContentItem.CreatedUtc.Value)).DateTime
: null;
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,9 @@ public async Task<ShapeBinding> GetShapeBindingAsync(string shapeType)

var localTemplates = _previewTemplatesProvider.GetTemplates();

if (localTemplates != null)
if (localTemplates != null && localTemplates.Templates.TryGetValue(shapeType, out var localTemplate))
{
if (localTemplates.Templates.TryGetValue(shapeType, out var localTemplate))
{
return BuildShapeBinding(shapeType, localTemplate);
}
return BuildShapeBinding(shapeType, localTemplate);
}

_templatesDocument ??= await _templatesManager.GetTemplatesDocumentAsync();
Expand All @@ -55,10 +52,8 @@ public async Task<ShapeBinding> GetShapeBindingAsync(string shapeType)
{
return BuildShapeBinding(shapeType, template);
}
else
{
return null;
}

return null;
}

private ShapeBinding BuildShapeBinding(string shapeType, Template template)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,9 @@ public async Task<ShapeBinding> GetShapeBindingAsync(string shapeType)

var localTemplates = _previewTemplatesProvider.GetTemplates();

if (localTemplates != null)
if (localTemplates != null && localTemplates.Templates.TryGetValue(shapeType, out var localTemplate))
{
if (localTemplates.Templates.TryGetValue(shapeType, out var localTemplate))
{
return BuildShapeBinding(shapeType, localTemplate);
}
return BuildShapeBinding(shapeType, localTemplate);
}

_templatesDocument ??= await _templatesManager.GetTemplatesDocumentAsync();
Expand All @@ -55,10 +52,8 @@ public async Task<ShapeBinding> GetShapeBindingAsync(string shapeType)
{
return BuildShapeBinding(shapeType, template);
}
else
{
return null;
}

return null;
}

private ShapeBinding BuildShapeBinding(string shapeType, Template template)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ public static void Apply(HttpContext context)
context.Items[typeof(AdminAttribute)] = null;
}

public static bool IsApplied(HttpContext context) => context.Items.TryGetValue(typeof(AdminAttribute), out _);
public static bool IsApplied(HttpContext context)
=> context.Items.ContainsKey(typeof(AdminAttribute));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public override ShapeResult Factory(string shapeType, Func<IBuildShapeContext, V

result.Displaying(ctx =>
{
var displayTypes = new[] { "", "_" + ctx.Shape.Metadata.DisplayType };
var displayTypes = new[] { string.Empty, "_" + ctx.Shape.Metadata.DisplayType };

// [ShapeType]_[DisplayType], e.g. TextField.Summary
ctx.Shape.Metadata.Alternates.Add($"{shapeType}_{ctx.Shape.Metadata.DisplayType}");
Expand Down Expand Up @@ -100,7 +100,7 @@ public override ShapeResult Factory(string shapeType, Func<IBuildShapeContext, V
{
shapeType = $"{fieldType}__{displayMode}";

if (displayType == "")
if (displayType == string.Empty)
{
displayType = DisplayToken;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ public ShapeAlterationBuilder Configure(Action<ShapeDescriptor> action)

public ShapeAlterationBuilder BoundAs(string bindingSource, Func<DisplayContext, Task<IHtmlContent>> bindingDelegate)
{
ArgumentException.ThrowIfNullOrEmpty(bindingSource);

// Schedule the configuration.
return Configure(descriptor =>
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Html;
using Microsoft.Extensions.Logging;
Expand All @@ -14,6 +13,8 @@ namespace OrchardCore.DisplayManagement.Implementation
{
public class DefaultHtmlDisplay : IHtmlDisplay
{
private const string _separator = "__";

private readonly IShapeTableManager _shapeTableManager;
private readonly IEnumerable<IShapeDisplayEvents> _shapeDisplayEvents;
private readonly IEnumerable<IShapeBindingResolver> _shapeBindingResolvers;
Expand Down Expand Up @@ -48,7 +49,7 @@ public async Task<IHtmlContent> ExecuteAsync(DisplayContext context)
}

// Check if the shape is Position Wrapper
if(shape is PositionWrapper wrapper)
if (shape is PositionWrapper wrapper)
{
return PositionWrapper.UnWrap(wrapper);
}
Expand All @@ -62,7 +63,7 @@ public async Task<IHtmlContent> ExecuteAsync(DisplayContext context)
var shapeMetadata = shape.Metadata;

// Can't really cope with a shape that has no type information.
if (shapeMetadata == null || string.IsNullOrEmpty(shapeMetadata.Type))
if (string.IsNullOrEmpty(shapeMetadata?.Type))
{
return new HtmlContentString(context.Value.ToString());
}
Expand All @@ -71,7 +72,7 @@ public async Task<IHtmlContent> ExecuteAsync(DisplayContext context)
// for instance to change the HtmlFieldPrefix.
var localContext = new DisplayContext(context)
{
HtmlFieldPrefix = shapeMetadata.Prefix ?? "",
HtmlFieldPrefix = shapeMetadata.Prefix ?? string.Empty,
};

var displayContext = new ShapeDisplayContext
Expand All @@ -97,8 +98,8 @@ public async Task<IHtmlContent> ExecuteAsync(DisplayContext context)
await shapeDescriptor.DisplayingAsync.InvokeAsync((action, displayContext) => action(displayContext), displayContext, _logger);

// Copy all binding sources (all templates for this shape) in order to use them as Localization scopes.
shapeMetadata.BindingSources = shapeDescriptor.BindingSources.Where(x => x != null).ToList();
if (!shapeMetadata.BindingSources.Any())
shapeMetadata.BindingSources = shapeDescriptor.BindingSources;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you check that no null values can be set as Bindingsources in any way?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in the ShapeAlterationBuilder.cs which is why I added a null check. and if needed, we can add .Where(x => x != null) in the ShapeDescriptorIndex class instead so it is not evaluated on every call.

if (shapeMetadata.BindingSources.Count == 0)
{
shapeMetadata.BindingSources.Add(shapeDescriptor.BindingSource);
}
Expand All @@ -122,17 +123,12 @@ public async Task<IHtmlContent> ExecuteAsync(DisplayContext context)
}

// Now find the actual binding to render, taking alternates into account.
var actualBinding = await GetShapeBindingAsync(shapeMetadata.Type, shapeMetadata.Alternates, shapeTable);
if (actualBinding != null)
{
await shapeMetadata.ProcessingAsync.InvokeAsync((action, displayContext) => action(displayContext.Shape), displayContext, _logger);
var actualBinding = await GetShapeBindingAsync(shapeMetadata.Type, shapeMetadata.Alternates, shapeTable)
?? throw new Exception($"The shape type '{shapeMetadata.Type}' is not found");

shape.Metadata.ChildContent = await ProcessAsync(actualBinding, shape, localContext);
}
else
{
throw new Exception($"Shape type '{shapeMetadata.Type}' not found");
}
await shapeMetadata.ProcessingAsync.InvokeAsync((action, displayContext) => action(displayContext.Shape), displayContext, _logger);

shape.Metadata.ChildContent = await ProcessAsync(actualBinding, shape, localContext);
}

// Process wrappers.
Expand Down Expand Up @@ -201,7 +197,7 @@ private static ShapeDescriptor GetShapeDescriptor(string shapeType, ShapeTable s
if (!shapeTable.Descriptors.TryGetValue(shapeType, out var shapeDescriptor))
{
// Check if not a fundamental type.
var index = shapeType.IndexOf("__", StringComparison.Ordinal);
var index = shapeType.IndexOf(_separator, StringComparison.Ordinal);

if (index > 0)
{
Expand Down Expand Up @@ -268,7 +264,7 @@ private async Task<ShapeBinding> GetShapeBindingAsync(string shapeType, Alternat

private static bool TryGetParentShapeTypeName(ref string shapeTypeScan)
{
var delimiterIndex = shapeTypeScan.LastIndexOf("__", StringComparison.Ordinal);
var delimiterIndex = shapeTypeScan.LastIndexOf(_separator, StringComparison.Ordinal);
if (delimiterIndex > 0)
{
shapeTypeScan = shapeTypeScan[..delimiterIndex];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Html;
using OrchardCore.DisplayManagement.Shapes;
using OrchardCore.DisplayManagement.Zones;

Expand Down Expand Up @@ -83,7 +82,10 @@ public ValueTask<IShape> AddAsync(object item, string position)

var wrapped = PositionWrapper.TryWrap(item, position);
if (wrapped is not null)
{
_items.Add(wrapped);
}

return new ValueTask<IShape>(this);
}
}
Expand Down
Loading