diff --git a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentCollectionAll.cs b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentCollectionAll.cs index ae98a5bd4..a07454389 100644 --- a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentCollectionAll.cs +++ b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentCollectionAll.cs @@ -125,6 +125,11 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents } } + public Task ResetScheduledAsync(Guid id) + { + return Collection.UpdateOneAsync(x => x.Id == id, Update.Unset(x => x.ScheduleJob).Unset(x => x.ScheduledAt)); + } + public Task FindAsync(Guid id) { return Collection.Find(x => x.Id == id).FirstOrDefaultAsync(); diff --git a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository.cs b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository.cs index b84d8406a..6198674f0 100644 --- a/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository.cs +++ b/backend/src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentRepository.cs @@ -114,6 +114,11 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents } } + public Task ResetScheduledAsync(Guid id) + { + return collectionAll.ResetScheduledAsync(id); + } + public Task QueryScheduledWithoutDataAsync(Instant now, Func callback) { return collectionAll.QueryScheduledWithoutDataAsync(now, callback); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Commands/ChangeContentStatus.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Commands/ChangeContentStatus.cs index d388b70e7..651acba98 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Commands/ChangeContentStatus.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Commands/ChangeContentStatus.cs @@ -17,6 +17,6 @@ namespace Squidex.Domain.Apps.Entities.Contents.Commands public Instant? DueTime { get; set; } - public Guid? JobId { get; set; } + public Guid? StatusJobId { get; set; } } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentDomainObject.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentDomainObject.cs index 5c44d4b12..9cd116038 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentDomainObject.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentDomainObject.cs @@ -172,7 +172,7 @@ namespace Squidex.Domain.Apps.Entities.Contents } catch (Exception) { - if (Snapshot.ScheduleJob != null && Snapshot.ScheduleJob.Id == c.JobId) + if (Snapshot.ScheduleJob != null && Snapshot.ScheduleJob.Id == c.StatusJobId) { CancelChangeStatus(c); } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentOperationContext.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentOperationContext.cs index e5c07d056..ac25cea50 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentOperationContext.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentOperationContext.cs @@ -55,21 +55,23 @@ namespace Squidex.Domain.Apps.Entities.Contents public async Task LoadAsync(NamedId appId, NamedId schemaId, ContentCommand command, bool optimized) { + this.command = command; + var (app, schema) = await appProvider.GetAppWithSchemaAsync(appId.Id, schemaId.Id); if (app == null) { - throw new InvalidOperationException($"Cannot resolve app with id {appId}."); + throw new DomainObjectNotFoundException(appId.ToString()); } + this.app = app; + if (schema == null) { - throw new InvalidOperationException($"Cannot resolve schema with id id {schemaId}."); + throw new DomainObjectNotFoundException(schemaId.ToString()); } - this.app = app; this.schema = schema; - this.command = command; validationContext = new ValidationContext(appId, schemaId, schema.SchemaDef, command.ContentId).Optimized(optimized); } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentSchedulerGrain.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentSchedulerGrain.cs index d50659cf1..cb266aa37 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentSchedulerGrain.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/ContentSchedulerGrain.cs @@ -69,22 +69,31 @@ namespace Squidex.Domain.Apps.Entities.Contents return contentRepository.QueryScheduledWithoutDataAsync(now, content => { - return Task.CompletedTask; return Dispatch(async () => { + var id = content.Id; + try { var job = content.ScheduleJob; if (job != null) { - var command = new ChangeContentStatus { ContentId = content.Id, Status = job.Status, JobId = job.Id }; - - command.Actor = job.ScheduledBy; + var command = new ChangeContentStatus + { + Actor = job.ScheduledBy, + ContentId = id, + Status = job.Status, + StatusJobId = job.Id + }; await commandBus.PublishAsync(command); } } + catch (DomainObjectNotFoundException) + { + await contentRepository.ResetScheduledAsync(content.Id); + } catch (Exception ex) { log.LogError(ex, content.Id.ToString(), (logContentId, w) => w diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Repositories/IContentRepository.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Repositories/IContentRepository.cs index 820d509eb..2339163e4 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Repositories/IContentRepository.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Repositories/IContentRepository.cs @@ -30,6 +30,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.Repositories Task FindContentAsync(IAppEntity app, ISchemaEntity schema, Guid id, SearchScope scope); + Task ResetScheduledAsync(Guid contentId); + Task QueryScheduledWithoutDataAsync(Instant now, Func callback); } } diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentDomainObjectTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentDomainObjectTests.cs index a470aac2d..34f22b797 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentDomainObjectTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentDomainObjectTests.cs @@ -436,7 +436,7 @@ namespace Squidex.Domain.Apps.Entities.Contents await ExecuteCreateAsync(); await ExecuteChangeStatusAsync(Status.Archived, dueTime); - var command = new ChangeContentStatus { Status = Status.Archived, JobId = sut.Snapshot.ScheduleJob!.Id }; + var command = new ChangeContentStatus { Status = Status.Archived, StatusJobId = sut.Snapshot.ScheduleJob!.Id }; A.CallTo(() => contentWorkflow.CanMoveToAsync(A._, Status.Draft, Status.Archived, User)) .Returns(true); @@ -464,7 +464,7 @@ namespace Squidex.Domain.Apps.Entities.Contents await ExecuteCreateAsync(); await ExecuteChangeStatusAsync(Status.Published, dueTime); - var command = new ChangeContentStatus { Status = Status.Published, JobId = sut.Snapshot.ScheduleJob!.Id }; + var command = new ChangeContentStatus { Status = Status.Published, StatusJobId = sut.Snapshot.ScheduleJob!.Id }; A.CallTo(() => contentWorkflow.CanMoveToAsync(A._, Status.Draft, Status.Published, User)) .Returns(false);