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();
}