From 299727bec1deaeedaecc30aabe21c8b7716a908d Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Mon, 14 Aug 2017 21:33:20 +0200 Subject: [PATCH] Structure improved. --- .../Apps/AppContributorAssigned.cs | 2 +- .../Apps/AppContributorRemoved.cs | 2 +- .../Apps/AppCreated.cs | 2 +- .../Assets/AssetCreated.cs | 2 +- .../Assets/AssetRenamed.cs | 2 +- .../Assets/AssetUpdated.cs | 2 +- .../Contents/ContentCreated.cs | 2 +- .../Contents/ContentDeleted.cs | 2 +- .../Contents/ContentPublished.cs | 2 +- .../Contents/ContentUnpublished.cs | 2 +- .../Contents/ContentUpdated.cs | 2 +- .../Schemas/FieldAdded.cs | 2 +- .../Schemas/FieldDeleted.cs | 2 +- .../Schemas/FieldDisabled.cs | 2 +- .../Schemas/FieldEnabled.cs | 2 +- .../Schemas/FieldHidden.cs | 2 +- .../Schemas/FieldLocked.cs | 2 +- .../Schemas/FieldShown.cs | 2 +- .../Schemas/FieldUpdated.cs | 2 +- .../Schemas/SchemaCreated.cs | 2 +- .../Schemas/SchemaDeleted.cs | 2 +- .../Schemas/SchemaFieldsReordered.cs | 2 +- .../Schemas/SchemaPublished.cs | 2 +- .../Schemas/SchemaUnpublished.cs | 2 +- .../Schemas/SchemaUpdated.cs | 2 +- .../Schemas/WebhookAdded.cs | 23 --- .../Schemas/WebhookDeleted.cs | 19 -- .../MongoSchemaRepository_EventHandling.cs | 10 -- .../Schemas/MongoSchemaWebhookEntity.cs | 57 ------ .../Schemas/MongoSchemaWebhookRepository.cs | 127 -------------- ...goSchemaWebhookRepository_EventHandling.cs | 68 -------- .../Schemas/MongoWebhookEventEntity.cs | 79 --------- .../Schemas/MongoWebhookEventRepository.cs | 116 ------------- .../Schemas/ISchemaWebhookEntity.cs | 25 --- .../Schemas/ISchemaWebhookUrlEntity.cs | 21 --- .../Schemas/IWebhookEventEntity.cs | 27 --- .../Repositories/ISchemaWebhookRepository.cs | 23 --- .../Repositories/IWebhookEventRepository.cs | 35 ---- .../Implementations/CachingSchemaProvider.cs | 8 - .../Schemas/WebhookDequeuer.cs | 164 ------------------ .../Schemas/WebhookEnqueuer.cs | 126 -------------- .../Schemas/WebhookJob.cs | 32 ---- .../Schemas/WebhookJobResult.cs | 18 -- .../Schemas/WebhookResult.cs | 18 -- .../Schemas/WebhookSender.cs | 89 ---------- .../Apps/Commands/AssignContributor.cs | 2 +- .../Apps/Commands/RemoveContributor.cs | 2 +- .../Apps/Commands/RevokeClient.cs | 2 +- .../Apps/Commands/UpdateClient.cs | 2 +- .../Assets/Commands/UpdateAsset.cs | 2 +- .../Contents/Commands/CreateContent.cs | 2 +- .../Contents/Commands/DeleteContent.cs | 2 +- .../Contents/Commands/PatchContent.cs | 2 +- .../Contents/Commands/PublishContent.cs | 2 +- .../Contents/Commands/UnpublishContent.cs | 2 +- .../Contents/Commands/UpdateContent.cs | 2 +- .../Contents/ContentCommandMiddleware.cs | 1 - .../Schemas/Commands/AddField.cs | 2 +- .../Schemas/Commands/AddWebhook.cs | 31 ---- .../Schemas/Commands/CreateSchema.cs | 2 +- .../Schemas/Commands/DeleteField.cs | 2 +- .../Schemas/Commands/DeleteSchema.cs | 2 +- .../Schemas/Commands/DeleteWebhook.cs | 17 -- .../Schemas/Commands/DisableField.cs | 2 +- .../Schemas/Commands/EnableField.cs | 2 +- .../Schemas/Commands/HideField.cs | 2 +- .../Schemas/Commands/LockField.cs | 2 +- .../Schemas/Commands/PublishSchema.cs | 2 +- .../Schemas/Commands/ReorderFields.cs | 2 +- .../Schemas/Commands/ShowField.cs | 2 +- .../Schemas/Commands/UnpublishSchema.cs | 2 +- .../Schemas/Commands/UpdateField.cs | 2 +- .../Schemas/Commands/UpdateSchema.cs | 2 +- .../Schemas/SchemaCommandMiddleware.cs | 10 -- .../Schemas/SchemaDomainObject.cs | 42 ----- .../Config/Domain/StoreMongoDbModule.cs | 6 +- .../Controllers/Api/Apps/AppsController.cs | 2 +- .../Api/Schemas/SchemaFieldsController.cs | 4 +- .../Api/Schemas/SchemasController.cs | 7 +- .../Api/Webhooks/Models/CreateWebhookDto.cs | 7 + .../Api/Webhooks/Models/WebhookCreatedDto.cs | 32 ---- .../Api/Webhooks/Models/WebhookDto.cs | 35 +++- .../Api/Webhooks/Models/WebhookEventDto.cs | 2 +- .../Api/Webhooks/WebhooksController.cs | 80 ++++++--- .../Schemas/WebhookDequeuerTests.cs | 130 -------------- .../Schemas/WebhookEnqueuerTests.cs | 118 ------------- .../Schemas/SchemaCommandHandlerTests.cs | 34 ---- .../Schemas/SchemaDomainObjectTests.cs | 94 ---------- 88 files changed, 157 insertions(+), 1680 deletions(-) delete mode 100644 src/Squidex.Domain.Apps.Events/Schemas/WebhookAdded.cs delete mode 100644 src/Squidex.Domain.Apps.Events/Schemas/WebhookDeleted.cs delete mode 100644 src/Squidex.Domain.Apps.Read.MongoDb/Schemas/MongoSchemaWebhookEntity.cs delete mode 100644 src/Squidex.Domain.Apps.Read.MongoDb/Schemas/MongoSchemaWebhookRepository.cs delete mode 100644 src/Squidex.Domain.Apps.Read.MongoDb/Schemas/MongoSchemaWebhookRepository_EventHandling.cs delete mode 100644 src/Squidex.Domain.Apps.Read.MongoDb/Schemas/MongoWebhookEventEntity.cs delete mode 100644 src/Squidex.Domain.Apps.Read.MongoDb/Schemas/MongoWebhookEventRepository.cs delete mode 100644 src/Squidex.Domain.Apps.Read/Schemas/ISchemaWebhookEntity.cs delete mode 100644 src/Squidex.Domain.Apps.Read/Schemas/ISchemaWebhookUrlEntity.cs delete mode 100644 src/Squidex.Domain.Apps.Read/Schemas/IWebhookEventEntity.cs delete mode 100644 src/Squidex.Domain.Apps.Read/Schemas/Repositories/ISchemaWebhookRepository.cs delete mode 100644 src/Squidex.Domain.Apps.Read/Schemas/Repositories/IWebhookEventRepository.cs delete mode 100644 src/Squidex.Domain.Apps.Read/Schemas/WebhookDequeuer.cs delete mode 100644 src/Squidex.Domain.Apps.Read/Schemas/WebhookEnqueuer.cs delete mode 100644 src/Squidex.Domain.Apps.Read/Schemas/WebhookJob.cs delete mode 100644 src/Squidex.Domain.Apps.Read/Schemas/WebhookJobResult.cs delete mode 100644 src/Squidex.Domain.Apps.Read/Schemas/WebhookResult.cs delete mode 100644 src/Squidex.Domain.Apps.Read/Schemas/WebhookSender.cs delete mode 100644 src/Squidex.Domain.Apps.Write/Schemas/Commands/AddWebhook.cs delete mode 100644 src/Squidex.Domain.Apps.Write/Schemas/Commands/DeleteWebhook.cs delete mode 100644 src/Squidex/Controllers/Api/Webhooks/Models/WebhookCreatedDto.cs delete mode 100644 tests/Squidex.Domain.Apps.Read.Tests/Schemas/WebhookDequeuerTests.cs delete mode 100644 tests/Squidex.Domain.Apps.Read.Tests/Schemas/WebhookEnqueuerTests.cs diff --git a/src/Squidex.Domain.Apps.Events/Apps/AppContributorAssigned.cs b/src/Squidex.Domain.Apps.Events/Apps/AppContributorAssigned.cs index 891df2226..256748e6c 100644 --- a/src/Squidex.Domain.Apps.Events/Apps/AppContributorAssigned.cs +++ b/src/Squidex.Domain.Apps.Events/Apps/AppContributorAssigned.cs @@ -12,7 +12,7 @@ using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Events.Apps { [TypeName("AppContributorAssignedEvent")] - public class AppContributorAssigned : AppEvent + public sealed class AppContributorAssigned : AppEvent { public string ContributorId { get; set; } diff --git a/src/Squidex.Domain.Apps.Events/Apps/AppContributorRemoved.cs b/src/Squidex.Domain.Apps.Events/Apps/AppContributorRemoved.cs index a852c3c4a..48de37e3e 100644 --- a/src/Squidex.Domain.Apps.Events/Apps/AppContributorRemoved.cs +++ b/src/Squidex.Domain.Apps.Events/Apps/AppContributorRemoved.cs @@ -11,7 +11,7 @@ using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Events.Apps { [TypeName("AppContributorRemovedEvent")] - public class AppContributorRemoved : AppEvent + public sealed class AppContributorRemoved : AppEvent { public string ContributorId { get; set; } } diff --git a/src/Squidex.Domain.Apps.Events/Apps/AppCreated.cs b/src/Squidex.Domain.Apps.Events/Apps/AppCreated.cs index 0fd140bdb..803bc435f 100644 --- a/src/Squidex.Domain.Apps.Events/Apps/AppCreated.cs +++ b/src/Squidex.Domain.Apps.Events/Apps/AppCreated.cs @@ -11,7 +11,7 @@ using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Events.Apps { [TypeName("AppCreatedEvent")] - public class AppCreated : AppEvent + public sealed class AppCreated : AppEvent { public string Name { get; set; } } diff --git a/src/Squidex.Domain.Apps.Events/Assets/AssetCreated.cs b/src/Squidex.Domain.Apps.Events/Assets/AssetCreated.cs index 992fb9e3e..ba4a266ed 100644 --- a/src/Squidex.Domain.Apps.Events/Assets/AssetCreated.cs +++ b/src/Squidex.Domain.Apps.Events/Assets/AssetCreated.cs @@ -11,7 +11,7 @@ using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Events.Assets { [TypeName("AssetCreatedEvent")] - public class AssetCreated : AssetEvent + public sealed class AssetCreated : AssetEvent { public string FileName { get; set; } diff --git a/src/Squidex.Domain.Apps.Events/Assets/AssetRenamed.cs b/src/Squidex.Domain.Apps.Events/Assets/AssetRenamed.cs index 61d98c5e6..3f82732a6 100644 --- a/src/Squidex.Domain.Apps.Events/Assets/AssetRenamed.cs +++ b/src/Squidex.Domain.Apps.Events/Assets/AssetRenamed.cs @@ -11,7 +11,7 @@ using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Events.Assets { [TypeName("AssetRenamedEvent")] - public class AssetRenamed : AssetEvent + public sealed class AssetRenamed : AssetEvent { public string FileName { get; set; } } diff --git a/src/Squidex.Domain.Apps.Events/Assets/AssetUpdated.cs b/src/Squidex.Domain.Apps.Events/Assets/AssetUpdated.cs index 6c283e4c5..64b2f57a7 100644 --- a/src/Squidex.Domain.Apps.Events/Assets/AssetUpdated.cs +++ b/src/Squidex.Domain.Apps.Events/Assets/AssetUpdated.cs @@ -11,7 +11,7 @@ using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Events.Assets { [TypeName("AssetUpdated")] - public class AssetUpdated : AssetEvent + public sealed class AssetUpdated : AssetEvent { public string MimeType { get; set; } diff --git a/src/Squidex.Domain.Apps.Events/Contents/ContentCreated.cs b/src/Squidex.Domain.Apps.Events/Contents/ContentCreated.cs index bb3b92171..6c43803d5 100644 --- a/src/Squidex.Domain.Apps.Events/Contents/ContentCreated.cs +++ b/src/Squidex.Domain.Apps.Events/Contents/ContentCreated.cs @@ -12,7 +12,7 @@ using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Events.Contents { [TypeName("ContentCreatedEvent")] - public class ContentCreated : ContentEvent + public sealed class ContentCreated : ContentEvent { public NamedContentData Data { get; set; } } diff --git a/src/Squidex.Domain.Apps.Events/Contents/ContentDeleted.cs b/src/Squidex.Domain.Apps.Events/Contents/ContentDeleted.cs index 2a1fae244..bcad5c030 100644 --- a/src/Squidex.Domain.Apps.Events/Contents/ContentDeleted.cs +++ b/src/Squidex.Domain.Apps.Events/Contents/ContentDeleted.cs @@ -11,7 +11,7 @@ using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Events.Contents { [TypeName("ContentDeletedEvent")] - public class ContentDeleted : ContentEvent + public sealed class ContentDeleted : ContentEvent { } } diff --git a/src/Squidex.Domain.Apps.Events/Contents/ContentPublished.cs b/src/Squidex.Domain.Apps.Events/Contents/ContentPublished.cs index 0bbcdc0ba..dd2f077a5 100644 --- a/src/Squidex.Domain.Apps.Events/Contents/ContentPublished.cs +++ b/src/Squidex.Domain.Apps.Events/Contents/ContentPublished.cs @@ -11,7 +11,7 @@ using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Events.Contents { [TypeName("ContentPublishedEvent")] - public class ContentPublished : ContentEvent + public sealed class ContentPublished : ContentEvent { } } diff --git a/src/Squidex.Domain.Apps.Events/Contents/ContentUnpublished.cs b/src/Squidex.Domain.Apps.Events/Contents/ContentUnpublished.cs index 5d1d0cfdd..e2e564ba2 100644 --- a/src/Squidex.Domain.Apps.Events/Contents/ContentUnpublished.cs +++ b/src/Squidex.Domain.Apps.Events/Contents/ContentUnpublished.cs @@ -11,7 +11,7 @@ using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Events.Contents { [TypeName("ContentUnpublishedEvent")] - public class ContentUnpublished : ContentEvent + public sealed class ContentUnpublished : ContentEvent { } } diff --git a/src/Squidex.Domain.Apps.Events/Contents/ContentUpdated.cs b/src/Squidex.Domain.Apps.Events/Contents/ContentUpdated.cs index 1e9d44b0a..c6148021d 100644 --- a/src/Squidex.Domain.Apps.Events/Contents/ContentUpdated.cs +++ b/src/Squidex.Domain.Apps.Events/Contents/ContentUpdated.cs @@ -12,7 +12,7 @@ using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Events.Contents { [TypeName("ContentUpdatedEvent")] - public class ContentUpdated : ContentEvent + public sealed class ContentUpdated : ContentEvent { public NamedContentData Data { get; set; } } diff --git a/src/Squidex.Domain.Apps.Events/Schemas/FieldAdded.cs b/src/Squidex.Domain.Apps.Events/Schemas/FieldAdded.cs index be67bd1e9..3e61be21d 100644 --- a/src/Squidex.Domain.Apps.Events/Schemas/FieldAdded.cs +++ b/src/Squidex.Domain.Apps.Events/Schemas/FieldAdded.cs @@ -12,7 +12,7 @@ using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Events.Schemas { [TypeName("FieldAddedEvent")] - public class FieldAdded : FieldEvent + public sealed class FieldAdded : FieldEvent { public string Name { get; set; } diff --git a/src/Squidex.Domain.Apps.Events/Schemas/FieldDeleted.cs b/src/Squidex.Domain.Apps.Events/Schemas/FieldDeleted.cs index e12c9d6b2..fa4cb0e72 100644 --- a/src/Squidex.Domain.Apps.Events/Schemas/FieldDeleted.cs +++ b/src/Squidex.Domain.Apps.Events/Schemas/FieldDeleted.cs @@ -11,7 +11,7 @@ using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Events.Schemas { [TypeName("FieldDeletedEvent")] - public class FieldDeleted : FieldEvent + public sealed class FieldDeleted : FieldEvent { } } diff --git a/src/Squidex.Domain.Apps.Events/Schemas/FieldDisabled.cs b/src/Squidex.Domain.Apps.Events/Schemas/FieldDisabled.cs index a9d416dad..7df2c668b 100644 --- a/src/Squidex.Domain.Apps.Events/Schemas/FieldDisabled.cs +++ b/src/Squidex.Domain.Apps.Events/Schemas/FieldDisabled.cs @@ -11,7 +11,7 @@ using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Events.Schemas { [TypeName("FieldDisabledEvent")] - public class FieldDisabled : FieldEvent + public sealed class FieldDisabled : FieldEvent { } } diff --git a/src/Squidex.Domain.Apps.Events/Schemas/FieldEnabled.cs b/src/Squidex.Domain.Apps.Events/Schemas/FieldEnabled.cs index 18cca9c2a..3123f5b0f 100644 --- a/src/Squidex.Domain.Apps.Events/Schemas/FieldEnabled.cs +++ b/src/Squidex.Domain.Apps.Events/Schemas/FieldEnabled.cs @@ -11,7 +11,7 @@ using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Events.Schemas { [TypeName("FieldEnabledEvent")] - public class FieldEnabled : FieldEvent + public sealed class FieldEnabled : FieldEvent { } } diff --git a/src/Squidex.Domain.Apps.Events/Schemas/FieldHidden.cs b/src/Squidex.Domain.Apps.Events/Schemas/FieldHidden.cs index 6be37e077..db7c8e953 100644 --- a/src/Squidex.Domain.Apps.Events/Schemas/FieldHidden.cs +++ b/src/Squidex.Domain.Apps.Events/Schemas/FieldHidden.cs @@ -11,7 +11,7 @@ using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Events.Schemas { [TypeName("FieldHiddenEvent")] - public class FieldHidden : FieldEvent + public sealed class FieldHidden : FieldEvent { } } diff --git a/src/Squidex.Domain.Apps.Events/Schemas/FieldLocked.cs b/src/Squidex.Domain.Apps.Events/Schemas/FieldLocked.cs index d9b7f2675..be4c6b7e1 100644 --- a/src/Squidex.Domain.Apps.Events/Schemas/FieldLocked.cs +++ b/src/Squidex.Domain.Apps.Events/Schemas/FieldLocked.cs @@ -11,7 +11,7 @@ using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Events.Schemas { [TypeName("FieldLockedEvent")] - public class FieldLocked : FieldEvent + public sealed class FieldLocked : FieldEvent { } } diff --git a/src/Squidex.Domain.Apps.Events/Schemas/FieldShown.cs b/src/Squidex.Domain.Apps.Events/Schemas/FieldShown.cs index 717b085bb..734111436 100644 --- a/src/Squidex.Domain.Apps.Events/Schemas/FieldShown.cs +++ b/src/Squidex.Domain.Apps.Events/Schemas/FieldShown.cs @@ -11,7 +11,7 @@ using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Events.Schemas { [TypeName("FieldShownEvent")] - public class FieldShown : FieldEvent + public sealed class FieldShown : FieldEvent { } } diff --git a/src/Squidex.Domain.Apps.Events/Schemas/FieldUpdated.cs b/src/Squidex.Domain.Apps.Events/Schemas/FieldUpdated.cs index 64c24c74f..dbdfe5153 100644 --- a/src/Squidex.Domain.Apps.Events/Schemas/FieldUpdated.cs +++ b/src/Squidex.Domain.Apps.Events/Schemas/FieldUpdated.cs @@ -12,7 +12,7 @@ using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Events.Schemas { [TypeName("FieldUpdatedEvent")] - public class FieldUpdated : FieldEvent + public sealed class FieldUpdated : FieldEvent { public FieldProperties Properties { get; set; } } diff --git a/src/Squidex.Domain.Apps.Events/Schemas/SchemaCreated.cs b/src/Squidex.Domain.Apps.Events/Schemas/SchemaCreated.cs index df8a6d2b0..eaa3a18ee 100644 --- a/src/Squidex.Domain.Apps.Events/Schemas/SchemaCreated.cs +++ b/src/Squidex.Domain.Apps.Events/Schemas/SchemaCreated.cs @@ -13,7 +13,7 @@ using SchemaFields = System.Collections.Generic.List FieldIds { get; set; } } diff --git a/src/Squidex.Domain.Apps.Events/Schemas/SchemaPublished.cs b/src/Squidex.Domain.Apps.Events/Schemas/SchemaPublished.cs index 089fb98c0..cc0aa8554 100644 --- a/src/Squidex.Domain.Apps.Events/Schemas/SchemaPublished.cs +++ b/src/Squidex.Domain.Apps.Events/Schemas/SchemaPublished.cs @@ -11,7 +11,7 @@ using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Events.Schemas { [TypeName("SchemaPublishedEvent")] - public class SchemaPublished : SchemaEvent + public sealed class SchemaPublished : SchemaEvent { } } diff --git a/src/Squidex.Domain.Apps.Events/Schemas/SchemaUnpublished.cs b/src/Squidex.Domain.Apps.Events/Schemas/SchemaUnpublished.cs index 31a49de90..14d023525 100644 --- a/src/Squidex.Domain.Apps.Events/Schemas/SchemaUnpublished.cs +++ b/src/Squidex.Domain.Apps.Events/Schemas/SchemaUnpublished.cs @@ -11,7 +11,7 @@ using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Events.Schemas { [TypeName("SchemaUnpublishedEvent")] - public class SchemaUnpublished : SchemaEvent + public sealed class SchemaUnpublished : SchemaEvent { } } diff --git a/src/Squidex.Domain.Apps.Events/Schemas/SchemaUpdated.cs b/src/Squidex.Domain.Apps.Events/Schemas/SchemaUpdated.cs index 7d26ca16b..300058870 100644 --- a/src/Squidex.Domain.Apps.Events/Schemas/SchemaUpdated.cs +++ b/src/Squidex.Domain.Apps.Events/Schemas/SchemaUpdated.cs @@ -12,7 +12,7 @@ using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Events.Schemas { [TypeName("SchemaUpdatedEvent")] - public class SchemaUpdated : SchemaEvent + public sealed class SchemaUpdated : SchemaEvent { public SchemaProperties Properties { get; set; } } diff --git a/src/Squidex.Domain.Apps.Events/Schemas/WebhookAdded.cs b/src/Squidex.Domain.Apps.Events/Schemas/WebhookAdded.cs deleted file mode 100644 index d4b03d07c..000000000 --- a/src/Squidex.Domain.Apps.Events/Schemas/WebhookAdded.cs +++ /dev/null @@ -1,23 +0,0 @@ -// ========================================================================== -// WebhookAdded.cs -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex Group -// All rights reserved. -// ========================================================================== - -using System; -using Squidex.Infrastructure; - -namespace Squidex.Domain.Apps.Events.Schemas -{ - [TypeName("WebhookAddedEvent")] - public sealed class WebhookAdded : SchemaEvent - { - public Guid Id { get; set; } - - public Uri Url { get; set; } - - public string SharedSecret { get; set; } - } -} diff --git a/src/Squidex.Domain.Apps.Events/Schemas/WebhookDeleted.cs b/src/Squidex.Domain.Apps.Events/Schemas/WebhookDeleted.cs deleted file mode 100644 index 5e03ddf72..000000000 --- a/src/Squidex.Domain.Apps.Events/Schemas/WebhookDeleted.cs +++ /dev/null @@ -1,19 +0,0 @@ -// ========================================================================== -// WebhookDeleted.cs -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex Group -// All rights reserved. -// ========================================================================== - -using System; -using Squidex.Infrastructure; - -namespace Squidex.Domain.Apps.Events.Schemas -{ - [TypeName("WebhookDeletedEvent")] - public sealed class WebhookDeleted : SchemaEvent - { - public Guid Id { get; set; } - } -} diff --git a/src/Squidex.Domain.Apps.Read.MongoDb/Schemas/MongoSchemaRepository_EventHandling.cs b/src/Squidex.Domain.Apps.Read.MongoDb/Schemas/MongoSchemaRepository_EventHandling.cs index 8770945bb..ad68a206c 100644 --- a/src/Squidex.Domain.Apps.Read.MongoDb/Schemas/MongoSchemaRepository_EventHandling.cs +++ b/src/Squidex.Domain.Apps.Read.MongoDb/Schemas/MongoSchemaRepository_EventHandling.cs @@ -103,16 +103,6 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Schemas return UpdateSchema(@event, headers, s => SchemaEventDispatcher.Dispatch(@event, s, registry)); } - protected Task On(WebhookAdded @event, EnvelopeHeaders headers) - { - return UpdateSchema(@event, headers, s => s); - } - - protected Task On(WebhookDeleted @event, EnvelopeHeaders headers) - { - return UpdateSchema(@event, headers, s => s); - } - protected Task On(SchemaDeleted @event, EnvelopeHeaders headers) { return Collection.UpdateAsync(@event, headers, e => e.IsDeleted = true); diff --git a/src/Squidex.Domain.Apps.Read.MongoDb/Schemas/MongoSchemaWebhookEntity.cs b/src/Squidex.Domain.Apps.Read.MongoDb/Schemas/MongoSchemaWebhookEntity.cs deleted file mode 100644 index c48d3e660..000000000 --- a/src/Squidex.Domain.Apps.Read.MongoDb/Schemas/MongoSchemaWebhookEntity.cs +++ /dev/null @@ -1,57 +0,0 @@ -// ========================================================================== -// MongoSchemaWebhookEntity.cs -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex Group -// All rights reserved. -// ========================================================================== - -using System; -using MongoDB.Bson; -using MongoDB.Bson.Serialization.Attributes; -using Squidex.Domain.Apps.Read.Schemas; - -// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global - -namespace Squidex.Domain.Apps.Read.MongoDb.Schemas -{ - public class MongoSchemaWebhookEntity : ISchemaWebhookEntity - { - [BsonId] - [BsonElement] - [BsonRepresentation(BsonType.String)] - public Guid Id { get; set; } - - [BsonRequired] - [BsonElement] - public Uri Url { get; set; } - - [BsonRequired] - [BsonElement] - public Guid AppId { get; set; } - - [BsonRequired] - [BsonElement] - public Guid SchemaId { get; set; } - - [BsonRequired] - [BsonElement] - public string SharedSecret { get; set; } - - [BsonRequired] - [BsonElement] - public long TotalSucceeded { get; set; } - - [BsonRequired] - [BsonElement] - public long TotalFailed { get; set; } - - [BsonRequired] - [BsonElement] - public long TotalTimedout { get; set; } - - [BsonRequired] - [BsonElement] - public long TotalRequestTime { get; set; } - } -} diff --git a/src/Squidex.Domain.Apps.Read.MongoDb/Schemas/MongoSchemaWebhookRepository.cs b/src/Squidex.Domain.Apps.Read.MongoDb/Schemas/MongoSchemaWebhookRepository.cs deleted file mode 100644 index 1138a655b..000000000 --- a/src/Squidex.Domain.Apps.Read.MongoDb/Schemas/MongoSchemaWebhookRepository.cs +++ /dev/null @@ -1,127 +0,0 @@ -// ========================================================================== -// MongoSchemaWebhookRepository.cs -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex Group -// All rights reserved. -// ========================================================================== - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using MongoDB.Bson; -using MongoDB.Driver; -using Squidex.Domain.Apps.Read.Schemas; -using Squidex.Domain.Apps.Read.Schemas.Repositories; -using Squidex.Infrastructure; -using Squidex.Infrastructure.CQRS.Events; -using Squidex.Infrastructure.MongoDb; -using Squidex.Infrastructure.Reflection; - -// ReSharper disable SwitchStatementMissingSomeCases - -namespace Squidex.Domain.Apps.Read.MongoDb.Schemas -{ - public partial class MongoSchemaWebhookRepository : MongoRepositoryBase, ISchemaWebhookRepository, IEventConsumer - { - private static readonly List EmptyWebhooks = new List(); - private Dictionary>> inMemoryWebhooks; - private readonly SemaphoreSlim lockObject = new SemaphoreSlim(1); - - public sealed class ShortInfo : ISchemaWebhookUrlEntity - { - public Guid Id { get; set; } - - public Uri Url { get; set; } - - public string SharedSecret { get; set; } - } - - public MongoSchemaWebhookRepository(IMongoDatabase database) - : base(database) - { - } - - protected override string CollectionName() - { - return "Projections_SchemaWebhooks"; - } - - protected override Task SetupCollectionAsync(IMongoCollection collection) - { - return collection.Indexes.CreateOneAsync(Index.Ascending(x => x.SchemaId)); - } - - public async Task> QueryByAppAsync(Guid appId) - { - return await Collection.Find(Filter.Eq(x => x.AppId, appId)).ToListAsync(); - } - - public async Task> QueryUrlsBySchemaAsync(Guid appId, Guid schemaId) - { - await EnsureWebooksLoadedAsync(); - - return inMemoryWebhooks.GetOrDefault(appId)?.GetOrDefault(schemaId)?.ToList() ?? EmptyWebhooks; - } - - public async Task TraceSentAsync(Guid webhookId, WebhookResult result, TimeSpan elapsed) - { - var webhookEntity = - await Collection.Find(x => x.Id == webhookId) - .FirstOrDefaultAsync(); - - if (webhookEntity != null) - { - switch (result) - { - case WebhookResult.Success: - webhookEntity.TotalSucceeded++; - break; - case WebhookResult.Failed: - webhookEntity.TotalFailed++; - break; - case WebhookResult.Timeout: - webhookEntity.TotalTimedout++; - break; - } - - webhookEntity.TotalRequestTime += (long)elapsed.TotalMilliseconds; - - await Collection.ReplaceOneAsync(x => x.Id == webhookId, webhookEntity); - } - } - - private async Task EnsureWebooksLoadedAsync() - { - if (inMemoryWebhooks == null) - { - try - { - await lockObject.WaitAsync(); - - if (inMemoryWebhooks == null) - { - var result = new Dictionary>>(); - - var webhooks = await Collection.Find(new BsonDocument()).ToListAsync(); - - foreach (var webhook in webhooks) - { - var list = result.GetOrAddNew(webhook.AppId).GetOrAddNew(webhook.SchemaId); - - list.Add(SimpleMapper.Map(webhook, new ShortInfo())); - } - - inMemoryWebhooks = result; - } - } - finally - { - lockObject.Release(); - } - } - } - } -} diff --git a/src/Squidex.Domain.Apps.Read.MongoDb/Schemas/MongoSchemaWebhookRepository_EventHandling.cs b/src/Squidex.Domain.Apps.Read.MongoDb/Schemas/MongoSchemaWebhookRepository_EventHandling.cs deleted file mode 100644 index 23d855dc0..000000000 --- a/src/Squidex.Domain.Apps.Read.MongoDb/Schemas/MongoSchemaWebhookRepository_EventHandling.cs +++ /dev/null @@ -1,68 +0,0 @@ -// ========================================================================== -// MongoSchemaWebhookRepository_EventHandling.cs -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex Group -// All rights reserved. -// ========================================================================== - -using System.Threading.Tasks; -using MongoDB.Driver; -using Squidex.Domain.Apps.Events.Schemas; -using Squidex.Infrastructure; -using Squidex.Infrastructure.CQRS.Events; -using Squidex.Infrastructure.Dispatching; -using Squidex.Infrastructure.Reflection; - -namespace Squidex.Domain.Apps.Read.MongoDb.Schemas -{ - public partial class MongoSchemaWebhookRepository - { - public string Name - { - get { return GetType().Name; } - } - - public string EventsFilter - { - get { return "^schema-"; } - } - - public Task On(Envelope @event) - { - return this.DispatchActionAsync(@event.Payload, @event.Headers); - } - - protected async Task On(WebhookAdded @event, EnvelopeHeaders headers) - { - await EnsureWebooksLoadedAsync(); - - var theAppId = @event.AppId.Id; - var theSchemaId = @event.SchemaId.Id; - - var webhook = SimpleMapper.Map(@event, new MongoSchemaWebhookEntity { AppId = theAppId, SchemaId = theSchemaId }); - - inMemoryWebhooks.GetOrAddNew(theAppId).GetOrAddNew(theSchemaId).Add(SimpleMapper.Map(@event, new ShortInfo())); - - await Collection.InsertOneAsync(webhook); - } - - protected async Task On(WebhookDeleted @event, EnvelopeHeaders headers) - { - await EnsureWebooksLoadedAsync(); - - inMemoryWebhooks.GetOrDefault(@event.AppId.Id)?.Remove(@event.SchemaId.Id); - - await Collection.DeleteManyAsync(x => x.Id == @event.Id); - } - - protected async Task On(SchemaDeleted @event, EnvelopeHeaders headers) - { - await EnsureWebooksLoadedAsync(); - - inMemoryWebhooks.GetOrDefault(@event.AppId.Id)?.Remove(@event.SchemaId.Id); - - await Collection.DeleteManyAsync(x => x.SchemaId == @event.SchemaId.Id); - } - } -} diff --git a/src/Squidex.Domain.Apps.Read.MongoDb/Schemas/MongoWebhookEventEntity.cs b/src/Squidex.Domain.Apps.Read.MongoDb/Schemas/MongoWebhookEventEntity.cs deleted file mode 100644 index 655ccd64b..000000000 --- a/src/Squidex.Domain.Apps.Read.MongoDb/Schemas/MongoWebhookEventEntity.cs +++ /dev/null @@ -1,79 +0,0 @@ -// ========================================================================== -// MongoWebhookEventEntity.cs -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex Group -// All rights reserved. -// ========================================================================== - -using System; -using MongoDB.Bson.Serialization.Attributes; -using NodaTime; -using Squidex.Domain.Apps.Read.Schemas; -using Squidex.Infrastructure.MongoDb; -using Squidex.Infrastructure.Reflection; - -namespace Squidex.Domain.Apps.Read.MongoDb.Schemas -{ - public sealed class MongoWebhookEventEntity : MongoEntity, IWebhookEventEntity - { - private WebhookJob job; - - [BsonRequired] - [BsonElement] - public Guid AppId { get; set; } - - [BsonRequired] - [BsonElement] - public Guid WebhookId { get; set; } - - [BsonRequired] - [BsonElement] - public Uri RequestUrl { get; set; } - - [BsonRequired] - [BsonElement] - public string RequestBody { get; set; } - - [BsonRequired] - [BsonElement] - public string RequestSignature { get; set; } - - [BsonRequired] - [BsonElement] - public string EventName { get; set; } - - [BsonRequired] - [BsonElement] - public string LastDump { get; set; } - - [BsonRequired] - [BsonElement] - public Instant Expires { get; set; } - - [BsonRequired] - [BsonElement] - public Instant? NextAttempt { get; set; } - - [BsonRequired] - [BsonElement] - public int NumCalls { get; set; } - - [BsonRequired] - [BsonElement] - public bool IsSending { get; set; } - - [BsonRequired] - [BsonElement] - public WebhookResult Result { get; set; } - - [BsonRequired] - [BsonElement] - public WebhookJobResult JobResult { get; set; } - - public WebhookJob Job - { - get { return job ?? (job = SimpleMapper.Map(this, new WebhookJob())); } - } - } -} diff --git a/src/Squidex.Domain.Apps.Read.MongoDb/Schemas/MongoWebhookEventRepository.cs b/src/Squidex.Domain.Apps.Read.MongoDb/Schemas/MongoWebhookEventRepository.cs deleted file mode 100644 index b95ccb46e..000000000 --- a/src/Squidex.Domain.Apps.Read.MongoDb/Schemas/MongoWebhookEventRepository.cs +++ /dev/null @@ -1,116 +0,0 @@ -// ========================================================================== -// MongoWebhookEventRepository.cs -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex Group -// All rights reserved. -// ========================================================================== - -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using MongoDB.Driver; -using NodaTime; -using Squidex.Domain.Apps.Read.Schemas; -using Squidex.Domain.Apps.Read.Schemas.Repositories; -using Squidex.Infrastructure; -using Squidex.Infrastructure.MongoDb; -using Squidex.Infrastructure.Reflection; - -namespace Squidex.Domain.Apps.Read.MongoDb.Schemas -{ - public sealed class MongoWebhookEventRepository : MongoRepositoryBase, IWebhookEventRepository - { - private readonly IClock clock; - - public MongoWebhookEventRepository(IMongoDatabase database, IClock clock) - : base(database) - { - Guard.NotNull(clock, nameof(clock)); - - this.clock = clock; - } - - protected override string CollectionName() - { - return "WebhookEvents"; - } - - protected override async Task SetupCollectionAsync(IMongoCollection collection) - { - await collection.Indexes.CreateOneAsync(Index.Ascending(x => x.NextAttempt).Descending(x => x.IsSending)); - await collection.Indexes.CreateOneAsync(Index.Ascending(x => x.AppId).Descending(x => x.Created)); - await collection.Indexes.CreateOneAsync(Index.Ascending(x => x.Expires), new CreateIndexOptions { ExpireAfter = TimeSpan.Zero }); - } - - public Task QueryPendingAsync(Func callback, CancellationToken cancellationToken = new CancellationToken()) - { - var now = clock.GetCurrentInstant(); - - return Collection.Find(x => x.NextAttempt < now && !x.IsSending).ForEachAsync(callback, cancellationToken); - } - - public async Task> QueryByAppAsync(Guid appId, int skip = 0, int take = 20) - { - var entities = await Collection.Find(x => x.AppId == appId).Skip(skip).Limit(take).SortByDescending(x => x.Created).ToListAsync(); - - return entities; - } - - public async Task FindAsync(Guid id) - { - var entity = await Collection.Find(x => x.Id == id).FirstOrDefaultAsync(); - - return entity; - } - - public async Task CountByAppAsync(Guid appId) - { - return (int)await Collection.CountAsync(x => x.AppId == appId); - } - - public Task EnqueueAsync(Guid id, Instant nextAttempt) - { - return Collection.UpdateOneAsync(x => x.Id == id, Update.Set(x => x.NextAttempt, nextAttempt)); - } - - public Task TraceSendingAsync(Guid jobId) - { - return Collection.UpdateOneAsync(x => x.Id == jobId, Update.Set(x => x.IsSending, true)); - } - - public Task EnqueueAsync(WebhookJob job, Instant nextAttempt) - { - var entity = SimpleMapper.Map(job, new MongoWebhookEventEntity { Created = clock.GetCurrentInstant(), NextAttempt = nextAttempt }); - - return Collection.InsertOneIfNotExistsAsync(entity); - } - - public Task TraceSentAsync(Guid jobId, string dump, WebhookResult result, TimeSpan elapsed, Instant? nextAttempt) - { - WebhookJobResult jobResult; - - if (result != WebhookResult.Success && nextAttempt == null) - { - jobResult = WebhookJobResult.Failed; - } - else if (result != WebhookResult.Success && nextAttempt.HasValue) - { - jobResult = WebhookJobResult.Retry; - } - else - { - jobResult = WebhookJobResult.Success; - } - - return Collection.UpdateOneAsync(x => x.Id == jobId, - Update.Set(x => x.Result, result) - .Set(x => x.LastDump, dump) - .Set(x => x.JobResult, jobResult) - .Set(x => x.IsSending, false) - .Set(x => x.NextAttempt, nextAttempt) - .Inc(x => x.NumCalls, 1)); - } - } -} diff --git a/src/Squidex.Domain.Apps.Read/Schemas/ISchemaWebhookEntity.cs b/src/Squidex.Domain.Apps.Read/Schemas/ISchemaWebhookEntity.cs deleted file mode 100644 index 433c683e1..000000000 --- a/src/Squidex.Domain.Apps.Read/Schemas/ISchemaWebhookEntity.cs +++ /dev/null @@ -1,25 +0,0 @@ -// ========================================================================== -// ISchemaWebhookEntity.cs -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex Group -// All rights reserved. -// ========================================================================== - -using System; - -namespace Squidex.Domain.Apps.Read.Schemas -{ - public interface ISchemaWebhookEntity : ISchemaWebhookUrlEntity - { - Guid SchemaId { get; } - - long TotalSucceeded { get; } - - long TotalFailed { get; } - - long TotalTimedout { get; } - - long TotalRequestTime { get; } - } -} diff --git a/src/Squidex.Domain.Apps.Read/Schemas/ISchemaWebhookUrlEntity.cs b/src/Squidex.Domain.Apps.Read/Schemas/ISchemaWebhookUrlEntity.cs deleted file mode 100644 index 1415dd5dd..000000000 --- a/src/Squidex.Domain.Apps.Read/Schemas/ISchemaWebhookUrlEntity.cs +++ /dev/null @@ -1,21 +0,0 @@ -// ========================================================================== -// ISchemaWebhookUrlEntity.cs -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex Group -// All rights reserved. -// ========================================================================== - -using System; - -namespace Squidex.Domain.Apps.Read.Schemas -{ - public interface ISchemaWebhookUrlEntity - { - Guid Id { get; } - - Uri Url { get; } - - string SharedSecret { get; } - } -} \ No newline at end of file diff --git a/src/Squidex.Domain.Apps.Read/Schemas/IWebhookEventEntity.cs b/src/Squidex.Domain.Apps.Read/Schemas/IWebhookEventEntity.cs deleted file mode 100644 index df1d01b5a..000000000 --- a/src/Squidex.Domain.Apps.Read/Schemas/IWebhookEventEntity.cs +++ /dev/null @@ -1,27 +0,0 @@ -// ========================================================================== -// IWebhookEventEntity.cs -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex Group -// All rights reserved. -// ========================================================================== - -using NodaTime; - -namespace Squidex.Domain.Apps.Read.Schemas -{ - public interface IWebhookEventEntity : IEntity - { - WebhookJob Job { get; } - - Instant? NextAttempt { get; } - - WebhookResult Result { get; } - - WebhookJobResult JobResult { get; } - - int NumCalls { get; } - - string LastDump { get; } - } -} diff --git a/src/Squidex.Domain.Apps.Read/Schemas/Repositories/ISchemaWebhookRepository.cs b/src/Squidex.Domain.Apps.Read/Schemas/Repositories/ISchemaWebhookRepository.cs deleted file mode 100644 index 23ee452d0..000000000 --- a/src/Squidex.Domain.Apps.Read/Schemas/Repositories/ISchemaWebhookRepository.cs +++ /dev/null @@ -1,23 +0,0 @@ -// ========================================================================== -// ISchemaWebhookRepository.cs -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex Group -// All rights reserved. -// ========================================================================== - -using System; -using System.Collections.Generic; -using System.Threading.Tasks; - -namespace Squidex.Domain.Apps.Read.Schemas.Repositories -{ - public interface ISchemaWebhookRepository - { - Task TraceSentAsync(Guid webhookId, WebhookResult result, TimeSpan elapsed); - - Task> QueryUrlsBySchemaAsync(Guid appId, Guid schemaId); - - Task> QueryByAppAsync(Guid appId); - } -} diff --git a/src/Squidex.Domain.Apps.Read/Schemas/Repositories/IWebhookEventRepository.cs b/src/Squidex.Domain.Apps.Read/Schemas/Repositories/IWebhookEventRepository.cs deleted file mode 100644 index 25c7d417e..000000000 --- a/src/Squidex.Domain.Apps.Read/Schemas/Repositories/IWebhookEventRepository.cs +++ /dev/null @@ -1,35 +0,0 @@ -// ========================================================================== -// IWebhookEventRepository.cs -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex Group -// All rights reserved. -// ========================================================================== - -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using NodaTime; - -namespace Squidex.Domain.Apps.Read.Schemas.Repositories -{ - public interface IWebhookEventRepository - { - Task EnqueueAsync(WebhookJob job, Instant nextAttempt); - - Task EnqueueAsync(Guid id, Instant nextAttempt); - - Task TraceSendingAsync(Guid jobId); - - Task TraceSentAsync(Guid jobId, string dump, WebhookResult result, TimeSpan elapsed, Instant? nextCall); - - Task QueryPendingAsync(Func callback, CancellationToken cancellationToken = default(CancellationToken)); - - Task CountByAppAsync(Guid appId); - - Task> QueryByAppAsync(Guid appId, int skip = 0, int take = 20); - - Task FindAsync(Guid id); - } -} diff --git a/src/Squidex.Domain.Apps.Read/Schemas/Services/Implementations/CachingSchemaProvider.cs b/src/Squidex.Domain.Apps.Read/Schemas/Services/Implementations/CachingSchemaProvider.cs index 72d85c9a2..8d6018204 100644 --- a/src/Squidex.Domain.Apps.Read/Schemas/Services/Implementations/CachingSchemaProvider.cs +++ b/src/Squidex.Domain.Apps.Read/Schemas/Services/Implementations/CachingSchemaProvider.cs @@ -125,14 +125,6 @@ namespace Squidex.Domain.Apps.Read.Schemas.Services.Implementations { Remove(schemaUpdatedEvent.AppId, schemaUpdatedEvent.SchemaId); } - else if (@event.Payload is WebhookAdded webhookAddedEvent) - { - Remove(webhookAddedEvent.AppId, webhookAddedEvent.SchemaId); - } - else if (@event.Payload is WebhookDeleted webhookDeletedEvent) - { - Remove(webhookDeletedEvent.AppId, webhookDeletedEvent.SchemaId); - } return TaskHelper.Done; } diff --git a/src/Squidex.Domain.Apps.Read/Schemas/WebhookDequeuer.cs b/src/Squidex.Domain.Apps.Read/Schemas/WebhookDequeuer.cs deleted file mode 100644 index bf51ffde6..000000000 --- a/src/Squidex.Domain.Apps.Read/Schemas/WebhookDequeuer.cs +++ /dev/null @@ -1,164 +0,0 @@ -// ========================================================================== -// WebhookDequeuer.cs -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex Group -// All rights reserved. -// ========================================================================== - -using System; -using System.Threading; -using System.Threading.Tasks; -using System.Threading.Tasks.Dataflow; -using NodaTime; -using Squidex.Domain.Apps.Read.Schemas.Repositories; -using Squidex.Infrastructure; -using Squidex.Infrastructure.Log; -using Squidex.Infrastructure.Timers; - -// ReSharper disable SwitchStatementMissingSomeCases -// ReSharper disable MethodSupportsCancellation -// ReSharper disable InvertIf - -namespace Squidex.Domain.Apps.Read.Schemas -{ - public sealed class WebhookDequeuer : DisposableObjectBase, IExternalSystem - { - private readonly ActionBlock requestBlock; - private readonly TransformBlock blockBlock; - private readonly IWebhookEventRepository webhookEventRepository; - private readonly ISchemaWebhookRepository webhookRepository; - private readonly WebhookSender webhookSender; - private readonly CompletionTimer timer; - private readonly ISemanticLog log; - private readonly IClock clock; - - public WebhookDequeuer(WebhookSender webhookSender, - IWebhookEventRepository webhookEventRepository, - ISchemaWebhookRepository webhookRepository, - IClock clock, - ISemanticLog log) - { - Guard.NotNull(webhookEventRepository, nameof(webhookEventRepository)); - Guard.NotNull(webhookRepository, nameof(webhookRepository)); - Guard.NotNull(webhookSender, nameof(webhookSender)); - Guard.NotNull(clock, nameof(clock)); - Guard.NotNull(log, nameof(log)); - - this.webhookEventRepository = webhookEventRepository; - this.webhookRepository = webhookRepository; - this.webhookSender = webhookSender; - - this.clock = clock; - - this.log = log; - - requestBlock = - new ActionBlock(MakeRequestAsync, - new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 32, BoundedCapacity = 32 }); - - blockBlock = - new TransformBlock(x => BlockAsync(x), - new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 1, BoundedCapacity = 1 }); - - blockBlock.LinkTo(requestBlock, new DataflowLinkOptions { PropagateCompletion = true }); - - timer = new CompletionTimer(5000, QueryAsync); - } - - protected override void DisposeObject(bool disposing) - { - if (disposing) - { - timer.StopAsync().Wait(); - - blockBlock.Complete(); - requestBlock.Completion.Wait(); - } - } - - public void Connect() - { - } - - public void Next() - { - timer.SkipCurrentDelay(); - } - - private async Task QueryAsync(CancellationToken cancellationToken) - { - try - { - await webhookEventRepository.QueryPendingAsync(blockBlock.SendAsync, cancellationToken); - } - catch (Exception ex) - { - log.LogError(ex, w => w - .WriteProperty("action", "QueueWebhookEvents") - .WriteProperty("status", "Failed")); - } - } - - private async Task BlockAsync(IWebhookEventEntity @event) - { - try - { - await webhookEventRepository.TraceSendingAsync(@event.Id); - - return @event; - } - catch (Exception ex) - { - log.LogError(ex, w => w - .WriteProperty("action", "BlockWebhookEvent") - .WriteProperty("status", "Failed")); - - throw; - } - } - - private async Task MakeRequestAsync(IWebhookEventEntity @event) - { - try - { - var response = await webhookSender.SendAsync(@event.Job); - - Instant? nextCall = null; - - if (response.Result != WebhookResult.Success) - { - var now = clock.GetCurrentInstant(); - - switch (@event.NumCalls) - { - case 0: - nextCall = now.Plus(Duration.FromMinutes(5)); - break; - case 1: - nextCall = now.Plus(Duration.FromHours(1)); - break; - case 2: - nextCall = now.Plus(Duration.FromHours(5)); - break; - case 3: - nextCall = now.Plus(Duration.FromHours(6)); - break; - } - } - - await Task.WhenAll( - webhookRepository.TraceSentAsync(@event.Job.WebhookId, response.Result, response.Elapsed), - webhookEventRepository.TraceSentAsync(@event.Id, response.Dump, response.Result, response.Elapsed, nextCall)); - } - catch (Exception ex) - { - log.LogError(ex, w => w - .WriteProperty("action", "SendWebhookEvent") - .WriteProperty("status", "Failed")); - - throw; - } - } - } -} diff --git a/src/Squidex.Domain.Apps.Read/Schemas/WebhookEnqueuer.cs b/src/Squidex.Domain.Apps.Read/Schemas/WebhookEnqueuer.cs deleted file mode 100644 index a55058076..000000000 --- a/src/Squidex.Domain.Apps.Read/Schemas/WebhookEnqueuer.cs +++ /dev/null @@ -1,126 +0,0 @@ -// ========================================================================== -// WebhookEnqueuer.cs -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex Group -// All rights reserved. -// ========================================================================== - -using System; -using System.Threading.Tasks; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using NodaTime; -using Squidex.Domain.Apps.Events; -using Squidex.Domain.Apps.Events.Contents; -using Squidex.Domain.Apps.Read.Schemas.Repositories; -using Squidex.Infrastructure; -using Squidex.Infrastructure.CQRS.Events; -using Squidex.Infrastructure.Tasks; - -namespace Squidex.Domain.Apps.Read.Schemas -{ - public sealed class WebhookEnqueuer : IEventConsumer - { - private const string ContentPrefix = "Content"; - private static readonly Duration ExpirationTime = Duration.FromDays(2); - private readonly IWebhookEventRepository webhookEventRepository; - private readonly ISchemaWebhookRepository webhookRepository; - private readonly IClock clock; - private readonly TypeNameRegistry typeNameRegistry; - private readonly JsonSerializer webhookSerializer; - - public string Name - { - get { return GetType().Name; } - } - - public string EventsFilter - { - get { return "^content-"; } - } - - public WebhookEnqueuer(TypeNameRegistry typeNameRegistry, - IWebhookEventRepository webhookEventRepository, - ISchemaWebhookRepository webhookRepository, - IClock clock, - JsonSerializer webhookSerializer) - { - Guard.NotNull(webhookEventRepository, nameof(webhookEventRepository)); - Guard.NotNull(webhookSerializer, nameof(webhookSerializer)); - Guard.NotNull(webhookRepository, nameof(webhookRepository)); - Guard.NotNull(typeNameRegistry, nameof(typeNameRegistry)); - Guard.NotNull(clock, nameof(clock)); - - this.webhookEventRepository = webhookEventRepository; - this.webhookSerializer = webhookSerializer; - this.webhookRepository = webhookRepository; - - this.clock = clock; - - this.typeNameRegistry = typeNameRegistry; - } - - public Task ClearAsync() - { - return TaskHelper.Done; - } - - public async Task On(Envelope @event) - { - if (@event.Payload is ContentEvent contentEvent) - { - var eventType = typeNameRegistry.GetName(@event.Payload.GetType()); - - var webhooks = await webhookRepository.QueryUrlsBySchemaAsync(contentEvent.AppId.Id, contentEvent.SchemaId.Id); - - if (webhooks.Count > 0) - { - var now = clock.GetCurrentInstant(); - - var payload = CreatePayload(@event, eventType); - - var eventName = $"{contentEvent.SchemaId.Name.ToPascalCase()}{CreateContentEventName(eventType)}"; - - foreach (var webhook in webhooks) - { - await EnqueueJobAsync(payload, webhook, contentEvent, eventName, now); - } - } - } - } - - private async Task EnqueueJobAsync(string payload, ISchemaWebhookUrlEntity webhook, AppEvent contentEvent, string eventName, Instant now) - { - var signature = $"{payload}{webhook.SharedSecret}".Sha256Base64(); - - var job = new WebhookJob - { - Id = Guid.NewGuid(), - AppId = contentEvent.AppId.Id, - RequestUrl = webhook.Url, - RequestBody = payload, - RequestSignature = signature, - EventName = eventName, - Expires = now.Plus(ExpirationTime), - WebhookId = webhook.Id - }; - - await webhookEventRepository.EnqueueAsync(job, now); - } - - private string CreatePayload(Envelope @event, string eventType) - { - return new JObject( - new JProperty("type", eventType), - new JProperty("payload", JObject.FromObject(@event.Payload, webhookSerializer)), - new JProperty("timestamp", @event.Headers.Timestamp().ToString())) - .ToString(Formatting.Indented); - } - - private static string CreateContentEventName(string eventType) - { - return eventType.StartsWith(ContentPrefix) ? eventType.Substring(ContentPrefix.Length) : eventType; - } - } -} diff --git a/src/Squidex.Domain.Apps.Read/Schemas/WebhookJob.cs b/src/Squidex.Domain.Apps.Read/Schemas/WebhookJob.cs deleted file mode 100644 index eaaa489a0..000000000 --- a/src/Squidex.Domain.Apps.Read/Schemas/WebhookJob.cs +++ /dev/null @@ -1,32 +0,0 @@ -// ========================================================================== -// WebhookJob.cs -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex Group -// All rights reserved. -// ========================================================================== - -using System; -using NodaTime; - -namespace Squidex.Domain.Apps.Read.Schemas -{ - public sealed class WebhookJob - { - public Guid Id { get; set; } - - public Guid AppId { get; set; } - - public Guid WebhookId { get; set; } - - public Uri RequestUrl { get; set; } - - public string RequestBody { get; set; } - - public string RequestSignature { get; set; } - - public string EventName { get; set; } - - public Instant Expires { get; set; } - } -} diff --git a/src/Squidex.Domain.Apps.Read/Schemas/WebhookJobResult.cs b/src/Squidex.Domain.Apps.Read/Schemas/WebhookJobResult.cs deleted file mode 100644 index 0122d057f..000000000 --- a/src/Squidex.Domain.Apps.Read/Schemas/WebhookJobResult.cs +++ /dev/null @@ -1,18 +0,0 @@ -// ========================================================================== -// WebhookJobResult.cs -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex Group -// All rights reserved. -// ========================================================================== - -namespace Squidex.Domain.Apps.Read.Schemas -{ - public enum WebhookJobResult - { - Pending, - Success, - Retry, - Failed - } -} diff --git a/src/Squidex.Domain.Apps.Read/Schemas/WebhookResult.cs b/src/Squidex.Domain.Apps.Read/Schemas/WebhookResult.cs deleted file mode 100644 index 5f30f63b0..000000000 --- a/src/Squidex.Domain.Apps.Read/Schemas/WebhookResult.cs +++ /dev/null @@ -1,18 +0,0 @@ -// ========================================================================== -// WebhookResult.cs -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex Group -// All rights reserved. -// ========================================================================== - -namespace Squidex.Domain.Apps.Read.Schemas -{ - public enum WebhookResult - { - Pending, - Success, - Failed, - Timeout - } -} diff --git a/src/Squidex.Domain.Apps.Read/Schemas/WebhookSender.cs b/src/Squidex.Domain.Apps.Read/Schemas/WebhookSender.cs deleted file mode 100644 index 1d94831a9..000000000 --- a/src/Squidex.Domain.Apps.Read/Schemas/WebhookSender.cs +++ /dev/null @@ -1,89 +0,0 @@ -// ========================================================================== -// WebhookSender.cs -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex Group -// All rights reserved. -// ========================================================================== - -using System; -using System.Diagnostics; -using System.Net.Http; -using System.Text; -using System.Threading.Tasks; -using Squidex.Infrastructure.Http; - -// ReSharper disable SuggestVarOrType_SimpleTypes - -namespace Squidex.Domain.Apps.Read.Schemas -{ - public class WebhookSender - { - private static readonly TimeSpan Timeout = TimeSpan.FromSeconds(2); - - public virtual async Task<(string Dump, WebhookResult Result, TimeSpan Elapsed)> SendAsync(WebhookJob job) - { - HttpRequestMessage request = BuildRequest(job); - HttpResponseMessage response = null; - - var isTimeout = false; - - var watch = Stopwatch.StartNew(); - - try - { - using (var client = new HttpClient { Timeout = Timeout }) - { - response = await client.SendAsync(request); - } - } - catch (TimeoutException) - { - isTimeout = true; - } - catch (OperationCanceledException) - { - isTimeout = true; - } - finally - { - watch.Stop(); - } - - var responseString = string.Empty; - - if (response != null) - { - responseString = await response.Content.ReadAsStringAsync(); - } - - var dump = DumpFormatter.BuildDump(request, response, job.RequestBody, responseString, watch.Elapsed); - - var result = WebhookResult.Failed; - - if (isTimeout) - { - result = WebhookResult.Timeout; - } - else if (response?.IsSuccessStatusCode == true) - { - result = WebhookResult.Success; - } - - return (dump, result, watch.Elapsed); - } - - private static HttpRequestMessage BuildRequest(WebhookJob job) - { - var request = new HttpRequestMessage(HttpMethod.Post, job.RequestUrl) - { - Content = new StringContent(job.RequestBody, Encoding.UTF8, "application/json") - }; - - request.Headers.Add("X-Signature", job.RequestSignature); - request.Headers.Add("User-Agent", "Squidex Webhook"); - - return request; - } - } -} diff --git a/src/Squidex.Domain.Apps.Write/Apps/Commands/AssignContributor.cs b/src/Squidex.Domain.Apps.Write/Apps/Commands/AssignContributor.cs index 459872a0e..13af0ced7 100644 --- a/src/Squidex.Domain.Apps.Write/Apps/Commands/AssignContributor.cs +++ b/src/Squidex.Domain.Apps.Write/Apps/Commands/AssignContributor.cs @@ -12,7 +12,7 @@ using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Write.Apps.Commands { - public class AssignContributor : AppAggregateCommand, IValidatable + public sealed class AssignContributor : AppAggregateCommand, IValidatable { public string ContributorId { get; set; } diff --git a/src/Squidex.Domain.Apps.Write/Apps/Commands/RemoveContributor.cs b/src/Squidex.Domain.Apps.Write/Apps/Commands/RemoveContributor.cs index 0816d6953..6c2ec4a13 100644 --- a/src/Squidex.Domain.Apps.Write/Apps/Commands/RemoveContributor.cs +++ b/src/Squidex.Domain.Apps.Write/Apps/Commands/RemoveContributor.cs @@ -11,7 +11,7 @@ using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Write.Apps.Commands { - public class RemoveContributor : AppAggregateCommand, IValidatable + public sealed class RemoveContributor : AppAggregateCommand, IValidatable { public string ContributorId { get; set; } diff --git a/src/Squidex.Domain.Apps.Write/Apps/Commands/RevokeClient.cs b/src/Squidex.Domain.Apps.Write/Apps/Commands/RevokeClient.cs index 8d2e93c1b..87afe99d0 100644 --- a/src/Squidex.Domain.Apps.Write/Apps/Commands/RevokeClient.cs +++ b/src/Squidex.Domain.Apps.Write/Apps/Commands/RevokeClient.cs @@ -11,7 +11,7 @@ using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Write.Apps.Commands { - public class RevokeClient : AppAggregateCommand, IValidatable + public sealed class RevokeClient : AppAggregateCommand, IValidatable { public string Id { get; set; } diff --git a/src/Squidex.Domain.Apps.Write/Apps/Commands/UpdateClient.cs b/src/Squidex.Domain.Apps.Write/Apps/Commands/UpdateClient.cs index 2e629d54e..2f954143a 100644 --- a/src/Squidex.Domain.Apps.Write/Apps/Commands/UpdateClient.cs +++ b/src/Squidex.Domain.Apps.Write/Apps/Commands/UpdateClient.cs @@ -11,7 +11,7 @@ using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Write.Apps.Commands { - public class UpdateClient : AppAggregateCommand, IValidatable + public sealed class UpdateClient : AppAggregateCommand, IValidatable { public string Id { get; set; } diff --git a/src/Squidex.Domain.Apps.Write/Assets/Commands/UpdateAsset.cs b/src/Squidex.Domain.Apps.Write/Assets/Commands/UpdateAsset.cs index d015d37c3..32b8b3935 100644 --- a/src/Squidex.Domain.Apps.Write/Assets/Commands/UpdateAsset.cs +++ b/src/Squidex.Domain.Apps.Write/Assets/Commands/UpdateAsset.cs @@ -10,7 +10,7 @@ using Squidex.Infrastructure.Assets; namespace Squidex.Domain.Apps.Write.Assets.Commands { - public class UpdateAsset : AssetAggregateCommand + public sealed class UpdateAsset : AssetAggregateCommand { public AssetFile File { get; set; } diff --git a/src/Squidex.Domain.Apps.Write/Contents/Commands/CreateContent.cs b/src/Squidex.Domain.Apps.Write/Contents/Commands/CreateContent.cs index ef0042aff..bbab13583 100644 --- a/src/Squidex.Domain.Apps.Write/Contents/Commands/CreateContent.cs +++ b/src/Squidex.Domain.Apps.Write/Contents/Commands/CreateContent.cs @@ -10,7 +10,7 @@ using System; namespace Squidex.Domain.Apps.Write.Contents.Commands { - public class CreateContent : ContentDataCommand + public sealed class CreateContent : ContentDataCommand { public bool Publish { get; set; } diff --git a/src/Squidex.Domain.Apps.Write/Contents/Commands/DeleteContent.cs b/src/Squidex.Domain.Apps.Write/Contents/Commands/DeleteContent.cs index 210815c1f..23638c95b 100644 --- a/src/Squidex.Domain.Apps.Write/Contents/Commands/DeleteContent.cs +++ b/src/Squidex.Domain.Apps.Write/Contents/Commands/DeleteContent.cs @@ -8,7 +8,7 @@ namespace Squidex.Domain.Apps.Write.Contents.Commands { - public class DeleteContent : ContentCommand + public sealed class DeleteContent : ContentCommand { } } diff --git a/src/Squidex.Domain.Apps.Write/Contents/Commands/PatchContent.cs b/src/Squidex.Domain.Apps.Write/Contents/Commands/PatchContent.cs index d14f5f5f8..ff38a5638 100644 --- a/src/Squidex.Domain.Apps.Write/Contents/Commands/PatchContent.cs +++ b/src/Squidex.Domain.Apps.Write/Contents/Commands/PatchContent.cs @@ -8,7 +8,7 @@ namespace Squidex.Domain.Apps.Write.Contents.Commands { - public class PatchContent : ContentDataCommand + public sealed class PatchContent : ContentDataCommand { } } diff --git a/src/Squidex.Domain.Apps.Write/Contents/Commands/PublishContent.cs b/src/Squidex.Domain.Apps.Write/Contents/Commands/PublishContent.cs index f6227ee79..fb8e38abd 100644 --- a/src/Squidex.Domain.Apps.Write/Contents/Commands/PublishContent.cs +++ b/src/Squidex.Domain.Apps.Write/Contents/Commands/PublishContent.cs @@ -8,7 +8,7 @@ namespace Squidex.Domain.Apps.Write.Contents.Commands { - public class PublishContent : ContentCommand + public sealed class PublishContent : ContentCommand { } } diff --git a/src/Squidex.Domain.Apps.Write/Contents/Commands/UnpublishContent.cs b/src/Squidex.Domain.Apps.Write/Contents/Commands/UnpublishContent.cs index c0a63beae..d6690ced9 100644 --- a/src/Squidex.Domain.Apps.Write/Contents/Commands/UnpublishContent.cs +++ b/src/Squidex.Domain.Apps.Write/Contents/Commands/UnpublishContent.cs @@ -8,7 +8,7 @@ namespace Squidex.Domain.Apps.Write.Contents.Commands { - public class UnpublishContent : ContentCommand + public sealed class UnpublishContent : ContentCommand { } } diff --git a/src/Squidex.Domain.Apps.Write/Contents/Commands/UpdateContent.cs b/src/Squidex.Domain.Apps.Write/Contents/Commands/UpdateContent.cs index 87b824b25..be9546173 100644 --- a/src/Squidex.Domain.Apps.Write/Contents/Commands/UpdateContent.cs +++ b/src/Squidex.Domain.Apps.Write/Contents/Commands/UpdateContent.cs @@ -8,7 +8,7 @@ namespace Squidex.Domain.Apps.Write.Contents.Commands { - public class UpdateContent : ContentDataCommand + public sealed class UpdateContent : ContentDataCommand { } } diff --git a/src/Squidex.Domain.Apps.Write/Contents/ContentCommandMiddleware.cs b/src/Squidex.Domain.Apps.Write/Contents/ContentCommandMiddleware.cs index b9cfc4893..a2c372e7d 100644 --- a/src/Squidex.Domain.Apps.Write/Contents/ContentCommandMiddleware.cs +++ b/src/Squidex.Domain.Apps.Write/Contents/ContentCommandMiddleware.cs @@ -42,7 +42,6 @@ namespace Squidex.Domain.Apps.Write.Contents { Guard.NotNull(handler, nameof(handler)); Guard.NotNull(schemas, nameof(schemas)); - Guard.NotNull(handler, nameof(handler)); Guard.NotNull(appProvider, nameof(appProvider)); Guard.NotNull(assetRepository, nameof(assetRepository)); Guard.NotNull(contentRepository, nameof(contentRepository)); diff --git a/src/Squidex.Domain.Apps.Write/Schemas/Commands/AddField.cs b/src/Squidex.Domain.Apps.Write/Schemas/Commands/AddField.cs index 1d8ff88eb..0bcfb726c 100644 --- a/src/Squidex.Domain.Apps.Write/Schemas/Commands/AddField.cs +++ b/src/Squidex.Domain.Apps.Write/Schemas/Commands/AddField.cs @@ -13,7 +13,7 @@ using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Write.Schemas.Commands { - public class AddField : FieldCommand, IValidatable + public sealed class AddField : FieldCommand, IValidatable { public string Name { get; set; } diff --git a/src/Squidex.Domain.Apps.Write/Schemas/Commands/AddWebhook.cs b/src/Squidex.Domain.Apps.Write/Schemas/Commands/AddWebhook.cs deleted file mode 100644 index 7715829c5..000000000 --- a/src/Squidex.Domain.Apps.Write/Schemas/Commands/AddWebhook.cs +++ /dev/null @@ -1,31 +0,0 @@ -// ========================================================================== -// AddWebhook.cs -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex Group -// All rights reserved. -// ========================================================================== - -using System; -using System.Collections.Generic; -using Squidex.Infrastructure; - -namespace Squidex.Domain.Apps.Write.Schemas.Commands -{ - public sealed class AddWebhook : SchemaAggregateCommand, IValidatable - { - public Guid Id { get; } = Guid.NewGuid(); - - public Uri Url { get; set; } - - public string SharedSecret { get; } = RandomHash.New(); - - public void Validate(IList errors) - { - if (Url == null || !Url.IsAbsoluteUri) - { - errors.Add(new ValidationError("Url must be specified and absolute", nameof(Url))); - } - } - } -} diff --git a/src/Squidex.Domain.Apps.Write/Schemas/Commands/CreateSchema.cs b/src/Squidex.Domain.Apps.Write/Schemas/Commands/CreateSchema.cs index a87b70bd9..0e3d646b9 100644 --- a/src/Squidex.Domain.Apps.Write/Schemas/Commands/CreateSchema.cs +++ b/src/Squidex.Domain.Apps.Write/Schemas/Commands/CreateSchema.cs @@ -15,7 +15,7 @@ using SchemaFields = System.Collections.Generic.List FieldIds { get; set; } diff --git a/src/Squidex.Domain.Apps.Write/Schemas/Commands/ShowField.cs b/src/Squidex.Domain.Apps.Write/Schemas/Commands/ShowField.cs index 83b01c10c..024148139 100644 --- a/src/Squidex.Domain.Apps.Write/Schemas/Commands/ShowField.cs +++ b/src/Squidex.Domain.Apps.Write/Schemas/Commands/ShowField.cs @@ -8,7 +8,7 @@ namespace Squidex.Domain.Apps.Write.Schemas.Commands { - public class ShowField : FieldCommand + public sealed class ShowField : FieldCommand { } } diff --git a/src/Squidex.Domain.Apps.Write/Schemas/Commands/UnpublishSchema.cs b/src/Squidex.Domain.Apps.Write/Schemas/Commands/UnpublishSchema.cs index 119ac26a1..f8e83ce02 100644 --- a/src/Squidex.Domain.Apps.Write/Schemas/Commands/UnpublishSchema.cs +++ b/src/Squidex.Domain.Apps.Write/Schemas/Commands/UnpublishSchema.cs @@ -8,7 +8,7 @@ namespace Squidex.Domain.Apps.Write.Schemas.Commands { - public class UnpublishSchema : SchemaAggregateCommand + public sealed class UnpublishSchema : SchemaAggregateCommand { } } diff --git a/src/Squidex.Domain.Apps.Write/Schemas/Commands/UpdateField.cs b/src/Squidex.Domain.Apps.Write/Schemas/Commands/UpdateField.cs index 385df624d..1f302c132 100644 --- a/src/Squidex.Domain.Apps.Write/Schemas/Commands/UpdateField.cs +++ b/src/Squidex.Domain.Apps.Write/Schemas/Commands/UpdateField.cs @@ -12,7 +12,7 @@ using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Write.Schemas.Commands { - public class UpdateField : FieldCommand, IValidatable + public sealed class UpdateField : FieldCommand, IValidatable { public FieldProperties Properties { get; set; } diff --git a/src/Squidex.Domain.Apps.Write/Schemas/Commands/UpdateSchema.cs b/src/Squidex.Domain.Apps.Write/Schemas/Commands/UpdateSchema.cs index a3989dadd..07fd69361 100644 --- a/src/Squidex.Domain.Apps.Write/Schemas/Commands/UpdateSchema.cs +++ b/src/Squidex.Domain.Apps.Write/Schemas/Commands/UpdateSchema.cs @@ -12,7 +12,7 @@ using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Write.Schemas.Commands { - public class UpdateSchema : SchemaAggregateCommand, IValidatable + public sealed class UpdateSchema : SchemaAggregateCommand, IValidatable { public SchemaProperties Properties { get; set; } diff --git a/src/Squidex.Domain.Apps.Write/Schemas/SchemaCommandMiddleware.cs b/src/Squidex.Domain.Apps.Write/Schemas/SchemaCommandMiddleware.cs index 823e4b5bf..391bed097 100644 --- a/src/Squidex.Domain.Apps.Write/Schemas/SchemaCommandMiddleware.cs +++ b/src/Squidex.Domain.Apps.Write/Schemas/SchemaCommandMiddleware.cs @@ -60,16 +60,6 @@ namespace Squidex.Domain.Apps.Write.Schemas }); } - protected Task On(AddWebhook command, CommandContext context) - { - return handler.UpdateAsync(context, s => s.AddWebhook(command)); - } - - protected Task On(DeleteWebhook command, CommandContext context) - { - return handler.UpdateAsync(context, s => s.DeleteWebhook(command)); - } - protected Task On(DeleteSchema command, CommandContext context) { return handler.UpdateAsync(context, s => s.Delete(command)); diff --git a/src/Squidex.Domain.Apps.Write/Schemas/SchemaDomainObject.cs b/src/Squidex.Domain.Apps.Write/Schemas/SchemaDomainObject.cs index 371096fb7..377d5c76b 100644 --- a/src/Squidex.Domain.Apps.Write/Schemas/SchemaDomainObject.cs +++ b/src/Squidex.Domain.Apps.Write/Schemas/SchemaDomainObject.cs @@ -23,7 +23,6 @@ namespace Squidex.Domain.Apps.Write.Schemas public class SchemaDomainObject : DomainObjectBase { private readonly FieldRegistry registry; - private readonly HashSet webhookIds = new HashSet(); private bool isDeleted; private long totalFields; private Schema schema; @@ -115,16 +114,6 @@ namespace Squidex.Domain.Apps.Write.Schemas schema = SchemaEventDispatcher.Dispatch(@event, schema); } - protected void On(WebhookAdded @event) - { - webhookIds.Add(@event.Id); - } - - protected void On(WebhookDeleted @event) - { - webhookIds.Remove(@event.Id); - } - protected void On(SchemaDeleted @event) { isDeleted = true; @@ -155,29 +144,6 @@ namespace Squidex.Domain.Apps.Write.Schemas return this; } - public SchemaDomainObject DeleteWebhook(DeleteWebhook command) - { - Guard.NotNull(command, nameof(command)); - - VerifyCreatedAndNotDeleted(); - VerifyWebhookExists(command.Id); - - RaiseEvent(SimpleMapper.Map(command, new WebhookDeleted())); - - return this; - } - - public SchemaDomainObject AddWebhook(AddWebhook command) - { - Guard.Valid(command, nameof(command), () => "Cannot add webhook"); - - VerifyCreatedAndNotDeleted(); - - RaiseEvent(SimpleMapper.Map(command, new WebhookAdded())); - - return this; - } - public SchemaDomainObject AddField(AddField command) { Guard.Valid(command, nameof(command), () => $"Cannot add field to schema {Id}"); @@ -335,14 +301,6 @@ namespace Squidex.Domain.Apps.Write.Schemas RaiseEvent(@event); } - private void VerifyWebhookExists(Guid id) - { - if (!webhookIds.Contains(id)) - { - throw new DomainObjectNotFoundException(id.ToString(), "Webhooks", typeof(Schema)); - } - } - private void VerifyNotCreated() { if (schema != null) diff --git a/src/Squidex/Config/Domain/StoreMongoDbModule.cs b/src/Squidex/Config/Domain/StoreMongoDbModule.cs index 9cbced6ca..bf5be1ae6 100644 --- a/src/Squidex/Config/Domain/StoreMongoDbModule.cs +++ b/src/Squidex/Config/Domain/StoreMongoDbModule.cs @@ -23,8 +23,10 @@ using Squidex.Domain.Apps.Read.MongoDb.Assets; using Squidex.Domain.Apps.Read.MongoDb.Contents; using Squidex.Domain.Apps.Read.MongoDb.History; using Squidex.Domain.Apps.Read.MongoDb.Schemas; +using Squidex.Domain.Apps.Read.MongoDb.Webhooks; using Squidex.Domain.Apps.Read.Schemas.Repositories; using Squidex.Domain.Apps.Read.Schemas.Services.Implementations; +using Squidex.Domain.Apps.Read.Webhooks.Repositories; using Squidex.Domain.Users; using Squidex.Domain.Users.MongoDb; using Squidex.Domain.Users.MongoDb.Infrastructure; @@ -170,9 +172,9 @@ namespace Squidex.Config.Domain .AsSelf() .SingleInstance(); - builder.RegisterType() + builder.RegisterType() .WithParameter(ResolvedParameter.ForNamed(MongoDatabaseRegistration)) - .As() + .As() .As() .As() .AsSelf() diff --git a/src/Squidex/Controllers/Api/Apps/AppsController.cs b/src/Squidex/Controllers/Api/Apps/AppsController.cs index e0d5ae817..517a40700 100644 --- a/src/Squidex/Controllers/Api/Apps/AppsController.cs +++ b/src/Squidex/Controllers/Api/Apps/AppsController.cs @@ -96,7 +96,7 @@ namespace Squidex.Controllers.Api.Apps var context = await CommandBus.PublishAsync(command); var result = context.Result>(); - var response = new EntityCreatedDto { Id = result.ToString(), Version = result.Version }; + var response = new EntityCreatedDto { Id = result.IdOrValue.ToString(), Version = result.Version }; return CreatedAtAction(nameof(GetApps), response); } diff --git a/src/Squidex/Controllers/Api/Schemas/SchemaFieldsController.cs b/src/Squidex/Controllers/Api/Schemas/SchemaFieldsController.cs index 1fb5ba493..4449d0627 100644 --- a/src/Squidex/Controllers/Api/Schemas/SchemaFieldsController.cs +++ b/src/Squidex/Controllers/Api/Schemas/SchemaFieldsController.cs @@ -59,8 +59,8 @@ namespace Squidex.Controllers.Api.Schemas var context = await CommandBus.PublishAsync(command); - var result = context.Result>().IdOrValue; - var response = new EntityCreatedDto { Id = result.ToString() }; + var result = context.Result>(); + var response = new EntityCreatedDto { Id = result.IdOrValue.ToString(), Version = result.Version }; return StatusCode(201, response); } diff --git a/src/Squidex/Controllers/Api/Schemas/SchemasController.cs b/src/Squidex/Controllers/Api/Schemas/SchemasController.cs index a8afa1e48..3f9a8c822 100644 --- a/src/Squidex/Controllers/Api/Schemas/SchemasController.cs +++ b/src/Squidex/Controllers/Api/Schemas/SchemasController.cs @@ -122,9 +122,12 @@ namespace Squidex.Controllers.Api.Schemas { var command = request.ToCommand(); - await CommandBus.PublishAsync(command); + var context = await CommandBus.PublishAsync(command); - return CreatedAtAction(nameof(GetSchema), new { name = request.Name }, new EntityCreatedDto { Id = command.Name }); + var result = context.Result>(); + var response = new EntityCreatedDto { Id = command.Name, Version = result.Version }; + + return CreatedAtAction(nameof(GetSchema), new { name = request.Name }, response); } /// diff --git a/src/Squidex/Controllers/Api/Webhooks/Models/CreateWebhookDto.cs b/src/Squidex/Controllers/Api/Webhooks/Models/CreateWebhookDto.cs index 8b96e509f..9813f52ab 100644 --- a/src/Squidex/Controllers/Api/Webhooks/Models/CreateWebhookDto.cs +++ b/src/Squidex/Controllers/Api/Webhooks/Models/CreateWebhookDto.cs @@ -7,6 +7,7 @@ // ========================================================================== using System; +using System.Collections.Generic; using System.ComponentModel.DataAnnotations; namespace Squidex.Controllers.Api.Webhooks.Models @@ -18,5 +19,11 @@ namespace Squidex.Controllers.Api.Webhooks.Models /// [Required] public Uri Url { get; set; } + + /// + /// The schema settings. + /// + [Required] + public List Schemas { get; set; } } } diff --git a/src/Squidex/Controllers/Api/Webhooks/Models/WebhookCreatedDto.cs b/src/Squidex/Controllers/Api/Webhooks/Models/WebhookCreatedDto.cs deleted file mode 100644 index 3b6ca754c..000000000 --- a/src/Squidex/Controllers/Api/Webhooks/Models/WebhookCreatedDto.cs +++ /dev/null @@ -1,32 +0,0 @@ -// ========================================================================== -// WebhookCreatedDto.cs -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex Group -// All rights reserved. -// ========================================================================== - -using System; -using System.ComponentModel.DataAnnotations; - -namespace Squidex.Controllers.Api.Webhooks.Models -{ - public class WebhookCreatedDto - { - /// - /// The id of the webhook. - /// - public Guid Id { get; set; } - - /// - /// The shared secret that is used to calculate the signature. - /// - [Required] - public string SharedSecret { get; set; } - - /// - /// The id of the schema. - /// - public string SchemaId { get; set; } - } -} diff --git a/src/Squidex/Controllers/Api/Webhooks/Models/WebhookDto.cs b/src/Squidex/Controllers/Api/Webhooks/Models/WebhookDto.cs index 4a1af05d8..f2801d9b1 100644 --- a/src/Squidex/Controllers/Api/Webhooks/Models/WebhookDto.cs +++ b/src/Squidex/Controllers/Api/Webhooks/Models/WebhookDto.cs @@ -8,6 +8,9 @@ using System; using System.ComponentModel.DataAnnotations; +using NodaTime; +using Squidex.Infrastructure; +using System.Collections.Generic; namespace Squidex.Controllers.Api.Webhooks.Models { @@ -19,9 +22,31 @@ namespace Squidex.Controllers.Api.Webhooks.Models public Guid Id { get; set; } /// - /// The id of the schema. + /// The user that has created the webhook. /// - public Guid SchemaId { get; set; } + [Required] + public RefToken CreatedBy { get; set; } + + /// + /// The user that has updated the webhook. + /// + [Required] + public RefToken LastModifiedBy { get; set; } + + /// + /// The date and time when the webhook has been created. + /// + public Instant Created { get; set; } + + /// + /// The date and time when the webhook has been modified last. + /// + public Instant LastModified { get; set; } + + /// + /// The version of the webhook. + /// + public int Version { get; set; } /// /// The number of succceeded calls. @@ -54,5 +79,11 @@ namespace Squidex.Controllers.Api.Webhooks.Models /// [Required] public string SharedSecret { get; set; } + + /// + /// The schema settings. + /// + [Required] + public List Schemas { get; set; } } } diff --git a/src/Squidex/Controllers/Api/Webhooks/Models/WebhookEventDto.cs b/src/Squidex/Controllers/Api/Webhooks/Models/WebhookEventDto.cs index 76487ddc2..21a721c71 100644 --- a/src/Squidex/Controllers/Api/Webhooks/Models/WebhookEventDto.cs +++ b/src/Squidex/Controllers/Api/Webhooks/Models/WebhookEventDto.cs @@ -9,7 +9,7 @@ using System; using System.ComponentModel.DataAnnotations; using NodaTime; -using Squidex.Domain.Apps.Read.Schemas; +using Squidex.Domain.Apps.Read.Webhooks; namespace Squidex.Controllers.Api.Webhooks.Models { diff --git a/src/Squidex/Controllers/Api/Webhooks/WebhooksController.cs b/src/Squidex/Controllers/Api/Webhooks/WebhooksController.cs index 21269b64c..ff2791ab7 100644 --- a/src/Squidex/Controllers/Api/Webhooks/WebhooksController.cs +++ b/src/Squidex/Controllers/Api/Webhooks/WebhooksController.cs @@ -10,12 +10,12 @@ using System; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Primitives; using NodaTime; using NSwag.Annotations; using Squidex.Controllers.Api.Webhooks.Models; -using Squidex.Domain.Apps.Read.Schemas.Repositories; -using Squidex.Domain.Apps.Write.Schemas.Commands; +using Squidex.Domain.Apps.Core.Webhooks; +using Squidex.Domain.Apps.Read.Webhooks.Repositories; +using Squidex.Domain.Apps.Write.Webhooks.Commands; using Squidex.Infrastructure.CQRS.Commands; using Squidex.Infrastructure.Reflection; using Squidex.Pipeline; @@ -31,11 +31,11 @@ namespace Squidex.Controllers.Api.Webhooks [MustBeAppDeveloper] public class WebhooksController : ControllerBase { - private readonly ISchemaWebhookRepository webhooksRepository; + private readonly IWebhookRepository webhooksRepository; private readonly IWebhookEventRepository webhookEventsRepository; public WebhooksController(ICommandBus commandBus, - ISchemaWebhookRepository webhooksRepository, + IWebhookRepository webhooksRepository, IWebhookEventRepository webhookEventsRepository) : base(commandBus) { @@ -59,14 +59,14 @@ namespace Squidex.Controllers.Api.Webhooks { var webhooks = await webhooksRepository.QueryByAppAsync(App.Id); - Response.Headers["ETag"] = new StringValues(App.Version.ToString()); - var response = webhooks.Select(w => { - var count = w.TotalTimedout + w.TotalSucceeded + w.TotalFailed; - var average = count == 0 ? 0 : w.TotalRequestTime / count; + var totalCount = w.TotalTimedout + w.TotalSucceeded + w.TotalFailed; + var totalAverage = totalCount == 0 ? 0 : w.TotalRequestTime / totalCount; + + var schemas = w.Schemas.Select(s => SimpleMapper.Map(s, new WebhookSchemaDto())).ToList(); - return SimpleMapper.Map(w, new WebhookDto { AverageRequestTimeMs = average }); + return SimpleMapper.Map(w, new WebhookDto { AverageRequestTimeMs = totalAverage, Schemas = schemas }); }); return Ok(response); @@ -76,50 +76,78 @@ namespace Squidex.Controllers.Api.Webhooks /// Create a new webhook. /// /// The name of the app. - /// The name of the schema. /// The webhook object that needs to be added to the app. /// /// 201 => Webhook created. - /// 400 => Webhook name or properties are not valid. - /// 409 => Webhook name already in use. - /// 404 => App or schema not found. + /// 400 => Webhook is not valid. + /// 404 => App not found. /// /// - /// All events for the specified app will be sent to the url. The timeout is 2 seconds. + /// All events for the specified schemas will be sent to the url. The timeout is 2 seconds. /// [HttpPost] - [Route("apps/{app}/schemas/{name}/webhooks/")] - [ProducesResponseType(typeof(WebhookCreatedDto), 201)] + [Route("apps/{app}/webhooks/")] + [ProducesResponseType(typeof(EntityCreatedDto), 201)] [ProducesResponseType(typeof(ErrorDto), 400)] - [ProducesResponseType(typeof(ErrorDto), 409)] [ApiCosts(1)] - public async Task PostWebhook(string app, string name, [FromBody] CreateWebhookDto request) + public async Task PostWebhook(string app, [FromBody] CreateWebhookDto request) { - var command = new AddWebhook { Url = request.Url }; + var schemas = request.Schemas.Select(s => SimpleMapper.Map(s, new WebhookSchema())).ToList(); - await CommandBus.PublishAsync(command); + var command = new CreateWebhook { Url = request.Url, Schemas = schemas }; + + var context = await CommandBus.PublishAsync(command); - var response = SimpleMapper.Map(command, new WebhookCreatedDto { SchemaId = command.SchemaId.Id.ToString() }); + var result = context.Result>(); + var response = new EntityCreatedDto { Id = result.IdOrValue.ToString(), Version = result.Version }; return CreatedAtAction(nameof(GetWebhooks), new { app }, response); } + /// + /// Update a webhook. + /// + /// The name of the app. + /// The id of the webhook to update. + /// The webhook object that needs to be added to the app. + /// + /// 203 => Webhook updated. + /// 400 => Webhook is not valid. + /// 404 => App or webhook not found. + /// + /// + /// All events for the specified schemas will be sent to the url. The timeout is 2 seconds. + /// + [HttpPut] + [Route("apps/{app}/webhooks/{id}")] + [ProducesResponseType(typeof(ErrorDto), 400)] + [ApiCosts(1)] + public async Task PutWebhook(string app, Guid id, [FromBody] CreateWebhookDto request) + { + var schemas = request.Schemas.Select(s => SimpleMapper.Map(s, new WebhookSchema())).ToList(); + + var command = new UpdateWebhook { WebhookId = id, Url = request.Url, Schemas = schemas }; + + await CommandBus.PublishAsync(command); + + return NoContent(); + } + /// /// Delete a webhook. /// /// The name of the app. - /// The name of the schema. /// The id of the webhook to delete. /// /// 204 => Webhook has been deleted. /// 404 => Webhook or shema or app not found. /// [HttpDelete] - [Route("apps/{app}/schemas/{name}/webhooks/{id}")] + [Route("apps/{app}//webhooks/{id}")] [ApiCosts(1)] - public async Task DeleteWebhook(string app, string name, Guid id) + public async Task DeleteWebhook(string app, Guid id) { - await CommandBus.PublishAsync(new DeleteWebhook { Id = id }); + await CommandBus.PublishAsync(new DeleteWebhook { WebhookId = id }); return NoContent(); } diff --git a/tests/Squidex.Domain.Apps.Read.Tests/Schemas/WebhookDequeuerTests.cs b/tests/Squidex.Domain.Apps.Read.Tests/Schemas/WebhookDequeuerTests.cs deleted file mode 100644 index 4ff600fb7..000000000 --- a/tests/Squidex.Domain.Apps.Read.Tests/Schemas/WebhookDequeuerTests.cs +++ /dev/null @@ -1,130 +0,0 @@ -// ========================================================================== -// WebhookDequeuerTests.cs -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex Group -// All rights reserved. -// ========================================================================== - -using System; -using System.Threading; -using System.Threading.Tasks; -using FakeItEasy; -using NodaTime; -using Squidex.Domain.Apps.Read.Schemas.Repositories; -using Squidex.Infrastructure.Log; -using Xunit; - -// ReSharper disable MethodSupportsCancellation -// ReSharper disable ImplicitlyCapturedClosure -// ReSharper disable ConvertToConstant.Local - -namespace Squidex.Domain.Apps.Read.Schemas -{ - public class WebhookDequeuerTests - { - private readonly IClock clock = A.Fake(); - private readonly ISchemaWebhookRepository webhookRepository = A.Fake(); - private readonly IWebhookEventRepository webhookEventRepository = A.Fake(); - private readonly WebhookSender webhookSender = A.Fake(); - private readonly Instant now = SystemClock.Instance.GetCurrentInstant(); - - public WebhookDequeuerTests() - { - A.CallTo(() => clock.GetCurrentInstant()).Returns(now); - } - - [Fact] - public void Should_update_repositories_on_successful_requests() - { - var @event = CreateEvent(0); - - var requestResult = WebhookResult.Success; - var requestTime = TimeSpan.FromMinutes(1); - var requestDump = "Dump"; - - SetupSender(@event, requestDump, requestResult, requestTime); - SetupPendingEvents(@event); - - var sut = new WebhookDequeuer( - webhookSender, - webhookEventRepository, - webhookRepository, - clock, A.Fake()); - - sut.Next(); - sut.Dispose(); - - VerifyRepositories(@event, requestDump, requestResult, requestTime, null); - } - - [Theory] - [InlineData(0, 5)] - [InlineData(1, 60)] - [InlineData(2, 300)] - [InlineData(3, 360)] - public void Should_set_next_attempt_based_on_num_calls(int calls, int minutes) - { - var @event = CreateEvent(calls); - - var requestResult = WebhookResult.Failed; - var requestTime = TimeSpan.FromMinutes(1); - var requestDump = "Dump"; - - SetupSender(@event, requestDump, requestResult, requestTime); - SetupPendingEvents(@event); - - var sut = new WebhookDequeuer( - webhookSender, - webhookEventRepository, - webhookRepository, - clock, A.Fake()); - - sut.Next(); - sut.Dispose(); - - VerifyRepositories(@event, requestDump, requestResult, requestTime, now.Plus(Duration.FromMinutes(minutes))); - } - - private void SetupSender(IWebhookEventEntity @event, string requestDump, WebhookResult requestResult, TimeSpan requestTime) - { - A.CallTo(() => webhookSender.SendAsync(@event.Job)) - .Returns(Task.FromResult((requestDump, requestResult, requestTime))); - } - - private void SetupPendingEvents(IWebhookEventEntity @event) - { - A.CallTo(() => webhookEventRepository.QueryPendingAsync(A>.Ignored, A.Ignored)) - .Invokes(async (Func callback, CancellationToken ct) => - { - await callback(@event); - }); - } - - private void VerifyRepositories(IWebhookEventEntity @event, string requestDump, WebhookResult requestResult, TimeSpan requestTime, Instant? nextAttempt) - { - A.CallTo(() => webhookEventRepository.TraceSendingAsync(@event.Id)) - .MustHaveHappened(); - - A.CallTo(() => webhookEventRepository.TraceSendingAsync(@event.Id)) - .MustHaveHappened(); - - A.CallTo(() => webhookEventRepository.TraceSentAsync(@event.Id, requestDump, requestResult, requestTime, nextAttempt)) - .MustHaveHappened(); - - A.CallTo(() => webhookRepository.TraceSentAsync(@event.Job.WebhookId, requestResult, requestTime)) - .MustHaveHappened(); - } - - private static IWebhookEventEntity CreateEvent(int numCalls) - { - var @event = A.Fake(); - - A.CallTo(() => @event.Id).Returns(Guid.NewGuid()); - A.CallTo(() => @event.Job).Returns(new WebhookJob { WebhookId = Guid.NewGuid() }); - A.CallTo(() => @event.NumCalls).Returns(numCalls); - - return @event; - } - } -} diff --git a/tests/Squidex.Domain.Apps.Read.Tests/Schemas/WebhookEnqueuerTests.cs b/tests/Squidex.Domain.Apps.Read.Tests/Schemas/WebhookEnqueuerTests.cs deleted file mode 100644 index 41aad56cb..000000000 --- a/tests/Squidex.Domain.Apps.Read.Tests/Schemas/WebhookEnqueuerTests.cs +++ /dev/null @@ -1,118 +0,0 @@ -// ========================================================================== -// WebhookEnqueuerTests.cs -// Squidex Headless CMS -// ========================================================================== -// Copyright (c) Squidex Group -// All rights reserved. -// ========================================================================== - -using System; -using System.Collections.Generic; -using System.Threading.Tasks; -using FakeItEasy; -using Newtonsoft.Json; -using NodaTime; -using Squidex.Domain.Apps.Events.Contents; -using Squidex.Domain.Apps.Read.Schemas.Repositories; -using Squidex.Infrastructure; -using Squidex.Infrastructure.CQRS.Events; -using Xunit; - -// ReSharper disable MethodSupportsCancellation -// ReSharper disable ImplicitlyCapturedClosure -// ReSharper disable ConvertToConstant.Local - -namespace Squidex.Domain.Apps.Read.Schemas -{ - public class WebhookEnqueuerTests - { - private readonly IClock clock = A.Fake(); - private readonly ISchemaWebhookRepository webhookRepository = A.Fake(); - private readonly IWebhookEventRepository webhookEventRepository = A.Fake(); - private readonly TypeNameRegistry typeNameRegisty = new TypeNameRegistry(); - private readonly Instant now = SystemClock.Instance.GetCurrentInstant(); - private readonly WebhookEnqueuer sut; - - public WebhookEnqueuerTests() - { - A.CallTo(() => clock.GetCurrentInstant()).Returns(now); - - typeNameRegisty.Map(typeof(ContentCreated)); - - sut = new WebhookEnqueuer( - typeNameRegisty, - webhookEventRepository, - webhookRepository, - clock, new JsonSerializer()); - } - - [Fact] - public void Should_return_contents_filter_for_events_filter() - { - Assert.Equal("^content-", sut.EventsFilter); - } - - [Fact] - public void Should_return_type_name_for_name() - { - Assert.Equal(typeof(WebhookEnqueuer).Name, sut.Name); - } - - [Fact] - public Task Should_do_nothing_on_clear() - { - return sut.ClearAsync(); - } - - [Fact] - public async Task Should_update_repositories_on_successful_requests() - { - var appId = new NamedId(Guid.NewGuid(), "my-app"); - - var schemaId = new NamedId(Guid.NewGuid(), "my-schema"); - - var @event = Envelope.Create(new ContentCreated { AppId = appId, SchemaId = schemaId }); - - var webhook1 = CreateWebhook(1); - var webhook2 = CreateWebhook(2); - - A.CallTo(() => webhookRepository.QueryUrlsBySchemaAsync(appId.Id, schemaId.Id)) - .Returns(Task.FromResult>(new List { webhook1, webhook2 })); - - await sut.On(@event); - - A.CallTo(() => webhookEventRepository.EnqueueAsync( - A.That.Matches(webhookJob => - !string.IsNullOrWhiteSpace(webhookJob.RequestSignature) - && !string.IsNullOrWhiteSpace(webhookJob.RequestBody) - && webhookJob.Id != Guid.Empty - && webhookJob.Expires == now.Plus(Duration.FromDays(2)) - && webhookJob.AppId == appId.Id - && webhookJob.EventName == "MySchemaCreatedEvent" - && webhookJob.RequestUrl == webhook1.Url - && webhookJob.WebhookId == webhook1.Id), now)).MustHaveHappened(); - - A.CallTo(() => webhookEventRepository.EnqueueAsync( - A.That.Matches(webhookJob => - !string.IsNullOrWhiteSpace(webhookJob.RequestSignature) - && !string.IsNullOrWhiteSpace(webhookJob.RequestBody) - && webhookJob.Id != Guid.Empty - && webhookJob.Expires == now.Plus(Duration.FromDays(2)) - && webhookJob.AppId == appId.Id - && webhookJob.EventName == "MySchemaCreatedEvent" - && webhookJob.RequestUrl == webhook2.Url - && webhookJob.WebhookId == webhook2.Id), now)).MustHaveHappened(); - } - - private static ISchemaWebhookUrlEntity CreateWebhook(int offset) - { - var webhook = A.Dummy(); - - A.CallTo(() => webhook.Id).Returns(Guid.NewGuid()); - A.CallTo(() => webhook.Url).Returns(new Uri($"http://domain{offset}.com")); - A.CallTo(() => webhook.SharedSecret).Returns($"secret{offset}"); - - return webhook; - } -} -} diff --git a/tests/Squidex.Domain.Apps.Write.Tests/Schemas/SchemaCommandHandlerTests.cs b/tests/Squidex.Domain.Apps.Write.Tests/Schemas/SchemaCommandHandlerTests.cs index 2881a4ac6..87ed80fb5 100644 --- a/tests/Squidex.Domain.Apps.Write.Tests/Schemas/SchemaCommandHandlerTests.cs +++ b/tests/Squidex.Domain.Apps.Write.Tests/Schemas/SchemaCommandHandlerTests.cs @@ -251,40 +251,6 @@ namespace Squidex.Domain.Apps.Write.Schemas }); } - [Fact] - public async Task AddWebhook_should_update_domain_object() - { - CreateSchema(); - - var context = CreateContextForCommand(new AddWebhook { Url = new Uri("http://cloud.squidex.io") }); - - await TestUpdate(schema, async _ => - { - await sut.HandleAsync(context); - }); - } - - [Fact] - public async Task DeleteWebhook_should_update_domain_object() - { - var createCommand = new AddWebhook { Url = new Uri("http://cloud.squidex.io") }; - - CreateSchema(); - CreateWebhook(createCommand); - - var context = CreateContextForCommand(new DeleteWebhook { Id = createCommand.Id }); - - await TestUpdate(schema, async _ => - { - await sut.HandleAsync(context); - }); - } - - private void CreateWebhook(AddWebhook command) - { - schema.AddWebhook(command); - } - private void CreateSchema() { schema.Create(CreateCommand(new CreateSchema { Name = SchemaName })); diff --git a/tests/Squidex.Domain.Apps.Write.Tests/Schemas/SchemaDomainObjectTests.cs b/tests/Squidex.Domain.Apps.Write.Tests/Schemas/SchemaDomainObjectTests.cs index 8f90a9aab..03f74f747 100644 --- a/tests/Squidex.Domain.Apps.Write.Tests/Schemas/SchemaDomainObjectTests.cs +++ b/tests/Squidex.Domain.Apps.Write.Tests/Schemas/SchemaDomainObjectTests.cs @@ -715,100 +715,6 @@ namespace Squidex.Domain.Apps.Write.Schemas ); } - [Fact] - public void AddWebhook_should_throw_exception_if_not_created() - { - Assert.Throws(() => - { - sut.AddWebhook(CreateCommand(new AddWebhook { Url = new Uri("https://cloud.squidex.io") })); - }); - } - - [Fact] - public void AddWebhook_should_throw_exception_if_command_is_not_valid() - { - Assert.Throws(() => - { - sut.AddWebhook(CreateCommand(new AddWebhook())); - }); - } - - [Fact] - public void AddWebhook_should_throw_exception_if_schema_is_deleted() - { - CreateSchema(); - DeleteSchema(); - - Assert.Throws(() => - { - sut.AddWebhook(CreateCommand(new AddWebhook { Url = new Uri("https://cloud.squidex.io") })); - }); - } - - [Fact] - public void AddWebhook_should_update_schema_and_create_events() - { - var command = new AddWebhook { Url = new Uri("https://cloud.squidex.io") }; - - CreateSchema(); - - sut.AddWebhook(CreateCommand(command)); - - sut.GetUncomittedEvents() - .ShouldHaveSameEvents( - CreateEvent(new WebhookAdded { Id = command.Id, Url = command.Url, SharedSecret = command.SharedSecret }) - ); - } - - [Fact] - public void DeleteWebhook_should_throw_exception_if_not_created() - { - Assert.Throws(() => - { - sut.DeleteWebhook(CreateCommand(new DeleteWebhook())); - }); - } - - [Fact] - public void DeleteWebhook_should_throw_exception_if_webhook_not_found() - { - CreateSchema(); - - Assert.Throws(() => - { - sut.DeleteWebhook(CreateCommand(new DeleteWebhook { Id = Guid.NewGuid() })); - }); - } - - [Fact] - public void DeleteWebhook_should_throw_exception_if_schema_is_deleted() - { - CreateSchema(); - DeleteSchema(); - - Assert.Throws(() => - { - sut.DeleteWebhook(CreateCommand(new DeleteWebhook { Id = Guid.NewGuid() })); - }); - } - - [Fact] - public void DeleteWebhook_should_update_schema_and_create_events() - { - var createCommand = new AddWebhook { Url = new Uri("https://cloud.squidex.io") }; - - CreateSchema(); - - sut.AddWebhook(CreateCommand(createCommand)); - sut.DeleteWebhook(CreateCommand(new DeleteWebhook { Id = createCommand.Id })); - - sut.GetUncomittedEvents() - .ShouldHaveSameEvents( - CreateEvent(new WebhookAdded { Id = createCommand.Id, Url = createCommand.Url, SharedSecret = createCommand.SharedSecret }), - CreateEvent(new WebhookDeleted { Id = createCommand.Id }) - ); - } - private void CreateField() { sut.AddField(new AddField { Name = fieldName, Properties = new NumberFieldProperties() });