Browse Source

Improve handling of default values. (#983)

* Improve handling of default values.

* Open Api fixes and parent id.
pull/984/head
Sebastian Stehle 3 years ago
committed by GitHub
parent
commit
46837d6195
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 4
      backend/src/Squidex.Domain.Apps.Core.Model/Apps/Json/RolesSurrogate.cs
  2. 4
      backend/src/Squidex.Domain.Apps.Core.Model/Apps/Role.cs
  3. 10
      backend/src/Squidex.Domain.Apps.Core.Model/Apps/Roles.cs
  4. 103
      backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/AddDefaultValues.cs
  5. 8
      backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/AddSchemaNames.cs
  6. 61
      backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/ContentConverter.cs
  7. 92
      backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/DefaultValueChecker.cs
  8. 6
      backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/DefaultValueFactory.cs
  9. 2
      backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/ExcludeChangedTypes.cs
  10. 2
      backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/ExcludeHidden.cs
  11. 31
      backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/IConverter.cs
  12. 31
      backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/ResolveFromPreviousPartitioning.cs
  13. 24
      backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/ResolveLanguages.cs
  14. 57
      backend/src/Squidex.Domain.Apps.Core.Operations/DefaultValues/DefaultValueExtensions.cs
  15. 2
      backend/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ContentReferencesExtensions.cs
  16. 4
      backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetFolderRepository.cs
  17. 4
      backend/src/Squidex.Domain.Apps.Entities/Apps/AppUISettings.cs
  18. 5
      backend/src/Squidex.Domain.Apps.Entities/Assets/IAssetQueryService.cs
  19. 29
      backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/AssetQueryService.cs
  20. 4
      backend/src/Squidex.Domain.Apps.Entities/Assets/Repositories/IAssetFolderRepository.cs
  21. 2
      backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/ContentDomainObject.cs
  22. 12
      backend/src/Squidex.Domain.Apps.Entities/Contents/DomainObject/Guards/ValidationExtensions.cs
  23. 2
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/NestedInputGraphType.cs
  24. 4
      backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Primitives/JsonGraphType.cs
  25. 17
      backend/src/Squidex.Domain.Apps.Entities/Contents/Queries/Steps/ConvertData.cs
  26. 11
      backend/src/Squidex.Domain.Users.MongoDb/MongoUserStore.cs
  27. 2
      backend/src/Squidex.Web/ErrorDto.cs
  28. 13
      backend/src/Squidex.Web/OpenApiRequestAttribute.cs
  29. 18
      backend/src/Squidex/Areas/Api/Config/OpenApi/OpenApiServices.cs
  30. 46
      backend/src/Squidex/Areas/Api/Config/OpenApi/RequiredSchemaProcessor.cs
  31. 2
      backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AddLanguageDto.cs
  32. 2
      backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AddRoleDto.cs
  33. 2
      backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AddWorkflowDto.cs
  34. 4
      backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AppDto.cs
  35. 3
      backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AppLanguageDto.cs
  36. 1
      backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AppLanguagesDto.cs
  37. 2
      backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AppSettingsDto.cs
  38. 4
      backend/src/Squidex/Areas/Api/Controllers/Apps/Models/ClientDto.cs
  39. 1
      backend/src/Squidex/Areas/Api/Controllers/Apps/Models/ClientsDto.cs
  40. 2
      backend/src/Squidex/Areas/Api/Controllers/Apps/Models/CreateAppDto.cs
  41. 2
      backend/src/Squidex/Areas/Api/Controllers/Apps/Models/CreateClientDto.cs
  42. 2
      backend/src/Squidex/Areas/Api/Controllers/Apps/Models/EditorDto.cs
  43. 2
      backend/src/Squidex/Areas/Api/Controllers/Apps/Models/PatternDto.cs
  44. 4
      backend/src/Squidex/Areas/Api/Controllers/Apps/Models/RoleDto.cs
  45. 2
      backend/src/Squidex/Areas/Api/Controllers/Apps/Models/RolesDto.cs
  46. 2
      backend/src/Squidex/Areas/Api/Controllers/Apps/Models/TransferToTeamDto.cs
  47. 2
      backend/src/Squidex/Areas/Api/Controllers/Apps/Models/UpdateAppDto.cs
  48. 7
      backend/src/Squidex/Areas/Api/Controllers/Apps/Models/UpdateAppSettingsDto.cs
  49. 2
      backend/src/Squidex/Areas/Api/Controllers/Apps/Models/UpdateAssetScriptsDto.cs
  50. 2
      backend/src/Squidex/Areas/Api/Controllers/Apps/Models/UpdateClientDto.cs
  51. 2
      backend/src/Squidex/Areas/Api/Controllers/Apps/Models/UpdateLanguageDto.cs
  52. 2
      backend/src/Squidex/Areas/Api/Controllers/Apps/Models/UpdateRoleDto.cs
  53. 2
      backend/src/Squidex/Areas/Api/Controllers/Apps/Models/UpdateWorkflowDto.cs
  54. 2
      backend/src/Squidex/Areas/Api/Controllers/Apps/Models/WorkflowDto.cs
  55. 3
      backend/src/Squidex/Areas/Api/Controllers/Apps/Models/WorkflowStepDto.cs
  56. 3
      backend/src/Squidex/Areas/Api/Controllers/Apps/Models/WorkflowsDto.cs
  57. 46
      backend/src/Squidex/Areas/Api/Controllers/Assets/AssetFoldersController.cs
  58. 2
      backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AnnotateAssetDto.cs
  59. 9
      backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetDto.cs
  60. 1
      backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetFolderDto.cs
  61. 2
      backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetFoldersDto.cs
  62. 1
      backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetsDto.cs
  63. 3
      backend/src/Squidex/Areas/Api/Controllers/Assets/Models/BulkUpdateAssetsDto.cs
  64. 2
      backend/src/Squidex/Areas/Api/Controllers/Assets/Models/BulkUpdateAssetsJobDto.cs
  65. 2
      backend/src/Squidex/Areas/Api/Controllers/Assets/Models/CreateAssetDto.cs
  66. 2
      backend/src/Squidex/Areas/Api/Controllers/Assets/Models/CreateAssetFolderDto.cs
  67. 2
      backend/src/Squidex/Areas/Api/Controllers/Assets/Models/DeleteAssetDto.cs
  68. 2
      backend/src/Squidex/Areas/Api/Controllers/Assets/Models/MoveAssetDto.cs
  69. 2
      backend/src/Squidex/Areas/Api/Controllers/Assets/Models/MoveAssetFolderDto.cs
  70. 2
      backend/src/Squidex/Areas/Api/Controllers/Assets/Models/RenameAssetFolderDto.cs
  71. 2
      backend/src/Squidex/Areas/Api/Controllers/Assets/Models/UpsertAssetDto.cs
  72. 2
      backend/src/Squidex/Areas/Api/Controllers/AssignContributorDto.cs
  73. 2
      backend/src/Squidex/Areas/Api/Controllers/Backups/Models/BackupJobsDto.cs
  74. 3
      backend/src/Squidex/Areas/Api/Controllers/Backups/Models/RestoreJobDto.cs
  75. 2
      backend/src/Squidex/Areas/Api/Controllers/Backups/Models/RestoreRequestDto.cs
  76. 4
      backend/src/Squidex/Areas/Api/Controllers/Comments/Models/CommentDto.cs
  77. 2
      backend/src/Squidex/Areas/Api/Controllers/Comments/Models/UpsertCommentDto.cs
  78. 1
      backend/src/Squidex/Areas/Api/Controllers/Contents/ContentsController.cs
  79. 2
      backend/src/Squidex/Areas/Api/Controllers/Contents/Models/AllContentsByGetDto.cs
  80. 2
      backend/src/Squidex/Areas/Api/Controllers/Contents/Models/AllContentsByPostDto.cs
  81. 2
      backend/src/Squidex/Areas/Api/Controllers/Contents/Models/BulkUpdateContentsDto.cs
  82. 2
      backend/src/Squidex/Areas/Api/Controllers/Contents/Models/BulkUpdateContentsJobDto.cs
  83. 2
      backend/src/Squidex/Areas/Api/Controllers/Contents/Models/ChangeStatusDto.cs
  84. 3
      backend/src/Squidex/Areas/Api/Controllers/Contents/Models/ContentDto.cs
  85. 2
      backend/src/Squidex/Areas/Api/Controllers/Contents/Models/ContentsDto.cs
  86. 2
      backend/src/Squidex/Areas/Api/Controllers/Contents/Models/ImportContentsDto.cs
  87. 1
      backend/src/Squidex/Areas/Api/Controllers/Contents/Models/ScheduleJobDto.cs
  88. 2
      backend/src/Squidex/Areas/Api/Controllers/Contents/Models/StatusInfoDto.cs
  89. 2
      backend/src/Squidex/Areas/Api/Controllers/Contents/Models/UpsertContentDto.cs
  90. 3
      backend/src/Squidex/Areas/Api/Controllers/ContributorDto.cs
  91. 1
      backend/src/Squidex/Areas/Api/Controllers/ContributorsDto.cs
  92. 3
      backend/src/Squidex/Areas/Api/Controllers/History/Models/HistoryEventDto.cs
  93. 3
      backend/src/Squidex/Areas/Api/Controllers/LanguageDto.cs
  94. 2
      backend/src/Squidex/Areas/Api/Controllers/News/Models/FeatureDto.cs
  95. 1
      backend/src/Squidex/Areas/Api/Controllers/News/Models/FeaturesDto.cs
  96. 2
      backend/src/Squidex/Areas/Api/Controllers/Plans/Models/ChangePlanDto.cs
  97. 3
      backend/src/Squidex/Areas/Api/Controllers/Plans/Models/PlanDto.cs
  98. 1
      backend/src/Squidex/Areas/Api/Controllers/Plans/Models/PlansDto.cs
  99. 2
      backend/src/Squidex/Areas/Api/Controllers/RenameTagDto.cs
  100. 2
      backend/src/Squidex/Areas/Api/Controllers/Rules/Models/CreateRuleDto.cs

4
backend/src/Squidex.Domain.Apps.Core.Model/Apps/Json/RolesSurrogate.cs

@ -25,7 +25,7 @@ public sealed class RolesSurrogate : Dictionary<string, JsonValue>, ISurrogate<R
}
var role =
new JsonObject()
JsonValue.Object()
.Add("permissions", permissions)
.Add("properties", customRole.Properties);
@ -44,7 +44,7 @@ public sealed class RolesSurrogate : Dictionary<string, JsonValue>, ISurrogate<R
{
var (key, value) = x;
var properties = new JsonObject();
var properties = JsonValue.Object();
var permissions = PermissionSet.Empty;
if (value.Value is JsonArray a)

4
backend/src/Squidex.Domain.Apps.Core.Model/Apps/Role.cs

@ -38,7 +38,7 @@ public sealed record Role(string Name, PermissionSet? Permissions = null, JsonOb
public string Name { get; } = Guard.NotNullOrEmpty(Name);
public JsonObject Properties { get; } = Properties ?? new JsonObject();
public JsonObject Properties { get; } = Properties ?? JsonValue.Object();
public PermissionSet Permissions { get; } = Permissions ?? PermissionSet.Empty;
@ -49,7 +49,7 @@ public sealed record Role(string Name, PermissionSet? Permissions = null, JsonOb
public static Role WithPermissions(string name, params string[] permissions)
{
return new Role(name, new PermissionSet(permissions), new JsonObject());
return new Role(name, new PermissionSet(permissions), JsonValue.Object());
}
public static Role WithProperties(string name, JsonObject properties)

10
backend/src/Squidex.Domain.Apps.Core.Model/Apps/Roles.cs

@ -25,13 +25,13 @@ public sealed class Roles
new Role(Role.Owner,
new PermissionSet(
WithoutPrefix(PermissionIds.App)),
new JsonObject()),
JsonValue.Object()),
[Role.Reader] =
new Role(Role.Reader,
new PermissionSet(
WithoutPrefix(PermissionIds.AppAssetsRead),
WithoutPrefix(PermissionIds.AppContentsRead)),
new JsonObject()
JsonValue.Object()
.Add("ui.api.hide", true)),
[Role.Editor] =
new Role(Role.Editor,
@ -40,7 +40,7 @@ public sealed class Roles
WithoutPrefix(PermissionIds.AppContents),
WithoutPrefix(PermissionIds.AppRolesRead),
WithoutPrefix(PermissionIds.AppWorkflowsRead)),
new JsonObject()
JsonValue.Object()
.Add("ui.api.hide", true)),
[Role.Developer] =
new Role(Role.Developer,
@ -51,7 +51,7 @@ public sealed class Roles
WithoutPrefix(PermissionIds.AppRules),
WithoutPrefix(PermissionIds.AppSchemas),
WithoutPrefix(PermissionIds.AppWorkflows)),
new JsonObject())
JsonValue.Object())
};
public static readonly Roles Empty = new Roles(new ReadonlyDictionary<string, Role>());
@ -105,7 +105,7 @@ public sealed class Roles
return this;
}
var newRole = new Role(name, null, new JsonObject());
var newRole = new Role(name, null, JsonValue.Object());
if (!inner.TryAdd(name, newRole, out var updated))
{

103
backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/AddDefaultValues.cs

@ -0,0 +1,103 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using NodaTime;
using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Infrastructure.Json.Objects;
namespace Squidex.Domain.Apps.Core.ConvertContent;
public sealed class AddDefaultValues : IContentDataConverter, IContentItemConverter, IContentFieldConverter
{
private readonly PartitionResolver partitionResolver;
private readonly IClock clock;
private Instant now;
public bool IgnoreRequiredFields { get; init; }
public bool IgnoreNonMasterFields { get; init; }
public AddDefaultValues(PartitionResolver partitionResolver, IClock? clock = null)
{
this.partitionResolver = partitionResolver;
this.clock = clock ?? SystemClock.Instance;
}
public void ConvertDataBefore(Schema schema, ContentData data)
{
foreach (var field in schema.Fields)
{
if (data.TryGetValue(field.Name, out var fieldData) && fieldData != null)
{
continue;
}
if ((field.RawProperties.IsRequired && IgnoreRequiredFields) || !DefaultValueChecker.HasDefaultValue(field))
{
continue;
}
data[field.Name] = new ContentFieldData();
}
}
public ContentFieldData? ConvertFieldAfter(IRootField field, ContentFieldData source)
{
var partitioning = partitionResolver(field.Partitioning);
foreach (var partitionKey in partitioning.AllKeys)
{
if (!partitioning.IsMaster(partitionKey) && IgnoreNonMasterFields)
{
continue;
}
Enrich(field, source, partitionKey);
}
return source;
}
public JsonObject ConvertItemBefore(IField parentField, JsonObject source, IEnumerable<IField> schema)
{
foreach (var field in schema)
{
Enrich(field, source, field.Name);
}
return source;
}
private void Enrich(IField field, Dictionary<string, JsonValue> fieldData, string key)
{
if (fieldData.TryGetValue(key, out _) || (field.RawProperties.IsRequired && IgnoreRequiredFields))
{
return;
}
var defaultValue = DefaultValueFactory.CreateDefaultValue(field, GetNow(), key);
if (defaultValue == default)
{
return;
}
fieldData[key] = defaultValue;
}
private Instant GetNow()
{
if (now == default)
{
now = clock.GetCurrentInstant();
}
return now;
}
}

8
backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/AddSchemaNames.cs

@ -21,9 +21,9 @@ public sealed class AddSchemaNames : IContentItemConverter
this.components = components;
}
public JsonObject ConvertItem(IField field, JsonObject source)
public JsonObject ConvertItemBefore(IField parentField, JsonObject source, IEnumerable<IField> schema)
{
if (field is IArrayField)
if (parentField is IArrayField)
{
return source;
}
@ -40,9 +40,9 @@ public sealed class AddSchemaNames : IContentItemConverter
var id = DomainId.Create(discriminator);
if (components.TryGetValue(id, out var schema))
if (components.TryGetValue(id, out var component))
{
source["schemaName"] = schema.Name;
source["schemaName"] = component.Name;
}
return source;

61
backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/ContentConverter.cs

@ -16,8 +16,8 @@ namespace Squidex.Domain.Apps.Core.ConvertContent;
public sealed class ContentConverter
{
private readonly List<IContentDataConverter> dataConverters = new List<IContentDataConverter>();
private readonly List<IContentItemConverter> itemConverters = new List<IContentItemConverter>();
private readonly List<IContentFieldAfterConverter> fieldAfterConverters = new List<IContentFieldAfterConverter>();
private readonly List<IContentFieldConverter> fieldConverters = new List<IContentFieldConverter>();
private readonly List<IContentValueConverter> valueConverters = new List<IContentValueConverter>();
private readonly ResolvedComponents components;
@ -31,6 +31,11 @@ public sealed class ContentConverter
public ContentConverter Add(IConverter converter)
{
if (converter is IContentDataConverter contentConverter)
{
dataConverters.Add(contentConverter);
}
if (converter is IContentItemConverter itemConverter)
{
itemConverters.Add(itemConverter);
@ -41,11 +46,6 @@ public sealed class ContentConverter
fieldConverters.Add(fieldConverter);
}
if (converter is IContentFieldAfterConverter fieldAfterConverter)
{
fieldAfterConverters.Add(fieldAfterConverter);
}
if (converter is IContentValueConverter valueConverter)
{
valueConverters.Add(valueConverter);
@ -56,12 +56,16 @@ public sealed class ContentConverter
public ContentData Convert(ContentData content)
{
Guard.NotNull(schema);
// The conversion process assumes that we have ownership of the data and can manipulate it.
// Clones are only created to save allocations.
var result = new ContentData(content.Count);
// Some conversions should be made early, e.g. calculating default values.
foreach (var converter in dataConverters)
{
converter.ConvertDataBefore(schema, content);
}
foreach (var (fieldName, fieldData) in content)
{
if (fieldData == null || !schema.FieldsByName.TryGetValue(fieldName, out var field))
@ -88,34 +92,44 @@ public sealed class ContentConverter
}
}
// Some conversions should be done later.
foreach (var converter in dataConverters)
{
converter.ConvertDataAfter(schema, result);
}
return result;
}
private ContentFieldData? ConvertField(IRootField field, ContentFieldData? data)
private ContentFieldData? ConvertField(IRootField field, ContentFieldData data)
{
foreach (var converter in fieldConverters)
{
data = converter.ConvertField(field, data!);
var newData = converter.ConvertFieldBefore(field, data);
if (data == null)
if (newData == null)
{
break;
return null;
}
data = newData;
}
return data;
}
private ContentFieldData? ConvertFieldAfter(IRootField field, ContentFieldData? data)
private ContentFieldData? ConvertFieldAfter(IRootField field, ContentFieldData data)
{
foreach (var converter in fieldAfterConverters)
foreach (var converter in fieldConverters)
{
data = converter.ConvertFieldAfter(field, data!);
var newData = converter.ConvertFieldAfter(field, data);
if (data == null)
if (newData == null)
{
break;
return null;
}
data = newData;
}
return data;
@ -206,7 +220,7 @@ public sealed class ContentConverter
return (true, default);
}
return (false, ConvertNested(component.FieldCollection, obj, parent));
return (false, ConvertNested(component.FieldCollection, obj, parent, component.Fields));
}
private (bool Remove, JsonValue) ConvertArrayItem(IArrayField field, JsonValue value)
@ -216,7 +230,7 @@ public sealed class ContentConverter
return (true, default);
}
return (false, ConvertNested(field.FieldCollection, obj, field));
return (false, ConvertNested(field.FieldCollection, obj, field, field.Fields));
}
private ContentFieldData ConvertValues(IField field, ContentFieldData source)
@ -244,8 +258,13 @@ public sealed class ContentConverter
return result ?? source;
}
private JsonValue ConvertNested<T>(FieldCollection<T> fields, JsonObject source, IField parent) where T : IField
private JsonValue ConvertNested<T>(FieldCollection<T> fields, JsonObject source, IField parent, IEnumerable<IField> fieldSchema) where T : IField
{
foreach (var converter in itemConverters)
{
source = converter.ConvertItemBefore(parent, source, fieldSchema);
}
JsonObject? result = null;
foreach (var (key, oldValue) in source)
@ -281,7 +300,7 @@ public sealed class ContentConverter
foreach (var converter in itemConverters)
{
result = converter.ConvertItem(parent, result);
result = converter.ConvertItemAfter(parent, result, fieldSchema);
}
return result ?? source;

92
backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/DefaultValueChecker.cs

@ -0,0 +1,92 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Infrastructure;
namespace Squidex.Domain.Apps.Core.ConvertContent;
internal sealed class DefaultValueChecker : IFieldPropertiesVisitor<bool, None>
{
private static readonly DefaultValueChecker Instance = new DefaultValueChecker();
private DefaultValueChecker()
{
}
public static bool HasDefaultValue(IField field)
{
Guard.NotNull(field);
return field.RawProperties.Accept(Instance, None.Value);
}
public bool Visit(ArrayFieldProperties properties, None args)
{
return true;
}
public bool Visit(AssetsFieldProperties properties, None args)
{
return properties.DefaultValue != null || properties.DefaultValues != null;
}
public bool Visit(BooleanFieldProperties properties, None args)
{
return properties.DefaultValue != null || properties.DefaultValues != null;
}
public bool Visit(ComponentFieldProperties properties, None args)
{
return false;
}
public bool Visit(ComponentsFieldProperties properties, None args)
{
return true;
}
public bool Visit(DateTimeFieldProperties properties, None args)
{
return properties.DefaultValue != null || properties.DefaultValues != null || properties.CalculatedDefaultValue != null;
}
public bool Visit(GeolocationFieldProperties properties, None args)
{
return false;
}
public bool Visit(JsonFieldProperties properties, None args)
{
return false;
}
public bool Visit(NumberFieldProperties properties, None args)
{
return properties.DefaultValue != null || properties.DefaultValues != null;
}
public bool Visit(ReferencesFieldProperties properties, None args)
{
return properties.DefaultValue != null || properties.DefaultValues != null;
}
public bool Visit(StringFieldProperties properties, None args)
{
return properties.DefaultValue != null || properties.DefaultValues != null;
}
public bool Visit(TagsFieldProperties properties, None args)
{
return properties.DefaultValue != null || properties.DefaultValues != null;
}
public bool Visit(UIFieldProperties properties, None args)
{
return false;
}
}

6
backend/src/Squidex.Domain.Apps.Core.Operations/DefaultValues/DefaultValueFactory.cs → backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/DefaultValueFactory.cs

@ -13,7 +13,7 @@ using Squidex.Infrastructure.Json.Objects;
#pragma warning disable SA1313 // Parameter names should begin with lower-case letter
namespace Squidex.Domain.Apps.Core.DefaultValues;
namespace Squidex.Domain.Apps.Core.ConvertContent;
public sealed class DefaultValueFactory : IFieldPropertiesVisitor<JsonValue, DefaultValueFactory.Args>
{
@ -30,9 +30,7 @@ public sealed class DefaultValueFactory : IFieldPropertiesVisitor<JsonValue, Def
Guard.NotNull(field);
Guard.NotNull(partition);
var x = field.RawProperties.Accept(Instance, new Args(now, partition));
return x;
return field.RawProperties.Accept(Instance, new Args(now, partition));
}
public JsonValue Visit(ArrayFieldProperties properties, Args args)

2
backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/ExcludeChangedTypes.cs

@ -22,7 +22,7 @@ public sealed class ExcludeChangedTypes : IContentFieldConverter, IContentValueC
this.serializer = serializer;
}
public ContentFieldData? ConvertField(IRootField field, ContentFieldData source)
public ContentFieldData? ConvertFieldBefore(IRootField field, ContentFieldData source)
{
foreach (var (_, value) in source)
{

2
backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/ExcludeHidden.cs

@ -19,7 +19,7 @@ public sealed class ExcludeHidden : IContentFieldConverter, IContentValueConvert
{
}
public ContentFieldData? ConvertField(IRootField field, ContentFieldData source)
public ContentFieldData? ConvertFieldBefore(IRootField field, ContentFieldData source)
{
return field.IsForApi() ? source : null;
}

31
backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/IConverter.cs

@ -8,6 +8,7 @@
using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Infrastructure.Json.Objects;
using static Google.Rpc.Context.AttributeContext.Types;
#pragma warning disable MA0048 // File name must match type name
@ -17,19 +18,41 @@ public interface IConverter
{
}
public interface IContentFieldAfterConverter : IConverter
public interface IContentDataConverter
{
ContentFieldData? ConvertFieldAfter(IRootField field, ContentFieldData source);
void ConvertDataBefore(Schema schema, ContentData source)
{
}
void ConvertDataAfter(Schema schema, ContentData source)
{
}
}
public interface IContentFieldConverter : IConverter
{
ContentFieldData? ConvertField(IRootField field, ContentFieldData source);
ContentFieldData? ConvertFieldBefore(IRootField field, ContentFieldData source)
{
return source;
}
ContentFieldData? ConvertFieldAfter(IRootField field, ContentFieldData source)
{
return source;
}
}
public interface IContentItemConverter : IConverter
{
JsonObject ConvertItem(IField field, JsonObject source);
JsonObject ConvertItemBefore(IField parentField, JsonObject source, IEnumerable<IField> schema)
{
return source;
}
JsonObject ConvertItemAfter(IField parentField, JsonObject source, IEnumerable<IField> schema)
{
return source;
}
}
public interface IContentValueConverter : IConverter

31
backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/ResolveInvariant.cs → backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/ResolveFromPreviousPartitioning.cs

@ -11,22 +11,47 @@ using Squidex.Domain.Apps.Core.Schemas;
namespace Squidex.Domain.Apps.Core.ConvertContent;
public sealed class ResolveInvariant : IContentFieldAfterConverter
public sealed class ResolveFromPreviousPartitioning : IContentFieldConverter
{
private readonly LanguagesConfig languages;
public ResolveInvariant(LanguagesConfig languages)
public ResolveFromPreviousPartitioning(LanguagesConfig languages)
{
this.languages = languages;
}
public ContentFieldData? ConvertFieldAfter(IRootField field, ContentFieldData source)
{
if (!field.Partitioning.Equals(Partitioning.Invariant))
if (field.Partitioning.Equals(Partitioning.Invariant))
{
return ResolveInvariant(source);
}
else
{
return ResolveLocalized(source);
}
}
private ContentFieldData ResolveLocalized(ContentFieldData source)
{
if (source.TryGetNonNull(languages.Master, out _))
{
return source;
}
if (source.TryGetNonNull(InvariantPartitioning.Key, out var value))
{
source = new ContentFieldData
{
[languages.Master] = value
};
}
return source;
}
private ContentFieldData ResolveInvariant(ContentFieldData source)
{
if (source.TryGetNonNull(InvariantPartitioning.Key, out _))
{
return source;

24
backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/ResolveLanguages.cs

@ -12,13 +12,14 @@ using Squidex.Infrastructure;
namespace Squidex.Domain.Apps.Core.ConvertContent;
public sealed class ResolveLanguages : IContentFieldAfterConverter
public sealed class ResolveLanguages : IContentFieldConverter
{
private readonly LanguagesConfig languages;
private readonly bool resolveFallback;
private readonly HashSet<string> languageCodes;
public ResolveLanguages(LanguagesConfig languages, bool resolveFallback = true, params Language[] filteredLanguages)
public bool ResolveFallback { get; init; }
public ResolveLanguages(LanguagesConfig languages, params Language[] filteredLanguages)
{
this.languages = languages;
@ -35,8 +36,6 @@ public sealed class ResolveLanguages : IContentFieldAfterConverter
{
languageCodes.Add(languages.Master);
}
this.resolveFallback = resolveFallback;
}
public ContentFieldData? ConvertFieldAfter(IRootField field, ContentFieldData source)
@ -46,15 +45,7 @@ public sealed class ResolveLanguages : IContentFieldAfterConverter
return source;
}
if (source.TryGetNonNull(InvariantPartitioning.Key, out var value))
{
source = new ContentFieldData
{
[languages.Master] = value
};
}
if (resolveFallback)
if (ResolveFallback)
{
foreach (var languageCode in languageCodes)
{
@ -65,6 +56,11 @@ public sealed class ResolveLanguages : IContentFieldAfterConverter
foreach (var fallback in languages.GetPriorities(languageCode))
{
if (fallback == languageCode)
{
continue;
}
if (source.TryGetNonNull(fallback, out var fallbackValue))
{
source[languageCode] = fallbackValue;

57
backend/src/Squidex.Domain.Apps.Core.Operations/DefaultValues/DefaultValueExtensions.cs

@ -1,57 +0,0 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using NodaTime;
using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Core.Schemas;
using Squidex.Infrastructure;
namespace Squidex.Domain.Apps.Core.DefaultValues;
public static class DefaultValueExtensions
{
public static void GenerateDefaultValues(this ContentData data, Schema schema, PartitionResolver partitionResolver)
{
Guard.NotNull(schema);
Guard.NotNull(partitionResolver);
foreach (var field in schema.Fields)
{
var fieldData = data.GetOrCreate(field.Name, _ => new ContentFieldData());
if (fieldData != null)
{
var partitioning = partitionResolver(field.Partitioning);
foreach (var partitionKey in partitioning.AllKeys)
{
Enrich(field, fieldData, partitionKey);
}
if (fieldData.Count > 0)
{
data[field.Name] = fieldData;
}
}
}
}
private static void Enrich(IField field, ContentFieldData fieldData, string partitionKey)
{
var defaultValue = DefaultValueFactory.CreateDefaultValue(field, SystemClock.Instance.GetCurrentInstant(), partitionKey);
if (field.RawProperties.IsRequired || defaultValue == default)
{
return;
}
if (!fieldData.TryGetValue(partitionKey, out _))
{
fieldData.AddLocalized(partitionKey, defaultValue);
}
}
}

2
backend/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ContentReferencesExtensions.cs

@ -105,7 +105,7 @@ public static class ContentReferencesExtensions
Guard.NotNull(schema);
Guard.NotNull(partitioning);
var result = new JsonObject();
var result = JsonValue.Object();
foreach (var partitionKey in partitioning.AllKeys)
{

4
backend/src/Squidex.Domain.Apps.Entities.MongoDb/Assets/MongoAssetFolderRepository.cs

@ -38,7 +38,7 @@ public sealed partial class MongoAssetFolderRepository : MongoRepositoryBase<Mon
}, ct);
}
public async Task<IResultList<IAssetFolderEntity>> QueryAsync(DomainId appId, DomainId parentId,
public async Task<IResultList<IAssetFolderEntity>> QueryAsync(DomainId appId, DomainId? parentId,
CancellationToken ct = default)
{
using (Telemetry.Activities.StartActivity("MongoAssetFolderRepository/QueryAsync"))
@ -53,7 +53,7 @@ public sealed partial class MongoAssetFolderRepository : MongoRepositoryBase<Mon
}
}
public async Task<IReadOnlyList<DomainId>> QueryChildIdsAsync(DomainId appId, DomainId parentId,
public async Task<IReadOnlyList<DomainId>> QueryChildIdsAsync(DomainId appId, DomainId? parentId,
CancellationToken ct = default)
{
using (Telemetry.Activities.StartActivity("MongoAssetFolderRepository/QueryChildIdsAsync"))

4
backend/src/Squidex.Domain.Apps.Entities/Apps/AppUISettings.cs

@ -18,7 +18,7 @@ public sealed class AppUISettings : IAppUISettings, IDeleter
[CollectionName("UISettings")]
public sealed class State
{
public JsonObject Settings { get; set; } = new JsonObject();
public JsonObject Settings { get; set; } = JsonValue.Object();
public bool Set(JsonObject settings)
{
@ -82,7 +82,7 @@ public sealed class AppUISettings : IAppUISettings, IDeleter
{
if (add)
{
found = new JsonObject();
found = JsonValue.Object();
current[segment] = found;
}

5
backend/src/Squidex.Domain.Apps.Entities/Assets/IAssetQueryService.cs

@ -14,10 +14,7 @@ public interface IAssetQueryService
Task<IResultList<IEnrichedAssetEntity>> QueryAsync(Context context, DomainId? parentId, Q q,
CancellationToken ct = default);
Task<IResultList<IAssetFolderEntity>> QueryAssetFoldersAsync(Context context, DomainId parentId,
CancellationToken ct = default);
Task<IResultList<IAssetFolderEntity>> QueryAssetFoldersAsync(DomainId appId, DomainId parentId,
Task<IResultList<IAssetFolderEntity>> QueryAssetFoldersAsync(Context context, DomainId? parentId,
CancellationToken ct = default);
Task<IReadOnlyList<IAssetFolderEntity>> FindAssetFolderAsync(DomainId appId, DomainId id,

29
backend/src/Squidex.Domain.Apps.Entities/Assets/Queries/AssetQueryService.cs

@ -64,20 +64,7 @@ public sealed class AssetQueryService : IAssetQueryService
}
}
public async Task<IResultList<IAssetFolderEntity>> QueryAssetFoldersAsync(DomainId appId, DomainId parentId,
CancellationToken ct = default)
{
using (var activity = Telemetry.Activities.StartActivity("AssetQueryService/QueryAssetFoldersAsync"))
{
activity?.SetTag("folderId", parentId);
var assetFolders = await QueryFoldersCoreAsync(appId, parentId, ct);
return assetFolders;
}
}
public async Task<IResultList<IAssetFolderEntity>> QueryAssetFoldersAsync(Context context, DomainId parentId,
public async Task<IResultList<IAssetFolderEntity>> QueryAssetFoldersAsync(Context context, DomainId? parentId,
CancellationToken ct = default)
{
using (var activity = Telemetry.Activities.StartActivity("AssetQueryService/QueryAssetFoldersAsync"))
@ -243,7 +230,7 @@ public sealed class AssetQueryService : IAssetQueryService
}
}
private async Task<IResultList<IAssetFolderEntity>> QueryFoldersCoreAsync(Context context, DomainId parentId,
private async Task<IResultList<IAssetFolderEntity>> QueryFoldersCoreAsync(Context context, DomainId? parentId,
CancellationToken ct)
{
using (var combined = CancellationTokenSource.CreateLinkedTokenSource(ct))
@ -255,18 +242,6 @@ public sealed class AssetQueryService : IAssetQueryService
}
}
private async Task<IResultList<IAssetFolderEntity>> QueryFoldersCoreAsync(DomainId appId, DomainId parentId,
CancellationToken ct)
{
using (var combined = CancellationTokenSource.CreateLinkedTokenSource(ct))
{
// Enforce a hard timeout
combined.CancelAfter(options.TimeoutQuery);
return await assetFolderRepository.QueryAsync(appId, parentId, combined.Token);
}
}
private async Task<IResultList<IAssetEntity>> QueryCoreAsync(Context context, DomainId? parentId, Q q,
CancellationToken ct)
{

4
backend/src/Squidex.Domain.Apps.Entities/Assets/Repositories/IAssetFolderRepository.cs

@ -11,10 +11,10 @@ namespace Squidex.Domain.Apps.Entities.Assets.Repositories;
public interface IAssetFolderRepository
{
Task<IResultList<IAssetFolderEntity>> QueryAsync(DomainId appId, DomainId parentId,
Task<IResultList<IAssetFolderEntity>> QueryAsync(DomainId appId, DomainId? parentId,
CancellationToken ct = default);
Task<IReadOnlyList<DomainId>> QueryChildIdsAsync(DomainId appId, DomainId parentId,
Task<IReadOnlyList<DomainId>> QueryChildIdsAsync(DomainId appId, DomainId? parentId,
CancellationToken ct = default);
Task<IAssetFolderEntity?> FindAssetFolderAsync(DomainId appId, DomainId id,

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

@ -246,7 +246,7 @@ public partial class ContentDomainObject : DomainObject<ContentDomainObject.Stat
c.Data = await operation.ExecuteCreateScriptAsync(c.Data, status, ct);
}
operation.GenerateDefaultValues(c.Data);
c.Data = operation.GenerateDefaultValues(c.Data);
if (!c.DoNotValidate)
{

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

@ -7,7 +7,7 @@
using Squidex.Domain.Apps.Core;
using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Core.DefaultValues;
using Squidex.Domain.Apps.Core.ConvertContent;
using Squidex.Domain.Apps.Core.ValidateContent;
using Squidex.Domain.Apps.Entities.Apps;
using Squidex.Domain.Apps.Entities.Contents.Repositories;
@ -87,9 +87,15 @@ public static class ValidationExtensions
operation.AddErrors(validator.Errors).ThrowOnErrors();
}
public static void GenerateDefaultValues(this ContentOperation operation, ContentData data)
public static ContentData GenerateDefaultValues(this ContentOperation operation, ContentData data)
{
data.GenerateDefaultValues(operation.Schema.SchemaDef, operation.Partition());
var converter =
new ContentConverter(
operation.Components,
operation.Schema.SchemaDef);
converter.Add(new AddDefaultValues(operation.Partition()) { IgnoreRequiredFields = true });
return converter.Convert(data);
}
public static async Task CheckReferrersAsync(this ContentOperation operation,

2
backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/NestedInputGraphType.cs

@ -41,7 +41,7 @@ internal sealed class NestedInputGraphType : InputObjectGraphType
public override object ParseDictionary(IDictionary<string, object?> value)
{
var result = new JsonObject();
var result = JsonValue.Object();
foreach (var field in Fields)
{

4
backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Primitives/JsonGraphType.cs

@ -59,7 +59,7 @@ public sealed class JsonGraphType : JsonNoopGraphType
case GraphQLObjectValue objectValue:
{
var json = new JsonObject();
var json = JsonValue.Object();
if (objectValue.Fields != null)
{
@ -86,7 +86,7 @@ public sealed class JsonGraphType : JsonNoopGraphType
case IDictionary<string, object> obj:
{
var json = new JsonObject();
var json = JsonValue.Object();
foreach (var (key, value) in obj)
{

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

@ -126,13 +126,20 @@ public sealed class ConvertData : IContentEnricherStep
converter.Add(cleanReferences);
}
converter.Add(new ResolveInvariant(context.App.Languages));
converter.Add(new ResolveFromPreviousPartitioning(context.App.Languages));
if (!context.IsFrontendClient)
{
converter.Add(new AddDefaultValues(context.App.PartitionResolver()) { IgnoreNonMasterFields = true });
}
converter.Add(
new ResolveLanguages(context.App.Languages,
context.IsFrontendClient == false &&
context.ShouldResolveLanguages(),
context.Languages().ToArray()));
new ResolveLanguages(
context.App.Languages,
context.Languages().ToArray())
{
ResolveFallback = !context.IsFrontendClient && context.ShouldResolveLanguages()
});
if (!context.IsFrontendClient)
{

11
backend/src/Squidex.Domain.Users.MongoDb/MongoUserStore.cs

@ -210,7 +210,7 @@ public sealed class MongoUserStore :
public async Task<IdentityUser?> FindByLoginAsync(string loginProvider, string providerKey,
CancellationToken cancellationToken)
{
var result = await Collection.Find(x => x.Logins.Exists(y => y.LoginProvider == loginProvider && y.ProviderKey == providerKey)).FirstOrDefaultAsync(cancellationToken);
var result = await Collection.Find(Filter.ElemMatch(x => x.Logins, BuildFilter(loginProvider, providerKey))).FirstOrDefaultAsync(cancellationToken);
return result;
}
@ -650,4 +650,13 @@ public sealed class MongoUserStore :
return Task.FromResult(false);
}
private static FilterDefinition<UserLogin> BuildFilter(string loginProvider, string providerKey)
{
var filter = Builders<UserLogin>.Filter;
return filter.And(
filter.Eq(x => x.LoginProvider, loginProvider),
filter.Eq(x => x.ProviderKey, providerKey));
}
}

2
backend/src/Squidex.Web/ErrorDto.cs

@ -14,7 +14,7 @@ public sealed class ErrorDto
{
[LocalizedRequired]
[Display(Description = "Error message.")]
public string? Message { get; set; }
public string Message { get; set; }
[Display(Description = "The error code.")]
public string? ErrorCode { get; set; }

13
backend/src/Squidex.Web/OpenApiRequestAttribute.cs

@ -0,0 +1,13 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
namespace Squidex.Web;
[AttributeUsage(AttributeTargets.Class)]
public sealed class OpenApiRequestAttribute : Attribute
{
}

18
backend/src/Squidex/Areas/Api/Config/OpenApi/OpenApiServices.cs

@ -86,6 +86,16 @@ public static class OpenApiServices
private static void ConfigureSchemaSettings(JsonSchemaGeneratorSettings settings, TypeRegistry typeRegistry, bool flatten)
{
settings.AllowReferencesWithProperties = true;
settings.DefaultDictionaryValueReferenceTypeNullHandling = ReferenceTypeNullHandling.NotNull;
settings.DefaultReferenceTypeNullHandling = ReferenceTypeNullHandling.NotNull;
settings.FlattenInheritanceHierarchy = flatten;
settings.ReflectionService = new ReflectionServices();
settings.SchemaNameGenerator = new SchemaNameGenerator();
settings.SchemaProcessors.Add(new DiscriminatorProcessor(typeRegistry));
settings.SchemaProcessors.Add(new RequiredSchemaProcessor());
settings.SchemaType = NJsonSchema.SchemaType.OpenApi3;
settings.TypeMappers = new List<ITypeMapper>
{
CreateAnyMap<FilterNode<JsonValue>>(),
@ -106,14 +116,6 @@ public static class OpenApiServices
CreateStringMap<RefToken>(),
CreateStringMap<Status>(),
};
settings.AllowReferencesWithProperties = true;
settings.DefaultReferenceTypeNullHandling = ReferenceTypeNullHandling.NotNull;
settings.FlattenInheritanceHierarchy = flatten;
settings.SchemaNameGenerator = new SchemaNameGenerator();
settings.SchemaProcessors.Add(new DiscriminatorProcessor(typeRegistry));
settings.SchemaType = NJsonSchema.SchemaType.OpenApi3;
settings.ReflectionService = new ReflectionServices();
}
private static ITypeMapper CreateObjectMap<T>()

46
backend/src/Squidex/Areas/Api/Config/OpenApi/RequiredSchemaProcessor.cs

@ -0,0 +1,46 @@
// ==========================================================================
// Squidex Headless CMS
// ==========================================================================
// Copyright (c) Squidex UG (haftungsbeschraenkt)
// All rights reserved. Licensed under the MIT license.
// ==========================================================================
using NJsonSchema;
using NJsonSchema.Generation;
using Squidex.Web;
namespace Squidex.Areas.Api.Config.OpenApi;
public sealed class RequiredSchemaProcessor : ISchemaProcessor
{
public void Process(SchemaProcessorContext context)
{
if (context.ContextualType.GetAttribute<OpenApiRequestAttribute>() != null)
{
return;
}
FixRequired(context.Schema);
foreach (var schema in context.Schema.AllOf)
{
FixRequired(schema);
}
foreach (var schema in context.Schema.OneOf)
{
FixRequired(schema);
}
static void FixRequired(JsonSchema schema)
{
foreach (var property in schema.Properties.Values)
{
if (!property.IsNullable(SchemaType.OpenApi3))
{
property.IsRequired = true;
}
}
}
}
}

2
backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AddLanguageDto.cs

@ -9,9 +9,11 @@ using Squidex.Domain.Apps.Entities.Apps.Commands;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Reflection;
using Squidex.Infrastructure.Validation;
using Squidex.Web;
namespace Squidex.Areas.Api.Controllers.Apps.Models;
[OpenApiRequest]
public sealed class AddLanguageDto
{
/// <summary>

2
backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AddRoleDto.cs

@ -7,9 +7,11 @@
using Squidex.Domain.Apps.Entities.Apps.Commands;
using Squidex.Infrastructure.Validation;
using Squidex.Web;
namespace Squidex.Areas.Api.Controllers.Apps.Models;
[OpenApiRequest]
public sealed class AddRoleDto
{
/// <summary>

2
backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AddWorkflowDto.cs

@ -7,9 +7,11 @@
using Squidex.Domain.Apps.Entities.Apps.Commands;
using Squidex.Infrastructure.Validation;
using Squidex.Web;
namespace Squidex.Areas.Api.Controllers.Apps.Models;
[OpenApiRequest]
public sealed class AddWorkflowDto
{
/// <summary>

4
backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AppDto.cs

@ -36,7 +36,6 @@ public sealed class AppDto : Resource
/// <summary>
/// The name of the app.
/// </summary>
[LocalizedRequired]
[LocalizedRegularExpression("^[a-z0-9]+(\\-[a-z0-9]+)*$")]
public string Name { get; set; }
@ -94,7 +93,6 @@ public sealed class AppDto : Resource
/// <summary>
/// The properties from the role.
/// </summary>
[LocalizedRequired]
public JsonObject RoleProperties { get; set; }
public static AppDto FromDomain(IAppEntity app, string userId, bool isFrontend, Resources resources)
@ -125,7 +123,7 @@ public sealed class AppDto : Resource
}
else
{
result.RoleProperties = new JsonObject();
result.RoleProperties = JsonValue.Object();
}
foreach (var (key, value) in resources.Context.UserPrincipal.Claims.GetUIProperties(app.Name))

3
backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AppLanguageDto.cs

@ -18,19 +18,16 @@ public sealed class AppLanguageDto : Resource
/// <summary>
/// The iso code of the language.
/// </summary>
[LocalizedRequired]
public string Iso2Code { get; set; }
/// <summary>
/// The english name of the language.
/// </summary>
[LocalizedRequired]
public string EnglishName { get; set; }
/// <summary>
/// The fallback languages.
/// </summary>
[LocalizedRequired]
public Language[] Fallback { get; set; }
/// <summary>

1
backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AppLanguagesDto.cs

@ -16,7 +16,6 @@ public sealed class AppLanguagesDto : Resource
/// <summary>
/// The languages.
/// </summary>
[LocalizedRequired]
public AppLanguageDto[] Items { get; set; }
public static AppLanguagesDto FromDomain(IAppEntity app, Resources resources)

2
backend/src/Squidex/Areas/Api/Controllers/Apps/Models/AppSettingsDto.cs

@ -16,13 +16,11 @@ public sealed class AppSettingsDto : Resource
/// <summary>
/// The configured app patterns.
/// </summary>
[LocalizedRequired]
public PatternDto[] Patterns { get; set; }
/// <summary>
/// The configured UI editors.
/// </summary>
[LocalizedRequired]
public EditorDto[] Editors { get; set; }
/// <summary>

4
backend/src/Squidex/Areas/Api/Controllers/Apps/Models/ClientDto.cs

@ -7,7 +7,6 @@
using Squidex.Domain.Apps.Core.Apps;
using Squidex.Infrastructure.Reflection;
using Squidex.Infrastructure.Validation;
using Squidex.Web;
namespace Squidex.Areas.Api.Controllers.Apps.Models;
@ -17,19 +16,16 @@ public sealed class ClientDto : Resource
/// <summary>
/// The client id.
/// </summary>
[LocalizedRequired]
public string Id { get; set; }
/// <summary>
/// The client secret.
/// </summary>
[LocalizedRequired]
public string Secret { get; set; }
/// <summary>
/// The client name.
/// </summary>
[LocalizedRequired]
public string Name { get; set; }
/// <summary>

1
backend/src/Squidex/Areas/Api/Controllers/Apps/Models/ClientsDto.cs

@ -16,7 +16,6 @@ public sealed class ClientsDto : Resource
/// <summary>
/// The clients.
/// </summary>
[LocalizedRequired]
public ClientDto[] Items { get; set; }
public static ClientsDto FromApp(IAppEntity app, Resources resources)

2
backend/src/Squidex/Areas/Api/Controllers/Apps/Models/CreateAppDto.cs

@ -8,9 +8,11 @@
using Squidex.Domain.Apps.Entities.Apps.Commands;
using Squidex.Infrastructure.Reflection;
using Squidex.Infrastructure.Validation;
using Squidex.Web;
namespace Squidex.Areas.Api.Controllers.Apps.Models;
[OpenApiRequest]
public sealed class CreateAppDto
{
/// <summary>

2
backend/src/Squidex/Areas/Api/Controllers/Apps/Models/CreateClientDto.cs

@ -8,9 +8,11 @@
using Squidex.Domain.Apps.Entities.Apps.Commands;
using Squidex.Infrastructure.Reflection;
using Squidex.Infrastructure.Validation;
using Squidex.Web;
namespace Squidex.Areas.Api.Controllers.Apps.Models;
[OpenApiRequest]
public sealed class CreateClientDto
{
/// <summary>

2
backend/src/Squidex/Areas/Api/Controllers/Apps/Models/EditorDto.cs

@ -16,13 +16,11 @@ public sealed class EditorDto
/// <summary>
/// The name of the editor.
/// </summary>
[LocalizedRequired]
public string Name { get; set; }
/// <summary>
/// The url to the editor.
/// </summary>
[LocalizedRequired]
public string Url { get; set; }
public static EditorDto FromDomain(Editor editor)

2
backend/src/Squidex/Areas/Api/Controllers/Apps/Models/PatternDto.cs

@ -16,13 +16,11 @@ public sealed class PatternDto
/// <summary>
/// The name of the suggestion.
/// </summary>
[LocalizedRequired]
public string Name { get; set; }
/// <summary>
/// The regex pattern.
/// </summary>
[LocalizedRequired]
public string Regex { get; set; }
/// <summary>

4
backend/src/Squidex/Areas/Api/Controllers/Apps/Models/RoleDto.cs

@ -8,7 +8,6 @@
using Squidex.Domain.Apps.Core.Apps;
using Squidex.Domain.Apps.Entities.Apps;
using Squidex.Infrastructure.Json.Objects;
using Squidex.Infrastructure.Validation;
using Squidex.Web;
namespace Squidex.Areas.Api.Controllers.Apps.Models;
@ -18,7 +17,6 @@ public sealed class RoleDto : Resource
/// <summary>
/// The role name.
/// </summary>
[LocalizedRequired]
public string Name { get; set; }
/// <summary>
@ -39,13 +37,11 @@ public sealed class RoleDto : Resource
/// <summary>
/// Associated list of permissions.
/// </summary>
[LocalizedRequired]
public string[] Permissions { get; set; }
/// <summary>
/// Associated list of UI properties.
/// </summary>
[LocalizedRequired]
public JsonObject Properties { get; set; }
public static RoleDto FromDomain(Role role, IAppEntity app)

2
backend/src/Squidex/Areas/Api/Controllers/Apps/Models/RolesDto.cs

@ -6,7 +6,6 @@
// ==========================================================================
using Squidex.Domain.Apps.Entities.Apps;
using Squidex.Infrastructure.Validation;
using Squidex.Web;
namespace Squidex.Areas.Api.Controllers.Apps.Models;
@ -16,7 +15,6 @@ public sealed class RolesDto : Resource
/// <summary>
/// The roles.
/// </summary>
[LocalizedRequired]
public RoleDto[] Items { get; set; }
public static RolesDto FromDomain(IAppEntity app, Resources resources)

2
backend/src/Squidex/Areas/Api/Controllers/Apps/Models/TransferToTeamDto.cs

@ -8,9 +8,11 @@
using Squidex.Domain.Apps.Entities.Apps.Commands;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Reflection;
using Squidex.Web;
namespace Squidex.Areas.Api.Controllers.Apps.Models;
[OpenApiRequest]
public sealed class TransferToTeamDto
{
/// <summary>

2
backend/src/Squidex/Areas/Api/Controllers/Apps/Models/UpdateAppDto.cs

@ -7,9 +7,11 @@
using Squidex.Domain.Apps.Entities.Apps.Commands;
using Squidex.Infrastructure.Reflection;
using Squidex.Web;
namespace Squidex.Areas.Api.Controllers.Apps.Models;
[OpenApiRequest]
public sealed class UpdateAppDto
{
/// <summary>

7
backend/src/Squidex/Areas/Api/Controllers/Apps/Models/UpdateAppSettingsDto.cs

@ -9,21 +9,24 @@ using System.ComponentModel.DataAnnotations;
using Squidex.Domain.Apps.Core.Apps;
using Squidex.Domain.Apps.Entities.Apps.Commands;
using Squidex.Infrastructure.Collections;
using Squidex.Infrastructure.Validation;
using Squidex.Web;
namespace Squidex.Areas.Api.Controllers.Apps.Models;
[OpenApiRequest]
public sealed class UpdateAppSettingsDto
{
/// <summary>
/// The configured app patterns.
/// </summary>
[Required]
[LocalizedRequired]
public PatternDto[] Patterns { get; set; }
/// <summary>
/// The configured UI editors.
/// </summary>
[Required]
[LocalizedRequired]
public EditorDto[] Editors { get; set; }
/// <summary>

2
backend/src/Squidex/Areas/Api/Controllers/Apps/Models/UpdateAssetScriptsDto.cs

@ -8,9 +8,11 @@
using Squidex.Domain.Apps.Core.Assets;
using Squidex.Domain.Apps.Entities.Apps.Commands;
using Squidex.Infrastructure.Reflection;
using Squidex.Web;
namespace Squidex.Areas.Api.Controllers.Apps.Models;
[OpenApiRequest]
public sealed class UpdateAssetScriptsDto
{
/// <summary>

2
backend/src/Squidex/Areas/Api/Controllers/Apps/Models/UpdateClientDto.cs

@ -8,9 +8,11 @@
using Squidex.Domain.Apps.Entities.Apps.Commands;
using Squidex.Infrastructure.Reflection;
using Squidex.Infrastructure.Validation;
using Squidex.Web;
namespace Squidex.Areas.Api.Controllers.Apps.Models;
[OpenApiRequest]
public sealed class UpdateClientDto
{
/// <summary>

2
backend/src/Squidex/Areas/Api/Controllers/Apps/Models/UpdateLanguageDto.cs

@ -8,9 +8,11 @@
using Squidex.Domain.Apps.Entities.Apps.Commands;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Reflection;
using Squidex.Web;
namespace Squidex.Areas.Api.Controllers.Apps.Models;
[OpenApiRequest]
public sealed class UpdateLanguageDto
{
/// <summary>

2
backend/src/Squidex/Areas/Api/Controllers/Apps/Models/UpdateRoleDto.cs

@ -9,9 +9,11 @@ using Squidex.Domain.Apps.Entities.Apps.Commands;
using Squidex.Infrastructure.Json.Objects;
using Squidex.Infrastructure.Reflection;
using Squidex.Infrastructure.Validation;
using Squidex.Web;
namespace Squidex.Areas.Api.Controllers.Apps.Models;
[OpenApiRequest]
public sealed class UpdateRoleDto
{
/// <summary>

2
backend/src/Squidex/Areas/Api/Controllers/Apps/Models/UpdateWorkflowDto.cs

@ -10,9 +10,11 @@ using Squidex.Domain.Apps.Entities.Apps.Commands;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Collections;
using Squidex.Infrastructure.Validation;
using Squidex.Web;
namespace Squidex.Areas.Api.Controllers.Apps.Models;
[OpenApiRequest]
public sealed class UpdateWorkflowDto
{
/// <summary>

2
backend/src/Squidex/Areas/Api/Controllers/Apps/Models/WorkflowDto.cs

@ -14,6 +14,7 @@ using Squidex.Web;
namespace Squidex.Areas.Api.Controllers.Apps.Models;
[OpenApiRequest]
public sealed class WorkflowDto : Resource
{
/// <summary>
@ -29,7 +30,6 @@ public sealed class WorkflowDto : Resource
/// <summary>
/// The workflow steps.
/// </summary>
[LocalizedRequired]
public Dictionary<Status, WorkflowStepDto> Steps { get; set; }
/// <summary>

3
backend/src/Squidex/Areas/Api/Controllers/Apps/Models/WorkflowStepDto.cs

@ -9,16 +9,17 @@ using Squidex.Domain.Apps.Core.Contents;
using Squidex.Infrastructure.Collections;
using Squidex.Infrastructure.Reflection;
using Squidex.Infrastructure.Validation;
using Squidex.Web;
using NoUpdateType = Squidex.Domain.Apps.Core.Contents.NoUpdate;
namespace Squidex.Areas.Api.Controllers.Apps.Models;
[OpenApiRequest]
public sealed class WorkflowStepDto
{
/// <summary>
/// The transitions.
/// </summary>
[LocalizedRequired]
public Dictionary<Status, WorkflowTransitionDto> Transitions { get; set; }
/// <summary>

3
backend/src/Squidex/Areas/Api/Controllers/Apps/Models/WorkflowsDto.cs

@ -7,7 +7,6 @@
using Squidex.Domain.Apps.Entities.Apps;
using Squidex.Domain.Apps.Entities.Contents;
using Squidex.Infrastructure.Validation;
using Squidex.Web;
namespace Squidex.Areas.Api.Controllers.Apps.Models;
@ -17,13 +16,11 @@ public sealed class WorkflowsDto : Resource
/// <summary>
/// The workflow.
/// </summary>
[LocalizedRequired]
public WorkflowDto[] Items { get; set; }
/// <summary>
/// The errros that should be fixed.
/// </summary>
[LocalizedRequired]
public string[] Errors { get; set; }
public static async Task<WorkflowsDto> FromAppAsync(IWorkflowsValidator workflowsValidator, IAppEntity app, Resources resources)

46
backend/src/Squidex/Areas/Api/Controllers/Assets/AssetFoldersController.cs

@ -49,11 +49,31 @@ public sealed class AssetFoldersController : ApiController
[ProducesResponseType(typeof(AssetFoldersDto), StatusCodes.Status200OK)]
[ApiPermissionOrAnonymous(PermissionIds.AppAssetsRead)]
[ApiCosts(1)]
public async Task<IActionResult> GetAssetFolders(string app, [FromQuery] DomainId parentId, [FromQuery] AssetFolderScope scope = AssetFolderScope.PathAndItems)
public async Task<IActionResult> GetAssetFolders(string app, [FromQuery] DomainId? parentId, [FromQuery] AssetFolderScope scope = AssetFolderScope.PathAndItems)
{
Task<IReadOnlyList<IAssetFolderEntity>> GetAssetPathAsync()
{
if (scope == AssetFolderScope.Items || parentId == null)
{
return Task.FromResult<IReadOnlyList<IAssetFolderEntity>>(ReadonlyList.Empty<IAssetFolderEntity>());
}
return assetQuery.FindAssetFolderAsync(Context.App.Id, parentId.Value, HttpContext.RequestAborted);
}
Task<IResultList<IAssetFolderEntity>> GetAssetFoldersAsync()
{
if (scope == AssetFolderScope.Path)
{
return Task.FromResult(ResultList.Empty<IAssetFolderEntity>());
}
return assetQuery.QueryAssetFoldersAsync(Context, parentId, HttpContext.RequestAborted);
}
var (folders, path) = await AsyncHelper.WhenAll(
GetAssetFoldersAsync(parentId, scope),
GetAssetPathAsync(parentId, scope));
GetAssetFoldersAsync(),
GetAssetPathAsync());
var response = Deferred.Response(() =>
{
@ -163,24 +183,4 @@ public sealed class AssetFoldersController : ApiController
return AssetFolderDto.FromDomain(context.Result<IAssetFolderEntity>(), Resources);
}
private Task<IReadOnlyList<IAssetFolderEntity>> GetAssetPathAsync(DomainId parentId, AssetFolderScope scope)
{
if (scope == AssetFolderScope.Items)
{
return Task.FromResult<IReadOnlyList<IAssetFolderEntity>>(ReadonlyList.Empty<IAssetFolderEntity>());
}
return assetQuery.FindAssetFolderAsync(Context.App.Id, parentId, HttpContext.RequestAborted);
}
private Task<IResultList<IAssetFolderEntity>> GetAssetFoldersAsync(DomainId parentId, AssetFolderScope scope)
{
if (scope == AssetFolderScope.Path)
{
return Task.FromResult(ResultList.Empty<IAssetFolderEntity>());
}
return assetQuery.QueryAssetFoldersAsync(Context, parentId, HttpContext.RequestAborted);
}
}

2
backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AnnotateAssetDto.cs

@ -9,9 +9,11 @@ using Squidex.Domain.Apps.Core.Assets;
using Squidex.Domain.Apps.Entities.Assets.Commands;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Reflection;
using Squidex.Web;
namespace Squidex.Areas.Api.Controllers.Assets.Models;
[OpenApiRequest]
public sealed class AnnotateAssetDto
{
/// <summary>

9
backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetDto.cs

@ -31,7 +31,6 @@ public sealed class AssetDto : Resource
/// <summary>
/// The file name.
/// </summary>
[LocalizedRequired]
public string FileName { get; set; }
/// <summary>
@ -47,25 +46,21 @@ public sealed class AssetDto : Resource
/// <summary>
/// The slug.
/// </summary>
[LocalizedRequired]
public string Slug { get; set; }
/// <summary>
/// The mime type.
/// </summary>
[LocalizedRequired]
public string MimeType { get; set; }
/// <summary>
/// The file type.
/// </summary>
[LocalizedRequired]
public string FileType { get; set; }
/// <summary>
/// The formatted text representation of the metadata.
/// </summary>
[LocalizedRequired]
public string MetadataText { get; set; }
/// <summary>
@ -76,13 +71,11 @@ public sealed class AssetDto : Resource
/// <summary>
/// The asset metadata.
/// </summary>
[LocalizedRequired]
public AssetMetadata Metadata { get; set; }
/// <summary>
/// The asset tags.
/// </summary>
[LocalizedRequired]
public HashSet<string>? Tags { get; set; }
/// <summary>
@ -103,13 +96,11 @@ public sealed class AssetDto : Resource
/// <summary>
/// The user that has created the schema.
/// </summary>
[LocalizedRequired]
public RefToken CreatedBy { get; set; }
/// <summary>
/// The user that has updated the asset.
/// </summary>
[LocalizedRequired]
public RefToken LastModifiedBy { get; set; }
/// <summary>

1
backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetFolderDto.cs

@ -28,7 +28,6 @@ public sealed class AssetFolderDto : Resource
/// <summary>
/// The folder name.
/// </summary>
[LocalizedRequired]
public string FolderName { get; set; }
/// <summary>

2
backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetFoldersDto.cs

@ -22,13 +22,11 @@ public sealed class AssetFoldersDto : Resource
/// <summary>
/// The assets folders.
/// </summary>
[LocalizedRequired]
public AssetFolderDto[] Items { get; set; }
/// <summary>
/// The path to the current folder.
/// </summary>
[LocalizedRequired]
public AssetFolderDto[] Path { get; set; }
public static AssetFoldersDto FromDomain(IResultList<IAssetFolderEntity> assetFolders, IEnumerable<IAssetFolderEntity> path, Resources resources)

1
backend/src/Squidex/Areas/Api/Controllers/Assets/Models/AssetsDto.cs

@ -22,7 +22,6 @@ public sealed class AssetsDto : Resource
/// <summary>
/// The assets.
/// </summary>
[LocalizedRequired]
public AssetDto[] Items { get; set; }
public static AssetsDto FromDomain(IResultList<IEnrichedAssetEntity> assets, Resources resources)

3
backend/src/Squidex/Areas/Api/Controllers/Assets/Models/BulkUpdateAssetsDto.cs

@ -8,15 +8,16 @@
using Squidex.Domain.Apps.Entities.Assets.Commands;
using Squidex.Infrastructure.Reflection;
using Squidex.Infrastructure.Validation;
using Squidex.Web;
namespace Squidex.Areas.Api.Controllers.Assets.Models;
[OpenApiRequest]
public sealed class BulkUpdateAssetsDto
{
/// <summary>
/// The contents to update or insert.
/// </summary>
[LocalizedRequired]
public BulkUpdateAssetsJobDto[]? Jobs { get; set; }
/// <summary>

2
backend/src/Squidex/Areas/Api/Controllers/Assets/Models/BulkUpdateAssetsJobDto.cs

@ -9,9 +9,11 @@ using Squidex.Domain.Apps.Core.Assets;
using Squidex.Domain.Apps.Entities.Assets.Commands;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Reflection;
using Squidex.Web;
namespace Squidex.Areas.Api.Controllers.Assets.Models;
[OpenApiRequest]
public class BulkUpdateAssetsJobDto
{
/// <summary>

2
backend/src/Squidex/Areas/Api/Controllers/Assets/Models/CreateAssetDto.cs

@ -10,9 +10,11 @@ using Squidex.Assets;
using Squidex.Domain.Apps.Entities.Assets.Commands;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Reflection;
using Squidex.Web;
namespace Squidex.Areas.Api.Controllers.Assets.Models;
[OpenApiRequest]
public sealed class CreateAssetDto
{
/// <summary>

2
backend/src/Squidex/Areas/Api/Controllers/Assets/Models/CreateAssetFolderDto.cs

@ -9,9 +9,11 @@ using Squidex.Domain.Apps.Entities.Assets.Commands;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Reflection;
using Squidex.Infrastructure.Validation;
using Squidex.Web;
namespace Squidex.Areas.Api.Controllers.Assets.Models;
[OpenApiRequest]
public sealed class CreateAssetFolderDto
{
/// <summary>

2
backend/src/Squidex/Areas/Api/Controllers/Assets/Models/DeleteAssetDto.cs

@ -9,9 +9,11 @@ using Microsoft.AspNetCore.Mvc;
using Squidex.Domain.Apps.Entities.Assets.Commands;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Reflection;
using Squidex.Web;
namespace Squidex.Areas.Api.Controllers.Assets.Models;
[OpenApiRequest]
public sealed class DeleteAssetDto
{
/// <summary>

2
backend/src/Squidex/Areas/Api/Controllers/Assets/Models/MoveAssetDto.cs

@ -8,9 +8,11 @@
using Squidex.Domain.Apps.Entities.Assets.Commands;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Reflection;
using Squidex.Web;
namespace Squidex.Areas.Api.Controllers.Assets.Models;
[OpenApiRequest]
public sealed class MoveAssetDto
{
/// <summary>

2
backend/src/Squidex/Areas/Api/Controllers/Assets/Models/MoveAssetFolderDto.cs

@ -8,9 +8,11 @@
using Squidex.Domain.Apps.Entities.Assets.Commands;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Reflection;
using Squidex.Web;
namespace Squidex.Areas.Api.Controllers.Assets.Models;
[OpenApiRequest]
public sealed class MoveAssetFolderDto
{
/// <summary>

2
backend/src/Squidex/Areas/Api/Controllers/Assets/Models/RenameAssetFolderDto.cs

@ -9,9 +9,11 @@ using Squidex.Domain.Apps.Entities.Assets.Commands;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Reflection;
using Squidex.Infrastructure.Validation;
using Squidex.Web;
namespace Squidex.Areas.Api.Controllers.Assets.Models;
[OpenApiRequest]
public sealed class RenameAssetFolderDto
{
/// <summary>

2
backend/src/Squidex/Areas/Api/Controllers/Assets/Models/UpsertAssetDto.cs

@ -10,9 +10,11 @@ using Squidex.Assets;
using Squidex.Domain.Apps.Entities.Assets.Commands;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Reflection;
using Squidex.Web;
namespace Squidex.Areas.Api.Controllers.Assets.Models;
[OpenApiRequest]
public sealed class UpsertAssetDto
{
/// <summary>

2
backend/src/Squidex/Areas/Api/Controllers/AssignContributorDto.cs

@ -6,10 +6,12 @@
// ==========================================================================
using Squidex.Infrastructure.Validation;
using Squidex.Web;
using Roles = Squidex.Domain.Apps.Core.Apps.Role;
namespace Squidex.Areas.Api.Controllers;
[OpenApiRequest]
public sealed class AssignContributorDto
{
/// <summary>

2
backend/src/Squidex/Areas/Api/Controllers/Backups/Models/BackupJobsDto.cs

@ -6,7 +6,6 @@
// ==========================================================================
using Squidex.Domain.Apps.Entities.Backup;
using Squidex.Infrastructure.Validation;
using Squidex.Web;
namespace Squidex.Areas.Api.Controllers.Backups.Models;
@ -16,7 +15,6 @@ public sealed class BackupJobsDto : Resource
/// <summary>
/// The backups.
/// </summary>
[LocalizedRequired]
public BackupJobDto[] Items { get; set; }
public static BackupJobsDto FromDomain(IEnumerable<IBackupJob> backups, Resources resources)

3
backend/src/Squidex/Areas/Api/Controllers/Backups/Models/RestoreJobDto.cs

@ -9,6 +9,7 @@ using NodaTime;
using Squidex.Domain.Apps.Entities.Backup;
using Squidex.Infrastructure.Reflection;
using Squidex.Infrastructure.Validation;
using Squidex.Web;
namespace Squidex.Areas.Api.Controllers.Backups.Models;
@ -17,13 +18,11 @@ public sealed class RestoreJobDto
/// <summary>
/// The uri to load from.
/// </summary>
[LocalizedRequired]
public Uri Url { get; set; }
/// <summary>
/// The status log.
/// </summary>
[LocalizedRequired]
public List<string> Log { get; set; }
/// <summary>

2
backend/src/Squidex/Areas/Api/Controllers/Backups/Models/RestoreRequestDto.cs

@ -6,9 +6,11 @@
// ==========================================================================
using Squidex.Infrastructure.Validation;
using Squidex.Web;
namespace Squidex.Areas.Api.Controllers.Backups.Models;
[OpenApiRequest]
public sealed class RestoreRequestDto
{
/// <summary>

4
backend/src/Squidex/Areas/Api/Controllers/Comments/Models/CommentDto.cs

@ -10,7 +10,6 @@ using Squidex.Domain.Apps.Core.Comments;
using Squidex.Domain.Apps.Entities.Comments.Commands;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Reflection;
using Squidex.Infrastructure.Validation;
namespace Squidex.Areas.Api.Controllers.Comments.Models;
@ -24,19 +23,16 @@ public sealed class CommentDto
/// <summary>
/// The time when the comment was created or updated last.
/// </summary>
[LocalizedRequired]
public Instant Time { get; set; }
/// <summary>
/// The user who created or updated the comment.
/// </summary>
[LocalizedRequired]
public RefToken User { get; set; }
/// <summary>
/// The text of the comment.
/// </summary>
[LocalizedRequired]
public string Text { get; set; }
/// <summary>

2
backend/src/Squidex/Areas/Api/Controllers/Comments/Models/UpsertCommentDto.cs

@ -9,9 +9,11 @@ using Squidex.Domain.Apps.Entities.Comments.Commands;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Reflection;
using Squidex.Infrastructure.Validation;
using Squidex.Web;
namespace Squidex.Areas.Api.Controllers.Comments.Models;
[OpenApiRequest]
public sealed class UpsertCommentDto
{
/// <summary>

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

@ -21,6 +21,7 @@ using Squidex.Web.Pipeline;
namespace Squidex.Areas.Api.Controllers.Contents;
[SchemaMustBePublished]
[ApiExplorerSettings(GroupName = nameof(Contents))]
public sealed class ContentsController : ApiController
{
private readonly IContentQueryService contentQuery;

2
backend/src/Squidex/Areas/Api/Controllers/Contents/Models/AllContentsByGetDto.cs

@ -11,9 +11,11 @@ using Squidex.Domain.Apps.Entities;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Translations;
using Squidex.Infrastructure.Validation;
using Squidex.Web;
namespace Squidex.Areas.Api.Controllers.Contents.Models;
[OpenApiRequest]
public sealed class AllContentsByGetDto
{
/// <summary>

2
backend/src/Squidex/Areas/Api/Controllers/Contents/Models/AllContentsByPostDto.cs

@ -12,9 +12,11 @@ using Squidex.Domain.Apps.Entities;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Translations;
using Squidex.Infrastructure.Validation;
using Squidex.Web;
namespace Squidex.Areas.Api.Controllers.Contents.Models;
[OpenApiRequest]
public sealed class AllContentsByPostDto
{
/// <summary>

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

@ -9,9 +9,11 @@ using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Entities.Contents.Commands;
using Squidex.Infrastructure.Reflection;
using Squidex.Infrastructure.Validation;
using Squidex.Web;
namespace Squidex.Areas.Api.Controllers.Contents.Models;
[OpenApiRequest]
public sealed class BulkUpdateContentsDto
{
/// <summary>

2
backend/src/Squidex/Areas/Api/Controllers/Contents/Models/BulkUpdateContentsJobDto.cs

@ -10,9 +10,11 @@ using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Entities.Contents.Commands;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Reflection;
using Squidex.Web;
namespace Squidex.Areas.Api.Controllers.Contents.Models;
[OpenApiRequest]
public class BulkUpdateContentsJobDto
{
/// <summary>

2
backend/src/Squidex/Areas/Api/Controllers/Contents/Models/ChangeStatusDto.cs

@ -11,9 +11,11 @@ using Squidex.Domain.Apps.Entities.Contents.Commands;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Reflection;
using Squidex.Infrastructure.Validation;
using Squidex.Web;
namespace Squidex.Areas.Api.Controllers.Contents.Models;
[OpenApiRequest]
public sealed class ChangeStatusDto
{
/// <summary>

3
backend/src/Squidex/Areas/Api/Controllers/Contents/Models/ContentDto.cs

@ -27,19 +27,16 @@ public sealed class ContentDto : Resource
/// <summary>
/// The user that has created the content item.
/// </summary>
[LocalizedRequired]
public RefToken CreatedBy { get; set; }
/// <summary>
/// The user that has updated the content item.
/// </summary>
[LocalizedRequired]
public RefToken LastModifiedBy { get; set; }
/// <summary>
/// The data of the content item.
/// </summary>
[LocalizedRequired]
public object Data { get; set; }
/// <summary>

2
backend/src/Squidex/Areas/Api/Controllers/Contents/Models/ContentsDto.cs

@ -23,13 +23,11 @@ public sealed class ContentsDto : Resource
/// <summary>
/// The content items.
/// </summary>
[LocalizedRequired]
public ContentDto[] Items { get; set; }
/// <summary>
/// The possible statuses.
/// </summary>
[LocalizedRequired]
public StatusInfoDto[] Statuses { get; set; }
public static async Task<ContentsDto> FromContentsAsync(IResultList<IEnrichedContentEntity> contents, Resources resources,

2
backend/src/Squidex/Areas/Api/Controllers/Contents/Models/ImportContentsDto.cs

@ -9,9 +9,11 @@ using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Entities.Contents.Commands;
using Squidex.Infrastructure.Reflection;
using Squidex.Infrastructure.Validation;
using Squidex.Web;
namespace Squidex.Areas.Api.Controllers.Contents.Models;
[OpenApiRequest]
public sealed class ImportContentsDto
{
/// <summary>

1
backend/src/Squidex/Areas/Api/Controllers/Contents/Models/ScheduleJobDto.cs

@ -37,6 +37,5 @@ public sealed class ScheduleJobDto
/// <summary>
/// The user who schedule the content.
/// </summary>
[LocalizedRequired]
public RefToken ScheduledBy { get; set; }
}

2
backend/src/Squidex/Areas/Api/Controllers/Contents/Models/StatusInfoDto.cs

@ -15,13 +15,11 @@ public sealed class StatusInfoDto
/// <summary>
/// The name of the status.
/// </summary>
[LocalizedRequired]
public Status Status { get; set; }
/// <summary>
/// The color of the status.
/// </summary>
[LocalizedRequired]
public string Color { get; set; }
public static StatusInfoDto FromDomain(StatusInfo statusInfo)

2
backend/src/Squidex/Areas/Api/Controllers/Contents/Models/UpsertContentDto.cs

@ -10,10 +10,12 @@ using Squidex.Domain.Apps.Core.Contents;
using Squidex.Domain.Apps.Entities.Contents.Commands;
using Squidex.Infrastructure;
using Squidex.Infrastructure.Reflection;
using Squidex.Web;
using StatusType = Squidex.Domain.Apps.Core.Contents.Status;
namespace Squidex.Areas.Api.Controllers.Contents.Models;
[OpenApiRequest]
public class UpsertContentDto
{
/// <summary>

3
backend/src/Squidex/Areas/Api/Controllers/ContributorDto.cs

@ -20,19 +20,16 @@ public sealed class ContributorDto : Resource
/// <summary>
/// The ID of the user that contributes to the app.
/// </summary>
[LocalizedRequired]
public string ContributorId { get; set; }
/// <summary>
/// The display name.
/// </summary>
[LocalizedRequired]
public string ContributorName { get; set; }
/// <summary>
/// The email address.
/// </summary>
[LocalizedRequired]
public string ContributorEmail { get; set; }
/// <summary>

1
backend/src/Squidex/Areas/Api/Controllers/ContributorsDto.cs

@ -22,7 +22,6 @@ public sealed class ContributorsDto : Resource
/// <summary>
/// The contributors.
/// </summary>
[LocalizedRequired]
public ContributorDto[] Items { get; set; }
/// <summary>

3
backend/src/Squidex/Areas/Api/Controllers/History/Models/HistoryEventDto.cs

@ -18,19 +18,16 @@ public sealed class HistoryEventDto
/// <summary>
/// The message for the event.
/// </summary>
[LocalizedRequired]
public string Message { get; set; }
/// <summary>
/// The type of the original event.
/// </summary>
[LocalizedRequired]
public string EventType { get; set; }
/// <summary>
/// The user who called the action.
/// </summary>
[LocalizedRequired]
public string Actor { get; set; }
/// <summary>

3
backend/src/Squidex/Areas/Api/Controllers/LanguageDto.cs

@ -16,19 +16,16 @@ public sealed class LanguageDto
/// <summary>
/// The iso code of the language.
/// </summary>
[LocalizedRequired]
public string Iso2Code { get; set; }
/// <summary>
/// The english name of the language.
/// </summary>
[LocalizedRequired]
public string EnglishName { get; set; }
/// <summary>
/// The native name of the language.
/// </summary>
[LocalizedRequired]
public string NativeName { get; set; }
public static LanguageDto FromDomain(Language language)

2
backend/src/Squidex/Areas/Api/Controllers/News/Models/FeatureDto.cs

@ -14,12 +14,10 @@ public sealed class FeatureDto
/// <summary>
/// The name of the feature.
/// </summary>
[LocalizedRequired]
public string Name { get; set; }
/// <summary>
/// The description text.
/// </summary>
[LocalizedRequired]
public string Text { get; set; }
}

1
backend/src/Squidex/Areas/Api/Controllers/News/Models/FeaturesDto.cs

@ -14,7 +14,6 @@ public class FeaturesDto
/// <summary>
/// The latest features.
/// </summary>
[LocalizedRequired]
public List<FeatureDto> Features { get; } = new List<FeatureDto>();
/// <summary>

2
backend/src/Squidex/Areas/Api/Controllers/Plans/Models/ChangePlanDto.cs

@ -6,9 +6,11 @@
// ==========================================================================
using Squidex.Infrastructure.Validation;
using Squidex.Web;
namespace Squidex.Areas.Api.Controllers.Plans.Models;
[OpenApiRequest]
public sealed class ChangePlanDto
{
/// <summary>

3
backend/src/Squidex/Areas/Api/Controllers/Plans/Models/PlanDto.cs

@ -16,19 +16,16 @@ public sealed class PlanDto
/// <summary>
/// The ID of the plan.
/// </summary>
[LocalizedRequired]
public string Id { get; set; }
/// <summary>
/// The name of the plan.
/// </summary>
[LocalizedRequired]
public string Name { get; set; }
/// <summary>
/// The monthly costs of the plan.
/// </summary>
[LocalizedRequired]
public string Costs { get; set; }
/// <summary>

1
backend/src/Squidex/Areas/Api/Controllers/Plans/Models/PlansDto.cs

@ -15,7 +15,6 @@ public sealed class PlansDto
/// <summary>
/// The available plans.
/// </summary>
[LocalizedRequired]
public PlanDto[] Plans { get; set; }
/// <summary>

2
backend/src/Squidex/Areas/Api/Controllers/RenameTagDto.cs

@ -6,9 +6,11 @@
// ==========================================================================
using Squidex.Infrastructure.Validation;
using Squidex.Web;
namespace Squidex.Areas.Api.Controllers;
[OpenApiRequest]
public sealed class RenameTagDto
{
/// <summary>

2
backend/src/Squidex/Areas/Api/Controllers/Rules/Models/CreateRuleDto.cs

@ -8,9 +8,11 @@
using Squidex.Domain.Apps.Core.Rules;
using Squidex.Domain.Apps.Entities.Rules.Commands;
using Squidex.Infrastructure.Validation;
using Squidex.Web;
namespace Squidex.Areas.Api.Controllers.Rules.Models;
[OpenApiRequest]
public sealed class CreateRuleDto
{
/// <summary>

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save