Browse Source

* DueDate => DueTime (renamed)

* Tests added
* Parsing due time from query string.
pull/247/head
Sebastian Stehle 8 years ago
parent
commit
a13943bf18
  1. 6
      src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentEntity.cs
  2. 2
      src/Squidex.Domain.Apps.Entities/Contents/Commands/ChangeContentStatus.cs
  3. 2
      src/Squidex.Domain.Apps.Entities/Contents/ContentCommandMiddleware.cs
  4. 4
      src/Squidex.Domain.Apps.Entities/Contents/ContentDomainObject.cs
  5. 4
      src/Squidex.Domain.Apps.Entities/Contents/Guards/GuardContent.cs
  6. 24
      src/Squidex/Areas/Api/Controllers/Content/ContentsController.cs
  7. 16
      tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentCommandMiddlewareTests.cs
  8. 20
      tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentDomainObjectTests.cs
  9. 11
      tests/Squidex.Domain.Apps.Entities.Tests/Contents/Guard/GuardContentTests.cs

6
src/Squidex.Domain.Apps.Entities.MongoDb/Contents/MongoContentEntity.cs

@ -71,15 +71,15 @@ namespace Squidex.Domain.Apps.Entities.MongoDb.Contents
public NamedId<Guid> SchemaId { get; set; } public NamedId<Guid> SchemaId { get; set; }
[BsonIgnoreIfNull] [BsonIgnoreIfNull]
[BsonElement("st")] [BsonElement("sdt")]
public Status? ScheduledTo { get; set; } public Status? ScheduledTo { get; set; }
[BsonIgnoreIfNull] [BsonIgnoreIfNull]
[BsonElement("sa")] [BsonElement("sda")]
public Instant? ScheduledAt { get; set; } public Instant? ScheduledAt { get; set; }
[BsonIgnoreIfNull] [BsonIgnoreIfNull]
[BsonElement("sb")] [BsonElement("sdb")]
public RefToken ScheduledBy { get; set; } public RefToken ScheduledBy { get; set; }
[BsonRequired] [BsonRequired]

2
src/Squidex.Domain.Apps.Entities/Contents/Commands/ChangeContentStatus.cs

@ -14,6 +14,6 @@ namespace Squidex.Domain.Apps.Entities.Contents.Commands
{ {
public Status Status { get; set; } public Status Status { get; set; }
public Instant? DueDate { get; set; } public Instant? DueTime { get; set; }
} }
} }

2
src/Squidex.Domain.Apps.Entities/Contents/ContentCommandMiddleware.cs

@ -109,7 +109,7 @@ namespace Squidex.Domain.Apps.Entities.Contents
{ {
GuardContent.CanChangeContentStatus(content.Snapshot.Status, command); GuardContent.CanChangeContentStatus(content.Snapshot.Status, command);
if (!command.DueDate.HasValue) if (!command.DueTime.HasValue)
{ {
var operationContext = await CreateContext(command, content, () => "Failed to patch content."); var operationContext = await CreateContext(command, content, () => "Failed to patch content.");

4
src/Squidex.Domain.Apps.Entities/Contents/ContentDomainObject.cs

@ -46,9 +46,9 @@ namespace Squidex.Domain.Apps.Entities.Contents
{ {
VerifyCreatedAndNotDeleted(); VerifyCreatedAndNotDeleted();
if (command.DueDate.HasValue) if (command.DueTime.HasValue)
{ {
RaiseEvent(SimpleMapper.Map(command, new ContentStatusScheduled())); RaiseEvent(SimpleMapper.Map(command, new ContentStatusScheduled { DueTime = command.DueTime.Value }));
} }
else else
{ {

4
src/Squidex.Domain.Apps.Entities/Contents/Guards/GuardContent.cs

@ -65,9 +65,9 @@ namespace Squidex.Domain.Apps.Entities.Contents.Guards
error(new ValidationError($"Content cannot be changed from status {status} to {command.Status}.", nameof(command.Status))); error(new ValidationError($"Content cannot be changed from status {status} to {command.Status}.", nameof(command.Status)));
} }
if (command.DueDate.HasValue && command.DueDate.Value < SystemClock.Instance.GetCurrentInstant()) if (command.DueTime.HasValue && command.DueTime.Value < SystemClock.Instance.GetCurrentInstant())
{ {
error(new ValidationError("DueDate must be in the future.", nameof(command.DueDate))); error(new ValidationError("DueTime must be in the future.", nameof(command.DueTime)));
} }
}); });
} }

24
src/Squidex/Areas/Api/Controllers/Content/ContentsController.cs

@ -215,11 +215,11 @@ namespace Squidex.Areas.Api.Controllers.Contents
[HttpPut] [HttpPut]
[Route("content/{app}/{name}/{id}/publish/")] [Route("content/{app}/{name}/{id}/publish/")]
[ApiCosts(1)] [ApiCosts(1)]
public async Task<IActionResult> PublishContent(string name, Guid id, string dueDate = null) public async Task<IActionResult> PublishContent(string name, Guid id, string dueTime = null)
{ {
await contentQuery.FindSchemaAsync(App, name); await contentQuery.FindSchemaAsync(App, name);
var command = CreateCommand(id, Status.Published, dueDate); var command = CreateCommand(id, Status.Published, dueTime);
await CommandBus.PublishAsync(command); await CommandBus.PublishAsync(command);
@ -230,11 +230,11 @@ namespace Squidex.Areas.Api.Controllers.Contents
[HttpPut] [HttpPut]
[Route("content/{app}/{name}/{id}/unpublish/")] [Route("content/{app}/{name}/{id}/unpublish/")]
[ApiCosts(1)] [ApiCosts(1)]
public async Task<IActionResult> UnpublishContent(string name, Guid id, string dueDate = null) public async Task<IActionResult> UnpublishContent(string name, Guid id, string dueTime = null)
{ {
await contentQuery.FindSchemaAsync(App, name); await contentQuery.FindSchemaAsync(App, name);
var command = CreateCommand(id, Status.Draft, dueDate); var command = CreateCommand(id, Status.Draft, dueTime);
await CommandBus.PublishAsync(command); await CommandBus.PublishAsync(command);
@ -245,11 +245,11 @@ namespace Squidex.Areas.Api.Controllers.Contents
[HttpPut] [HttpPut]
[Route("content/{app}/{name}/{id}/archive/")] [Route("content/{app}/{name}/{id}/archive/")]
[ApiCosts(1)] [ApiCosts(1)]
public async Task<IActionResult> ArchiveContent(string name, Guid id, string dueDate = null) public async Task<IActionResult> ArchiveContent(string name, Guid id, string dueTime = null)
{ {
await contentQuery.FindSchemaAsync(App, name); await contentQuery.FindSchemaAsync(App, name);
var command = CreateCommand(id, Status.Archived, dueDate); var command = CreateCommand(id, Status.Archived, dueTime);
await CommandBus.PublishAsync(command); await CommandBus.PublishAsync(command);
@ -260,11 +260,11 @@ namespace Squidex.Areas.Api.Controllers.Contents
[HttpPut] [HttpPut]
[Route("content/{app}/{name}/{id}/restore/")] [Route("content/{app}/{name}/{id}/restore/")]
[ApiCosts(1)] [ApiCosts(1)]
public async Task<IActionResult> RestoreContent(string name, Guid id, string dueDate = null) public async Task<IActionResult> RestoreContent(string name, Guid id, string dueTime = null)
{ {
await contentQuery.FindSchemaAsync(App, name); await contentQuery.FindSchemaAsync(App, name);
var command = CreateCommand(id, Status.Draft, dueDate); var command = CreateCommand(id, Status.Draft, dueTime);
await CommandBus.PublishAsync(command); await CommandBus.PublishAsync(command);
@ -286,13 +286,13 @@ namespace Squidex.Areas.Api.Controllers.Contents
return NoContent(); return NoContent();
} }
private static ChangeContentStatus CreateCommand(Guid id, Status status, string dueDate) private static ChangeContentStatus CreateCommand(Guid id, Status status, string dueTime)
{ {
Instant? dt = null; Instant? dt = null;
if (string.IsNullOrWhiteSpace(dueDate)) if (string.IsNullOrWhiteSpace(dueTime))
{ {
var parseResult = InstantPattern.General.Parse(dueDate); var parseResult = InstantPattern.General.Parse(dueTime);
if (!parseResult.Success) if (!parseResult.Success)
{ {
@ -300,7 +300,7 @@ namespace Squidex.Areas.Api.Controllers.Contents
} }
} }
return new ChangeContentStatus { Status = status, ContentId = id, DueDate = dt }; return new ChangeContentStatus { Status = status, ContentId = id, DueTime = dt };
} }
} }
} }

16
tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentCommandMiddlewareTests.cs

@ -9,6 +9,7 @@ using System;
using System.Security.Claims; using System.Security.Claims;
using System.Threading.Tasks; using System.Threading.Tasks;
using FakeItEasy; using FakeItEasy;
using NodaTime;
using Squidex.Domain.Apps.Core; using Squidex.Domain.Apps.Core;
using Squidex.Domain.Apps.Core.Apps; using Squidex.Domain.Apps.Core.Apps;
using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.Contents;
@ -225,6 +226,21 @@ namespace Squidex.Domain.Apps.Entities.Contents
A.CallTo(() => scriptEngine.Execute(A<ScriptContext>.Ignored, "<change-script>")).MustHaveHappened(); A.CallTo(() => scriptEngine.Execute(A<ScriptContext>.Ignored, "<change-script>")).MustHaveHappened();
} }
[Fact]
public async Task ChangeStatus_should_not_invoke_scripts_when_scheduled()
{
CreateContent();
var context = CreateContextForCommand(new ChangeContentStatus { ContentId = contentId, User = user, Status = Status.Published, DueTime = Instant.MaxValue });
await TestUpdate(content, async _ =>
{
await sut.HandleAsync(context);
});
A.CallTo(() => scriptEngine.Execute(A<ScriptContext>.Ignored, "<change-script>")).MustNotHaveHappened();
}
[Fact] [Fact]
public async Task Delete_should_update_domain_object() public async Task Delete_should_update_domain_object()
{ {

20
tests/Squidex.Domain.Apps.Entities.Tests/Contents/ContentDomainObjectTests.cs

@ -8,6 +8,7 @@
using System; using System;
using FakeItEasy; using FakeItEasy;
using FluentAssertions; using FluentAssertions;
using NodaTime;
using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Entities.Contents.Commands; using Squidex.Domain.Apps.Entities.Contents.Commands;
using Squidex.Domain.Apps.Entities.TestHelpers; using Squidex.Domain.Apps.Entities.TestHelpers;
@ -207,6 +208,25 @@ namespace Squidex.Domain.Apps.Entities.Contents
); );
} }
[Fact]
public void ChangeStatus_should_refresh_properties_and_create_scheduled_events_when_command_has_due_time()
{
CreateContent();
var dueTime = Instant.MaxValue;
sut.ChangeStatus(CreateContentCommand(new ChangeContentStatus { Status = Status.Published, DueTime = dueTime }));
Assert.Equal(Status.Draft, sut.Snapshot.Status);
Assert.Equal(Status.Published, sut.Snapshot.ScheduledTo);
Assert.Equal(dueTime, sut.Snapshot.ScheduledAt);
sut.GetUncomittedEvents()
.ShouldHaveSameEvents(
CreateContentEvent(new ContentStatusScheduled { Status = Status.Published, DueTime = dueTime })
);
}
[Fact] [Fact]
public void Delete_should_throw_exception_if_not_created() public void Delete_should_throw_exception_if_not_created()
{ {

11
tests/Squidex.Domain.Apps.Entities.Tests/Contents/Guard/GuardContentTests.cs

@ -5,6 +5,7 @@
// All rights reserved. Licensed under the MIT license. // All rights reserved. Licensed under the MIT license.
// ========================================================================== // ==========================================================================
using NodaTime;
using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Entities.Contents.Commands; using Squidex.Domain.Apps.Entities.Contents.Commands;
using Squidex.Domain.Apps.Entities.Contents.Guards; using Squidex.Domain.Apps.Entities.Contents.Guards;
@ -15,6 +16,8 @@ namespace Squidex.Domain.Apps.Entities.Contents.Guard
{ {
public class GuardContentTests public class GuardContentTests
{ {
private readonly Instant dueTimeInPast = SystemClock.Instance.GetCurrentInstant().Minus(Duration.FromHours(1));
[Fact] [Fact]
public void CanCreate_should_throw_exception_if_data_is_null() public void CanCreate_should_throw_exception_if_data_is_null()
{ {
@ -79,6 +82,14 @@ namespace Squidex.Domain.Apps.Entities.Contents.Guard
Assert.Throws<ValidationException>(() => GuardContent.CanChangeContentStatus(Status.Archived, command)); Assert.Throws<ValidationException>(() => GuardContent.CanChangeContentStatus(Status.Archived, command));
} }
[Fact]
public void CanChangeContentStatus_should_throw_exception_if_due_date_in_past()
{
var command = new ChangeContentStatus { Status = Status.Published, DueTime = dueTimeInPast };
Assert.Throws<ValidationException>(() => GuardContent.CanChangeContentStatus(Status.Draft, command));
}
[Fact] [Fact]
public void CanChangeContentStatus_not_should_throw_exception_if_status_flow_valid() public void CanChangeContentStatus_not_should_throw_exception_if_status_flow_valid()
{ {

Loading…
Cancel
Save