Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
@@ -1,9 +1,11 @@
using Umbraco.Cms.Core.Actions;
using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.Composing;
using Umbraco.Cms.Core.DeliveryApi;
using Umbraco.Cms.Core.ContentApps;
using Umbraco.Cms.Core.Dashboards;
using Umbraco.Cms.Core.DeliveryApi;
using Umbraco.Cms.Core.DynamicRoot.Origin;
using Umbraco.Cms.Core.DynamicRoot.QuerySteps;
using Umbraco.Cms.Core.Editors;
using Umbraco.Cms.Core.HealthChecks;
using Umbraco.Cms.Core.HealthChecks.NotificationMethods;
Expand All @@ -15,8 +17,6 @@
using Umbraco.Cms.Core.Routing;
using Umbraco.Cms.Core.Sections;
using Umbraco.Cms.Core.Snippets;
using Umbraco.Cms.Core.DynamicRoot.QuerySteps;
using Umbraco.Cms.Core.DynamicRoot.Origin;
using Umbraco.Cms.Core.Strings;
using Umbraco.Cms.Core.Tour;
using Umbraco.Cms.Core.Trees;
Expand Down Expand Up @@ -145,7 +145,7 @@ internal static void AddAllCoreCollectionBuilders(this IUmbracoBuilder builder)
builder.FilterHandlers().Add(() => builder.TypeLoader.GetTypes<IFilterHandler>());
builder.SortHandlers().Add(() => builder.TypeLoader.GetTypes<ISortHandler>());
builder.ContentIndexHandlers().Add(() => builder.TypeLoader.GetTypes<IContentIndexHandler>());
builder.WebhookEvents().AddCoreWebhooks();
builder.WebhookEvents().AddDefaultWebhooks();
}

/// <summary>
Expand Down
18 changes: 5 additions & 13 deletions src/Umbraco.Core/Extensions/TypeExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// See LICENSE for more details.

using System.Collections;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
using System.Runtime.CompilerServices;
using Umbraco.Cms.Core;
Expand Down Expand Up @@ -132,9 +133,7 @@ public static bool IsEnumerable(this Type type)
/// <c>true</c> if [is of generic type] [the specified type]; otherwise, <c>false</c>.
/// </returns>
public static bool IsOfGenericType(this Type type, Type genericType)
{
return type.TryGetGenericArguments(genericType, out Type[]? args);
}
=> type.TryGetGenericArguments(genericType, out _);

/// <summary>
/// Will find the generic type of the 'type' parameter passed in that is equal to the 'genericType' parameter passed in
Expand All @@ -143,17 +142,10 @@ public static bool IsOfGenericType(this Type type, Type genericType)
/// <param name="genericType"></param>
/// <param name="genericArgType"></param>
/// <returns></returns>
public static bool TryGetGenericArguments(this Type type, Type genericType, out Type[]? genericArgType)
public static bool TryGetGenericArguments(this Type type, Type genericType, [NotNullWhen(true)] out Type[]? genericArgType)
{
if (type == null)
{
throw new ArgumentNullException("type");
}

if (genericType == null)
{
throw new ArgumentNullException("genericType");
}
ArgumentNullException.ThrowIfNull(type);
ArgumentNullException.ThrowIfNull(genericType);

if (genericType.IsGenericType == false)
{
Expand Down
237 changes: 10 additions & 227 deletions src/Umbraco.Core/Webhooks/WebhookEventCollectionBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,38 +1,20 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Umbraco.Cms.Core.Composing;
using Umbraco.Cms.Core.Events;
using Umbraco.Cms.Core.Notifications;
using Umbraco.Cms.Core.Webhooks.Events.Content;
using Umbraco.Cms.Core.Webhooks.Events.DataType;
using Umbraco.Cms.Core.Webhooks.Events.Dictionary;
using Umbraco.Cms.Core.Webhooks.Events.Domain;
using Umbraco.Cms.Core.Webhooks.Events.Language;
using Umbraco.Cms.Core.Webhooks.Events.Media;
using Umbraco.Cms.Core.Webhooks.Events.MediaType;
using Umbraco.Cms.Core.Webhooks.Events.Member;
using Umbraco.Cms.Core.Webhooks.Events.MemberType;
using Umbraco.Cms.Core.Webhooks.Events.Package;
using Umbraco.Cms.Core.Webhooks.Events.PublicAccess;
using Umbraco.Cms.Core.Webhooks.Events.Relation;
using Umbraco.Cms.Core.Webhooks.Events.RelationType;
using Umbraco.Cms.Core.Webhooks.Events.Script;
using Umbraco.Cms.Core.Webhooks.Events.Stylesheet;
using Umbraco.Cms.Core.Webhooks.Events.Template;
using Umbraco.Cms.Core.Webhooks.Events.User;
using Umbraco.Extensions;

namespace Umbraco.Cms.Core.Webhooks;

public class WebhookEventCollectionBuilder : OrderedCollectionBuilderBase<WebhookEventCollectionBuilder,
WebhookEventCollection, IWebhookEvent>
public class WebhookEventCollectionBuilder : OrderedCollectionBuilderBase<WebhookEventCollectionBuilder, WebhookEventCollection, IWebhookEvent>
{
protected override WebhookEventCollectionBuilder This => this;

public override void RegisterWith(IServiceCollection services)
{
// register the collection
services.Add(new ServiceDescriptor(typeof(WebhookEventCollection), CreateCollection,
ServiceLifetime.Singleton));
services.Add(new ServiceDescriptor(typeof(WebhookEventCollection), CreateCollection, ServiceLifetime.Singleton));

// register the types
RegisterTypes(services);
Expand All @@ -43,16 +25,16 @@ private void RegisterTypes(IServiceCollection services)
{
Type[] types = GetRegisteringTypes(GetTypes()).ToArray();

// ensure they are safe
// Ensure they are safe
foreach (Type type in types)
{
EnsureType(type, "register");
}

// Register all webhooks as notification handlers
foreach (Type type in types)
{
Type? notificationType = GetNotificationType(type);

if (notificationType is null)
{
continue;
Expand All @@ -63,211 +45,12 @@ private void RegisterTypes(IServiceCollection services)
type,
ServiceLifetime.Transient);

if (!services.Contains(descriptor))
{
services.Add(descriptor);
}
services.TryAddEnumerable(descriptor);
}
}

private Type? GetNotificationType(Type handlerType)
{
if (handlerType.IsOfGenericType(typeof(INotificationAsyncHandler<>)))
{
Type[] genericArguments = handlerType.BaseType!.GetGenericArguments();

Type? notificationType =
genericArguments.FirstOrDefault(arg => typeof(INotification).IsAssignableFrom(arg));

if (notificationType is not null)
{
return notificationType;
}
}

return null;
}

public WebhookEventCollectionBuilder AddAllAvailableWebhooks() =>
this.AddContentWebhooks()
.AddDataTypeWebhooks()
.AddDictionaryWebhooks()
.AddDomainWebhooks()
.AddLanguageWebhooks()
.AddMediaWebhooks()
.AddMemberWebhooks()
.AddMemberTypeWebhooks()
.AddPackageWebhooks()
.AddPublicAccessWebhooks()
.AddRelationWebhooks()
.AddScriptWebhooks()
.AddStylesheetWebhooks()
.AddTemplateWebhooks()
.AddUserWebhooks();

public WebhookEventCollectionBuilder AddContentWebhooks()
{
Append<ContentCopiedWebhookEvent>();
Append<ContentDeletedBlueprintWebhookEvent>();
Append<ContentDeletedVersionsWebhookEvent>();
Append<ContentDeletedWebhookEvent>();
Append<ContentEmptiedRecycleBinWebhookEvent>();
Append<ContentMovedToRecycleBinWebhookEvent>();
Append<ContentMovedWebhookEvent>();
Append<ContentPublishedWebhookEvent>();
Append<ContentRolledBackWebhookEvent>();
Append<ContentSavedBlueprintWebhookEvent>();
Append<ContentSavedWebhookEvent>();
Append<ContentSortedWebhookEvent>();
Append<ContentUnpublishedWebhookEvent>();
return this;
}

public WebhookEventCollectionBuilder AddCoreWebhooks()
{
Append<ContentDeletedWebhookEvent>();
Append<ContentPublishedWebhookEvent>();
Append<ContentUnpublishedWebhookEvent>();
Append<MediaDeletedWebhookEvent>();
Append<MediaSavedWebhookEvent>();
return this;
}

public WebhookEventCollectionBuilder AddDataTypeWebhooks()
{
Append<DataTypeDeletedWebhookEvent>();
Append<DataTypeMovedWebhookEvent>();
Append<DataTypeSavedWebhookEvent>();
return this;
}

public WebhookEventCollectionBuilder AddDictionaryWebhooks()
{
Append<DictionaryItemDeletedWebhookEvent>();
Append<DictionaryItemSavedWebhookEvent>();
return this;
}

public WebhookEventCollectionBuilder AddDomainWebhooks()
{
Append<DomainDeletedWebhookEvent>();
Append<DomainSavedWebhookEvent>();
return this;
}

public WebhookEventCollectionBuilder AddLanguageWebhooks()
{
Append<LanguageDeletedWebhookEvent>();
Append<LanguageSavedWebhookEvent>();
return this;
}

public WebhookEventCollectionBuilder AddMediaWebhooks()
{
// Even though these two are in the AddCoreWebhooks()
// The job of the CollectionBuilder should be removing duplicates
// Would allow someone to use .AddCoreWebhooks().AddMediaWebhooks()
// Or if they explicitly they could skip over CoreWebHooks and just add this perhaps
Append<MediaDeletedWebhookEvent>();
Append<MediaSavedWebhookEvent>();

Append<MediaEmptiedRecycleBinWebhookEvent>();
Append<MediaMovedWebhookEvent>();
Append<MediaMovedToRecycleBinWebhookEvent>();

Append<MediaTypeChangedWebhookEvent>();
Append<MediaTypeDeletedWebhookEvent>();
Append<MediaTypeMovedWebhookEvent>();
Append<MediaTypeSavedWebhookEvent>();
return this;
}

public WebhookEventCollectionBuilder AddMemberWebhooks()
{
Append<AssignedMemberRolesWebhookEvent>();
Append<ExportedMemberWebhookEvent>();
Append<MemberDeletedWebhookEvent>();
Append<MemberGroupDeletedWebhookEvent>();
Append<MemberGroupSavedWebhookEvent>();
Append<MemberSavedWebhookEvent>();
Append<RemovedMemberRolesWebhookEvent>();
return this;
}

public WebhookEventCollectionBuilder AddMemberTypeWebhooks()
{
Append<MemberTypeChangedWebhookEvent>();
Append<MemberTypeDeletedWebhookEvent>();
Append<MemberTypeMovedWebhookEvent>();
Append<MemberTypeSavedWebhookEvent>();
return this;
}

public WebhookEventCollectionBuilder AddPackageWebhooks()
{
Append<ImportedPackageWebhookEvent>();
return this;
}

public WebhookEventCollectionBuilder AddPublicAccessWebhooks()
{
Append<PublicAccessEntryDeletedWebhookEvent>();
Append<PublicAccessEntrySavedWebhookEvent>();
return this;
}

public WebhookEventCollectionBuilder AddRelationWebhooks()
{
Append<RelationDeletedWebhookEvent>();
Append<RelationSavedWebhookEvent>();

Append<RelationTypeDeletedWebhookEvent>();
Append<RelationTypeSavedWebhookEvent>();
return this;
}

public WebhookEventCollectionBuilder AddScriptWebhooks()
{
Append<ScriptDeletedWebhookEvent>();
Append<ScriptSavedWebhookEvent>();
return this;
}

public WebhookEventCollectionBuilder AddStylesheetWebhooks()
{
Append<StylesheetDeletedWebhookEvent>();
Append<StylesheetSavedWebhookEvent>();
return this;
}

public WebhookEventCollectionBuilder AddTemplateWebhooks()
{
Append<PartialViewDeletedWebhookEvent>();
Append<PartialViewSavedWebhookEvent>();

Append<TemplateDeletedWebhookEvent>();
Append<TemplateSavedWebhookEvent>();
return this;
}

public WebhookEventCollectionBuilder AddUserWebhooks()
{
Append<AssignedUserGroupPermissionsWebhookEvent>();
Append<UserDeletedWebhookEvent>();
Append<UserForgotPasswordRequestedWebhookEvent>();
Append<UserForgottenPasswordRequestedWebhookEvent>();
Append<UserGroupDeletedWebhookEvent>();
Append<UserGroupSavedWebhookEvent>();
Append<UserLockedWebhookEvent>();
Append<UserLoginFailedWebhookEvent>();
Append<UserLoginRequiresVerificationWebhookEvent>();
Append<UserLoginSuccessWebhookEvent>();
Append<UserLogoutSuccessWebhookEvent>();
Append<UserPasswordChangedWebhookEvent>();
Append<UserPasswordResetWebhookEvent>();
Append<UserSavedWebhookEvent>();
Append<UserTwoFactorRequestedWebhookEvent>();
Append<UserUnlockedWebhookEvent>();
return this;
}
=> handlerType.TryGetGenericArguments(typeof(INotificationAsyncHandler<>), out Type[]? genericArguments)
? genericArguments.FirstOrDefault(arg => typeof(INotification).IsAssignableFrom(arg))
: null;
}
Loading