Browse Source

Merge branch 'master' of github.com:Squidex/squidex

pull/1122/head
Sebastian Stehle 2 years ago
parent
commit
49d039ce1c
  1. 14
      .github/workflows/dev.yml
  2. 8
      .github/workflows/make-screenshots.yml
  3. 12
      .github/workflows/release.yml
  4. 12
      backend/src/Squidex.Domain.Apps.Entities/Apps/Indexes/AppsIndex.cs
  5. 2
      backend/src/Squidex.Domain.Apps.Entities/Assets/AssetSlug.cs
  6. 2
      backend/src/Squidex.Domain.Apps.Entities/Contents/Commands/BulkUpdateContents.cs
  7. 1
      backend/src/Squidex.Domain.Apps.Entities/Contents/Commands/EnrichContentDefaults.cs
  8. 2
      backend/src/Squidex.Domain.Apps.Entities/Contents/Commands/UpsertContent.cs
  9. 12
      backend/src/Squidex.Domain.Apps.Entities/Contents/ContentHeaders.cs
  10. 6
      backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/ContentDomainObject.cs
  11. 20
      backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/Guards/ValidationExtensions.cs
  12. 9
      backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentEnricher.cs
  13. 2
      backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ConvertData.cs
  14. 2
      backend/src/Squidex.Domain.Apps.Entities/Jobs/JobWorker.cs
  15. 12
      backend/src/Squidex.Domain.Apps.Entities/Schemas/Indexes/SchemasIndex.cs
  16. 2
      backend/src/Squidex.Infrastructure/Migrations/Migrator.cs
  17. 4
      backend/src/Squidex/Areas/Api/Controllers/Contents/ContentsController.cs
  18. 5
      backend/src/Squidex/Areas/Api/Controllers/Contents/Models/BulkUpdateContentsDto.cs
  19. 29
      backend/src/Squidex/Areas/Api/Controllers/Contents/Models/EnrichContentDefaultsDto.cs
  20. 1
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/EnrichForCachingTests.cs
  21. 1
      backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/EnrichForCachingTests.cs
  22. 3
      helm/squidex/templates/service.yaml
  23. 3
      helm/squidex/values.yaml
  24. 3
      tools/.editorconfig
  25. 2
      tools/TestSuite/TestSuite.ApiTests/AssetFoldersTests.cs
  26. 2
      tools/TestSuite/TestSuite.ApiTests/ContentQueryTests.cs
  27. 155
      tools/TestSuite/TestSuite.ApiTests/ContentUpdateTests.cs
  28. 15
      tools/TestSuite/TestSuite.ApiTests/GraphQLTests.cs
  29. 20
      tools/TestSuite/TestSuite.ApiTests/TestSuite.ApiTests.csproj
  30. 8
      tools/TestSuite/TestSuite.LoadTests/TestSuite.LoadTests.csproj
  31. 2
      tools/TestSuite/TestSuite.Shared/ClientExtensions.cs
  32. 49
      tools/TestSuite/TestSuite.Shared/ContentStrategies.cs
  33. 14
      tools/TestSuite/TestSuite.Shared/TestSuite.Shared.csproj

14
.github/workflows/dev.yml

@ -22,10 +22,10 @@ jobs:
uses: rlespinasse/github-slug-action@v4.5.0 uses: rlespinasse/github-slug-action@v4.5.0
- name: Prepare - Setup QEMU - name: Prepare - Setup QEMU
uses: docker/setup-qemu-action@v3.1.0 uses: docker/setup-qemu-action@v3.2.0
- name: Prepare - Setup Docker Buildx - name: Prepare - Setup Docker Buildx
uses: docker/setup-buildx-action@v3.4.0 uses: docker/setup-buildx-action@v3.6.1
- name: Prepare - Setup Node - name: Prepare - Setup Node
uses: actions/setup-node@v4.0.3 uses: actions/setup-node@v4.0.3
@ -33,7 +33,7 @@ jobs:
node-version: 18 node-version: 18
- name: Build - BUILD - name: Build - BUILD
uses: docker/build-push-action@v6.4.1 uses: docker/build-push-action@v6.7.0
with: with:
load: true load: true
build-args: "SQUIDEX__RUNTIME__VERSION=7.0.0-dev-${{ env.BUILD_NUMBER }}" build-args: "SQUIDEX__RUNTIME__VERSION=7.0.0-dev-${{ env.BUILD_NUMBER }}"
@ -103,7 +103,7 @@ jobs:
- name: Test - Upload Playwright Artifacts - name: Test - Upload Playwright Artifacts
if: always() if: always()
uses: actions/upload-artifact@v4.3.4 uses: actions/upload-artifact@v4.3.6
with: with:
name: playwright-report name: playwright-report
path: tools/e2e/playwright-report/ path: tools/e2e/playwright-report/
@ -111,7 +111,7 @@ jobs:
- name: Test - Upload Screenshots - name: Test - Upload Screenshots
if: failure() if: failure()
uses: actions/upload-artifact@v4.3.4 uses: actions/upload-artifact@v4.3.6
with: with:
path: | path: |
tools/TestSuite/TestSuite.ApiTests/bin/Debug/net8.0/screenshots/ tools/TestSuite/TestSuite.ApiTests/bin/Debug/net8.0/screenshots/
@ -142,14 +142,14 @@ jobs:
- name: Publish - Login to Docker Hub - name: Publish - Login to Docker Hub
if: github.event_name != 'pull_request' if: github.event_name != 'pull_request'
uses: docker/login-action@v3.2.0 uses: docker/login-action@v3.3.0
with: with:
username: ${{ secrets.DOCKER_USERNAME }} username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }} password: ${{ secrets.DOCKER_PASSWORD }}
- name: Publish - Build & Push for Multi-Platforms - name: Publish - Build & Push for Multi-Platforms
if: github.event_name != 'pull_request' if: github.event_name != 'pull_request'
uses: docker/build-push-action@v6.4.1 uses: docker/build-push-action@v6.7.0
with: with:
build-args: "SQUIDEX__RUNTIME__VERSION=7.0.0-dev-${{ env.BUILD_NUMBER }}" build-args: "SQUIDEX__RUNTIME__VERSION=7.0.0-dev-${{ env.BUILD_NUMBER }}"
cache-from: type=gha cache-from: type=gha

8
.github/workflows/make-screenshots.yml

@ -12,10 +12,10 @@ jobs:
uses: actions/checkout@v4.1.7 uses: actions/checkout@v4.1.7
- name: Prepare - Setup QEMU - name: Prepare - Setup QEMU
uses: docker/setup-qemu-action@v3.1.0 uses: docker/setup-qemu-action@v3.2.0
- name: Prepare - Setup Docker Buildx - name: Prepare - Setup Docker Buildx
uses: docker/setup-buildx-action@v3.4.0 uses: docker/setup-buildx-action@v3.6.1
- name: Prepare - Setup Node - name: Prepare - Setup Node
uses: actions/setup-node@v4.0.3 uses: actions/setup-node@v4.0.3
@ -23,7 +23,7 @@ jobs:
node-version: 18 node-version: 18
- name: Build - BUILD - name: Build - BUILD
uses: docker/build-push-action@v6.4.1 uses: docker/build-push-action@v6.7.0
with: with:
load: true load: true
cache-from: type=gha cache-from: type=gha
@ -50,7 +50,7 @@ jobs:
- name: Test - Upload Playwright Artifacts - name: Test - Upload Playwright Artifacts
if: always() if: always()
uses: actions/upload-artifact@v4.3.4 uses: actions/upload-artifact@v4.3.6
with: with:
name: snapshots name: snapshots
path: tools/e2e/snapshots/ path: tools/e2e/snapshots/

12
.github/workflows/release.yml

@ -17,10 +17,10 @@ jobs:
uses: rlespinasse/github-slug-action@v4.5.0 uses: rlespinasse/github-slug-action@v4.5.0
- name: Prepare - Setup QEMU - name: Prepare - Setup QEMU
uses: docker/setup-qemu-action@v3.1.0 uses: docker/setup-qemu-action@v3.2.0
- name: Prepare - Setup Docker Buildx - name: Prepare - Setup Docker Buildx
uses: docker/setup-buildx-action@v3.4.0 uses: docker/setup-buildx-action@v3.6.1
- name: Prepare - Setup Node - name: Prepare - Setup Node
uses: actions/setup-node@v4.0.3 uses: actions/setup-node@v4.0.3
@ -28,7 +28,7 @@ jobs:
node-version: 18 node-version: 18
- name: Build - BUILD - name: Build - BUILD
uses: docker/build-push-action@v6.4.1 uses: docker/build-push-action@v6.7.0
with: with:
load: true load: true
build-args: "SQUIDEX__BUILD__VERSION=${{ env.GITHUB_REF_SLUG }},SQUIDEX__RUNTIME__VERSION=${{ env.GITHUB_REF_SLUG }}" build-args: "SQUIDEX__BUILD__VERSION=${{ env.GITHUB_REF_SLUG }},SQUIDEX__RUNTIME__VERSION=${{ env.GITHUB_REF_SLUG }}"
@ -98,7 +98,7 @@ jobs:
- name: Test - Upload Playwright Artifacts - name: Test - Upload Playwright Artifacts
if: always() if: always()
uses: actions/upload-artifact@v4.3.4 uses: actions/upload-artifact@v4.3.6
with: with:
name: playwright-report name: playwright-report
path: tools/e2e/playwright-report/ path: tools/e2e/playwright-report/
@ -136,13 +136,13 @@ jobs:
fi fi
- name: Publish - Login to Docker Hub - name: Publish - Login to Docker Hub
uses: docker/login-action@v3.2.0 uses: docker/login-action@v3.3.0
with: with:
username: ${{ secrets.DOCKER_USERNAME }} username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }} password: ${{ secrets.DOCKER_PASSWORD }}
- name: Publish - Build & Push for Multi-Platforms - name: Publish - Build & Push for Multi-Platforms
uses: docker/build-push-action@v6.4.1 uses: docker/build-push-action@v6.7.0
with: with:
build-args: "SQUIDEX__BUILD__VERSION=${{ env.GITHUB_REF_SLUG }},SQUIDEX__RUNTIME__VERSION=${{ env.GITHUB_REF_SLUG }}" build-args: "SQUIDEX__BUILD__VERSION=${{ env.GITHUB_REF_SLUG }},SQUIDEX__RUNTIME__VERSION=${{ env.GITHUB_REF_SLUG }}"
cache-from: type=gha cache-from: type=gha

12
backend/src/Squidex.Domain.Apps.Entities/Apps/Indexes/AppsIndex.cs

@ -227,11 +227,11 @@ public sealed class AppsIndex : IAppsIndex, ICommandMiddleware, IInitializable
} }
// Do not use cancellation here as we already so far. // Do not use cancellation here as we already so far.
await appCache.AddAsync(new[] await appCache.AddAsync(
{ [
new KeyValuePair<string, object?>(GetCacheKey(app.Id), app), new KeyValuePair<string, object?>(GetCacheKey(app.Id), app),
new KeyValuePair<string, object?>(GetCacheKey(app.Name), app), new KeyValuePair<string, object?>(GetCacheKey(app.Name), app),
}, options.CacheDuration); ], options.CacheDuration);
return app; return app;
} }
@ -244,10 +244,10 @@ public sealed class AppsIndex : IAppsIndex, ICommandMiddleware, IInitializable
} }
// Do not use cancellation here as we already so far. // Do not use cancellation here as we already so far.
return appCache.RemoveAsync(new[] return appCache.RemoveAsync(
{ [
GetCacheKey(id), GetCacheKey(id),
GetCacheKey(name) GetCacheKey(name)
}); ]);
} }
} }

2
backend/src/Squidex.Domain.Apps.Entities/Assets/AssetSlug.cs

@ -11,7 +11,7 @@ namespace Squidex.Domain.Apps.Entities.Assets;
public static class AssetSlug public static class AssetSlug
{ {
private static readonly HashSet<char> Dot = new HashSet<char>(new[] { '.' }); private static readonly HashSet<char> Dot = new HashSet<char>(['.']);
public static string ToAssetSlug(this string value) public static string ToAssetSlug(this string value)
{ {

2
backend/src/Squidex.Domain.Apps.Entities/Contents/Commands/BulkUpdateContents.cs

@ -29,5 +29,7 @@ public sealed class BulkUpdateContents : SquidexCommand, IAppCommand, ISchemaCom
public bool OptimizeValidation { get; set; } public bool OptimizeValidation { get; set; }
public bool EnrichRequiredFields { get; set; }
public BulkUpdateJob[]? Jobs { get; set; } public BulkUpdateJob[]? Jobs { get; set; }
} }

1
backend/src/Squidex.Domain.Apps.Entities/Contents/Commands/EnrichContentDefaults.cs

@ -9,4 +9,5 @@ namespace Squidex.Domain.Apps.Entities.Contents.Commands;
public sealed class EnrichContentDefaults : ContentCommand public sealed class EnrichContentDefaults : ContentCommand
{ {
public bool EnrichRequiredFields { get; set; }
} }

2
backend/src/Squidex.Domain.Apps.Entities/Contents/Commands/UpsertContent.cs

@ -21,6 +21,8 @@ public sealed class UpsertContent : ContentDataCommand, ISchemaCommand
public bool EnrichDefaults { get; set; } public bool EnrichDefaults { get; set; }
public bool EnrichRequiredFields { get; set; }
public UpsertContent() public UpsertContent()
{ {
ContentId = DomainId.NewGuid(); ContentId = DomainId.NewGuid();

12
backend/src/Squidex.Domain.Apps.Entities/Contents/ContentHeaders.cs

@ -19,6 +19,7 @@ public static class ContentHeaders
public const string KeyLanguages = "X-Languages"; public const string KeyLanguages = "X-Languages";
public const string KeyNoCleanup = "X-NoCleanup"; public const string KeyNoCleanup = "X-NoCleanup";
public const string KeyNoEnrichment = "X-NoEnrichment"; public const string KeyNoEnrichment = "X-NoEnrichment";
public const string KeyNoDefaults = "X-NoDefaults";
public const string KeyNoResolveLanguages = "X-NoResolveLanguages"; public const string KeyNoResolveLanguages = "X-NoResolveLanguages";
public const string KeyResolveFlow = "X-ResolveFlow"; public const string KeyResolveFlow = "X-ResolveFlow";
public const string KeyResolveUrls = "X-ResolveUrls"; public const string KeyResolveUrls = "X-ResolveUrls";
@ -32,6 +33,7 @@ public static class ContentHeaders
cache.AddHeader(KeyLanguages); cache.AddHeader(KeyLanguages);
cache.AddHeader(KeyNoCleanup); cache.AddHeader(KeyNoCleanup);
cache.AddHeader(KeyNoEnrichment); cache.AddHeader(KeyNoEnrichment);
cache.AddHeader(KeyNoDefaults);
cache.AddHeader(KeyNoResolveLanguages); cache.AddHeader(KeyNoResolveLanguages);
cache.AddHeader(KeyResolveFlow); cache.AddHeader(KeyResolveFlow);
cache.AddHeader(KeyResolveUrls); cache.AddHeader(KeyResolveUrls);
@ -63,6 +65,16 @@ public static class ContentHeaders
return builder.WithBoolean(KeyNoEnrichment, value); return builder.WithBoolean(KeyNoEnrichment, value);
} }
public static bool NoDefaults(this Context context)
{
return context.AsBoolean(KeyNoDefaults);
}
public static ICloneBuilder WithNoDefaults(this ICloneBuilder builder, bool value = true)
{
return builder.WithBoolean(KeyNoDefaults, value);
}
public static bool Unpublished(this Context context) public static bool Unpublished(this Context context)
{ {
return context.AsBoolean(KeyUnpublished); return context.AsBoolean(KeyUnpublished);

6
backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/ContentDomainObject.cs

@ -211,7 +211,7 @@ public partial class ContentDomainObject : DomainObject<WriteContent>
{ {
var operation = await ContentOperation.CreateAsync(serviceProvider, c, () => Snapshot); var operation = await ContentOperation.CreateAsync(serviceProvider, c, () => Snapshot);
var newData = operation.GenerateDefaultValues(Snapshot.EditingData.Clone()); var newData = operation.GenerateDefaultValues(Snapshot.EditingData.Clone(), !c.EnrichRequiredFields);
if (!newData.Equals(Snapshot.EditingData)) if (!newData.Equals(Snapshot.EditingData))
{ {
@ -263,7 +263,7 @@ public partial class ContentDomainObject : DomainObject<WriteContent>
c.Data = await operation.ExecuteCreateScriptAsync(c.Data, status, ct); c.Data = await operation.ExecuteCreateScriptAsync(c.Data, status, ct);
} }
c.Data = operation.GenerateDefaultValues(c.Data); c.Data = operation.GenerateDefaultValues(c.Data, false);
if (!c.DoNotValidate) if (!c.DoNotValidate)
{ {
@ -336,7 +336,7 @@ public partial class ContentDomainObject : DomainObject<WriteContent>
if (c.EnrichDefaults) if (c.EnrichDefaults)
{ {
newData = operation.GenerateDefaultValues(newData); newData = operation.GenerateDefaultValues(newData, true);
} }
if (newData.Equals(Snapshot.EditingData)) if (newData.Equals(Snapshot.EditingData))

20
backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/Guards/ValidationExtensions.cs

@ -47,7 +47,8 @@ public static class ValidationExtensions
operation.ThrowOnErrors(); operation.ThrowOnErrors();
} }
public static async Task ValidateInputAsync(this ContentOperation operation, ContentData data, bool optimize, bool published, public static async Task ValidateInputAsync(this ContentOperation operation,
ContentData data, bool optimize, bool published,
CancellationToken ct) CancellationToken ct)
{ {
var validator = GetValidator(operation, optimize, published); var validator = GetValidator(operation, optimize, published);
@ -57,7 +58,8 @@ public static class ValidationExtensions
operation.AddErrors(validator.Errors).ThrowOnErrors(); operation.AddErrors(validator.Errors).ThrowOnErrors();
} }
public static async Task ValidateInputPartialAsync(this ContentOperation operation, ContentData data, bool optimize, bool published, public static async Task ValidateInputPartialAsync(this ContentOperation operation,
ContentData data, bool optimize, bool published,
CancellationToken ct) CancellationToken ct)
{ {
var validator = GetValidator(operation, optimize, published); var validator = GetValidator(operation, optimize, published);
@ -67,7 +69,8 @@ public static class ValidationExtensions
operation.AddErrors(validator.Errors).ThrowOnErrors(); operation.AddErrors(validator.Errors).ThrowOnErrors();
} }
public static async Task ValidateContentAsync(this ContentOperation operation, ContentData data, bool optimize, bool published, public static async Task ValidateContentAsync(this ContentOperation operation,
ContentData data, bool optimize, bool published,
CancellationToken ct) CancellationToken ct)
{ {
var validator = GetValidator(operation, optimize, published); var validator = GetValidator(operation, optimize, published);
@ -77,7 +80,8 @@ public static class ValidationExtensions
operation.AddErrors(validator.Errors).ThrowOnErrors(); operation.AddErrors(validator.Errors).ThrowOnErrors();
} }
public static async Task ValidateContentAndInputAsync(this ContentOperation operation, ContentData data, bool optimize, bool published, public static async Task ValidateContentAndInputAsync(this ContentOperation operation,
ContentData data, bool optimize, bool published,
CancellationToken ct) CancellationToken ct)
{ {
var validator = GetValidator(operation, optimize, published); var validator = GetValidator(operation, optimize, published);
@ -87,18 +91,20 @@ public static class ValidationExtensions
operation.AddErrors(validator.Errors).ThrowOnErrors(); operation.AddErrors(validator.Errors).ThrowOnErrors();
} }
public static ContentData GenerateDefaultValues(this ContentOperation operation, ContentData data) public static ContentData GenerateDefaultValues(this ContentOperation operation,
ContentData data, bool ignoreRequired)
{ {
var converter = var converter =
new ContentConverter( new ContentConverter(
operation.Components, operation.Components,
operation.Schema); operation.Schema);
converter.Add(new AddDefaultValues(operation.Partition()) { IgnoreRequiredFields = true }); converter.Add(new AddDefaultValues(operation.Partition()) { IgnoreRequiredFields = ignoreRequired });
return converter.Convert(data); return converter.Convert(data);
} }
public static ContentData InvokeUpdates(this ContentOperation operation, ContentData data, ContentData currentData, bool canUnset) public static ContentData InvokeUpdates(this ContentOperation operation, ContentData data,
ContentData currentData, bool canUnset)
{ {
var converter = var converter =
new ContentConverter( new ContentConverter(

9
backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/ContentEnricher.cs

@ -67,6 +67,7 @@ public sealed class ContentEnricher : IContentEnricher
{ {
var result = SimpleMapper.Map(content, new EnrichedContent()); var result = SimpleMapper.Map(content, new EnrichedContent());
// Clone the data to keep the existing value intact (for example when cached in memory).
if (cloneData) if (cloneData)
{ {
using (Telemetry.Activities.StartActivity("ContentEnricher/CloneData")) using (Telemetry.Activities.StartActivity("ContentEnricher/CloneData"))
@ -86,12 +87,8 @@ public sealed class ContentEnricher : IContentEnricher
{ {
return schemaCache.GetOrAdd(id, async x => return schemaCache.GetOrAdd(id, async x =>
{ {
var schema = await appProvider.GetSchemaAsync(context.App.Id, x, false, ct); var schema = await appProvider.GetSchemaAsync(context.App.Id, x, false, ct)
?? throw new DomainObjectNotFoundException(x.ToString());
if (schema == null)
{
throw new DomainObjectNotFoundException(x.ToString());
}
var components = await appProvider.GetComponentsAsync(schema, ct); var components = await appProvider.GetComponentsAsync(schema, ct);

2
backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ConvertData.cs

@ -133,7 +133,7 @@ public sealed class ConvertData : IContentEnricherStep
converter.Add(new ResolveFromPreviousPartitioning(context.App.Languages)); converter.Add(new ResolveFromPreviousPartitioning(context.App.Languages));
if (!context.IsFrontendClient) if (!context.IsFrontendClient && !context.NoDefaults())
{ {
converter.Add(new AddDefaultValues(context.App.PartitionResolver()) converter.Add(new AddDefaultValues(context.App.PartitionResolver())
{ {

2
backend/src/Squidex.Domain.Apps.Entities/Jobs/JobWorker.cs

@ -27,7 +27,7 @@ public sealed class JobWorker :
processorFactory = key => processorFactory = key =>
{ {
return (JobProcessor)objectFactory(serviceProvider, new object[] { key }); return (JobProcessor)objectFactory(serviceProvider, [key]);
}; };
} }

12
backend/src/Squidex.Domain.Apps.Entities/Schemas/Indexes/SchemasIndex.cs

@ -218,11 +218,11 @@ public sealed class SchemasIndex : ICommandMiddleware, ISchemasIndex
} }
// Do not use cancellation here as we already so far. // Do not use cancellation here as we already so far.
await schemaCache.AddAsync(new[] await schemaCache.AddAsync(
{ [
new KeyValuePair<string, object?>(GetCacheKey(schema.AppId.Id, schema.Id), schema), new KeyValuePair<string, object?>(GetCacheKey(schema.AppId.Id, schema.Id), schema),
new KeyValuePair<string, object?>(GetCacheKey(schema.AppId.Id, schema.Name), schema), new KeyValuePair<string, object?>(GetCacheKey(schema.AppId.Id, schema.Name), schema),
}, options.CacheDuration); ], options.CacheDuration);
return schema; return schema;
} }
@ -235,10 +235,10 @@ public sealed class SchemasIndex : ICommandMiddleware, ISchemasIndex
} }
// Do not use cancellation here as we already so far. // Do not use cancellation here as we already so far.
return schemaCache.RemoveAsync(new[] return schemaCache.RemoveAsync(
{ [
GetCacheKey(appId, id), GetCacheKey(appId, id),
GetCacheKey(appId, name) GetCacheKey(appId, name)
}); ]);
} }
} }

2
backend/src/Squidex.Infrastructure/Migrations/Migrator.cs

@ -86,7 +86,7 @@ public sealed class Migrator
{ {
while (!await migrationStatus.TryLockAsync(ct)) while (!await migrationStatus.TryLockAsync(ct))
{ {
log.LogInformation("Could not acquire lock to start migrating. Tryping again in {time}ms.", LockWaitMs); log.LogInformation("Could not acquire lock to start migrating. Trying again in {time}ms.", LockWaitMs);
await Task.Delay(LockWaitMs, ct); await Task.Delay(LockWaitMs, ct);
} }
} }

4
backend/src/Squidex/Areas/Api/Controllers/Contents/ContentsController.cs

@ -464,9 +464,9 @@ public sealed class ContentsController : ApiController
[AcceptHeader.Unpublished] [AcceptHeader.Unpublished]
[AcceptHeader.Languages] [AcceptHeader.Languages]
[ApiCosts(1)] [ApiCosts(1)]
public async Task<IActionResult> PutContentDefaults(string app, string schema, DomainId id) public async Task<IActionResult> PutContentDefaults(string app, string schema, DomainId id, EnrichContentDefaultsDto request)
{ {
var command = new EnrichContentDefaults { ContentId = id }; var command = request.ToCommand(id);
var response = await InvokeCommandAsync(command); var response = await InvokeCommandAsync(command);

5
backend/src/Squidex/Areas/Api/Controllers/Contents/Models/BulkUpdateContentsDto.cs

@ -33,6 +33,11 @@ public sealed class BulkUpdateContentsDto
/// </summary> /// </summary>
public bool DoNotScript { get; set; } = true; public bool DoNotScript { get; set; } = true;
/// <summary>
/// True, to also enrich required fields. Default: false.
/// </summary>
public bool EnrichRequiredFields { get; set; }
/// <summary> /// <summary>
/// True to turn off validation for faster inserts. Default: false. /// True to turn off validation for faster inserts. Default: false.
/// </summary> /// </summary>

29
backend/src/Squidex/Areas/Api/Controllers/Contents/Models/EnrichContentDefaultsDto.cs

@ -0,0 +1,29 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using Microsoft.AspNetCore.Mvc;
using Squidex.Domain.Apps.Entities.Contents.Commands;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Reflection;
namespace Squidex.Areas.Api.Controllers.Contents.Models;
public class EnrichContentDefaultsDto
{
/// <summary>
/// True, to also enrich required fields. Default: false.
/// </summary>
[FromQuery(Name = "enrichRequiredFields")]
public bool EnrichRequiredFields { get; set; }
public EnrichContentDefaults ToCommand(DomainId id)
{
var command = SimpleMapper.Map(this, new EnrichContentDefaults { ContentId = id });
return command;
}
}

1
backend/tests/Squidex.Domain.Apps.Entities.Tests/Assets/Queries/EnrichForCachingTests.cs

@ -38,6 +38,7 @@ public class EnrichForCachingTests : GivenContext
"X-Languages", "X-Languages",
"X-NoCleanup", "X-NoCleanup",
"X-NoEnrichment", "X-NoEnrichment",
"X-NoDefaults",
"X-NoResolveLanguages", "X-NoResolveLanguages",
"X-ResolveFlow", "X-ResolveFlow",
"X-ResolveUrls", "X-ResolveUrls",

1
backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Queries/EnrichForCachingTests.cs

@ -39,6 +39,7 @@ public class EnrichForCachingTests : GivenContext
"X-Languages", "X-Languages",
"X-NoCleanup", "X-NoCleanup",
"X-NoEnrichment", "X-NoEnrichment",
"X-NoDefaults",
"X-NoResolveLanguages", "X-NoResolveLanguages",
"X-ResolveFlow", "X-ResolveFlow",
"X-ResolveUrls", "X-ResolveUrls",

3
helm/squidex/templates/service.yaml

@ -11,5 +11,8 @@ spec:
targetPort: http targetPort: http
protocol: TCP protocol: TCP
name: http name: http
{{- if and (eq (lower .Values.service.type) "nodeport") .Values.service.nodePort }}
nodePort: {{ .Values.service.nodePort }}
{{- end }}
selector: selector:
{{- include "squidex.selectors" . | indent 4 }} {{- include "squidex.selectors" . | indent 4 }}

3
helm/squidex/values.yaml

@ -9,6 +9,9 @@ service:
## @param service.port Kubernetes Service port ## @param service.port Kubernetes Service port
## ##
port: 80 port: 80
## @param service.port Kubernetes Service port
##
nodePort: null
deployment: deployment:
## @param deployment.replicaCount Number of instances. ## @param deployment.replicaCount Number of instances.
## ##

3
tools/.editorconfig

@ -30,6 +30,9 @@ dotnet_diagnostic.IDE0305.severity = none
# CA1707: Identifiers should not contain underscores # CA1707: Identifiers should not contain underscores
dotnet_diagnostic.CA1707.severity = none dotnet_diagnostic.CA1707.severity = none
# CA1861: Avoid constant arrays as arguments
dotnet_diagnostic.CA1861.severity = none
# CA2016: Forward the 'CancellationToken' parameter to methods # CA2016: Forward the 'CancellationToken' parameter to methods
dotnet_diagnostic.CA2016.severity = none dotnet_diagnostic.CA2016.severity = none

2
tools/TestSuite/TestSuite.ApiTests/AssetFoldersTests.cs

@ -145,7 +145,7 @@ public class AssetFoldersTests : IClassFixture<CreatedAppFixture>
// STEP 3: Query by nested id. // STEP 3: Query by nested id.
var folders2 = await _.Client.Assets.GetAssetFoldersAsync(folder1.Id); var folders2 = await _.Client.Assets.GetAssetFoldersAsync(folder1.Id);
Assert.Equal(new[] { folder2.Id }, folders2.Items.Select(x => x.Id)); Assert.Equal([folder2.Id], folders2.Items.Select(x => x.Id));
// STEP 3: Query all // STEP 3: Query all

2
tools/TestSuite/TestSuite.ApiTests/ContentQueryTests.cs

@ -633,7 +633,7 @@ public class ContentQueryTests : IClassFixture<ContentQueryFixture>
} }
}; };
var results = await _.Client.SharedDynamicContents.GraphQlAsync<QueryResult>(new[] { query1, query2 }); var results = await _.Client.SharedDynamicContents.GraphQlAsync<QueryResult>([query1, query2]);
var items1 = results.ElementAt(0).Data.Items; var items1 = results.ElementAt(0).Data.Items;
var items2 = results.ElementAt(1).Data.Items; var items2 = results.ElementAt(1).Data.Items;

155
tools/TestSuite/TestSuite.ApiTests/ContentUpdateTests.cs

@ -941,7 +941,7 @@ public class ContentUpdateTests : IClassFixture<ContentFixture>
[InlineData(ContentStrategies.EnrichDefaults.Bulk)] [InlineData(ContentStrategies.EnrichDefaults.Bulk)]
[InlineData(ContentStrategies.EnrichDefaults.BulkWithSchema)] [InlineData(ContentStrategies.EnrichDefaults.BulkWithSchema)]
[InlineData(ContentStrategies.EnrichDefaults.BulkShared)] [InlineData(ContentStrategies.EnrichDefaults.BulkShared)]
public async Task Should_enrich_defaults(ContentStrategies.EnrichDefaults strategy) public async Task Should_enrich_default_fields(ContentStrategies.EnrichDefaults strategy)
{ {
var schemaName = $"schema-{Guid.NewGuid()}"; var schemaName = $"schema-{Guid.NewGuid()}";
@ -949,14 +949,6 @@ public class ContentUpdateTests : IClassFixture<ContentFixture>
var schemaRequest = new CreateSchemaDto var schemaRequest = new CreateSchemaDto
{ {
Name = schemaName, Name = schemaName,
Fields =
[
new UpsertSchemaFieldDto
{
Name = TestEntityData.NumberField,
Properties = new NumberFieldPropertiesDto()
},
],
IsPublished = true IsPublished = true
}; };
@ -968,30 +960,161 @@ public class ContentUpdateTests : IClassFixture<ContentFixture>
// STEP 1: Create a new item. // STEP 1: Create a new item.
var content_0 = await contents.CreateAsync([], ContentCreateOptions.AsPublish); var content_0 = await contents.CreateAsync([], ContentCreateOptions.AsPublish);
Assert.Null(content_0.Data.GetValueOrDefault(TestEntityData.StringField)); Assert.Null(content_0.Data.GetValueOrDefault("fieldDefault"));
// STEP 2: Add required field. // STEP 2: Add new fields.
var fieldRequest = new AddFieldDto var fieldRequest = new AddFieldDto
{ {
Name = TestEntityData.StringField, Name = "fieldDefault",
Properties = new StringFieldPropertiesDto
{
DefaultValue = "Hello Squidex",
IsRequired = false
}
};
await _.Client.Schemas.PostFieldAsync(schemaName, fieldRequest);
// STEP 3: Create required field.
await _.Client.EnrichDefaultsAsync(content_0, content_0.Data, strategy, false);
// STEP 4: Get content.
var context = QueryContext.Default.WithHeaderHandler(request =>
{
request.Headers.TryAddWithoutValidation("X-NoDefaults", "1");
});
var content_1 = await contents.GetAsync(content_0.Id, context);
Assert.Equal("Hello Squidex", content_1.Data["fieldDefault"]!["iv"]!.ToString());
}
[Theory]
[InlineData(ContentStrategies.EnrichDefaults.Normal)]
[InlineData(ContentStrategies.EnrichDefaults.Bulk)]
[InlineData(ContentStrategies.EnrichDefaults.BulkWithSchema)]
[InlineData(ContentStrategies.EnrichDefaults.BulkShared)]
public async Task Should_enrich_non_required_default_fields(ContentStrategies.EnrichDefaults strategy)
{
var schemaName = $"schema-{Guid.NewGuid()}";
// STEP 0: Create initial schema.
var schemaRequest = new CreateSchemaDto
{
Name = schemaName,
IsPublished = true
};
await _.Client.Schemas.PostSchemaAsync(schemaRequest);
var contents = _.Client.DynamicContents(schemaName);
// STEP 1: Create a new item.
var content_0 = await contents.CreateAsync([], ContentCreateOptions.AsPublish);
Assert.Null(content_0.Data.GetValueOrDefault("fieldDefault"));
Assert.Null(content_0.Data.GetValueOrDefault("fieldRequired"));
// STEP 2: Add new fields.
var fieldRequest1 = new AddFieldDto
{
Name = "fieldDefault",
Properties = new StringFieldPropertiesDto
{
DefaultValue = "Hello Squidex",
IsRequired = false
}
};
var fieldRequest2 = new AddFieldDto
{
Name = "fieldRequired",
Properties = new StringFieldPropertiesDto Properties = new StringFieldPropertiesDto
{ {
DefaultValue = "Hello Squidex" DefaultValue = "Hello Required",
IsRequired = true
} }
}; };
await _.Client.Schemas.PostFieldAsync(schemaName, fieldRequest1);
await _.Client.Schemas.PostFieldAsync(schemaName, fieldRequest2);
// STEP 3: Create required field.
await _.Client.EnrichDefaultsAsync(content_0, content_0.Data, strategy, false);
// STEP 4: Get content.
var context = QueryContext.Default.WithHeaderHandler(request =>
{
request.Headers.TryAddWithoutValidation("X-NoDefaults", "1");
});
var content_1 = await contents.GetAsync(content_0.Id, context);
Assert.Equal("Hello Squidex", content_1.Data["fieldDefault"]!["iv"]!.ToString());
Assert.Null(content_0.Data.GetValueOrDefault("fieldRequired"));
}
[Theory]
[InlineData(ContentStrategies.EnrichDefaults.Normal)]
[InlineData(ContentStrategies.EnrichDefaults.Bulk)]
[InlineData(ContentStrategies.EnrichDefaults.BulkWithSchema)]
[InlineData(ContentStrategies.EnrichDefaults.BulkShared)]
public async Task Should_enrich_required_default_field_if_flag_is_true(ContentStrategies.EnrichDefaults strategy)
{
var schemaName = $"schema-{Guid.NewGuid()}";
// STEP 0: Create initial schema.
var schemaRequest = new CreateSchemaDto
{
Name = schemaName,
IsPublished = true
};
await _.Client.Schemas.PostSchemaAsync(schemaRequest);
var contents = _.Client.DynamicContents(schemaName);
// STEP 1: Create a new item.
var content_0 = await contents.CreateAsync([], ContentCreateOptions.AsPublish);
Assert.Null(content_0.Data.GetValueOrDefault("fieldDefault"));
Assert.Null(content_0.Data.GetValueOrDefault("fieldRequired"));
// STEP 2: Add new field.
var fieldRequest = new AddFieldDto
{
Name = "fieldRequired",
Properties = new StringFieldPropertiesDto
{
DefaultValue = "Hello Required",
IsRequired = true
}
};
await _.Client.Schemas.PostFieldAsync(schemaName, fieldRequest); await _.Client.Schemas.PostFieldAsync(schemaName, fieldRequest);
// STEP 3: Create required field. // STEP 3: Create required field.
await _.Client.EnrichDefaultsAsync(content_0, content_0.Data, strategy); await _.Client.EnrichDefaultsAsync(content_0, content_0.Data, strategy, true);
// STEP 4: Get content. // STEP 4: Get content.
var content_1 = await contents.GetAsync(content_0.Id); var context = QueryContext.Default.WithHeaderHandler(request =>
{
request.Headers.TryAddWithoutValidation("X-NoDefaults", "1");
});
var content_1 = await contents.GetAsync(content_0.Id, context);
Assert.Equal("Hello Squidex", content_1.Data[TestEntityData.StringField]!["iv"]!.ToString()); Assert.Equal("Hello Required", content_1.Data["fieldRequired"]!["iv"]!.ToString());
} }
[Fact] [Fact]

15
tools/TestSuite/TestSuite.ApiTests/GraphQLTests.cs

@ -239,7 +239,7 @@ public sealed class GraphQLTests : IClassFixture<GraphQLFixture>
.Select(x => x.Data.Name) .Select(x => x.Data.Name)
.Order(); .Order();
Assert.Equal(new[] { "Leipzig", "Munich" }, cityNames); Assert.Equal(["Leipzig", "Munich"], cityNames);
} }
[Fact] [Fact]
@ -276,7 +276,7 @@ public sealed class GraphQLTests : IClassFixture<GraphQLFixture>
.Select(x => x["data"]!["name"]!.Value<string>()) .Select(x => x["data"]!["name"]!.Value<string>())
.Order(); .Order();
Assert.Equal(new[] { "Leipzig", "Munich" }, cityNames); Assert.Equal(["Leipzig", "Munich"], cityNames);
} }
[Fact] [Fact]
@ -313,7 +313,7 @@ public sealed class GraphQLTests : IClassFixture<GraphQLFixture>
.Select(x => x["data"]!["name"]!.Value<string>()) .Select(x => x["data"]!["name"]!.Value<string>())
.Order(); .Order();
Assert.Equal(new[] { "Leipzig" }, cityNames); Assert.Equal(["Leipzig"], cityNames);
} }
[Fact] [Fact]
@ -341,7 +341,7 @@ public sealed class GraphQLTests : IClassFixture<GraphQLFixture>
.Select(x => x["data"]!["name"]!.Value<string>()) .Select(x => x["data"]!["name"]!.Value<string>())
.Order(); .Order();
Assert.Equal(new[] { "Bavaria", "Saxony" }, stateNames); Assert.Equal(["Bavaria", "Saxony"], stateNames);
} }
[Fact] [Fact]
@ -369,7 +369,7 @@ public sealed class GraphQLTests : IClassFixture<GraphQLFixture>
.Select(x => x!["data"]!["name"]!.Value<string>()) .Select(x => x!["data"]!["name"]!.Value<string>())
.Order(); .Order();
Assert.Equal(new[] { "Saxony" }, stateNames); Assert.Equal(["Saxony"], stateNames);
} }
[Fact] [Fact]
@ -392,7 +392,7 @@ public sealed class GraphQLTests : IClassFixture<GraphQLFixture>
.Select(x => x["data__dynamic"]!["name"]!["iv"]!.Value<string>()) .Select(x => x["data__dynamic"]!["name"]!["iv"]!.Value<string>())
.Order(); .Order();
Assert.Equal(new[] { "Leipzig", "Munich" }, cityNames); Assert.Equal(["Leipzig", "Munich"], cityNames);
} }
[Fact] [Fact]
@ -458,7 +458,7 @@ public sealed class GraphQLTests : IClassFixture<GraphQLFixture>
.Select(x => x["data"]!["name"]!.Value<string>()) .Select(x => x["data"]!["name"]!.Value<string>())
.Order(); .Order();
Assert.Equal(new[] { "Bavaria", "Leipzig", "Munich", "Saxony" }, names); Assert.Equal(["Bavaria", "Leipzig", "Munich", "Saxony"], names);
} }
[Fact] [Fact]
@ -523,6 +523,7 @@ public sealed class GraphQLTests : IClassFixture<GraphQLFixture>
"X-Flatten", "X-Flatten",
"X-Languages", "X-Languages",
"X-NoCleanup", "X-NoCleanup",
"X-NoDefaults",
"X-NoEnrichment", "X-NoEnrichment",
"X-NoResolveLanguages", "X-NoResolveLanguages",
"X-ResolveFlow", "X-ResolveFlow",

20
tools/TestSuite/TestSuite.ApiTests/TestSuite.ApiTests.csproj

@ -8,20 +8,20 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.12.0" /> <PackageReference Include="FluentAssertions" Version="6.12.0" />
<PackageReference Include="GraphQL.Client" Version="6.0.5" /> <PackageReference Include="GraphQL.Client" Version="6.1.0" />
<PackageReference Include="GraphQL.Client.Serializer.Newtonsoft" Version="6.0.5" /> <PackageReference Include="GraphQL.Client.Serializer.Newtonsoft" Version="6.1.0" />
<PackageReference Include="Meziantou.Analyzer" Version="2.0.150"> <PackageReference Include="Meziantou.Analyzer" Version="2.0.163">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
<PackageReference Include="NSwag.Core" Version="14.0.7" /> <PackageReference Include="NSwag.Core" Version="14.1.0" />
<PackageReference Include="Squidex.Assets" Version="6.6.4" /> <PackageReference Include="Squidex.Assets" Version="6.18.0" />
<PackageReference Include="Squidex.Assets.ImageSharp" Version="6.6.4" /> <PackageReference Include="Squidex.Assets.ImageSharp" Version="6.18.0" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" /> <PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
<PackageReference Include="Verify.Xunit" Version="24.2.0" /> <PackageReference Include="Verify.Xunit" Version="26.2.0" />
<PackageReference Include="xunit" Version="2.8.0" /> <PackageReference Include="xunit" Version="2.9.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.0"> <PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference> </PackageReference>

8
tools/TestSuite/TestSuite.LoadTests/TestSuite.LoadTests.csproj

@ -7,14 +7,14 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Meziantou.Analyzer" Version="2.0.150"> <PackageReference Include="Meziantou.Analyzer" Version="2.0.163">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" /> <PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
<PackageReference Include="xunit" Version="2.8.0" /> <PackageReference Include="xunit" Version="2.9.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.0"> <PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference> </PackageReference>

2
tools/TestSuite/TestSuite.Shared/ClientExtensions.cs

@ -338,7 +338,7 @@ public static class ClientExtensions
return temp; return temp;
} }
public static async Task UploadInChunksAsync(this IAssetsClient client, ProgressHandler progress, FileParameter fileParameter, string? id = null) public static async Task UploadInChunksAsync(this IAssetsClient client, ProgressHandler progress, FileParameter fileParameter, string? id = null)
{ {
var pausingStream = new PauseStream(fileParameter.Data, 0.25); var pausingStream = new PauseStream(fileParameter.Data, 0.25);
var pausingFile = new FileParameter(pausingStream, fileParameter.FileName, fileParameter.ContentType) var pausingFile = new FileParameter(pausingStream, fileParameter.FileName, fileParameter.ContentType)

49
tools/TestSuite/TestSuite.Shared/ContentStrategies.cs

@ -21,7 +21,8 @@ public static partial class ContentStrategies
BulkPermanent BulkPermanent
} }
public static Task DeleteAsync(this ISquidexClient client, ContentBase content, Deletion strategy) public static Task DeleteAsync(this ISquidexClient client, ContentBase content,
Deletion strategy)
{ {
IContentsClient<MyContent, object> GetClient() IContentsClient<MyContent, object> GetClient()
{ {
@ -75,7 +76,8 @@ public static partial class ContentStrategies
BulkShared BulkShared
} }
public static Task UpdateAsync(this ISquidexClient client, ContentBase content, object data, Update strategy) public static Task UpdateAsync(this ISquidexClient client, ContentBase content, object data,
Update strategy)
{ {
IContentsClient<MyContent, object> GetClient() IContentsClient<MyContent, object> GetClient()
{ {
@ -157,7 +159,8 @@ public static partial class ContentStrategies
BulkShared BulkShared
} }
public static Task PatchAsync(this ISquidexClient client, ContentBase content, object data, Patch strategy) public static Task PatchAsync(this ISquidexClient client, ContentBase content, object data,
Patch strategy)
{ {
IContentsClient<MyContent, object> GetClient() IContentsClient<MyContent, object> GetClient()
{ {
@ -242,7 +245,8 @@ public static partial class ContentStrategies
UpdateBulk UpdateBulk
} }
public static Task EnrichDefaultsAsync(this ISquidexClient client, ContentBase content, object data, EnrichDefaults strategy) public static Task EnrichDefaultsAsync(this ISquidexClient client, ContentBase content, object data,
EnrichDefaults strategy, bool requiredFields)
{ {
IContentsClient<MyContent, object> GetClient() IContentsClient<MyContent, object> GetClient()
{ {
@ -252,11 +256,27 @@ public static partial class ContentStrategies
switch (strategy) switch (strategy)
{ {
case EnrichDefaults.Normal: case EnrichDefaults.Normal:
return GetClient().EnrichDefaultsAsync(content.Id); var createOptions = new ContentEnrichDefaultsOptions
{
EnrichRequiredFields = requiredFields
};
return GetClient().EnrichDefaultsAsync(content.Id, createOptions);
case EnrichDefaults.Update: case EnrichDefaults.Update:
return GetClient().UpdateAsync(content.Id, data, ContentUpdateOptions.AsEnrichDefaults); var updateOptions = new ContentUpdateOptions
{
EnrichDefaults = true
};
return GetClient().UpdateAsync(content.Id, data, updateOptions);
case EnrichDefaults.Upsert: case EnrichDefaults.Upsert:
return GetClient().UpsertAsync(content.Id, data, ContentUpsertOptions.AsEnrichDefaults); var upsertOptions = new ContentUpsertOptions
{
EnrichDefaults = true,
EnrichRequiredFields = requiredFields
};
return GetClient().UpsertAsync(content.Id, data, upsertOptions);
case EnrichDefaults.Bulk: case EnrichDefaults.Bulk:
return GetClient().BulkUpdateAsync(new BulkUpdate return GetClient().BulkUpdateAsync(new BulkUpdate
{ {
@ -267,7 +287,8 @@ public static partial class ContentStrategies
Type = BulkUpdateType.EnrichDefaults, Type = BulkUpdateType.EnrichDefaults,
Id = content.Id Id = content.Id
}, },
] ],
EnrichRequiredFields = requiredFields
}); });
case EnrichDefaults.UpdateBulk: case EnrichDefaults.UpdateBulk:
return GetClient().BulkUpdateAsync(new BulkUpdate return GetClient().BulkUpdateAsync(new BulkUpdate
@ -281,7 +302,8 @@ public static partial class ContentStrategies
Data = data, Data = data,
EnrichDefaults = true, EnrichDefaults = true,
}, },
] ],
EnrichRequiredFields = requiredFields
}); });
case EnrichDefaults.UpsertBulk: case EnrichDefaults.UpsertBulk:
return GetClient().BulkUpdateAsync(new BulkUpdate return GetClient().BulkUpdateAsync(new BulkUpdate
@ -295,7 +317,8 @@ public static partial class ContentStrategies
Data = data, Data = data,
EnrichDefaults = true, EnrichDefaults = true,
}, },
] ],
EnrichRequiredFields = requiredFields
}); });
case EnrichDefaults.BulkWithSchema: case EnrichDefaults.BulkWithSchema:
return GetClient().BulkUpdateAsync(new BulkUpdate return GetClient().BulkUpdateAsync(new BulkUpdate
@ -308,7 +331,8 @@ public static partial class ContentStrategies
Id = content.Id, Id = content.Id,
Schema = content.SchemaName Schema = content.SchemaName
}, },
] ],
EnrichRequiredFields = requiredFields
}); });
case EnrichDefaults.BulkShared: case EnrichDefaults.BulkShared:
return GetSharedClient(client).BulkUpdateAsync(new BulkUpdate return GetSharedClient(client).BulkUpdateAsync(new BulkUpdate
@ -321,7 +345,8 @@ public static partial class ContentStrategies
Id = content.Id, Id = content.Id,
Schema = content.SchemaName Schema = content.SchemaName
}, },
] ],
EnrichRequiredFields = requiredFields
}); });
default: default:
return Task.CompletedTask; return Task.CompletedTask;

14
tools/TestSuite/TestSuite.Shared/TestSuite.Shared.csproj

@ -7,22 +7,22 @@
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Meziantou.Analyzer" Version="2.0.150"> <PackageReference Include="Meziantou.Analyzer" Version="2.0.163">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="8.0.1" /> <PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="8.0.2" />
<PackageReference Include="Microsoft.Extensions.Configuration.CommandLine" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.CommandLine" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" /> <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" />
<PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" /> <PackageReference Include="RefactoringEssentials" Version="5.6.0" PrivateAssets="all" />
<PackageReference Include="Squidex.Assets" Version="6.6.4" /> <PackageReference Include="Squidex.Assets" Version="6.18.0" />
<PackageReference Include="Squidex.ClientLibrary" Version="19.2.0" /> <PackageReference Include="Squidex.ClientLibrary" Version="19.7.0" />
<PackageReference Include="Squidex.ClientLibrary.ServiceExtensions" Version="19.2.0" /> <PackageReference Include="Squidex.ClientLibrary.ServiceExtensions" Version="19.7.0" />
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" /> <PackageReference Include="StyleCop.Analyzers" Version="1.1.118" PrivateAssets="all" />
<PackageReference Include="Verify" Version="24.2.0" /> <PackageReference Include="Verify" Version="26.2.0" />
<PackageReference Include="xunit" Version="2.8.0" /> <PackageReference Include="xunit" Version="2.9.0" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<AdditionalFiles Include="..\..\stylecop.json" Link="stylecop.json" /> <AdditionalFiles Include="..\..\stylecop.json" Link="stylecop.json" />

Loading…
Cancel
Save