Browse Source

Archive implemented.

pull/107/head
Sebastian Stehle 8 years ago
parent
commit
8fde549a3d
  1. 15
      src/Squidex.Domain.Apps.Core/Scripting/JintScriptEngine.cs
  2. 2
      src/Squidex.Domain.Apps.Core/Scripting/ScriptContext.cs
  3. 4
      src/Squidex.Domain.Apps.Events/Schemas/ScriptsConfigured.cs
  4. 4
      src/Squidex.Domain.Apps.Read.MongoDb/Assets/MongoAssetEntity.cs
  5. 9
      src/Squidex.Domain.Apps.Read.MongoDb/Assets/MongoAssetRepository.cs
  6. 6
      src/Squidex.Domain.Apps.Read.MongoDb/Assets/MongoAssetRepository_EventHandling.cs
  7. 2
      src/Squidex.Domain.Apps.Read.MongoDb/Contents/MongoContentEntity.cs
  8. 8
      src/Squidex.Domain.Apps.Read.MongoDb/Contents/MongoContentRepository.cs
  9. 34
      src/Squidex.Domain.Apps.Read.MongoDb/Contents/MongoContentRepository_EventHandling.cs
  10. 8
      src/Squidex.Domain.Apps.Read.MongoDb/Contents/Visitors/FindExtensions.cs
  11. 4
      src/Squidex.Domain.Apps.Read.MongoDb/Schemas/MongoSchemaEntity.cs
  12. 2
      src/Squidex.Domain.Apps.Read/Assets/IAssetEntity.cs
  13. 8
      src/Squidex.Domain.Apps.Read/Contents/ContentQueryService.cs
  14. 4
      src/Squidex.Domain.Apps.Read/Contents/GraphQL/QueryContext.cs
  15. 2
      src/Squidex.Domain.Apps.Read/Contents/IContentEntity.cs
  16. 2
      src/Squidex.Domain.Apps.Read/Contents/IContentQueryService.cs
  17. 4
      src/Squidex.Domain.Apps.Read/Contents/Repositories/IContentRepository.cs
  18. 4
      src/Squidex.Domain.Apps.Read/Schemas/ISchemaEntity.cs
  19. 45
      src/Squidex.Domain.Apps.Write/Contents/ContentCommandMiddleware.cs
  20. 30
      src/Squidex.Domain.Apps.Write/Contents/ContentDomainObject.cs
  21. 4
      src/Squidex.Domain.Apps.Write/Schemas/Commands/ConfigureScripts.cs
  22. 2
      src/Squidex/Controllers/Api/Assets/AssetsController.cs
  23. 9
      src/Squidex/Controllers/Api/Schemas/Models/ConfigureScriptsDto.cs
  24. 9
      src/Squidex/Controllers/Api/Schemas/Models/SchemaDetailsDto.cs
  25. 19
      src/Squidex/Controllers/ContentApi/ContentsController.cs
  26. 25
      src/Squidex/Controllers/ContentApi/Generator/SchemaSwaggerGenerator.cs
  27. 21
      src/Squidex/Controllers/ContentApi/Models/ContentDto.cs
  28. 23
      tests/Squidex.Domain.Apps.Core.Tests/Scripting/JintScriptEngineTests.cs
  29. 6
      tests/Squidex.Domain.Apps.Read.Tests/Contents/ContentQueryServiceTests.cs
  30. 2
      tests/Squidex.Domain.Apps.Read.Tests/Contents/TestData/FakeContentEntity.cs
  31. 51
      tests/Squidex.Domain.Apps.Write.Tests/Contents/ContentCommandMiddlewareTests.cs
  32. 79
      tests/Squidex.Domain.Apps.Write.Tests/Contents/ContentDomainObjectTests.cs
  33. 6
      tests/Squidex.Domain.Apps.Write.Tests/Schemas/SchemaDomainObjectTests.cs

15
src/Squidex.Domain.Apps.Core/Scripting/JintScriptEngine.cs

@ -49,6 +49,16 @@ namespace Squidex.Domain.Apps.Core.Scripting
EnableDisallow(engine); EnableDisallow(engine);
EnableReject(engine, operationName); EnableReject(engine, operationName);
engine.SetValue("operation", new Action(() =>
{
var dataInstance = engine.GetValue("ctx").AsObject().Get("data");
if (dataInstance != null && dataInstance.IsObject() && dataInstance.AsObject() is ContentDataObject data)
{
data.TryUpdate(out result);
}
}));
engine.SetValue("replace", new Action(() => engine.SetValue("replace", new Action(() =>
{ {
var dataInstance = engine.GetValue("ctx").AsObject().Get("data"); var dataInstance = engine.GetValue("ctx").AsObject().Get("data");
@ -135,6 +145,11 @@ namespace Squidex.Domain.Apps.Core.Scripting
contextInstance.FastAddProperty("user", new JintUser(engine, context.User), false, true, false); contextInstance.FastAddProperty("user", new JintUser(engine, context.User), false, true, false);
} }
if (!string.IsNullOrWhiteSpace(context.Operation))
{
contextInstance.FastAddProperty("operation", context.Operation, false, true, false);
}
engine.SetValue("ctx", contextInstance); engine.SetValue("ctx", contextInstance);
return engine; return engine;

2
src/Squidex.Domain.Apps.Core/Scripting/ScriptContext.cs

@ -21,5 +21,7 @@ namespace Squidex.Domain.Apps.Core.Scripting
public NamedContentData Data { get; set; } public NamedContentData Data { get; set; }
public NamedContentData OldData { get; set; } public NamedContentData OldData { get; set; }
public string Operation { get; set; }
} }
} }

4
src/Squidex.Domain.Apps.Events/Schemas/ScriptsConfigured.cs

@ -21,8 +21,6 @@ namespace Squidex.Domain.Apps.Events.Schemas
public string ScriptDelete { get; set; } public string ScriptDelete { get; set; }
public string ScriptPublish { get; set; } public string ScriptChange { get; set; }
public string ScriptUnpublish { get; set; }
} }
} }

4
src/Squidex.Domain.Apps.Read.MongoDb/Assets/MongoAssetEntity.cs

@ -36,10 +36,6 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Assets
[BsonElement] [BsonElement]
public bool IsImage { get; set; } public bool IsImage { get; set; }
[BsonRequired]
[BsonElement]
public bool IsDeleted { get; set; }
[BsonRequired] [BsonRequired]
[BsonElement] [BsonElement]
public long Version { get; set; } public long Version { get; set; }

9
src/Squidex.Domain.Apps.Read.MongoDb/Assets/MongoAssetRepository.cs

@ -33,7 +33,11 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Assets
protected override Task SetupCollectionAsync(IMongoCollection<MongoAssetEntity> collection) protected override Task SetupCollectionAsync(IMongoCollection<MongoAssetEntity> collection)
{ {
return collection.Indexes.CreateOneAsync(Index.Ascending(x => x.AppId).Ascending(x => x.IsDeleted).Descending(x => x.LastModified).Ascending(x => x.FileName).Ascending(x => x.MimeType)); return collection.Indexes.CreateOneAsync(
Index.Ascending(x => x.AppId)
.Ascending(x => x.FileName)
.Ascending(x => x.MimeType)
.Descending(x => x.LastModified));
} }
public async Task<IReadOnlyList<Guid>> QueryNotFoundAsync(Guid appId, IList<Guid> assetIds) public async Task<IReadOnlyList<Guid>> QueryNotFoundAsync(Guid appId, IList<Guid> assetIds)
@ -80,8 +84,7 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Assets
{ {
var filters = new List<FilterDefinition<MongoAssetEntity>> var filters = new List<FilterDefinition<MongoAssetEntity>>
{ {
Filter.Eq(x => x.AppId, appId), Filter.Eq(x => x.AppId, appId)
Filter.Eq(x => x.IsDeleted, false)
}; };
if (ids != null && ids.Count > 0) if (ids != null && ids.Count > 0)

6
src/Squidex.Domain.Apps.Read.MongoDb/Assets/MongoAssetRepository_EventHandling.cs

@ -7,6 +7,7 @@
// ========================================================================== // ==========================================================================
using System.Threading.Tasks; using System.Threading.Tasks;
using MongoDB.Driver;
using Squidex.Domain.Apps.Events.Assets; using Squidex.Domain.Apps.Events.Assets;
using Squidex.Domain.Apps.Read.MongoDb.Utils; using Squidex.Domain.Apps.Read.MongoDb.Utils;
using Squidex.Infrastructure.CQRS.Events; using Squidex.Infrastructure.CQRS.Events;
@ -58,10 +59,7 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Assets
protected Task On(AssetDeleted @event, EnvelopeHeaders headers) protected Task On(AssetDeleted @event, EnvelopeHeaders headers)
{ {
return Collection.UpdateAsync(@event, headers, a => return Collection.DeleteOneAsync(x => x.Id == @event.AssetId);
{
a.IsDeleted = true;
});
} }
} }
} }

2
src/Squidex.Domain.Apps.Read.MongoDb/Contents/MongoContentEntity.cs

@ -49,7 +49,7 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Contents
[BsonRequired] [BsonRequired]
[BsonElement("dl")] [BsonElement("dl")]
public bool IsDeleted { get; set; } public bool IsArchived { get; set; }
[BsonRequired] [BsonRequired]
[BsonElement("dt")] [BsonElement("dt")]

8
src/Squidex.Domain.Apps.Read.MongoDb/Contents/MongoContentRepository.cs

@ -71,7 +71,7 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Contents
this.database = database; this.database = database;
} }
public async Task<IReadOnlyList<IContentEntity>> QueryAsync(IAppEntity app, ISchemaEntity schema, bool nonPublished, HashSet<Guid> ids, ODataUriParser odataQuery) public async Task<IReadOnlyList<IContentEntity>> QueryAsync(IAppEntity app, ISchemaEntity schema, bool nonPublished, bool archived, HashSet<Guid> ids, ODataUriParser odataQuery)
{ {
var collection = GetCollection(app.Id); var collection = GetCollection(app.Id);
@ -80,7 +80,7 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Contents
{ {
cursor = cursor =
collection collection
.Find(odataQuery, ids, schema.Id, schema.SchemaDef, nonPublished) .Find(odataQuery, ids, schema.Id, schema.SchemaDef, nonPublished, archived)
.Take(odataQuery) .Take(odataQuery)
.Skip(odataQuery) .Skip(odataQuery)
.Sort(odataQuery, schema.SchemaDef); .Sort(odataQuery, schema.SchemaDef);
@ -104,14 +104,14 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Contents
return entities; return entities;
} }
public Task<long> CountAsync(IAppEntity app, ISchemaEntity schema, bool nonPublished, HashSet<Guid> ids, ODataUriParser odataQuery) public Task<long> CountAsync(IAppEntity app, ISchemaEntity schema, bool nonPublished, bool archived, HashSet<Guid> ids, ODataUriParser odataQuery)
{ {
var collection = GetCollection(app.Id); var collection = GetCollection(app.Id);
IFindFluent<MongoContentEntity, MongoContentEntity> cursor; IFindFluent<MongoContentEntity, MongoContentEntity> cursor;
try try
{ {
cursor = collection.Find(odataQuery, ids, schema.Id, schema.SchemaDef, nonPublished); cursor = collection.Find(odataQuery, ids, schema.Id, schema.SchemaDef, nonPublished, archived);
} }
catch (NotSupportedException) catch (NotSupportedException)
{ {

34
src/Squidex.Domain.Apps.Read.MongoDb/Contents/MongoContentRepository_EventHandling.cs

@ -62,7 +62,7 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Contents
await collection.Indexes.CreateOneAsync(Index.Ascending(x => x.SchemaId).Descending(x => x.LastModified)); await collection.Indexes.CreateOneAsync(Index.Ascending(x => x.SchemaId).Descending(x => x.LastModified));
await collection.Indexes.CreateOneAsync(Index.Ascending(x => x.ReferencedIds)); await collection.Indexes.CreateOneAsync(Index.Ascending(x => x.ReferencedIds));
await collection.Indexes.CreateOneAsync(Index.Ascending(x => x.IsPublished)); await collection.Indexes.CreateOneAsync(Index.Ascending(x => x.IsPublished));
await collection.Indexes.CreateOneAsync(Index.Ascending(x => x.IsDeleted)); await collection.Indexes.CreateOneAsync(Index.Ascending(x => x.IsArchived));
await collection.Indexes.CreateOneAsync(Index.Text(x => x.DataText)); await collection.Indexes.CreateOneAsync(Index.Text(x => x.DataText));
}); });
} }
@ -115,30 +115,24 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Contents
}); });
} }
protected Task On(ContentRestored @event, EnvelopeHeaders headers) protected Task On(ContentArchived @event, EnvelopeHeaders headers)
{ {
return ForAppIdAsync(@event.AppId.Id, collection => return ForAppIdAsync(@event.AppId.Id, collection =>
{ {
return collection.UpdateAsync(@event, headers, x => return collection.UpdateAsync(@event, headers, x =>
{ {
x.IsDeleted = false; x.IsArchived = true;
}); });
}); });
} }
protected Task On(ContentDeleted @event, EnvelopeHeaders headers) protected Task On(ContentRestored @event, EnvelopeHeaders headers)
{ {
return ForAppIdAsync(@event.AppId.Id, async collection => return ForAppIdAsync(@event.AppId.Id, collection =>
{ {
await collection.UpdateManyAsync( return collection.UpdateAsync(@event, headers, x =>
Filter.And(
Filter.AnyEq(x => x.ReferencedIds, @event.ContentId),
Filter.AnyNe(x => x.ReferencedIdsDeleted, @event.ContentId)),
Update.AddToSet(x => x.ReferencedIdsDeleted, @event.ContentId));
await collection.UpdateAsync(@event, headers, x =>
{ {
x.IsDeleted = true; x.IsArchived = false;
}); });
}); });
} }
@ -155,6 +149,20 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Contents
}); });
} }
protected Task On(ContentDeleted @event, EnvelopeHeaders headers)
{
return ForAppIdAsync(@event.AppId.Id, async collection =>
{
await collection.UpdateManyAsync(
Filter.And(
Filter.AnyEq(x => x.ReferencedIds, @event.ContentId),
Filter.AnyNe(x => x.ReferencedIdsDeleted, @event.ContentId)),
Update.AddToSet(x => x.ReferencedIdsDeleted, @event.ContentId));
await collection.DeleteOneAsync(x => x.Id == @event.ContentId);
});
}
private Task ForAppIdAsync(Guid appId, Func<IMongoCollection<MongoContentEntity>, Task> action) private Task ForAppIdAsync(Guid appId, Func<IMongoCollection<MongoContentEntity>, Task> action)
{ {
var collection = GetCollection(appId); var collection = GetCollection(appId);

8
src/Squidex.Domain.Apps.Read.MongoDb/Contents/Visitors/FindExtensions.cs

@ -56,19 +56,19 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Contents.Visitors
return cursor; return cursor;
} }
public static IFindFluent<MongoContentEntity, MongoContentEntity> Find(this IMongoCollection<MongoContentEntity> cursor, ODataUriParser query, HashSet<Guid> ids, Guid schemaId, Schema schema, bool nonPublished) public static IFindFluent<MongoContentEntity, MongoContentEntity> Find(this IMongoCollection<MongoContentEntity> cursor, ODataUriParser query, HashSet<Guid> ids, Guid schemaId, Schema schema, bool nonPublished, bool archived)
{ {
var filter = BuildQuery(query, ids, schemaId, schema, nonPublished); var filter = BuildQuery(query, ids, schemaId, schema, nonPublished, archived);
return cursor.Find(filter); return cursor.Find(filter);
} }
public static FilterDefinition<MongoContentEntity> BuildQuery(ODataUriParser query, HashSet<Guid> ids, Guid schemaId, Schema schema, bool nonPublished) public static FilterDefinition<MongoContentEntity> BuildQuery(ODataUriParser query, HashSet<Guid> ids, Guid schemaId, Schema schema, bool nonPublished, bool archived)
{ {
var filters = new List<FilterDefinition<MongoContentEntity>> var filters = new List<FilterDefinition<MongoContentEntity>>
{ {
Filter.Eq(x => x.SchemaId, schemaId), Filter.Eq(x => x.SchemaId, schemaId),
Filter.Eq(x => x.IsDeleted, false) Filter.Eq(x => x.IsArchived, archived)
}; };
if (!nonPublished) if (!nonPublished)

4
src/Squidex.Domain.Apps.Read.MongoDb/Schemas/MongoSchemaEntity.cs

@ -25,8 +25,6 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Schemas
[BsonElement] [BsonElement]
public string Name { get; set; } public string Name { get; set; }
public string ScriptUnpublish { get; set; }
[BsonRequired] [BsonRequired]
[BsonElement] [BsonElement]
public string Schema { get; set; } public string Schema { get; set; }
@ -73,7 +71,7 @@ namespace Squidex.Domain.Apps.Read.MongoDb.Schemas
[BsonIgnoreIfNull] [BsonIgnoreIfNull]
[BsonElement] [BsonElement]
public string ScriptPublish { get; set; } public string ScriptChange { get; set; }
Schema ISchemaEntity.SchemaDef Schema ISchemaEntity.SchemaDef
{ {

2
src/Squidex.Domain.Apps.Read/Assets/IAssetEntity.cs

@ -20,8 +20,6 @@ namespace Squidex.Domain.Apps.Read.Assets
bool IsImage { get; } bool IsImage { get; }
bool IsDeleted { get; }
int? PixelWidth { get; } int? PixelWidth { get; }
int? PixelHeight { get; } int? PixelHeight { get; }

8
src/Squidex.Domain.Apps.Read/Contents/ContentQueryService.cs

@ -73,7 +73,7 @@ namespace Squidex.Domain.Apps.Read.Contents
return (schema, content); return (schema, content);
} }
public async Task<(ISchemaEntity Schema, long Total, IReadOnlyList<IContentEntity> Items)> QueryWithCountAsync(IAppEntity app, string schemaIdOrName, ClaimsPrincipal user, HashSet<Guid> ids, string query) public async Task<(ISchemaEntity Schema, long Total, IReadOnlyList<IContentEntity> Items)> QueryWithCountAsync(IAppEntity app, string schemaIdOrName, ClaimsPrincipal user, bool archived, HashSet<Guid> ids, string query)
{ {
Guard.NotNull(app, nameof(app)); Guard.NotNull(app, nameof(app));
Guard.NotNull(user, nameof(user)); Guard.NotNull(user, nameof(user));
@ -85,8 +85,8 @@ namespace Squidex.Domain.Apps.Read.Contents
var isFrontendClient = user.IsInClient("squidex-frontend"); var isFrontendClient = user.IsInClient("squidex-frontend");
var taskForItems = contentRepository.QueryAsync(app, schema, isFrontendClient, ids, parsedQuery); var taskForItems = contentRepository.QueryAsync(app, schema, isFrontendClient, archived, ids, parsedQuery);
var taskForCount = contentRepository.CountAsync(app, schema, isFrontendClient, ids, parsedQuery); var taskForCount = contentRepository.CountAsync(app, schema, isFrontendClient, archived, ids, parsedQuery);
await Task.WhenAll(taskForItems, taskForCount); await Task.WhenAll(taskForItems, taskForCount);
@ -156,7 +156,7 @@ namespace Squidex.Domain.Apps.Read.Contents
public Guid Id { get; set; } public Guid Id { get; set; }
public Guid AppId { get; set; } public Guid AppId { get; set; }
public long Version { get; set; } public long Version { get; set; }
public bool IsDeleted { get; set; } public bool IsArchived { get; set; }
public bool IsPublished { get; set; } public bool IsPublished { get; set; }
public Instant Created { get; set; } public Instant Created { get; set; }
public Instant LastModified { get; set; } public Instant LastModified { get; set; }

4
src/Squidex.Domain.Apps.Read/Contents/GraphQL/QueryContext.cs

@ -105,7 +105,7 @@ namespace Squidex.Domain.Apps.Read.Contents.GraphQL
public async Task<IReadOnlyList<IContentEntity>> QueryContentsAsync(Guid schemaId, string query) public async Task<IReadOnlyList<IContentEntity>> QueryContentsAsync(Guid schemaId, string query)
{ {
var contents = (await contentQuery.QueryWithCountAsync(app, schemaId.ToString(), user, null, query).ConfigureAwait(false)).Items; var contents = (await contentQuery.QueryWithCountAsync(app, schemaId.ToString(), user, false, null, query).ConfigureAwait(false)).Items;
foreach (var content in contents) foreach (var content in contents)
{ {
@ -156,7 +156,7 @@ namespace Squidex.Domain.Apps.Read.Contents.GraphQL
if (notLoadedContents.Count > 0) if (notLoadedContents.Count > 0)
{ {
var contents = (await contentQuery.QueryWithCountAsync(app, schemaId.ToString(), user, notLoadedContents, null).ConfigureAwait(false)).Items; var contents = (await contentQuery.QueryWithCountAsync(app, schemaId.ToString(), user, false, notLoadedContents, null).ConfigureAwait(false)).Items;
foreach (var content in contents) foreach (var content in contents)
{ {

2
src/Squidex.Domain.Apps.Read/Contents/IContentEntity.cs

@ -14,7 +14,7 @@ namespace Squidex.Domain.Apps.Read.Contents
{ {
bool IsPublished { get; } bool IsPublished { get; }
bool IsDeleted { get; } bool IsArchived { get; }
NamedContentData Data { get; } NamedContentData Data { get; }
} }

2
src/Squidex.Domain.Apps.Read/Contents/IContentQueryService.cs

@ -17,7 +17,7 @@ namespace Squidex.Domain.Apps.Read.Contents
{ {
public interface IContentQueryService public interface IContentQueryService
{ {
Task<(ISchemaEntity Schema, long Total, IReadOnlyList<IContentEntity> Items)> QueryWithCountAsync(IAppEntity app, string schemaIdOrName, ClaimsPrincipal user, HashSet<Guid> ids, string query); Task<(ISchemaEntity Schema, long Total, IReadOnlyList<IContentEntity> Items)> QueryWithCountAsync(IAppEntity app, string schemaIdOrName, ClaimsPrincipal user, bool archived, HashSet<Guid> ids, string query);
Task<(ISchemaEntity Schema, IContentEntity Content)> FindContentAsync(IAppEntity app, string schemaIdOrName, ClaimsPrincipal user, Guid id); Task<(ISchemaEntity Schema, IContentEntity Content)> FindContentAsync(IAppEntity app, string schemaIdOrName, ClaimsPrincipal user, Guid id);

4
src/Squidex.Domain.Apps.Read/Contents/Repositories/IContentRepository.cs

@ -17,11 +17,11 @@ namespace Squidex.Domain.Apps.Read.Contents.Repositories
{ {
public interface IContentRepository public interface IContentRepository
{ {
Task<IReadOnlyList<IContentEntity>> QueryAsync(IAppEntity app, ISchemaEntity schema, bool nonPublished, HashSet<Guid> ids, ODataUriParser odataQuery); Task<IReadOnlyList<IContentEntity>> QueryAsync(IAppEntity app, ISchemaEntity schema, bool nonPublished, bool archived, HashSet<Guid> ids, ODataUriParser odataQuery);
Task<IReadOnlyList<Guid>> QueryNotFoundAsync(Guid appId, Guid schemaId, IList<Guid> contentIds); Task<IReadOnlyList<Guid>> QueryNotFoundAsync(Guid appId, Guid schemaId, IList<Guid> contentIds);
Task<long> CountAsync(IAppEntity app, ISchemaEntity schema, bool nonPublished, HashSet<Guid> ids, ODataUriParser odataQuery); Task<long> CountAsync(IAppEntity app, ISchemaEntity schema, bool nonPublished, bool archived, HashSet<Guid> ids, ODataUriParser odataQuery);
Task<IContentEntity> FindContentAsync(IAppEntity app, ISchemaEntity schema, Guid id); Task<IContentEntity> FindContentAsync(IAppEntity app, ISchemaEntity schema, Guid id);
} }

4
src/Squidex.Domain.Apps.Read/Schemas/ISchemaEntity.cs

@ -26,9 +26,7 @@ namespace Squidex.Domain.Apps.Read.Schemas
string ScriptDelete { get; } string ScriptDelete { get; }
string ScriptPublish { get; } string ScriptChange { get; }
string ScriptUnpublish { get; }
Schema SchemaDef { get; } Schema SchemaDef { get; }
} }

45
src/Squidex.Domain.Apps.Write/Contents/ContentCommandMiddleware.cs

@ -116,9 +116,9 @@ namespace Squidex.Domain.Apps.Write.Contents
return handler.UpdateAsync<ContentDomainObject>(context, async content => return handler.UpdateAsync<ContentDomainObject>(context, async content =>
{ {
var schemaAndApp = await ResolveSchemaAndAppAsync(command); var schemaAndApp = await ResolveSchemaAndAppAsync(command);
var scriptContext = CreateScriptContext(content, command); var scriptContext = CreateScriptContext(content, command, "Publish");
scriptEngine.Execute(scriptContext, schemaAndApp.SchemaEntity.ScriptPublish, "publish content"); scriptEngine.Execute(scriptContext, schemaAndApp.SchemaEntity.ScriptChange, "publish content");
content.Publish(command); content.Publish(command);
}); });
@ -129,35 +129,53 @@ namespace Squidex.Domain.Apps.Write.Contents
return handler.UpdateAsync<ContentDomainObject>(context, async content => return handler.UpdateAsync<ContentDomainObject>(context, async content =>
{ {
var schemaAndApp = await ResolveSchemaAndAppAsync(command); var schemaAndApp = await ResolveSchemaAndAppAsync(command);
var scriptContext = CreateScriptContext(content, command); var scriptContext = CreateScriptContext(content, command, "Unpublish");
scriptEngine.Execute(scriptContext, schemaAndApp.SchemaEntity.ScriptUnpublish, "unpublish content"); scriptEngine.Execute(scriptContext, schemaAndApp.SchemaEntity.ScriptChange, "unpublish content");
content.Unpublish(command); content.Unpublish(command);
}); });
} }
protected Task On(DeleteContent command, CommandContext context) protected Task On(ArchiveContent command, CommandContext context)
{ {
return handler.UpdateAsync<ContentDomainObject>(context, async content => return handler.UpdateAsync<ContentDomainObject>(context, async content =>
{ {
var schemaAndApp = await ResolveSchemaAndAppAsync(command); var schemaAndApp = await ResolveSchemaAndAppAsync(command);
var scriptContext = CreateScriptContext(content, command); var scriptContext = CreateScriptContext(content, command, "Archive");
scriptEngine.Execute(scriptContext, schemaAndApp.SchemaEntity.ScriptDelete, "delete content"); scriptEngine.Execute(scriptContext, schemaAndApp.SchemaEntity.ScriptChange, "archive content");
content.Delete(command); content.Archive(command);
}); });
} }
protected Task On(RestoreContent command, CommandContext context) protected Task On(RestoreContent command, CommandContext context)
{ {
return handler.UpdateAsync<ContentDomainObject>(context, content => return handler.UpdateAsync<ContentDomainObject>(context, async content =>
{ {
var schemaAndApp = await ResolveSchemaAndAppAsync(command);
var scriptContext = CreateScriptContext(content, command, "Restore");
scriptEngine.Execute(scriptContext, schemaAndApp.SchemaEntity.ScriptChange, "restore content");
content.Restore(command); content.Restore(command);
}); });
} }
protected Task On(DeleteContent command, CommandContext context)
{
return handler.UpdateAsync<ContentDomainObject>(context, async content =>
{
var schemaAndApp = await ResolveSchemaAndAppAsync(command);
var scriptContext = CreateScriptContext(content, command, "Delete");
scriptEngine.Execute(scriptContext, schemaAndApp.SchemaEntity.ScriptDelete, "delete content");
content.Delete(command);
});
}
public async Task HandleAsync(CommandContext context, Func<Task> next) public async Task HandleAsync(CommandContext context, Func<Task> next)
{ {
if (!await this.DispatchActionAsync(context.Command, context)) if (!await this.DispatchActionAsync(context.Command, context))
@ -200,9 +218,14 @@ namespace Squidex.Domain.Apps.Write.Contents
} }
} }
private static ScriptContext CreateScriptContext(ContentDomainObject content, ContentCommand command, NamedContentData data = null) private static ScriptContext CreateScriptContext(ContentDomainObject content, ContentCommand command, string operation)
{
return new ScriptContext { ContentId = content.Id, OldData = content.Data, User = command.User, Operation = operation };
}
private static ScriptContext CreateScriptContext(ContentDomainObject content, ContentCommand command, NamedContentData data)
{ {
return new ScriptContext { ContentId = content.Id, Data = data, OldData = content.Data, User = command.User }; return new ScriptContext { ContentId = content.Id, OldData = content.Data, User = command.User, Data = data };
} }
private async Task<(ISchemaEntity SchemaEntity, IAppEntity AppEntity)> ResolveSchemaAndAppAsync(SchemaCommand command) private async Task<(ISchemaEntity SchemaEntity, IAppEntity AppEntity)> ResolveSchemaAndAppAsync(SchemaCommand command)

30
src/Squidex.Domain.Apps.Write/Contents/ContentDomainObject.cs

@ -23,6 +23,7 @@ namespace Squidex.Domain.Apps.Write.Contents
private bool isDeleted; private bool isDeleted;
private bool isCreated; private bool isCreated;
private bool isPublished; private bool isPublished;
private bool isArchived;
private NamedContentData data; private NamedContentData data;
public bool IsDeleted public bool IsDeleted
@ -30,6 +31,11 @@ namespace Squidex.Domain.Apps.Write.Contents
get { return isDeleted; } get { return isDeleted; }
} }
public bool IsArchived
{
get { return isArchived; }
}
public bool IsPublished public bool IsPublished
{ {
get { return isPublished; } get { return isPublished; }
@ -67,14 +73,19 @@ namespace Squidex.Domain.Apps.Write.Contents
isPublished = false; isPublished = false;
} }
protected void On(ContentDeleted @event) protected void On(ContentArchived @event)
{ {
isDeleted = true; isArchived = true;
} }
protected void On(ContentRestored @event) protected void On(ContentRestored @event)
{ {
isDeleted = false; isArchived = false;
}
protected void On(ContentDeleted @event)
{
isDeleted = true;
} }
public ContentDomainObject Create(CreateContent command) public ContentDomainObject Create(CreateContent command)
@ -108,13 +119,24 @@ namespace Squidex.Domain.Apps.Write.Contents
{ {
Guard.NotNull(command, nameof(command)); Guard.NotNull(command, nameof(command));
VerifyDeleted(); VerifyCreatedAndNotDeleted();
RaiseEvent(SimpleMapper.Map(command, new ContentRestored())); RaiseEvent(SimpleMapper.Map(command, new ContentRestored()));
return this; return this;
} }
public ContentDomainObject Archive(ArchiveContent command)
{
Guard.NotNull(command, nameof(command));
VerifyCreatedAndNotDeleted();
RaiseEvent(SimpleMapper.Map(command, new ContentArchived()));
return this;
}
public ContentDomainObject Publish(PublishContent command) public ContentDomainObject Publish(PublishContent command)
{ {
Guard.NotNull(command, nameof(command)); Guard.NotNull(command, nameof(command));

4
src/Squidex.Domain.Apps.Write/Schemas/Commands/ConfigureScripts.cs

@ -18,8 +18,6 @@ namespace Squidex.Domain.Apps.Write.Schemas.Commands
public string ScriptDelete { get; set; } public string ScriptDelete { get; set; }
public string ScriptPublish { get; set; } public string ScriptChange { get; set; }
public string ScriptUnpublish { get; set; }
} }
} }

2
src/Squidex/Controllers/Api/Assets/AssetsController.cs

@ -133,7 +133,7 @@ namespace Squidex.Controllers.Api.Assets
{ {
var entity = await assetRepository.FindAssetAsync(id); var entity = await assetRepository.FindAssetAsync(id);
if (entity == null || entity.IsDeleted) if (entity == null)
{ {
return NotFound(); return NotFound();
} }

9
src/Squidex/Controllers/Api/Schemas/Models/ConfigureScriptsDto.cs

@ -31,13 +31,8 @@ namespace Squidex.Controllers.Api.Schemas.Models
public string ScriptDelete { get; set; } public string ScriptDelete { get; set; }
/// <summary> /// <summary>
/// The script that is executed when publishing a content. /// The script that is executed when change a content status.
/// </summary> /// </summary>
public string ScriptPublish { get; set; } public string ScriptChange { get; set; }
/// <summary>
/// The script that is executed when unpublishing a content.
/// </summary>
public string ScriptUnpublish { get; set; }
} }
} }

9
src/Squidex/Controllers/Api/Schemas/Models/SchemaDetailsDto.cs

@ -54,14 +54,9 @@ namespace Squidex.Controllers.Api.Schemas.Models
public string ScriptDelete { get; set; } public string ScriptDelete { get; set; }
/// <summary> /// <summary>
/// The script that is executed when publishing a content. /// The script that is executed when changing a content status.
/// </summary> /// </summary>
public string ScriptPublish { get; set; } public string ScriptChange { get; set; }
/// <summary>
/// The script that is executed when unpublishing a content.
/// </summary>
public string ScriptUnpublish { get; set; }
/// <summary> /// <summary>
/// The list of fields. /// The list of fields.

19
src/Squidex/Controllers/ContentApi/ContentsController.cs

@ -69,7 +69,7 @@ namespace Squidex.Controllers.ContentApi
[HttpGet] [HttpGet]
[Route("content/{app}/{name}")] [Route("content/{app}/{name}")]
[ApiCosts(2)] [ApiCosts(2)]
public async Task<IActionResult> GetContents(string name, [FromQuery] string ids = null) public async Task<IActionResult> GetContents(string name, [FromQuery] bool archived = false, [FromQuery] string ids = null)
{ {
var idsList = new HashSet<Guid>(); var idsList = new HashSet<Guid>();
@ -86,7 +86,7 @@ namespace Squidex.Controllers.ContentApi
var isFrontendClient = User.IsFrontendClient(); var isFrontendClient = User.IsFrontendClient();
var contents = await contentQuery.QueryWithCountAsync(App, name, User, idsList, Request.QueryString.ToString()); var contents = await contentQuery.QueryWithCountAsync(App, name, User, archived, idsList, Request.QueryString.ToString());
var response = new AssetsDto var response = new AssetsDto
{ {
@ -228,6 +228,21 @@ namespace Squidex.Controllers.ContentApi
return NoContent(); return NoContent();
} }
[MustBeAppEditor]
[HttpPut]
[Route("content/{app}/{name}/{id}/archive")]
[ApiCosts(1)]
public async Task<IActionResult> ArchiveContent(string name, Guid id)
{
await contentQuery.FindSchemaAsync(App, name);
var command = new ArchiveContent { ContentId = id, User = User };
await CommandBus.PublishAsync(command);
return NoContent();
}
[MustBeAppEditor] [MustBeAppEditor]
[HttpPut] [HttpPut]
[Route("content/{app}/{name}/{id}/restore")] [Route("content/{app}/{name}/{id}/restore")]

25
src/Squidex/Controllers/ContentApi/Generator/SchemaSwaggerGenerator.cs

@ -92,9 +92,10 @@ namespace Squidex.Controllers.ContentApi.Generator
GenerateSchemaGetOperation(), GenerateSchemaGetOperation(),
GenerateSchemaUpdateOperation(), GenerateSchemaUpdateOperation(),
GenerateSchemaPatchOperation(), GenerateSchemaPatchOperation(),
GenerateSchemaRestoreOperation(),
GenerateSchemaPublishOperation(), GenerateSchemaPublishOperation(),
GenerateSchemaUnpublishOperation(), GenerateSchemaUnpublishOperation(),
GenerateSchemaArchiveOperation(),
GenerateSchemaRestoreOperation(),
GenerateSchemaDeleteOperation() GenerateSchemaDeleteOperation()
}; };
@ -161,7 +162,7 @@ namespace Squidex.Controllers.ContentApi.Generator
operation.AddBodyParameter("data", dataSchema, SchemaBodyDescription); operation.AddBodyParameter("data", dataSchema, SchemaBodyDescription);
operation.AddResponse("201", $"{schemaName} element updated.", dataSchema); operation.AddResponse("201", $"{schemaName} item updated.", dataSchema);
}); });
} }
@ -175,7 +176,7 @@ namespace Squidex.Controllers.ContentApi.Generator
operation.AddBodyParameter("data", contentSchema, SchemaBodyDescription); operation.AddBodyParameter("data", contentSchema, SchemaBodyDescription);
operation.AddResponse("201", $"{schemaName} element patched.", dataSchema); operation.AddResponse("201", $"{schemaName} item patched.", dataSchema);
}); });
} }
@ -187,7 +188,7 @@ namespace Squidex.Controllers.ContentApi.Generator
operation.Summary = $"Publish a {schemaName} content."; operation.Summary = $"Publish a {schemaName} content.";
operation.Security = EditorSecurity; operation.Security = EditorSecurity;
operation.AddResponse("204", $"{schemaName} element published."); operation.AddResponse("204", $"{schemaName} item published.");
}); });
} }
@ -199,7 +200,19 @@ namespace Squidex.Controllers.ContentApi.Generator
operation.Summary = $"Unpublish a {schemaName} content."; operation.Summary = $"Unpublish a {schemaName} content.";
operation.Security = EditorSecurity; operation.Security = EditorSecurity;
operation.AddResponse("204", $"{schemaName} element unpublished."); operation.AddResponse("204", $"{schemaName} item unpublished.");
});
}
private SwaggerOperations GenerateSchemaArchiveOperation()
{
return AddOperation(SwaggerOperationMethod.Put, schemaName, $"{appPath}/{schemaPath}/{{id}}/archive", operation =>
{
operation.OperationId = $"Archive{schemaKey}Content";
operation.Summary = $"Archive a {schemaName} content.";
operation.Security = EditorSecurity;
operation.AddResponse("204", $"{schemaName} item restored.");
}); });
} }
@ -211,7 +224,7 @@ namespace Squidex.Controllers.ContentApi.Generator
operation.Summary = $"Restore a {schemaName} content."; operation.Summary = $"Restore a {schemaName} content.";
operation.Security = EditorSecurity; operation.Security = EditorSecurity;
operation.AddResponse("204", $"{schemaName} element restored."); operation.AddResponse("204", $"{schemaName} item restored.");
}); });
} }

21
src/Squidex/Controllers/ContentApi/Models/ContentDto.cs

@ -19,18 +19,18 @@ namespace Squidex.Controllers.ContentApi.Models
public sealed class ContentDto public sealed class ContentDto
{ {
/// <summary> /// <summary>
/// The if of the content element. /// The if of the content item.
/// </summary> /// </summary>
public Guid Id { get; set; } public Guid Id { get; set; }
/// <summary> /// <summary>
/// The user that has created the content element. /// The user that has created the content item.
/// </summary> /// </summary>
[Required] [Required]
public RefToken CreatedBy { get; set; } public RefToken CreatedBy { get; set; }
/// <summary> /// <summary>
/// The user that has updated the content element. /// The user that has updated the content item.
/// </summary> /// </summary>
[Required] [Required]
public RefToken LastModifiedBy { get; set; } public RefToken LastModifiedBy { get; set; }
@ -42,35 +42,30 @@ namespace Squidex.Controllers.ContentApi.Models
public object Data { get; set; } public object Data { get; set; }
/// <summary> /// <summary>
/// The date and time when the content element has been created. /// The date and time when the content item has been created.
/// </summary> /// </summary>
public Instant Created { get; set; } public Instant Created { get; set; }
/// <summary> /// <summary>
/// The date and time when the content element has been modified last. /// The date and time when the content item has been modified last.
/// </summary> /// </summary>
public Instant LastModified { get; set; } public Instant LastModified { get; set; }
/// <summary> /// <summary>
/// Indicates if the content element is published. /// Indicates if the content item is published.
/// </summary> /// </summary>
public bool? IsPublished { get; set; } public bool? IsPublished { get; set; }
/// <summary> /// <summary>
/// Indicates if the content element is deleted. /// Indicates if the content item is archived.
/// </summary> /// </summary>
public bool IsDeleted { get; set; } public bool IsArchived { get; set; }
/// <summary> /// <summary>
/// The version of the content. /// The version of the content.
/// </summary> /// </summary>
public long Version { get; set; } public long Version { get; set; }
public bool ShouldSerializeIsDeleted()
{
return IsDeleted;
}
public static ContentDto Create(CreateContent command, EntityCreatedResult<NamedContentData> result) public static ContentDto Create(CreateContent command, EntityCreatedResult<NamedContentData> result)
{ {
var now = SystemClock.Instance.GetCurrentInstant(); var now = SystemClock.Instance.GetCurrentInstant();

23
tests/Squidex.Domain.Apps.Core.Tests/Scripting/JintScriptEngineTests.cs

@ -80,6 +80,29 @@ namespace Squidex.Domain.Apps.Core.Scripting
Assert.Same(content, result); Assert.Same(content, result);
} }
[Fact]
public void Should_fetch_operation_name()
{
var content = new NamedContentData();
var expected =
new NamedContentData()
.AddField("operation",
new ContentFieldData()
.AddValue("iv", "MyOperation"));
var context = new ScriptContext { Data = content, Operation = "MyOperation" };
var result = scriptEngine.ExecuteAndTransform(context, @"
var data = ctx.data;
data.operation = { iv: ctx.operation };
replace(data)", "update");
Assert.Equal(expected, result);
}
[Fact] [Fact]
public void Should_transform_content_and_return_with_transform() public void Should_transform_content_and_return_with_transform()
{ {

6
tests/Squidex.Domain.Apps.Read.Tests/Contents/ContentQueryServiceTests.cs

@ -122,9 +122,9 @@ namespace Squidex.Domain.Apps.Read.Contents
A.CallTo(() => schemas.FindSchemaByIdAsync(schemaId, false)) A.CallTo(() => schemas.FindSchemaByIdAsync(schemaId, false))
.Returns(schema); .Returns(schema);
A.CallTo(() => contentRepository.QueryAsync(app, schema, false, ids, A<ODataUriParser>.Ignored)) A.CallTo(() => contentRepository.QueryAsync(app, schema, false, true, ids, A<ODataUriParser>.Ignored))
.Returns(new List<IContentEntity> { content }); .Returns(new List<IContentEntity> { content });
A.CallTo(() => contentRepository.CountAsync(app, schema, false, ids, A<ODataUriParser>.Ignored)) A.CallTo(() => contentRepository.CountAsync(app, schema, false, true, ids, A<ODataUriParser>.Ignored))
.Returns(123); .Returns(123);
A.CallTo(() => schema.ScriptQuery) A.CallTo(() => schema.ScriptQuery)
@ -133,7 +133,7 @@ namespace Squidex.Domain.Apps.Read.Contents
A.CallTo(() => scriptEngine.Transform(A<ScriptContext>.That.Matches(x => x.User == user && x.ContentId == contentId && ReferenceEquals(x.Data, data)), "<query-script>")) A.CallTo(() => scriptEngine.Transform(A<ScriptContext>.That.Matches(x => x.User == user && x.ContentId == contentId && ReferenceEquals(x.Data, data)), "<query-script>"))
.Returns(transformedData); .Returns(transformedData);
var result = await sut.QueryWithCountAsync(app, schemaId.ToString(), user, ids, null); var result = await sut.QueryWithCountAsync(app, schemaId.ToString(), user, true, ids, null);
Assert.Equal(123, result.Total); Assert.Equal(123, result.Total);
Assert.Equal(schema, result.Schema); Assert.Equal(schema, result.Schema);

2
tests/Squidex.Domain.Apps.Read.Tests/Contents/TestData/FakeContentEntity.cs

@ -31,6 +31,8 @@ namespace Squidex.Domain.Apps.Read.Contents.TestData
public bool IsPublished { get; set; } public bool IsPublished { get; set; }
public bool IsArchived { get; set; }
public NamedContentData Data { get; set; } public NamedContentData Data { get; set; }
} }
} }

51
tests/Squidex.Domain.Apps.Write.Tests/Contents/ContentCommandMiddlewareTests.cs

@ -178,8 +178,8 @@ namespace Squidex.Domain.Apps.Write.Contents
[Fact] [Fact]
public async Task Publish_should_publish_domain_object() public async Task Publish_should_publish_domain_object()
{ {
A.CallTo(() => schema.ScriptPublish) A.CallTo(() => schema.ScriptChange)
.Returns("<publish-script>"); .Returns("<change-script>");
CreateContent(); CreateContent();
@ -190,14 +190,14 @@ namespace Squidex.Domain.Apps.Write.Contents
await sut.HandleAsync(context); await sut.HandleAsync(context);
}); });
A.CallTo(() => scriptEngine.Execute(A<ScriptContext>.Ignored, "<publish-script>", "publish content")).MustHaveHappened(); A.CallTo(() => scriptEngine.Execute(A<ScriptContext>.Ignored, "<change-script>", "publish content")).MustHaveHappened();
} }
[Fact] [Fact]
public async Task Unpublish_should_unpublish_domain_object() public async Task Unpublish_should_unpublish_domain_object()
{ {
A.CallTo(() => schema.ScriptUnpublish) A.CallTo(() => schema.ScriptChange)
.Returns("<unpublish-script>"); .Returns("<change-script>");
CreateContent(); CreateContent();
@ -208,40 +208,61 @@ namespace Squidex.Domain.Apps.Write.Contents
await sut.HandleAsync(context); await sut.HandleAsync(context);
}); });
A.CallTo(() => scriptEngine.Execute(A<ScriptContext>.Ignored, "<unpublish-script>", "unpublish content")).MustHaveHappened(); A.CallTo(() => scriptEngine.Execute(A<ScriptContext>.Ignored, "<change-script>", "unpublish content")).MustHaveHappened();
} }
[Fact] [Fact]
public async Task Delete_should_update_domain_object() public async Task Archive_should_archive_domain_object()
{ {
A.CallTo(() => schema.ScriptDelete) A.CallTo(() => schema.ScriptChange)
.Returns("<delete-script>"); .Returns("<change-script>");
CreateContent(); CreateContent();
var command = CreateContextForCommand(new DeleteContent { ContentId = contentId, User = user }); var context = CreateContextForCommand(new ArchiveContent { ContentId = contentId, User = user });
await TestUpdate(content, async _ => await TestUpdate(content, async _ =>
{ {
await sut.HandleAsync(command); await sut.HandleAsync(context);
}); });
A.CallTo(() => scriptEngine.Execute(A<ScriptContext>.Ignored, "<delete-script>", "delete content")).MustHaveHappened(); A.CallTo(() => scriptEngine.Execute(A<ScriptContext>.Ignored, "<change-script>", "archive content")).MustHaveHappened();
} }
[Fact] [Fact]
public async Task Restore_should_update_domain_object() public async Task Restore_should_restore_domain_object()
{ {
A.CallTo(() => schema.ScriptChange)
.Returns("<change-script>");
CreateContent(); CreateContent();
content.Delete(new DeleteContent()); var context = CreateContextForCommand(new RestoreContent { ContentId = contentId, User = user });
await TestUpdate(content, async _ =>
{
await sut.HandleAsync(context);
});
A.CallTo(() => scriptEngine.Execute(A<ScriptContext>.Ignored, "<change-script>", "restore content")).MustHaveHappened();
}
var command = CreateContextForCommand(new RestoreContent { ContentId = contentId, User = user }); [Fact]
public async Task Delete_should_update_domain_object()
{
A.CallTo(() => schema.ScriptDelete)
.Returns("<delete-script>");
CreateContent();
var command = CreateContextForCommand(new DeleteContent { ContentId = contentId, User = user });
await TestUpdate(content, async _ => await TestUpdate(content, async _ =>
{ {
await sut.HandleAsync(command); await sut.HandleAsync(command);
}); });
A.CallTo(() => scriptEngine.Execute(A<ScriptContext>.Ignored, "<delete-script>", "delete content")).MustHaveHappened();
} }
private void CreateContent() private void CreateContent()

79
tests/Squidex.Domain.Apps.Write.Tests/Contents/ContentDomainObjectTests.cs

@ -268,59 +268,71 @@ namespace Squidex.Domain.Apps.Write.Contents
} }
[Fact] [Fact]
public void Delete_should_throw_exception_if_not_created() public void Archive_should_throw_exception_if_not_created()
{ {
Assert.Throws<DomainException>(() => Assert.Throws<DomainException>(() =>
{ {
sut.Delete(CreateContentCommand(new DeleteContent())); sut.Archive(CreateContentCommand(new ArchiveContent()));
}); });
} }
[Fact] [Fact]
public void Delete_should_throw_exception_if_already_deleted() public void Archive_should_throw_exception_if_content_is_deleted()
{ {
CreateContent(); CreateContent();
DeleteContent(); DeleteContent();
Assert.Throws<DomainException>(() => Assert.Throws<DomainException>(() =>
{ {
sut.Delete(CreateContentCommand(new DeleteContent())); sut.Archive(CreateContentCommand(new ArchiveContent()));
}); });
} }
[Fact] [Fact]
public void Delete_should_update_properties_create_events() public void Archive_should_refresh_properties_and_create_events()
{ {
CreateContent(); CreateContent();
sut.Delete(CreateContentCommand(new DeleteContent())); sut.Archive(CreateContentCommand(new ArchiveContent()));
Assert.True(sut.IsDeleted); Assert.True(sut.IsArchived);
sut.GetUncomittedEvents() sut.GetUncomittedEvents()
.ShouldHaveSameEvents( .ShouldHaveSameEvents(
CreateContentEvent(new ContentDeleted()) CreateContentEvent(new ContentArchived())
); );
} }
[Fact] [Fact]
public void Restore_should_throw_exception_if_not_deleted() public void Restore_should_throw_exception_if_not_created()
{ {
Assert.Throws<DomainException>(() => Assert.Throws<DomainException>(() =>
{ {
sut.Delete(CreateContentCommand(new DeleteContent())); sut.Restore(CreateContentCommand(new RestoreContent()));
}); });
} }
[Fact] [Fact]
public void Restore_should_update_properties_create_events() public void Restore_should_throw_exception_if_content_is_deleted()
{ {
CreateContent(); CreateContent();
DeleteContent(); DeleteContent();
Assert.Throws<DomainException>(() =>
{
sut.Restore(CreateContentCommand(new RestoreContent())); sut.Restore(CreateContentCommand(new RestoreContent()));
});
}
Assert.False(sut.IsDeleted); [Fact]
public void Restore_should_refresh_properties_and_create_events()
{
CreateContent();
ArchiveContent();
sut.Restore(CreateContentCommand(new RestoreContent()));
Assert.False(sut.IsArchived);
sut.GetUncomittedEvents() sut.GetUncomittedEvents()
.ShouldHaveSameEvents( .ShouldHaveSameEvents(
@ -328,6 +340,42 @@ namespace Squidex.Domain.Apps.Write.Contents
); );
} }
[Fact]
public void Delete_should_throw_exception_if_not_created()
{
Assert.Throws<DomainException>(() =>
{
sut.Delete(CreateContentCommand(new DeleteContent()));
});
}
[Fact]
public void Delete_should_throw_exception_if_already_deleted()
{
CreateContent();
DeleteContent();
Assert.Throws<DomainException>(() =>
{
sut.Delete(CreateContentCommand(new DeleteContent()));
});
}
[Fact]
public void Delete_should_update_properties_create_events()
{
CreateContent();
sut.Delete(CreateContentCommand(new DeleteContent()));
Assert.True(sut.IsDeleted);
sut.GetUncomittedEvents()
.ShouldHaveSameEvents(
CreateContentEvent(new ContentDeleted())
);
}
private void CreateContent() private void CreateContent()
{ {
sut.Create(CreateContentCommand(new CreateContent { Data = data })); sut.Create(CreateContentCommand(new CreateContent { Data = data }));
@ -349,6 +397,13 @@ namespace Squidex.Domain.Apps.Write.Contents
((IAggregate)sut).ClearUncommittedEvents(); ((IAggregate)sut).ClearUncommittedEvents();
} }
private void ArchiveContent()
{
sut.Archive(CreateContentCommand(new ArchiveContent()));
((IAggregate)sut).ClearUncommittedEvents();
}
private void DeleteContent() private void DeleteContent()
{ {
sut.Delete(CreateContentCommand(new DeleteContent())); sut.Delete(CreateContentCommand(new DeleteContent()));

6
tests/Squidex.Domain.Apps.Write.Tests/Schemas/SchemaDomainObjectTests.cs

@ -189,8 +189,7 @@ namespace Squidex.Domain.Apps.Write.Schemas
ScriptCreate = "<script-create>", ScriptCreate = "<script-create>",
ScriptUpdate = "<script-update>", ScriptUpdate = "<script-update>",
ScriptDelete = "<script-delete>", ScriptDelete = "<script-delete>",
ScriptPublish = "<script-publish>", ScriptChange = "<script-change>"
ScriptUnpublish = "<script-unpublish>"
})); }));
sut.GetUncomittedEvents() sut.GetUncomittedEvents()
@ -201,8 +200,7 @@ namespace Squidex.Domain.Apps.Write.Schemas
ScriptCreate = "<script-create>", ScriptCreate = "<script-create>",
ScriptUpdate = "<script-update>", ScriptUpdate = "<script-update>",
ScriptDelete = "<script-delete>", ScriptDelete = "<script-delete>",
ScriptPublish = "<script-publish>", ScriptChange = "<script-change>"
ScriptUnpublish = "<script-unpublish>"
}) })
); );
} }

Loading…
Cancel
Save