From cb5d127d9c171813ab4c06ef63eb0960c983fc95 Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Sat, 2 Sep 2017 19:16:44 +0200 Subject: [PATCH] API extended. --- .../Contents/ContentCommandMiddleware.cs | 4 +- ...dResult.cs => ContentDataChangedResult.cs} | 8 +-- .../Api/Schemas/Models/ConfigureScriptsDto.cs | 43 +++++++++++++ .../Api/Schemas/SchemasController.cs | 24 +++++++ .../ContentApi/ContentsController.cs | 63 +++++++++++++++---- .../Generator/SchemaSwaggerGenerator.cs | 6 +- .../ContentApi/Models/ContentDto.cs | 24 +------ .../Contents/ContentCommandHandlerTests.cs | 4 +- 8 files changed, 130 insertions(+), 46 deletions(-) rename src/Squidex.Domain.Apps.Write/Contents/{ContentChangedResult.cs => ContentDataChangedResult.cs} (71%) create mode 100644 src/Squidex/Controllers/Api/Schemas/Models/ConfigureScriptsDto.cs diff --git a/src/Squidex.Domain.Apps.Write/Contents/ContentCommandMiddleware.cs b/src/Squidex.Domain.Apps.Write/Contents/ContentCommandMiddleware.cs index 745cf4b81..cbc816575 100644 --- a/src/Squidex.Domain.Apps.Write/Contents/ContentCommandMiddleware.cs +++ b/src/Squidex.Domain.Apps.Write/Contents/ContentCommandMiddleware.cs @@ -92,7 +92,7 @@ namespace Squidex.Domain.Apps.Write.Contents content.Update(command); - context.Complete(new ContentChangedResult(content.Data, content.Version)); + context.Complete(new ContentDataChangedResult(content.Data, content.Version)); }); } @@ -109,7 +109,7 @@ namespace Squidex.Domain.Apps.Write.Contents content.Patch(command); - context.Complete(new ContentChangedResult(content.Data, content.Version)); + context.Complete(new ContentDataChangedResult(content.Data, content.Version)); }); } diff --git a/src/Squidex.Domain.Apps.Write/Contents/ContentChangedResult.cs b/src/Squidex.Domain.Apps.Write/Contents/ContentDataChangedResult.cs similarity index 71% rename from src/Squidex.Domain.Apps.Write/Contents/ContentChangedResult.cs rename to src/Squidex.Domain.Apps.Write/Contents/ContentDataChangedResult.cs index 4550eb7ae..44bce98d5 100644 --- a/src/Squidex.Domain.Apps.Write/Contents/ContentChangedResult.cs +++ b/src/Squidex.Domain.Apps.Write/Contents/ContentDataChangedResult.cs @@ -11,14 +11,14 @@ using Squidex.Infrastructure.CQRS.Commands; namespace Squidex.Domain.Apps.Write.Contents { - public sealed class ContentChangedResult : EntitySavedResult + public sealed class ContentDataChangedResult : EntitySavedResult { - public NamedContentData Content { get; } + public NamedContentData Data { get; } - public ContentChangedResult(NamedContentData content, long version) + public ContentDataChangedResult(NamedContentData data, long version) : base(version) { - Content = content; + Data = data; } } } diff --git a/src/Squidex/Controllers/Api/Schemas/Models/ConfigureScriptsDto.cs b/src/Squidex/Controllers/Api/Schemas/Models/ConfigureScriptsDto.cs new file mode 100644 index 000000000..8471d70f2 --- /dev/null +++ b/src/Squidex/Controllers/Api/Schemas/Models/ConfigureScriptsDto.cs @@ -0,0 +1,43 @@ +// ========================================================================== +// ConfigureScriptsDto.cs +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex Group +// All rights reserved. +// ========================================================================== + +namespace Squidex.Controllers.Api.Schemas.Models +{ + public sealed class ConfigureScriptsDto + { + /// + /// The script that is executed for each query when querying contents. + /// + public string ScriptQuery { get; set; } + + /// + /// The script that is executed when creating a content. + /// + public string ScriptCreate { get; set; } + + /// + /// The script that is executed when updating a content. + /// + public string ScriptUpdate { get; set; } + + /// + /// The script that is executed when deleting a content. + /// + public string ScriptDelete { get; set; } + + /// + /// The script that is executed when publishing a content. + /// + public string ScriptPublish { get; set; } + + /// + /// The script that is executed when unpublishing a content. + /// + public string ScriptUnpublish { get; set; } + } +} diff --git a/src/Squidex/Controllers/Api/Schemas/SchemasController.cs b/src/Squidex/Controllers/Api/Schemas/SchemasController.cs index 8174fd9ec..b933d0090 100644 --- a/src/Squidex/Controllers/Api/Schemas/SchemasController.cs +++ b/src/Squidex/Controllers/Api/Schemas/SchemasController.cs @@ -154,6 +154,30 @@ namespace Squidex.Controllers.Api.Schemas return NoContent(); } + /// + /// Update the scripts of a schema. + /// + /// The name of the app. + /// The name of the schema. + /// The schema scripts object that needs to updated. + /// + /// 204 => Schema has been updated. + /// 400 => Schema properties are not valid. + /// 404 => Schema or app not found. + /// + [MustBeAppDeveloper] + [HttpPut] + [Route("apps/{app}/schemas/{name}/scripts/")] + [ApiCosts(1)] + public async Task PutSchemaScripts(string app, string name, [FromBody] ConfigureScriptsDto request) + { + var command = SimpleMapper.Map(request, new ConfigureScripts()); + + await CommandBus.PublishAsync(command); + + return NoContent(); + } + /// /// Publish a schema. /// diff --git a/src/Squidex/Controllers/ContentApi/ContentsController.cs b/src/Squidex/Controllers/ContentApi/ContentsController.cs index df74c4df8..50399d900 100644 --- a/src/Squidex/Controllers/ContentApi/ContentsController.cs +++ b/src/Squidex/Controllers/ContentApi/ContentsController.cs @@ -15,15 +15,18 @@ using Microsoft.Extensions.Primitives; using NSwag.Annotations; using Squidex.Controllers.ContentApi.Models; using Squidex.Domain.Apps.Core.Contents; +using Squidex.Domain.Apps.Core.Scripting; using Squidex.Domain.Apps.Read.Contents.GraphQL; using Squidex.Domain.Apps.Read.Contents.Repositories; using Squidex.Domain.Apps.Read.Schemas; using Squidex.Domain.Apps.Read.Schemas.Services; +using Squidex.Domain.Apps.Write.Contents; using Squidex.Domain.Apps.Write.Contents.Commands; using Squidex.Infrastructure.CQRS.Commands; using Squidex.Infrastructure.Reflection; using Squidex.Pipeline; +// ReSharper disable InvertIf // ReSharper disable PossibleNullReferenceException // ReSharper disable RedundantIfElseBlock @@ -35,17 +38,20 @@ namespace Squidex.Controllers.ContentApi public sealed class ContentsController : ControllerBase { private readonly ISchemaProvider schemas; + private readonly IScriptEngine scriptEngine; private readonly IContentRepository contentRepository; private readonly IGraphQLService graphQL; public ContentsController( ICommandBus commandBus, - ISchemaProvider schemas, + ISchemaProvider schemas, + IScriptEngine scriptEngine, IContentRepository contentRepository, IGraphQLService graphQL) : base(commandBus) { this.graphQL = graphQL; + this.scriptEngine = scriptEngine; this.schemas = schemas; this.contentRepository = contentRepository; } @@ -99,16 +105,28 @@ namespace Squidex.Controllers.ContentApi await Task.WhenAll(taskForItems, taskForCount); + var scriptUser = ScriptUser.Create(User); + var scriptText = schemaEntity.ScriptQuery; + + var hasScript = !string.IsNullOrWhiteSpace(scriptText); + var response = new AssetsDto { Total = taskForCount.Result, - Items = taskForItems.Result.Take(200).Select(x => + Items = taskForItems.Result.Take(200).Select(item => { - var itemModel = SimpleMapper.Map(x, new ContentDto()); + var itemModel = SimpleMapper.Map(item, new ContentDto()); - if (x.Data != null) + if (item.Data != null) { - itemModel.Data = x.Data.ToApiModel(schemaEntity.Schema, App.LanguagesConfig, null, !isFrontendClient); + var data = item.Data.ToApiModel(schemaEntity.Schema, App.LanguagesConfig, null, !isFrontendClient); + + if (hasScript && !isFrontendClient) + { + data = scriptEngine.ExecuteAndTransform(new ScriptContext { Data = data, ContentId = item.Id, User = scriptUser }, scriptText, "transform item"); + } + + itemModel.Data = data; } return itemModel; @@ -144,7 +162,22 @@ namespace Squidex.Controllers.ContentApi { var isFrontendClient = User.IsFrontendClient(); - response.Data = entity.Data.ToApiModel(schemaEntity.Schema, App.LanguagesConfig, null, !isFrontendClient); + var data = entity.Data.ToApiModel(schemaEntity.Schema, App.LanguagesConfig, null, !isFrontendClient); + + if (!isFrontendClient) + { + var scriptUser = ScriptUser.Create(User); + var scriptText = schemaEntity.ScriptQuery; + + var hasScript = !string.IsNullOrWhiteSpace(scriptText); + + if (hasScript) + { + data = scriptEngine.ExecuteAndTransform(new ScriptContext { Data = data, ContentId = entity.Id, User = scriptUser }, scriptText, "transform item"); + } + } + + response.Data = data; } Response.Headers["ETag"] = new StringValues(entity.Version.ToString()); @@ -163,9 +196,9 @@ namespace Squidex.Controllers.ContentApi var context = await CommandBus.PublishAsync(command); var result = context.Result>(); - var response = ContentDto.Create(command, result); + var response = result.IdOrValue; - return CreatedAtAction(nameof(GetContent), new { id = response.Id }, response); + return CreatedAtAction(nameof(GetContent), new { id = command.ContentId }, response); } [MustBeAppEditor] @@ -176,9 +209,12 @@ namespace Squidex.Controllers.ContentApi { var command = new UpdateContent { ContentId = id, Data = request.ToCleaned() }; - await CommandBus.PublishAsync(command); + var context = await CommandBus.PublishAsync(command); - return NoContent(); + var result = context.Result(); + var response = result.Data; + + return Ok(response); } [MustBeAppEditor] @@ -189,9 +225,12 @@ namespace Squidex.Controllers.ContentApi { var command = new PatchContent { ContentId = id, Data = request.ToCleaned() }; - await CommandBus.PublishAsync(command); + var context = await CommandBus.PublishAsync(command); - return NoContent(); + var result = context.Result(); + var response = result.Data; + + return Ok(response); } [MustBeAppEditor] diff --git a/src/Squidex/Controllers/ContentApi/Generator/SchemaSwaggerGenerator.cs b/src/Squidex/Controllers/ContentApi/Generator/SchemaSwaggerGenerator.cs index 5af7a3e8f..096eb1e15 100644 --- a/src/Squidex/Controllers/ContentApi/Generator/SchemaSwaggerGenerator.cs +++ b/src/Squidex/Controllers/ContentApi/Generator/SchemaSwaggerGenerator.cs @@ -150,7 +150,7 @@ namespace Squidex.Controllers.ContentApi.Generator operation.AddBodyParameter("data", dataSchema, SchemaBodyDescription); operation.AddQueryParameter("publish", JsonObjectType.Boolean, "Set to true to autopublish content."); - operation.AddResponse("201", $"{schemaName} created.", contentSchema); + operation.AddResponse("201", $"{schemaName} created.", dataSchema); operation.Security = EditorSecurity; }); @@ -165,7 +165,7 @@ namespace Squidex.Controllers.ContentApi.Generator operation.AddBodyParameter("data", dataSchema, SchemaBodyDescription); - operation.AddResponse("204", $"{schemaName} element updated."); + operation.AddResponse("201", $"{schemaName} element updated.", dataSchema); operation.Security = EditorSecurity; }); @@ -180,7 +180,7 @@ namespace Squidex.Controllers.ContentApi.Generator operation.AddBodyParameter("data", contentSchema, SchemaBodyDescription); - operation.AddResponse("204", $"{schemaName} element updated."); + operation.AddResponse("201", $"{schemaName} element patched.", dataSchema); operation.Security = EditorSecurity; }); diff --git a/src/Squidex/Controllers/ContentApi/Models/ContentDto.cs b/src/Squidex/Controllers/ContentApi/Models/ContentDto.cs index fc15492f3..182b1e5cc 100644 --- a/src/Squidex/Controllers/ContentApi/Models/ContentDto.cs +++ b/src/Squidex/Controllers/ContentApi/Models/ContentDto.cs @@ -9,10 +9,7 @@ using System; using System.ComponentModel.DataAnnotations; using NodaTime; -using Squidex.Domain.Apps.Core.Contents; -using Squidex.Domain.Apps.Write.Contents.Commands; using Squidex.Infrastructure; -using Squidex.Infrastructure.CQRS.Commands; namespace Squidex.Controllers.ContentApi.Models { @@ -54,30 +51,11 @@ namespace Squidex.Controllers.ContentApi.Models /// /// Indicates if the content element is publihed. /// - public bool IsPublished { get; set; } + public bool? IsPublished { get; set; } /// /// The version of the content. /// public long Version { get; set; } - - public static ContentDto Create(CreateContent command, EntityCreatedResult result) - { - var now = SystemClock.Instance.GetCurrentInstant(); - - var response = new ContentDto - { - Id = command.ContentId, - Data = result.IdOrValue, - Version = result.Version, - Created = now, - CreatedBy = command.Actor, - LastModified = now, - LastModifiedBy = command.Actor, - IsPublished = command.Publish - }; - - return response; - } } } diff --git a/tests/Squidex.Domain.Apps.Write.Tests/Contents/ContentCommandHandlerTests.cs b/tests/Squidex.Domain.Apps.Write.Tests/Contents/ContentCommandHandlerTests.cs index 221ab88fb..394f7ab84 100644 --- a/tests/Squidex.Domain.Apps.Write.Tests/Contents/ContentCommandHandlerTests.cs +++ b/tests/Squidex.Domain.Apps.Write.Tests/Contents/ContentCommandHandlerTests.cs @@ -123,7 +123,7 @@ namespace Squidex.Domain.Apps.Write.Contents await sut.HandleAsync(context); }); - Assert.Equal(data, context.Result().Content); + Assert.Equal(data, context.Result().Data); A.CallTo(() => scriptEngine.ExecuteAndTransform(A.Ignored, "", "update content", true)).MustHaveHappened(); } @@ -162,7 +162,7 @@ namespace Squidex.Domain.Apps.Write.Contents await sut.HandleAsync(context); }); - Assert.NotNull(context.Result().Content); + Assert.NotNull(context.Result().Data); A.CallTo(() => scriptEngine.ExecuteAndTransform(A.Ignored, "", "patch content", true)).MustHaveHappened(); }