// ========================================================================== // Squidex Headless CMS // ========================================================================== // Copyright (c) Squidex UG (haftungsbeschränkt) // All rights reserved. Licensed under the MIT license. // ========================================================================== using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.DefaultValues; using Squidex.Domain.Apps.Core.Schemas; using Squidex.Domain.Apps.Core.Scripting; using Squidex.Domain.Apps.Core.ValidateContent; using Squidex.Domain.Apps.Entities.Apps; using Squidex.Domain.Apps.Entities.Contents.Commands; using Squidex.Domain.Apps.Entities.Schemas; using Squidex.Infrastructure; using Squidex.Infrastructure.Validation; #pragma warning disable IDE0016 // Use 'throw' expression namespace Squidex.Domain.Apps.Entities.Contents { public sealed class ContentOperationContext { private static readonly ScriptOptions ScriptOptions = new ScriptOptions { AsContext = true, CanDisallow = true, CanReject = true }; private readonly IScriptEngine scriptEngine; private readonly IAppProvider appProvider; private readonly IEnumerable factories; private ISchemaEntity schema; private IAppEntity app; private ContentCommand command; private ValidationContext validationContext; public ContentOperationContext(IAppProvider appProvider, IEnumerable factories, IScriptEngine scriptEngine) { this.appProvider = appProvider; this.factories = factories; this.scriptEngine = scriptEngine; } public ISchemaEntity Schema { get { return schema; } } public async Task LoadAsync(NamedId appId, NamedId schemaId, ContentCommand command, bool optimized) { var (app, schema) = await appProvider.GetAppWithSchemaAsync(appId.Id, schemaId.Id); if (app == null) { throw new InvalidOperationException($"Cannot resolve app with id {appId}."); } if (schema == null) { throw new InvalidOperationException($"Cannot resolve schema with id id {schemaId}."); } this.app = app; this.schema = schema; this.command = command; validationContext = new ValidationContext(appId, schemaId, schema.SchemaDef, command.ContentId).Optimized(optimized); } public Task GenerateDefaultValuesAsync(NamedContentData data) { data.GenerateDefaultValues(schema.SchemaDef, app.PartitionResolver()); return Task.CompletedTask; } public async Task ValidateInputAsync(NamedContentData data) { var validator = new ContentValidator(app.PartitionResolver(), validationContext, factories); await validator.ValidateInputAsync(data); CheckErrors(validator); } public async Task ValidateInputPartialAsync(NamedContentData data) { var validator = new ContentValidator(app.PartitionResolver(), validationContext, factories); await validator.ValidateInputPartialAsync(data); CheckErrors(validator); } public async Task ValidateContentAsync(NamedContentData data) { var validator = new ContentValidator(app.PartitionResolver(), validationContext, factories); await validator.ValidateContentAsync(data); CheckErrors(validator); } private void CheckErrors(ContentValidator validator) { if (validator.Errors.Count > 0) { throw new ValidationException(validator.Errors.ToList()); } } public async Task ExecuteScriptAndTransformAsync(Func script, ScriptVars context) { Enrich(context); var actualScript = GetScript(script); if (string.IsNullOrWhiteSpace(actualScript)) { return context.Data!; } return await scriptEngine.TransformAsync(context, actualScript, ScriptOptions); } public async Task ExecuteScriptAsync(Func script, ScriptVars context) { Enrich(context); var actualScript = GetScript(script); if (string.IsNullOrWhiteSpace(actualScript)) { return; } await scriptEngine.ExecuteAsync(context, GetScript(script), ScriptOptions); } private void Enrich(ScriptVars context) { context.ContentId = command.ContentId; context.AppId = app.Id; context.AppName = app.Name; context.User = command.User; } private string GetScript(Func script) { return script(schema.SchemaDef.Scripts); } } }