Skip to content

Commit

Permalink
Introduce a new interface IContentDefinitionHandler
Browse files Browse the repository at this point in the history
  • Loading branch information
MikeAlhayek committed Oct 24, 2024
1 parent 0800bc1 commit b8245ec
Show file tree
Hide file tree
Showing 11 changed files with 109 additions and 154 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,13 @@

namespace OrchardCore.AdminDashboard.Services;

public sealed class DashboardPartContentTypeDefinitionHandler : ContentDefinitionHandlerBase
public sealed class DashboardPartContentTypeDefinitionHandler : IContentDefinitionHandler
{
public override void ContentTypeBuilding(BuildingContentTypeContext context)
/// <summary>
/// Adds the <see cref="DashboardPart"/> to the content type definition when the stereotype is set to 'DashboardWidget'.
/// This occurs during the content type building process, allowing the content type to function as a dashboard widget.
/// </summary>
public void ContentTypeBuilding(BuildingContentTypeContext context)
{
if (!context.Record.Settings.TryGetPropertyValue(nameof(ContentTypeSettings), out var node))
{
Expand All @@ -36,13 +40,17 @@ public override void ContentTypeBuilding(BuildingContentTypeContext context)
{
[nameof(ContentSettings)] = JObject.FromObject(new ContentSettings
{
IsCodeManaged = true,
IsSystemType = true,
}),
},
});
}

public override void ContentTypePartBuilding(ContentTypePartContextBuilding context)
/// <summary>
/// Marks the part on the content type as a system type to prevent its removal.
/// This ensures that the part remains integral to the content type and cannot be deleted.
/// </summary>
public void ContentTypePartBuilding(ContentTypePartContextBuilding context)
{
if (!context.Record.PartName.EqualsOrdinalIgnoreCase(nameof(DashboardPart)))
{
Expand All @@ -52,12 +60,16 @@ public override void ContentTypePartBuilding(ContentTypePartContextBuilding cont
var settings = context.Record.Settings[nameof(ContentSettings)]?.ToObject<ContentSettings>()
?? new ContentSettings();

settings.IsCodeManaged = true;
settings.IsSystemType = true;

context.Record.Settings[nameof(ContentSettings)] = JObject.FromObject(settings);
}

public override void ContentPartDefinitionBuilding(ContentPartDefinitionContextBuilding context)
/// <summary>
/// Creates a definition if the Record is null and the part name is 'DashboardPart'.
/// This ensures that the 'DashboardPart' has a valid definition when it is missing.
/// </summary>
public void ContentPartDefinitionBuilding(ContentPartDefinitionContextBuilding context)
{
if (context.Record is not null || context.Name != nameof(DashboardPart))
{
Expand All @@ -76,9 +88,13 @@ public override void ContentPartDefinitionBuilding(ContentPartDefinitionContextB
}),
[nameof(ContentSettings)] = JObject.FromObject(new ContentSettings
{
IsCodeManaged = true,
IsSystemType = true,
}),
},
};
}

public void ContentPartFieldBuilding(ContentPartFieldContextBuilding context)
{
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ public override void ConfigureServices(IServiceCollection services)
services.AddScoped<IContentDisplayDriver, DashboardContentDisplayDriver>();

services.AddDataMigration<Migrations>();
services.AddScoped<IContentDefinitionEventHandler, DashboardPartContentTypeDefinitionHandler>();
services.AddScoped<IContentDefinitionHandler, DashboardPartContentTypeDefinitionHandler>();
}

public override void Configure(IApplicationBuilder builder, IEndpointRouteBuilder routes, IServiceProvider serviceProvider)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,19 +216,17 @@ public async Task RemovePartFromTypeAsync(string partName, string typeName)

var settings = partDefinition.GetSettings<ContentSettings>();

if (settings.IsCodeManaged)
if (settings.IsSystemType)
{
_logger.LogError("The part '{PartName}' is code managed and cannot be removed from '{ContentType}' content type.", partName, typeName);

throw new InvalidOperationException("Unable to remove code managed part.");
throw new InvalidOperationException("Unable to remove system-type part.");
}

await _contentDefinitionManager.AlterTypeDefinitionAsync(typeName, typeBuilder => typeBuilder.RemovePart(partName));

var context = new ContentPartDetachedContext
{
ContentTypeName = typeName,
ContentPartName = partName
ContentPartName = partName,
};

_contentDefinitionEventHandlers.Invoke((handler, ctx) => handler.ContentPartDetached(ctx), context, _logger);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@

<div class="float-end">
<a asp-route-action="EditTypePart" asp-route-id="@Model.TypeDefinition.Name" asp-route-name="@partDefinition.Name" class="btn btn-primary btn-sm" role="button">@T["Edit"]</a>
@if (!settings.IsCodeManaged)
@if (!settings.IsSystemType)
{
<a asp-route-action="RemovePart" asp-route-id="@Model.TypeDefinition.Name" asp-route-name="@partDefinition.Name" class="btn btn-danger btn-sm" role="button" data-url-af="UnsafeUrl RemoveUrl">@T["Remove"]</a>
}
Expand Down Expand Up @@ -165,7 +165,7 @@
</div>
</form>
<script asp-name="Sortable" at="Foot"></script>
<script at="Foot" depends-on="jquery-resizable">
<script at="Foot" depends-on="jquery-resizable,Sortable">
document.addEventListener('DOMContentLoaded', function () {
const fields = document.getElementById("fields");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@ namespace OrchardCore.ContentManagement.Metadata.Settings;

public class ContentSettings
{
public bool IsCodeManaged { get; set; }
public bool IsSystemType { get; set; }
}
Original file line number Diff line number Diff line change
@@ -1,32 +1,30 @@
using GraphQL;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using OrchardCore.ContentManagement.GraphQL.Options;
using OrchardCore.ContentManagement.Metadata;
using OrchardCore.ContentTypes.Events;

namespace OrchardCore.ContentManagement.GraphQL.Queries.Types;

public class DynamicContentFieldsIndexAliasProvider : ContentDefinitionHandlerBase, IIndexAliasProvider
public class DynamicContentFieldsIndexAliasProvider : IIndexAliasProvider, IContentDefinitionEventHandler
{
private static readonly string _cacheKey = nameof(DynamicContentFieldsIndexAliasProvider);

private readonly IEnumerable<IContentFieldProvider> _contentFieldProviders;
private readonly IServiceProvider _serviceProvider;
private readonly IContentDefinitionManager _contentDefinitionManager;
private readonly IMemoryCache _memoryCache;
private readonly GraphQLContentOptions _contentOptions;

private IContentDefinitionManager _contentDefinitionManager;

public DynamicContentFieldsIndexAliasProvider(
IEnumerable<IContentFieldProvider> contentFieldProviders,
IOptions<GraphQLContentOptions> contentOptionsAccessor,
IServiceProvider serviceProvider,
IContentDefinitionManager contentDefinitionManager,
IMemoryCache memoryCache)
{
_contentFieldProviders = contentFieldProviders;
_serviceProvider = serviceProvider;
_contentDefinitionManager = contentDefinitionManager;
_memoryCache = memoryCache;
_contentOptions = contentOptionsAccessor.Value;
}
Expand All @@ -40,9 +38,6 @@ private async ValueTask<IEnumerable<IndexAlias>> GetAliasesInternalAsync()
{
var aliases = new List<IndexAlias>();

// Resolve the definition manager lazily to avoid circular dependency.
_contentDefinitionManager ??= _serviceProvider.GetRequiredService<IContentDefinitionManager>();

var types = await _contentDefinitionManager.ListTypeDefinitionsAsync();
var parts = types.SelectMany(t => t.Parts);

Expand Down Expand Up @@ -86,48 +81,56 @@ private async ValueTask<IEnumerable<IndexAlias>> GetAliasesInternalAsync()
private void InvalidateInternal()
=> _memoryCache.Remove(_cacheKey);

public override void ContentFieldAttached(ContentFieldAttachedContext context)
public void ContentFieldAttached(ContentFieldAttachedContext context)
=> InvalidateInternal();

public override void ContentFieldDetached(ContentFieldDetachedContext context)
public void ContentFieldDetached(ContentFieldDetachedContext context)
=> InvalidateInternal();

public override void ContentPartAttached(ContentPartAttachedContext context)
public void ContentPartAttached(ContentPartAttachedContext context)
=> InvalidateInternal();

public override void ContentPartCreated(ContentPartCreatedContext context)
public void ContentPartCreated(ContentPartCreatedContext context)
=> InvalidateInternal();

public override void ContentPartDetached(ContentPartDetachedContext context)
public void ContentPartDetached(ContentPartDetachedContext context)
=> InvalidateInternal();

public override void ContentPartImported(ContentPartImportedContext context)
public void ContentPartImported(ContentPartImportedContext context)
=> InvalidateInternal();

public override void ContentPartRemoved(ContentPartRemovedContext context)
public void ContentPartRemoved(ContentPartRemovedContext context)
=> InvalidateInternal();

public override void ContentTypeCreated(ContentTypeCreatedContext context)
public void ContentTypeCreated(ContentTypeCreatedContext context)
=> InvalidateInternal();

public override void ContentTypeImported(ContentTypeImportedContext context)
public void ContentTypeImported(ContentTypeImportedContext context)
=> InvalidateInternal();

public override void ContentTypeRemoved(ContentTypeRemovedContext context)
public void ContentTypeRemoved(ContentTypeRemovedContext context)
=> InvalidateInternal();

public override void ContentTypeUpdated(ContentTypeUpdatedContext context)
public void ContentTypeUpdated(ContentTypeUpdatedContext context)
=> InvalidateInternal();

public override void ContentPartUpdated(ContentPartUpdatedContext context)
public void ContentPartUpdated(ContentPartUpdatedContext context)
=> InvalidateInternal();

public override void ContentTypePartUpdated(ContentTypePartUpdatedContext context)
public void ContentTypePartUpdated(ContentTypePartUpdatedContext context)
=> InvalidateInternal();

public override void ContentFieldUpdated(ContentFieldUpdatedContext context)
public void ContentFieldUpdated(ContentFieldUpdatedContext context)
=> InvalidateInternal();

public override void ContentPartFieldUpdated(ContentPartFieldUpdatedContext context)
public void ContentPartFieldUpdated(ContentPartFieldUpdatedContext context)
=> InvalidateInternal();

public void ContentTypeImporting(ContentTypeImportingContext context)
{
}

public void ContentPartImporting(ContentPartImportingContext context)
{
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public class ContentDefinitionManager : IContentDefinitionManager
private const string CacheKey = nameof(ContentDefinitionManager);

private readonly IContentDefinitionStore _contentDefinitionStore;
private readonly IEnumerable<IContentDefinitionEventHandler> _handlers;
private readonly IEnumerable<IContentDefinitionHandler> _handlers;
private readonly ILogger _logger;
private readonly IMemoryCache _memoryCache;

Expand All @@ -27,7 +27,7 @@ public class ContentDefinitionManager : IContentDefinitionManager

public ContentDefinitionManager(
IContentDefinitionStore contentDefinitionStore,
IEnumerable<IContentDefinitionEventHandler> handlers,
IEnumerable<IContentDefinitionHandler> handlers,
ILogger<ContentDefinitionManager> logger,
IMemoryCache memoryCache)
{
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -35,20 +35,4 @@ public interface IContentDefinitionEventHandler
void ContentFieldDetached(ContentFieldDetachedContext context);

void ContentPartFieldUpdated(ContentPartFieldUpdatedContext context);

void ContentTypeBuilding(BuildingContentTypeContext context)
{
}

void ContentTypePartBuilding(ContentTypePartContextBuilding context)
{
}

void ContentPartFieldBuilding(ContentPartFieldContextBuilding context)
{
}

void ContentPartDefinitionBuilding(ContentPartDefinitionContextBuilding context)
{
}
}
Loading

0 comments on commit b8245ec

Please sign in to comment.