From 223687424482a619acc2c98195fe1fb4295c6a22 Mon Sep 17 00:00:00 2001 From: Sebastian Stehle Date: Tue, 20 Jan 2026 23:43:07 +0100 Subject: [PATCH] User info (#1278) * Menu * Move to components. * Show a marker for unsaved changes. * User info field. * User info implementation. * Fix tests * Update tests * Update auth. * Fix DB provider. * User info * Instructions. --- .../Text/Azure/AzureIndexDefinition.cs | 8 + .../Text/Azure/AzureTextIndex.cs | 42 +- .../Text/Azure/CommandFactory.cs | 22 + .../Text/ElasticSearch/CommandFactory.cs | 22 + .../ElasticSearchIndexDefinition.cs | 4 + .../ElasticSearch/ElasticSearchTextIndex.cs | 54 +- backend/i18n/frontend_de.json | 5 + backend/i18n/frontend_en.json | 5 + backend/i18n/frontend_fr.json | 5 + backend/i18n/frontend_it.json | 5 + backend/i18n/frontend_nl.json | 5 + backend/i18n/frontend_pt.json | 5 + backend/i18n/frontend_zh.json | 5 + backend/i18n/source/backend_en.json | 3 + backend/i18n/source/frontend_en.json | 5 + .../Entities/Contents/Text/EFTextBuilder.cs | 12 +- .../Entities/Contents/Text/EFTextIndex.cs | 88 +- .../Contents/Text/EFTextIndexGeoEntity.cs | 4 + .../Contents/Text/EFTextIndexTextEntity.cs | 3 + .../Text/EFTextIndexUserInfoEntity.cs | 40 + ...0260117183413_AddUserInfoIndex.Designer.cs | 1629 ++ .../20260117183413_AddUserInfoIndex.cs | 52 + .../Migrations/MySqlDbContextModelSnapshot.cs | 55 +- ...0260117183420_AddUserInfoIndex.Designer.cs | 1630 ++ .../20260117183420_AddUserInfoIndex.cs | 45 + .../PostgresDbContextModelSnapshot.cs | 55 +- ...0260117183427_AddUserInfoIndex.Designer.cs | 1632 ++ .../20260117183427_AddUserInfoIndex.cs | 45 + .../SqlServerDbContextModelSnapshot.cs | 55 +- .../Entities/Contents/Text/CommandFactory.cs | 31 + .../Contents/Text/DocumentDbTextIndex.cs | 3 +- .../Contents/Text/MongoShardedTextIndex.cs | 9 +- .../Entities/Contents/Text/MongoTextIndex.cs | 5 +- .../Contents/Text/MongoTextIndexBase.cs | 48 +- .../Contents/Text/MongoTextIndexEntity.cs | 9 + .../Contents/Component.cs | 1 - .../Contents/GeoJsonValue.cs | 1 - .../Contents/UserInfoParseResult.cs | 16 + .../Contents/UserInfoValue.cs | 53 + .../FieldDescriptions.Designer.cs | 18 + .../FieldDescriptions.resx | 6 + .../Schemas/ArrayField.cs | 2 +- .../Schemas/Fields.cs | 716 +- .../Schemas/IFieldPropertiesVisitor.cs | 2 + .../Schemas/IFieldVisitor.cs | 2 + .../Schemas/UserInfoFieldProperties.cs | 33 + .../ConvertContent/AddDefaultValues.cs | 1 - .../ConvertContent/ContentConverter.cs | 5 - .../ConvertContent/DefaultValueChecker.cs | 5 + .../ConvertContent/DefaultValueFactory.cs | 11 + .../ConvertContent/StringFormatter.cs | 5 + .../ExtractReferenceIds/ReferencesCleaner.cs | 5 + .../GenerateFilters/FilterVisitor.cs | 5 + .../GenerateJsonSchema/JsonTypeVisitor.cs | 15 + .../Scripting/ContentScriptVars.cs | 2 +- .../Scripting/ScriptVars.cs | 2 +- .../DefaultFieldValueValidatorsFactory.cs | 12 +- .../ValidateContent/JsonValueConverter.cs | 17 + .../ValidateContent/JsonValueValidator.cs | 9 +- .../Types/Contents/FieldInputVisitor.cs | 5 + .../GraphQL/Types/Contents/FieldVisitor.cs | 5 + .../Contents/Text/ApiKeyQuery.cs | 14 + .../Contents/Text/Extensions.cs | 24 + .../Contents/Text/ITextIndex.cs | 8 + .../Contents/Text/TextIndexingProcess.cs | 1 + .../Contents/Text/UpsertIndexEntry.cs | 3 + .../Guards/FieldPropertiesValidator.cs | 5 + .../DomainObject/SchemaDomainObject.State.cs | 2 +- backend/src/Squidex.Shared/Texts.de.resx | 9 + backend/src/Squidex.Shared/Texts.fr.resx | 9 + backend/src/Squidex.Shared/Texts.it.resx | 9 + backend/src/Squidex.Shared/Texts.nl.resx | 9 + backend/src/Squidex.Shared/Texts.pt.resx | 9 + backend/src/Squidex.Shared/Texts.resx | 9 + backend/src/Squidex.Shared/Texts.zh.resx | 9 + backend/src/Squidex.Web/Constants.cs | 4 + backend/src/Squidex.Web/Extensions.cs | 8 + .../ApiKeyAuthenticationBuilderExtensions.cs | 20 + .../Squidex.Web/Pipeline/ApiKeyDefaults.cs | 13 + .../src/Squidex.Web/Pipeline/ApiKeyHandler.cs | 131 + .../src/Squidex.Web/Pipeline/ApiKeyOptions.cs | 14 + .../src/Squidex.Web/Pipeline/AppResolver.cs | 26 +- .../Converters/FieldPropertiesDtoFactory.cs | 5 + .../Fields/UserInfoFieldPropertiesDto.cs | 31 + .../Authentication/AuthenticationServices.cs | 3 + .../Authentication/IdentityServerServices.cs | 26 +- .../Domain/Contents/Text/EFTextIndexTests.cs | 2 + .../Model/Schemas/ArrayFieldTests.cs | 34 +- .../DefaultValueFactoryTests.cs | 20 + .../ValidateContent/GeolocationFieldTests.cs | 11 + .../UserInfoFieldPropertiesTests.cs | 99 + .../Contents/GraphQL/TestContent.cs | 20 +- .../Contents/GraphQL/TestSchemas.cs | 2 + .../Contents/Text/TextIndexerTests.cs | 61 +- frontend/cache.json | 23838 ++++++++++++++++ .../editor/content-editor.component.html | 4 +- .../shared/forms/assets-editor.component.html | 6 +- .../shared/forms/assets-editor.component.scss | 4 + .../forms/component-section.component.html | 4 +- .../forms/content-section.component.html | 2 +- .../shared/forms/field-editor.component.html | 6 +- .../shared/forms/field-editor.component.ts | 4 +- .../forms/user-info-editor.component.html | 31 + .../forms/user-info-editor.component.scss | 24 + .../forms/user-info-editor.component.ts | 97 + .../pages/rule/step-dialog.component.html | 2 +- .../fields/forms/field-form-ui.component.html | 4 + .../fields/forms/field-form-ui.component.ts | 2 + .../field-form-validation.component.html | 6 +- .../forms/field-form-validation.component.ts | 2 + .../fields/types/user-info-ui.component.html | 0 .../fields/types/user-info-ui.component.scss | 2 + .../fields/types/user-info-ui.component.ts | 26 + .../types/user-info-validation.component.html | 14 + .../types/user-info-validation.component.scss | 2 + .../types/user-info-validation.component.ts | 42 + .../schema/indexes/index-form.component.html | 2 +- .../client-connect-form.component.html | 2 +- .../angular/forms/form-row.component.html | 4 +- .../modals/tour-template.component.html | 4 +- .../assets/asset-dialog.component.scss | 8 +- frontend/src/app/shared/model/custom.ts | 18 + frontend/src/app/shared/model/generated.ts | 63 +- frontend/src/app/shared/model/schemas.ts | 13 +- .../state/contents.forms.visitors.spec.ts | 26 + .../shared/state/contents.forms.visitors.ts | 31 +- frontend/src/app/shared/state/roles.state.ts | 10 +- .../src/app/shared/state/schemas.forms.ts | 4 + frontend/src/app/theme/icomoon/Read Me.txt | 2 +- frontend/src/app/theme/icomoon/demo.html | 14 + .../src/app/theme/icomoon/fonts/icomoon.eot | Bin 36876 -> 36876 bytes .../src/app/theme/icomoon/fonts/icomoon.svg | 2 +- .../src/app/theme/icomoon/fonts/icomoon.ttf | Bin 36712 -> 36712 bytes .../src/app/theme/icomoon/fonts/icomoon.woff | Bin 36788 -> 36788 bytes frontend/src/app/theme/icomoon/selection.json | 2 +- frontend/src/app/theme/icomoon/style.css | 13 +- .../TestSuite.ApiTests/ContentUserTests.cs | 100 + .../GraphQLSubscriptionTests.cs | 5 +- .../TestSuite.ApiTests.csproj | 4 +- .../TestSuite.Shared/TestSuite.Shared.csproj | 6 +- 140 files changed, 31412 insertions(+), 292 deletions(-) create mode 100644 backend/src/Squidex.Data.EntityFramework/Domain/Apps/Entities/Contents/Text/EFTextIndexUserInfoEntity.cs create mode 100644 backend/src/Squidex.Data.EntityFramework/Providers/MySql/App/Migrations/20260117183413_AddUserInfoIndex.Designer.cs create mode 100644 backend/src/Squidex.Data.EntityFramework/Providers/MySql/App/Migrations/20260117183413_AddUserInfoIndex.cs create mode 100644 backend/src/Squidex.Data.EntityFramework/Providers/Postgres/App/Migrations/20260117183420_AddUserInfoIndex.Designer.cs create mode 100644 backend/src/Squidex.Data.EntityFramework/Providers/Postgres/App/Migrations/20260117183420_AddUserInfoIndex.cs create mode 100644 backend/src/Squidex.Data.EntityFramework/Providers/SqlServer/App/Migrations/20260117183427_AddUserInfoIndex.Designer.cs create mode 100644 backend/src/Squidex.Data.EntityFramework/Providers/SqlServer/App/Migrations/20260117183427_AddUserInfoIndex.cs create mode 100644 backend/src/Squidex.Domain.Apps.Core.Model/Contents/UserInfoParseResult.cs create mode 100644 backend/src/Squidex.Domain.Apps.Core.Model/Contents/UserInfoValue.cs create mode 100644 backend/src/Squidex.Domain.Apps.Core.Model/Schemas/UserInfoFieldProperties.cs create mode 100644 backend/src/Squidex.Domain.Apps.Entities/Contents/Text/ApiKeyQuery.cs create mode 100644 backend/src/Squidex.Web/Pipeline/ApiKeyAuthenticationBuilderExtensions.cs create mode 100644 backend/src/Squidex.Web/Pipeline/ApiKeyDefaults.cs create mode 100644 backend/src/Squidex.Web/Pipeline/ApiKeyHandler.cs create mode 100644 backend/src/Squidex.Web/Pipeline/ApiKeyOptions.cs create mode 100644 backend/src/Squidex/Areas/Api/Controllers/Schemas/Models/Fields/UserInfoFieldPropertiesDto.cs create mode 100644 backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/UserInfoFieldPropertiesTests.cs create mode 100644 frontend/cache.json create mode 100644 frontend/src/app/features/content/shared/forms/user-info-editor.component.html create mode 100644 frontend/src/app/features/content/shared/forms/user-info-editor.component.scss create mode 100644 frontend/src/app/features/content/shared/forms/user-info-editor.component.ts create mode 100644 frontend/src/app/features/schemas/pages/schema/fields/types/user-info-ui.component.html create mode 100644 frontend/src/app/features/schemas/pages/schema/fields/types/user-info-ui.component.scss create mode 100644 frontend/src/app/features/schemas/pages/schema/fields/types/user-info-ui.component.ts create mode 100644 frontend/src/app/features/schemas/pages/schema/fields/types/user-info-validation.component.html create mode 100644 frontend/src/app/features/schemas/pages/schema/fields/types/user-info-validation.component.scss create mode 100644 frontend/src/app/features/schemas/pages/schema/fields/types/user-info-validation.component.ts create mode 100644 tools/TestSuite/TestSuite.ApiTests/ContentUserTests.cs diff --git a/backend/extensions/Squidex.Extensions/Text/Azure/AzureIndexDefinition.cs b/backend/extensions/Squidex.Extensions/Text/Azure/AzureIndexDefinition.cs index 9fa3561d1..74b6eb5ab 100644 --- a/backend/extensions/Squidex.Extensions/Text/Azure/AzureIndexDefinition.cs +++ b/backend/extensions/Squidex.Extensions/Text/Azure/AzureIndexDefinition.cs @@ -116,6 +116,14 @@ public static class AzureIndexDefinition { IsFilterable = true, }, + new SimpleField("userInfoApiKey", SearchFieldDataType.String) + { + IsFilterable = true, + }, + new SimpleField("userInfoField", SearchFieldDataType.String) + { + IsFilterable = true, + }, }; foreach (var (field, analyzer) in FieldAnalyzers.Values) diff --git a/backend/extensions/Squidex.Extensions/Text/Azure/AzureTextIndex.cs b/backend/extensions/Squidex.Extensions/Text/Azure/AzureTextIndex.cs index b8ec78968..866af21eb 100644 --- a/backend/extensions/Squidex.Extensions/Text/Azure/AzureTextIndex.cs +++ b/backend/extensions/Squidex.Extensions/Text/Azure/AzureTextIndex.cs @@ -123,20 +123,52 @@ public sealed class AzureTextIndex : IInitializable, ITextIndex CancellationToken ct = default) { var searchField = GetServeField(scope); + var searchFilter = $"{string.Join(" or ", schemaIds.Select(x => $"schemaId eq '{x}'"))} and {searchField} eq true"; - var filter = $"{string.Join(" or ", schemaIds.Select(x => $"schemaId eq '{x}'"))} and {searchField} eq true"; - - return SearchAsync(result, text, filter, take, factor, ct); + return SearchAsync(result, text, searchFilter, take, factor, ct); } private Task SearchByAppAsync(List<(DomainId, double)> result, string text, App app, SearchScope scope, int take, double factor, CancellationToken ct = default) { var searchField = GetServeField(scope); + var searchFilter = $"appId eq '{app.Id}' and {searchField} eq true"; + + return SearchAsync(result, text, searchFilter, take, factor, ct); + } + + public async Task FindUserInfo(App app, ApiKeyQuery query, SearchScope scope, + CancellationToken ct = default) + { + Guard.NotNull(app); + Guard.NotNull(query); + + var searchField = GetServeField(scope); + var searchFilter = $"appId eq '{app.Id}' and {searchField} eq true and userApiKey eq '{query.ApiKey}'"; + var searchOptions = new SearchOptions + { + Filter = searchFilter, + }; - var filter = $"appId eq '{app.Id}' and {searchField} eq true"; + searchOptions.Select.Add("contentId"); + searchOptions.Select.Add("userInfoApiKey"); + searchOptions.Select.Add("userInfoRole"); + searchOptions.Size = 1; + searchOptions.QueryType = SearchQueryType.Full; + + var results = await searchClient.SearchAsync(searchFilter, searchOptions, ct); + + await foreach (var item in results.Value.GetResultsAsync().WithCancellation(ct)) + { + if (item != null) + { + var id = DomainId.Create(item.Document["contentId"].ToString()!); + + return new UserInfoResult(id, item.Document["userInfoRole"].ToString()!); + } + } - return SearchAsync(result, text, filter, take, factor, ct); + return null; } private async Task SearchAsync(List<(DomainId, double)> result, string text, string filter, int take, double factor, diff --git a/backend/extensions/Squidex.Extensions/Text/Azure/CommandFactory.cs b/backend/extensions/Squidex.Extensions/Text/Azure/CommandFactory.cs index 776108e42..7c75d6a59 100644 --- a/backend/extensions/Squidex.Extensions/Text/Azure/CommandFactory.cs +++ b/backend/extensions/Squidex.Extensions/Text/Azure/CommandFactory.cs @@ -70,6 +70,28 @@ public static class CommandFactory } } + if (upsert.UserInfos != null) + { + foreach (var userInfo in upsert.UserInfos) + { + var geoDocument = new SearchDocument + { + ["docId"] = upsert.ToDocId(), + ["appId"] = upsert.UniqueContentId.AppId.ToString(), + ["appName"] = string.Empty, + ["contentId"] = upsert.UniqueContentId.ContentId.ToString(), + ["schemaId"] = upsert.SchemaId.Id.ToString(), + ["schemaName"] = upsert.SchemaId.Name, + ["serveAll"] = upsert.ServeAll, + ["servePublished"] = upsert.ServePublished, + ["userInfoApiKey"] = userInfo, + ["userInfoRole"] = userInfo.Role, + }; + + batch.Add(IndexDocumentsAction.MergeOrUpload(geoDocument)); + } + } + if (upsert.Texts is { Count: > 0 }) { var document = new SearchDocument diff --git a/backend/extensions/Squidex.Extensions/Text/ElasticSearch/CommandFactory.cs b/backend/extensions/Squidex.Extensions/Text/ElasticSearch/CommandFactory.cs index e0acb14c4..89bf8c197 100644 --- a/backend/extensions/Squidex.Extensions/Text/ElasticSearch/CommandFactory.cs +++ b/backend/extensions/Squidex.Extensions/Text/ElasticSearch/CommandFactory.cs @@ -81,6 +81,28 @@ public static class CommandFactory } } + if (upsert.UserInfos != null) + { + foreach (var userInfo in upsert.UserInfos) + { + var userInfoApiKey = userInfo.ApiKey; + var userInfoRole = userInfo.Role; + + AddArgs(new + { + appId = upsert.UniqueContentId.AppId.ToString(), + appName = string.Empty, + contentId = upsert.UniqueContentId.ContentId.ToString(), + schemaId = upsert.SchemaId.Id.ToString(), + schemaName = upsert.SchemaId.Name, + serveAll = upsert.ServeAll, + servePublished = upsert.ServePublished, + userInfoApiKey, + userInfoRole, + }); + } + } + if (upsert.Texts is { Count: > 0 }) { var texts = new Dictionary(); diff --git a/backend/extensions/Squidex.Extensions/Text/ElasticSearch/ElasticSearchIndexDefinition.cs b/backend/extensions/Squidex.Extensions/Text/ElasticSearch/ElasticSearchIndexDefinition.cs index d869e99f8..652ae0012 100644 --- a/backend/extensions/Squidex.Extensions/Text/ElasticSearch/ElasticSearchIndexDefinition.cs +++ b/backend/extensions/Squidex.Extensions/Text/ElasticSearch/ElasticSearchIndexDefinition.cs @@ -105,6 +105,10 @@ public static class ElasticSearchIndexDefinition { type = "geo_point", }, + ["userInfoApiKey"] = new + { + type = "text", + }, }, }; diff --git a/backend/extensions/Squidex.Extensions/Text/ElasticSearch/ElasticSearchTextIndex.cs b/backend/extensions/Squidex.Extensions/Text/ElasticSearch/ElasticSearchTextIndex.cs index 03a54bdb2..d25bdf353 100644 --- a/backend/extensions/Squidex.Extensions/Text/ElasticSearch/ElasticSearchTextIndex.cs +++ b/backend/extensions/Squidex.Extensions/Text/ElasticSearch/ElasticSearchTextIndex.cs @@ -15,7 +15,8 @@ using Squidex.Infrastructure.Json; namespace Squidex.Extensions.Text.ElasticSearch; -public sealed partial class ElasticSearchTextIndex(IElasticSearchClient elasticClient, string indexName, IJsonSerializer jsonSerializer) : ITextIndex, IInitializable +public sealed partial class ElasticSearchTextIndex(IElasticSearchClient elasticClient, string indexName, IJsonSerializer jsonSerializer) + : ITextIndex, IInitializable { private static readonly Regex RegexLanguageNormal = BuildLanguageRegexNormal(); private static readonly Regex RegexLanguageStart = BuildLanguageRegexStart(); @@ -198,13 +199,62 @@ public sealed partial class ElasticSearchTextIndex(IElasticSearchClient elasticC return await SearchAsync(elasticQuery, ct); } + public async Task FindUserInfo(App app, ApiKeyQuery query, SearchScope scope, + CancellationToken ct = default) + { + Guard.NotNull(app); + Guard.NotNull(query); + + var serveField = GetServeField(scope); + + var elasticQuery = new + { + query = new + { + @bool = new + { + filter = new object[] + { + new + { + term = new Dictionary + { + [serveField] = "true", + }, + }, + new + { + term = new Dictionary + { + ["userInfoApiKey.keyword"] = query.ApiKey, + }, + }, + }, + }, + }, + _source = new[] + { + "contentId", + "userInfoApiKey", + "userInfoRole", + }, + size = 1, + }; + + var hits = await elasticClient.SearchAsync(indexName, elasticQuery, ct); + var hit = hits.FirstOrDefault(); + + return hit != null ? + new UserInfoResult(DomainId.Create(hit["_source"]["contentId"]), hit["_source"]["userInfoRole"]) : + null; + } + private async Task> SearchAsync(object query, CancellationToken ct) { var hits = await elasticClient.SearchAsync(indexName, query, ct); var ids = new List(); - foreach (var item in hits) { ids.Add(DomainId.Create(item["_source"]["contentId"])); diff --git a/backend/i18n/frontend_de.json b/backend/i18n/frontend_de.json index 38b268162..0b8f823cc 100644 --- a/backend/i18n/frontend_de.json +++ b/backend/i18n/frontend_de.json @@ -198,6 +198,7 @@ "common.administration": "Verwaltung", "common.administrationPageTitle": "Verwaltung", "common.api": "API", + "common.apiKey": "API Key", "common.apps": "Apps", "common.aspectRatio": "Seitenverhältnis", "common.assets": "Assets", @@ -523,6 +524,7 @@ "contents.unsetValueConfirmTitle": "Möchten Sie den Wert zurücksetzen?", "contents.updated": "Inhalt erfolgreich aktualisiert.", "contents.updateFailed": "Fehler beim Aktualisieren des Inhalts. Bitte neu laden.", + "contents.userInfo.instructions": "Connect as this user with the following header. The first part of the value is the app name.\n\nDo not miss the colon and remember the assign a restrictive role.", "contents.validate": "Validieren", "contents.validationHint": "Bitte denken Sie daran, alle Sprachen zu überprüfen, wenn Sie Validierungsfehler sehen.", "contents.versionCompare": "Vergleichen", @@ -984,6 +986,9 @@ "schemas.fieldTypes.tags.countMin": "Min. Elemente", "schemas.fieldTypes.tags.description": "Spezialformat für Tags.", "schemas.fieldTypes.ui.description": "Trennzeichen für die Bearbeitungsoberfläche.", + "schemas.fieldTypes.user.description": "User Credentials for custom Auth.", + "schemas.fieldTypes.userInfo.defaultRole": "Default Role", + "schemas.fieldTypes.userInfo.defaultRoleHint": "The default role. If a value is set a user info with a random API Key will be generated.", "schemas.hideFieldFailed": "Fehler beim Ausblenden des Feldes. Bitte neu laden.", "schemas.import": "Schema importieren", "schemas.indexes.addIndex": "Index hinzufügen", diff --git a/backend/i18n/frontend_en.json b/backend/i18n/frontend_en.json index e4d52db8c..d24ee97ad 100644 --- a/backend/i18n/frontend_en.json +++ b/backend/i18n/frontend_en.json @@ -198,6 +198,7 @@ "common.administration": "Administration", "common.administrationPageTitle": "Administration", "common.api": "API", + "common.apiKey": "API Key", "common.apps": "Apps", "common.aspectRatio": "AspectRatio", "common.assets": "Assets", @@ -523,6 +524,7 @@ "contents.unsetValueConfirmTitle": "Do you want to unset the value?", "contents.updated": "Content updated successfully.", "contents.updateFailed": "Failed to update content. Please reload.", + "contents.userInfo.instructions": "Connect as this user with the following header. The first part of the value is the app name.\n\nDo not miss the colon and remember the assign a restrictive role.", "contents.validate": "Validate", "contents.validationHint": "Please remember to check all languages when you see validation errors.", "contents.versionCompare": "Compare", @@ -984,6 +986,9 @@ "schemas.fieldTypes.tags.countMin": "Min Items", "schemas.fieldTypes.tags.description": "Special format for tags.", "schemas.fieldTypes.ui.description": "Separator for editing UI.", + "schemas.fieldTypes.user.description": "User Credentials for custom Auth.", + "schemas.fieldTypes.userInfo.defaultRole": "Default Role", + "schemas.fieldTypes.userInfo.defaultRoleHint": "The default role. If a value is set a user info with a random API Key will be generated.", "schemas.hideFieldFailed": "Failed to hide field. Please reload.", "schemas.import": "Import schema", "schemas.indexes.addIndex": "Add Index", diff --git a/backend/i18n/frontend_fr.json b/backend/i18n/frontend_fr.json index 3da5bd9d1..ab5ba9a18 100644 --- a/backend/i18n/frontend_fr.json +++ b/backend/i18n/frontend_fr.json @@ -198,6 +198,7 @@ "common.administration": "Administration", "common.administrationPageTitle": "Administration", "common.api": "API", + "common.apiKey": "API Key", "common.apps": "applications", "common.aspectRatio": "Ratio d'aspect", "common.assets": "Actifs", @@ -523,6 +524,7 @@ "contents.unsetValueConfirmTitle": "Voulez-vous annuler la valeur\u00A0?", "contents.updated": "Contenu mis à jour avec succès.", "contents.updateFailed": "Échec de la mise à jour du contenu. Veuillez recharger.", + "contents.userInfo.instructions": "Connect as this user with the following header. The first part of the value is the app name.\n\nDo not miss the colon and remember the assign a restrictive role.", "contents.validate": "Valider", "contents.validationHint": "N'oubliez pas de vérifier toutes les langues lorsque vous voyez des erreurs de validation.", "contents.versionCompare": "Comparer", @@ -984,6 +986,9 @@ "schemas.fieldTypes.tags.countMin": "Articles minimum", "schemas.fieldTypes.tags.description": "Format spécial pour les balises.", "schemas.fieldTypes.ui.description": "Séparateur pour l'édition de l'interface utilisateur.", + "schemas.fieldTypes.user.description": "User Credentials for custom Auth.", + "schemas.fieldTypes.userInfo.defaultRole": "Default Role", + "schemas.fieldTypes.userInfo.defaultRoleHint": "The default role. If a value is set a user info with a random API Key will be generated.", "schemas.hideFieldFailed": "Impossible de masquer le champ. Veuillez recharger.", "schemas.import": "Calendrier d'importation", "schemas.indexes.addIndex": "Add Index", diff --git a/backend/i18n/frontend_it.json b/backend/i18n/frontend_it.json index e088d7075..64faac1fc 100644 --- a/backend/i18n/frontend_it.json +++ b/backend/i18n/frontend_it.json @@ -198,6 +198,7 @@ "common.administration": "Amministrazione", "common.administrationPageTitle": "Amministrazione", "common.api": "API", + "common.apiKey": "API Key", "common.apps": "App", "common.aspectRatio": "Proporzioni", "common.assets": "Risorse", @@ -523,6 +524,7 @@ "contents.unsetValueConfirmTitle": "Sei sicuro di voler annullare il valore impostato?", "contents.updated": "Contenuto aggiornato con successo.", "contents.updateFailed": "Non è stato possibile aggiornare il contenuto. Per favore ricarica.", + "contents.userInfo.instructions": "Connect as this user with the following header. The first part of the value is the app name.\n\nDo not miss the colon and remember the assign a restrictive role.", "contents.validate": "Convalida", "contents.validationHint": "Ricorda di verificare tutte le lingue quando vedi errori di validazione.", "contents.versionCompare": "Confronta", @@ -984,6 +986,9 @@ "schemas.fieldTypes.tags.countMin": "Numero min di Elementi", "schemas.fieldTypes.tags.description": "Formato speciale per i tag.", "schemas.fieldTypes.ui.description": "Separatore per il pannello delle modifiche della UI.", + "schemas.fieldTypes.user.description": "User Credentials for custom Auth.", + "schemas.fieldTypes.userInfo.defaultRole": "Default Role", + "schemas.fieldTypes.userInfo.defaultRoleHint": "The default role. If a value is set a user info with a random API Key will be generated.", "schemas.hideFieldFailed": "Non è stato possibile nascondere il campo. Per favore ricarica.", "schemas.import": "Importa uno schema", "schemas.indexes.addIndex": "Add Index", diff --git a/backend/i18n/frontend_nl.json b/backend/i18n/frontend_nl.json index 4f850e5cd..75e970f3b 100644 --- a/backend/i18n/frontend_nl.json +++ b/backend/i18n/frontend_nl.json @@ -198,6 +198,7 @@ "common.administration": "Administratie", "common.administrationPageTitle": "Administratie", "common.api": "API", + "common.apiKey": "API Key", "common.apps": "Apps", "common.aspectRatio": "AspectRatio", "common.assets": "Bestanden", @@ -523,6 +524,7 @@ "contents.unsetValueConfirmTitle": "Weet je zeker dat je de waarde leeg wilt maken?", "contents.updated": "Inhoud succesvol bijgewerkt.", "contents.updateFailed": "Bijwerken van inhoud is mislukt. Laad opnieuw.", + "contents.userInfo.instructions": "Connect as this user with the following header. The first part of the value is the app name.\n\nDo not miss the colon and remember the assign a restrictive role.", "contents.validate": "Valideren", "contents.validationHint": "Denk eraan om alle talen te controleren wanneer je validatiefouten ziet.", "contents.versionCompare": "Vergelijk", @@ -984,6 +986,9 @@ "schemas.fieldTypes.tags.countMin": "Min. items", "schemas.fieldTypes.tags.description": "Speciaal formaat voor tags.", "schemas.fieldTypes.ui.description": "Scheidingsteken voor het bewerken van gebruikersinterface.", + "schemas.fieldTypes.user.description": "User Credentials for custom Auth.", + "schemas.fieldTypes.userInfo.defaultRole": "Default Role", + "schemas.fieldTypes.userInfo.defaultRoleHint": "The default role. If a value is set a user info with a random API Key will be generated.", "schemas.hideFieldFailed": "Kan veld niet verbergen. Laad opnieuw.", "schemas.import": "Importeer schema", "schemas.indexes.addIndex": "Add Index", diff --git a/backend/i18n/frontend_pt.json b/backend/i18n/frontend_pt.json index c5667a5af..f4fd44d35 100644 --- a/backend/i18n/frontend_pt.json +++ b/backend/i18n/frontend_pt.json @@ -198,6 +198,7 @@ "common.administration": "Administração", "common.administrationPageTitle": "Administração", "common.api": "API", + "common.apiKey": "API Key", "common.apps": "Aplicativos", "common.aspectRatio": "AspectRatio", "common.assets": "Ficheiros", @@ -523,6 +524,7 @@ "contents.unsetValueConfirmTitle": "Quer desaparassar o valor?", "contents.updated": "Conteúdo atualizado com sucesso.", "contents.updateFailed": "Falhou na atualização do conteúdo. Por favor, recarregue.", + "contents.userInfo.instructions": "Connect as this user with the following header. The first part of the value is the app name.\n\nDo not miss the colon and remember the assign a restrictive role.", "contents.validate": "Validar", "contents.validationHint": "Por favor, lembre-se de verificar todos os idiomas quando vir erros de validação.", "contents.versionCompare": "Comparar", @@ -984,6 +986,9 @@ "schemas.fieldTypes.tags.countMin": "Min Itens", "schemas.fieldTypes.tags.description": "Formato especial para tags.", "schemas.fieldTypes.ui.description": "Separador para edição de UI.", + "schemas.fieldTypes.user.description": "User Credentials for custom Auth.", + "schemas.fieldTypes.userInfo.defaultRole": "Default Role", + "schemas.fieldTypes.userInfo.defaultRoleHint": "The default role. If a value is set a user info with a random API Key will be generated.", "schemas.hideFieldFailed": "Falhou em esconder o campo. Por favor, recarregue.", "schemas.import": "Esquema de importação", "schemas.indexes.addIndex": "Add Index", diff --git a/backend/i18n/frontend_zh.json b/backend/i18n/frontend_zh.json index 08f8305cf..2f76f965b 100644 --- a/backend/i18n/frontend_zh.json +++ b/backend/i18n/frontend_zh.json @@ -198,6 +198,7 @@ "common.administration": "管理", "common.administrationPageTitle": "管理", "common.api": "API", + "common.apiKey": "API Key", "common.apps": "应用程序", "common.aspectRatio": "纵横比", "common.assets": "资源", @@ -523,6 +524,7 @@ "contents.unsetValueConfirmTitle": "你想取消设置吗?", "contents.updated": "内容更新成功。", "contents.updateFailed": "更新内容失败,请重新加载。", + "contents.userInfo.instructions": "Connect as this user with the following header. The first part of the value is the app name.\n\nDo not miss the colon and remember the assign a restrictive role.", "contents.validate": "验证", "contents.validationHint": "当您看到验证错误时,请记住检查所有语言。", "contents.versionCompare": "比较", @@ -984,6 +986,9 @@ "schemas.fieldTypes.tags.countMin": "最小项目", "schemas.fieldTypes.tags.description": "标签的特殊格式。", "schemas.fieldTypes.ui.description": "编辑 UI 的分隔符。", + "schemas.fieldTypes.user.description": "User Credentials for custom Auth.", + "schemas.fieldTypes.userInfo.defaultRole": "Default Role", + "schemas.fieldTypes.userInfo.defaultRoleHint": "The default role. If a value is set a user info with a random API Key will be generated.", "schemas.hideFieldFailed": "隐藏字段失败。请重新加载。", "schemas.import": "导入Schemas", "schemas.indexes.addIndex": "Add Index", diff --git a/backend/i18n/source/backend_en.json b/backend/i18n/source/backend_en.json index aabfcd7b8..be1ae1ea5 100644 --- a/backend/i18n/source/backend_en.json +++ b/backend/i18n/source/backend_en.json @@ -139,6 +139,9 @@ "contents.invalidNumber": "Invalid json type, expected number.", "contents.invalidRichText": "Invalid rich text.", "contents.invalidString": "Invalid json type, expected string.", + "contents.invalidUserInfo": "Invalid json type, expected apiKey+role object.", + "contents.invalidUserInfoApiKey": "ApiKey must be defined.", + "contents.invalidUserInfoRole": "Role must be defined.", "contents.listReferences": "{count} Reference(s)", "contents.referenced": "Content is referenced by another content and cannot be deleted or unpublished.", "contents.schemaNotPublished": "Schema not published.", diff --git a/backend/i18n/source/frontend_en.json b/backend/i18n/source/frontend_en.json index e4d52db8c..d24ee97ad 100644 --- a/backend/i18n/source/frontend_en.json +++ b/backend/i18n/source/frontend_en.json @@ -198,6 +198,7 @@ "common.administration": "Administration", "common.administrationPageTitle": "Administration", "common.api": "API", + "common.apiKey": "API Key", "common.apps": "Apps", "common.aspectRatio": "AspectRatio", "common.assets": "Assets", @@ -523,6 +524,7 @@ "contents.unsetValueConfirmTitle": "Do you want to unset the value?", "contents.updated": "Content updated successfully.", "contents.updateFailed": "Failed to update content. Please reload.", + "contents.userInfo.instructions": "Connect as this user with the following header. The first part of the value is the app name.\n\nDo not miss the colon and remember the assign a restrictive role.", "contents.validate": "Validate", "contents.validationHint": "Please remember to check all languages when you see validation errors.", "contents.versionCompare": "Compare", @@ -984,6 +986,9 @@ "schemas.fieldTypes.tags.countMin": "Min Items", "schemas.fieldTypes.tags.description": "Special format for tags.", "schemas.fieldTypes.ui.description": "Separator for editing UI.", + "schemas.fieldTypes.user.description": "User Credentials for custom Auth.", + "schemas.fieldTypes.userInfo.defaultRole": "Default Role", + "schemas.fieldTypes.userInfo.defaultRoleHint": "The default role. If a value is set a user info with a random API Key will be generated.", "schemas.hideFieldFailed": "Failed to hide field. Please reload.", "schemas.import": "Import schema", "schemas.indexes.addIndex": "Add Index", diff --git a/backend/src/Squidex.Data.EntityFramework/Domain/Apps/Entities/Contents/Text/EFTextBuilder.cs b/backend/src/Squidex.Data.EntityFramework/Domain/Apps/Entities/Contents/Text/EFTextBuilder.cs index 989820325..8bca3d824 100644 --- a/backend/src/Squidex.Data.EntityFramework/Domain/Apps/Entities/Contents/Text/EFTextBuilder.cs +++ b/backend/src/Squidex.Data.EntityFramework/Domain/Apps/Entities/Contents/Text/EFTextBuilder.cs @@ -25,8 +25,6 @@ public static class EFTextBuilder builder.Entity(b => { - b.ToTable("Texts"); - b.Property(x => x.Id).HasMaxLength(400); b.Property(x => x.AppId).AsString(); b.Property(x => x.SchemaId).AsString(); b.Property(x => x.ContentId).AsString(); @@ -34,12 +32,16 @@ public static class EFTextBuilder builder.Entity(b => { - b.ToTable("Geos"); - b.Property(x => x.Id).HasMaxLength(400); b.Property(x => x.AppId).AsString(); b.Property(x => x.SchemaId).AsString(); b.Property(x => x.ContentId).AsString(); - b.Property(x => x.GeoField).HasMaxLength(255); + }); + + builder.Entity(b => + { + b.Property(x => x.AppId).AsString(); + b.Property(x => x.SchemaId).AsString(); + b.Property(x => x.ContentId).AsString(); }); } } diff --git a/backend/src/Squidex.Data.EntityFramework/Domain/Apps/Entities/Contents/Text/EFTextIndex.cs b/backend/src/Squidex.Data.EntityFramework/Domain/Apps/Entities/Contents/Text/EFTextIndex.cs index d82bbc267..d859f60ba 100644 --- a/backend/src/Squidex.Data.EntityFramework/Domain/Apps/Entities/Contents/Text/EFTextIndex.cs +++ b/backend/src/Squidex.Data.EntityFramework/Domain/Apps/Entities/Contents/Text/EFTextIndex.cs @@ -53,6 +53,9 @@ public sealed class EFTextIndex(IDbContextFactory dbContextF await dbContext.Set().Where(x => x.AppId == app.Id) .ExecuteDeleteAsync(ct); + + await dbContext.Set().Where(x => x.AppId == app.Id) + .ExecuteDeleteAsync(ct); } async Task IDeleter.DeleteSchemaAsync(App app, Schema schema, @@ -65,6 +68,9 @@ public sealed class EFTextIndex(IDbContextFactory dbContextF await dbContext.Set().Where(x => x.AppId == app.Id && x.SchemaId == schema.Id) .ExecuteDeleteAsync(ct); + + await dbContext.Set().Where(x => x.AppId == app.Id && x.SchemaId == schema.Id) + .ExecuteDeleteAsync(ct); } public async Task ClearAsync(CancellationToken ct = default) @@ -91,15 +97,19 @@ public sealed class EFTextIndex(IDbContextFactory dbContextF SRID = 4326, }; - // The distance must be converted to decrees (in contrast to MongoDB, which uses radian). - var degrees = query.Radius / 111320; + var distance = query.Radius; + if (dbContext.Database.IsNpgsql()) + { + // The distance must be converted to decrees (in contrast to MongoDB, which uses radian). + distance = query.Radius / 111320; + } var ids = await dbContext.Set() .Where(x => x.AppId == app.Id) .Where(x => x.SchemaId == query.SchemaId) .Where(x => x.GeoField == query.Field) - .Where(x => x.GeoObject.Distance(point) < degrees) + .Where(x => x.GeoObject.Distance(point) < distance) .WhereScope(scope) .Select(x => x.ContentId) .ToListAsync(ct); @@ -151,38 +161,63 @@ public sealed class EFTextIndex(IDbContextFactory dbContextF return search.Results.OrderByDescending(x => x.Score).Select(x => x.Id).Distinct().ToList(); } - private static Task SearchBySchemaAsync(TContext context, SearchOperation search, IEnumerable schemaIds, double factor, + public async Task FindUserInfo(App app, ApiKeyQuery query, SearchScope scope, CancellationToken ct = default) { + Guard.NotNull(app); + Guard.NotNull(query); + + await using var dbContext = await CreateDbContextAsync(ct); + var queryBuilder = - context.Query() + dbContext.Query() + .Where(ClrFilter.Eq("AppId", app.Id)) + .Where(ClrFilter.Eq("UserInfoApiKey", query.ApiKey)) + .WhereScope(scope); + + var (sql, parameters) = queryBuilder.Compile(); + + var entity = + await dbContext.Set().FromSqlRaw(sql, parameters) + .FirstOrDefaultAsync(ct); + + return entity != null ? + new UserInfoResult(entity.ContentId, entity.UserInfoRole) : + null; + } + + private static Task SearchBySchemaAsync(TContext dbContext, SearchOperation search, IEnumerable schemaIds, double factor, + CancellationToken ct = default) + { + var queryBuilder = + dbContext.Query() .Where(ClrFilter.Eq("AppId", search.App.Id)) .Where(ClrFilter.In("SchemaId", schemaIds.ToList())) .WhereMatch("Texts", search.SearchTerms) .WhereScope(search.SearchScope); - return SearchAsync(context, search, queryBuilder, factor, ct); + return SearchAsync(dbContext, search, queryBuilder, factor, ct); } - private static Task SearchByAppAsync(TContext context, SearchOperation search, double factor, + private static Task SearchByAppAsync(TContext dbContext, SearchOperation search, double factor, CancellationToken ct = default) { var queryBuilder = - context.Query() + dbContext.Query() .Where(ClrFilter.Eq("AppId", search.App.Id)) .WhereMatch("Texts", search.SearchTerms) .WhereScope(search.SearchScope); - return SearchAsync(context, search, queryBuilder, factor, ct); + return SearchAsync(dbContext, search, queryBuilder, factor, ct); } - private static async Task SearchAsync(TContext context, SearchOperation search, SqlQueryBuilder queryBuilder, double factor, + private static async Task SearchAsync(TContext dbContext, SearchOperation search, SqlQueryBuilder queryBuilder, double factor, CancellationToken ct) { var (sql, parameters) = queryBuilder.Compile(); var ids = - await context.Set().FromSqlRaw(sql, parameters) + await dbContext.Set().FromSqlRaw(sql, parameters) .Select(x => x.ContentId) .ToListAsync(ct); @@ -196,6 +231,7 @@ public sealed class EFTextIndex(IDbContextFactory dbContextF var insertsText = new List(); var insertsGeo = new List(); + var insertsUser = new List(); foreach (var batch in commands.Batch(1000)) { @@ -264,6 +300,24 @@ public sealed class EFTextIndex(IDbContextFactory dbContextF } } + foreach (var userInfo in upsert.UserInfos.OrEmpty()) + { + var entity = new EFTextIndexUserInfoEntity + { + Id = id, + AppId = appId, + ContentId = contentId, + UserInfoApiKey = userInfo.ApiKey, + UserInfoRole = userInfo.Role, + SchemaId = upsert.SchemaId.Id, + ServeAll = upsert.ServeAll, + ServePublished = upsert.ServePublished, + Stage = upsert.Stage, + }; + + insertsUser.Add(entity); + } + break; case DeleteIndexEntry: await dbContext.Set() @@ -273,6 +327,10 @@ public sealed class EFTextIndex(IDbContextFactory dbContextF await dbContext.Set() .Where(x => x.Id == id) .ExecuteDeleteAsync(ct); + + await dbContext.Set() + .Where(x => x.Id == id) + .ExecuteDeleteAsync(ct); break; case UpdateIndexEntry update: await dbContext.Set() @@ -288,6 +346,13 @@ public sealed class EFTextIndex(IDbContextFactory dbContextF .SetProperty(x => x.ServeAll, update.ServeAll) .SetProperty(x => x.ServePublished, update.ServePublished), ct); + + await dbContext.Set() + .Where(x => x.Id == id) + .ExecuteUpdateAsync(u => u + .SetProperty(x => x.ServeAll, update.ServeAll) + .SetProperty(x => x.ServePublished, update.ServePublished), + ct); break; } } @@ -295,6 +360,7 @@ public sealed class EFTextIndex(IDbContextFactory dbContextF await dbContext.BulkUpsertAsync(insertsText, ct); await dbContext.BulkUpsertAsync(insertsGeo, ct); + await dbContext.BulkUpsertAsync(insertsUser, ct); } private Task CreateDbContextAsync(CancellationToken ct) diff --git a/backend/src/Squidex.Data.EntityFramework/Domain/Apps/Entities/Contents/Text/EFTextIndexGeoEntity.cs b/backend/src/Squidex.Data.EntityFramework/Domain/Apps/Entities/Contents/Text/EFTextIndexGeoEntity.cs index 797a776b9..3da46fd5f 100644 --- a/backend/src/Squidex.Data.EntityFramework/Domain/Apps/Entities/Contents/Text/EFTextIndexGeoEntity.cs +++ b/backend/src/Squidex.Data.EntityFramework/Domain/Apps/Entities/Contents/Text/EFTextIndexGeoEntity.cs @@ -6,14 +6,17 @@ // ========================================================================== using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; using NetTopologySuite.Geometries; using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Contents.Text; +[Table("Geos")] public sealed class EFTextIndexGeoEntity { [Key] + [MaxLength(400)] required public string Id { get; set; } public DomainId AppId { get; set; } @@ -28,6 +31,7 @@ public sealed class EFTextIndexGeoEntity public bool ServePublished { get; set; } + [MaxLength(255)] public string GeoField { get; set; } public Geometry GeoObject { get; set; } diff --git a/backend/src/Squidex.Data.EntityFramework/Domain/Apps/Entities/Contents/Text/EFTextIndexTextEntity.cs b/backend/src/Squidex.Data.EntityFramework/Domain/Apps/Entities/Contents/Text/EFTextIndexTextEntity.cs index 03b9b7f7e..66c2009e7 100644 --- a/backend/src/Squidex.Data.EntityFramework/Domain/Apps/Entities/Contents/Text/EFTextIndexTextEntity.cs +++ b/backend/src/Squidex.Data.EntityFramework/Domain/Apps/Entities/Contents/Text/EFTextIndexTextEntity.cs @@ -6,13 +6,16 @@ // ========================================================================== using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Contents.Text; +[Table("Texts")] public sealed class EFTextIndexTextEntity { [Key] + [MaxLength(400)] required public string Id { get; set; } public DomainId AppId { get; set; } diff --git a/backend/src/Squidex.Data.EntityFramework/Domain/Apps/Entities/Contents/Text/EFTextIndexUserInfoEntity.cs b/backend/src/Squidex.Data.EntityFramework/Domain/Apps/Entities/Contents/Text/EFTextIndexUserInfoEntity.cs new file mode 100644 index 000000000..ad0222dc6 --- /dev/null +++ b/backend/src/Squidex.Data.EntityFramework/Domain/Apps/Entities/Contents/Text/EFTextIndexUserInfoEntity.cs @@ -0,0 +1,40 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using Microsoft.EntityFrameworkCore; +using Squidex.Infrastructure; + +namespace Squidex.Domain.Apps.Entities.Contents.Text; + +[Table("UserInfos")] +[Index(nameof(UserInfoApiKey))] +public sealed class EFTextIndexUserInfoEntity +{ + [Key] + [MaxLength(400)] + required public string Id { get; set; } + + public DomainId AppId { get; set; } + + public DomainId SchemaId { get; set; } + + public DomainId ContentId { get; set; } + + public byte Stage { get; set; } + + public bool ServeAll { get; set; } + + public bool ServePublished { get; set; } + + [MaxLength(256)] + public string UserInfoApiKey { get; set; } + + [MaxLength(256)] + public string UserInfoRole { get; set; } +} diff --git a/backend/src/Squidex.Data.EntityFramework/Providers/MySql/App/Migrations/20260117183413_AddUserInfoIndex.Designer.cs b/backend/src/Squidex.Data.EntityFramework/Providers/MySql/App/Migrations/20260117183413_AddUserInfoIndex.Designer.cs new file mode 100644 index 000000000..6833bd645 --- /dev/null +++ b/backend/src/Squidex.Data.EntityFramework/Providers/MySql/App/Migrations/20260117183413_AddUserInfoIndex.Designer.cs @@ -0,0 +1,1629 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using NetTopologySuite.Geometries; +using Squidex.Providers.MySql.App; + +#nullable disable + +namespace Squidex.Providers.MySql.App.Migrations +{ + [DbContext(typeof(MySqlAppDbContext))] + [Migration("20260117183413_AddUserInfoIndex")] + partial class AddUserInfoIndex + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.16") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("varchar(255)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("longtext"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("longtext"); + + b.Property("ClaimValue") + .HasColumnType("longtext"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b => + { + b.Property("Id") + .HasColumnType("varchar(255)"); + + b.Property("AccessFailedCount") + .HasColumnType("int"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("longtext"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("tinyint(1)"); + + b.Property("LockoutEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("LockoutEnd") + .HasColumnType("datetime(6)"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("PasswordHash") + .HasColumnType("longtext"); + + b.Property("PhoneNumber") + .HasColumnType("longtext"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("tinyint(1)"); + + b.Property("SecurityStamp") + .HasColumnType("longtext"); + + b.Property("TwoFactorEnabled") + .HasColumnType("tinyint(1)"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("longtext"); + + b.Property("ClaimValue") + .HasColumnType("longtext"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("varchar(255)"); + + b.Property("ProviderKey") + .HasColumnType("varchar(255)"); + + b.Property("ProviderDisplayName") + .HasColumnType("longtext"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("varchar(255)"); + + b.Property("RoleId") + .HasColumnType("varchar(255)"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("varchar(255)"); + + b.Property("LoginProvider") + .HasColumnType("varchar(255)"); + + b.Property("Name") + .HasColumnType("varchar(255)"); + + b.Property("Value") + .HasColumnType("longtext"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreAuthorization", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("varchar(255)"); + + b.Property("ApplicationId") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.Property("ConcurrencyToken") + .IsConcurrencyToken() + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("Properties") + .HasColumnType("longtext"); + + b.Property("Scopes") + .HasColumnType("longtext"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("Subject") + .HasMaxLength(400) + .HasColumnType("varchar(400)"); + + b.Property("Type") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId", "Status", "Subject", "Type"); + + b.ToTable("OpenIddictAuthorizations", (string)null); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("varchar(255)"); + + b.Property("ApplicationId") + .HasColumnType("varchar(255)"); + + b.Property("AuthorizationId") + .HasColumnType("varchar(255)"); + + b.Property("ConcurrencyToken") + .IsConcurrencyToken() + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("CreationDate") + .HasColumnType("datetime(6)"); + + b.Property("ExpirationDate") + .HasColumnType("datetime(6)"); + + b.Property("Payload") + .HasColumnType("longtext"); + + b.Property("Properties") + .HasColumnType("longtext"); + + b.Property("RedemptionDate") + .HasColumnType("datetime(6)"); + + b.Property("ReferenceId") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("Subject") + .HasMaxLength(400) + .HasColumnType("varchar(400)"); + + b.Property("Type") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("AuthorizationId"); + + b.HasIndex("ReferenceId") + .IsUnique(); + + b.HasIndex("ApplicationId", "Status", "Subject", "Type"); + + b.ToTable("OpenIddictTokens", (string)null); + }); + + modelBuilder.Entity("Squidex.AI.Mongo.EFChatEntity", b => + { + b.Property("Id") + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("LastUpdated") + .HasColumnType("datetime(6)"); + + b.Property("Value") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Version") + .IsConcurrencyToken() + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("LastUpdated"); + + b.ToTable("Chats", (string)null); + }); + + modelBuilder.Entity("Squidex.Assets.EntityFramework.EFAssetKeyValueEntity", b => + { + b.Property("Key") + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("Expires") + .HasColumnType("datetime(6)"); + + b.Property("Value") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Key"); + + b.HasIndex("Expires"); + + b.ToTable("AssetKeyValueStore_TusMetadata", (string)null); + }); + + modelBuilder.Entity("Squidex.Domain.Apps.Entities.Apps.EFAppEntity", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("Document") + .HasColumnType("json"); + + b.Property("IndexedCreated") + .HasColumnType("datetime(6)") + .HasColumnName("Created"); + + b.Property("IndexedDeleted") + .HasColumnType("tinyint(1)") + .HasColumnName("Deleted"); + + b.Property("IndexedName") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("Name"); + + b.Property("IndexedTeamId") + .HasMaxLength(255) + .HasColumnType("varchar(255)") + .HasColumnName("TeamId"); + + b.Property("IndexedUserIds") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("UserIds"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.ToTable("States_App", (string)null); + }); + + modelBuilder.Entity("Squidex.Domain.Apps.Entities.Assets.EFAssetEntity", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("AppId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("Created") + .HasColumnType("datetime(6)"); + + b.Property("CreatedBy") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("FileHash") + .HasColumnType("longtext"); + + b.Property("FileName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("FileSize") + .HasColumnType("bigint"); + + b.Property("FileVersion") + .HasColumnType("bigint"); + + b.Property("Id") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("IndexedAppId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("IsDeleted") + .HasColumnType("tinyint(1)"); + + b.Property("IsProtected") + .HasColumnType("tinyint(1)"); + + b.Property("LastModified") + .HasColumnType("datetime(6)"); + + b.Property("LastModifiedBy") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("Metadata") + .IsRequired() + .HasColumnType("json"); + + b.Property("MimeType") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("ParentId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("Slug") + .HasColumnType("longtext"); + + b.Property("Tags") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("varchar(1000)"); + + b.Property("TotalSize") + .HasColumnType("bigint"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.HasIndex("IndexedAppId", "Id"); + + b.ToTable("Assets"); + }); + + modelBuilder.Entity("Squidex.Domain.Apps.Entities.Assets.EFAssetFolderEntity", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("AppId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("Created") + .HasColumnType("datetime(6)"); + + b.Property("CreatedBy") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("FolderName") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Id") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("IndexedAppId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("IsDeleted") + .HasColumnType("tinyint(1)"); + + b.Property("LastModified") + .HasColumnType("datetime(6)"); + + b.Property("LastModifiedBy") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("ParentId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.HasIndex("IndexedAppId", "Id"); + + b.ToTable("AssetFolders"); + }); + + modelBuilder.Entity("Squidex.Domain.Apps.Entities.Contents.EFContentCompleteEntity", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("AppId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("Created") + .HasColumnType("datetime(6)"); + + b.Property("CreatedBy") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("Data") + .IsRequired() + .HasColumnType("json"); + + b.Property("Id") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("IndexedAppId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("IndexedSchemaId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("IsDeleted") + .HasColumnType("tinyint(1)"); + + b.Property("LastModified") + .HasColumnType("datetime(6)"); + + b.Property("LastModifiedBy") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("NewData") + .HasColumnType("json"); + + b.Property("NewStatus") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("ScheduleJob") + .HasColumnType("json"); + + b.Property("ScheduledAt") + .HasColumnType("datetime(6)"); + + b.Property("SchemaId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("TranslationStatus") + .HasColumnType("json"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.ToTable("ContentsAll", (string)null); + }); + + modelBuilder.Entity("Squidex.Domain.Apps.Entities.Contents.EFContentPublishedEntity", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("AppId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("Created") + .HasColumnType("datetime(6)"); + + b.Property("CreatedBy") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("Data") + .IsRequired() + .HasColumnType("json"); + + b.Property("Id") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("IndexedAppId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("IndexedSchemaId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("IsDeleted") + .HasColumnType("tinyint(1)"); + + b.Property("LastModified") + .HasColumnType("datetime(6)"); + + b.Property("LastModifiedBy") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("NewData") + .HasColumnType("json"); + + b.Property("NewStatus") + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("ScheduleJob") + .HasColumnType("json"); + + b.Property("ScheduledAt") + .HasColumnType("datetime(6)"); + + b.Property("SchemaId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("TranslationStatus") + .HasColumnType("json"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.ToTable("ContentsPublished", (string)null); + }); + + modelBuilder.Entity("Squidex.Domain.Apps.Entities.Contents.EFContentTableEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("AppId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("SchemaId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("AppId", "SchemaId") + .IsUnique(); + + b.ToTable("ContentTables", (string)null); + }); + + modelBuilder.Entity("Squidex.Domain.Apps.Entities.Contents.EFReferenceCompleteEntity", b => + { + b.Property("AppId") + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("FromKey") + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("ToId") + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("FromSchema") + .IsRequired() + .ValueGeneratedOnAdd() + .HasMaxLength(255) + .HasColumnType("varchar(255)") + .HasDefaultValue("00000000-0000-0000-0000-000000000000"); + + b.HasKey("AppId", "FromKey", "ToId"); + + b.ToTable("ContentReferencesAll", (string)null); + }); + + modelBuilder.Entity("Squidex.Domain.Apps.Entities.Contents.EFReferencePublishedEntity", b => + { + b.Property("AppId") + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("FromKey") + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("ToId") + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("FromSchema") + .IsRequired() + .ValueGeneratedOnAdd() + .HasMaxLength(255) + .HasColumnType("varchar(255)") + .HasDefaultValue("00000000-0000-0000-0000-000000000000"); + + b.HasKey("AppId", "FromKey", "ToId"); + + b.ToTable("ContentReferencesPublished", (string)null); + }); + + modelBuilder.Entity("Squidex.Domain.Apps.Entities.Contents.Text.EFTextIndexGeoEntity", b => + { + b.Property("Id") + .HasMaxLength(400) + .HasColumnType("varchar(400)"); + + b.Property("AppId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("ContentId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("GeoField") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("GeoObject") + .IsRequired() + .HasColumnType("geometry"); + + b.Property("SchemaId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("ServeAll") + .HasColumnType("tinyint(1)"); + + b.Property("ServePublished") + .HasColumnType("tinyint(1)"); + + b.Property("Stage") + .HasColumnType("tinyint unsigned"); + + b.HasKey("Id"); + + b.ToTable("Geos"); + }); + + modelBuilder.Entity("Squidex.Domain.Apps.Entities.Contents.Text.EFTextIndexTextEntity", b => + { + b.Property("Id") + .HasMaxLength(400) + .HasColumnType("varchar(400)"); + + b.Property("AppId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("ContentId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("SchemaId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("ServeAll") + .HasColumnType("tinyint(1)"); + + b.Property("ServePublished") + .HasColumnType("tinyint(1)"); + + b.Property("Stage") + .HasColumnType("tinyint unsigned"); + + b.Property("Texts") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.ToTable("Texts"); + }); + + modelBuilder.Entity("Squidex.Domain.Apps.Entities.Contents.Text.EFTextIndexUserInfoEntity", b => + { + b.Property("Id") + .HasMaxLength(400) + .HasColumnType("varchar(400)"); + + b.Property("AppId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("ContentId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("SchemaId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("ServeAll") + .HasColumnType("tinyint(1)"); + + b.Property("ServePublished") + .HasColumnType("tinyint(1)"); + + b.Property("Stage") + .HasColumnType("tinyint unsigned"); + + b.Property("UserInfoApiKey") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("UserInfoRole") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("UserInfoApiKey"); + + b.ToTable("UserInfos"); + }); + + modelBuilder.Entity("Squidex.Domain.Apps.Entities.Contents.Text.State.TextContentState", b => + { + b.Property("UniqueContentId") + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("State") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.HasKey("UniqueContentId"); + + b.ToTable("TextState", (string)null); + }); + + modelBuilder.Entity("Squidex.Domain.Apps.Entities.History.HistoryEvent", b => + { + b.Property("Id") + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("Actor") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("Channel") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Created") + .HasColumnType("datetime(6)"); + + b.Property("EventType") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("OwnerId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("Parameters") + .IsRequired() + .HasColumnType("json"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("HistoryEvent"); + }); + + modelBuilder.Entity("Squidex.Domain.Apps.Entities.Rules.EFRuleEntity", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("Document") + .HasColumnType("json"); + + b.Property("IndexedAppId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)") + .HasColumnName("AppId"); + + b.Property("IndexedDeleted") + .HasColumnType("tinyint(1)") + .HasColumnName("Deleted"); + + b.Property("IndexedId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)") + .HasColumnName("Id"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.ToTable("States_Rule", (string)null); + }); + + modelBuilder.Entity("Squidex.Domain.Apps.Entities.Schemas.EFSchemaEntity", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("Document") + .HasColumnType("json"); + + b.Property("IndexedAppId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)") + .HasColumnName("AppId"); + + b.Property("IndexedDeleted") + .HasColumnType("tinyint(1)") + .HasColumnName("Deleted"); + + b.Property("IndexedId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)") + .HasColumnName("Id"); + + b.Property("IndexedName") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("Name"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.ToTable("States_Schema", (string)null); + }); + + modelBuilder.Entity("Squidex.Domain.Apps.Entities.Teams.EFTeamEntity", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("Document") + .HasColumnType("json"); + + b.Property("IndexedAuthDomain") + .HasColumnType("longtext") + .HasColumnName("AuthDomain"); + + b.Property("IndexedDeleted") + .HasColumnType("tinyint(1)") + .HasColumnName("Deleted"); + + b.Property("IndexedUserIds") + .IsRequired() + .HasColumnType("longtext") + .HasColumnName("UserIds"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.ToTable("States_Team", (string)null); + }); + + modelBuilder.Entity("Squidex.Events.EntityFramework.EFEventCommit", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("EventStream") + .IsRequired() + .HasMaxLength(750) + .HasColumnType("varchar(750)"); + + b.Property("EventStreamOffset") + .HasColumnType("bigint"); + + b.Property("Events") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("EventsCount") + .HasColumnType("bigint"); + + b.Property("Position") + .HasColumnType("bigint"); + + b.Property("Timestamp") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("EventStream", "EventStreamOffset") + .IsUnique(); + + b.HasIndex("EventStream", "Position"); + + b.HasIndex("EventStream", "Timestamp"); + + b.ToTable("Events"); + }); + + modelBuilder.Entity("Squidex.Events.EntityFramework.EFPosition", b => + { + b.Property("Id") + .HasColumnType("bigint"); + + b.Property("Position") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("EventPosition"); + }); + + modelBuilder.Entity("Squidex.Flows.EntityFramework.EFCronJobEntity", b => + { + b.Property("Id") + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("Data") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("DueTime") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("DueTime"); + + b.ToTable("CronJobs", (string)null); + }); + + modelBuilder.Entity("Squidex.Flows.EntityFramework.EFFlowStateEntity", b => + { + b.Property("Id") + .HasColumnType("char(36)"); + + b.Property("Created") + .HasColumnType("datetime(6)"); + + b.Property("DefinitionId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("DueTime") + .HasColumnType("datetime(6)"); + + b.Property("OwnerId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("SchedulePartition") + .HasColumnType("int"); + + b.Property("State") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("Id"); + + b.HasIndex("DueTime", "SchedulePartition"); + + b.ToTable("Flows", (string)null); + }); + + modelBuilder.Entity("Squidex.Infrastructure.Caching.EFCacheEntity", b => + { + b.Property("Key") + .HasColumnType("varchar(255)"); + + b.Property("Expires") + .HasColumnType("datetime(6)"); + + b.Property("Value") + .IsRequired() + .HasColumnType("longblob"); + + b.HasKey("Key"); + + b.ToTable("Cache", (string)null); + }); + + modelBuilder.Entity("Squidex.Infrastructure.Log.EFRequestEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("Id")); + + b.Property("Key") + .IsRequired() + .HasColumnType("varchar(255)"); + + b.Property("Properties") + .IsRequired() + .HasColumnType("json"); + + b.Property("Timestamp") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.HasIndex("Key"); + + b.ToTable("Requests", (string)null); + }); + + modelBuilder.Entity("Squidex.Infrastructure.Migrations.EFMigrationEntity", b => + { + b.Property("Id") + .HasColumnType("int"); + + b.Property("IsLocked") + .HasColumnType("tinyint(1)"); + + b.Property("Version") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("Migrations", (string)null); + }); + + modelBuilder.Entity("Squidex.Infrastructure.States.EFState", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("Document") + .HasColumnType("json"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.ToTable("States_UISettings", (string)null); + }); + + modelBuilder.Entity("Squidex.Infrastructure.States.EFState", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("Document") + .HasColumnType("json"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.ToTable("States_Index_TagHistory", (string)null); + }); + + modelBuilder.Entity("Squidex.Infrastructure.States.EFState", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("Document") + .HasColumnType("json"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.ToTable("States_UsageNotifications", (string)null); + }); + + modelBuilder.Entity("Squidex.Infrastructure.States.EFState", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("Document") + .HasColumnType("json"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.ToTable("States_Counters", (string)null); + }); + + modelBuilder.Entity("Squidex.Infrastructure.States.EFState", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("Document") + .HasColumnType("json"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.ToTable("States_JobsState", (string)null); + }); + + modelBuilder.Entity("Squidex.Infrastructure.States.EFState", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("Document") + .HasColumnType("json"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.ToTable("States_UsageTracker", (string)null); + }); + + modelBuilder.Entity("Squidex.Infrastructure.States.EFState", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("Document") + .HasColumnType("json"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.ToTable("States_Index_Tags", (string)null); + }); + + modelBuilder.Entity("Squidex.Infrastructure.States.EFState", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("Document") + .HasColumnType("json"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.ToTable("States_Identity_Keys", (string)null); + }); + + modelBuilder.Entity("Squidex.Infrastructure.States.EFState", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("Document") + .HasColumnType("json"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.ToTable("States_Identity_Xml", (string)null); + }); + + modelBuilder.Entity("Squidex.Infrastructure.States.EFState", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("Document") + .HasColumnType("json"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.ToTable("States_EventConsumerState", (string)null); + }); + + modelBuilder.Entity("Squidex.Infrastructure.States.EFState", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("Document") + .HasColumnType("json"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.ToTable("States_Names", (string)null); + }); + + modelBuilder.Entity("Squidex.Infrastructure.UsageTracking.EFUsageCounterEntity", b => + { + b.Property("Key") + .HasColumnType("varchar(255)"); + + b.Property("Date") + .HasColumnType("datetime(6)"); + + b.Property("Category") + .HasColumnType("varchar(255)"); + + b.Property("CounterKey") + .HasColumnType("varchar(255)"); + + b.Property("CounterValue") + .HasColumnType("double"); + + b.HasKey("Key", "Date", "Category", "CounterKey"); + + b.ToTable("Counter", (string)null); + }); + + modelBuilder.Entity("Squidex.Messaging.EntityFramework.EFMessage", b => + { + b.Property("Id") + .HasColumnType("varchar(255)"); + + b.Property("ChannelName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("MessageData") + .IsRequired() + .HasColumnType("longblob"); + + b.Property("MessageHeaders") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("varchar(2000)"); + + b.Property("QueueName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("TimeHandled") + .HasColumnType("datetime(6)"); + + b.Property("TimeToLive") + .HasColumnType("datetime(6)"); + + b.Property("Version") + .IsConcurrencyToken() + .HasColumnType("char(36)"); + + b.HasKey("Id"); + + b.HasIndex("ChannelName", "TimeHandled"); + + b.ToTable("Messages", (string)null); + }); + + modelBuilder.Entity("Squidex.Messaging.EntityFramework.EFMessagingDataEntity", b => + { + b.Property("Group") + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("Key") + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("Expiration") + .HasColumnType("datetime(6)"); + + b.Property("ValueData") + .IsRequired() + .HasColumnType("longblob"); + + b.Property("ValueFormat") + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("ValueType") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.HasKey("Group", "Key"); + + b.HasIndex("Expiration"); + + b.ToTable("MessagingData", (string)null); + }); + + modelBuilder.Entity("YDotNet.Server.EntityFramework.YDotNetDocument", b => + { + b.Property("Id") + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("Data") + .IsRequired() + .HasColumnType("longblob"); + + b.Property("Expiration") + .HasColumnType("datetime(6)"); + + b.HasKey("Id"); + + b.ToTable("YDotNetDocument", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreToken", b => + { + b.HasOne("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreAuthorization", "Authorization") + .WithMany("Tokens") + .HasForeignKey("AuthorizationId"); + + b.Navigation("Authorization"); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreAuthorization", b => + { + b.Navigation("Tokens"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/backend/src/Squidex.Data.EntityFramework/Providers/MySql/App/Migrations/20260117183413_AddUserInfoIndex.cs b/backend/src/Squidex.Data.EntityFramework/Providers/MySql/App/Migrations/20260117183413_AddUserInfoIndex.cs new file mode 100644 index 000000000..e59fae3ef --- /dev/null +++ b/backend/src/Squidex.Data.EntityFramework/Providers/MySql/App/Migrations/20260117183413_AddUserInfoIndex.cs @@ -0,0 +1,52 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Squidex.Providers.MySql.App.Migrations +{ + /// + public partial class AddUserInfoIndex : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "UserInfos", + columns: table => new + { + Id = table.Column(type: "varchar(400)", maxLength: 400, nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + AppId = table.Column(type: "varchar(255)", maxLength: 255, nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + SchemaId = table.Column(type: "varchar(255)", maxLength: 255, nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + ContentId = table.Column(type: "varchar(255)", maxLength: 255, nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + Stage = table.Column(type: "tinyint unsigned", nullable: false), + ServeAll = table.Column(type: "tinyint(1)", nullable: false), + ServePublished = table.Column(type: "tinyint(1)", nullable: false), + UserInfoApiKey = table.Column(type: "varchar(256)", maxLength: 256, nullable: false) + .Annotation("MySql:CharSet", "utf8mb4"), + UserInfoRole = table.Column(type: "varchar(256)", maxLength: 256, nullable: false) + .Annotation("MySql:CharSet", "utf8mb4") + }, + constraints: table => + { + table.PrimaryKey("PK_UserInfos", x => x.Id); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.CreateIndex( + name: "IX_UserInfos_UserInfoApiKey", + table: "UserInfos", + column: "UserInfoApiKey"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "UserInfos"); + } + } +} diff --git a/backend/src/Squidex.Data.EntityFramework/Providers/MySql/App/Migrations/MySqlDbContextModelSnapshot.cs b/backend/src/Squidex.Data.EntityFramework/Providers/MySql/App/Migrations/MySqlDbContextModelSnapshot.cs index e6dd9f393..67a07b809 100644 --- a/backend/src/Squidex.Data.EntityFramework/Providers/MySql/App/Migrations/MySqlDbContextModelSnapshot.cs +++ b/backend/src/Squidex.Data.EntityFramework/Providers/MySql/App/Migrations/MySqlDbContextModelSnapshot.cs @@ -18,7 +18,7 @@ namespace Squidex.Providers.MySql.Migrations { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "8.0.14") + .HasAnnotation("ProductVersion", "8.0.16") .HasAnnotation("Relational:MaxIdentifierLength", 64); MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder); @@ -845,7 +845,7 @@ namespace Squidex.Providers.MySql.Migrations b.HasKey("Id"); - b.ToTable("Geos", (string)null); + b.ToTable("Geos"); }); modelBuilder.Entity("Squidex.Domain.Apps.Entities.Contents.Text.EFTextIndexTextEntity", b => @@ -884,7 +884,54 @@ namespace Squidex.Providers.MySql.Migrations b.HasKey("Id"); - b.ToTable("Texts", (string)null); + b.ToTable("Texts"); + }); + + modelBuilder.Entity("Squidex.Domain.Apps.Entities.Contents.Text.EFTextIndexUserInfoEntity", b => + { + b.Property("Id") + .HasMaxLength(400) + .HasColumnType("varchar(400)"); + + b.Property("AppId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("ContentId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("SchemaId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("varchar(255)"); + + b.Property("ServeAll") + .HasColumnType("tinyint(1)"); + + b.Property("ServePublished") + .HasColumnType("tinyint(1)"); + + b.Property("Stage") + .HasColumnType("tinyint unsigned"); + + b.Property("UserInfoApiKey") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.Property("UserInfoRole") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("varchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("UserInfoApiKey"); + + b.ToTable("UserInfos"); }); modelBuilder.Entity("Squidex.Domain.Apps.Entities.Contents.Text.State.TextContentState", b => @@ -1046,7 +1093,6 @@ namespace Squidex.Providers.MySql.Migrations modelBuilder.Entity("Squidex.Events.EntityFramework.EFEventCommit", b => { b.Property("Id") - .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("EventStream") @@ -1118,7 +1164,6 @@ namespace Squidex.Providers.MySql.Migrations modelBuilder.Entity("Squidex.Flows.EntityFramework.EFFlowStateEntity", b => { b.Property("Id") - .ValueGeneratedOnAdd() .HasColumnType("char(36)"); b.Property("Created") diff --git a/backend/src/Squidex.Data.EntityFramework/Providers/Postgres/App/Migrations/20260117183420_AddUserInfoIndex.Designer.cs b/backend/src/Squidex.Data.EntityFramework/Providers/Postgres/App/Migrations/20260117183420_AddUserInfoIndex.Designer.cs new file mode 100644 index 000000000..c0e859b76 --- /dev/null +++ b/backend/src/Squidex.Data.EntityFramework/Providers/Postgres/App/Migrations/20260117183420_AddUserInfoIndex.Designer.cs @@ -0,0 +1,1630 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using NetTopologySuite.Geometries; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using Squidex.Providers.Postgres.App; + +#nullable disable + +namespace Squidex.Providers.Postgres.App.Migrations +{ + [DbContext(typeof(PostgresAppDbContext))] + [Migration("20260117183420_AddUserInfoIndex")] + partial class AddUserInfoIndex + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.16") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "postgis"); + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("AccessFailedCount") + .HasColumnType("integer"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("text"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("boolean"); + + b.Property("LockoutEnabled") + .HasColumnType("boolean"); + + b.Property("LockoutEnd") + .HasColumnType("timestamp with time zone"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("PasswordHash") + .HasColumnType("text"); + + b.Property("PhoneNumber") + .HasColumnType("text"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("boolean"); + + b.Property("SecurityStamp") + .HasColumnType("text"); + + b.Property("TwoFactorEnabled") + .HasColumnType("boolean"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("text"); + + b.Property("ClaimValue") + .HasColumnType("text"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("ProviderKey") + .HasColumnType("text"); + + b.Property("ProviderDisplayName") + .HasColumnType("text"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("text"); + + b.Property("RoleId") + .HasColumnType("text"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("text"); + + b.Property("LoginProvider") + .HasColumnType("text"); + + b.Property("Name") + .HasColumnType("text"); + + b.Property("Value") + .HasColumnType("text"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreAuthorization", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("text"); + + b.Property("ApplicationId") + .IsRequired() + .HasColumnType("text"); + + b.Property("ConcurrencyToken") + .IsConcurrencyToken() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Properties") + .HasColumnType("text"); + + b.Property("Scopes") + .HasColumnType("text"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Subject") + .HasMaxLength(400) + .HasColumnType("character varying(400)"); + + b.Property("Type") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId", "Status", "Subject", "Type"); + + b.ToTable("OpenIddictAuthorizations", (string)null); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("text"); + + b.Property("ApplicationId") + .HasColumnType("text"); + + b.Property("AuthorizationId") + .HasColumnType("text"); + + b.Property("ConcurrencyToken") + .IsConcurrencyToken() + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("CreationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("ExpirationDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Payload") + .HasColumnType("text"); + + b.Property("Properties") + .HasColumnType("text"); + + b.Property("RedemptionDate") + .HasColumnType("timestamp with time zone"); + + b.Property("ReferenceId") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.Property("Subject") + .HasMaxLength(400) + .HasColumnType("character varying(400)"); + + b.Property("Type") + .HasMaxLength(50) + .HasColumnType("character varying(50)"); + + b.HasKey("Id"); + + b.HasIndex("AuthorizationId"); + + b.HasIndex("ReferenceId") + .IsUnique(); + + b.HasIndex("ApplicationId", "Status", "Subject", "Type"); + + b.ToTable("OpenIddictTokens", (string)null); + }); + + modelBuilder.Entity("Squidex.AI.Mongo.EFChatEntity", b => + { + b.Property("Id") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("LastUpdated") + .HasColumnType("timestamp with time zone"); + + b.Property("Value") + .IsRequired() + .HasColumnType("text"); + + b.Property("Version") + .IsConcurrencyToken() + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("LastUpdated"); + + b.ToTable("Chats", (string)null); + }); + + modelBuilder.Entity("Squidex.Assets.EntityFramework.EFAssetKeyValueEntity", b => + { + b.Property("Key") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("Expires") + .HasColumnType("timestamp with time zone"); + + b.Property("Value") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Key"); + + b.HasIndex("Expires"); + + b.ToTable("AssetKeyValueStore_TusMetadata", (string)null); + }); + + modelBuilder.Entity("Squidex.Domain.Apps.Entities.Apps.EFAppEntity", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("Document") + .HasColumnType("jsonb"); + + b.Property("IndexedCreated") + .HasColumnType("timestamp with time zone") + .HasColumnName("Created"); + + b.Property("IndexedDeleted") + .HasColumnType("boolean") + .HasColumnName("Deleted"); + + b.Property("IndexedName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("Name"); + + b.Property("IndexedTeamId") + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("TeamId"); + + b.Property("IndexedUserIds") + .IsRequired() + .HasColumnType("text") + .HasColumnName("UserIds"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.ToTable("States_App", (string)null); + }); + + modelBuilder.Entity("Squidex.Domain.Apps.Entities.Assets.EFAssetEntity", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("AppId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("CreatedBy") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("FileHash") + .HasColumnType("text"); + + b.Property("FileName") + .IsRequired() + .HasColumnType("text"); + + b.Property("FileSize") + .HasColumnType("bigint"); + + b.Property("FileVersion") + .HasColumnType("bigint"); + + b.Property("Id") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("IndexedAppId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("IsProtected") + .HasColumnType("boolean"); + + b.Property("LastModified") + .HasColumnType("timestamp with time zone"); + + b.Property("LastModifiedBy") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Metadata") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("MimeType") + .IsRequired() + .HasColumnType("text"); + + b.Property("ParentId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("Slug") + .HasColumnType("text"); + + b.Property("Tags") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("character varying(1000)"); + + b.Property("TotalSize") + .HasColumnType("bigint"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.HasIndex("IndexedAppId", "Id"); + + b.ToTable("Assets"); + }); + + modelBuilder.Entity("Squidex.Domain.Apps.Entities.Assets.EFAssetFolderEntity", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("AppId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("CreatedBy") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("FolderName") + .IsRequired() + .HasColumnType("text"); + + b.Property("Id") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("IndexedAppId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("LastModified") + .HasColumnType("timestamp with time zone"); + + b.Property("LastModifiedBy") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("ParentId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.HasIndex("IndexedAppId", "Id"); + + b.ToTable("AssetFolders"); + }); + + modelBuilder.Entity("Squidex.Domain.Apps.Entities.Contents.EFContentCompleteEntity", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("AppId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("CreatedBy") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Data") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("Id") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("IndexedAppId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("IndexedSchemaId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("LastModified") + .HasColumnType("timestamp with time zone"); + + b.Property("LastModifiedBy") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("NewData") + .HasColumnType("jsonb"); + + b.Property("NewStatus") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("ScheduleJob") + .HasColumnType("jsonb"); + + b.Property("ScheduledAt") + .HasColumnType("timestamp with time zone"); + + b.Property("SchemaId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("TranslationStatus") + .HasColumnType("jsonb"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.ToTable("ContentsAll", (string)null); + }); + + modelBuilder.Entity("Squidex.Domain.Apps.Entities.Contents.EFContentPublishedEntity", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("AppId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("CreatedBy") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Data") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("Id") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("IndexedAppId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("IndexedSchemaId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("IsDeleted") + .HasColumnType("boolean"); + + b.Property("LastModified") + .HasColumnType("timestamp with time zone"); + + b.Property("LastModifiedBy") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("NewData") + .HasColumnType("jsonb"); + + b.Property("NewStatus") + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("ScheduleJob") + .HasColumnType("jsonb"); + + b.Property("ScheduledAt") + .HasColumnType("timestamp with time zone"); + + b.Property("SchemaId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("TranslationStatus") + .HasColumnType("jsonb"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.ToTable("ContentsPublished", (string)null); + }); + + modelBuilder.Entity("Squidex.Domain.Apps.Entities.Contents.EFContentTableEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AppId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("SchemaId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.HasKey("Id"); + + b.HasIndex("AppId", "SchemaId") + .IsUnique(); + + b.ToTable("ContentTables", (string)null); + }); + + modelBuilder.Entity("Squidex.Domain.Apps.Entities.Contents.EFReferenceCompleteEntity", b => + { + b.Property("AppId") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("FromKey") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("ToId") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("FromSchema") + .IsRequired() + .ValueGeneratedOnAdd() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasDefaultValue("00000000-0000-0000-0000-000000000000"); + + b.HasKey("AppId", "FromKey", "ToId"); + + b.ToTable("ContentReferencesAll", (string)null); + }); + + modelBuilder.Entity("Squidex.Domain.Apps.Entities.Contents.EFReferencePublishedEntity", b => + { + b.Property("AppId") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("FromKey") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("ToId") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("FromSchema") + .IsRequired() + .ValueGeneratedOnAdd() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasDefaultValue("00000000-0000-0000-0000-000000000000"); + + b.HasKey("AppId", "FromKey", "ToId"); + + b.ToTable("ContentReferencesPublished", (string)null); + }); + + modelBuilder.Entity("Squidex.Domain.Apps.Entities.Contents.Text.EFTextIndexGeoEntity", b => + { + b.Property("Id") + .HasMaxLength(400) + .HasColumnType("character varying(400)"); + + b.Property("AppId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("ContentId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("GeoField") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("GeoObject") + .IsRequired() + .HasColumnType("geometry"); + + b.Property("SchemaId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("ServeAll") + .HasColumnType("boolean"); + + b.Property("ServePublished") + .HasColumnType("boolean"); + + b.Property("Stage") + .HasColumnType("smallint"); + + b.HasKey("Id"); + + b.ToTable("Geos"); + }); + + modelBuilder.Entity("Squidex.Domain.Apps.Entities.Contents.Text.EFTextIndexTextEntity", b => + { + b.Property("Id") + .HasMaxLength(400) + .HasColumnType("character varying(400)"); + + b.Property("AppId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("ContentId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("SchemaId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("ServeAll") + .HasColumnType("boolean"); + + b.Property("ServePublished") + .HasColumnType("boolean"); + + b.Property("Stage") + .HasColumnType("smallint"); + + b.Property("Texts") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("Texts"); + }); + + modelBuilder.Entity("Squidex.Domain.Apps.Entities.Contents.Text.EFTextIndexUserInfoEntity", b => + { + b.Property("Id") + .HasMaxLength(400) + .HasColumnType("character varying(400)"); + + b.Property("AppId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("ContentId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("SchemaId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("ServeAll") + .HasColumnType("boolean"); + + b.Property("ServePublished") + .HasColumnType("boolean"); + + b.Property("Stage") + .HasColumnType("smallint"); + + b.Property("UserInfoApiKey") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("UserInfoRole") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("UserInfoApiKey"); + + b.ToTable("UserInfos"); + }); + + modelBuilder.Entity("Squidex.Domain.Apps.Entities.Contents.Text.State.TextContentState", b => + { + b.Property("UniqueContentId") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("State") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.HasKey("UniqueContentId"); + + b.ToTable("TextState", (string)null); + }); + + modelBuilder.Entity("Squidex.Domain.Apps.Entities.History.HistoryEvent", b => + { + b.Property("Id") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("Actor") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("character varying(100)"); + + b.Property("Channel") + .IsRequired() + .HasColumnType("text"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("EventType") + .IsRequired() + .HasColumnType("text"); + + b.Property("OwnerId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("Parameters") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("HistoryEvent"); + }); + + modelBuilder.Entity("Squidex.Domain.Apps.Entities.Rules.EFRuleEntity", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("Document") + .HasColumnType("jsonb"); + + b.Property("IndexedAppId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("AppId"); + + b.Property("IndexedDeleted") + .HasColumnType("boolean") + .HasColumnName("Deleted"); + + b.Property("IndexedId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("Id"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.ToTable("States_Rule", (string)null); + }); + + modelBuilder.Entity("Squidex.Domain.Apps.Entities.Schemas.EFSchemaEntity", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("Document") + .HasColumnType("jsonb"); + + b.Property("IndexedAppId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("AppId"); + + b.Property("IndexedDeleted") + .HasColumnType("boolean") + .HasColumnName("Deleted"); + + b.Property("IndexedId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)") + .HasColumnName("Id"); + + b.Property("IndexedName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("Name"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.ToTable("States_Schema", (string)null); + }); + + modelBuilder.Entity("Squidex.Domain.Apps.Entities.Teams.EFTeamEntity", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("Document") + .HasColumnType("jsonb"); + + b.Property("IndexedAuthDomain") + .HasColumnType("text") + .HasColumnName("AuthDomain"); + + b.Property("IndexedDeleted") + .HasColumnType("boolean") + .HasColumnName("Deleted"); + + b.Property("IndexedUserIds") + .IsRequired() + .HasColumnType("text") + .HasColumnName("UserIds"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.ToTable("States_Team", (string)null); + }); + + modelBuilder.Entity("Squidex.Events.EntityFramework.EFEventCommit", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("EventStream") + .IsRequired() + .HasMaxLength(750) + .HasColumnType("character varying(750)"); + + b.Property("EventStreamOffset") + .HasColumnType("bigint"); + + b.Property("Events") + .IsRequired() + .HasColumnType("text[]"); + + b.Property("EventsCount") + .HasColumnType("bigint"); + + b.Property("Position") + .HasColumnType("bigint"); + + b.Property("Timestamp") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("EventStream", "EventStreamOffset") + .IsUnique(); + + b.HasIndex("EventStream", "Position"); + + b.HasIndex("EventStream", "Timestamp"); + + b.ToTable("Events"); + }); + + modelBuilder.Entity("Squidex.Events.EntityFramework.EFPosition", b => + { + b.Property("Id") + .HasColumnType("bigint"); + + b.Property("Position") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("EventPosition"); + }); + + modelBuilder.Entity("Squidex.Flows.EntityFramework.EFCronJobEntity", b => + { + b.Property("Id") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("Data") + .IsRequired() + .HasColumnType("text"); + + b.Property("DueTime") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("DueTime"); + + b.ToTable("CronJobs", (string)null); + }); + + modelBuilder.Entity("Squidex.Flows.EntityFramework.EFFlowStateEntity", b => + { + b.Property("Id") + .HasColumnType("uuid"); + + b.Property("Created") + .HasColumnType("timestamp with time zone"); + + b.Property("DefinitionId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("DueTime") + .HasColumnType("timestamp with time zone"); + + b.Property("OwnerId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("SchedulePartition") + .HasColumnType("integer"); + + b.Property("State") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.HasIndex("DueTime", "SchedulePartition"); + + b.ToTable("Flows", (string)null); + }); + + modelBuilder.Entity("Squidex.Infrastructure.Caching.EFCacheEntity", b => + { + b.Property("Key") + .HasColumnType("text"); + + b.Property("Expires") + .HasColumnType("timestamp with time zone"); + + b.Property("Value") + .IsRequired() + .HasColumnType("bytea"); + + b.HasKey("Key"); + + b.ToTable("Cache", (string)null); + }); + + modelBuilder.Entity("Squidex.Infrastructure.Log.EFRequestEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Key") + .IsRequired() + .HasColumnType("text"); + + b.Property("Properties") + .IsRequired() + .HasColumnType("jsonb"); + + b.Property("Timestamp") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.HasIndex("Key"); + + b.ToTable("Requests", (string)null); + }); + + modelBuilder.Entity("Squidex.Infrastructure.Migrations.EFMigrationEntity", b => + { + b.Property("Id") + .HasColumnType("integer"); + + b.Property("IsLocked") + .HasColumnType("boolean"); + + b.Property("Version") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.ToTable("Migrations", (string)null); + }); + + modelBuilder.Entity("Squidex.Infrastructure.States.EFState", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("Document") + .HasColumnType("jsonb"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.ToTable("States_UISettings", (string)null); + }); + + modelBuilder.Entity("Squidex.Infrastructure.States.EFState", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("Document") + .HasColumnType("jsonb"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.ToTable("States_Index_TagHistory", (string)null); + }); + + modelBuilder.Entity("Squidex.Infrastructure.States.EFState", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("Document") + .HasColumnType("jsonb"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.ToTable("States_UsageNotifications", (string)null); + }); + + modelBuilder.Entity("Squidex.Infrastructure.States.EFState", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("Document") + .HasColumnType("jsonb"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.ToTable("States_Counters", (string)null); + }); + + modelBuilder.Entity("Squidex.Infrastructure.States.EFState", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("Document") + .HasColumnType("jsonb"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.ToTable("States_JobsState", (string)null); + }); + + modelBuilder.Entity("Squidex.Infrastructure.States.EFState", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("Document") + .HasColumnType("jsonb"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.ToTable("States_UsageTracker", (string)null); + }); + + modelBuilder.Entity("Squidex.Infrastructure.States.EFState", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("Document") + .HasColumnType("jsonb"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.ToTable("States_Index_Tags", (string)null); + }); + + modelBuilder.Entity("Squidex.Infrastructure.States.EFState", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("Document") + .HasColumnType("jsonb"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.ToTable("States_Identity_Keys", (string)null); + }); + + modelBuilder.Entity("Squidex.Infrastructure.States.EFState", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("Document") + .HasColumnType("jsonb"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.ToTable("States_Identity_Xml", (string)null); + }); + + modelBuilder.Entity("Squidex.Infrastructure.States.EFState", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("Document") + .HasColumnType("jsonb"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.ToTable("States_EventConsumerState", (string)null); + }); + + modelBuilder.Entity("Squidex.Infrastructure.States.EFState", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("Document") + .HasColumnType("jsonb"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.ToTable("States_Names", (string)null); + }); + + modelBuilder.Entity("Squidex.Infrastructure.UsageTracking.EFUsageCounterEntity", b => + { + b.Property("Key") + .HasColumnType("text"); + + b.Property("Date") + .HasColumnType("timestamp with time zone"); + + b.Property("Category") + .HasColumnType("text"); + + b.Property("CounterKey") + .HasColumnType("text"); + + b.Property("CounterValue") + .HasColumnType("double precision"); + + b.HasKey("Key", "Date", "Category", "CounterKey"); + + b.ToTable("Counter", (string)null); + }); + + modelBuilder.Entity("Squidex.Messaging.EntityFramework.EFMessage", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("ChannelName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("MessageData") + .IsRequired() + .HasColumnType("bytea"); + + b.Property("MessageHeaders") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("character varying(2000)"); + + b.Property("QueueName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("TimeHandled") + .HasColumnType("timestamp with time zone"); + + b.Property("TimeToLive") + .HasColumnType("timestamp with time zone"); + + b.Property("Version") + .IsConcurrencyToken() + .HasColumnType("uuid"); + + b.HasKey("Id"); + + b.HasIndex("ChannelName", "TimeHandled"); + + b.ToTable("Messages", (string)null); + }); + + modelBuilder.Entity("Squidex.Messaging.EntityFramework.EFMessagingDataEntity", b => + { + b.Property("Group") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("Key") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("Expiration") + .HasColumnType("timestamp with time zone"); + + b.Property("ValueData") + .IsRequired() + .HasColumnType("bytea"); + + b.Property("ValueFormat") + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("ValueType") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.HasKey("Group", "Key"); + + b.HasIndex("Expiration"); + + b.ToTable("MessagingData", (string)null); + }); + + modelBuilder.Entity("YDotNet.Server.EntityFramework.YDotNetDocument", b => + { + b.Property("Id") + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("Data") + .IsRequired() + .HasColumnType("bytea"); + + b.Property("Expiration") + .HasColumnType("timestamp with time zone"); + + b.HasKey("Id"); + + b.ToTable("YDotNetDocument", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreToken", b => + { + b.HasOne("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreAuthorization", "Authorization") + .WithMany("Tokens") + .HasForeignKey("AuthorizationId"); + + b.Navigation("Authorization"); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreAuthorization", b => + { + b.Navigation("Tokens"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/backend/src/Squidex.Data.EntityFramework/Providers/Postgres/App/Migrations/20260117183420_AddUserInfoIndex.cs b/backend/src/Squidex.Data.EntityFramework/Providers/Postgres/App/Migrations/20260117183420_AddUserInfoIndex.cs new file mode 100644 index 000000000..763c6fee1 --- /dev/null +++ b/backend/src/Squidex.Data.EntityFramework/Providers/Postgres/App/Migrations/20260117183420_AddUserInfoIndex.cs @@ -0,0 +1,45 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Squidex.Providers.Postgres.App.Migrations +{ + /// + public partial class AddUserInfoIndex : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "UserInfos", + columns: table => new + { + Id = table.Column(type: "character varying(400)", maxLength: 400, nullable: false), + AppId = table.Column(type: "character varying(255)", maxLength: 255, nullable: false), + SchemaId = table.Column(type: "character varying(255)", maxLength: 255, nullable: false), + ContentId = table.Column(type: "character varying(255)", maxLength: 255, nullable: false), + Stage = table.Column(type: "smallint", nullable: false), + ServeAll = table.Column(type: "boolean", nullable: false), + ServePublished = table.Column(type: "boolean", nullable: false), + UserInfoApiKey = table.Column(type: "character varying(256)", maxLength: 256, nullable: false), + UserInfoRole = table.Column(type: "character varying(256)", maxLength: 256, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_UserInfos", x => x.Id); + }); + + migrationBuilder.CreateIndex( + name: "IX_UserInfos_UserInfoApiKey", + table: "UserInfos", + column: "UserInfoApiKey"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "UserInfos"); + } + } +} diff --git a/backend/src/Squidex.Data.EntityFramework/Providers/Postgres/App/Migrations/PostgresDbContextModelSnapshot.cs b/backend/src/Squidex.Data.EntityFramework/Providers/Postgres/App/Migrations/PostgresDbContextModelSnapshot.cs index ee2599db2..73fe5610f 100644 --- a/backend/src/Squidex.Data.EntityFramework/Providers/Postgres/App/Migrations/PostgresDbContextModelSnapshot.cs +++ b/backend/src/Squidex.Data.EntityFramework/Providers/Postgres/App/Migrations/PostgresDbContextModelSnapshot.cs @@ -18,7 +18,7 @@ namespace Squidex.Providers.Postgres.Migrations { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "8.0.14") + .HasAnnotation("ProductVersion", "8.0.16") .HasAnnotation("Relational:MaxIdentifierLength", 63); NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "postgis"); @@ -846,7 +846,7 @@ namespace Squidex.Providers.Postgres.Migrations b.HasKey("Id"); - b.ToTable("Geos", (string)null); + b.ToTable("Geos"); }); modelBuilder.Entity("Squidex.Domain.Apps.Entities.Contents.Text.EFTextIndexTextEntity", b => @@ -885,7 +885,54 @@ namespace Squidex.Providers.Postgres.Migrations b.HasKey("Id"); - b.ToTable("Texts", (string)null); + b.ToTable("Texts"); + }); + + modelBuilder.Entity("Squidex.Domain.Apps.Entities.Contents.Text.EFTextIndexUserInfoEntity", b => + { + b.Property("Id") + .HasMaxLength(400) + .HasColumnType("character varying(400)"); + + b.Property("AppId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("ContentId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("SchemaId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("character varying(255)"); + + b.Property("ServeAll") + .HasColumnType("boolean"); + + b.Property("ServePublished") + .HasColumnType("boolean"); + + b.Property("Stage") + .HasColumnType("smallint"); + + b.Property("UserInfoApiKey") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.Property("UserInfoRole") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("character varying(256)"); + + b.HasKey("Id"); + + b.HasIndex("UserInfoApiKey"); + + b.ToTable("UserInfos"); }); modelBuilder.Entity("Squidex.Domain.Apps.Entities.Contents.Text.State.TextContentState", b => @@ -1047,7 +1094,6 @@ namespace Squidex.Providers.Postgres.Migrations modelBuilder.Entity("Squidex.Events.EntityFramework.EFEventCommit", b => { b.Property("Id") - .ValueGeneratedOnAdd() .HasColumnType("uuid"); b.Property("EventStream") @@ -1119,7 +1165,6 @@ namespace Squidex.Providers.Postgres.Migrations modelBuilder.Entity("Squidex.Flows.EntityFramework.EFFlowStateEntity", b => { b.Property("Id") - .ValueGeneratedOnAdd() .HasColumnType("uuid"); b.Property("Created") diff --git a/backend/src/Squidex.Data.EntityFramework/Providers/SqlServer/App/Migrations/20260117183427_AddUserInfoIndex.Designer.cs b/backend/src/Squidex.Data.EntityFramework/Providers/SqlServer/App/Migrations/20260117183427_AddUserInfoIndex.Designer.cs new file mode 100644 index 000000000..20abc3bfd --- /dev/null +++ b/backend/src/Squidex.Data.EntityFramework/Providers/SqlServer/App/Migrations/20260117183427_AddUserInfoIndex.Designer.cs @@ -0,0 +1,1632 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using NetTopologySuite.Geometries; +using Squidex.Providers.SqlServer.App; + +#nullable disable + +namespace Squidex.Providers.SqlServer.App.Migrations +{ + [DbContext(typeof(SqlServerAppDbContext))] + [Migration("20260117183427_AddUserInfoIndex")] + partial class AddUserInfoIndex + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.16") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Name") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedName") + .IsUnique() + .HasDatabaseName("RoleNameIndex") + .HasFilter("[NormalizedName] IS NOT NULL"); + + b.ToTable("AspNetRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("RoleId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetRoleClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("AccessFailedCount") + .HasColumnType("int"); + + b.Property("ConcurrencyStamp") + .IsConcurrencyToken() + .HasColumnType("nvarchar(max)"); + + b.Property("Email") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("EmailConfirmed") + .HasColumnType("bit"); + + b.Property("LockoutEnabled") + .HasColumnType("bit"); + + b.Property("LockoutEnd") + .HasColumnType("datetimeoffset"); + + b.Property("NormalizedEmail") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("NormalizedUserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("PasswordHash") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumber") + .HasColumnType("nvarchar(max)"); + + b.Property("PhoneNumberConfirmed") + .HasColumnType("bit"); + + b.Property("SecurityStamp") + .HasColumnType("nvarchar(max)"); + + b.Property("TwoFactorEnabled") + .HasColumnType("bit"); + + b.Property("UserName") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("NormalizedEmail") + .HasDatabaseName("EmailIndex"); + + b.HasIndex("NormalizedUserName") + .IsUnique() + .HasDatabaseName("UserNameIndex") + .HasFilter("[NormalizedUserName] IS NOT NULL"); + + b.ToTable("AspNetUsers", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("ClaimType") + .HasColumnType("nvarchar(max)"); + + b.Property("ClaimValue") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("Id"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserClaims", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.Property("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property("ProviderKey") + .HasColumnType("nvarchar(450)"); + + b.Property("ProviderDisplayName") + .HasColumnType("nvarchar(max)"); + + b.Property("UserId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.HasKey("LoginProvider", "ProviderKey"); + + b.HasIndex("UserId"); + + b.ToTable("AspNetUserLogins", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("RoleId") + .HasColumnType("nvarchar(450)"); + + b.HasKey("UserId", "RoleId"); + + b.HasIndex("RoleId"); + + b.ToTable("AspNetUserRoles", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.Property("UserId") + .HasColumnType("nvarchar(450)"); + + b.Property("LoginProvider") + .HasColumnType("nvarchar(450)"); + + b.Property("Name") + .HasColumnType("nvarchar(450)"); + + b.Property("Value") + .HasColumnType("nvarchar(max)"); + + b.HasKey("UserId", "LoginProvider", "Name"); + + b.ToTable("AspNetUserTokens", (string)null); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreAuthorization", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("nvarchar(450)"); + + b.Property("ApplicationId") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("ConcurrencyToken") + .IsConcurrencyToken() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("Properties") + .HasColumnType("nvarchar(max)"); + + b.Property("Scopes") + .HasColumnType("nvarchar(max)"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Subject") + .HasMaxLength(400) + .HasColumnType("nvarchar(400)"); + + b.Property("Type") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("ApplicationId", "Status", "Subject", "Type"); + + b.ToTable("OpenIddictAuthorizations", (string)null); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreToken", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("nvarchar(450)"); + + b.Property("ApplicationId") + .HasColumnType("nvarchar(450)"); + + b.Property("AuthorizationId") + .HasColumnType("nvarchar(450)"); + + b.Property("ConcurrencyToken") + .IsConcurrencyToken() + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("CreationDate") + .HasColumnType("datetime2"); + + b.Property("ExpirationDate") + .HasColumnType("datetime2"); + + b.Property("Payload") + .HasColumnType("nvarchar(max)"); + + b.Property("Properties") + .HasColumnType("nvarchar(max)"); + + b.Property("RedemptionDate") + .HasColumnType("datetime2"); + + b.Property("ReferenceId") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("Status") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.Property("Subject") + .HasMaxLength(400) + .HasColumnType("nvarchar(400)"); + + b.Property("Type") + .HasMaxLength(50) + .HasColumnType("nvarchar(50)"); + + b.HasKey("Id"); + + b.HasIndex("AuthorizationId"); + + b.HasIndex("ReferenceId") + .IsUnique() + .HasFilter("[ReferenceId] IS NOT NULL"); + + b.HasIndex("ApplicationId", "Status", "Subject", "Type"); + + b.ToTable("OpenIddictTokens", (string)null); + }); + + modelBuilder.Entity("Squidex.AI.Mongo.EFChatEntity", b => + { + b.Property("Id") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("LastUpdated") + .HasColumnType("datetime2"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Version") + .IsConcurrencyToken() + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("LastUpdated"); + + b.ToTable("Chats", (string)null); + }); + + modelBuilder.Entity("Squidex.Assets.EntityFramework.EFAssetKeyValueEntity", b => + { + b.Property("Key") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Expires") + .HasColumnType("datetimeoffset"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Key"); + + b.HasIndex("Expires"); + + b.ToTable("AssetKeyValueStore_TusMetadata", (string)null); + }); + + modelBuilder.Entity("Squidex.Domain.Apps.Entities.Apps.EFAppEntity", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Document") + .HasColumnType("nvarchar(max)"); + + b.Property("IndexedCreated") + .HasColumnType("datetimeoffset") + .HasColumnName("Created"); + + b.Property("IndexedDeleted") + .HasColumnType("bit") + .HasColumnName("Deleted"); + + b.Property("IndexedName") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("Name"); + + b.Property("IndexedTeamId") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)") + .HasColumnName("TeamId"); + + b.Property("IndexedUserIds") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("UserIds"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.ToTable("States_App", (string)null); + }); + + modelBuilder.Entity("Squidex.Domain.Apps.Entities.Assets.EFAssetEntity", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("AppId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("CreatedBy") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("FileHash") + .HasColumnType("nvarchar(max)"); + + b.Property("FileName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("FileSize") + .HasColumnType("bigint"); + + b.Property("FileVersion") + .HasColumnType("bigint"); + + b.Property("Id") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("IndexedAppId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("IsProtected") + .HasColumnType("bit"); + + b.Property("LastModified") + .HasColumnType("datetimeoffset"); + + b.Property("LastModifiedBy") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("Metadata") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("MimeType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ParentId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Slug") + .HasColumnType("nvarchar(max)"); + + b.Property("Tags") + .IsRequired() + .HasMaxLength(1000) + .HasColumnType("nvarchar(1000)"); + + b.Property("TotalSize") + .HasColumnType("bigint"); + + b.Property("Type") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.HasIndex("IndexedAppId", "Id"); + + b.ToTable("Assets"); + }); + + modelBuilder.Entity("Squidex.Domain.Apps.Entities.Assets.EFAssetFolderEntity", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("AppId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("CreatedBy") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("FolderName") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Id") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("IndexedAppId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("LastModified") + .HasColumnType("datetimeoffset"); + + b.Property("LastModifiedBy") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("ParentId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.HasIndex("IndexedAppId", "Id"); + + b.ToTable("AssetFolders"); + }); + + modelBuilder.Entity("Squidex.Domain.Apps.Entities.Contents.EFContentCompleteEntity", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("AppId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("CreatedBy") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("Data") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Id") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("IndexedAppId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("IndexedSchemaId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("LastModified") + .HasColumnType("datetimeoffset"); + + b.Property("LastModifiedBy") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("NewData") + .HasColumnType("nvarchar(max)"); + + b.Property("NewStatus") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("ScheduleJob") + .HasColumnType("nvarchar(max)"); + + b.Property("ScheduledAt") + .HasColumnType("datetimeoffset"); + + b.Property("SchemaId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("TranslationStatus") + .HasColumnType("nvarchar(max)"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.ToTable("ContentsAll", (string)null); + }); + + modelBuilder.Entity("Squidex.Domain.Apps.Entities.Contents.EFContentPublishedEntity", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("AppId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("CreatedBy") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("Data") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Id") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("IndexedAppId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("IndexedSchemaId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("IsDeleted") + .HasColumnType("bit"); + + b.Property("LastModified") + .HasColumnType("datetimeoffset"); + + b.Property("LastModifiedBy") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("NewData") + .HasColumnType("nvarchar(max)"); + + b.Property("NewStatus") + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("ScheduleJob") + .HasColumnType("nvarchar(max)"); + + b.Property("ScheduledAt") + .HasColumnType("datetimeoffset"); + + b.Property("SchemaId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Status") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("TranslationStatus") + .HasColumnType("nvarchar(max)"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.ToTable("ContentsPublished", (string)null); + }); + + modelBuilder.Entity("Squidex.Domain.Apps.Entities.Contents.EFContentTableEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("AppId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("SchemaId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.HasKey("Id"); + + b.HasIndex("AppId", "SchemaId") + .IsUnique(); + + b.ToTable("ContentTables", (string)null); + }); + + modelBuilder.Entity("Squidex.Domain.Apps.Entities.Contents.EFReferenceCompleteEntity", b => + { + b.Property("AppId") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("FromKey") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("ToId") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("FromSchema") + .IsRequired() + .ValueGeneratedOnAdd() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)") + .HasDefaultValue("00000000-0000-0000-0000-000000000000"); + + b.HasKey("AppId", "FromKey", "ToId"); + + b.ToTable("ContentReferencesAll", (string)null); + }); + + modelBuilder.Entity("Squidex.Domain.Apps.Entities.Contents.EFReferencePublishedEntity", b => + { + b.Property("AppId") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("FromKey") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("ToId") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("FromSchema") + .IsRequired() + .ValueGeneratedOnAdd() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)") + .HasDefaultValue("00000000-0000-0000-0000-000000000000"); + + b.HasKey("AppId", "FromKey", "ToId"); + + b.ToTable("ContentReferencesPublished", (string)null); + }); + + modelBuilder.Entity("Squidex.Domain.Apps.Entities.Contents.Text.EFTextIndexGeoEntity", b => + { + b.Property("Id") + .HasMaxLength(400) + .HasColumnType("nvarchar(400)"); + + b.Property("AppId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("ContentId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("GeoField") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("GeoObject") + .IsRequired() + .HasColumnType("geography"); + + b.Property("SchemaId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("ServeAll") + .HasColumnType("bit"); + + b.Property("ServePublished") + .HasColumnType("bit"); + + b.Property("Stage") + .HasColumnType("tinyint"); + + b.HasKey("Id"); + + b.ToTable("Geos"); + }); + + modelBuilder.Entity("Squidex.Domain.Apps.Entities.Contents.Text.EFTextIndexTextEntity", b => + { + b.Property("Id") + .HasMaxLength(400) + .HasColumnType("nvarchar(400)"); + + b.Property("AppId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("ContentId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("SchemaId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("ServeAll") + .HasColumnType("bit"); + + b.Property("ServePublished") + .HasColumnType("bit"); + + b.Property("Stage") + .HasColumnType("tinyint"); + + b.Property("Texts") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.ToTable("Texts"); + }); + + modelBuilder.Entity("Squidex.Domain.Apps.Entities.Contents.Text.EFTextIndexUserInfoEntity", b => + { + b.Property("Id") + .HasMaxLength(400) + .HasColumnType("nvarchar(400)"); + + b.Property("AppId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("ContentId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("SchemaId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("ServeAll") + .HasColumnType("bit"); + + b.Property("ServePublished") + .HasColumnType("bit"); + + b.Property("Stage") + .HasColumnType("tinyint"); + + b.Property("UserInfoApiKey") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("UserInfoRole") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("UserInfoApiKey"); + + b.ToTable("UserInfos"); + }); + + modelBuilder.Entity("Squidex.Domain.Apps.Entities.Contents.Text.State.TextContentState", b => + { + b.Property("UniqueContentId") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("State") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.HasKey("UniqueContentId"); + + b.ToTable("TextState", (string)null); + }); + + modelBuilder.Entity("Squidex.Domain.Apps.Entities.History.HistoryEvent", b => + { + b.Property("Id") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Actor") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("nvarchar(100)"); + + b.Property("Channel") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("EventType") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("OwnerId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Parameters") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("HistoryEvent"); + }); + + modelBuilder.Entity("Squidex.Domain.Apps.Entities.Rules.EFRuleEntity", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Document") + .HasColumnType("nvarchar(max)"); + + b.Property("IndexedAppId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)") + .HasColumnName("AppId"); + + b.Property("IndexedDeleted") + .HasColumnType("bit") + .HasColumnName("Deleted"); + + b.Property("IndexedId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)") + .HasColumnName("Id"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.ToTable("States_Rule", (string)null); + }); + + modelBuilder.Entity("Squidex.Domain.Apps.Entities.Schemas.EFSchemaEntity", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Document") + .HasColumnType("nvarchar(max)"); + + b.Property("IndexedAppId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)") + .HasColumnName("AppId"); + + b.Property("IndexedDeleted") + .HasColumnType("bit") + .HasColumnName("Deleted"); + + b.Property("IndexedId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)") + .HasColumnName("Id"); + + b.Property("IndexedName") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("Name"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.ToTable("States_Schema", (string)null); + }); + + modelBuilder.Entity("Squidex.Domain.Apps.Entities.Teams.EFTeamEntity", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Document") + .HasColumnType("nvarchar(max)"); + + b.Property("IndexedAuthDomain") + .HasColumnType("nvarchar(max)") + .HasColumnName("AuthDomain"); + + b.Property("IndexedDeleted") + .HasColumnType("bit") + .HasColumnName("Deleted"); + + b.Property("IndexedUserIds") + .IsRequired() + .HasColumnType("nvarchar(max)") + .HasColumnName("UserIds"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.ToTable("States_Team", (string)null); + }); + + modelBuilder.Entity("Squidex.Events.EntityFramework.EFEventCommit", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("EventStream") + .IsRequired() + .HasMaxLength(750) + .HasColumnType("nvarchar(750)"); + + b.Property("EventStreamOffset") + .HasColumnType("bigint"); + + b.Property("Events") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("EventsCount") + .HasColumnType("bigint"); + + b.Property("Position") + .HasColumnType("bigint"); + + b.Property("Timestamp") + .HasColumnType("datetime2"); + + b.HasKey("Id"); + + b.HasIndex("EventStream", "EventStreamOffset") + .IsUnique(); + + b.HasIndex("EventStream", "Position"); + + b.HasIndex("EventStream", "Timestamp"); + + b.ToTable("Events"); + }); + + modelBuilder.Entity("Squidex.Events.EntityFramework.EFPosition", b => + { + b.Property("Id") + .HasColumnType("bigint"); + + b.Property("Position") + .HasColumnType("bigint"); + + b.HasKey("Id"); + + b.ToTable("EventPosition"); + }); + + modelBuilder.Entity("Squidex.Flows.EntityFramework.EFCronJobEntity", b => + { + b.Property("Id") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Data") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("DueTime") + .HasColumnType("datetimeoffset"); + + b.HasKey("Id"); + + b.HasIndex("DueTime"); + + b.ToTable("CronJobs", (string)null); + }); + + modelBuilder.Entity("Squidex.Flows.EntityFramework.EFFlowStateEntity", b => + { + b.Property("Id") + .HasColumnType("uniqueidentifier"); + + b.Property("Created") + .HasColumnType("datetimeoffset"); + + b.Property("DefinitionId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("DueTime") + .HasColumnType("datetimeoffset"); + + b.Property("OwnerId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("SchedulePartition") + .HasColumnType("int"); + + b.Property("State") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Id"); + + b.HasIndex("DueTime", "SchedulePartition"); + + b.ToTable("Flows", (string)null); + }); + + modelBuilder.Entity("Squidex.Infrastructure.Caching.EFCacheEntity", b => + { + b.Property("Key") + .HasColumnType("nvarchar(450)"); + + b.Property("Expires") + .HasColumnType("datetime2"); + + b.Property("Value") + .IsRequired() + .HasColumnType("varbinary(max)"); + + b.HasKey("Key"); + + b.ToTable("Cache", (string)null); + }); + + modelBuilder.Entity("Squidex.Infrastructure.Log.EFRequestEntity", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id")); + + b.Property("Key") + .IsRequired() + .HasColumnType("nvarchar(450)"); + + b.Property("Properties") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Timestamp") + .HasColumnType("datetimeoffset"); + + b.HasKey("Id"); + + b.HasIndex("Key"); + + b.ToTable("Requests", (string)null); + }); + + modelBuilder.Entity("Squidex.Infrastructure.Migrations.EFMigrationEntity", b => + { + b.Property("Id") + .HasColumnType("int"); + + b.Property("IsLocked") + .HasColumnType("bit"); + + b.Property("Version") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.ToTable("Migrations", (string)null); + }); + + modelBuilder.Entity("Squidex.Infrastructure.States.EFState", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Document") + .HasColumnType("nvarchar(max)"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.ToTable("States_UISettings", (string)null); + }); + + modelBuilder.Entity("Squidex.Infrastructure.States.EFState", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Document") + .HasColumnType("nvarchar(max)"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.ToTable("States_Index_TagHistory", (string)null); + }); + + modelBuilder.Entity("Squidex.Infrastructure.States.EFState", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Document") + .HasColumnType("nvarchar(max)"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.ToTable("States_UsageNotifications", (string)null); + }); + + modelBuilder.Entity("Squidex.Infrastructure.States.EFState", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Document") + .HasColumnType("nvarchar(max)"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.ToTable("States_Counters", (string)null); + }); + + modelBuilder.Entity("Squidex.Infrastructure.States.EFState", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Document") + .HasColumnType("nvarchar(max)"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.ToTable("States_JobsState", (string)null); + }); + + modelBuilder.Entity("Squidex.Infrastructure.States.EFState", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Document") + .HasColumnType("nvarchar(max)"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.ToTable("States_UsageTracker", (string)null); + }); + + modelBuilder.Entity("Squidex.Infrastructure.States.EFState", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Document") + .HasColumnType("nvarchar(max)"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.ToTable("States_Index_Tags", (string)null); + }); + + modelBuilder.Entity("Squidex.Infrastructure.States.EFState", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Document") + .HasColumnType("nvarchar(max)"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.ToTable("States_Identity_Keys", (string)null); + }); + + modelBuilder.Entity("Squidex.Infrastructure.States.EFState", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Document") + .HasColumnType("nvarchar(max)"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.ToTable("States_Identity_Xml", (string)null); + }); + + modelBuilder.Entity("Squidex.Infrastructure.States.EFState", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Document") + .HasColumnType("nvarchar(max)"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.ToTable("States_EventConsumerState", (string)null); + }); + + modelBuilder.Entity("Squidex.Infrastructure.States.EFState", b => + { + b.Property("DocumentId") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Document") + .HasColumnType("nvarchar(max)"); + + b.Property("Version") + .HasColumnType("bigint"); + + b.HasKey("DocumentId"); + + b.ToTable("States_Names", (string)null); + }); + + modelBuilder.Entity("Squidex.Infrastructure.UsageTracking.EFUsageCounterEntity", b => + { + b.Property("Key") + .HasColumnType("nvarchar(450)"); + + b.Property("Date") + .HasColumnType("datetime2"); + + b.Property("Category") + .HasColumnType("nvarchar(450)"); + + b.Property("CounterKey") + .HasColumnType("nvarchar(450)"); + + b.Property("CounterValue") + .HasColumnType("float"); + + b.HasKey("Key", "Date", "Category", "CounterKey"); + + b.ToTable("Counter", (string)null); + }); + + modelBuilder.Entity("Squidex.Messaging.EntityFramework.EFMessage", b => + { + b.Property("Id") + .HasColumnType("nvarchar(450)"); + + b.Property("ChannelName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("MessageData") + .IsRequired() + .HasColumnType("varbinary(max)"); + + b.Property("MessageHeaders") + .IsRequired() + .HasMaxLength(2000) + .HasColumnType("nvarchar(2000)"); + + b.Property("QueueName") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("TimeHandled") + .HasColumnType("datetime2"); + + b.Property("TimeToLive") + .HasColumnType("datetime2"); + + b.Property("Version") + .IsConcurrencyToken() + .HasColumnType("uniqueidentifier"); + + b.HasKey("Id"); + + b.HasIndex("ChannelName", "TimeHandled"); + + b.ToTable("Messages", (string)null); + }); + + modelBuilder.Entity("Squidex.Messaging.EntityFramework.EFMessagingDataEntity", b => + { + b.Property("Group") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Key") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("Expiration") + .HasColumnType("datetime2"); + + b.Property("ValueData") + .IsRequired() + .HasColumnType("varbinary(max)"); + + b.Property("ValueFormat") + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("ValueType") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.HasKey("Group", "Key"); + + b.HasIndex("Expiration"); + + b.ToTable("MessagingData", (string)null); + }); + + modelBuilder.Entity("YDotNet.Server.EntityFramework.YDotNetDocument", b => + { + b.Property("Id") + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("Data") + .IsRequired() + .HasColumnType("varbinary(max)"); + + b.Property("Expiration") + .HasColumnType("datetime2"); + + b.HasKey("Id"); + + b.ToTable("YDotNetDocument", (string)null); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) + .WithMany() + .HasForeignKey("RoleId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => + { + b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreToken", b => + { + b.HasOne("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreAuthorization", "Authorization") + .WithMany("Tokens") + .HasForeignKey("AuthorizationId"); + + b.Navigation("Authorization"); + }); + + modelBuilder.Entity("OpenIddict.EntityFrameworkCore.Models.OpenIddictEntityFrameworkCoreAuthorization", b => + { + b.Navigation("Tokens"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/backend/src/Squidex.Data.EntityFramework/Providers/SqlServer/App/Migrations/20260117183427_AddUserInfoIndex.cs b/backend/src/Squidex.Data.EntityFramework/Providers/SqlServer/App/Migrations/20260117183427_AddUserInfoIndex.cs new file mode 100644 index 000000000..8e30c07bf --- /dev/null +++ b/backend/src/Squidex.Data.EntityFramework/Providers/SqlServer/App/Migrations/20260117183427_AddUserInfoIndex.cs @@ -0,0 +1,45 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Squidex.Providers.SqlServer.App.Migrations +{ + /// + public partial class AddUserInfoIndex : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "UserInfos", + columns: table => new + { + Id = table.Column(type: "nvarchar(400)", maxLength: 400, nullable: false), + AppId = table.Column(type: "nvarchar(255)", maxLength: 255, nullable: false), + SchemaId = table.Column(type: "nvarchar(255)", maxLength: 255, nullable: false), + ContentId = table.Column(type: "nvarchar(255)", maxLength: 255, nullable: false), + Stage = table.Column(type: "tinyint", nullable: false), + ServeAll = table.Column(type: "bit", nullable: false), + ServePublished = table.Column(type: "bit", nullable: false), + UserInfoApiKey = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false), + UserInfoRole = table.Column(type: "nvarchar(256)", maxLength: 256, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_UserInfos", x => x.Id); + }); + + migrationBuilder.CreateIndex( + name: "IX_UserInfos_UserInfoApiKey", + table: "UserInfos", + column: "UserInfoApiKey"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "UserInfos"); + } + } +} diff --git a/backend/src/Squidex.Data.EntityFramework/Providers/SqlServer/App/Migrations/SqlServerDbContextModelSnapshot.cs b/backend/src/Squidex.Data.EntityFramework/Providers/SqlServer/App/Migrations/SqlServerDbContextModelSnapshot.cs index 7fd48ad17..abcb6f693 100644 --- a/backend/src/Squidex.Data.EntityFramework/Providers/SqlServer/App/Migrations/SqlServerDbContextModelSnapshot.cs +++ b/backend/src/Squidex.Data.EntityFramework/Providers/SqlServer/App/Migrations/SqlServerDbContextModelSnapshot.cs @@ -18,7 +18,7 @@ namespace Squidex.Providers.SqlServer.Migrations { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "8.0.14") + .HasAnnotation("ProductVersion", "8.0.16") .HasAnnotation("Relational:MaxIdentifierLength", 128); SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); @@ -848,7 +848,7 @@ namespace Squidex.Providers.SqlServer.Migrations b.HasKey("Id"); - b.ToTable("Geos", (string)null); + b.ToTable("Geos"); }); modelBuilder.Entity("Squidex.Domain.Apps.Entities.Contents.Text.EFTextIndexTextEntity", b => @@ -887,7 +887,54 @@ namespace Squidex.Providers.SqlServer.Migrations b.HasKey("Id"); - b.ToTable("Texts", (string)null); + b.ToTable("Texts"); + }); + + modelBuilder.Entity("Squidex.Domain.Apps.Entities.Contents.Text.EFTextIndexUserInfoEntity", b => + { + b.Property("Id") + .HasMaxLength(400) + .HasColumnType("nvarchar(400)"); + + b.Property("AppId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("ContentId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("SchemaId") + .IsRequired() + .HasMaxLength(255) + .HasColumnType("nvarchar(255)"); + + b.Property("ServeAll") + .HasColumnType("bit"); + + b.Property("ServePublished") + .HasColumnType("bit"); + + b.Property("Stage") + .HasColumnType("tinyint"); + + b.Property("UserInfoApiKey") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.Property("UserInfoRole") + .IsRequired() + .HasMaxLength(256) + .HasColumnType("nvarchar(256)"); + + b.HasKey("Id"); + + b.HasIndex("UserInfoApiKey"); + + b.ToTable("UserInfos"); }); modelBuilder.Entity("Squidex.Domain.Apps.Entities.Contents.Text.State.TextContentState", b => @@ -1049,7 +1096,6 @@ namespace Squidex.Providers.SqlServer.Migrations modelBuilder.Entity("Squidex.Events.EntityFramework.EFEventCommit", b => { b.Property("Id") - .ValueGeneratedOnAdd() .HasColumnType("uniqueidentifier"); b.Property("EventStream") @@ -1121,7 +1167,6 @@ namespace Squidex.Providers.SqlServer.Migrations modelBuilder.Entity("Squidex.Flows.EntityFramework.EFFlowStateEntity", b => { b.Property("Id") - .ValueGeneratedOnAdd() .HasColumnType("uniqueidentifier"); b.Property("Created") diff --git a/backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/Contents/Text/CommandFactory.cs b/backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/Contents/Text/CommandFactory.cs index dcbe6d193..a2e083538 100644 --- a/backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/Contents/Text/CommandFactory.cs +++ b/backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/Contents/Text/CommandFactory.cs @@ -80,6 +80,37 @@ public sealed class CommandFactory(Func, T> textBu })); } } + + if (upsert.UserInfos?.Count > 0) + { + if (!upsert.IsNew) + { + writes.Add( + new DeleteManyModel>( + Filter.And( + FilterByCommand(upsert), + Filter.Exists(x => x.UserInfoApiKey), + Filter.Exists(x => x.UserInfoRole)))); + } + + foreach (var userInfo in upsert.UserInfos) + { + writes.Add( + new InsertOneModel>( + new MongoTextIndexEntity + { + Id = ObjectId.GenerateNewId(), + AppId = upsert.UniqueContentId.AppId, + ContentId = upsert.UniqueContentId.ContentId, + UserInfoApiKey = userInfo.ApiKey, + UserInfoRole = userInfo.Role, + SchemaId = upsert.SchemaId.Id, + ServeAll = upsert.ServeAll, + ServePublished = upsert.ServePublished, + Stage = upsert.Stage, + })); + } + } } private T? BuildTexts(UpsertIndexEntry upsert) diff --git a/backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/Contents/Text/DocumentDbTextIndex.cs b/backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/Contents/Text/DocumentDbTextIndex.cs index 03ac5f9ce..659419c4f 100644 --- a/backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/Contents/Text/DocumentDbTextIndex.cs +++ b/backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/Contents/Text/DocumentDbTextIndex.cs @@ -14,7 +14,8 @@ using Squidex.Infrastructure.ObjectPool; namespace Squidex.Domain.Apps.Entities.Contents.Text; public sealed class DocumentDbTextIndex(IMongoDatabase database, string shardKey) - : MongoTextIndexBase(database, shardKey, new CommandFactory(BuildTexts)) + : MongoTextIndexBase(database, shardKey, + new CommandFactory(BuildTexts)) { private record struct SearchOperation { diff --git a/backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/Contents/Text/MongoShardedTextIndex.cs b/backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/Contents/Text/MongoShardedTextIndex.cs index b456a8636..7e34abc8d 100644 --- a/backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/Contents/Text/MongoShardedTextIndex.cs +++ b/backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/Contents/Text/MongoShardedTextIndex.cs @@ -12,7 +12,8 @@ using Squidex.Infrastructure.States; namespace Squidex.Domain.Apps.Entities.Contents.Text; -public sealed class MongoShardedTextIndex(IShardingStrategy sharding, Func> factory) : ShardedService>(sharding, factory), ITextIndex, IDeleter where T : class +public sealed class MongoShardedTextIndex(IShardingStrategy sharding, Func> factory) + : ShardedService>(sharding, factory), ITextIndex, IDeleter where T : class { public async Task ClearAsync( CancellationToken ct = default) @@ -45,6 +46,12 @@ public sealed class MongoShardedTextIndex(IShardingStrategy sharding, Func FindUserInfo(App app, ApiKeyQuery query, SearchScope scope, + CancellationToken ct = default) + { + return Shard(app.Id).FindUserInfo(app, query, scope, ct); + } + async Task IDeleter.DeleteAppAsync(App app, CancellationToken ct) { diff --git a/backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/Contents/Text/MongoTextIndex.cs b/backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/Contents/Text/MongoTextIndex.cs index d64ec1dff..20cb93460 100644 --- a/backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/Contents/Text/MongoTextIndex.cs +++ b/backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/Contents/Text/MongoTextIndex.cs @@ -11,8 +11,9 @@ using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Contents.Text; -public sealed class MongoTextIndex(IMongoDatabase database, string shardKey) - : MongoTextIndexBase>(database, shardKey, new CommandFactory>(BuildTexts)) +public sealed class MongoTextIndex(IMongoDatabase database, string shardKey) + : MongoTextIndexBase>(database, shardKey, + new CommandFactory>(BuildTexts)) { private record struct SearchOperation { diff --git a/backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/Contents/Text/MongoTextIndexBase.cs b/backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/Contents/Text/MongoTextIndexBase.cs index f4ab89dfd..165b568a7 100644 --- a/backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/Contents/Text/MongoTextIndexBase.cs +++ b/backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/Contents/Text/MongoTextIndexBase.cs @@ -14,7 +14,8 @@ using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Contents.Text; -public abstract class MongoTextIndexBase(IMongoDatabase database, string shardKey, CommandFactory factory) : MongoRepositoryBase>(database), ITextIndex, IDeleter where T : class +public abstract class MongoTextIndexBase(IMongoDatabase database, string shardKey, CommandFactory factory) + : MongoRepositoryBase>(database), ITextIndex, IDeleter where T : class { protected sealed class MongoTextResult { @@ -31,6 +32,25 @@ public abstract class MongoTextIndexBase(IMongoDatabase database, string shar public double Score { get; set; } } + protected sealed class MongoApiKeyResult + { + [BsonId] + [BsonElement] + public ObjectId Id { get; set; } + + [BsonRequired] + [BsonElement("c")] + public DomainId ContentId { get; set; } + + [BsonIgnoreIfNull] + [BsonElement("k")] + public string UserInfoApiKey { get; set; } + + [BsonIgnoreIfNull] + [BsonElement("r")] + public string UserInfoRole { get; set; } + } + protected override async Task SetupCollectionAsync(IMongoCollection> collection, CancellationToken ct) { @@ -54,6 +74,11 @@ public abstract class MongoTextIndexBase(IMongoDatabase database, string shar new CreateIndexModel>( Index .Geo2DSphere(x => x.GeoObject)), + + new CreateIndexModel>( + Index + .Geo2DSphere(x => x.UserInfoApiKey), + new CreateIndexOptions { Sparse = true }), ], ct); } else @@ -123,6 +148,27 @@ public abstract class MongoTextIndexBase(IMongoDatabase database, string shar } } + public async Task FindUserInfo(App app, ApiKeyQuery query, SearchScope scope, + CancellationToken ct = default) + { + Guard.NotNull(app); + Guard.NotNull(query); + + // Use the filter in the correct order to leverage the index in the best way. + var findFilter = + Filter.And( + Filter.Eq(x => x.AppId, app.Id), + Filter.Eq(x => x.UserInfoApiKey, query.ApiKey), + FilterByScope(scope)); + + var byApiKey = + await GetCollection(scope).Find(findFilter).Limit(1) + .Project(Projection.Include(x => x.ContentId).Include(x => x.UserInfoRole)) + .FirstOrDefaultAsync(ct); + + return byApiKey != null ? new UserInfoResult(byApiKey.ContentId, byApiKey.UserInfoRole) : null; + } + public virtual async Task?> SearchAsync(App app, GeoQuery query, SearchScope scope, CancellationToken ct = default) { diff --git a/backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/Contents/Text/MongoTextIndexEntity.cs b/backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/Contents/Text/MongoTextIndexEntity.cs index 2012c92e0..ddc4e0c7c 100644 --- a/backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/Contents/Text/MongoTextIndexEntity.cs +++ b/backend/src/Squidex.Data.MongoDb/Domain/Apps/Entities/Contents/Text/MongoTextIndexEntity.cs @@ -8,6 +8,7 @@ using MongoDB.Bson; using MongoDB.Bson.Serialization.Attributes; using NetTopologySuite.Geometries; +using Squidex.Domain.Apps.Core.Contents; using Squidex.Infrastructure; namespace Squidex.Domain.Apps.Entities.Contents.Text; @@ -49,6 +50,14 @@ public sealed class MongoTextIndexEntity [BsonElement("t")] public T Texts { get; set; } + [BsonIgnoreIfNull] + [BsonElement("k")] + public string? UserInfoApiKey { get; set; } + + [BsonIgnoreIfNull] + [BsonElement("r")] + public string? UserInfoRole { get; set; } + [BsonIgnoreIfNull] [BsonElement("g")] public string GeoField { get; set; } diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Contents/Component.cs b/backend/src/Squidex.Domain.Apps.Core.Model/Contents/Component.cs index f3abb5e6b..5f186da15 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Model/Contents/Component.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Model/Contents/Component.cs @@ -53,7 +53,6 @@ public sealed record Component(string Type, JsonObject Data, Schema Schema) } discriminator = s; - return true; } } diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Contents/GeoJsonValue.cs b/backend/src/Squidex.Domain.Apps.Core.Model/Contents/GeoJsonValue.cs index 5345d3eef..3cc377a34 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Model/Contents/GeoJsonValue.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Model/Contents/GeoJsonValue.cs @@ -41,7 +41,6 @@ public static class GeoJsonValue } geoJSON = new Point(new Coordinate(lon, lat)); - return GeoJsonParseResult.Success; } diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Contents/UserInfoParseResult.cs b/backend/src/Squidex.Domain.Apps.Core.Model/Contents/UserInfoParseResult.cs new file mode 100644 index 000000000..42d456c3c --- /dev/null +++ b/backend/src/Squidex.Domain.Apps.Core.Model/Contents/UserInfoParseResult.cs @@ -0,0 +1,16 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +namespace Squidex.Domain.Apps.Core.Contents; + +public enum UserInfoParseResult +{ + Success, + InvalidApiKey, + InvalidRole, + InvalidValue, +} diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Contents/UserInfoValue.cs b/backend/src/Squidex.Domain.Apps.Core.Model/Contents/UserInfoValue.cs new file mode 100644 index 000000000..fd3fe5609 --- /dev/null +++ b/backend/src/Squidex.Domain.Apps.Core.Model/Contents/UserInfoValue.cs @@ -0,0 +1,53 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using Squidex.Infrastructure; +using Squidex.Infrastructure.Json.Objects; + +#pragma warning disable SA1313 // Parameter names should begin with lower-case letter + +namespace Squidex.Domain.Apps.Core.Contents; + +public sealed record UserInfoValue(string ApiKey, string Role) +{ + public static JsonValue CreateDefault(string role) + { + var apiKey = + Guid.NewGuid().ToString().ToSha256Base64() + .Replace("+", string.Empty, StringComparison.Ordinal) + .Replace("/", string.Empty, StringComparison.Ordinal) + .TrimEnd('='); + + return JsonValue.Object().Add("apiKey", apiKey).Add("role", role); + } + + public static UserInfoParseResult TryParse(JsonValue value, out UserInfoValue? userInfo) + { + Guard.NotNull(value); + + userInfo = null; + + if (value.Value is JsonObject o) + { + if (!o.TryGetValue("apiKey", out var found) || found.Value is not string apiKey || string.IsNullOrWhiteSpace(apiKey)) + { + return UserInfoParseResult.InvalidApiKey; + } + + if (!o.TryGetValue("role", out found) || found.Value is not string role || string.IsNullOrWhiteSpace(role)) + { + return UserInfoParseResult.InvalidRole; + } + + userInfo = new UserInfoValue(apiKey, role); + + return UserInfoParseResult.Success; + } + + return UserInfoParseResult.InvalidValue; + } +} diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/FieldDescriptions.Designer.cs b/backend/src/Squidex.Domain.Apps.Core.Model/FieldDescriptions.Designer.cs index a5d3b8211..3a2ab86c4 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Model/FieldDescriptions.Designer.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Model/FieldDescriptions.Designer.cs @@ -1131,6 +1131,24 @@ namespace Squidex.Domain.Apps.Core { } } + /// + /// Looks up a localized string similar to The API key for authentication.. + /// + public static string UserInfoApiKey { + get { + return ResourceManager.GetString("UserInfoApiKey", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The user role.. + /// + public static string UserInfoRole { + get { + return ResourceManager.GetString("UserInfoRole", resourceCulture); + } + } + /// /// Looks up a localized string similar to True when this user is a client, which is typically the case when the request is made from the API.. /// diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/FieldDescriptions.resx b/backend/src/Squidex.Domain.Apps.Core.Model/FieldDescriptions.resx index 97c9d1af2..ccd701913 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Model/FieldDescriptions.resx +++ b/backend/src/Squidex.Domain.Apps.Core.Model/FieldDescriptions.resx @@ -483,4 +483,10 @@ The type of action that is performed. + + The API key for authentication. + + + The user role. + \ No newline at end of file diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/ArrayField.cs b/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/ArrayField.cs index 50c36f2b0..840140d60 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/ArrayField.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/ArrayField.cs @@ -45,7 +45,7 @@ public sealed record ArrayField : RootField, IArrayField } [Pure] - public ArrayField AddField(NestedField field) + public ArrayField AddUserInfo(NestedField field) { return Updatefields(f => f.Add(field)); } diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/Fields.cs b/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/Fields.cs index 48851f043..4810e5fb8 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/Fields.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/Fields.cs @@ -11,170 +11,452 @@ namespace Squidex.Domain.Apps.Core.Schemas; public static class Fields { - public static ArrayField Array(long id, string name, Partitioning partitioning, - ArrayFieldProperties? properties = null, params NestedField[] fields) + public static ArrayField Array( + long id, + string name, + Partitioning partitioning, + ArrayFieldProperties? properties = null, + params NestedField[] fields + ) + { + return new ArrayField + { + Id = id, + Name = name, + Partitioning = partitioning, + Properties = properties ?? new(), + FieldCollection = new FieldCollection(fields), + }; + } + + public static RootField Assets( + long id, + string name, + Partitioning partitioning, + AssetsFieldProperties? properties = null + ) + { + return new RootField + { + Id = id, + Name = name, + Partitioning = partitioning, + Properties = properties ?? new(), + }; + } + + public static RootField Boolean( + long id, + string name, + Partitioning partitioning, + BooleanFieldProperties? properties = null + ) { - return new ArrayField { Id = id, Name = name, Partitioning = partitioning, Properties = properties ?? new(), FieldCollection = new FieldCollection(fields) }; + return new RootField + { + Id = id, + Name = name, + Partitioning = partitioning, + Properties = properties ?? new(), + }; } - public static RootField Assets(long id, string name, Partitioning partitioning, - AssetsFieldProperties? properties = null) + public static RootField Component( + long id, + string name, + Partitioning partitioning, + ComponentFieldProperties? properties = null + ) { - return new RootField { Id = id, Name = name, Partitioning = partitioning, Properties = properties ?? new() }; + return new RootField + { + Id = id, + Name = name, + Partitioning = partitioning, + Properties = properties ?? new(), + }; } - public static RootField Boolean(long id, string name, Partitioning partitioning, - BooleanFieldProperties? properties = null) + public static RootField Components( + long id, + string name, + Partitioning partitioning, + ComponentsFieldProperties? properties = null + ) { - return new RootField { Id = id, Name = name, Partitioning = partitioning, Properties = properties ?? new() }; + return new RootField + { + Id = id, + Name = name, + Partitioning = partitioning, + Properties = properties ?? new(), + }; } - public static RootField Component(long id, string name, Partitioning partitioning, - ComponentFieldProperties? properties = null) + public static RootField DateTime( + long id, + string name, + Partitioning partitioning, + DateTimeFieldProperties? properties = null + ) { - return new RootField { Id = id, Name = name, Partitioning = partitioning, Properties = properties ?? new() }; + return new RootField + { + Id = id, + Name = name, + Partitioning = partitioning, + Properties = properties ?? new(), + }; } - public static RootField Components(long id, string name, Partitioning partitioning, - ComponentsFieldProperties? properties = null) + public static RootField Geolocation( + long id, + string name, + Partitioning partitioning, + GeolocationFieldProperties? properties = null + ) { - return new RootField { Id = id, Name = name, Partitioning = partitioning, Properties = properties ?? new() }; + return new RootField + { + Id = id, + Name = name, + Partitioning = partitioning, + Properties = properties ?? new(), + }; } - public static RootField DateTime(long id, string name, Partitioning partitioning, - DateTimeFieldProperties? properties = null) + public static RootField Json( + long id, + string name, + Partitioning partitioning, + JsonFieldProperties? properties = null + ) { - return new RootField { Id = id, Name = name, Partitioning = partitioning, Properties = properties ?? new() }; + return new RootField + { + Id = id, + Name = name, + Partitioning = partitioning, + Properties = properties ?? new(), + }; } - public static RootField Geolocation(long id, string name, Partitioning partitioning, - GeolocationFieldProperties? properties = null) + public static RootField Number( + long id, + string name, + Partitioning partitioning, + NumberFieldProperties? properties = null + ) { - return new RootField { Id = id, Name = name, Partitioning = partitioning, Properties = properties ?? new() }; + return new RootField + { + Id = id, + Name = name, + Partitioning = partitioning, + Properties = properties ?? new(), + }; } - public static RootField Json(long id, string name, Partitioning partitioning, - JsonFieldProperties? properties = null) + public static RootField References( + long id, + string name, + Partitioning partitioning, + ReferencesFieldProperties? properties = null + ) { - return new RootField { Id = id, Name = name, Partitioning = partitioning, Properties = properties ?? new() }; + return new RootField + { + Id = id, + Name = name, + Partitioning = partitioning, + Properties = properties ?? new(), + }; } - public static RootField Number(long id, string name, Partitioning partitioning, - NumberFieldProperties? properties = null) + public static RootField RichText( + long id, + string name, + Partitioning partitioning, + RichTextFieldProperties? properties = null + ) { - return new RootField { Id = id, Name = name, Partitioning = partitioning, Properties = properties ?? new() }; + return new RootField + { + Id = id, + Name = name, + Partitioning = partitioning, + Properties = properties ?? new(), + }; } - public static RootField References(long id, string name, Partitioning partitioning, - ReferencesFieldProperties? properties = null) + public static RootField String( + long id, + string name, + Partitioning partitioning, + StringFieldProperties? properties = null + ) { - return new RootField { Id = id, Name = name, Partitioning = partitioning, Properties = properties ?? new() }; + return new RootField + { + Id = id, + Name = name, + Partitioning = partitioning, + Properties = properties ?? new(), + }; } - public static RootField RichText(long id, string name, Partitioning partitioning, - RichTextFieldProperties? properties = null) + public static RootField Tags( + long id, + string name, + Partitioning partitioning, + TagsFieldProperties? properties = null + ) { - return new RootField { Id = id, Name = name, Partitioning = partitioning, Properties = properties ?? new() }; + return new RootField + { + Id = id, + Name = name, + Partitioning = partitioning, + Properties = properties ?? new(), + }; } - public static RootField String(long id, string name, Partitioning partitioning, - StringFieldProperties? properties = null) + public static RootField UI( + long id, + string name, + Partitioning partitioning, + UIFieldProperties? properties = null + ) { - return new RootField { Id = id, Name = name, Partitioning = partitioning, Properties = properties ?? new() }; + return new RootField + { + Id = id, + Name = name, + Partitioning = partitioning, + Properties = properties ?? new(), + }; } - public static RootField Tags(long id, string name, Partitioning partitioning, - TagsFieldProperties? properties = null) + public static RootField UserInfo( + long id, + string name, + Partitioning partitioning, + UserInfoFieldProperties? properties = null + ) { - return new RootField { Id = id, Name = name, Partitioning = partitioning, Properties = properties ?? new() }; + return new RootField + { + Id = id, + Name = name, + Partitioning = partitioning, + Properties = properties ?? new(), + }; } - public static RootField UI(long id, string name, Partitioning partitioning, - UIFieldProperties? properties = null) + public static NestedField Assets( + long id, + string name, + AssetsFieldProperties? properties = null + ) { - return new RootField { Id = id, Name = name, Partitioning = partitioning, Properties = properties ?? new() }; + return new NestedField + { + Id = id, + Name = name, + Properties = properties ?? new(), + }; } - public static NestedField Assets(long id, string name, - AssetsFieldProperties? properties = null) + public static NestedField Boolean( + long id, + string name, + BooleanFieldProperties? properties = null + ) { - return new NestedField { Id = id, Name = name, Properties = properties ?? new() }; + return new NestedField + { + Id = id, + Name = name, + Properties = properties ?? new(), + }; } - public static NestedField Boolean(long id, string name, - BooleanFieldProperties? properties = null) + public static NestedField Component( + long id, + string name, + ComponentFieldProperties? properties = null + ) { - return new NestedField { Id = id, Name = name, Properties = properties ?? new() }; + return new NestedField + { + Id = id, + Name = name, + Properties = properties ?? new(), + }; } - public static NestedField Component(long id, string name, - ComponentFieldProperties? properties = null) + public static NestedField Components( + long id, + string name, + ComponentsFieldProperties? properties = null + ) { - return new NestedField { Id = id, Name = name, Properties = properties ?? new() }; + return new NestedField + { + Id = id, + Name = name, + Properties = properties ?? new(), + }; } - public static NestedField Components(long id, string name, - ComponentsFieldProperties? properties = null) + public static NestedField DateTime( + long id, + string name, + DateTimeFieldProperties? properties = null + ) { - return new NestedField { Id = id, Name = name, Properties = properties ?? new() }; + return new NestedField + { + Id = id, + Name = name, + Properties = properties ?? new(), + }; } - public static NestedField DateTime(long id, string name, - DateTimeFieldProperties? properties = null) + public static NestedField Geolocation( + long id, + string name, + GeolocationFieldProperties? properties = null + ) { - return new NestedField { Id = id, Name = name, Properties = properties ?? new() }; + return new NestedField + { + Id = id, + Name = name, + Properties = properties ?? new(), + }; } - public static NestedField Geolocation(long id, string name, - GeolocationFieldProperties? properties = null) + public static NestedField Json( + long id, + string name, + JsonFieldProperties? properties = null + ) { - return new NestedField { Id = id, Name = name, Properties = properties ?? new() }; + return new NestedField + { + Id = id, + Name = name, + Properties = properties ?? new(), + }; } - public static NestedField Json(long id, string name, - JsonFieldProperties? properties = null) + public static NestedField Number( + long id, + string name, + NumberFieldProperties? properties = null + ) { - return new NestedField { Id = id, Name = name, Properties = properties ?? new() }; + return new NestedField + { + Id = id, + Name = name, + Properties = properties ?? new(), + }; } - public static NestedField Number(long id, string name, - NumberFieldProperties? properties = null) + public static NestedField References( + long id, + string name, + ReferencesFieldProperties? properties = null + ) { - return new NestedField { Id = id, Name = name, Properties = properties ?? new() }; + return new NestedField + { + Id = id, + Name = name, + Properties = properties ?? new(), + }; } - public static NestedField References(long id, string name, - ReferencesFieldProperties? properties = null) + public static NestedField RichText( + long id, + string name, + RichTextFieldProperties? properties = null + ) { - return new NestedField { Id = id, Name = name, Properties = properties ?? new() }; + return new NestedField + { + Id = id, + Name = name, + Properties = properties ?? new(), + }; } - public static NestedField RichText(long id, string name, - RichTextFieldProperties? properties = null) + public static NestedField String( + long id, + string name, + StringFieldProperties? properties = null + ) { - return new NestedField { Id = id, Name = name, Properties = properties ?? new() }; + return new NestedField + { + Id = id, + Name = name, + Properties = properties ?? new(), + }; } - public static NestedField String(long id, string name, - StringFieldProperties? properties = null) + public static NestedField Tags( + long id, + string name, + TagsFieldProperties? properties = null + ) { - return new NestedField { Id = id, Name = name, Properties = properties ?? new() }; + return new NestedField + { + Id = id, + Name = name, + Properties = properties ?? new(), + }; } - public static NestedField Tags(long id, string name, - TagsFieldProperties? properties = null) + public static NestedField UI( + long id, + string name, + UIFieldProperties? properties = null + ) { - return new NestedField { Id = id, Name = name, Properties = properties ?? new() }; + return new NestedField + { + Id = id, + Name = name, + Properties = properties ?? new(), + }; } - public static NestedField UI(long id, string name, - UIFieldProperties? properties = null) + public static NestedField User( + long id, + string name, + UserInfoFieldProperties? properties = null + ) { - return new NestedField { Id = id, Name = name, Properties = properties ?? new() }; + return new NestedField + { + Id = id, + Name = name, + Properties = properties ?? new(), + }; } - public static Schema AddArray(this Schema schema, long id, string name, Partitioning partitioning, - Func? handler = null, ArrayFieldProperties? properties = null) + public static Schema AddArray( + this Schema schema, + long id, + string name, + Partitioning partitioning, + Func? handler = null, + ArrayFieldProperties? properties = null + ) { var field = Array(id, name, partitioning, properties); @@ -186,159 +468,297 @@ public static class Fields return schema.AddField(field); } - public static Schema AddAssets(this Schema schema, long id, string name, Partitioning partitioning, - AssetsFieldProperties? properties = null) + public static Schema AddAssets( + this Schema schema, + long id, + string name, + Partitioning partitioning, + AssetsFieldProperties? properties = null + ) { return schema.AddField(Assets(id, name, partitioning, properties)); } - public static Schema AddBoolean(this Schema schema, long id, string name, Partitioning partitioning, - BooleanFieldProperties? properties = null) + public static Schema AddBoolean( + this Schema schema, + long id, + string name, + Partitioning partitioning, + BooleanFieldProperties? properties = null + ) { return schema.AddField(Boolean(id, name, partitioning, properties)); } - public static Schema AddComponent(this Schema schema, long id, string name, Partitioning partitioning, - ComponentFieldProperties? properties = null) + public static Schema AddComponent( + this Schema schema, + long id, + string name, + Partitioning partitioning, + ComponentFieldProperties? properties = null + ) { return schema.AddField(Component(id, name, partitioning, properties)); } - public static Schema AddComponents(this Schema schema, long id, string name, Partitioning partitioning, - ComponentsFieldProperties? properties = null) + public static Schema AddComponents( + this Schema schema, + long id, + string name, + Partitioning partitioning, + ComponentsFieldProperties? properties = null + ) { return schema.AddField(Components(id, name, partitioning, properties)); } - public static Schema AddDateTime(this Schema schema, long id, string name, Partitioning partitioning, - DateTimeFieldProperties? properties = null) + public static Schema AddDateTime( + this Schema schema, + long id, + string name, + Partitioning partitioning, + DateTimeFieldProperties? properties = null + ) { return schema.AddField(DateTime(id, name, partitioning, properties)); } - public static Schema AddGeolocation(this Schema schema, long id, string name, Partitioning partitioning, - GeolocationFieldProperties? properties = null) + public static Schema AddGeolocation( + this Schema schema, + long id, + string name, + Partitioning partitioning, + GeolocationFieldProperties? properties = null + ) { return schema.AddField(Geolocation(id, name, partitioning, properties)); } - public static Schema AddJson(this Schema schema, long id, string name, Partitioning partitioning, - JsonFieldProperties? properties = null) + public static Schema AddJson( + this Schema schema, + long id, + string name, + Partitioning partitioning, + JsonFieldProperties? properties = null + ) { return schema.AddField(Json(id, name, partitioning, properties)); } - public static Schema AddNumber(this Schema schema, long id, string name, Partitioning partitioning, - NumberFieldProperties? properties = null) + public static Schema AddNumber( + this Schema schema, + long id, + string name, + Partitioning partitioning, + NumberFieldProperties? properties = null + ) { return schema.AddField(Number(id, name, partitioning, properties)); } - public static Schema AddReferences(this Schema schema, long id, string name, Partitioning partitioning, - ReferencesFieldProperties? properties = null) + public static Schema AddReferences( + this Schema schema, + long id, + string name, + Partitioning partitioning, + ReferencesFieldProperties? properties = null + ) { return schema.AddField(References(id, name, partitioning, properties)); } - public static Schema AddRichText(this Schema schema, long id, string name, Partitioning partitioning, - RichTextFieldProperties? properties = null) + public static Schema AddRichText( + this Schema schema, + long id, + string name, + Partitioning partitioning, + RichTextFieldProperties? properties = null + ) { return schema.AddField(RichText(id, name, partitioning, properties)); } - public static Schema AddString(this Schema schema, long id, string name, Partitioning partitioning, - StringFieldProperties? properties = null) + public static Schema AddString( + this Schema schema, + long id, + string name, + Partitioning partitioning, + StringFieldProperties? properties = null + ) { return schema.AddField(String(id, name, partitioning, properties)); } - public static Schema AddTags(this Schema schema, long id, string name, Partitioning partitioning, - TagsFieldProperties? properties = null) + public static Schema AddTags( + this Schema schema, + long id, + string name, + Partitioning partitioning, + TagsFieldProperties? properties = null + ) { return schema.AddField(Tags(id, name, partitioning, properties)); } - public static Schema AddUI(this Schema schema, long id, string name, Partitioning partitioning, - UIFieldProperties? properties = null) + public static Schema AddUI( + this Schema schema, + long id, + string name, + Partitioning partitioning, + UIFieldProperties? properties = null + ) { return schema.AddField(UI(id, name, partitioning, properties)); } - public static ArrayField AddAssets(this ArrayField field, long id, string name, - AssetsFieldProperties? properties = null) + public static Schema AddUserInfo( + this Schema schema, + long id, + string name, + Partitioning partitioning, + UserInfoFieldProperties? properties = null + ) + { + return schema.AddField(UserInfo(id, name, partitioning, properties)); + } + + public static ArrayField AddAssets( + this ArrayField field, + long id, + string name, + AssetsFieldProperties? properties = null + ) + { + return field.AddUserInfo(Assets(id, name, properties)); + } + + public static ArrayField AddBoolean( + this ArrayField field, + long id, + string name, + BooleanFieldProperties? properties = null + ) { - return field.AddField(Assets(id, name, properties)); + return field.AddUserInfo(Boolean(id, name, properties)); } - public static ArrayField AddBoolean(this ArrayField field, long id, string name, - BooleanFieldProperties? properties = null) + public static ArrayField AddComponent( + this ArrayField field, + long id, + string name, + ComponentFieldProperties? properties = null + ) { - return field.AddField(Boolean(id, name, properties)); + return field.AddUserInfo(Component(id, name, properties)); } - public static ArrayField AddComponent(this ArrayField field, long id, string name, - ComponentFieldProperties? properties = null) + public static ArrayField AddComponents( + this ArrayField field, + long id, + string name, + ComponentsFieldProperties? properties = null + ) { - return field.AddField(Component(id, name, properties)); + return field.AddUserInfo(Components(id, name, properties)); } - public static ArrayField AddComponents(this ArrayField field, long id, string name, - ComponentsFieldProperties? properties = null) + public static ArrayField AddDateTime( + this ArrayField field, + long id, + string name, + DateTimeFieldProperties? properties = null + ) { - return field.AddField(Components(id, name, properties)); + return field.AddUserInfo(DateTime(id, name, properties)); } - public static ArrayField AddDateTime(this ArrayField field, long id, string name, - DateTimeFieldProperties? properties = null) + public static ArrayField AddGeolocation( + this ArrayField field, + long id, + string name, + GeolocationFieldProperties? properties = null + ) { - return field.AddField(DateTime(id, name, properties)); + return field.AddUserInfo(Geolocation(id, name, properties)); } - public static ArrayField AddGeolocation(this ArrayField field, long id, string name, - GeolocationFieldProperties? properties = null) + public static ArrayField AddJson( + this ArrayField field, + long id, + string name, + JsonFieldProperties? properties = null + ) { - return field.AddField(Geolocation(id, name, properties)); + return field.AddUserInfo(Json(id, name, properties)); } - public static ArrayField AddJson(this ArrayField field, long id, string name, - JsonFieldProperties? properties = null) + public static ArrayField AddNumber( + this ArrayField field, + long id, + string name, + NumberFieldProperties? properties = null + ) { - return field.AddField(Json(id, name, properties)); + return field.AddUserInfo(Number(id, name, properties)); } - public static ArrayField AddNumber(this ArrayField field, long id, string name, - NumberFieldProperties? properties = null) + public static ArrayField AddReferences( + this ArrayField field, + long id, + string name, + ReferencesFieldProperties? properties = null + ) { - return field.AddField(Number(id, name, properties)); + return field.AddUserInfo(References(id, name, properties)); } - public static ArrayField AddReferences(this ArrayField field, long id, string name, - ReferencesFieldProperties? properties = null) + public static ArrayField AddRichText( + this ArrayField field, + long id, + string name, + RichTextFieldProperties? properties = null + ) { - return field.AddField(References(id, name, properties)); + return field.AddUserInfo(RichText(id, name, properties)); } - public static ArrayField AddRichText(this ArrayField field, long id, string name, - RichTextFieldProperties? properties = null) + public static ArrayField AddString( + this ArrayField field, + long id, + string name, + StringFieldProperties? properties = null + ) { - return field.AddField(RichText(id, name, properties)); + return field.AddUserInfo(String(id, name, properties)); } - public static ArrayField AddString(this ArrayField field, long id, string name, - StringFieldProperties? properties = null) + public static ArrayField AddTags( + this ArrayField field, + long id, + string name, + TagsFieldProperties? properties = null + ) { - return field.AddField(String(id, name, properties)); + return field.AddUserInfo(Tags(id, name, properties)); } - public static ArrayField AddTags(this ArrayField field, long id, string name, - TagsFieldProperties? properties = null) + public static ArrayField AddUI( + this ArrayField field, + long id, + string name, + UIFieldProperties? properties = null + ) { - return field.AddField(Tags(id, name, properties)); + return field.AddUserInfo(UI(id, name, properties)); } - public static ArrayField AddUI(this ArrayField field, long id, string name, - UIFieldProperties? properties = null) + public static ArrayField AddUserInfo( + this ArrayField field, + long id, + string name, + UserInfoFieldProperties? properties = null + ) { - return field.AddField(UI(id, name, properties)); + return field.AddUserInfo(User(id, name, properties)); } } diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/IFieldPropertiesVisitor.cs b/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/IFieldPropertiesVisitor.cs index 86fa16ccf..7b17610f1 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/IFieldPropertiesVisitor.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/IFieldPropertiesVisitor.cs @@ -36,4 +36,6 @@ public interface IFieldPropertiesVisitor T Visit(TagsFieldProperties properties, TArgs args); T Visit(UIFieldProperties properties, TArgs args); + + T Visit(UserInfoFieldProperties properties, TArgs args); } diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/IFieldVisitor.cs b/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/IFieldVisitor.cs index decf75ff5..02401d54b 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/IFieldVisitor.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/IFieldVisitor.cs @@ -36,4 +36,6 @@ public interface IFieldVisitor T Visit(IField field, TArgs args); T Visit(IField field, TArgs args); + + T Visit(IField field, TArgs args); } diff --git a/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/UserInfoFieldProperties.cs b/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/UserInfoFieldProperties.cs new file mode 100644 index 000000000..f97135ebe --- /dev/null +++ b/backend/src/Squidex.Domain.Apps.Core.Model/Schemas/UserInfoFieldProperties.cs @@ -0,0 +1,33 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +namespace Squidex.Domain.Apps.Core.Schemas; + +public record class UserInfoFieldProperties : FieldProperties +{ + public string? DefaultRole { get; init; } + + public override T Accept(IFieldPropertiesVisitor visitor, TArgs args) + { + return visitor.Visit(this, args); + } + + public override T Accept(IFieldVisitor visitor, IField field, TArgs args) + { + return visitor.Visit((IField)field, args); + } + + public override RootField CreateRootField(long id, string name, Partitioning partitioning) + { + return Fields.UserInfo(id, name, partitioning, this); + } + + public override NestedField CreateNestedField(long id, string name) + { + return Fields.User(id, name, this); + } +} diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/AddDefaultValues.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/AddDefaultValues.cs index 6768cdd85..f896ea6c3 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/AddDefaultValues.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/AddDefaultValues.cs @@ -88,7 +88,6 @@ public sealed class AddDefaultValues(PartitionResolver partitionResolver, IClock } var defaultValue = DefaultValueFactory.CreateDefaultValue(field, GetNow(), key); - if (defaultValue == default) { return; diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/ContentConverter.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/ContentConverter.cs index c0573ebe3..4d66827e7 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/ContentConverter.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/ContentConverter.cs @@ -67,7 +67,6 @@ public sealed class ContentConverter(ResolvedComponents components, Schema schem // Some conversions are faster to do upfront, e.g. to remove hidden fields. var newData = ConvertField(field, fieldData); - if (newData == null) { continue; @@ -98,7 +97,6 @@ public sealed class ContentConverter(ResolvedComponents components, Schema schem foreach (var converter in fieldConverters) { var newData = converter.ConvertFieldBefore(field, data); - if (newData == null) { return null; @@ -115,7 +113,6 @@ public sealed class ContentConverter(ResolvedComponents components, Schema schem foreach (var converter in fieldConverters) { var newData = converter.ConvertFieldAfter(field, data); - if (newData == null) { return null; @@ -157,7 +154,6 @@ public sealed class ContentConverter(ResolvedComponents components, Schema schem var oldValue = array[i]; var (removed, newValue) = ConvertArrayItem(field, oldValue); - if (removed) { array.RemoveAt(i); @@ -184,7 +180,6 @@ public sealed class ContentConverter(ResolvedComponents components, Schema schem var oldValue = array[i]; var (removed, newValue) = ConvertComponent(oldValue, parent); - if (removed) { array.RemoveAt(i); diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/DefaultValueChecker.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/DefaultValueChecker.cs index 2c5a69071..7cb459636 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/DefaultValueChecker.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/DefaultValueChecker.cs @@ -94,4 +94,9 @@ internal sealed class DefaultValueChecker : IFieldPropertiesVisitor { return false; } + + public bool Visit(UserInfoFieldProperties properties, None args) + { + return !string.IsNullOrWhiteSpace(properties.DefaultRole); + } } diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/DefaultValueFactory.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/DefaultValueFactory.cs index 93ada0126..c0d8ec28b 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/DefaultValueFactory.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ConvertContent/DefaultValueFactory.cs @@ -7,6 +7,7 @@ using System.Globalization; using NodaTime; +using Squidex.Domain.Apps.Core.Contents; using Squidex.Domain.Apps.Core.Schemas; using Squidex.Infrastructure.Json.Objects; @@ -118,6 +119,16 @@ public sealed class DefaultValueFactory : IFieldPropertiesVisitor"; } + public string Visit(UserInfoFieldProperties properties, Args args) + { + return "[User]"; + } + public string Visit(NumberFieldProperties properties, Args args) { return args.Value.ToString(); diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ReferencesCleaner.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ReferencesCleaner.cs index d56c811f3..2c5809e3b 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ReferencesCleaner.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ExtractReferenceIds/ReferencesCleaner.cs @@ -100,6 +100,11 @@ internal sealed class ReferencesCleaner : IFieldPropertiesVisitor field, Args args) + { + return FilterSchema.Any; + } + public FilterSchema? Visit(IField field, Args args) { if (args.Level >= MaxDepth) diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/GenerateJsonSchema/JsonTypeVisitor.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/GenerateJsonSchema/JsonTypeVisitor.cs index b2c4a13ba..aedbb2640 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/GenerateJsonSchema/JsonTypeVisitor.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/GenerateJsonSchema/JsonTypeVisitor.cs @@ -257,6 +257,21 @@ internal sealed class JsonTypeVisitor : IFieldVisitor field, Args args) + { + var scheme = JsonTypeBuilder.Object(); + + scheme.Properties.Add( + "apiKey", + JsonTypeBuilder.StringProperty(FieldDescriptions.UserInfoApiKey, true)); + + scheme.Properties.Add( + "role", + JsonTypeBuilder.StringProperty(FieldDescriptions.UserInfoRole, true)); + + return JsonTypeBuilder.ObjectProperty(scheme); + } + private static void BuildComponent(JsonSchema jsonSchema, ReadonlyList? schemaIds, Args args) { if (args.WithComponents) diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ContentScriptVars.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ContentScriptVars.cs index c91080ad0..c521182f1 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ContentScriptVars.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ContentScriptVars.cs @@ -111,7 +111,7 @@ public sealed class ContentScriptVars : DataScriptVars } [FieldDescription(nameof(FieldDescriptions.EntityCreated))] - public Instant Created + public Instant Created { set => SetInitial(value); } diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ScriptVars.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ScriptVars.cs index 02e6a1886..d3ddfde99 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ScriptVars.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/Scripting/ScriptVars.cs @@ -59,7 +59,7 @@ public class ScriptVars : IDictionary } public void CopyTo(KeyValuePair[] array, int arrayIndex) - { + { Guard.NotNull(array); ((IDictionary)values).CopyTo(array, arrayIndex); } diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/DefaultFieldValueValidatorsFactory.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/DefaultFieldValueValidatorsFactory.cs index dd9f7a35c..63664ea43 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/DefaultFieldValueValidatorsFactory.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/DefaultFieldValueValidatorsFactory.cs @@ -263,6 +263,16 @@ internal sealed class DefaultFieldValueValidatorsFactory : IFieldVisitor Visit(IField field, Args args) + { + var properties = field.Properties; + + if (IsRequired(properties, args.Context, out _)) + { + yield return new RequiredValidator(); + } + } + private static bool IsRequired(FieldProperties properties, ValidationContext context, out bool result) { var isRequired = properties.IsRequired; @@ -277,7 +287,7 @@ internal sealed class DefaultFieldValueValidatorsFactory : IFieldVisitor { diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/JsonValueConverter.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/JsonValueConverter.cs index 802a0ec65..e7d1d4af5 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/JsonValueConverter.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/JsonValueConverter.cs @@ -155,6 +155,23 @@ public sealed class JsonValueConverter : IFieldPropertiesVisitor<(object? Result } } + public (object? Result, JsonError? Error) Visit(UserInfoFieldProperties properties, Args args) + { + var result = UserInfoValue.TryParse(args.Value, out var value); + + switch (result) + { + case UserInfoParseResult.InvalidApiKey: + return (null, new JsonError(T.Get("contents.invalidUserInfoApiKey"))); + case UserInfoParseResult.InvalidRole: + return (null, new JsonError(T.Get("contents.invalidUserInfoRole"))); + case UserInfoParseResult.InvalidValue: + return (null, new JsonError(T.Get("contents.invalidUserInfo"))); + default: + return (value, null); + } + } + private static (object? Result, JsonError? Error) ConvertToIdList(JsonValue value) { if (value.Value is JsonArray a) diff --git a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/JsonValueValidator.cs b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/JsonValueValidator.cs index 48839094d..f5f3ed241 100644 --- a/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/JsonValueValidator.cs +++ b/backend/src/Squidex.Domain.Apps.Core.Operations/ValidateContent/JsonValueValidator.cs @@ -75,9 +75,7 @@ public sealed class JsonValueValidator : IFieldPropertiesVisitor field, FieldInfo args) + { + return Scalars.Json; + } } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/FieldVisitor.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/FieldVisitor.cs index 5239e3088..f945f890e 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/FieldVisitor.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/GraphQL/Types/Contents/FieldVisitor.cs @@ -266,6 +266,11 @@ internal sealed class FieldVisitor(Builder builder) : IFieldVisitor field, FieldInfo args) + { + return new (Scalars.Json, JsonPath, ContentActions.Json.Arguments); + } + private IGraphType? ResolveReferences(FieldInfo fieldInfo, ReadonlyList? schemaIds) { IGraphType? contentType = null; diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/ApiKeyQuery.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/ApiKeyQuery.cs new file mode 100644 index 000000000..5e5ac9759 --- /dev/null +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/ApiKeyQuery.cs @@ -0,0 +1,14 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +namespace Squidex.Domain.Apps.Entities.Contents.Text; + +#pragma warning disable SA1313 // Parameter names should begin with lower-case letter + +public sealed record ApiKeyQuery(string ApiKey) +{ +} diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/Extensions.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/Extensions.cs index 9541ff618..4c3690f45 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/Extensions.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/Extensions.cs @@ -41,6 +41,30 @@ public static class Extensions return result; } + public static List? ToUserInfos(this ContentData data) + { + List? result = null; + + foreach (var (field, value) in data) + { + if (value != null) + { + foreach (var (key, jsonValue) in value) + { + UserInfoValue.TryParse(jsonValue, out var userInfo); + + if (userInfo != null) + { + result ??= []; + result.Add(userInfo); + } + } + } + } + + return result; + } + public static Dictionary? ToTexts(this ContentData data) { Dictionary? result = null; diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/ITextIndex.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/ITextIndex.cs index 70c0cd578..36a686225 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/ITextIndex.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/ITextIndex.cs @@ -8,8 +8,13 @@ using Squidex.Domain.Apps.Core.Apps; using Squidex.Infrastructure; +#pragma warning disable MA0048 // File name must match type name +#pragma warning disable SA1313 // Parameter names should begin with lower-case letter + namespace Squidex.Domain.Apps.Entities.Contents.Text; +public record class UserInfoResult(DomainId ContentId, string Role); + public interface ITextIndex { Task?> SearchAsync(App app, TextQuery query, SearchScope scope, @@ -18,6 +23,9 @@ public interface ITextIndex Task?> SearchAsync(App app, GeoQuery query, SearchScope scope, CancellationToken ct = default); + Task FindUserInfo(App app, ApiKeyQuery query, SearchScope scope, + CancellationToken ct = default); + Task ClearAsync( CancellationToken ct = default); diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/TextIndexingProcess.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/TextIndexingProcess.cs index d39d5304a..3a75bdb4f 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/TextIndexingProcess.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/TextIndexingProcess.cs @@ -106,6 +106,7 @@ public sealed class TextIndexingProcess( ServeAll = true, ServePublished = false, Texts = data.ToTexts(), + UserInfos = data.ToUserInfos(), }); states[state.UniqueContentId] = state; diff --git a/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/UpsertIndexEntry.cs b/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/UpsertIndexEntry.cs index 495541123..9431dbd79 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/UpsertIndexEntry.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Contents/Text/UpsertIndexEntry.cs @@ -6,6 +6,7 @@ // ========================================================================== using NetTopologySuite.Geometries; +using Squidex.Domain.Apps.Core.Contents; namespace Squidex.Domain.Apps.Entities.Contents.Text; @@ -15,6 +16,8 @@ public sealed class UpsertIndexEntry : IndexCommand public Dictionary? Texts { get; set; } + public List? UserInfos { get; set; } + public bool ServeAll { get; set; } public bool ServePublished { get; set; } diff --git a/backend/src/Squidex.Domain.Apps.Entities/Schemas/DomainObject/Guards/FieldPropertiesValidator.cs b/backend/src/Squidex.Domain.Apps.Entities/Schemas/DomainObject/Guards/FieldPropertiesValidator.cs index 597bfdde3..91e0845cc 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Schemas/DomainObject/Guards/FieldPropertiesValidator.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Schemas/DomainObject/Guards/FieldPropertiesValidator.cs @@ -316,6 +316,11 @@ public sealed class FieldPropertiesValidator : IFieldPropertiesVisitor Visit(UserInfoFieldProperties properties, None args) + { + yield break; + } + private static bool IsMaxGreaterThanMin(T? min, T? max) where T : struct, IComparable { return max.HasValue && min.HasValue && min.Value.CompareTo(max.Value) < 0; diff --git a/backend/src/Squidex.Domain.Apps.Entities/Schemas/DomainObject/SchemaDomainObject.State.cs b/backend/src/Squidex.Domain.Apps.Entities/Schemas/DomainObject/SchemaDomainObject.State.cs index f67e3a165..eace08b0d 100644 --- a/backend/src/Squidex.Domain.Apps.Entities/Schemas/DomainObject/SchemaDomainObject.State.cs +++ b/backend/src/Squidex.Domain.Apps.Entities/Schemas/DomainObject/SchemaDomainObject.State.cs @@ -37,7 +37,7 @@ public partial class SchemaDomainObject { var field = e.Properties.CreateNestedField(e.FieldId.Id, e.Name); - newSnapshot = newSnapshot.UpdateField(e.ParentFieldId.Id, x => ((ArrayField)x).AddField(field)); + newSnapshot = newSnapshot.UpdateField(e.ParentFieldId.Id, x => ((ArrayField)x).AddUserInfo(field)); } else { diff --git a/backend/src/Squidex.Shared/Texts.de.resx b/backend/src/Squidex.Shared/Texts.de.resx index 7b6ca4e64..781073a04 100644 --- a/backend/src/Squidex.Shared/Texts.de.resx +++ b/backend/src/Squidex.Shared/Texts.de.resx @@ -502,6 +502,15 @@ Ungültiger JSON-Typ, Zeichenfolge erwartet. + + Invalid json type, expected apiKey+role object. + + + ApiKey must be defined. + + + Role must be defined. + {count} Referenz(en) diff --git a/backend/src/Squidex.Shared/Texts.fr.resx b/backend/src/Squidex.Shared/Texts.fr.resx index 2ab7f9b1f..60a13a758 100644 --- a/backend/src/Squidex.Shared/Texts.fr.resx +++ b/backend/src/Squidex.Shared/Texts.fr.resx @@ -502,6 +502,15 @@ Type json non valide, chaîne attendue. + + Invalid json type, expected apiKey+role object. + + + ApiKey must be defined. + + + Role must be defined. + {count} Les références) diff --git a/backend/src/Squidex.Shared/Texts.it.resx b/backend/src/Squidex.Shared/Texts.it.resx index b006c3a2d..974684eef 100644 --- a/backend/src/Squidex.Shared/Texts.it.resx +++ b/backend/src/Squidex.Shared/Texts.it.resx @@ -502,6 +502,15 @@ Errore nel json, atteso una string. + + Invalid json type, expected apiKey+role object. + + + ApiKey must be defined. + + + Role must be defined. + {count} Collegamenti(s) diff --git a/backend/src/Squidex.Shared/Texts.nl.resx b/backend/src/Squidex.Shared/Texts.nl.resx index 842aa8491..d1b5a36e2 100644 --- a/backend/src/Squidex.Shared/Texts.nl.resx +++ b/backend/src/Squidex.Shared/Texts.nl.resx @@ -502,6 +502,15 @@ Ongeldig json-type, verwachte string. + + Invalid json type, expected apiKey+role object. + + + ApiKey must be defined. + + + Role must be defined. + {count} referentie (s) diff --git a/backend/src/Squidex.Shared/Texts.pt.resx b/backend/src/Squidex.Shared/Texts.pt.resx index 0e9ea9abd..598e5f9d6 100644 --- a/backend/src/Squidex.Shared/Texts.pt.resx +++ b/backend/src/Squidex.Shared/Texts.pt.resx @@ -502,6 +502,15 @@ Json type inválido, esperado texto. + + Invalid json type, expected apiKey+role object. + + + ApiKey must be defined. + + + Role must be defined. + {count} Referencia(s) diff --git a/backend/src/Squidex.Shared/Texts.resx b/backend/src/Squidex.Shared/Texts.resx index 7f74a020a..6ae445772 100644 --- a/backend/src/Squidex.Shared/Texts.resx +++ b/backend/src/Squidex.Shared/Texts.resx @@ -502,6 +502,15 @@ Invalid json type, expected string. + + Invalid json type, expected apiKey+role object. + + + ApiKey must be defined. + + + Role must be defined. + {count} Reference(s) diff --git a/backend/src/Squidex.Shared/Texts.zh.resx b/backend/src/Squidex.Shared/Texts.zh.resx index fcc7582ee..941243908 100644 --- a/backend/src/Squidex.Shared/Texts.zh.resx +++ b/backend/src/Squidex.Shared/Texts.zh.resx @@ -502,6 +502,15 @@ 无效的 json 类型,需要的字符串。 + + Invalid json type, expected apiKey+role object. + + + ApiKey must be defined. + + + Role must be defined. + {count} 个引用 diff --git a/backend/src/Squidex.Web/Constants.cs b/backend/src/Squidex.Web/Constants.cs index 8a738b540..065801a4a 100644 --- a/backend/src/Squidex.Web/Constants.cs +++ b/backend/src/Squidex.Web/Constants.cs @@ -32,6 +32,10 @@ public static class Constants public const string ScopeApi = "squidex-api"; + public const string ClaimTypeApp = "app/name"; + + public const string ClaimTypeRole = "app/role"; + public static readonly string ClientFrontendId = DefaultClients.Frontend; public static readonly string ClientInternalId = "squidex-internal"; diff --git a/backend/src/Squidex.Web/Extensions.cs b/backend/src/Squidex.Web/Extensions.cs index 19293aecb..944ee82a5 100644 --- a/backend/src/Squidex.Web/Extensions.cs +++ b/backend/src/Squidex.Web/Extensions.cs @@ -12,6 +12,14 @@ namespace Squidex.Web; public static class Extensions { + public static (string? UserId, string? App, string? Role) GetUserInfo(this ClaimsPrincipal principal) + { + return ( + principal.FindFirst(ClaimTypes.NameIdentifier)?.Value, + principal.FindFirst(Constants.ClaimTypeApp)?.Value, + principal.FindFirst(Constants.ClaimTypeRole)?.Value); + } + public static string? GetClientId(this ClaimsPrincipal principal) { var clientId = principal.FindFirst(OpenIdClaims.ClientId)?.Value; diff --git a/backend/src/Squidex.Web/Pipeline/ApiKeyAuthenticationBuilderExtensions.cs b/backend/src/Squidex.Web/Pipeline/ApiKeyAuthenticationBuilderExtensions.cs new file mode 100644 index 000000000..00a52d6a3 --- /dev/null +++ b/backend/src/Squidex.Web/Pipeline/ApiKeyAuthenticationBuilderExtensions.cs @@ -0,0 +1,20 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using Squidex.Web.Pipeline; + +#pragma warning disable IDE0130 // Namespace does not match folder structure + +namespace Microsoft.AspNetCore.Authentication; + +public static class ApiKeyAuthenticationBuilderExtensions +{ + public static AuthenticationBuilder AddApiKey(this AuthenticationBuilder builder) + { + return builder.AddScheme(ApiKeyDefaults.AuthenticationScheme, _ => { }); + } +} diff --git a/backend/src/Squidex.Web/Pipeline/ApiKeyDefaults.cs b/backend/src/Squidex.Web/Pipeline/ApiKeyDefaults.cs new file mode 100644 index 000000000..7521365db --- /dev/null +++ b/backend/src/Squidex.Web/Pipeline/ApiKeyDefaults.cs @@ -0,0 +1,13 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +namespace Squidex.Web.Pipeline; + +public static class ApiKeyDefaults +{ + public const string AuthenticationScheme = "ApiKey"; +} diff --git a/backend/src/Squidex.Web/Pipeline/ApiKeyHandler.cs b/backend/src/Squidex.Web/Pipeline/ApiKeyHandler.cs new file mode 100644 index 000000000..dfc6ffc80 --- /dev/null +++ b/backend/src/Squidex.Web/Pipeline/ApiKeyHandler.cs @@ -0,0 +1,131 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using System.Diagnostics.CodeAnalysis; +using System.Security.Claims; +using System.Text.Encodings.Web; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Microsoft.Net.Http.Headers; +using Squidex.Domain.Apps.Entities; +using Squidex.Domain.Apps.Entities.Contents; +using Squidex.Domain.Apps.Entities.Contents.Text; + +namespace Squidex.Web.Pipeline; + +public sealed class ApiKeyHandler( + IAppProvider appProvider, + ITextIndex textIndex, + IOptionsMonitor options, + ILoggerFactory logger, + UrlEncoder encoder) + : AuthenticationHandler(options, logger, encoder) +{ + private const string ApiKeyPrefix = "ApiKey "; + private const string ApiKeyHeader = "ApiKey"; + private const string ApiKeyHeaderX = "X-ApiKey"; + private const string ApiKeyQuery = "api_key"; + + protected override async Task HandleAuthenticateAsync() + { + try + { + if (!IsApiKey(Request, out var apiKey)) + { + return AuthenticateResult.NoResult(); + } + + var keyParts = apiKey.Split(':', StringSplitOptions.RemoveEmptyEntries); + if (keyParts.Length != 2) + { + return AuthenticateResult.Fail("Invalid API Key"); + } + + var app = await appProvider.GetAppAsync(keyParts[0], true, Context.RequestAborted); + if (app == null) + { + return AuthenticateResult.Fail("Invalid API Key"); + } + + var user = + await textIndex.FindUserInfo( + app, + new ApiKeyQuery(keyParts[1]), + SearchScope.Published, + Context.RequestAborted); + if (user == null) + { + return AuthenticateResult.Fail("Invalid API Key"); + } + + var identity = new ClaimsIdentity( + [ + new Claim(ClaimTypes.NameIdentifier, user.ContentId.ToString()), + new Claim(Constants.ClaimTypeApp, app.Name), + new Claim(Constants.ClaimTypeRole, user.Role), + ], ApiKeyDefaults.AuthenticationScheme); + + return Success(identity); + } + catch (Exception ex) + { + Logger.LogError(ex, "Error while handling api key."); + + throw; + } + } + + private AuthenticateResult Success(ClaimsIdentity identity) + { + var principal = new ClaimsPrincipal(identity); + + var ticket = new AuthenticationTicket(principal, Scheme.Name); + + return AuthenticateResult.Success(ticket); + } + + public static bool IsApiKey(HttpRequest request, [MaybeNullWhen(false)] out string apiKey) + { + apiKey = null!; + string? authorizationHeader = request.Headers[HeaderNames.Authorization]; + + if (authorizationHeader?.StartsWith(ApiKeyPrefix, StringComparison.OrdinalIgnoreCase) == true) + { + var key = authorizationHeader[ApiKeyPrefix.Length..].Trim(); + if (!string.IsNullOrWhiteSpace(key)) + { + apiKey = key; + return true; + } + } + + string? apiKeyHeader = request.Headers[ApiKeyHeader]; + if (!string.IsNullOrWhiteSpace(apiKeyHeader)) + { + apiKey = apiKeyHeader; + return true; + } + + string? apiKeyHeaderX = request.Headers[ApiKeyHeaderX]; + if (!string.IsNullOrWhiteSpace(apiKeyHeaderX)) + { + apiKey = apiKeyHeaderX; + return true; + } + + string? apiKeyQuery = request.Query[ApiKeyQuery]; + if (!string.IsNullOrWhiteSpace(apiKeyQuery)) + { + apiKey = apiKeyQuery; + return true; + } + + return false; + } +} diff --git a/backend/src/Squidex.Web/Pipeline/ApiKeyOptions.cs b/backend/src/Squidex.Web/Pipeline/ApiKeyOptions.cs new file mode 100644 index 000000000..ebc1af134 --- /dev/null +++ b/backend/src/Squidex.Web/Pipeline/ApiKeyOptions.cs @@ -0,0 +1,14 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using Microsoft.AspNetCore.Authentication; + +namespace Squidex.Web.Pipeline; + +public sealed class ApiKeyOptions : AuthenticationSchemeOptions +{ +} diff --git a/backend/src/Squidex.Web/Pipeline/AppResolver.cs b/backend/src/Squidex.Web/Pipeline/AppResolver.cs index 4e7f0b836..0c4f43281 100644 --- a/backend/src/Squidex.Web/Pipeline/AppResolver.cs +++ b/backend/src/Squidex.Web/Pipeline/AppResolver.cs @@ -28,7 +28,6 @@ public sealed class AppResolver(IAppProvider appProvider) : IAsyncActionFilter if (context.RouteData.Values.TryGetValue("app", out var appValue)) { var appName = appValue?.ToString(); - if (string.IsNullOrWhiteSpace(appName)) { context.Result = new NotFoundResult(); @@ -51,12 +50,16 @@ public sealed class AppResolver(IAppProvider appProvider) : IAsyncActionFilter string? clientId = null; var (role, permissions) = FindByOpenIdSubject(app, user, isFrontend); - if (permissions == null) { (clientId, role, permissions) = FindByOpenIdClient(app, user, isFrontend); } + if (permissions == null) + { + (role, permissions) = FindByUserInfo(app, user, isFrontend); + } + if (permissions == null) { (clientId, role, permissions) = FindAnonymousClient(app, isFrontend); @@ -125,7 +128,6 @@ public sealed class AppResolver(IAppProvider appProvider) : IAsyncActionFilter private static (string?, string?, PermissionSet?) FindByOpenIdClient(App app, ClaimsPrincipal user, bool isFrontend) { var (appName, clientId) = user.GetClient(); - if (app.Name != appName || clientId == null) { return default; @@ -139,10 +141,25 @@ public sealed class AppResolver(IAppProvider appProvider) : IAsyncActionFilter return default; } + private static (string?, PermissionSet?) FindByUserInfo(App app, ClaimsPrincipal user, bool isFrontend) + { + var (_, appName, roleName) = user.GetUserInfo(); + if (app.Name != appName || roleName == null) + { + return default; + } + + if (app.TryGetRole(roleName, isFrontend, out var role)) + { + return (role.Name, role.Permissions); + } + + return default; + } + private static (string?, string?, PermissionSet?) FindAnonymousClient(App app, bool isFrontend) { var client = app.Clients.FirstOrDefault(x => x.Value.AllowAnonymous); - if (client.Value == null) { return default; @@ -159,7 +176,6 @@ public sealed class AppResolver(IAppProvider appProvider) : IAsyncActionFilter private static (string?, PermissionSet?) FindByOpenIdSubject(App app, ClaimsPrincipal user, bool isFrontend) { var subjectId = user.OpenIdSubject(); - if (subjectId == null) { return default; diff --git a/backend/src/Squidex/Areas/Api/Controllers/Schemas/Models/Converters/FieldPropertiesDtoFactory.cs b/backend/src/Squidex/Areas/Api/Controllers/Schemas/Models/Converters/FieldPropertiesDtoFactory.cs index 2a78ed9d7..479299949 100644 --- a/backend/src/Squidex/Areas/Api/Controllers/Schemas/Models/Converters/FieldPropertiesDtoFactory.cs +++ b/backend/src/Squidex/Areas/Api/Controllers/Schemas/Models/Converters/FieldPropertiesDtoFactory.cs @@ -93,4 +93,9 @@ internal sealed class FieldPropertiesDtoFactory : IFieldPropertiesVisitor + /// The role to create a default value. + /// + public string? DefaultRole { get; init; } + + public static UserInfoFieldPropertiesDto FromDomain(UserInfoFieldProperties fieldProperties) + { + return SimpleMapper.Map(fieldProperties, new UserInfoFieldPropertiesDto()); + } + + public override FieldProperties ToProperties() + { + return SimpleMapper.Map(this, new UserInfoFieldProperties()); + } +} diff --git a/backend/src/Squidex/Config/Authentication/AuthenticationServices.cs b/backend/src/Squidex/Config/Authentication/AuthenticationServices.cs index 6f0250b9e..165f20cbe 100644 --- a/backend/src/Squidex/Config/Authentication/AuthenticationServices.cs +++ b/backend/src/Squidex/Config/Authentication/AuthenticationServices.cs @@ -6,7 +6,9 @@ // ========================================================================== using Microsoft.AspNetCore.Authentication; +using OpenIddict.Validation.AspNetCore; using Squidex.Hosting.Web; +using Squidex.Web.Pipeline; namespace Squidex.Config.Authentication; @@ -18,6 +20,7 @@ public static class AuthenticationServices services.AddAuthentication() .AddSquidexCookies(config) + .AddApiKey() .AddSquidexExternalGithubAuthentication(identityOptions) .AddSquidexExternalGoogleAuthentication(identityOptions) .AddSquidexExternalMicrosoftAuthentication(identityOptions) diff --git a/backend/src/Squidex/Config/Authentication/IdentityServerServices.cs b/backend/src/Squidex/Config/Authentication/IdentityServerServices.cs index adee79922..849d37b78 100644 --- a/backend/src/Squidex/Config/Authentication/IdentityServerServices.cs +++ b/backend/src/Squidex/Config/Authentication/IdentityServerServices.cs @@ -11,6 +11,7 @@ using Microsoft.AspNetCore.Authentication.OpenIdConnect; using OpenIddict.Validation.AspNetCore; using Squidex.Hosting; using Squidex.Web; +using Squidex.Web.Pipeline; using static OpenIddict.Abstractions.OpenIddictConstants; namespace Squidex.Config.Authentication; @@ -19,8 +20,9 @@ public static class IdentityServerServices { public static AuthenticationBuilder AddSquidexIdentityServerAuthentication(this AuthenticationBuilder authBuilder, MyIdentityOptions identityOptions, IConfiguration config) { - var useCustomAuthorityUrl = !string.IsNullOrWhiteSpace(identityOptions.AuthorityUrl); + var defaultScheme = OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme; + var useCustomAuthorityUrl = !string.IsNullOrWhiteSpace(identityOptions.AuthorityUrl); if (useCustomAuthorityUrl) { const string ExternalIdentityServerSchema = nameof(ExternalIdentityServerSchema); @@ -34,21 +36,23 @@ public static class IdentityServerServices options.Scope.Add(Constants.ScopeApi); }); - authBuilder.AddPolicyScheme(Constants.ApiSecurityScheme, Constants.ApiSecurityScheme, options => - { - options.ForwardDefaultSelector = context => ExternalIdentityServerSchema; - }); + defaultScheme = ExternalIdentityServerSchema; } - else - { - authBuilder.AddPolicyScheme(Constants.ApiSecurityScheme, Constants.ApiSecurityScheme, options => + + authBuilder.AddPolicyScheme(Constants.ApiSecurityScheme, null, options => { - options.ForwardDefaultSelector = _ => OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme; + options.ForwardDefaultSelector = context => + { + if (ApiKeyHandler.IsApiKey(context.Request, out _)) + { + return ApiKeyDefaults.AuthenticationScheme; + } + + return defaultScheme; + }; }); - } authBuilder.AddOpenIdConnect(); - authBuilder.Services.AddOptions(OpenIdConnectDefaults.AuthenticationScheme) .Configure((options, urlGenerator) => { diff --git a/backend/tests/Squidex.Data.Tests/EntityFramework/Domain/Contents/Text/EFTextIndexTests.cs b/backend/tests/Squidex.Data.Tests/EntityFramework/Domain/Contents/Text/EFTextIndexTests.cs index f6889fcf0..d50f31157 100644 --- a/backend/tests/Squidex.Data.Tests/EntityFramework/Domain/Contents/Text/EFTextIndexTests.cs +++ b/backend/tests/Squidex.Data.Tests/EntityFramework/Domain/Contents/Text/EFTextIndexTests.cs @@ -17,6 +17,8 @@ public abstract class EFTextIndexTests(ISqlFixture fixture) { public override bool SupportsQuerySyntax => false; + public override bool SupportsGeo => true; + public override async Task CreateSutAsync() { var sut = new EFTextIndex(fixture.DbContextFactory); diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Schemas/ArrayFieldTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Schemas/ArrayFieldTests.cs index a1f471ae0..89d66214e 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Schemas/ArrayFieldTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Model/Schemas/ArrayFieldTests.cs @@ -20,7 +20,7 @@ public class ArrayfieldTests { var field = CreateField(1); - var parent_1 = parent_0.AddField(field); + var parent_1 = parent_0.AddUserInfo(field); Assert.Empty(parent_0.Fields); Assert.Equal(field, parent_1.FieldsById[1]); @@ -29,7 +29,7 @@ public class ArrayfieldTests [Fact] public void Should_throw_exception_if_adding_field_with_name_that_already_exists() { - var parent_1 = parent_0.AddField(CreateField(1)); + var parent_1 = parent_0.AddUserInfo(CreateField(1)); Assert.Throws(() => parent_1.AddNumber(2, "myField1")); } @@ -37,7 +37,7 @@ public class ArrayfieldTests [Fact] public void Should_throw_exception_if_adding_field_with_id_that_already_exists() { - var parent_1 = parent_0.AddField(CreateField(1)); + var parent_1 = parent_0.AddUserInfo(CreateField(1)); Assert.Throws(() => parent_1.AddNumber(1, "myField2")); } @@ -45,7 +45,7 @@ public class ArrayfieldTests [Fact] public void Should_hide_field() { - var parent_1 = parent_0.AddField(CreateField(1)); + var parent_1 = parent_0.AddUserInfo(CreateField(1)); var parent_2 = parent_1.UpdateField(1, f => f.Hide()); var parent_3 = parent_2.UpdateField(1, f => f.Hide()); @@ -67,7 +67,7 @@ public class ArrayfieldTests [Fact] public void Should_show_field() { - var parent_1 = parent_0.AddField(CreateField(1)); + var parent_1 = parent_0.AddUserInfo(CreateField(1)); var parent_2 = parent_1.UpdateField(1, f => f.Hide()); var parent_3 = parent_2.UpdateField(1, f => f.Show()); @@ -90,7 +90,7 @@ public class ArrayfieldTests [Fact] public void Should_disable_field() { - var parent_1 = parent_0.AddField(CreateField(1)); + var parent_1 = parent_0.AddUserInfo(CreateField(1)); var parent_2 = parent_1.UpdateField(1, f => f.Disable()); var parent_3 = parent_2.UpdateField(1, f => f.Disable()); @@ -112,7 +112,7 @@ public class ArrayfieldTests [Fact] public void Should_enable_field() { - var parent_1 = parent_0.AddField(CreateField(1)); + var parent_1 = parent_0.AddUserInfo(CreateField(1)); var parent_2 = parent_1.UpdateField(1, f => f.Disable()); var parent_3 = parent_2.UpdateField(1, f => f.Enable()); @@ -144,7 +144,7 @@ public class ArrayfieldTests MinValue = 10, }; - var parent_1 = parent_0.AddField(CreateField(1)); + var parent_1 = parent_0.AddUserInfo(CreateField(1)); var parent_2 = parent_1.UpdateField(1, f => f.Update(properties1)); var parent_3 = parent_2.UpdateField(1, f => f.Update(properties2)); @@ -157,7 +157,7 @@ public class ArrayfieldTests [Fact] public void Should_throw_exception_if_updating_with_invalid_properties_type() { - var parent_1 = parent_0.AddField(CreateField(1)); + var parent_1 = parent_0.AddUserInfo(CreateField(1)); Assert.Throws(() => parent_1.UpdateField(1, f => f.Update(new StringFieldProperties()))); } @@ -173,7 +173,7 @@ public class ArrayfieldTests [Fact] public void Should_delete_field() { - var parent_1 = parent_0.AddField(CreateField(1)); + var parent_1 = parent_0.AddUserInfo(CreateField(1)); var parent_2 = parent_1.DeleteField(1); var parent_3 = parent_2.DeleteField(1); @@ -197,9 +197,9 @@ public class ArrayfieldTests var field2 = CreateField(2); var field3 = CreateField(3); - var parent_1 = parent_0.AddField(field1); - var parent_2 = parent_1.AddField(field2); - var parent_3 = parent_2.AddField(field3); + var parent_1 = parent_0.AddUserInfo(field1); + var parent_2 = parent_1.AddUserInfo(field2); + var parent_3 = parent_2.AddUserInfo(field3); var parent_4 = parent_3.ReorderFields([3, 2, 1]); var parent_5 = parent_4.ReorderFields([3, 2, 1]); @@ -214,8 +214,8 @@ public class ArrayfieldTests var field1 = CreateField(1); var field2 = CreateField(2); - var parent_1 = parent_0.AddField(field1); - var parent_2 = parent_1.AddField(field2); + var parent_1 = parent_0.AddUserInfo(field1); + var parent_2 = parent_1.AddUserInfo(field2); Assert.Throws(() => parent_2.ReorderFields([1])); } @@ -226,8 +226,8 @@ public class ArrayfieldTests var field1 = CreateField(1); var field2 = CreateField(2); - var parent_1 = parent_0.AddField(field1); - var parent_2 = parent_1.AddField(field2); + var parent_1 = parent_0.AddUserInfo(field1); + var parent_2 = parent_1.AddUserInfo(field2); Assert.Throws(() => parent_2.ReorderFields([1, 4])); } diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/DefaultValueFactoryTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/DefaultValueFactoryTests.cs index 1f948bfae..20f9add33 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/DefaultValueFactoryTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ConvertContent/DefaultValueFactoryTests.cs @@ -316,6 +316,26 @@ public class DefaultValueFactoryTests Assert.Equal(new JsonArray(), DefaultValueFactory.CreateDefaultValue(field, now, language.Iso2Code)); } + [Fact] + public void Should_get_default_value_from_userinfo_field_if_role_is_not_set() + { + var field = + Fields.UserInfo(1, "1", Partitioning.Invariant, + new UserInfoFieldProperties()); + + Assert.Equal(JsonValue.Null, DefaultValueFactory.CreateDefaultValue(field, now, language.Iso2Code)); + } + + [Fact] + public void Should_get_default_value_from_userinfo_field_if_role_is_set() + { + var field = + Fields.UserInfo(1, "1", Partitioning.Invariant, + new UserInfoFieldProperties { DefaultRole = "myRole" }); + + Assert.IsType(DefaultValueFactory.CreateDefaultValue(field, now, language.Iso2Code).Value); + } + private Instant FutureDays(int days) { return now.WithoutMs().Plus(Duration.FromDays(days)); diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/GeolocationFieldTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/GeolocationFieldTests.cs index a3dfb6d32..dc9051cef 100644 --- a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/GeolocationFieldTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/GeolocationFieldTests.cs @@ -61,6 +61,17 @@ public class GeolocationFieldTests : IClassFixture Assert.Empty(errors); } + [Fact] + public async Task Should_add_error_if_geolocation_is_not_an_object() + { + var sut = Field(new GeolocationFieldProperties { IsRequired = true }); + + await sut.ValidateAsync(JsonValue.True, errors); + + errors.Should().BeEquivalentTo( + ["Invalid json type, expected latitude/longitude object."]); + } + [Fact] public async Task Should_add_error_if_geolocation_has_invalid_latitude() { diff --git a/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/UserInfoFieldPropertiesTests.cs b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/UserInfoFieldPropertiesTests.cs new file mode 100644 index 000000000..7bf8d34b3 --- /dev/null +++ b/backend/tests/Squidex.Domain.Apps.Core.Tests/Operations/ValidateContent/UserInfoFieldPropertiesTests.cs @@ -0,0 +1,99 @@ +// ========================================================================== +// Squidex Headless CMS +// ========================================================================== +// Copyright (c) Squidex UG (haftungsbeschraenkt) +// All rights reserved. Licensed under the MIT license. +// ========================================================================== + +using Squidex.Domain.Apps.Core.Schemas; +using Squidex.Domain.Apps.Core.TestHelpers; +using Squidex.Infrastructure.Json.Objects; + +namespace Squidex.Domain.Apps.Core.Operations.ValidateContent; + +public class UserInfoFieldPropertiesTests : IClassFixture +{ + private readonly List errors = []; + + [Fact] + public void Should_instantiate_field() + { + var sut = Field(new UserInfoFieldProperties()); + + Assert.Equal("myUserInfo", sut.Name); + } + + [Fact] + public async Task Should_not_add_error_if_userinfo_is_valid_null() + { + var sut = Field(new UserInfoFieldProperties()); + + await sut.ValidateAsync(JsonValue.Null, errors); + + Assert.Empty(errors); + } + + [Fact] + public async Task Should_not_add_error_if_userinfo_is_valid() + { + var sut = Field(new UserInfoFieldProperties()); + + await sut.ValidateAsync(CreateValue("Key", "Role"), errors); + + Assert.Empty(errors); + } + + [Fact] + public async Task Should_add_error_if_userinfo_is_not_an_object() + { + var sut = Field(new UserInfoFieldProperties { IsRequired = true }); + + await sut.ValidateAsync(JsonValue.True, errors); + + errors.Should().BeEquivalentTo( + ["Invalid json type, expected apiKey+role object."]); + } + + [Fact] + public async Task Should_add_error_if_userinfo_has_invalid_role() + { + var sut = Field(new UserInfoFieldProperties { IsRequired = true }); + + await sut.ValidateAsync(CreateValue("Key", null), errors); + + errors.Should().BeEquivalentTo( + ["Role must be defined."]); + } + + [Fact] + public async Task Should_add_error_if_userinfo_has_invalid_apiKey() + { + var sut = Field(new UserInfoFieldProperties { IsRequired = true }); + + await sut.ValidateAsync(CreateValue(null, "Role"), errors); + + errors.Should().BeEquivalentTo( + ["ApiKey must be defined."]); + } + + [Fact] + public async Task Should_add_error_if_userinfo_is_required() + { + var sut = Field(new UserInfoFieldProperties { IsRequired = true }); + + await sut.ValidateAsync(JsonValue.Null, errors); + + errors.Should().BeEquivalentTo( + ["Field is required."]); + } + + private static JsonValue CreateValue(string? apiKey, string? role) + { + return JsonValue.Object().Add("apiKey", apiKey).Add("role", role); + } + + private static RootField Field(UserInfoFieldProperties properties) + { + return Fields.UserInfo(1, "myUserInfo", Partitioning.Invariant, properties); + } +} diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/TestContent.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/TestContent.cs index 7193e0cd2..ce14e684d 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/TestContent.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/TestContent.cs @@ -136,6 +136,9 @@ public static class TestContent text } } + myUserInfo { + iv + } }"; public const string AllFlatFields = @" @@ -225,6 +228,7 @@ public static class TestContent markdown text } + myUserInfo }"; public static EnrichedContent Create(DomainId id, ContentData? data = null) @@ -340,7 +344,12 @@ public static class TestContent .Add("content", JsonValue.Array( JsonValue.Object() .Add("type", "text") - .Add("text", "Rich Text"))))); + .Add("text", "Rich Text"))))) + .AddField("my-user-info", + new ContentFieldData() + .AddInvariant(JsonValue.Object() + .Add("apiKey", "MyKey") + .Add("role", "MyRole"))); var content = new EnrichedContent { @@ -621,6 +630,10 @@ public static class TestContent }, }, }, + ["myUserInfo"] = new + { + iv = new { apiKey = "MyKey", role = "MyRole" }, + }, }; return actual; @@ -814,6 +827,10 @@ public static class TestContent text = "Rich Text", }, }, + ["myUserInfo"] = new + { + iv = new { apiKey = "MyKey", role = "MyRole" }, + }, }; return actual; @@ -956,6 +973,7 @@ public static class TestContent markdown = "# Rich Text", text = "Rich Text", }, + ["myUserInfo"] = new { apiKey = "MyKey", role = "MyRole" }, }; return actual; diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/TestSchemas.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/TestSchemas.cs index 0bf89e295..903d1350c 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/TestSchemas.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/GraphQL/TestSchemas.cs @@ -136,6 +136,8 @@ public static class TestSchemas new StringFieldProperties { IsEmbeddable = true, SchemaIds = ReadonlyList.Create(Reference1.Id, Reference2.Id) }) .AddRichText(18, "my-richtext", Partitioning.Invariant, new RichTextFieldProperties { SchemaIds = ReadonlyList.Create(Reference1.Id, Reference2.Id) }) + .AddUserInfo(19, "my-user-info", Partitioning.Invariant, + new UserInfoFieldProperties()) .AddArray(100, "my-array", Partitioning.Invariant, f => f .AddBoolean(121, "nested-boolean", new BooleanFieldProperties()) diff --git a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/TextIndexerTests.cs b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/TextIndexerTests.cs index c534cc718..5f3fae479 100644 --- a/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/TextIndexerTests.cs +++ b/backend/tests/Squidex.Domain.Apps.Entities.Tests/Contents/Text/TextIndexerTests.cs @@ -114,6 +114,24 @@ public abstract class TextIndexerTests : GivenContext await SearchGeo(expected: null, "other.iv", 51.48596429889613, 12.102629469505713); } + [Fact] + public async Task Should_search_by_userinfo() + { + var field = Guid.NewGuid().ToString(); + + // With same ApiKey + await CreateUserInfoAsync(Ids1[0], field, "Key1", "Role1"); + + // Other ApiKey + await CreateUserInfoAsync(Ids2[0], field, "Key2", "Role2"); + + // With same ApiKey + await SearchApiKey(Ids1[0], "Key1"); + + // Wrong ApiKey + await SearchApiKey(null, "Key3"); + } + [Fact] public async Task Should_search_by_app() { @@ -356,6 +374,13 @@ public abstract class TextIndexerTests : GivenContext return UpdateAsync(id, new ContentCreated { Data = data }); } + protected Task CreateUserInfoAsync(DomainId id, string field, string apiKey, string role) + { + var data = UserInfoData(field, apiKey, role); + + return UpdateAsync(id, new ContentCreated { Data = data }); + } + protected Task UpdateTextAsync(DomainId id, string language, string text) { var data = TextData(language, text); @@ -422,6 +447,14 @@ public abstract class TextIndexerTests : GivenContext .AddInvariant(JsonValue.Object().Add("latitude", latitude).Add("longitude", longitude))); } + private static ContentData UserInfoData(string field, string apiKey, string role) + { + return new ContentData() + .AddField(field, + new ContentFieldData() + .AddInvariant(JsonValue.Object().Add("apiKey", apiKey).Add("role", role))); + } + private static ContentData GeoJsonData(string field, double latitude, double longitude) { return new ContentData() @@ -435,18 +468,34 @@ public abstract class TextIndexerTests : GivenContext .Add(latitude)))); } - protected async Task SearchGeo(List? expected, string field, double latitude, double longitude, SearchScope target = SearchScope.All) + protected async Task SearchApiKey( + DomainId? expected, + string apiKey, + SearchScope target = SearchScope.All) { - var query = new GeoQuery(SchemaId.Id, field, latitude, longitude, 1000, 1000) - { - SchemaId = SchemaId.Id, - }; + var query = new ApiKeyQuery(apiKey); + + var actual = await SearchAsync(i => i.FindUserInfo(App, query, target, default), x => x?.ContentId == expected); + Assert.Equal(expected, actual?.ContentId); + } + + protected async Task SearchGeo( + List? expected, + string field, + double latitude, + double longitude, + SearchScope target = SearchScope.All) + { + var query = new GeoQuery(SchemaId.Id, field, latitude, longitude, 1000, 1000); var actual = await SearchAsync(i => i.SearchAsync(App, query, target, default), x => IsExpected(x, expected)); AssertIds(actual, expected); } - protected async Task SearchText(List? expected, string text, SearchScope target = SearchScope.All) + protected async Task SearchText( + List? expected, + string text, + SearchScope target = SearchScope.All) { var query = new TextQuery(text, 1000) { diff --git a/frontend/cache.json b/frontend/cache.json new file mode 100644 index 000000000..42c22156b --- /dev/null +++ b/frontend/cache.json @@ -0,0 +1,23838 @@ +{ + "x-generator": "NSwag v14.1.0.0 (NJsonSchema v11.0.2.0 (Newtonsoft.Json v13.0.0.0))", + "openapi": "3.0.0", + "info": { + "title": "Squidex API", + "version": "1.0.0.0", + "x-logo": { + "url": "https://localhost:5001/images/logo-white.png", + "backgroundStyle": "", + "backgroundColor": "#3f83df" + } + }, + "servers": [ + { + "url": "https://localhost:5001" + } + ], + "paths": { + "/api/user-management": { + "get": { + "tags": [ + "UserManagement" + ], + "summary": "Get users by query.", + "operationId": "UserManagement_GetUsers", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "Optional query to search by email address or username.", + "schema": { + "type": "string", + "nullable": true + }, + "x-position": 1 + }, + { + "name": "skip", + "in": "query", + "description": "The number of users to skip.", + "schema": { + "type": "integer", + "format": "int32", + "default": 0 + }, + "x-position": 2 + }, + { + "name": "take", + "in": "query", + "description": "The number of users to return.", + "schema": { + "type": "integer", + "format": "int32", + "default": 10 + }, + "x-position": 3 + } + ], + "responses": { + "200": { + "description": "Users returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UsersDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.admin.users.read" + ] + } + ] + }, + "post": { + "tags": [ + "UserManagement" + ], + "summary": "Create a new user.", + "operationId": "UserManagement_PostUser", + "requestBody": { + "x-name": "request", + "description": "The user object that needs to be added.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateUserDto" + } + } + }, + "required": true, + "x-position": 1 + }, + "responses": { + "201": { + "description": "User created.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserDto" + } + } + } + }, + "400": { + "description": "User request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.admin.users.create" + ] + } + ] + } + }, + "/api/user-management/{id}": { + "get": { + "tags": [ + "UserManagement" + ], + "summary": "Get a user by ID.", + "operationId": "UserManagement_GetUser", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the user.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "responses": { + "200": { + "description": "User returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserDto" + } + } + } + }, + "404": { + "description": "User not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.admin.users.read" + ] + } + ] + }, + "put": { + "tags": [ + "UserManagement" + ], + "summary": "Update a user.", + "operationId": "UserManagement_PutUser", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the user.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "requestBody": { + "x-name": "request", + "description": "The user object that needs to be updated.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateUserDto" + } + } + }, + "required": true, + "x-position": 2 + }, + "responses": { + "200": { + "description": "User created.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserDto" + } + } + } + }, + "400": { + "description": "User request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "User not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.admin.users.update" + ] + } + ] + }, + "delete": { + "tags": [ + "UserManagement" + ], + "summary": "Delete a User.", + "operationId": "UserManagement_DeleteUser", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the user to delete.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "responses": { + "204": { + "description": "User deleted." + }, + "403": { + "description": "User is the current user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "User not found." + }, + "400": { + "description": "Validation error.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.admin.users.unlock" + ] + } + ] + } + }, + "/api/user-management/{id}/lock": { + "put": { + "tags": [ + "UserManagement" + ], + "summary": "Lock a user.", + "operationId": "UserManagement_LockUser", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the user to lock.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "responses": { + "200": { + "description": "User locked.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserDto" + } + } + } + }, + "403": { + "description": "User is the current user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "User not found." + }, + "400": { + "description": "Validation error.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.admin.users.lock" + ] + } + ] + } + }, + "/api/user-management/{id}/unlock": { + "put": { + "tags": [ + "UserManagement" + ], + "summary": "Unlock a user.", + "operationId": "UserManagement_UnlockUser", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the user to unlock.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "responses": { + "200": { + "description": "User unlocked.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserDto" + } + } + } + }, + "403": { + "description": "User is the current user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "User not found." + }, + "400": { + "description": "Validation error.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.admin.users.unlock" + ] + } + ] + } + }, + "/api": { + "get": { + "tags": [ + "Users" + ], + "summary": "Get the user resources.", + "operationId": "Users_GetUserResources", + "responses": { + "200": { + "description": "User resources returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ResourcesDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [] + } + ] + } + }, + "/api/user": { + "post": { + "tags": [ + "Users" + ], + "summary": "Update the user profile.", + "operationId": "Users_PostUser", + "requestBody": { + "x-name": "request", + "description": "The values to update.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateProfileDto" + } + } + }, + "required": true, + "x-position": 1 + }, + "responses": { + "204": { + "description": "User updated." + }, + "400": { + "description": "Validation error.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [] + } + ] + } + }, + "/api/users": { + "get": { + "tags": [ + "Users" + ], + "summary": "Get users by query.", + "description": "Search the user by query that contains the email address or the part of the email address.", + "operationId": "Users_GetUsers", + "parameters": [ + { + "name": "query", + "in": "query", + "description": "The query to search the user by email address. Case invariant.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "responses": { + "200": { + "description": "Users returned.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UserDto" + } + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [] + } + ] + } + }, + "/api/users/{id}": { + "get": { + "tags": [ + "Users" + ], + "summary": "Get user by id.", + "operationId": "Users_GetUser", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the user (GUID).", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "responses": { + "200": { + "description": "User found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UserDto" + } + } + } + }, + "404": { + "description": "User not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [] + } + ] + } + }, + "/api/users/{id}/picture": { + "get": { + "tags": [ + "Users" + ], + "summary": "Get user picture by id.", + "operationId": "Users_GetUserPicture", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the user (GUID).", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "responses": { + "200": { + "description": "User found and image or fallback returned.", + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "404": { + "description": "User not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + } + } + }, + "/api/apps/{app}/translations": { + "post": { + "tags": [ + "Translations" + ], + "summary": "Translate a text.", + "operationId": "Translations_PostTranslation", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "requestBody": { + "x-name": "request", + "description": "The translation request.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TranslateDto" + } + } + }, + "required": true, + "x-position": 2 + }, + "responses": { + "200": { + "description": "Text translated.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TranslationDto" + } + } + } + }, + "400": { + "description": "Validation error.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.translate" + ] + } + ] + } + }, + "/api/templates": { + "get": { + "tags": [ + "Templates" + ], + "summary": "Get all templates.", + "operationId": "Templates_GetTemplates", + "parameters": [ + { + "name": "includeDetails", + "in": "query", + "description": "Also include the details.", + "schema": { + "type": "boolean" + }, + "x-position": 1 + } + ], + "responses": { + "200": { + "description": "Templates returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TemplatesDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [] + } + ] + } + }, + "/api/templates/{name}": { + "get": { + "tags": [ + "Templates" + ], + "summary": "Get template details.", + "operationId": "Templates_GetTemplate", + "parameters": [ + { + "name": "name", + "in": "path", + "required": true, + "description": "The name of the template.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "responses": { + "200": { + "description": "Template returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TemplateDetailsDto" + } + } + } + }, + "404": { + "description": "Template not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [] + } + ] + } + }, + "/api/teams/{team}/contributors": { + "get": { + "tags": [ + "Teams" + ], + "summary": "Get team contributors.", + "operationId": "TeamContributors_GetContributors", + "parameters": [ + { + "name": "team", + "in": "path", + "required": true, + "description": "The ID of the team.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "responses": { + "200": { + "description": "Contributors returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContributorsDto" + } + } + } + }, + "404": { + "description": "Team not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.teams.{team}.contributors.read" + ] + } + ] + }, + "post": { + "tags": [ + "Teams" + ], + "summary": "Assign contributor to team.", + "operationId": "TeamContributors_PostContributor", + "parameters": [ + { + "name": "team", + "in": "path", + "required": true, + "description": "The ID of the team.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "requestBody": { + "x-name": "request", + "description": "Contributor object that needs to be added to the team.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AssignContributorDto" + } + } + }, + "required": true, + "x-position": 2 + }, + "responses": { + "201": { + "description": "Contributor assigned to team.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContributorsDto" + } + } + } + }, + "400": { + "description": "Contributor request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Team not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.teams.{team}.contributors.assign" + ] + } + ] + } + }, + "/api/teams/{team}/contributors/me": { + "delete": { + "tags": [ + "Teams" + ], + "summary": "Remove yourself.", + "operationId": "TeamContributors_DeleteMyself", + "parameters": [ + { + "name": "team", + "in": "path", + "required": true, + "description": "The ID of the team.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "responses": { + "200": { + "description": "Contributor removed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContributorsDto" + } + } + } + }, + "404": { + "description": "Contributor or team not found." + }, + "400": { + "description": "Validation error.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [] + } + ] + } + }, + "/api/teams/{team}/contributors/{id}": { + "delete": { + "tags": [ + "Teams" + ], + "summary": "Remove contributor.", + "operationId": "TeamContributors_DeleteContributor", + "parameters": [ + { + "name": "team", + "in": "path", + "required": true, + "description": "The ID of the team.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the contributor.", + "schema": { + "type": "string" + }, + "x-position": 2 + } + ], + "responses": { + "200": { + "description": "Contributor removed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContributorsDto" + } + } + } + }, + "404": { + "description": "Contributor or team not found." + }, + "400": { + "description": "Validation error.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.teams.{team}.contributors.revoke" + ] + } + ] + } + }, + "/api/teams": { + "get": { + "tags": [ + "Teams" + ], + "summary": "Get your teams.", + "description": "You can only retrieve the list of teams when you are authenticated as a user (OpenID implicit flow).\nYou will retrieve all teams, where you are assigned as a contributor.", + "operationId": "Teams_GetTeams", + "responses": { + "200": { + "description": "Teams returned.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TeamDto" + } + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [] + } + ] + }, + "post": { + "tags": [ + "Teams" + ], + "summary": "Create a new team.", + "description": "You can only create an team when you are authenticated as a user (OpenID implicit flow).\nYou will be assigned as owner of the new team automatically.", + "operationId": "Teams_PostTeam", + "requestBody": { + "x-name": "request", + "description": "The team object that needs to be added to Squidex.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateTeamDto" + } + } + }, + "required": true, + "x-position": 1 + }, + "responses": { + "201": { + "description": "Team created.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TeamDto" + } + } + } + }, + "400": { + "description": "Team request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [] + } + ] + } + }, + "/api/teams/{team}": { + "get": { + "tags": [ + "Teams" + ], + "summary": "Get an team by ID.", + "operationId": "Teams_GetTeam", + "parameters": [ + { + "name": "team", + "in": "path", + "required": true, + "description": "The ID of the team.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "responses": { + "200": { + "description": "Teams returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TeamDto" + } + } + } + }, + "404": { + "description": "Team not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [] + } + ] + }, + "put": { + "tags": [ + "Teams" + ], + "summary": "Update the team.", + "operationId": "Teams_PutTeam", + "parameters": [ + { + "name": "team", + "in": "path", + "required": true, + "description": "The ID of the team to update.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "requestBody": { + "x-name": "request", + "description": "The values to update.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateTeamDto" + } + } + }, + "required": true, + "x-position": 2 + }, + "responses": { + "200": { + "description": "Team updated.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TeamDto" + } + } + } + }, + "400": { + "description": "Team request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Team not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.teams.{team}.update" + ] + } + ] + }, + "delete": { + "tags": [ + "Teams" + ], + "summary": "Delete the team.", + "operationId": "Teams_DeleteTeam", + "parameters": [ + { + "name": "team", + "in": "path", + "required": true, + "description": "The ID of the team to delete.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "responses": { + "204": { + "description": "Team deleted." + }, + "404": { + "description": "Team not found." + }, + "400": { + "description": "Validation error.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.teams.{team}.delete" + ] + } + ] + } + }, + "/api/teams/{team}/auth": { + "get": { + "tags": [ + "Teams" + ], + "summary": "Get the team auth settings.", + "operationId": "Teams_GetTeamAuth", + "parameters": [ + { + "name": "team", + "in": "path", + "required": true, + "description": "The ID of the team.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "responses": { + "200": { + "description": "Teams returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthSchemeResponseDto" + } + } + } + }, + "404": { + "description": "Team not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.teams.{team}.auth.read" + ] + } + ] + }, + "put": { + "tags": [ + "Teams" + ], + "summary": "Update the team auth.", + "operationId": "Teams_PutTeamAuth", + "parameters": [ + { + "name": "team", + "in": "path", + "required": true, + "description": "The ID of the team to update.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "requestBody": { + "x-name": "request", + "description": "The values to update.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthSchemeValueDto" + } + } + }, + "required": true, + "x-position": 2 + }, + "responses": { + "200": { + "description": "Team updated.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthSchemeResponseDto" + } + } + } + }, + "400": { + "description": "Team request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Team not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.teams.{team}.auth.change" + ] + } + ] + } + }, + "/api/apps/{app}/usages/log": { + "get": { + "tags": [ + "Statistics" + ], + "summary": "Get api calls as log file.", + "operationId": "Usages_GetLog", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "responses": { + "200": { + "description": "Usage tracking results returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LogDownloadDto" + } + } + } + }, + "404": { + "description": "App not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.usage" + ] + } + ] + } + }, + "/api/apps/{app}/usages/calls/{fromDate}/{toDate}": { + "get": { + "tags": [ + "Statistics" + ], + "summary": "Get api calls in date range for app.", + "operationId": "Usages_GetUsages", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "fromDate", + "in": "path", + "required": true, + "description": "The from date.", + "schema": { + "type": "string", + "format": "date" + }, + "x-position": 2 + }, + { + "name": "toDate", + "in": "path", + "required": true, + "description": "The to date.", + "schema": { + "type": "string", + "format": "date" + }, + "x-position": 3 + } + ], + "responses": { + "200": { + "description": "API call returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CallsUsageDto" + } + } + } + }, + "404": { + "description": "App not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.usage" + ] + } + ] + } + }, + "/api/teams/{team}/usages/calls/{fromDate}/{toDate}": { + "get": { + "tags": [ + "Statistics" + ], + "summary": "Get api calls in date range for team.", + "operationId": "Usages_GetUsagesForTeam", + "parameters": [ + { + "name": "team", + "in": "path", + "required": true, + "description": "The name of the team.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "fromDate", + "in": "path", + "required": true, + "description": "The from date.", + "schema": { + "type": "string", + "format": "date" + }, + "x-position": 2 + }, + { + "name": "toDate", + "in": "path", + "required": true, + "description": "The to date.", + "schema": { + "type": "string", + "format": "date" + }, + "x-position": 3 + } + ], + "responses": { + "200": { + "description": "API call returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CallsUsageDto" + } + } + } + }, + "404": { + "description": "Team not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.teams.{team}.usage" + ] + } + ] + } + }, + "/api/apps/{app}/usages/storage/today": { + "get": { + "tags": [ + "Statistics" + ], + "summary": "Get total asset size for app.", + "operationId": "Usages_GetCurrentStorageSize", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "responses": { + "200": { + "description": "Storage usage returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CurrentStorageDto" + } + } + } + }, + "404": { + "description": "App not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.usage" + ] + } + ] + } + }, + "/api/teams/{team}/usages/storage/today": { + "get": { + "tags": [ + "Statistics" + ], + "summary": "Get total asset size for team.", + "operationId": "Usages_GetTeamCurrentStorageSizeForTeam", + "parameters": [ + { + "name": "team", + "in": "path", + "required": true, + "description": "The ID of the team.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "responses": { + "200": { + "description": "Storage usage returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CurrentStorageDto" + } + } + } + }, + "404": { + "description": "Team not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.teams.{team}.usage" + ] + } + ] + } + }, + "/api/apps/{app}/usages/storage/{fromDate}/{toDate}": { + "get": { + "tags": [ + "Statistics" + ], + "summary": "Get asset usage by date for app.", + "operationId": "Usages_GetStorageSizes", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "fromDate", + "in": "path", + "required": true, + "description": "The from date.", + "schema": { + "type": "string", + "format": "date" + }, + "x-position": 2 + }, + { + "name": "toDate", + "in": "path", + "required": true, + "description": "The to date.", + "schema": { + "type": "string", + "format": "date" + }, + "x-position": 3 + } + ], + "responses": { + "200": { + "description": "Storage usage returned.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/StorageUsagePerDateDto" + } + } + } + } + }, + "404": { + "description": "App not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.usage" + ] + } + ] + } + }, + "/api/teams/{team}/usages/storage/{fromDate}/{toDate}": { + "get": { + "tags": [ + "Statistics" + ], + "summary": "Get asset usage by date for team.", + "operationId": "Usages_GetStorageSizesForTeam", + "parameters": [ + { + "name": "team", + "in": "path", + "required": true, + "description": "The ID of the team.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "fromDate", + "in": "path", + "required": true, + "description": "The from date.", + "schema": { + "type": "string", + "format": "date" + }, + "x-position": 2 + }, + { + "name": "toDate", + "in": "path", + "required": true, + "description": "The to date.", + "schema": { + "type": "string", + "format": "date" + }, + "x-position": 3 + } + ], + "responses": { + "200": { + "description": "Storage usage returned.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/StorageUsagePerDateDto" + } + } + } + } + }, + "404": { + "description": "Team not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.teams.{team}.usage" + ] + } + ] + } + }, + "/api/apps/{app}/search": { + "get": { + "tags": [ + "Search" + ], + "summary": "Get search results.", + "operationId": "Search_GetSearchResults", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "query", + "in": "query", + "description": "The search query.", + "schema": { + "type": "string", + "nullable": true + }, + "x-position": 2 + } + ], + "responses": { + "200": { + "description": "Search results returned.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SearchResultDto" + } + } + } + } + }, + "404": { + "description": "App not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.search" + ] + } + ] + } + }, + "/api/apps/{app}/schemas/{schema}/fields": { + "post": { + "tags": [ + "Schemas" + ], + "summary": "Add a schema field.", + "operationId": "SchemaFields_PostField", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "schema", + "in": "path", + "required": true, + "description": "The name of the schema.", + "schema": { + "type": "string" + }, + "x-position": 2 + } + ], + "requestBody": { + "x-name": "request", + "description": "The field object that needs to be added to the schema.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AddFieldDto" + } + } + }, + "required": true, + "x-position": 3 + }, + "responses": { + "201": { + "description": "Schema field created.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchemaDto" + } + } + } + }, + "400": { + "description": "Schema request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Schema or app not found." + }, + "409": { + "description": "Schema field name already in use.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.schemas.{schema}.update" + ] + } + ] + } + }, + "/api/apps/{app}/schemas/{schema}/fields/{parentId}/nested": { + "post": { + "tags": [ + "Schemas" + ], + "summary": "Add a nested field.", + "operationId": "SchemaFields_PostNestedField", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "schema", + "in": "path", + "required": true, + "description": "The name of the schema.", + "schema": { + "type": "string" + }, + "x-position": 2 + }, + { + "name": "parentId", + "in": "path", + "required": true, + "description": "The parent field id.", + "schema": { + "type": "integer", + "format": "int64" + }, + "x-position": 3 + } + ], + "requestBody": { + "x-name": "request", + "description": "The field object that needs to be added to the schema.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AddFieldDto" + } + } + }, + "required": true, + "x-position": 4 + }, + "responses": { + "201": { + "description": "Schema field created.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchemaDto" + } + } + } + }, + "400": { + "description": "Schema request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "409": { + "description": "Schema field name already in use.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Schema, field or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.schemas.{schema}.update" + ] + } + ] + } + }, + "/api/apps/{app}/schemas/{schema}/fields/ui": { + "put": { + "tags": [ + "Schemas" + ], + "summary": "Configure UI fields.", + "operationId": "SchemaFields_PutSchemaUIFields", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "schema", + "in": "path", + "required": true, + "description": "The name of the schema.", + "schema": { + "type": "string" + }, + "x-position": 2 + } + ], + "requestBody": { + "x-name": "request", + "description": "The request that contains the field names.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ConfigureUIFieldsDto" + } + } + }, + "required": true, + "x-position": 3 + }, + "responses": { + "200": { + "description": "Schema UI fields defined.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchemaDto" + } + } + } + }, + "400": { + "description": "Schema request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Schema or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.schemas.{schema}.update" + ] + } + ] + } + }, + "/api/apps/{app}/schemas/{schema}/fields/ordering": { + "put": { + "tags": [ + "Schemas" + ], + "summary": "Reorder all fields.", + "operationId": "SchemaFields_PutSchemaFieldOrdering", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "schema", + "in": "path", + "required": true, + "description": "The name of the schema.", + "schema": { + "type": "string" + }, + "x-position": 2 + } + ], + "requestBody": { + "x-name": "request", + "description": "The request that contains the field ids.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReorderFieldsDto" + } + } + }, + "required": true, + "x-position": 3 + }, + "responses": { + "200": { + "description": "Schema fields reordered.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchemaDto" + } + } + } + }, + "400": { + "description": "Schema request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Schema or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.schemas.{schema}.update" + ] + } + ] + } + }, + "/api/apps/{app}/schemas/{schema}/fields/{parentId}/nested/ordering": { + "put": { + "tags": [ + "Schemas" + ], + "summary": "Reorder all nested fields.", + "operationId": "SchemaFields_PutNestedFieldOrdering", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "schema", + "in": "path", + "required": true, + "description": "The name of the schema.", + "schema": { + "type": "string" + }, + "x-position": 2 + }, + { + "name": "parentId", + "in": "path", + "required": true, + "description": "The parent field id.", + "schema": { + "type": "integer", + "format": "int64" + }, + "x-position": 3 + } + ], + "requestBody": { + "x-name": "request", + "description": "The request that contains the field ids.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ReorderFieldsDto" + } + } + }, + "required": true, + "x-position": 4 + }, + "responses": { + "200": { + "description": "Schema fields reordered.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchemaDto" + } + } + } + }, + "400": { + "description": "Schema field request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Schema, field or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.schemas.{schema}.update" + ] + } + ] + } + }, + "/api/apps/{app}/schemas/{schema}/fields/{id}": { + "put": { + "tags": [ + "Schemas" + ], + "summary": "Update a schema field.", + "operationId": "SchemaFields_PutField", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "schema", + "in": "path", + "required": true, + "description": "The name of the schema.", + "schema": { + "type": "string" + }, + "x-position": 2 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the field to update.", + "schema": { + "type": "integer", + "format": "int64" + }, + "x-position": 3 + } + ], + "requestBody": { + "x-name": "request", + "description": "The field object that needs to be added to the schema.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateFieldDto" + } + } + }, + "required": true, + "x-position": 4 + }, + "responses": { + "200": { + "description": "Schema field updated.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchemaDto" + } + } + } + }, + "400": { + "description": "Schema field request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Schema, field or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.schemas.{schema}.update" + ] + } + ] + }, + "delete": { + "tags": [ + "Schemas" + ], + "summary": "Delete a schema field.", + "operationId": "SchemaFields_DeleteField", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "schema", + "in": "path", + "required": true, + "description": "The name of the schema.", + "schema": { + "type": "string" + }, + "x-position": 2 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the field to disable.", + "schema": { + "type": "integer", + "format": "int64" + }, + "x-position": 3 + } + ], + "responses": { + "200": { + "description": "Schema field deleted.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchemaDto" + } + } + } + }, + "400": { + "description": "Schema field request not valid or field locked.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Schema, field or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.schemas.{schema}.update" + ] + } + ] + } + }, + "/api/apps/{app}/schemas/{schema}/fields/{parentId}/nested/{id}": { + "put": { + "tags": [ + "Schemas" + ], + "summary": "Update a nested field.", + "operationId": "SchemaFields_PutNestedField", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "schema", + "in": "path", + "required": true, + "description": "The name of the schema.", + "schema": { + "type": "string" + }, + "x-position": 2 + }, + { + "name": "parentId", + "in": "path", + "required": true, + "description": "The parent field id.", + "schema": { + "type": "integer", + "format": "int64" + }, + "x-position": 3 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the field to update.", + "schema": { + "type": "integer", + "format": "int64" + }, + "x-position": 4 + } + ], + "requestBody": { + "x-name": "request", + "description": "The field object that needs to be added to the schema.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateFieldDto" + } + } + }, + "required": true, + "x-position": 5 + }, + "responses": { + "200": { + "description": "Schema field updated.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchemaDto" + } + } + } + }, + "400": { + "description": "Schema field request not valid or field locked.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Schema, field or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.schemas.{schema}.update" + ] + } + ] + }, + "delete": { + "tags": [ + "Schemas" + ], + "summary": "Delete a nested field.", + "operationId": "SchemaFields_DeleteNestedField", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "schema", + "in": "path", + "required": true, + "description": "The name of the schema.", + "schema": { + "type": "string" + }, + "x-position": 2 + }, + { + "name": "parentId", + "in": "path", + "required": true, + "description": "The parent field id.", + "schema": { + "type": "integer", + "format": "int64" + }, + "x-position": 3 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the field to disable.", + "schema": { + "type": "integer", + "format": "int64" + }, + "x-position": 4 + } + ], + "responses": { + "200": { + "description": "Schema field deleted.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchemaDto" + } + } + } + }, + "400": { + "description": "Schema field request not valid or field locked.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Schema, field or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.schemas.{schema}.update" + ] + } + ] + } + }, + "/api/apps/{app}/schemas/{schema}/fields/{id}/lock": { + "put": { + "tags": [ + "Schemas" + ], + "summary": "Lock a schema field.", + "description": "A locked field cannot be updated or deleted.", + "operationId": "SchemaFields_LockField", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "schema", + "in": "path", + "required": true, + "description": "The name of the schema.", + "schema": { + "type": "string" + }, + "x-position": 2 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the field to lock.", + "schema": { + "type": "integer", + "format": "int64" + }, + "x-position": 3 + } + ], + "responses": { + "200": { + "description": "Schema field shown.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchemaDto" + } + } + } + }, + "400": { + "description": "Schema field request not valid or field locked.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Schema, field or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.schemas.{schema}.update" + ] + } + ] + } + }, + "/api/apps/{app}/schemas/{schema}/fields/{parentId}/nested/{id}/lock": { + "put": { + "tags": [ + "Schemas" + ], + "summary": "Lock a nested field.", + "description": "A locked field cannot be edited or deleted.", + "operationId": "SchemaFields_LockNestedField", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "schema", + "in": "path", + "required": true, + "description": "The name of the schema.", + "schema": { + "type": "string" + }, + "x-position": 2 + }, + { + "name": "parentId", + "in": "path", + "required": true, + "description": "The parent field id.", + "schema": { + "type": "integer", + "format": "int64" + }, + "x-position": 3 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the field to lock.", + "schema": { + "type": "integer", + "format": "int64" + }, + "x-position": 4 + } + ], + "responses": { + "200": { + "description": "Schema field hidden.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchemaDto" + } + } + } + }, + "400": { + "description": "Schema field request not valid or field locked.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Field, schema, or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.schemas.{schema}.update" + ] + } + ] + } + }, + "/api/apps/{app}/schemas/{schema}/fields/{id}/hide": { + "put": { + "tags": [ + "Schemas" + ], + "summary": "Hide a schema field.", + "description": "A hidden field is not part of the API response, but can still be edited in the portal.", + "operationId": "SchemaFields_HideField", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "schema", + "in": "path", + "required": true, + "description": "The name of the schema.", + "schema": { + "type": "string" + }, + "x-position": 2 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the field to hide.", + "schema": { + "type": "integer", + "format": "int64" + }, + "x-position": 3 + } + ], + "responses": { + "200": { + "description": "Schema field hidden.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchemaDto" + } + } + } + }, + "400": { + "description": "Schema field request not valid or field locked.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Schema, field or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.schemas.{schema}.update" + ] + } + ] + } + }, + "/api/apps/{app}/schemas/{schema}/fields/{parentId}/nested/{id}/hide": { + "put": { + "tags": [ + "Schemas" + ], + "summary": "Hide a nested field.", + "description": "A hidden field is not part of the API response, but can still be edited in the portal.", + "operationId": "SchemaFields_HideNestedField", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "schema", + "in": "path", + "required": true, + "description": "The name of the schema.", + "schema": { + "type": "string" + }, + "x-position": 2 + }, + { + "name": "parentId", + "in": "path", + "required": true, + "description": "The parent field id.", + "schema": { + "type": "integer", + "format": "int64" + }, + "x-position": 3 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the field to hide.", + "schema": { + "type": "integer", + "format": "int64" + }, + "x-position": 4 + } + ], + "responses": { + "200": { + "description": "Schema field hidden.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchemaDto" + } + } + } + }, + "400": { + "description": "Schema field request not valid or field locked.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Field, schema, or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.schemas.{schema}.update" + ] + } + ] + } + }, + "/api/apps/{app}/schemas/{schema}/fields/{id}/show": { + "put": { + "tags": [ + "Schemas" + ], + "summary": "Show a schema field.", + "description": "A hidden field is not part of the API response, but can still be edited in the portal.", + "operationId": "SchemaFields_ShowField", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "schema", + "in": "path", + "required": true, + "description": "The name of the schema.", + "schema": { + "type": "string" + }, + "x-position": 2 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the field to show.", + "schema": { + "type": "integer", + "format": "int64" + }, + "x-position": 3 + } + ], + "responses": { + "200": { + "description": "Schema field shown.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchemaDto" + } + } + } + }, + "400": { + "description": "Schema field request not valid or field locked.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Schema, field or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.schemas.{schema}.update" + ] + } + ] + } + }, + "/api/apps/{app}/schemas/{schema}/fields/{parentId}/nested/{id}/show": { + "put": { + "tags": [ + "Schemas" + ], + "summary": "Show a nested field.", + "description": "A hidden field is not part of the API response, but can still be edited in the portal.", + "operationId": "SchemaFields_ShowNestedField", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "schema", + "in": "path", + "required": true, + "description": "The name of the schema.", + "schema": { + "type": "string" + }, + "x-position": 2 + }, + { + "name": "parentId", + "in": "path", + "required": true, + "description": "The parent field id.", + "schema": { + "type": "integer", + "format": "int64" + }, + "x-position": 3 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the field to show.", + "schema": { + "type": "integer", + "format": "int64" + }, + "x-position": 4 + } + ], + "responses": { + "200": { + "description": "Schema field shown.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchemaDto" + } + } + } + }, + "400": { + "description": "Schema field request not valid or field locked.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Schema, field or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.schemas.{schema}.update" + ] + } + ] + } + }, + "/api/apps/{app}/schemas/{schema}/fields/{id}/enable": { + "put": { + "tags": [ + "Schemas" + ], + "summary": "Enable a schema field.", + "description": "A disabled field cannot not be edited in the squidex portal anymore, but will be part of the API response.", + "operationId": "SchemaFields_EnableField", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "schema", + "in": "path", + "required": true, + "description": "The name of the schema.", + "schema": { + "type": "string" + }, + "x-position": 2 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the field to enable.", + "schema": { + "type": "integer", + "format": "int64" + }, + "x-position": 3 + } + ], + "responses": { + "200": { + "description": "Schema field enabled.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchemaDto" + } + } + } + }, + "400": { + "description": "Schema field request not valid or field locked.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Schema, field or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.schemas.{schema}.update" + ] + } + ] + } + }, + "/api/apps/{app}/schemas/{schema}/fields/{parentId}/nested/{id}/enable": { + "put": { + "tags": [ + "Schemas" + ], + "summary": "Enable a nested field.", + "description": "A disabled field cannot not be edited in the squidex portal anymore, but will be part of the API response.", + "operationId": "SchemaFields_EnableNestedField", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "schema", + "in": "path", + "required": true, + "description": "The name of the schema.", + "schema": { + "type": "string" + }, + "x-position": 2 + }, + { + "name": "parentId", + "in": "path", + "required": true, + "description": "The parent field id.", + "schema": { + "type": "integer", + "format": "int64" + }, + "x-position": 3 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the field to enable.", + "schema": { + "type": "integer", + "format": "int64" + }, + "x-position": 4 + } + ], + "responses": { + "200": { + "description": "Schema field enabled.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchemaDto" + } + } + } + }, + "400": { + "description": "Schema field request not valid or field locked.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Schema, field or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.schemas.{schema}.update" + ] + } + ] + } + }, + "/api/apps/{app}/schemas/{schema}/fields/{id}/disable": { + "put": { + "tags": [ + "Schemas" + ], + "summary": "Disable a schema field.", + "description": "A disabled field cannot not be edited in the squidex portal anymore, but will be part of the API response.", + "operationId": "SchemaFields_DisableField", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "schema", + "in": "path", + "required": true, + "description": "The name of the schema.", + "schema": { + "type": "string" + }, + "x-position": 2 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the field to disable.", + "schema": { + "type": "integer", + "format": "int64" + }, + "x-position": 3 + } + ], + "responses": { + "200": { + "description": "Schema field disabled.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchemaDto" + } + } + } + }, + "400": { + "description": "Schema field request not valid or field locked.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Schema, field or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.schemas.{schema}.update" + ] + } + ] + } + }, + "/api/apps/{app}/schemas/{schema}/fields/{parentId}/nested/{id}/disable": { + "put": { + "tags": [ + "Schemas" + ], + "summary": "Disable a nested field.", + "description": "A disabled field cannot not be edited in the squidex portal anymore, but will be part of the API response.", + "operationId": "SchemaFields_DisableNestedField", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "schema", + "in": "path", + "required": true, + "description": "The name of the schema.", + "schema": { + "type": "string" + }, + "x-position": 2 + }, + { + "name": "parentId", + "in": "path", + "required": true, + "description": "The parent field id.", + "schema": { + "type": "integer", + "format": "int64" + }, + "x-position": 3 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the field to disable.", + "schema": { + "type": "integer", + "format": "int64" + }, + "x-position": 4 + } + ], + "responses": { + "200": { + "description": "Schema field disabled.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchemaDto" + } + } + } + }, + "400": { + "description": "Schema field request not valid or field locked.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Schema, field or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.schemas.{schema}.update" + ] + } + ] + } + }, + "/api/apps/{app}/schemas/{schema}/indexes": { + "get": { + "tags": [ + "Schemas" + ], + "summary": "Gets the schema indexes.", + "operationId": "SchemaIndexes_GetIndexes", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "schema", + "in": "path", + "required": true, + "description": "The name of the schema.", + "schema": { + "type": "string" + }, + "x-position": 2 + } + ], + "responses": { + "200": { + "description": "Schema indexes returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IndexesDto" + } + } + } + }, + "404": { + "description": "Schema or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.schemas.{schema}.indexes" + ] + } + ] + }, + "post": { + "tags": [ + "Schemas" + ], + "summary": "Create a schema indexes.", + "operationId": "SchemaIndexes_PostIndex", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "schema", + "in": "path", + "required": true, + "description": "The name of the schema.", + "schema": { + "type": "string" + }, + "x-position": 2 + } + ], + "requestBody": { + "x-name": "request", + "description": "The request object that represents an index.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateIndexDto" + } + } + }, + "required": true, + "x-position": 3 + }, + "responses": { + "204": { + "description": "" + }, + "404": { + "description": "Schema or app not found." + }, + "400": { + "description": "Validation error.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.schemas.{schema}.indexes" + ] + } + ] + } + }, + "/api/apps/{app}/schemas/{schema}/indexes/{name}": { + "delete": { + "tags": [ + "Schemas" + ], + "summary": "Create a schema indexes.", + "operationId": "SchemaIndexes_DeleteIndex", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "schema", + "in": "path", + "required": true, + "description": "The name of the schema.", + "schema": { + "type": "string" + }, + "x-position": 2 + }, + { + "name": "name", + "in": "path", + "required": true, + "description": "The name of the index.", + "schema": { + "type": "string" + }, + "x-position": 3 + } + ], + "responses": { + "204": { + "description": "Schema index deletion added to job queue." + }, + "404": { + "description": "Schema or app not found." + }, + "400": { + "description": "Validation error.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.schemas.{schema}.indexes" + ] + } + ] + } + }, + "/api/apps/{app}/schemas": { + "get": { + "tags": [ + "Schemas" + ], + "summary": "Get schemas.", + "operationId": "Schemas_GetSchemas", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "responses": { + "200": { + "description": "Schemas returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchemasDto" + } + } + } + }, + "404": { + "description": "App not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.schemas.read" + ] + } + ] + }, + "post": { + "tags": [ + "Schemas" + ], + "summary": "Create a new schema.", + "operationId": "Schemas_PostSchema", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "requestBody": { + "x-name": "request", + "description": "The schema object that needs to be added to the app.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateSchemaDto" + } + } + }, + "required": true, + "x-position": 2 + }, + "responses": { + "201": { + "description": "Schema created.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchemaDto" + } + } + } + }, + "400": { + "description": "Schema request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "409": { + "description": "Schema name already in use.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.schemas.create" + ] + } + ] + } + }, + "/api/apps/{app}/schemas/{schema}": { + "get": { + "tags": [ + "Schemas" + ], + "summary": "Get a schema by name.", + "operationId": "Schemas_GetSchema", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "schema", + "in": "path", + "required": true, + "description": "The name of the schema to retrieve.", + "schema": { + "type": "string" + }, + "x-position": 2 + } + ], + "responses": { + "200": { + "description": "Schema found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchemaDto" + } + } + } + }, + "404": { + "description": "Schema or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.schemas.read" + ] + } + ] + }, + "put": { + "tags": [ + "Schemas" + ], + "summary": "Update a schema.", + "operationId": "Schemas_PutSchema", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "schema", + "in": "path", + "required": true, + "description": "The name of the schema.", + "schema": { + "type": "string" + }, + "x-position": 2 + } + ], + "requestBody": { + "x-name": "request", + "description": "The schema object that needs to updated.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateSchemaDto" + } + } + }, + "required": true, + "x-position": 3 + }, + "responses": { + "200": { + "description": "Schema updated.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchemaDto" + } + } + } + }, + "400": { + "description": "Schema request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Schema or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.schemas.{schema}.update" + ] + } + ] + }, + "delete": { + "tags": [ + "Schemas" + ], + "summary": "Delete a schema.", + "operationId": "Schemas_DeleteSchema", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "schema", + "in": "path", + "required": true, + "description": "The name of the schema to delete.", + "schema": { + "type": "string" + }, + "x-position": 2 + }, + { + "name": "permanent", + "in": "query", + "description": "True to delete the schema and the contents permanently.", + "schema": { + "type": "boolean" + }, + "x-position": 3 + } + ], + "responses": { + "204": { + "description": "Schema deleted." + }, + "404": { + "description": "Schema or app not found." + }, + "400": { + "description": "Validation error.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.schemas.{schema}.delete" + ] + } + ] + } + }, + "/api/apps/{app}/schemas/generate": { + "post": { + "tags": [ + "Schemas" + ], + "summary": "Generate a new schema.", + "operationId": "Schemas_PostSchemaGenerate", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "requestBody": { + "x-name": "request", + "description": "The schema object that needs to be added to the app.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GenerateSchemaDto" + } + } + }, + "required": true, + "x-position": 2 + }, + "responses": { + "201": { + "description": "Schema created.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GenerateSchemaResponseDto" + } + } + } + }, + "400": { + "description": "Schema request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "409": { + "description": "Schema name already in use.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.schemas.create" + ] + } + ] + } + }, + "/api/apps/{app}/schemas/{schema}/sync": { + "put": { + "tags": [ + "Schemas" + ], + "summary": "Synchronize a schema.", + "operationId": "Schemas_PutSchemaSync", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "schema", + "in": "path", + "required": true, + "description": "The name of the schema.", + "schema": { + "type": "string" + }, + "x-position": 2 + } + ], + "requestBody": { + "x-name": "request", + "description": "The schema object that needs to updated.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SynchronizeSchemaDto" + } + } + }, + "required": true, + "x-position": 3 + }, + "responses": { + "200": { + "description": "Schema updated.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchemaDto" + } + } + } + }, + "400": { + "description": "Schema request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Schema or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.schemas.{schema}.update" + ] + } + ] + } + }, + "/api/apps/{app}/schemas/{schema}/category": { + "put": { + "tags": [ + "Schemas" + ], + "summary": "Update a schema category.", + "operationId": "Schemas_PutCategory", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "schema", + "in": "path", + "required": true, + "description": "The name of the schema.", + "schema": { + "type": "string" + }, + "x-position": 2 + } + ], + "requestBody": { + "x-name": "request", + "description": "The schema object that needs to updated.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChangeCategoryDto" + } + } + }, + "required": true, + "x-position": 3 + }, + "responses": { + "200": { + "description": "Schema updated.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchemaDto" + } + } + } + }, + "400": { + "description": "Schema request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Schema or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.schemas.{schema}.update" + ] + } + ] + } + }, + "/api/apps/{app}/schemas/{schema}/preview-urls": { + "put": { + "tags": [ + "Schemas" + ], + "summary": "Update the preview urls.", + "operationId": "Schemas_PutPreviewUrls", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "schema", + "in": "path", + "required": true, + "description": "The name of the schema.", + "schema": { + "type": "string" + }, + "x-position": 2 + } + ], + "requestBody": { + "x-name": "request", + "description": "The preview urls for the schema.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ConfigurePreviewUrlsDto" + } + } + }, + "required": true, + "x-position": 3 + }, + "responses": { + "200": { + "description": "Schema updated.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchemaDto" + } + } + } + }, + "400": { + "description": "Schema request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Schema or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.schemas.{schema}.update" + ] + } + ] + } + }, + "/api/apps/{app}/schemas/{schema}/scripts": { + "put": { + "tags": [ + "Schemas" + ], + "summary": "Update the scripts.", + "operationId": "Schemas_PutScripts", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "schema", + "in": "path", + "required": true, + "description": "The name of the schema.", + "schema": { + "type": "string" + }, + "x-position": 2 + } + ], + "requestBody": { + "x-name": "request", + "description": "The schema scripts object that needs to updated.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchemaScriptsDto" + } + } + }, + "required": true, + "x-position": 3 + }, + "responses": { + "200": { + "description": "Schema updated.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchemaDto" + } + } + } + }, + "400": { + "description": "Schema request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Schema or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.schemas.{schema}.scripts" + ] + } + ] + } + }, + "/api/apps/{app}/schemas/{schema}/rules": { + "put": { + "tags": [ + "Schemas" + ], + "summary": "Update the rules.", + "operationId": "Schemas_PutRules", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "schema", + "in": "path", + "required": true, + "description": "The name of the schema.", + "schema": { + "type": "string" + }, + "x-position": 2 + } + ], + "requestBody": { + "x-name": "request", + "description": "The schema rules object that needs to updated.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ConfigureFieldRulesDto" + } + } + }, + "required": true, + "x-position": 3 + }, + "responses": { + "200": { + "description": "Schema updated.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchemaDto" + } + } + } + }, + "400": { + "description": "Schema request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Schema or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.schemas.{schema}.update" + ] + } + ] + } + }, + "/api/apps/{app}/schemas/{schema}/publish": { + "put": { + "tags": [ + "Schemas" + ], + "summary": "Publish a schema.", + "operationId": "Schemas_PublishSchema", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "schema", + "in": "path", + "required": true, + "description": "The name of the schema to publish.", + "schema": { + "type": "string" + }, + "x-position": 2 + } + ], + "responses": { + "200": { + "description": "Schema published.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchemaDto" + } + } + } + }, + "404": { + "description": "Schema or app not found." + }, + "400": { + "description": "Validation error.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.schemas.{schema}.publish" + ] + } + ] + } + }, + "/api/apps/{app}/schemas/{schema}/unpublish": { + "put": { + "tags": [ + "Schemas" + ], + "summary": "Unpublish a schema.", + "operationId": "Schemas_UnpublishSchema", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "schema", + "in": "path", + "required": true, + "description": "The name of the schema to unpublish.", + "schema": { + "type": "string" + }, + "x-position": 2 + } + ], + "responses": { + "200": { + "description": "Schema unpublished.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchemaDto" + } + } + } + }, + "404": { + "description": "Schema or app not found." + }, + "400": { + "description": "Validation error.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.schemas.{schema}.publish" + ] + } + ] + } + }, + "/api/rules/steps": { + "get": { + "tags": [ + "Rules" + ], + "summary": "Get supported rule steps.", + "operationId": "Rules_GetSteps", + "responses": { + "200": { + "description": "Rule actions returned.", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/RuleElementDto" + } + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [] + } + ] + } + }, + "/api/apps/{app}/rules": { + "get": { + "tags": [ + "Rules" + ], + "summary": "Get rules.", + "operationId": "Rules_GetRules", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "responses": { + "200": { + "description": "Rules returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RulesDto" + } + } + } + }, + "404": { + "description": "App not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.rules.read" + ] + } + ] + }, + "post": { + "tags": [ + "Rules" + ], + "summary": "Create a new rule.", + "operationId": "Rules_PostRule", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "requestBody": { + "x-name": "request", + "description": "The rule object that needs to be added to the app.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateRuleDto" + } + } + }, + "required": true, + "x-position": 2 + }, + "responses": { + "201": { + "description": "Rule created.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RuleDto" + } + } + } + }, + "400": { + "description": "Rule request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "App not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.rules.create" + ] + } + ] + } + }, + "/api/apps/{app}/rules/run": { + "delete": { + "tags": [ + "Rules" + ], + "summary": "Cancel the current run.", + "operationId": "Rules_DeleteRuleRun", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "responses": { + "204": { + "description": "Rule run cancelled." + }, + "400": { + "description": "Validation error.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.rules.events.update" + ] + } + ] + } + }, + "/api/apps/{app}/rules/{id}": { + "put": { + "tags": [ + "Rules" + ], + "summary": "Update a rule.", + "operationId": "Rules_PutRule", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the rule to update.", + "schema": { + "type": "string" + }, + "x-position": 2 + } + ], + "requestBody": { + "x-name": "request", + "description": "The rule object that needs to be added to the app.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateRuleDto" + } + } + }, + "required": true, + "x-position": 3 + }, + "responses": { + "200": { + "description": "Rule updated.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RuleDto" + } + } + } + }, + "400": { + "description": "Rule request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Rule or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.rules.update" + ] + } + ] + }, + "delete": { + "tags": [ + "Rules" + ], + "summary": "Delete a rule.", + "operationId": "Rules_DeleteRule", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the rule to delete.", + "schema": { + "type": "string" + }, + "x-position": 2 + } + ], + "responses": { + "204": { + "description": "Rule deleted." + }, + "404": { + "description": "Rule or app not found." + }, + "400": { + "description": "Validation error.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.rules.delete" + ] + } + ] + } + }, + "/api/apps/{app}/rules/{id}/enable": { + "put": { + "tags": [ + "Rules" + ], + "summary": "Enable a rule.", + "operationId": "Rules_EnableRule", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the rule to enable.", + "schema": { + "type": "string" + }, + "x-position": 2 + } + ], + "responses": { + "200": { + "description": "Rule enabled.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RuleDto" + } + } + } + }, + "404": { + "description": "Rule or app not found." + }, + "400": { + "description": "Validation error.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.rules.disable" + ] + } + ] + } + }, + "/api/apps/{app}/rules/{id}/disable": { + "put": { + "tags": [ + "Rules" + ], + "summary": "Disable a rule.", + "operationId": "Rules_DisableRule", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the rule to disable.", + "schema": { + "type": "string" + }, + "x-position": 2 + } + ], + "responses": { + "200": { + "description": "Rule disabled.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RuleDto" + } + } + } + }, + "404": { + "description": "Rule or app not found." + }, + "400": { + "description": "Validation error.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.rules.disable" + ] + } + ] + } + }, + "/api/apps/{app}/rules/{id}/trigger": { + "put": { + "tags": [ + "Rules" + ], + "summary": "Trigger a rule.", + "operationId": "Rules_TriggerRule", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the rule to disable.", + "schema": { + "type": "string" + }, + "x-position": 2 + } + ], + "requestBody": { + "x-name": "request", + "description": "The arguments for the rule flow.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TriggerRuleDto" + } + } + }, + "required": true, + "x-position": 3 + }, + "responses": { + "204": { + "description": "Rule triggered." + }, + "404": { + "description": "Rule or app not found." + }, + "400": { + "description": "Validation error.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.rules.events.run" + ] + } + ] + } + }, + "/api/apps/{app}/rules/{id}/run": { + "put": { + "tags": [ + "Rules" + ], + "summary": "Run a rule.", + "operationId": "Rules_PutRuleRun", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the rule to run.", + "schema": { + "type": "string" + }, + "x-position": 2 + }, + { + "name": "fromSnapshots", + "in": "query", + "description": "Runs the rule from snapeshots if possible.", + "schema": { + "type": "boolean", + "default": false + }, + "x-position": 3 + } + ], + "responses": { + "204": { + "description": "Rule started." + }, + "400": { + "description": "Validation error.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.rules.events.run" + ] + } + ] + } + }, + "/api/apps/{app}/rules/{id}/events": { + "delete": { + "tags": [ + "Rules" + ], + "summary": "Cancels all rule events.", + "operationId": "Rules_DeleteRuleEvents", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the rule to cancel.", + "schema": { + "type": "string" + }, + "x-position": 2 + } + ], + "responses": { + "204": { + "description": "Rule events cancelled." + }, + "400": { + "description": "Validation error.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.rules.events.delete" + ] + } + ] + } + }, + "/api/apps/{app}/rules/validate/trigger": { + "post": { + "tags": [ + "Rules" + ], + "summary": "Validates a rule trigger.", + "operationId": "Rules_ValidateTrigger", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "requestBody": { + "x-name": "request", + "description": "The rule trigger that needs to be validate.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RuleTriggerDto" + } + } + }, + "required": true, + "x-position": 2 + }, + "responses": { + "204": { + "description": "Rule trigger validated." + }, + "400": { + "description": "Rule trigger not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Rule or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [] + } + ] + } + }, + "/api/apps/{app}/rules/validate/step": { + "post": { + "tags": [ + "Rules" + ], + "summary": "Validates a rule step.", + "operationId": "Rules_ValidateStep", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "requestBody": { + "x-name": "request", + "description": "The rule step that needs to be validate.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FlowStepDto" + } + } + }, + "required": true, + "x-position": 2 + }, + "responses": { + "204": { + "description": "Rule step validated." + }, + "400": { + "description": "Rule step not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Rule or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [] + } + ] + } + }, + "/api/apps/{app}/rules/simulate": { + "post": { + "tags": [ + "Rules" + ], + "summary": "Simulate a rule.", + "operationId": "Rules_SimulatePOST", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "requestBody": { + "x-name": "request", + "description": "The rule to simulate.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateRuleDto" + } + } + }, + "required": true, + "x-position": 2 + }, + "responses": { + "200": { + "description": "Rule simulated.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SimulatedRuleEventsDto" + } + } + } + }, + "404": { + "description": "Rule or app not found." + }, + "400": { + "description": "Validation error.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.rules.events.read" + ] + } + ] + } + }, + "/api/apps/{app}/rules/{id}/simulate": { + "get": { + "tags": [ + "Rules" + ], + "summary": "Simulate a rule.", + "operationId": "Rules_SimulateGET", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the rule to simulate.", + "schema": { + "type": "string" + }, + "x-position": 2 + } + ], + "responses": { + "200": { + "description": "Rule simulated.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SimulatedRuleEventsDto" + } + } + } + }, + "404": { + "description": "Rule or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.rules.events.read" + ] + } + ] + } + }, + "/api/apps/{app}/rules/events": { + "get": { + "tags": [ + "Rules" + ], + "summary": "Get rule events.", + "operationId": "Rules_GetEvents", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "ruleId", + "in": "query", + "description": "The optional rule id to filter to events.", + "schema": { + "type": "string", + "nullable": true + }, + "x-position": 2 + }, + { + "name": "skip", + "in": "query", + "description": "The number of events to skip.", + "schema": { + "type": "integer", + "format": "int32", + "default": 0 + }, + "x-position": 3 + }, + { + "name": "take", + "in": "query", + "description": "The number of events to take.", + "schema": { + "type": "integer", + "format": "int32", + "default": 20 + }, + "x-position": 4 + } + ], + "responses": { + "200": { + "description": "Rule events returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RuleEventsDto" + } + } + } + }, + "404": { + "description": "App not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.rules.events.read" + ] + } + ] + }, + "delete": { + "tags": [ + "Rules" + ], + "summary": "Cancels all events.", + "operationId": "Rules_DeleteEvents", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "responses": { + "204": { + "description": "Events cancelled." + }, + "400": { + "description": "Validation error.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.rules.events.delete" + ] + } + ] + } + }, + "/api/apps/{app}/rules/events/{id}": { + "put": { + "tags": [ + "Rules" + ], + "summary": "Retry the event immediately.", + "operationId": "Rules_PutEvent", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The event to enqueue.", + "schema": { + "type": "string", + "format": "guid" + }, + "x-position": 2 + } + ], + "responses": { + "204": { + "description": "Rule enqueued." + }, + "404": { + "description": "App or rule event not found." + }, + "400": { + "description": "Validation error.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.rules.events.update" + ] + } + ] + }, + "delete": { + "tags": [ + "Rules" + ], + "summary": "Cancels an event.", + "operationId": "Rules_DeleteEvent", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The event to cancel.", + "schema": { + "type": "string", + "format": "guid" + }, + "x-position": 2 + } + ], + "responses": { + "204": { + "description": "Rule event cancelled." + }, + "404": { + "description": "App or rule event not found." + }, + "400": { + "description": "Validation error.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [] + } + ] + } + }, + "/api/rules/eventtypes": { + "get": { + "tags": [ + "Rules" + ], + "summary": "Provide a list of all event types that are used in rules.", + "operationId": "Rules_GetEventTypes", + "responses": { + "200": { + "description": "Rule events returned.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + } + } + }, + "/api/rules/eventtypes/{type}": { + "get": { + "tags": [ + "Rules" + ], + "summary": "Provide the json schema for the event with the specified name.", + "operationId": "Rules_GetEventSchema", + "parameters": [ + { + "name": "type", + "in": "path", + "required": true, + "description": "The type name of the event.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "responses": { + "200": { + "description": "Rule event type found.", + "content": { + "application/json": { + "schema": {} + } + } + }, + "404": { + "description": "Rule event not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + } + } + }, + "/api/apps/{app}/plans": { + "get": { + "tags": [ + "Plans" + ], + "summary": "Get app plan information.", + "operationId": "AppPlans_GetPlans", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "responses": { + "200": { + "description": "App plan information returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PlansDto" + } + } + } + }, + "404": { + "description": "App not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.plans.read" + ] + } + ] + } + }, + "/api/apps/{app}/plan": { + "put": { + "tags": [ + "Plans" + ], + "summary": "Change the app plan.", + "operationId": "AppPlans_PutPlan", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "requestBody": { + "x-name": "request", + "description": "Plan object that needs to be changed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChangePlanDto" + } + } + }, + "required": true, + "x-position": 2 + }, + "responses": { + "200": { + "description": "Plan changed or redirect url returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PlanChangedDto" + } + } + } + }, + "400": { + "description": "Plan not owned by user.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "App not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.plans.change" + ] + } + ] + } + }, + "/api/teams/{team}/plans": { + "get": { + "tags": [ + "Plans" + ], + "summary": "Get team plan information.", + "operationId": "TeamPlans_GetTeamPlans", + "parameters": [ + { + "name": "team", + "in": "path", + "required": true, + "description": "The name of the team.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "responses": { + "200": { + "description": "Team plan information returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PlansDto" + } + } + } + }, + "404": { + "description": "Team not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.teams.{team}.plans.read" + ] + } + ] + } + }, + "/api/teams/{team}/plan": { + "put": { + "tags": [ + "Plans" + ], + "summary": "Change the team plan.", + "operationId": "TeamPlans_PutTeamPlan", + "parameters": [ + { + "name": "team", + "in": "path", + "required": true, + "description": "The name of the team.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "requestBody": { + "x-name": "request", + "description": "Plan object that needs to be changed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChangePlanDto" + } + } + }, + "required": true, + "x-position": 2 + }, + "responses": { + "200": { + "description": "Plan changed or redirect url returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PlanChangedDto" + } + } + } + }, + "404": { + "description": "Team not found." + }, + "400": { + "description": "Validation error.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.teams.{team}.plans.change" + ] + } + ] + } + }, + "/api/info": { + "get": { + "tags": [ + "Ping" + ], + "summary": "Get API information.", + "operationId": "Ping_GetInfo", + "responses": { + "200": { + "description": "Infos returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExposedValues" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + } + } + }, + "/api/ping": { + "get": { + "tags": [ + "Ping" + ], + "summary": "Get ping status of the API.", + "description": "Can be used to test, if the Squidex API is alive and responding.", + "operationId": "Ping_GetPing", + "responses": { + "204": { + "description": "Service ping successful." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + } + } + }, + "/api/ping/{app}": { + "get": { + "tags": [ + "Ping" + ], + "summary": "Get ping status.", + "description": "Can be used to test, if the Squidex API is alive and responding.", + "operationId": "Ping_GetAppPing", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "responses": { + "204": { + "description": "Service ping successful." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.ping" + ] + } + ] + } + }, + "/api/news/features": { + "get": { + "tags": [ + "News" + ], + "summary": "Get features since version.", + "operationId": "News_GetNews", + "parameters": [ + { + "name": "version", + "in": "query", + "description": "The latest received version.", + "schema": { + "type": "integer", + "format": "int32", + "default": 0 + }, + "x-position": 1 + } + ], + "responses": { + "200": { + "description": "Latest features returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FeaturesDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [] + } + ] + } + }, + "/api/languages": { + "get": { + "tags": [ + "Languages" + ], + "summary": "Get supported languages.", + "description": "Provide a list of supported language codes, following the ISO2Code standard.", + "operationId": "Languages_GetLanguages", + "responses": { + "200": { + "description": "Supported language codes returned.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/LanguageDto" + } + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [] + } + ] + } + }, + "/api/apps/jobs/{id}": { + "get": { + "tags": [ + "Jobs" + ], + "summary": "Get the job content.", + "operationId": "JobsContent_GetJobContent", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the job.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "appId", + "in": "query", + "description": "The ID of the app.", + "schema": { + "type": "string" + }, + "x-position": 2 + } + ], + "responses": { + "200": { + "description": "Job found and content returned.", + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "404": { + "description": "Job or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + } + } + }, + "/api/apps/{app}/jobs": { + "get": { + "tags": [ + "Jobs" + ], + "summary": "Get all jobs.", + "operationId": "Jobs_GetJobs", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "responses": { + "200": { + "description": "Jobs returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/JobsDto" + } + } + } + }, + "404": { + "description": "App not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.jobs.read" + ] + } + ] + } + }, + "/api/apps/{app}/jobs/{id}": { + "delete": { + "tags": [ + "Jobs" + ], + "summary": "Delete a job.", + "operationId": "Jobs_DeleteJob", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the jobs to delete.", + "schema": { + "type": "string" + }, + "x-position": 2 + } + ], + "responses": { + "204": { + "description": "Job deleted." + }, + "404": { + "description": "Job or app not found." + }, + "400": { + "description": "Validation error.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.jobs.delete" + ] + } + ] + } + }, + "/api/apps/{app}/history": { + "get": { + "tags": [ + "History" + ], + "summary": "Get the app history.", + "operationId": "History_GetAppHistory", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "channel", + "in": "query", + "description": "The name of the channel.", + "schema": { + "type": "string" + }, + "x-position": 2 + } + ], + "responses": { + "200": { + "description": "Events returned.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HistoryEventDto" + } + } + } + } + }, + "404": { + "description": "App not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.history" + ] + } + ] + } + }, + "/api/teams/{team}/history": { + "get": { + "tags": [ + "History" + ], + "summary": "Get the team history.", + "operationId": "History_GetTeamHistory", + "parameters": [ + { + "name": "team", + "in": "path", + "required": true, + "description": "The ID of the team.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "channel", + "in": "query", + "description": "The name of the channel.", + "schema": { + "type": "string" + }, + "x-position": 2 + } + ], + "responses": { + "200": { + "description": "Events returned.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HistoryEventDto" + } + } + } + } + }, + "404": { + "description": "Team not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.teams.{team}.history" + ] + } + ] + } + }, + "/api/event-consumers": { + "get": { + "tags": [ + "EventConsumers" + ], + "summary": "Get event consumers.", + "operationId": "EventConsumers_GetEventConsumers", + "responses": { + "200": { + "description": "Event consumers returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventConsumersDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.admin.events.read" + ] + } + ] + } + }, + "/api/event-consumers/{consumerName}/start": { + "put": { + "tags": [ + "EventConsumers" + ], + "summary": "Start an event consumer.", + "operationId": "EventConsumers_StartEventConsumer", + "parameters": [ + { + "name": "consumerName", + "in": "path", + "required": true, + "description": "The name of the event consumer.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "responses": { + "200": { + "description": "Event consumer started asynchronously.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventConsumerDto" + } + } + } + }, + "404": { + "description": "Event consumer not found." + }, + "400": { + "description": "Validation error.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.admin.events.manage" + ] + } + ] + } + }, + "/api/event-consumers/{consumerName}/stop": { + "put": { + "tags": [ + "EventConsumers" + ], + "summary": "Stop an event consumer.", + "operationId": "EventConsumers_StopEventConsumer", + "parameters": [ + { + "name": "consumerName", + "in": "path", + "required": true, + "description": "The name of the event consumer.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "responses": { + "200": { + "description": "Event consumer stopped asynchronously.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventConsumerDto" + } + } + } + }, + "404": { + "description": "Event consumer not found." + }, + "400": { + "description": "Validation error.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.admin.events.manage" + ] + } + ] + } + }, + "/api/event-consumers/{consumerName}/reset": { + "put": { + "tags": [ + "EventConsumers" + ], + "summary": "Reset an event consumer.", + "operationId": "EventConsumers_ResetEventConsumer", + "parameters": [ + { + "name": "consumerName", + "in": "path", + "required": true, + "description": "The name of the event consumer.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "responses": { + "200": { + "description": "Event consumer resetted asynchronously.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EventConsumerDto" + } + } + } + }, + "404": { + "description": "Event consumer not found." + }, + "400": { + "description": "Validation error.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.admin.events.manage" + ] + } + ] + } + }, + "/api/diagnostics/dump": { + "get": { + "tags": [ + "Diagnostics" + ], + "summary": "Creates a dump and writes it into storage..", + "operationId": "Diagnostics_GetDump", + "responses": { + "204": { + "description": "Dump created successful." + }, + "501": { + "description": "Not configured.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.admin.*" + ] + } + ] + } + }, + "/api/diagnostics/gcdump": { + "get": { + "tags": [ + "Diagnostics" + ], + "summary": "Creates a gc dump and writes it into storage.", + "operationId": "Diagnostics_GetGCDump", + "responses": { + "204": { + "description": "Dump created successful." + }, + "501": { + "description": "Not configured.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.admin.*" + ] + } + ] + } + }, + "/api/content/{app}/{schema}": { + "get": { + "tags": [ + "Contents" + ], + "summary": "Queries contents.", + "description": "You can read the generated documentation for your app at /api/content/{appName}/docs.", + "operationId": "Contents_GetContents", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 0 + }, + { + "name": "schema", + "in": "path", + "required": true, + "description": "The name of the schema.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "ids", + "in": "query", + "description": "The optional ids of the content to fetch.", + "schema": { + "type": "string", + "nullable": true + }, + "x-position": 2 + }, + { + "name": "q", + "in": "query", + "description": "The optional json query.", + "schema": { + "type": "string", + "nullable": true + }, + "x-position": 3 + }, + { + "name": "$search", + "in": "query", + "description": "Optional number of items to skip.", + "schema": { + "type": "string" + }, + "x-position": 4 + }, + { + "name": "$top", + "in": "query", + "description": "Optional number of items to take.", + "schema": { + "type": "number" + }, + "x-position": 5 + }, + { + "name": "$skip", + "in": "query", + "description": "Optional number of items to skip.", + "schema": { + "type": "number" + }, + "x-position": 6 + }, + { + "name": "$orderby", + "in": "query", + "description": "Optional OData order definition.", + "schema": { + "type": "string" + }, + "x-position": 7 + }, + { + "name": "$filter", + "in": "query", + "description": "Optional OData filter.", + "schema": { + "type": "string" + }, + "x-position": 8 + }, + { + "name": "X-Fields", + "in": "header", + "description": "The list of content fields (comma-separated).", + "schema": { + "type": "string" + }, + "x-position": 9 + }, + { + "name": "X-Flatten", + "in": "header", + "description": "Provide the data as flat object.", + "schema": { + "type": "boolean" + }, + "x-position": 10 + }, + { + "name": "X-Languages", + "in": "header", + "description": "The list of languages to resolve (comma-separated).", + "schema": { + "type": "string" + }, + "x-position": 11 + }, + { + "name": "X-NoSlowTotal", + "in": "header", + "description": "Do not return the total amount, if it would be slow.", + "schema": { + "type": "boolean" + }, + "x-position": 12 + }, + { + "name": "X-NoTotal", + "in": "header", + "description": "Do not return the total amount.", + "schema": { + "type": "boolean" + }, + "x-position": 13 + }, + { + "name": "X-Unpublished", + "in": "header", + "description": "Return unpublished content items.", + "schema": { + "type": "boolean" + }, + "x-position": 14 + } + ], + "responses": { + "200": { + "description": "Contents returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContentsDto" + } + } + } + }, + "404": { + "description": "Schema or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [] + } + ] + }, + "post": { + "tags": [ + "Contents" + ], + "summary": "Create a content item.", + "description": "You can read the generated documentation for your app at /api/content/{appName}/docs.", + "operationId": "Contents_PostContent", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 0 + }, + { + "name": "schema", + "in": "path", + "required": true, + "description": "The name of the schema.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "status", + "in": "query", + "description": "The initial status.", + "schema": { + "type": "string", + "nullable": true + }, + "x-position": 3 + }, + { + "name": "id", + "in": "query", + "description": "The optional custom content id.", + "schema": { + "type": "string", + "nullable": true + }, + "x-position": 4 + }, + { + "name": "publish", + "in": "query", + "description": "True to automatically publish the content.", + "schema": { + "type": "boolean" + }, + "x-position": 5 + }, + { + "name": "X-Unpublished", + "in": "header", + "description": "Return unpublished content items.", + "schema": { + "type": "boolean" + }, + "x-position": 6 + }, + { + "name": "X-Languages", + "in": "header", + "description": "The list of languages to resolve (comma-separated).", + "schema": { + "type": "string" + }, + "x-position": 7 + } + ], + "requestBody": { + "x-name": "Data", + "description": "The full data for the content item.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContentData" + } + } + }, + "required": true, + "x-position": 2 + }, + "responses": { + "201": { + "description": "Content created.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContentDto" + } + } + } + }, + "400": { + "description": "Content request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Content, schema or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.contents.{schema}.create" + ] + } + ] + } + }, + "/api/content/{app}/{schema}/query": { + "post": { + "tags": [ + "Contents" + ], + "summary": "Queries contents.", + "description": "You can read the generated documentation for your app at /api/content/{appName}/docs.", + "operationId": "Contents_GetContentsPost", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 0 + }, + { + "name": "schema", + "in": "path", + "required": true, + "description": "The name of the schema.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "X-Fields", + "in": "header", + "description": "The list of content fields (comma-separated).", + "schema": { + "type": "string" + }, + "x-position": 3 + }, + { + "name": "X-Flatten", + "in": "header", + "description": "Provide the data as flat object.", + "schema": { + "type": "boolean" + }, + "x-position": 4 + }, + { + "name": "X-Languages", + "in": "header", + "description": "The list of languages to resolve (comma-separated).", + "schema": { + "type": "string" + }, + "x-position": 5 + }, + { + "name": "X-NoSlowTotal", + "in": "header", + "description": "Do not return the total amount, if it would be slow.", + "schema": { + "type": "boolean" + }, + "x-position": 6 + }, + { + "name": "X-NoTotal", + "in": "header", + "description": "Do not return the total amount.", + "schema": { + "type": "boolean" + }, + "x-position": 7 + }, + { + "name": "X-Unpublished", + "in": "header", + "description": "Return unpublished content items.", + "schema": { + "type": "boolean" + }, + "x-position": 8 + } + ], + "requestBody": { + "x-name": "query", + "description": "The required query object.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QueryDto" + } + } + }, + "required": true, + "x-position": 2 + }, + "responses": { + "200": { + "description": "Contents returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContentsDto" + } + } + } + }, + "404": { + "description": "Schema or app not found." + }, + "400": { + "description": "Validation error.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [] + } + ] + } + }, + "/api/content/{app}/{schema}/{id}": { + "get": { + "tags": [ + "Contents" + ], + "summary": "Get a content item.", + "description": "You can read the generated documentation for your app at /api/content/{appName}/docs.", + "operationId": "Contents_GetContent", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 0 + }, + { + "name": "schema", + "in": "path", + "required": true, + "description": "The name of the schema.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the content to fetch.", + "schema": { + "type": "string" + }, + "x-position": 2 + }, + { + "name": "version", + "in": "query", + "description": "The optional version.", + "schema": { + "type": "integer", + "format": "int64", + "default": -2 + }, + "x-position": 3 + }, + { + "name": "X-Fields", + "in": "header", + "description": "The list of content fields (comma-separated).", + "schema": { + "type": "string" + }, + "x-position": 4 + }, + { + "name": "X-Flatten", + "in": "header", + "description": "Provide the data as flat object.", + "schema": { + "type": "boolean" + }, + "x-position": 5 + }, + { + "name": "X-Languages", + "in": "header", + "description": "The list of languages to resolve (comma-separated).", + "schema": { + "type": "string" + }, + "x-position": 6 + }, + { + "name": "X-Unpublished", + "in": "header", + "description": "Return unpublished content items.", + "schema": { + "type": "boolean" + }, + "x-position": 7 + } + ], + "responses": { + "200": { + "description": "Content returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContentDto" + } + } + } + }, + "404": { + "description": "Content, schema or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [] + } + ] + }, + "post": { + "tags": [ + "Contents" + ], + "summary": "Upsert a content item.", + "description": "You can read the generated documentation for your app at /api/content/{appName}/docs.", + "operationId": "Contents_PostUpsertContent", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 0 + }, + { + "name": "schema", + "in": "path", + "required": true, + "description": "The name of the schema.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the content item to update.", + "schema": { + "type": "string" + }, + "x-position": 2 + }, + { + "name": "status", + "in": "query", + "description": "The initial status.", + "schema": { + "type": "string", + "nullable": true + }, + "x-position": 4 + }, + { + "name": "patch", + "in": "query", + "description": "Makes the update as patch.", + "schema": { + "type": "boolean" + }, + "x-position": 5 + }, + { + "name": "enrichDefaults", + "in": "query", + "description": "Enrich the content with defaults.", + "schema": { + "type": "boolean" + }, + "x-position": 6 + }, + { + "name": "publish", + "in": "query", + "description": "True to automatically publish the content.", + "schema": { + "type": "boolean" + }, + "x-position": 7 + }, + { + "name": "X-Unpublished", + "in": "header", + "description": "Return unpublished content items.", + "schema": { + "type": "boolean" + }, + "x-position": 8 + }, + { + "name": "X-Languages", + "in": "header", + "description": "The list of languages to resolve (comma-separated).", + "schema": { + "type": "string" + }, + "x-position": 9 + } + ], + "requestBody": { + "x-name": "Data", + "description": "The full data for the content item.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContentData" + } + } + }, + "required": true, + "x-position": 3 + }, + "responses": { + "200": { + "description": "Content created or updated.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContentDto" + } + } + } + }, + "400": { + "description": "Content request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Content references, schema or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.contents.{schema}.upsert" + ] + } + ] + }, + "put": { + "tags": [ + "Contents" + ], + "summary": "Update a content item.", + "description": "You can read the generated documentation for your app at /api/content/{appName}/docs.", + "operationId": "Contents_PutContent", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 0 + }, + { + "name": "schema", + "in": "path", + "required": true, + "description": "The name of the schema.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the content item to update.", + "schema": { + "type": "string" + }, + "x-position": 2 + }, + { + "name": "enrichDefaults", + "in": "query", + "description": "Enrich the content with defaults.", + "schema": { + "type": "boolean" + }, + "x-position": 4 + }, + { + "name": "X-Unpublished", + "in": "header", + "description": "Return unpublished content items.", + "schema": { + "type": "boolean" + }, + "x-position": 5 + }, + { + "name": "X-Languages", + "in": "header", + "description": "The list of languages to resolve (comma-separated).", + "schema": { + "type": "string" + }, + "x-position": 6 + } + ], + "requestBody": { + "x-name": "Data", + "description": "The full data for the content item.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContentData" + } + } + }, + "required": true, + "x-position": 3 + }, + "responses": { + "200": { + "description": "Content updated.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContentDto" + } + } + } + }, + "400": { + "description": "Content request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Content references, schema or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.contents.{schema}.update.own" + ] + } + ] + }, + "patch": { + "tags": [ + "Contents" + ], + "summary": "Patchs a content item.", + "description": "You can read the generated documentation for your app at /api/content/{appName}/docs.", + "operationId": "Contents_PatchContent", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 0 + }, + { + "name": "schema", + "in": "path", + "required": true, + "description": "The name of the schema.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the content item to patch.", + "schema": { + "type": "string" + }, + "x-position": 2 + }, + { + "name": "X-Unpublished", + "in": "header", + "description": "Return unpublished content items.", + "schema": { + "type": "boolean" + }, + "x-position": 4 + }, + { + "name": "X-Languages", + "in": "header", + "description": "The list of languages to resolve (comma-separated).", + "schema": { + "type": "string" + }, + "x-position": 5 + } + ], + "requestBody": { + "x-name": "request", + "description": "The patch for the content item.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContentData" + } + } + }, + "required": true, + "x-position": 3 + }, + "responses": { + "200": { + "description": "Content patched.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContentDto" + } + } + } + }, + "400": { + "description": "Content request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Content, schema or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.contents.{schema}.update.own" + ] + } + ] + }, + "delete": { + "tags": [ + "Contents" + ], + "summary": "Delete a content item.", + "description": "You can create an generated documentation for your app at /api/content/{appName}/docs.", + "operationId": "Contents_DeleteContent", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "schema", + "in": "path", + "required": true, + "description": "The name of the schema.", + "schema": { + "type": "string" + }, + "x-position": 2 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the content item to delete.", + "schema": { + "type": "string" + }, + "x-position": 3 + }, + { + "name": "checkReferrers", + "in": "query", + "description": "True to check referrers of this content.", + "schema": { + "type": "boolean" + }, + "x-position": 4 + }, + { + "name": "permanent", + "in": "query", + "description": "True to delete the content permanently.", + "schema": { + "type": "boolean" + }, + "x-position": 5 + } + ], + "responses": { + "204": { + "description": "Content deleted." + }, + "400": { + "description": "Content cannot be deleted.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Content, schema or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.contents.{schema}.delete.own" + ] + } + ] + } + }, + "/api/content/{app}/{schema}/{id}/validity": { + "get": { + "tags": [ + "Contents" + ], + "summary": "Get a content item validity.", + "description": "You can read the generated documentation for your app at /api/content/{appName}/docs.", + "operationId": "Contents_GetContentValidity", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "schema", + "in": "path", + "required": true, + "description": "The name of the schema.", + "schema": { + "type": "string" + }, + "x-position": 2 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the content to fetch.", + "schema": { + "type": "string" + }, + "x-position": 3 + } + ], + "responses": { + "204": { + "description": "Content is valid." + }, + "400": { + "description": "Content not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Content, schema or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [] + } + ] + } + }, + "/api/content/{app}/{schema}/{id}/references": { + "get": { + "tags": [ + "Contents" + ], + "summary": "Get all references of a content.", + "description": "You can read the generated documentation for your app at /api/content/{appName}/docs.", + "operationId": "Contents_GetReferences", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 0 + }, + { + "name": "schema", + "in": "path", + "required": true, + "description": "The name of the schema.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the content to fetch.", + "schema": { + "type": "string" + }, + "x-position": 2 + }, + { + "name": "q", + "in": "query", + "description": "The optional json query.", + "schema": { + "type": "string", + "nullable": true + }, + "x-position": 3 + }, + { + "name": "X-Fields", + "in": "header", + "description": "The list of content fields (comma-separated).", + "schema": { + "type": "string" + }, + "x-position": 4 + }, + { + "name": "X-Flatten", + "in": "header", + "description": "Provide the data as flat object.", + "schema": { + "type": "boolean" + }, + "x-position": 5 + }, + { + "name": "X-Languages", + "in": "header", + "description": "The list of languages to resolve (comma-separated).", + "schema": { + "type": "string" + }, + "x-position": 6 + }, + { + "name": "X-Unpublished", + "in": "header", + "description": "Return unpublished content items.", + "schema": { + "type": "boolean" + }, + "x-position": 7 + }, + { + "name": "X-NoSlowTotal", + "in": "header", + "description": "Do not return the total amount, if it would be slow.", + "schema": { + "type": "boolean" + }, + "x-position": 8 + }, + { + "name": "X-NoTotal", + "in": "header", + "description": "Do not return the total amount.", + "schema": { + "type": "boolean" + }, + "x-position": 9 + } + ], + "responses": { + "200": { + "description": "Contents returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContentsDto" + } + } + } + }, + "404": { + "description": "Content, schema or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [] + } + ] + } + }, + "/api/content/{app}/{schema}/{id}/referencing": { + "get": { + "tags": [ + "Contents" + ], + "summary": "Get a referencing contents of a content item.", + "description": "You can read the generated documentation for your app at /api/content/{appName}/docs.", + "operationId": "Contents_GetReferencing", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 0 + }, + { + "name": "schema", + "in": "path", + "required": true, + "description": "The name of the schema.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the content to fetch.", + "schema": { + "type": "string" + }, + "x-position": 2 + }, + { + "name": "q", + "in": "query", + "description": "The optional json query.", + "schema": { + "type": "string", + "nullable": true + }, + "x-position": 3 + }, + { + "name": "X-Fields", + "in": "header", + "description": "The list of content fields (comma-separated).", + "schema": { + "type": "string" + }, + "x-position": 4 + }, + { + "name": "X-Flatten", + "in": "header", + "description": "Provide the data as flat object.", + "schema": { + "type": "boolean" + }, + "x-position": 5 + }, + { + "name": "X-Languages", + "in": "header", + "description": "The list of languages to resolve (comma-separated).", + "schema": { + "type": "string" + }, + "x-position": 6 + }, + { + "name": "X-Unpublished", + "in": "header", + "description": "Return unpublished content items.", + "schema": { + "type": "boolean" + }, + "x-position": 7 + }, + { + "name": "X-NoSlowTotal", + "in": "header", + "description": "Do not return the total amount, if it would be slow.", + "schema": { + "type": "boolean" + }, + "x-position": 8 + }, + { + "name": "X-NoTotal", + "in": "header", + "description": "Do not return the total amount.", + "schema": { + "type": "boolean" + }, + "x-position": 9 + } + ], + "responses": { + "200": { + "description": "Content returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContentsDto" + } + } + } + }, + "404": { + "description": "Content, schema or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [] + } + ] + } + }, + "/api/content/{app}/{schema}/{id}/{version}": { + "get": { + "tags": [ + "Contents" + ], + "summary": "Get a content by version.", + "description": "You can read the generated documentation for your app at /api/content/{appName}/docs.", + "operationId": "Contents_GetContentVersion", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 0 + }, + { + "name": "schema", + "in": "path", + "required": true, + "description": "The name of the schema.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the content to fetch.", + "schema": { + "type": "string" + }, + "x-position": 2 + }, + { + "name": "version", + "in": "path", + "required": true, + "description": "The version fo the content to fetch.", + "schema": { + "type": "integer", + "format": "int32" + }, + "x-position": 3 + }, + { + "name": "X-Unpublished", + "in": "header", + "description": "Return unpublished content items.", + "schema": { + "type": "boolean" + }, + "x-position": 4 + }, + { + "name": "X-Languages", + "in": "header", + "description": "The list of languages to resolve (comma-separated).", + "schema": { + "type": "string" + }, + "x-position": 5 + } + ], + "responses": { + "200": { + "description": "Content version returned.", + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "404": { + "description": "Content, schema or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "deprecated": true, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.contents.{schema}.read.own" + ] + } + ] + } + }, + "/api/content/{app}/{schema}/import": { + "post": { + "tags": [ + "Contents" + ], + "summary": "Import content items.", + "description": "You can read the generated documentation for your app at /api/content/{appName}/docs.", + "operationId": "Contents_PostContents", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "schema", + "in": "path", + "required": true, + "description": "The name of the schema.", + "schema": { + "type": "string" + }, + "x-position": 2 + } + ], + "requestBody": { + "x-name": "request", + "description": "The import request.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ImportContentsDto" + } + } + }, + "required": true, + "x-position": 3 + }, + "responses": { + "200": { + "description": "Contents created.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BulkResultDto" + } + } + } + } + }, + "400": { + "description": "Content request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Content references, schema or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "deprecated": true, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.contents.{schema}.create" + ] + } + ] + } + }, + "/api/content/{app}/{schema}/bulk": { + "post": { + "tags": [ + "Contents" + ], + "summary": "Bulk update content items.", + "description": "You can read the generated documentation for your app at /api/content/{appName}/docs.", + "operationId": "Contents_BulkUpdateContents", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "schema", + "in": "path", + "required": true, + "description": "The name of the schema.", + "schema": { + "type": "string" + }, + "x-position": 2 + } + ], + "requestBody": { + "x-name": "request", + "description": "The bulk update request.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BulkUpdateContentsDto" + } + } + }, + "required": true, + "x-position": 3 + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BulkResultDto" + } + } + } + } + }, + "400": { + "description": "Contents request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Contents references, schema or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.contents.{schema}.read.own" + ] + } + ] + } + }, + "/api/content/{app}/{schema}/{id}/defaults": { + "put": { + "tags": [ + "Contents" + ], + "summary": "Enrich a content item with defaults.", + "description": "You can read the generated documentation for your app at /api/content/{appName}/docs.", + "operationId": "Contents_PutContentDefaults", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 0 + }, + { + "name": "schema", + "in": "path", + "required": true, + "description": "The name of the schema.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the content item to update.", + "schema": { + "type": "string" + }, + "x-position": 2 + }, + { + "name": "enrichRequiredFields", + "in": "query", + "description": "True, to also enrich required fields. Default: false.", + "schema": { + "type": "boolean" + }, + "x-position": 3 + }, + { + "name": "X-Unpublished", + "in": "header", + "description": "Return unpublished content items.", + "schema": { + "type": "boolean" + }, + "x-position": 4 + }, + { + "name": "X-Languages", + "in": "header", + "description": "The list of languages to resolve (comma-separated).", + "schema": { + "type": "string" + }, + "x-position": 5 + } + ], + "responses": { + "200": { + "description": "Content updated.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContentDto" + } + } + } + }, + "404": { + "description": "Content references, schema or app not found." + }, + "400": { + "description": "Validation error.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.contents.{schema}.update.own" + ] + } + ] + } + }, + "/api/content/{app}/{schema}/{id}/status": { + "put": { + "tags": [ + "Contents" + ], + "summary": "Change status of a content item.", + "description": "You can read the generated documentation for your app at /api/content/{appName}/docs.", + "operationId": "Contents_PutContentStatus", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 0 + }, + { + "name": "schema", + "in": "path", + "required": true, + "description": "The name of the schema.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the content item to change.", + "schema": { + "type": "string" + }, + "x-position": 2 + }, + { + "name": "X-Unpublished", + "in": "header", + "description": "Return unpublished content items.", + "schema": { + "type": "boolean" + }, + "x-position": 4 + }, + { + "name": "X-Languages", + "in": "header", + "description": "The list of languages to resolve (comma-separated).", + "schema": { + "type": "string" + }, + "x-position": 5 + } + ], + "requestBody": { + "x-name": "request", + "description": "The status request.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ChangeStatusDto" + } + } + }, + "required": true, + "x-position": 3 + }, + "responses": { + "200": { + "description": "Content status changed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContentDto" + } + } + } + }, + "400": { + "description": "Content request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Content, schema or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.contents.{schema}.changestatus.own" + ] + } + ] + }, + "delete": { + "tags": [ + "Contents" + ], + "summary": "Cancel status change of a content item.", + "description": "You can read the generated documentation for your app at /api/content/{appName}/docs.", + "operationId": "Contents_DeleteContentStatus", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 0 + }, + { + "name": "schema", + "in": "path", + "required": true, + "description": "The name of the schema.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the content item to cancel.", + "schema": { + "type": "string" + }, + "x-position": 2 + }, + { + "name": "X-Unpublished", + "in": "header", + "description": "Return unpublished content items.", + "schema": { + "type": "boolean" + }, + "x-position": 3 + }, + { + "name": "X-Languages", + "in": "header", + "description": "The list of languages to resolve (comma-separated).", + "schema": { + "type": "string" + }, + "x-position": 4 + } + ], + "responses": { + "200": { + "description": "Content status change cancelled.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContentDto" + } + } + } + }, + "400": { + "description": "Content request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Content, schema or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.contents.{schema}.changestatus.own" + ] + } + ] + } + }, + "/api/content/{app}/{schema}/{id}/draft": { + "post": { + "tags": [ + "Contents" + ], + "summary": "Create a new draft version.", + "description": "You can read the generated documentation for your app at /api/content/{appName}/docs.", + "operationId": "Contents_CreateDraft", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 0 + }, + { + "name": "schema", + "in": "path", + "required": true, + "description": "The name of the schema.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the content item to create the draft for.", + "schema": { + "type": "string" + }, + "x-position": 2 + }, + { + "name": "X-Unpublished", + "in": "header", + "description": "Return unpublished content items.", + "schema": { + "type": "boolean" + }, + "x-position": 3 + }, + { + "name": "X-Languages", + "in": "header", + "description": "The list of languages to resolve (comma-separated).", + "schema": { + "type": "string" + }, + "x-position": 4 + } + ], + "responses": { + "200": { + "description": "Content draft created.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContentDto" + } + } + } + }, + "404": { + "description": "Content, schema or app not found." + }, + "400": { + "description": "Validation error.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.contents.{schema}.version.create.own" + ] + } + ] + }, + "delete": { + "tags": [ + "Contents" + ], + "summary": "Delete the draft version.", + "description": "You can read the generated documentation for your app at /api/content/{appName}/docs.", + "operationId": "Contents_DeleteVersion", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 0 + }, + { + "name": "schema", + "in": "path", + "required": true, + "description": "The name of the schema.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the content item to delete the draft from.", + "schema": { + "type": "string" + }, + "x-position": 2 + }, + { + "name": "X-Unpublished", + "in": "header", + "description": "Return unpublished content items.", + "schema": { + "type": "boolean" + }, + "x-position": 3 + }, + { + "name": "X-Languages", + "in": "header", + "description": "The list of languages to resolve (comma-separated).", + "schema": { + "type": "string" + }, + "x-position": 4 + } + ], + "responses": { + "200": { + "description": "Content draft deleted.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContentDto" + } + } + } + }, + "404": { + "description": "Content, schema or app not found." + }, + "400": { + "description": "Validation error.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.contents.{schema}.version.delete.own" + ] + } + ] + } + }, + "/api/content/{app}/graphql": { + "get": { + "tags": [ + "Contents" + ], + "summary": "GraphQL endpoint.", + "description": "You can read the generated documentation for your app at /api/content/{appName}/docs.", + "operationId": "ContentsShared_GetGraphQL", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 0 + }, + { + "name": "The query string", + "in": "query", + "description": "The optional version of the asset.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "variables", + "in": "query", + "description": "The optional operation variables.", + "schema": { + "type": "string", + "nullable": true + }, + "x-position": 2 + }, + { + "name": "operationName", + "in": "query", + "description": "The optional operation name.", + "schema": { + "type": "string", + "nullable": true + }, + "x-position": 3 + }, + { + "name": "X-Unpublished", + "in": "header", + "description": "Return unpublished content items.", + "schema": { + "type": "boolean" + }, + "x-position": 4 + } + ], + "responses": { + "200": { + "description": "Contents returned or mutated.", + "content": { + "application/json": { + "schema": {} + } + } + }, + "404": { + "description": "App not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [] + } + ] + }, + "post": { + "tags": [ + "Contents" + ], + "summary": "GraphQL endpoint.", + "description": "You can read the generated documentation for your app at /api/content/{appName}/docs.", + "operationId": "ContentsShared_PostGraphQL", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 0 + }, + { + "name": "X-Unpublished", + "in": "header", + "description": "Return unpublished content items.", + "schema": { + "type": "boolean" + }, + "x-position": 2 + } + ], + "requestBody": { + "x-name": "request", + "description": "The graphql request.", + "content": { + "application/json": { + "schema": {} + } + }, + "x-position": 1 + }, + "responses": { + "200": { + "description": "Contents returned or mutated.", + "content": { + "application/json": { + "schema": {} + } + } + }, + "404": { + "description": "App not found." + }, + "400": { + "description": "Validation error.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [] + } + ] + } + }, + "/api/content/{app}/graphql/batch": { + "get": { + "tags": [ + "Contents" + ], + "summary": "GraphQL batch endpoint.", + "description": "You can read the generated documentation for your app at /api/content/{appName}/docs.", + "operationId": "ContentsShared_GetGraphQLBatch", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 0 + }, + { + "name": "The query string", + "in": "query", + "description": "The optional version of the asset.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "variables", + "in": "query", + "description": "The optional operation variables.", + "schema": { + "type": "string", + "nullable": true + }, + "x-position": 2 + }, + { + "name": "operationName", + "in": "query", + "description": "The optional operation name.", + "schema": { + "type": "string", + "nullable": true + }, + "x-position": 3 + }, + { + "name": "X-Unpublished", + "in": "header", + "description": "Return unpublished content items.", + "schema": { + "type": "boolean" + }, + "x-position": 4 + } + ], + "responses": { + "200": { + "description": "Contents returned or mutated.", + "content": { + "application/json": { + "schema": {} + } + } + }, + "404": { + "description": "App not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [] + } + ] + }, + "post": { + "tags": [ + "Contents" + ], + "summary": "GraphQL batch endpoint.", + "description": "You can read the generated documentation for your app at /api/content/{appName}/docs.", + "operationId": "ContentsShared_PostGraphQLBatch", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 0 + }, + { + "name": "X-Unpublished", + "in": "header", + "description": "Return unpublished content items.", + "schema": { + "type": "boolean" + }, + "x-position": 2 + } + ], + "requestBody": { + "x-name": "request", + "description": "The graphql request.", + "content": { + "application/json": { + "schema": {} + } + }, + "x-position": 1 + }, + "responses": { + "200": { + "description": "Contents returned or mutated.", + "content": { + "application/json": { + "schema": {} + } + } + }, + "404": { + "description": "App not found." + }, + "400": { + "description": "Validation error.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [] + } + ] + } + }, + "/api/content/{app}": { + "get": { + "tags": [ + "Contents" + ], + "summary": "Queries contents.", + "description": "You can read the generated documentation for your app at /api/content/{appName}/docs.", + "operationId": "ContentsShared_GetAllContents", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 0 + }, + { + "name": "ids", + "in": "query", + "description": "The list of ids to query.", + "schema": { + "type": "string", + "nullable": true + }, + "x-position": 1 + }, + { + "name": "scheduledFrom", + "in": "query", + "description": "The start time of the scheduled content period (see scheduledTo).", + "schema": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "x-position": 2 + }, + { + "name": "scheduledTo", + "in": "query", + "description": "The end time of the scheduled content period (see scheduledFrom).", + "schema": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "x-position": 3 + }, + { + "name": "referencing", + "in": "query", + "description": "The ID of the referencing content item.", + "schema": { + "type": "string", + "nullable": true + }, + "x-position": 4 + }, + { + "name": "references", + "in": "query", + "description": "The ID of the reference content item.", + "schema": { + "type": "string", + "nullable": true + }, + "x-position": 5 + }, + { + "name": "q", + "in": "query", + "description": "The optional json query.", + "schema": { + "type": "string", + "nullable": true + }, + "x-position": 6 + }, + { + "name": "X-Fields", + "in": "header", + "description": "The list of content fields (comma-separated).", + "schema": { + "type": "string" + }, + "x-position": 7 + }, + { + "name": "X-Flatten", + "in": "header", + "description": "Provide the data as flat object.", + "schema": { + "type": "boolean" + }, + "x-position": 8 + }, + { + "name": "X-Languages", + "in": "header", + "description": "The list of languages to resolve (comma-separated).", + "schema": { + "type": "string" + }, + "x-position": 9 + }, + { + "name": "X-NoSlowTotal", + "in": "header", + "description": "Do not return the total amount, if it would be slow.", + "schema": { + "type": "boolean" + }, + "x-position": 10 + }, + { + "name": "X-NoTotal", + "in": "header", + "description": "Do not return the total amount.", + "schema": { + "type": "boolean" + }, + "x-position": 11 + }, + { + "name": "X-Unpublished", + "in": "header", + "description": "Return unpublished content items.", + "schema": { + "type": "boolean" + }, + "x-position": 12 + } + ], + "responses": { + "200": { + "description": "Contents returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContentsDto" + } + } + } + }, + "404": { + "description": "App not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [] + } + ] + }, + "post": { + "tags": [ + "Contents" + ], + "summary": "Queries contents.", + "description": "You can read the generated documentation for your app at /api/content/{appName}/docs.", + "operationId": "ContentsShared_GetAllContentsPost", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 0 + }, + { + "name": "X-Fields", + "in": "header", + "description": "The list of content fields (comma-separated).", + "schema": { + "type": "string" + }, + "x-position": 2 + }, + { + "name": "X-Flatten", + "in": "header", + "description": "Provide the data as flat object.", + "schema": { + "type": "boolean" + }, + "x-position": 3 + }, + { + "name": "X-Languages", + "in": "header", + "description": "The list of languages to resolve (comma-separated).", + "schema": { + "type": "string" + }, + "x-position": 4 + }, + { + "name": "X-NoSlowTotal", + "in": "header", + "description": "Do not return the total amount, if it would be slow.", + "schema": { + "type": "boolean" + }, + "x-position": 5 + }, + { + "name": "X-NoTotal", + "in": "header", + "description": "Do not return the total amount.", + "schema": { + "type": "boolean" + }, + "x-position": 6 + }, + { + "name": "X-Unpublished", + "in": "header", + "description": "Return unpublished content items.", + "schema": { + "type": "boolean" + }, + "x-position": 7 + } + ], + "requestBody": { + "x-name": "query", + "description": "The required query object.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AllContentsByPostDto" + } + } + }, + "required": true, + "x-position": 1 + }, + "responses": { + "200": { + "description": "Contents returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContentsDto" + } + } + } + }, + "404": { + "description": "App not found." + }, + "400": { + "description": "Validation error.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [] + } + ] + } + }, + "/api/content/{app}/bulk": { + "post": { + "tags": [ + "Contents" + ], + "summary": "Bulk update content items.", + "description": "You can read the generated documentation for your app at /api/content/{appName}/docs.", + "operationId": "ContentsShared_BulkUpdateAllContents", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "schema", + "in": "query", + "description": "The name of the schema.", + "schema": { + "type": "string" + }, + "x-position": 2 + } + ], + "requestBody": { + "x-name": "request", + "description": "The bulk update request.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BulkUpdateContentsDto" + } + } + }, + "required": true, + "x-position": 3 + }, + "responses": { + "200": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BulkResultDto" + } + } + } + } + }, + "400": { + "description": "Contents request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Contents references, schema or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.contents.{schema}.read.own" + ] + } + ] + } + }, + "/api/apps/{app}/backups/{id}": { + "get": { + "tags": [ + "Backups" + ], + "summary": "Get the backup content.", + "operationId": "BackupContent_GetBackupContent", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the backup.", + "schema": { + "type": "string" + }, + "x-position": 2 + } + ], + "responses": { + "200": { + "description": "Backup found and content returned.", + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "404": { + "description": "Backup or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "deprecated": true + }, + "delete": { + "tags": [ + "Backups" + ], + "summary": "Delete a backup.", + "operationId": "Backups_DeleteBackup", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the backup to delete.", + "schema": { + "type": "string" + }, + "x-position": 2 + } + ], + "responses": { + "204": { + "description": "Backup deleted." + }, + "404": { + "description": "Backup or app not found." + }, + "400": { + "description": "Validation error.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "deprecated": true, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.jobs.delete" + ] + } + ] + } + }, + "/api/apps/backups/{id}": { + "get": { + "tags": [ + "Backups" + ], + "summary": "Get the backup content.", + "operationId": "BackupContent_GetBackupContentV2", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the backup.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "appId", + "in": "query", + "description": "The ID of the app.", + "schema": { + "type": "string" + }, + "x-position": 2 + }, + { + "name": "app", + "in": "query", + "description": "The name of the app.", + "schema": { + "type": "string", + "default": "" + }, + "x-position": 3 + } + ], + "responses": { + "200": { + "description": "Backup found and content returned.", + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "404": { + "description": "Backup or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "deprecated": true + } + }, + "/api/apps/{app}/backups": { + "get": { + "tags": [ + "Backups" + ], + "summary": "Get all backup jobs.", + "operationId": "Backups_GetBackups", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "responses": { + "200": { + "description": "Backups returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BackupJobsDto" + } + } + } + }, + "404": { + "description": "App not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "deprecated": true, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.jobs.read" + ] + } + ] + }, + "post": { + "tags": [ + "Backups" + ], + "summary": "Start a new backup.", + "operationId": "Backups_PostBackup", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "responses": { + "204": { + "description": "Backup started." + }, + "400": { + "description": "Backup contingent reached.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "App not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.jobs.create" + ] + } + ] + } + }, + "/api/apps/restore": { + "get": { + "tags": [ + "Backups" + ], + "summary": "Get current restore status.", + "operationId": "Restore_GetRestoreJob", + "responses": { + "200": { + "description": "Status returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RestoreJobDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.admin.restore" + ] + } + ] + }, + "post": { + "tags": [ + "Backups" + ], + "summary": "Restore a backup.", + "operationId": "Restore_PostRestoreJob", + "requestBody": { + "x-name": "request", + "description": "The backup to restore.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RestoreRequestDto" + } + } + }, + "required": true, + "x-position": 1 + }, + "responses": { + "204": { + "description": "Restore operation started." + }, + "400": { + "description": "Validation error.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.admin.restore" + ] + } + ] + } + }, + "/api/assets/{app}/{idOrSlug}/{more}": { + "get": { + "tags": [ + "Assets" + ], + "summary": "Get the asset content.", + "operationId": "AssetContent_GetAssetContentBySlug", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "idOrSlug", + "in": "path", + "required": true, + "description": "The id or slug of the asset.", + "schema": { + "type": "string" + }, + "x-position": 2 + }, + { + "name": "version", + "in": "query", + "description": "The optional version of the asset.", + "schema": { + "type": "integer", + "format": "int64" + }, + "x-position": 3 + }, + { + "name": "cache", + "in": "query", + "description": "The cache duration in seconds.", + "schema": { + "type": "integer", + "format": "int64" + }, + "x-position": 4 + }, + { + "name": "download", + "in": "query", + "description": "Set it to 0 to prevent download.", + "schema": { + "type": "integer", + "format": "int32" + }, + "x-position": 5 + }, + { + "name": "width", + "in": "query", + "description": "The target width of the asset, if it is an image.", + "schema": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "x-position": 6 + }, + { + "name": "height", + "in": "query", + "description": "The target height of the asset, if it is an image.", + "schema": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "x-position": 7 + }, + { + "name": "quality", + "in": "query", + "description": "Optional image quality, it is is an jpeg image.", + "schema": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "x-position": 8 + }, + { + "name": "mode", + "in": "query", + "description": "The resize mode when the width and height is defined.", + "schema": { + "nullable": true, + "$ref": "#/components/schemas/ResizeMode" + }, + "x-position": 9 + }, + { + "name": "bg", + "in": "query", + "description": "Optional background color.", + "schema": { + "type": "string", + "nullable": true + }, + "x-position": 10 + }, + { + "name": "focusX", + "in": "query", + "description": "Override the y focus point.", + "schema": { + "type": "number", + "format": "float", + "nullable": true + }, + "x-position": 11 + }, + { + "name": "focusY", + "in": "query", + "description": "Override the x focus point.", + "schema": { + "type": "number", + "format": "float", + "nullable": true + }, + "x-position": 12 + }, + { + "name": "nofocus", + "in": "query", + "description": "True to ignore the asset focus point if any.", + "schema": { + "type": "boolean" + }, + "x-position": 13 + }, + { + "name": "auto", + "in": "query", + "description": "True to use auto format.", + "schema": { + "type": "boolean" + }, + "x-position": 14 + }, + { + "name": "force", + "in": "query", + "description": "True to force a new resize even if it already stored.", + "schema": { + "type": "boolean" + }, + "x-position": 15 + }, + { + "name": "deleted", + "in": "query", + "description": "Also return deleted content items.", + "schema": { + "type": "boolean" + }, + "x-position": 16 + }, + { + "name": "format", + "in": "query", + "description": "True to force a new resize even if it already stored.", + "schema": { + "nullable": true, + "$ref": "#/components/schemas/ImageFormat" + }, + "x-position": 17 + }, + { + "name": "watermarkUrl", + "in": "query", + "description": "Adds the image with the given URL on to of your image. If the watermark cannot be loaded or found, the watermark is just ignored.", + "schema": { + "type": "string", + "nullable": true + }, + "x-position": 18 + }, + { + "name": "watermarkOpacity", + "in": "query", + "description": "The opacity of the watermark image.", + "schema": { + "type": "number", + "format": "float" + }, + "x-position": 19 + }, + { + "name": "watermarkAnchor", + "in": "query", + "description": "The anchor where the watermark should be placed.", + "schema": { + "$ref": "#/components/schemas/WatermarkAnchor" + }, + "x-position": 20 + }, + { + "name": "more", + "in": "path", + "required": true, + "description": "Optional suffix that can be used to seo-optimize the link to the image Has not effect.", + "schema": { + "type": "string" + }, + "x-position": 21 + } + ], + "responses": { + "200": { + "description": "Asset found and content or (resized) image returned.", + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "404": { + "description": "Asset or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [] + } + ] + } + }, + "/api/assets/{id}": { + "get": { + "tags": [ + "Assets" + ], + "summary": "Get the asset content.", + "operationId": "AssetContent_GetAssetContent", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the asset.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "version", + "in": "query", + "description": "The optional version of the asset.", + "schema": { + "type": "integer", + "format": "int64" + }, + "x-position": 2 + }, + { + "name": "cache", + "in": "query", + "description": "The cache duration in seconds.", + "schema": { + "type": "integer", + "format": "int64" + }, + "x-position": 3 + }, + { + "name": "download", + "in": "query", + "description": "Set it to 0 to prevent download.", + "schema": { + "type": "integer", + "format": "int32" + }, + "x-position": 4 + }, + { + "name": "width", + "in": "query", + "description": "The target width of the asset, if it is an image.", + "schema": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "x-position": 5 + }, + { + "name": "height", + "in": "query", + "description": "The target height of the asset, if it is an image.", + "schema": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "x-position": 6 + }, + { + "name": "quality", + "in": "query", + "description": "Optional image quality, it is is an jpeg image.", + "schema": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "x-position": 7 + }, + { + "name": "mode", + "in": "query", + "description": "The resize mode when the width and height is defined.", + "schema": { + "nullable": true, + "$ref": "#/components/schemas/ResizeMode" + }, + "x-position": 8 + }, + { + "name": "bg", + "in": "query", + "description": "Optional background color.", + "schema": { + "type": "string", + "nullable": true + }, + "x-position": 9 + }, + { + "name": "focusX", + "in": "query", + "description": "Override the y focus point.", + "schema": { + "type": "number", + "format": "float", + "nullable": true + }, + "x-position": 10 + }, + { + "name": "focusY", + "in": "query", + "description": "Override the x focus point.", + "schema": { + "type": "number", + "format": "float", + "nullable": true + }, + "x-position": 11 + }, + { + "name": "nofocus", + "in": "query", + "description": "True to ignore the asset focus point if any.", + "schema": { + "type": "boolean" + }, + "x-position": 12 + }, + { + "name": "auto", + "in": "query", + "description": "True to use auto format.", + "schema": { + "type": "boolean" + }, + "x-position": 13 + }, + { + "name": "force", + "in": "query", + "description": "True to force a new resize even if it already stored.", + "schema": { + "type": "boolean" + }, + "x-position": 14 + }, + { + "name": "deleted", + "in": "query", + "description": "Also return deleted content items.", + "schema": { + "type": "boolean" + }, + "x-position": 15 + }, + { + "name": "format", + "in": "query", + "description": "True to force a new resize even if it already stored.", + "schema": { + "nullable": true, + "$ref": "#/components/schemas/ImageFormat" + }, + "x-position": 16 + }, + { + "name": "watermarkUrl", + "in": "query", + "description": "Adds the image with the given URL on to of your image. If the watermark cannot be loaded or found, the watermark is just ignored.", + "schema": { + "type": "string", + "nullable": true + }, + "x-position": 17 + }, + { + "name": "watermarkOpacity", + "in": "query", + "description": "The opacity of the watermark image.", + "schema": { + "type": "number", + "format": "float" + }, + "x-position": 18 + }, + { + "name": "watermarkAnchor", + "in": "query", + "description": "The anchor where the watermark should be placed.", + "schema": { + "$ref": "#/components/schemas/WatermarkAnchor" + }, + "x-position": 19 + } + ], + "responses": { + "200": { + "description": "Asset found and content or (resized) image returned.", + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "404": { + "description": "Asset or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "deprecated": true, + "security": [ + { + "squidex-oauth-auth": [] + } + ] + } + }, + "/api/apps/{app}/assets/folders": { + "get": { + "tags": [ + "Assets" + ], + "summary": "Get asset folders.", + "description": "Get all asset folders for the app.", + "operationId": "AssetFolders_GetAssetFolders", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "parentId", + "in": "query", + "description": "The optional parent folder id.", + "schema": { + "type": "string", + "nullable": true + }, + "x-position": 2 + }, + { + "name": "scope", + "in": "query", + "description": "The scope of the query.", + "schema": { + "default": "PathAndItems", + "$ref": "#/components/schemas/AssetFolderScope" + }, + "x-position": 3 + } + ], + "responses": { + "200": { + "description": "Asset folders returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AssetFoldersDto" + } + } + } + }, + "404": { + "description": "App not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.assets.read" + ] + } + ] + }, + "post": { + "tags": [ + "Assets" + ], + "summary": "Create an asset folder.", + "operationId": "AssetFolders_PostAssetFolder", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "requestBody": { + "x-name": "request", + "description": "The asset folder object that needs to be added to the App.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateAssetFolderDto" + } + } + }, + "required": true, + "x-position": 2 + }, + "responses": { + "201": { + "description": "Asset folder created.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AssetFolderDto" + } + } + } + }, + "400": { + "description": "Asset folder request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "App not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.assets.folders.create" + ] + } + ] + } + }, + "/api/apps/{app}/assets/folders/{id}": { + "put": { + "tags": [ + "Assets" + ], + "summary": "Update an asset folder.", + "operationId": "AssetFolders_PutAssetFolder", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the asset folder.", + "schema": { + "type": "string" + }, + "x-position": 2 + } + ], + "requestBody": { + "x-name": "request", + "description": "The asset folder object that needs to updated.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RenameAssetFolderDto" + } + } + }, + "required": true, + "x-position": 3 + }, + "responses": { + "200": { + "description": "Asset folder updated.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AssetFolderDto" + } + } + } + }, + "400": { + "description": "Asset folder request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Asset folder or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.assets.folders.update" + ] + } + ] + }, + "delete": { + "tags": [ + "Assets" + ], + "summary": "Delete an asset folder.", + "operationId": "AssetFolders_DeleteAssetFolder", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the asset folder to delete.", + "schema": { + "type": "string" + }, + "x-position": 2 + } + ], + "responses": { + "204": { + "description": "Asset folder deleted." + }, + "404": { + "description": "Asset folder or app not found." + }, + "400": { + "description": "Validation error.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.assets.folders.delete" + ] + } + ] + } + }, + "/api/apps/{app}/assets/folders/{id}/parent": { + "put": { + "tags": [ + "Assets" + ], + "summary": "Move an asset folder.", + "operationId": "AssetFolders_PutAssetFolderParent", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the asset folder.", + "schema": { + "type": "string" + }, + "x-position": 2 + } + ], + "requestBody": { + "x-name": "request", + "description": "The asset folder object that needs to updated.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MoveAssetFolderDto" + } + } + }, + "required": true, + "x-position": 3 + }, + "responses": { + "200": { + "description": "Asset folder moved.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AssetFolderDto" + } + } + } + }, + "400": { + "description": "Asset folder request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Asset folder or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.assets.folders.update" + ] + } + ] + } + }, + "/api/apps/{app}/assets/tags": { + "get": { + "tags": [ + "Assets" + ], + "summary": "Get assets tags.", + "description": "Get all tags for assets.", + "operationId": "Assets_GetTags", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "responses": { + "200": { + "description": "Assets tags returned.", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": { + "type": "integer", + "format": "int32" + } + } + } + } + }, + "404": { + "description": "App not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.assets.read" + ] + } + ] + } + }, + "/api/apps/{app}/assets/tags/{name}": { + "put": { + "tags": [ + "Assets" + ], + "summary": "Rename an asset tag.", + "operationId": "Assets_PutTag", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "name", + "in": "path", + "required": true, + "description": "The tag to return.", + "schema": { + "type": "string" + }, + "x-position": 2 + } + ], + "requestBody": { + "x-name": "request", + "description": "The required request object.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RenameTagDto" + } + } + }, + "required": true, + "x-position": 3 + }, + "responses": { + "200": { + "description": "Asset tag renamed and new tags returned.", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": { + "type": "integer", + "format": "int32" + } + } + } + } + }, + "404": { + "description": "App not found." + }, + "400": { + "description": "Validation error.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.assets.update" + ] + } + ] + } + }, + "/api/apps/{app}/assets": { + "get": { + "tags": [ + "Assets" + ], + "summary": "Get assets.", + "description": "Get all assets for the app.", + "operationId": "Assets_GetAssets", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 0 + }, + { + "name": "parentId", + "in": "query", + "description": "The optional parent folder id.", + "schema": { + "type": "string", + "nullable": true + }, + "x-position": 1 + }, + { + "name": "ids", + "in": "query", + "description": "The optional asset ids.", + "schema": { + "type": "string", + "nullable": true + }, + "x-position": 2 + }, + { + "name": "q", + "in": "query", + "description": "The optional json query.", + "schema": { + "type": "string", + "nullable": true + }, + "x-position": 3 + }, + { + "name": "$top", + "in": "query", + "description": "Optional number of items to take.", + "schema": { + "type": "number" + }, + "x-position": 4 + }, + { + "name": "$skip", + "in": "query", + "description": "Optional number of items to skip.", + "schema": { + "type": "number" + }, + "x-position": 5 + }, + { + "name": "$orderby", + "in": "query", + "description": "Optional OData order definition.", + "schema": { + "type": "string" + }, + "x-position": 6 + }, + { + "name": "$filter", + "in": "query", + "description": "Optional OData filter.", + "schema": { + "type": "string" + }, + "x-position": 7 + }, + { + "name": "X-NoTotal", + "in": "header", + "description": "Do not return the total amount.", + "schema": { + "type": "boolean" + }, + "x-position": 8 + }, + { + "name": "X-NoSlowTotal", + "in": "header", + "description": "Do not return the total amount, if it would be slow.", + "schema": { + "type": "boolean" + }, + "x-position": 9 + } + ], + "responses": { + "200": { + "description": "Assets returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AssetsDto" + } + } + } + }, + "404": { + "description": "App not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.assets.read" + ] + } + ] + }, + "post": { + "tags": [ + "Assets" + ], + "summary": "Upload a new asset.", + "description": "You can only upload one file at a time. The mime type of the file is not calculated by Squidex and is required correctly.", + "operationId": "Assets_PostAsset", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "ParentId", + "in": "query", + "description": "The optional parent folder id.", + "schema": { + "type": "string" + }, + "x-position": 2 + }, + { + "name": "id", + "in": "query", + "description": "The optional custom asset id.", + "schema": { + "type": "string", + "nullable": true + }, + "x-position": 3 + }, + { + "name": "duplicate", + "in": "query", + "description": "True to duplicate the asset, event if the file has been uploaded.", + "schema": { + "type": "boolean" + }, + "x-position": 4 + } + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "properties": { + "file": { + "type": "string", + "format": "binary" + }, + "url": { + "type": "string" + }, + "name": { + "type": "string" + } + } + } + } + } + }, + "responses": { + "201": { + "description": "Asset created.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AssetDto" + } + } + } + }, + "400": { + "description": "Asset request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "413": { + "description": "Asset exceeds the maximum upload size.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "App not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.assets.create" + ] + } + ] + } + }, + "/api/apps/{app}/assets/query": { + "post": { + "tags": [ + "Assets" + ], + "summary": "Get assets.", + "description": "Get all assets for the app.", + "operationId": "Assets_GetAssetsPost", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 0 + }, + { + "name": "X-NoTotal", + "in": "header", + "description": "Do not return the total amount.", + "schema": { + "type": "boolean" + }, + "x-position": 2 + }, + { + "name": "X-NoSlowTotal", + "in": "header", + "description": "Do not return the total amount, if it would be slow.", + "schema": { + "type": "boolean" + }, + "x-position": 3 + } + ], + "requestBody": { + "x-name": "query", + "description": "The required query object.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/QueryDto" + } + } + }, + "required": true, + "x-position": 1 + }, + "responses": { + "200": { + "description": "Assets returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AssetsDto" + } + } + } + }, + "404": { + "description": "App not found." + }, + "400": { + "description": "Validation error.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.assets.read" + ] + } + ] + } + }, + "/api/apps/{app}/assets/{id}": { + "get": { + "tags": [ + "Assets" + ], + "summary": "Get an asset by id.", + "operationId": "Assets_GetAsset", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the asset to retrieve.", + "schema": { + "type": "string" + }, + "x-position": 2 + } + ], + "responses": { + "200": { + "description": "Asset found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AssetDto" + } + } + } + }, + "404": { + "description": "Asset or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.assets.read" + ] + } + ] + }, + "post": { + "tags": [ + "Assets" + ], + "summary": "Upsert an asset.", + "description": "You can only upload one file at a time. The mime type of the file is not calculated by Squidex and is required correctly.", + "operationId": "Assets_PostUpsertAsset", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The optional custom asset id.", + "schema": { + "type": "string" + }, + "x-position": 2 + }, + { + "name": "parentId", + "in": "query", + "description": "The optional parent folder id.", + "schema": { + "type": "string" + }, + "x-position": 3 + }, + { + "name": "duplicate", + "in": "query", + "description": "True to duplicate the asset, event if the file has been uploaded.", + "schema": { + "type": "boolean" + }, + "x-position": 4 + } + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "properties": { + "file": { + "type": "string", + "format": "binary" + }, + "url": { + "type": "string" + }, + "name": { + "type": "string" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Asset created or updated.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AssetDto" + } + } + } + }, + "400": { + "description": "Asset request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "413": { + "description": "Asset exceeds the maximum upload size.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "App not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.assets.create" + ] + } + ] + }, + "put": { + "tags": [ + "Assets" + ], + "summary": "Update an asset.", + "operationId": "Assets_PutAsset", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the asset.", + "schema": { + "type": "string" + }, + "x-position": 2 + } + ], + "requestBody": { + "x-name": "request", + "description": "The asset object that needs to updated.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AnnotateAssetDto" + } + } + }, + "required": true, + "x-position": 3 + }, + "responses": { + "200": { + "description": "Asset updated.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AssetDto" + } + } + } + }, + "400": { + "description": "Asset request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Asset or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.assets.update" + ] + } + ] + }, + "delete": { + "tags": [ + "Assets" + ], + "summary": "Delete an asset.", + "operationId": "Assets_DeleteAsset", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the asset to delete.", + "schema": { + "type": "string" + }, + "x-position": 2 + }, + { + "name": "checkReferrers", + "in": "query", + "description": "True to check referrers of this asset.", + "schema": { + "type": "boolean" + }, + "x-position": 3 + }, + { + "name": "permanent", + "in": "query", + "description": "True to delete the asset permanently.", + "schema": { + "type": "boolean" + }, + "x-position": 4 + } + ], + "responses": { + "204": { + "description": "Asset deleted." + }, + "404": { + "description": "Asset or app not found." + }, + "400": { + "description": "Validation error.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.assets.delete" + ] + } + ] + } + }, + "/api/apps/{app}/assets/bulk": { + "post": { + "tags": [ + "Assets" + ], + "summary": "Bulk update assets.", + "operationId": "Assets_BulkUpdateAssets", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "requestBody": { + "x-name": "request", + "description": "The bulk update request.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BulkUpdateAssetsDto" + } + } + }, + "required": true, + "x-position": 2 + }, + "responses": { + "200": { + "description": "Assets created, update or delete.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BulkResultDto" + } + } + } + } + }, + "400": { + "description": "Assets request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "App not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.assets.read" + ] + } + ] + } + }, + "/api/apps/{app}/assets/{id}/content": { + "put": { + "tags": [ + "Assets" + ], + "summary": "Replace asset content.", + "description": "Use multipart request to upload an asset.", + "operationId": "Assets_PutAssetContent", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the asset.", + "schema": { + "type": "string" + }, + "x-position": 2 + } + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "properties": { + "file": { + "type": "string", + "format": "binary" + }, + "url": { + "type": "string" + }, + "name": { + "type": "string" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Asset updated.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AssetDto" + } + } + } + }, + "400": { + "description": "Asset request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "413": { + "description": "Asset exceeds the maximum upload size.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Asset or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.assets.upload" + ] + } + ] + } + }, + "/api/apps/{app}/assets/{id}/parent": { + "put": { + "tags": [ + "Assets" + ], + "summary": "Moves the asset.", + "operationId": "Assets_PutAssetParent", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the asset.", + "schema": { + "type": "string" + }, + "x-position": 2 + } + ], + "requestBody": { + "x-name": "request", + "description": "The asset object that needs to updated.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MoveAssetDto" + } + } + }, + "required": true, + "x-position": 3 + }, + "responses": { + "200": { + "description": "Asset moved.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AssetDto" + } + } + } + }, + "400": { + "description": "Asset request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Asset or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.assets.update" + ] + } + ] + } + }, + "/api/apps/{app}/assets/scripts": { + "get": { + "tags": [ + "Apps" + ], + "summary": "Get the app asset scripts.", + "operationId": "AppAssets_GetAssetScripts", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app to get the asset scripts for.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "responses": { + "200": { + "description": "Asset scripts returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AssetScriptsDto" + } + } + } + }, + "404": { + "description": "App not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.asset-scripts.read" + ] + } + ] + }, + "put": { + "tags": [ + "Apps" + ], + "summary": "Update the asset scripts.", + "operationId": "AppAssets_PutAssetScripts", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app to update.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "requestBody": { + "x-name": "request", + "description": "The values to update.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateAssetScriptsDto" + } + } + }, + "required": true, + "x-position": 2 + }, + "responses": { + "200": { + "description": "Asset scripts updated.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AssetScriptsDto" + } + } + } + }, + "400": { + "description": "Asset request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "App not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.asset-scripts.update" + ] + } + ] + } + }, + "/api/apps/{app}/clients": { + "get": { + "tags": [ + "Apps" + ], + "summary": "Get app clients.", + "description": "Gets all configured clients for the app with the specified name.", + "operationId": "AppClients_GetClients", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "responses": { + "200": { + "description": "Clients returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ClientsDto" + } + } + } + }, + "404": { + "description": "App not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.clients.read" + ] + } + ] + }, + "post": { + "tags": [ + "Apps" + ], + "summary": "Create a new app client.", + "description": "Create a new client for the app with the specified name.\nThe client secret is auto generated on the server and returned. The client does not expire, the access token is valid for 30 days.", + "operationId": "AppClients_PostClient", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "requestBody": { + "x-name": "request", + "description": "Client object that needs to be added to the app.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateClientDto" + } + } + }, + "required": true, + "x-position": 2 + }, + "responses": { + "201": { + "description": "Client created.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ClientsDto" + } + } + } + }, + "400": { + "description": "Client request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "App not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.clients.create" + ] + } + ] + } + }, + "/api/apps/{app}/clients/{id}": { + "put": { + "tags": [ + "Apps" + ], + "summary": "Updates an app client.", + "description": "Only the display name can be changed, create a new client if necessary.", + "operationId": "AppClients_PutClient", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the client that must be updated.", + "schema": { + "type": "string" + }, + "x-position": 2 + } + ], + "requestBody": { + "x-name": "request", + "description": "Client object that needs to be updated.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateClientDto" + } + } + }, + "required": true, + "x-position": 3 + }, + "responses": { + "200": { + "description": "Client updated.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ClientsDto" + } + } + } + }, + "400": { + "description": "Client request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Client or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.clients.update" + ] + } + ] + }, + "delete": { + "tags": [ + "Apps" + ], + "summary": "Revoke an app client.", + "description": "The application that uses this client credentials cannot access the API after it has been revoked.", + "operationId": "AppClients_DeleteClient", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the client that must be deleted.", + "schema": { + "type": "string" + }, + "x-position": 2 + } + ], + "responses": { + "200": { + "description": "Client deleted.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ClientsDto" + } + } + } + }, + "404": { + "description": "Client or app not found." + }, + "400": { + "description": "Validation error.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.clients.delete" + ] + } + ] + } + }, + "/api/apps/{app}/contributors": { + "get": { + "tags": [ + "Apps" + ], + "summary": "Get app contributors.", + "operationId": "AppContributors_GetContributors", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "responses": { + "200": { + "description": "Contributors returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContributorsDto" + } + } + } + }, + "404": { + "description": "App not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.contributors.read" + ] + } + ] + }, + "post": { + "tags": [ + "Apps" + ], + "summary": "Assign contributor to app.", + "operationId": "AppContributors_PostContributor", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "requestBody": { + "x-name": "request", + "description": "Contributor object that needs to be added to the app.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AssignContributorDto" + } + } + }, + "required": true, + "x-position": 2 + }, + "responses": { + "201": { + "description": "Contributor assigned to app.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContributorsDto" + } + } + } + }, + "400": { + "description": "Contributor request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "App not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.contributors.assign" + ] + } + ] + } + }, + "/api/apps/{app}/contributors/me": { + "delete": { + "tags": [ + "Apps" + ], + "summary": "Remove yourself.", + "operationId": "AppContributors_DeleteMyself", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "responses": { + "200": { + "description": "Contributor removed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContributorsDto" + } + } + } + }, + "404": { + "description": "Contributor or app not found." + }, + "400": { + "description": "Validation error.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [] + } + ] + } + }, + "/api/apps/{app}/contributors/{id}": { + "delete": { + "tags": [ + "Apps" + ], + "summary": "Remove contributor.", + "operationId": "AppContributors_DeleteContributor", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the contributor.", + "schema": { + "type": "string" + }, + "x-position": 2 + } + ], + "responses": { + "200": { + "description": "Contributor removed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContributorsDto" + } + } + } + }, + "404": { + "description": "Contributor or app not found." + }, + "400": { + "description": "Validation error.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.contributors.revoke" + ] + } + ] + } + }, + "/api/apps/{app}/image": { + "get": { + "tags": [ + "Apps" + ], + "summary": "Get the app image.", + "operationId": "AppImage_GetImage", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "responses": { + "200": { + "description": "App image found and content or (resized) image returned.", + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "404": { + "description": "App not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + } + }, + "post": { + "tags": [ + "Apps" + ], + "summary": "Upload the app image.", + "operationId": "Apps_UploadImage", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app to update.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "requestBody": { + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "properties": { + "file": { + "type": "string", + "format": "binary" + }, + "url": { + "type": "string" + }, + "name": { + "type": "string" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "App image uploaded.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AppDto" + } + } + } + }, + "400": { + "description": "App request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "App not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.image" + ] + } + ] + }, + "delete": { + "tags": [ + "Apps" + ], + "summary": "Remove the app image.", + "operationId": "Apps_DeleteImage", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app to update.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "responses": { + "200": { + "description": "App image removed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AppDto" + } + } + } + }, + "404": { + "description": "App not found." + }, + "400": { + "description": "Validation error.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.image" + ] + } + ] + } + }, + "/api/apps/{app}/languages": { + "get": { + "tags": [ + "Apps" + ], + "summary": "Get app languages.", + "operationId": "AppLanguages_GetLanguages", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "responses": { + "200": { + "description": "Languages returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AppLanguagesDto" + } + } + } + }, + "404": { + "description": "App not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.languages.read" + ] + } + ] + }, + "post": { + "tags": [ + "Apps" + ], + "summary": "Add an app language.", + "operationId": "AppLanguages_PostLanguage", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "requestBody": { + "x-name": "request", + "description": "The language to add to the app.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AddLanguageDto" + } + } + }, + "required": true, + "x-position": 2 + }, + "responses": { + "201": { + "description": "Language created.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AppLanguagesDto" + } + } + } + }, + "400": { + "description": "Language request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "App not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.languages.create" + ] + } + ] + } + }, + "/api/apps/{app}/languages/{language}": { + "put": { + "tags": [ + "Apps" + ], + "summary": "Updates an app language.", + "operationId": "AppLanguages_PutLanguage", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "language", + "in": "path", + "required": true, + "description": "The language to update.", + "schema": { + "type": "string" + }, + "x-position": 2 + } + ], + "requestBody": { + "x-name": "request", + "description": "The language object.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateLanguageDto" + } + } + }, + "required": true, + "x-position": 3 + }, + "responses": { + "200": { + "description": "Language updated.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AppLanguagesDto" + } + } + } + }, + "400": { + "description": "Language request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Language or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.languages.update" + ] + } + ] + }, + "delete": { + "tags": [ + "Apps" + ], + "summary": "Deletes an app language.", + "operationId": "AppLanguages_DeleteLanguage", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "language", + "in": "path", + "required": true, + "description": "The language to delete from the app.", + "schema": { + "type": "string" + }, + "x-position": 2 + } + ], + "responses": { + "200": { + "description": "Language deleted.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AppLanguagesDto" + } + } + } + }, + "400": { + "description": "Language is master language.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Language or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.languages.delete" + ] + } + ] + } + }, + "/api/apps/{app}/roles": { + "get": { + "tags": [ + "Apps" + ], + "summary": "Get app roles.", + "operationId": "AppRoles_GetRoles", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "responses": { + "200": { + "description": "Roles returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RolesDto" + } + } + } + }, + "404": { + "description": "App not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.roles.read" + ] + } + ] + }, + "post": { + "tags": [ + "Apps" + ], + "summary": "Add role to app.", + "operationId": "AppRoles_PostRole", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "requestBody": { + "x-name": "request", + "description": "Role object that needs to be added to the app.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AddRoleDto" + } + } + }, + "required": true, + "x-position": 2 + }, + "responses": { + "201": { + "description": "Role created.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RolesDto" + } + } + } + }, + "400": { + "description": "Role request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "App not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.roles.create" + ] + } + ] + } + }, + "/api/apps/{app}/roles/permissions": { + "get": { + "tags": [ + "Apps" + ], + "summary": "Get app permissions.", + "operationId": "AppRoles_GetPermissions", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "responses": { + "200": { + "description": "App permissions returned.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "404": { + "description": "App not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.roles.read" + ] + } + ] + } + }, + "/api/apps/{app}/roles/{roleName}": { + "put": { + "tags": [ + "Apps" + ], + "summary": "Update an app role.", + "operationId": "AppRoles_PutRole", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "roleName", + "in": "path", + "required": true, + "description": "The name of the role to be updated.", + "schema": { + "type": "string" + }, + "x-position": 2 + } + ], + "requestBody": { + "x-name": "request", + "description": "Role to be updated for the app.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateRoleDto" + } + } + }, + "required": true, + "x-position": 3 + }, + "responses": { + "200": { + "description": "Role updated.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RolesDto" + } + } + } + }, + "400": { + "description": "Role request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Role or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.roles.update" + ] + } + ] + }, + "delete": { + "tags": [ + "Apps" + ], + "summary": "Remove role from app.", + "operationId": "AppRoles_DeleteRole", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "roleName", + "in": "path", + "required": true, + "description": "The name of the role.", + "schema": { + "type": "string" + }, + "x-position": 2 + } + ], + "responses": { + "200": { + "description": "Role deleted.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RolesDto" + } + } + } + }, + "400": { + "description": "Role is in use by contributor or client or a default role.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Role or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.roles.delete" + ] + } + ] + } + }, + "/api/apps": { + "get": { + "tags": [ + "Apps" + ], + "summary": "Get your apps.", + "description": "You can only retrieve the list of apps when you are authenticated as a user (OpenID implicit flow).\nYou will retrieve all apps, where you are assigned as a contributor.", + "operationId": "Apps_GetApps", + "responses": { + "200": { + "description": "Apps returned.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AppDto" + } + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [] + } + ] + }, + "post": { + "tags": [ + "Apps" + ], + "summary": "Create a new app.", + "description": "You can only create an app when you are authenticated as a user (OpenID implicit flow).\nYou will be assigned as owner of the new app automatically.", + "operationId": "Apps_PostApp", + "requestBody": { + "x-name": "request", + "description": "The app object that needs to be added to Squidex.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateAppDto" + } + } + }, + "required": true, + "x-position": 1 + }, + "responses": { + "201": { + "description": "App created.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AppDto" + } + } + } + }, + "400": { + "description": "App request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "409": { + "description": "App name is already in use.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [] + } + ] + } + }, + "/api/teams/{team}/apps": { + "get": { + "tags": [ + "Apps" + ], + "summary": "Get team apps.", + "description": "You can only retrieve the list of apps when you are authenticated as a user (OpenID implicit flow).\nYou will retrieve all apps, where you are assigned as a contributor.", + "operationId": "Apps_GetTeamApps", + "parameters": [ + { + "name": "team", + "in": "path", + "required": true, + "description": "The ID of the team.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "responses": { + "200": { + "description": "Apps returned.", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AppDto" + } + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [] + } + ] + } + }, + "/api/apps/{app}": { + "get": { + "tags": [ + "Apps" + ], + "summary": "Get an app by name.", + "operationId": "Apps_GetApp", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "responses": { + "200": { + "description": "Apps returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AppDto" + } + } + } + }, + "404": { + "description": "App not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [] + } + ] + }, + "put": { + "tags": [ + "Apps" + ], + "summary": "Update the app.", + "operationId": "Apps_PutApp", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app to update.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "requestBody": { + "x-name": "request", + "description": "The values to update.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateAppDto" + } + } + }, + "required": true, + "x-position": 2 + }, + "responses": { + "200": { + "description": "App updated.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AppDto" + } + } + } + }, + "400": { + "description": "App request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "App not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.update" + ] + } + ] + }, + "delete": { + "tags": [ + "Apps" + ], + "summary": "Delete the app.", + "operationId": "Apps_DeleteApp", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app to delete.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "permanent", + "in": "query", + "description": "True to delete the app permanently.", + "schema": { + "type": "boolean" + }, + "x-position": 2 + } + ], + "responses": { + "204": { + "description": "App deleted." + }, + "404": { + "description": "App not found." + }, + "400": { + "description": "Validation error.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.delete" + ] + } + ] + } + }, + "/api/apps/{app}/team": { + "put": { + "tags": [ + "Apps" + ], + "summary": "Transfer the app.", + "operationId": "Apps_PutAppTeam", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app to update.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "requestBody": { + "x-name": "request", + "description": "The team information.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TransferToTeamDto" + } + } + }, + "required": true, + "x-position": 2 + }, + "responses": { + "200": { + "description": "App transferred.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AppDto" + } + } + } + }, + "400": { + "description": "App request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "App not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.transfer" + ] + } + ] + } + }, + "/api/apps/{app}/settings": { + "get": { + "tags": [ + "Apps" + ], + "summary": "Get the app settings.", + "operationId": "AppSettings_GetSettings", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app to get the settings for.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "responses": { + "200": { + "description": "App settings returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AppSettingsDto" + } + } + } + }, + "404": { + "description": "App not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [] + } + ] + }, + "put": { + "tags": [ + "Apps" + ], + "summary": "Update the settings.", + "operationId": "AppSettings_PutSettings", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app to update.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "requestBody": { + "x-name": "request", + "description": "The values to update.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateAppSettingsDto" + } + } + }, + "required": true, + "x-position": 2 + }, + "responses": { + "200": { + "description": "App updated.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AppSettingsDto" + } + } + } + }, + "400": { + "description": "App request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "App not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.settings" + ] + } + ] + } + }, + "/api/apps/{app}/workflows": { + "get": { + "tags": [ + "Apps" + ], + "summary": "Get app workflow.", + "operationId": "AppWorkflows_GetWorkflows", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "responses": { + "200": { + "description": "Workflows returned.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WorkflowsDto" + } + } + } + }, + "404": { + "description": "App not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.workflows.read" + ] + } + ] + }, + "post": { + "tags": [ + "Apps" + ], + "summary": "Create a workflow.", + "operationId": "AppWorkflows_PostWorkflow", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + } + ], + "requestBody": { + "x-name": "request", + "description": "The new workflow.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AddWorkflowDto" + } + } + }, + "required": true, + "x-position": 2 + }, + "responses": { + "200": { + "description": "Workflow created.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WorkflowsDto" + } + } + } + }, + "400": { + "description": "Workflow request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Workflow or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.workflows.update" + ] + } + ] + } + }, + "/api/apps/{app}/workflows/{id}": { + "put": { + "tags": [ + "Apps" + ], + "summary": "Update a workflow.", + "operationId": "AppWorkflows_PutWorkflow", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the workflow to update.", + "schema": { + "type": "string" + }, + "x-position": 2 + } + ], + "requestBody": { + "x-name": "request", + "description": "The new workflow.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateWorkflowDto" + } + } + }, + "required": true, + "x-position": 3 + }, + "responses": { + "200": { + "description": "Workflow updated.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WorkflowsDto" + } + } + } + }, + "400": { + "description": "Workflow request not valid.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "404": { + "description": "Workflow or app not found." + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.workflows.update" + ] + } + ] + }, + "delete": { + "tags": [ + "Apps" + ], + "summary": "Delete a workflow.", + "operationId": "AppWorkflows_DeleteWorkflow", + "parameters": [ + { + "name": "app", + "in": "path", + "required": true, + "description": "The name of the app.", + "schema": { + "type": "string" + }, + "x-position": 1 + }, + { + "name": "id", + "in": "path", + "required": true, + "description": "The ID of the workflow to update.", + "schema": { + "type": "string" + }, + "x-position": 2 + } + ], + "responses": { + "200": { + "description": "Workflow deleted.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WorkflowsDto" + } + } + } + }, + "404": { + "description": "Workflow or app not found." + }, + "400": { + "description": "Validation error.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + }, + "500": { + "description": "Operation failed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorDto" + } + } + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex.apps.{app}.workflows.update" + ] + } + ] + } + } + }, + "components": { + "schemas": { + "ErrorDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "message", + "statusCode" + ], + "properties": { + "message": { + "type": "string", + "description": "Error message.", + "minLength": 1 + }, + "errorCode": { + "type": "string", + "description": "The error code.", + "nullable": true + }, + "traceId": { + "type": "string", + "description": "The optional trace id.", + "nullable": true + }, + "type": { + "type": "string", + "description": "Link to the error details.", + "nullable": true + }, + "details": { + "type": "array", + "description": "Detailed error messages.", + "nullable": true, + "items": { + "type": "string" + } + }, + "statusCode": { + "type": "integer", + "description": "Status code of the http response.", + "format": "int32" + } + } + }, + "UserProperty": { + "type": "object", + "additionalProperties": false, + "required": [ + "name", + "value" + ], + "properties": { + "name": { + "type": "string", + "minLength": 1 + }, + "value": { + "type": "string", + "minLength": 1 + } + } + }, + "UpdateSettingDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "value" + ], + "properties": { + "value": { + "description": "The value for the setting." + } + } + }, + "UsersDto": { + "allOf": [ + { + "$ref": "#/components/schemas/Resource" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "total", + "items" + ], + "properties": { + "total": { + "type": "integer", + "description": "The total number of users.", + "format": "int64" + }, + "items": { + "type": "array", + "description": "The users.", + "items": { + "$ref": "#/components/schemas/UserDto" + } + } + } + } + ] + }, + "UserDto": { + "allOf": [ + { + "$ref": "#/components/schemas/Resource" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "email", + "displayName", + "isLocked", + "permissions" + ], + "properties": { + "id": { + "type": "string", + "description": "The ID of the user." + }, + "email": { + "type": "string", + "description": "The email of the user. Unique value." + }, + "displayName": { + "type": "string", + "description": "The display name (usually first name and last name) of the user." + }, + "isLocked": { + "type": "boolean", + "description": "Determines if the user is locked." + }, + "permissions": { + "type": "array", + "description": "Additional permissions for the user.", + "items": { + "type": "string" + } + } + } + } + ] + }, + "Resource": { + "type": "object", + "x-abstract": true, + "additionalProperties": false, + "required": [ + "_links" + ], + "properties": { + "_links": { + "type": "object", + "description": "The links.", + "additionalProperties": { + "$ref": "#/components/schemas/ResourceLink" + } + } + } + }, + "ResourceLink": { + "type": "object", + "additionalProperties": false, + "required": [ + "href", + "method" + ], + "properties": { + "href": { + "type": "string", + "description": "The link url.", + "minLength": 1 + }, + "method": { + "type": "string", + "description": "The link method.", + "minLength": 1 + }, + "metadata": { + "type": "string", + "description": "Additional data about the link.", + "nullable": true + } + } + }, + "CreateUserDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "email", + "displayName", + "password", + "permissions" + ], + "properties": { + "email": { + "type": "string", + "description": "The email of the user. Unique value.", + "minLength": 1 + }, + "displayName": { + "type": "string", + "description": "The display name (usually first name and last name) of the user.", + "minLength": 1 + }, + "password": { + "type": "string", + "description": "The password of the user.", + "minLength": 1 + }, + "permissions": { + "type": "array", + "description": "Additional permissions for the user.", + "items": { + "type": "string" + } + } + } + }, + "UpdateUserDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "email", + "displayName", + "permissions" + ], + "properties": { + "email": { + "type": "string", + "description": "The email of the user. Unique value.", + "minLength": 1 + }, + "displayName": { + "type": "string", + "description": "The display name (usually first name and last name) of the user.", + "minLength": 1 + }, + "password": { + "type": "string", + "description": "The password of the user.", + "nullable": true + }, + "permissions": { + "type": "array", + "description": "Additional permissions for the user.", + "items": { + "type": "string" + } + } + } + }, + "ResourcesDto": { + "allOf": [ + { + "$ref": "#/components/schemas/Resource" + }, + { + "type": "object", + "additionalProperties": false + } + ] + }, + "UpdateProfileDto": { + "type": "object", + "additionalProperties": false, + "properties": { + "answers": { + "type": "object", + "description": "The answers from a questionaire.", + "nullable": true, + "additionalProperties": { + "type": "string", + "nullable": true + } + } + } + }, + "TranslationDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "status", + "result" + ], + "properties": { + "status": { + "description": "The result of the translation.", + "$ref": "#/components/schemas/TranslationStatus" + }, + "result": { + "description": "The result of the translation.", + "deprecated": true, + "x-deprecatedMessage": "Use Status property now.", + "$ref": "#/components/schemas/TranslationStatus" + }, + "text": { + "type": "string", + "description": "The translated text.", + "nullable": true + } + } + }, + "TranslationStatus": { + "type": "string", + "description": "", + "x-enumNames": [ + "Translated", + "LanguageNotSupported", + "NotTranslated", + "NotConfigured", + "Unauthorized", + "Failed" + ], + "enum": [ + "Translated", + "LanguageNotSupported", + "NotTranslated", + "NotConfigured", + "Unauthorized", + "Failed" + ] + }, + "TranslateDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "text", + "targetLanguage" + ], + "properties": { + "text": { + "type": "string", + "description": "The text to translate.", + "minLength": 1 + }, + "targetLanguage": { + "type": "string", + "description": "The target language." + }, + "sourceLanguage": { + "type": "string", + "description": "The optional source language." + } + } + }, + "TemplatesDto": { + "allOf": [ + { + "$ref": "#/components/schemas/Resource" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "items" + ], + "properties": { + "items": { + "type": "array", + "description": "The event consumers.", + "items": { + "$ref": "#/components/schemas/TemplateDto" + } + } + } + } + ] + }, + "TemplateDto": { + "allOf": [ + { + "$ref": "#/components/schemas/Resource" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "name", + "title", + "description", + "details", + "isStarter" + ], + "properties": { + "name": { + "type": "string", + "description": "The name of the template." + }, + "title": { + "type": "string", + "description": "The title of the template." + }, + "description": { + "type": "string", + "description": "The description of the template." + }, + "details": { + "type": "string", + "description": "The details of the template." + }, + "isStarter": { + "type": "boolean", + "description": "True, if the template is a starter." + }, + "logo": { + "type": "string", + "description": "The optional logo.", + "nullable": true + } + } + } + ] + }, + "TemplateDetailsDto": { + "allOf": [ + { + "$ref": "#/components/schemas/Resource" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "details" + ], + "properties": { + "details": { + "type": "string", + "description": "The details of the template." + } + } + } + ] + }, + "ContributorsDto": { + "allOf": [ + { + "$ref": "#/components/schemas/Resource" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "items", + "maxContributors" + ], + "properties": { + "items": { + "type": "array", + "description": "The contributors.", + "items": { + "$ref": "#/components/schemas/ContributorDto" + } + }, + "maxContributors": { + "type": "integer", + "description": "The maximum number of allowed contributors.", + "format": "int64" + }, + "_meta": { + "description": "The metadata to provide information about this request.", + "nullable": true, + "$ref": "#/components/schemas/ContributorsMetadata" + } + } + } + ] + }, + "ContributorDto": { + "allOf": [ + { + "$ref": "#/components/schemas/Resource" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "contributorId", + "contributorName", + "contributorEmail" + ], + "properties": { + "contributorId": { + "type": "string", + "description": "The ID of the user that contributes to the app." + }, + "contributorName": { + "type": "string", + "description": "The display name." + }, + "contributorEmail": { + "type": "string", + "description": "The email address." + }, + "role": { + "type": "string", + "description": "The role of the contributor.", + "nullable": true + } + } + } + ] + }, + "ContributorsMetadata": { + "type": "object", + "additionalProperties": false, + "required": [ + "isInvited" + ], + "properties": { + "isInvited": { + "type": "string", + "description": "Indicates whether the user has been invited." + } + } + }, + "AssignContributorDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "contributorId" + ], + "properties": { + "contributorId": { + "type": "string", + "description": "The id or email of the user to add to the app.", + "minLength": 1 + }, + "role": { + "type": "string", + "description": "The role of the contributor.", + "nullable": true + }, + "invite": { + "type": "boolean", + "description": "Set to true to invite the user if he does not exist." + } + } + }, + "TeamDto": { + "allOf": [ + { + "$ref": "#/components/schemas/Resource" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "name", + "version", + "created", + "lastModified" + ], + "properties": { + "id": { + "type": "string", + "description": "The ID of the team." + }, + "name": { + "type": "string", + "description": "The name of the team." + }, + "version": { + "type": "integer", + "description": "The version of the team.", + "format": "int64" + }, + "created": { + "type": "string", + "description": "The timestamp when the team has been created.", + "format": "date-time" + }, + "lastModified": { + "type": "string", + "description": "The timestamp when the team has been modified last.", + "format": "date-time" + }, + "roleName": { + "type": "string", + "description": "The role name of the user.", + "nullable": true + } + } + } + ] + }, + "CreateTeamDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string", + "description": "The name of the team.", + "minLength": 1 + } + } + }, + "UpdateTeamDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string", + "description": "The name of the team.", + "minLength": 1 + } + } + }, + "AuthSchemeResponseDto": { + "allOf": [ + { + "$ref": "#/components/schemas/Resource" + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "scheme": { + "description": "The auth scheme if configured.", + "nullable": true, + "$ref": "#/components/schemas/AuthSchemeDto" + } + } + } + ] + }, + "AuthSchemeDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "domain", + "displayName", + "clientId", + "clientSecret", + "authority" + ], + "properties": { + "domain": { + "type": "string", + "description": "The domain name of your user accounts.", + "minLength": 1 + }, + "displayName": { + "type": "string", + "description": "The display name for buttons.", + "minLength": 1 + }, + "clientId": { + "type": "string", + "description": "The client ID.", + "minLength": 1 + }, + "clientSecret": { + "type": "string", + "description": "The client secret.", + "minLength": 1 + }, + "authority": { + "type": "string", + "description": "The authority URL.", + "minLength": 1 + }, + "signoutRedirectUrl": { + "type": "string", + "description": "The URL to redirect after a signout.", + "nullable": true + } + } + }, + "AuthSchemeValueDto": { + "type": "object", + "additionalProperties": false, + "properties": { + "scheme": { + "description": "The auth scheme if configured.", + "nullable": true, + "$ref": "#/components/schemas/AuthSchemeDto" + } + } + }, + "LogDownloadDto": { + "type": "object", + "additionalProperties": false, + "properties": { + "downloadUrl": { + "type": "string", + "description": "The url to download the log.", + "nullable": true + } + } + }, + "CallsUsageDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "totalCalls", + "totalBytes", + "monthCalls", + "monthBytes", + "blockingApiCalls", + "allowedBytes", + "allowedCalls", + "averageElapsedMs", + "details" + ], + "properties": { + "totalCalls": { + "type": "integer", + "description": "The total number of API calls.", + "format": "int64" + }, + "totalBytes": { + "type": "integer", + "description": "The total number of bytes transferred.", + "format": "int64" + }, + "monthCalls": { + "type": "integer", + "description": "The total number of API calls this month.", + "format": "int64" + }, + "monthBytes": { + "type": "integer", + "description": "The total number of bytes transferred this month.", + "format": "int64" + }, + "blockingApiCalls": { + "type": "integer", + "description": "The amount of calls that will block the app.", + "format": "int64" + }, + "allowedBytes": { + "type": "integer", + "description": "The included API traffic.", + "format": "int64" + }, + "allowedCalls": { + "type": "integer", + "description": "The included API calls.", + "format": "int64" + }, + "averageElapsedMs": { + "type": "number", + "description": "The average duration in milliseconds.", + "format": "double" + }, + "details": { + "type": "object", + "description": "The statistics by date and group.", + "additionalProperties": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CallsUsagePerDateDto" + } + } + } + } + }, + "CallsUsagePerDateDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "date", + "totalCalls", + "totalBytes", + "averageElapsedMs" + ], + "properties": { + "date": { + "type": "string", + "description": "The date when the usage was tracked.", + "format": "date" + }, + "totalCalls": { + "type": "integer", + "description": "The total number of API calls.", + "format": "int64" + }, + "totalBytes": { + "type": "integer", + "description": "The total number of bytes transferred.", + "format": "int64" + }, + "averageElapsedMs": { + "type": "number", + "description": "The average duration in milliseconds.", + "format": "double" + } + } + }, + "CurrentStorageDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "size", + "maxAllowed" + ], + "properties": { + "size": { + "type": "integer", + "description": "The size in bytes.", + "format": "int64" + }, + "maxAllowed": { + "type": "integer", + "description": "The maximum allowed asset size.", + "format": "int64" + } + } + }, + "StorageUsagePerDateDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "date", + "totalCount", + "totalSize" + ], + "properties": { + "date": { + "type": "string", + "description": "The date when the usage was tracked.", + "format": "date" + }, + "totalCount": { + "type": "integer", + "description": "The number of assets.", + "format": "int64" + }, + "totalSize": { + "type": "integer", + "description": "The size in bytes.", + "format": "int64" + } + } + }, + "SearchResultDto": { + "allOf": [ + { + "$ref": "#/components/schemas/Resource" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "name", + "type" + ], + "properties": { + "name": { + "type": "string", + "description": "The name of the search result." + }, + "type": { + "description": "The type of the search result.", + "$ref": "#/components/schemas/SearchResultType" + }, + "label": { + "type": "string", + "description": "An optional label.", + "nullable": true + } + } + } + ] + }, + "SearchResultType": { + "type": "string", + "description": "", + "x-enumNames": [ + "Asset", + "Content", + "Dashboard", + "Setting", + "Rule", + "Schema" + ], + "enum": [ + "Asset", + "Content", + "Dashboard", + "Setting", + "Rule", + "Schema" + ] + }, + "SchemaDto": { + "allOf": [ + { + "$ref": "#/components/schemas/Resource" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "createdBy", + "lastModifiedBy", + "name", + "properties", + "scripts", + "previewUrls", + "fieldsInLists", + "fieldsInReferences", + "fields", + "id", + "type", + "isSingleton", + "isPublished", + "created", + "lastModified", + "version", + "fieldRules" + ], + "properties": { + "id": { + "type": "string", + "description": "The ID of the schema." + }, + "createdBy": { + "type": "string", + "description": "The user that has created the schema." + }, + "lastModifiedBy": { + "type": "string", + "description": "The user that has updated the schema." + }, + "name": { + "type": "string", + "description": "The name of the schema. Unique within the app.", + "minLength": 1, + "pattern": "^[a-z0-9]+(\\-[a-z0-9]+)*$" + }, + "type": { + "description": "The type of the schema.", + "$ref": "#/components/schemas/SchemaType" + }, + "category": { + "type": "string", + "description": "The name of the category.", + "nullable": true + }, + "properties": { + "description": "The schema properties.", + "$ref": "#/components/schemas/SchemaPropertiesDto" + }, + "isSingleton": { + "type": "boolean", + "description": "Indicates if the schema is a singleton.", + "deprecated": true, + "x-deprecatedMessage": "Use 'type' field now." + }, + "isPublished": { + "type": "boolean", + "description": "Indicates if the schema is published." + }, + "created": { + "type": "string", + "description": "The date and time when the schema has been created.", + "format": "date-time" + }, + "lastModified": { + "type": "string", + "description": "The date and time when the schema has been modified last.", + "format": "date-time" + }, + "version": { + "type": "integer", + "description": "The version of the schema.", + "format": "int64" + }, + "scripts": { + "description": "The scripts.", + "$ref": "#/components/schemas/SchemaScriptsDto" + }, + "previewUrls": { + "type": "object", + "description": "The preview Urls.", + "additionalProperties": { + "type": "string" + } + }, + "fieldsInLists": { + "type": "array", + "description": "The name of fields that are used in content lists.", + "items": { + "type": "string" + } + }, + "fieldsInReferences": { + "type": "array", + "description": "The name of fields that are used in content references.", + "items": { + "type": "string" + } + }, + "fieldRules": { + "type": "array", + "description": "The field rules.", + "items": { + "$ref": "#/components/schemas/FieldRuleDto" + } + }, + "fields": { + "type": "array", + "description": "The list of fields.", + "items": { + "$ref": "#/components/schemas/FieldDto" + } + } + } + } + ] + }, + "SchemaType": { + "type": "string", + "description": "", + "x-enumNames": [ + "Default", + "Singleton", + "Component" + ], + "enum": [ + "Default", + "Singleton", + "Component" + ] + }, + "SchemaPropertiesDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "validateOnPublish" + ], + "properties": { + "label": { + "type": "string", + "description": "Optional label for the editor.", + "maxLength": 100, + "minLength": 0, + "nullable": true + }, + "hints": { + "type": "string", + "description": "Hints to describe the schema.", + "maxLength": 1000, + "minLength": 0, + "nullable": true + }, + "contentsSidebarUrl": { + "type": "string", + "description": "The url to a the sidebar plugin for content lists.", + "nullable": true + }, + "contentSidebarUrl": { + "type": "string", + "description": "The url to a the sidebar plugin for content items.", + "nullable": true + }, + "contentEditorUrl": { + "type": "string", + "description": "The url to the editor plugin.", + "nullable": true + }, + "contentsEditorUrl": { + "type": "string", + "description": "The url to the editor plugin.", + "nullable": true + }, + "contentsListUrl": { + "type": "string", + "description": "The url to the content list plugin.", + "nullable": true + }, + "validateOnPublish": { + "type": "boolean", + "description": "True to validate the content items on publish." + }, + "tags": { + "type": "array", + "description": "Tags for automation processes.", + "nullable": true, + "items": { + "type": "string" + } + } + } + }, + "SchemaScriptsDto": { + "type": "object", + "additionalProperties": false, + "properties": { + "query": { + "type": "string", + "description": "The script that is executed for each content when querying contents.", + "nullable": true + }, + "queryPre": { + "type": "string", + "description": "The script that is executed for all contents when querying contents.", + "nullable": true + }, + "create": { + "type": "string", + "description": "The script that is executed when creating a content.", + "nullable": true + }, + "update": { + "type": "string", + "description": "The script that is executed when updating a content.", + "nullable": true + }, + "delete": { + "type": "string", + "description": "The script that is executed when deleting a content.", + "nullable": true + }, + "change": { + "type": "string", + "description": "The script that is executed when change a content status.", + "nullable": true + } + } + }, + "FieldRuleDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "action", + "field" + ], + "properties": { + "action": { + "description": "The action to perform when the condition is met.", + "$ref": "#/components/schemas/FieldRuleAction" + }, + "field": { + "type": "string", + "description": "The field to update.", + "minLength": 1 + }, + "condition": { + "type": "string", + "description": "The condition.", + "nullable": true + } + } + }, + "FieldRuleAction": { + "type": "string", + "description": "", + "x-enumNames": [ + "Disable", + "Hide", + "Require" + ], + "enum": [ + "Disable", + "Hide", + "Require" + ] + }, + "FieldDto": { + "allOf": [ + { + "$ref": "#/components/schemas/Resource" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "name", + "partitioning", + "properties", + "fieldId", + "isHidden", + "isLocked", + "isDisabled" + ], + "properties": { + "fieldId": { + "type": "integer", + "description": "The ID of the field.", + "format": "int64" + }, + "name": { + "type": "string", + "description": "The name of the field. Must be unique within the schema.", + "minLength": 1, + "pattern": "^[a-z0-9]+(\\-[a-z0-9]+)*$" + }, + "isHidden": { + "type": "boolean", + "description": "Defines if the field is hidden." + }, + "isLocked": { + "type": "boolean", + "description": "Defines if the field is locked." + }, + "isDisabled": { + "type": "boolean", + "description": "Defines if the field is disabled." + }, + "partitioning": { + "type": "string", + "description": "Defines the partitioning of the field.", + "minLength": 1 + }, + "properties": { + "description": "The field properties.", + "$ref": "#/components/schemas/FieldPropertiesDto" + }, + "nested": { + "type": "array", + "description": "The nested fields.", + "nullable": true, + "items": { + "$ref": "#/components/schemas/NestedFieldDto" + } + } + } + } + ] + }, + "FieldPropertiesDto": { + "type": "object", + "discriminator": { + "propertyName": "fieldType", + "mapping": { + "Array": "#/components/schemas/ArrayFieldPropertiesDto", + "Assets": "#/components/schemas/AssetsFieldPropertiesDto", + "Boolean": "#/components/schemas/BooleanFieldPropertiesDto", + "Component": "#/components/schemas/ComponentFieldPropertiesDto", + "Components": "#/components/schemas/ComponentsFieldPropertiesDto", + "DateTime": "#/components/schemas/DateTimeFieldPropertiesDto", + "Geolocation": "#/components/schemas/GeolocationFieldPropertiesDto", + "Json": "#/components/schemas/JsonFieldPropertiesDto", + "Number": "#/components/schemas/NumberFieldPropertiesDto", + "References": "#/components/schemas/ReferencesFieldPropertiesDto", + "RichText": "#/components/schemas/RichTextFieldPropertiesDto", + "String": "#/components/schemas/StringFieldPropertiesDto", + "Tags": "#/components/schemas/TagsFieldPropertiesDto", + "UI": "#/components/schemas/UIFieldPropertiesDto", + "UserInfo": "#/components/schemas/UserInfoFieldPropertiesDto" + } + }, + "x-abstract": true, + "additionalProperties": false, + "required": [ + "fieldType" + ], + "properties": { + "label": { + "type": "string", + "description": "Optional label for the editor.", + "maxLength": 100, + "minLength": 0, + "nullable": true + }, + "hints": { + "type": "string", + "description": "Hints to describe the field.", + "maxLength": 1000, + "minLength": 0, + "nullable": true + }, + "placeholder": { + "type": "string", + "description": "Placeholder to show when no value has been entered.", + "maxLength": 100, + "minLength": 0, + "nullable": true + }, + "isRequired": { + "type": "boolean", + "description": "Indicates if the field is required." + }, + "isRequiredOnPublish": { + "type": "boolean", + "description": "Indicates if the field is required when publishing." + }, + "isHalfWidth": { + "type": "boolean", + "description": "Indicates if the field should be rendered with half width only." + }, + "isCreateOnly": { + "type": "boolean", + "description": "Indicates if the field can only be created and not modified." + }, + "editorUrl": { + "type": "string", + "description": "Optional url to the editor.", + "nullable": true + }, + "tags": { + "type": "array", + "description": "Tags for automation processes.", + "nullable": true, + "items": { + "type": "string" + } + }, + "fieldType": { + "type": "string" + } + } + }, + "ArrayFieldPropertiesDto": { + "allOf": [ + { + "$ref": "#/components/schemas/FieldPropertiesDto" + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "minItems": { + "type": "integer", + "description": "The minimum allowed items for the field value.", + "format": "int32", + "nullable": true + }, + "maxItems": { + "type": "integer", + "description": "The maximum allowed items for the field value.", + "format": "int32", + "nullable": true + }, + "calculatedDefaultValue": { + "description": "The calculated default value for the field value.", + "$ref": "#/components/schemas/ArrayCalculatedDefaultValue" + }, + "uniqueFields": { + "type": "array", + "description": "The fields that must be unique.", + "nullable": true, + "items": { + "type": "string" + } + } + } + } + ] + }, + "ArrayCalculatedDefaultValue": { + "type": "string", + "description": "", + "x-enumNames": [ + "EmptyArray", + "Null" + ], + "enum": [ + "EmptyArray", + "Null" + ] + }, + "AssetsFieldPropertiesDto": { + "allOf": [ + { + "$ref": "#/components/schemas/FieldPropertiesDto" + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "previewMode": { + "description": "The preview mode for the asset.", + "$ref": "#/components/schemas/AssetPreviewMode" + }, + "defaultValues": { + "description": "The language specific default value as a list of asset ids.", + "nullable": true, + "$ref": "#/components/schemas/LocalizedValueOfReadonlyListOfString" + }, + "defaultValue": { + "type": "array", + "description": "The default value as a list of asset ids.", + "nullable": true, + "items": { + "type": "string" + } + }, + "folderId": { + "type": "string", + "description": "The initial id to the folder.", + "nullable": true + }, + "previewFormat": { + "type": "string", + "description": "The preview format.", + "nullable": true + }, + "minItems": { + "type": "integer", + "description": "The minimum allowed items for the field value.", + "format": "int32", + "nullable": true + }, + "maxItems": { + "type": "integer", + "description": "The maximum allowed items for the field value.", + "format": "int32", + "nullable": true + }, + "minSize": { + "type": "integer", + "description": "The minimum file size in bytes.", + "format": "int32", + "nullable": true + }, + "maxSize": { + "type": "integer", + "description": "The maximum file size in bytes.", + "format": "int32", + "nullable": true + }, + "minWidth": { + "type": "integer", + "description": "The minimum image width in pixels.", + "format": "int32", + "nullable": true + }, + "maxWidth": { + "type": "integer", + "description": "The maximum image width in pixels.", + "format": "int32", + "nullable": true + }, + "minHeight": { + "type": "integer", + "description": "The minimum image height in pixels.", + "format": "int32", + "nullable": true + }, + "maxHeight": { + "type": "integer", + "description": "The maximum image height in pixels.", + "format": "int32", + "nullable": true + }, + "aspectWidth": { + "type": "integer", + "description": "The image aspect width in pixels.", + "format": "int32", + "nullable": true + }, + "aspectHeight": { + "type": "integer", + "description": "The image aspect height in pixels.", + "format": "int32", + "nullable": true + }, + "expectedType": { + "description": "The expected type.", + "nullable": true, + "$ref": "#/components/schemas/AssetType" + }, + "resolveFirst": { + "type": "boolean", + "description": "True to resolve first asset in the content list." + }, + "mustBeImage": { + "type": "boolean", + "description": "True to resolve first image in the content list.", + "deprecated": true, + "x-deprecatedMessage": "Use 'expectedType' field now" + }, + "resolveImage": { + "type": "boolean", + "description": "True to resolve first image in the content list.", + "deprecated": true, + "x-deprecatedMessage": "Use 'resolveFirst' field now" + }, + "allowedExtensions": { + "type": "array", + "description": "The allowed file extensions.", + "nullable": true, + "items": { + "type": "string" + } + }, + "allowDuplicates": { + "type": "boolean", + "description": "True, if duplicate values are allowed." + } + } + } + ] + }, + "AssetPreviewMode": { + "type": "string", + "description": "", + "x-enumNames": [ + "ImageAndFileName", + "Image", + "FileName" + ], + "enum": [ + "ImageAndFileName", + "Image", + "FileName" + ] + }, + "LocalizedValueOfReadonlyListOfString": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "AssetType": { + "type": "string", + "description": "", + "x-enumNames": [ + "Unknown", + "Image", + "Audio", + "Video" + ], + "enum": [ + "Unknown", + "Image", + "Audio", + "Video" + ] + }, + "BooleanFieldPropertiesDto": { + "allOf": [ + { + "$ref": "#/components/schemas/FieldPropertiesDto" + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "defaultValues": { + "description": "The language specific default value for the field value.", + "nullable": true, + "$ref": "#/components/schemas/LocalizedValueOfNullableBoolean" + }, + "defaultValue": { + "type": "boolean", + "description": "The default value for the field value.", + "nullable": true + }, + "inlineEditable": { + "type": "boolean", + "description": "Indicates that the inline editor is enabled for this field." + }, + "editor": { + "description": "The editor that is used to manage this field.", + "$ref": "#/components/schemas/BooleanFieldEditor" + } + } + } + ] + }, + "LocalizedValueOfNullableBoolean": { + "type": "object", + "additionalProperties": { + "type": "boolean", + "nullable": true + } + }, + "BooleanFieldEditor": { + "type": "string", + "description": "", + "x-enumNames": [ + "Checkbox", + "Toggle" + ], + "enum": [ + "Checkbox", + "Toggle" + ] + }, + "ComponentFieldPropertiesDto": { + "allOf": [ + { + "$ref": "#/components/schemas/FieldPropertiesDto" + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "schemaIds": { + "type": "array", + "description": "The ID of the embedded schemas.", + "nullable": true, + "items": { + "type": "string" + } + } + } + } + ] + }, + "ComponentsFieldPropertiesDto": { + "allOf": [ + { + "$ref": "#/components/schemas/FieldPropertiesDto" + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "minItems": { + "type": "integer", + "description": "The minimum allowed items for the field value.", + "format": "int32", + "nullable": true + }, + "maxItems": { + "type": "integer", + "description": "The maximum allowed items for the field value.", + "format": "int32", + "nullable": true + }, + "calculatedDefaultValue": { + "description": "The calculated default value for the field value.", + "$ref": "#/components/schemas/ArrayCalculatedDefaultValue" + }, + "schemaIds": { + "type": "array", + "description": "The ID of the embedded schemas.", + "nullable": true, + "items": { + "type": "string" + } + }, + "uniqueFields": { + "type": "array", + "description": "The fields that must be unique.", + "nullable": true, + "items": { + "type": "string" + } + } + } + } + ] + }, + "DateTimeFieldPropertiesDto": { + "allOf": [ + { + "$ref": "#/components/schemas/FieldPropertiesDto" + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "defaultValues": { + "description": "The language specific default value for the field value.", + "nullable": true, + "$ref": "#/components/schemas/LocalizedValueOfNullableInstant" + }, + "defaultValue": { + "type": "string", + "description": "The default value for the field value.", + "format": "date-time", + "nullable": true + }, + "maxValue": { + "type": "string", + "description": "The maximum allowed value for the field value.", + "format": "date-time", + "nullable": true + }, + "minValue": { + "type": "string", + "description": "The minimum allowed value for the field value.", + "format": "date-time", + "nullable": true + }, + "format": { + "type": "string", + "description": "The format pattern when displayed in the UI.", + "nullable": true + }, + "editor": { + "description": "The editor that is used to manage this field.", + "$ref": "#/components/schemas/DateTimeFieldEditor" + }, + "calculatedDefaultValue": { + "description": "The calculated default value for the field value.", + "nullable": true, + "$ref": "#/components/schemas/DateTimeCalculatedDefaultValue" + } + } + } + ] + }, + "LocalizedValueOfNullableInstant": { + "type": "object", + "additionalProperties": { + "type": "string", + "format": "date-time", + "nullable": true + } + }, + "DateTimeFieldEditor": { + "type": "string", + "description": "", + "x-enumNames": [ + "Date", + "DateTime" + ], + "enum": [ + "Date", + "DateTime" + ] + }, + "DateTimeCalculatedDefaultValue": { + "type": "string", + "description": "", + "x-enumNames": [ + "Now", + "Today" + ], + "enum": [ + "Now", + "Today" + ] + }, + "GeolocationFieldPropertiesDto": { + "allOf": [ + { + "$ref": "#/components/schemas/FieldPropertiesDto" + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "editor": { + "description": "The editor that is used to manage this field.", + "$ref": "#/components/schemas/GeolocationFieldEditor" + } + } + } + ] + }, + "GeolocationFieldEditor": { + "type": "string", + "description": "", + "x-enumNames": [ + "Map" + ], + "enum": [ + "Map" + ] + }, + "JsonFieldPropertiesDto": { + "allOf": [ + { + "$ref": "#/components/schemas/FieldPropertiesDto" + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "graphQLSchema": { + "type": "string", + "description": "The GraphQL schema.", + "nullable": true + } + } + } + ] + }, + "NumberFieldPropertiesDto": { + "allOf": [ + { + "$ref": "#/components/schemas/FieldPropertiesDto" + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "defaultValues": { + "description": "The language specific default value for the field value.", + "nullable": true, + "$ref": "#/components/schemas/LocalizedValueOfNullableDouble" + }, + "defaultValue": { + "type": "number", + "description": "The default value for the field value.", + "format": "double", + "nullable": true + }, + "maxValue": { + "type": "number", + "description": "The maximum allowed value for the field value.", + "format": "double", + "nullable": true + }, + "minValue": { + "type": "number", + "description": "The minimum allowed value for the field value.", + "format": "double", + "nullable": true + }, + "allowedValues": { + "type": "array", + "description": "The allowed values for the field value.", + "nullable": true, + "items": { + "type": "number", + "format": "double" + } + }, + "isUnique": { + "type": "boolean", + "description": "Indicates if the field value must be unique. Ignored for nested fields and localized fields." + }, + "inlineEditable": { + "type": "boolean", + "description": "Indicates that the inline editor is enabled for this field." + }, + "editor": { + "description": "The editor that is used to manage this field.", + "$ref": "#/components/schemas/NumberFieldEditor" + } + } + } + ] + }, + "LocalizedValueOfNullableDouble": { + "type": "object", + "additionalProperties": { + "type": "number", + "format": "double", + "nullable": true + } + }, + "NumberFieldEditor": { + "type": "string", + "description": "", + "x-enumNames": [ + "Input", + "Radio", + "Dropdown", + "Stars" + ], + "enum": [ + "Input", + "Radio", + "Dropdown", + "Stars" + ] + }, + "ReferencesFieldPropertiesDto": { + "allOf": [ + { + "$ref": "#/components/schemas/FieldPropertiesDto" + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "defaultValues": { + "description": "The language specific default value as a list of content ids.", + "nullable": true, + "$ref": "#/components/schemas/LocalizedValueOfReadonlyListOfString" + }, + "defaultValue": { + "type": "array", + "description": "The default value as a list of content ids.", + "nullable": true, + "items": { + "type": "string" + } + }, + "minItems": { + "type": "integer", + "description": "The minimum allowed items for the field value.", + "format": "int32", + "nullable": true + }, + "maxItems": { + "type": "integer", + "description": "The maximum allowed items for the field value.", + "format": "int32", + "nullable": true + }, + "allowDuplicates": { + "type": "boolean", + "description": "True, if duplicate values are allowed." + }, + "resolveReference": { + "type": "boolean", + "description": "True to resolve references in the content list." + }, + "mustBePublished": { + "type": "boolean", + "description": "True when all references must be published." + }, + "query": { + "type": "string", + "description": "The initial query that is applied in the UI.", + "nullable": true + }, + "editor": { + "description": "The editor that is used to manage this field.", + "$ref": "#/components/schemas/ReferencesFieldEditor" + }, + "schemaIds": { + "type": "array", + "description": "The ID of the referenced schemas.", + "nullable": true, + "items": { + "type": "string" + } + } + } + } + ] + }, + "ReferencesFieldEditor": { + "type": "string", + "description": "", + "x-enumNames": [ + "List", + "Dropdown", + "Tags", + "Checkboxes", + "Input", + "Radio" + ], + "enum": [ + "List", + "Dropdown", + "Tags", + "Checkboxes", + "Input", + "Radio" + ] + }, + "RichTextFieldPropertiesDto": { + "allOf": [ + { + "$ref": "#/components/schemas/FieldPropertiesDto" + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "folderId": { + "type": "string", + "description": "The initial id to the folder when the control supports file uploads.", + "nullable": true + }, + "minLength": { + "type": "integer", + "description": "The minimum allowed length for the field value.", + "format": "int32", + "nullable": true + }, + "maxLength": { + "type": "integer", + "description": "The maximum allowed length for the field value.", + "format": "int32", + "nullable": true + }, + "minCharacters": { + "type": "integer", + "description": "The minimum allowed of normal characters for the field value.", + "format": "int32", + "nullable": true + }, + "maxCharacters": { + "type": "integer", + "description": "The maximum allowed of normal characters for the field value.", + "format": "int32", + "nullable": true + }, + "minWords": { + "type": "integer", + "description": "The minimum allowed number of words for the field value.", + "format": "int32", + "nullable": true + }, + "maxWords": { + "type": "integer", + "description": "The maximum allowed number of words for the field value.", + "format": "int32", + "nullable": true + }, + "classNames": { + "type": "array", + "description": "The class names for the editor.", + "nullable": true, + "items": { + "type": "string" + } + }, + "schemaIds": { + "type": "array", + "description": "The allowed schema ids that can be embedded.", + "nullable": true, + "items": { + "type": "string" + } + } + } + } + ] + }, + "StringFieldPropertiesDto": { + "allOf": [ + { + "$ref": "#/components/schemas/FieldPropertiesDto" + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "defaultValues": { + "description": "The language specific default value for the field value.", + "nullable": true, + "$ref": "#/components/schemas/LocalizedValueOfString" + }, + "defaultValue": { + "type": "string", + "description": "The default value for the field value.", + "nullable": true + }, + "pattern": { + "type": "string", + "description": "The pattern to enforce a specific format for the field value.", + "nullable": true + }, + "patternMessage": { + "type": "string", + "description": "The validation message for the pattern.", + "nullable": true + }, + "folderId": { + "type": "string", + "description": "The initial id to the folder when the control supports file uploads.", + "nullable": true + }, + "minLength": { + "type": "integer", + "description": "The minimum allowed length for the field value.", + "format": "int32", + "nullable": true + }, + "maxLength": { + "type": "integer", + "description": "The maximum allowed length for the field value.", + "format": "int32", + "nullable": true + }, + "minCharacters": { + "type": "integer", + "description": "The minimum allowed of normal characters for the field value.", + "format": "int32", + "nullable": true + }, + "maxCharacters": { + "type": "integer", + "description": "The maximum allowed of normal characters for the field value.", + "format": "int32", + "nullable": true + }, + "minWords": { + "type": "integer", + "description": "The minimum allowed number of words for the field value.", + "format": "int32", + "nullable": true + }, + "maxWords": { + "type": "integer", + "description": "The maximum allowed number of words for the field value.", + "format": "int32", + "nullable": true + }, + "classNames": { + "type": "array", + "description": "The class names for the editor.", + "nullable": true, + "items": { + "type": "string" + } + }, + "allowedValues": { + "type": "array", + "description": "The allowed values for the field value.", + "nullable": true, + "items": { + "type": "string" + } + }, + "schemaIds": { + "type": "array", + "description": "The allowed schema ids that can be embedded.", + "nullable": true, + "items": { + "type": "string" + } + }, + "isUnique": { + "type": "boolean", + "description": "Indicates if the field value must be unique. Ignored for nested fields and localized fields." + }, + "isEmbeddable": { + "type": "boolean", + "description": "Indicates that other content items or references are embedded." + }, + "inlineEditable": { + "type": "boolean", + "description": "Indicates that the inline editor is enabled for this field." + }, + "createEnum": { + "type": "boolean", + "description": "Indicates whether GraphQL Enum should be created." + }, + "contentType": { + "description": "How the string content should be interpreted.", + "$ref": "#/components/schemas/StringContentType" + }, + "editor": { + "description": "The editor that is used to manage this field.", + "$ref": "#/components/schemas/StringFieldEditor" + } + } + } + ] + }, + "LocalizedValueOfString": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "StringContentType": { + "type": "string", + "description": "", + "x-enumNames": [ + "Unspecified", + "Html", + "Markdown" + ], + "enum": [ + "Unspecified", + "Html", + "Markdown" + ] + }, + "StringFieldEditor": { + "type": "string", + "description": "", + "x-enumNames": [ + "Input", + "Color", + "Markdown", + "Dropdown", + "Html", + "Radio", + "RichText", + "Slug", + "StockPhoto", + "TextArea" + ], + "enum": [ + "Input", + "Color", + "Markdown", + "Dropdown", + "Html", + "Radio", + "RichText", + "Slug", + "StockPhoto", + "TextArea" + ] + }, + "TagsFieldPropertiesDto": { + "allOf": [ + { + "$ref": "#/components/schemas/FieldPropertiesDto" + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "defaultValues": { + "description": "The language specific default value for the field value.", + "nullable": true, + "$ref": "#/components/schemas/LocalizedValueOfReadonlyListOfString" + }, + "defaultValue": { + "type": "array", + "description": "The default value.", + "nullable": true, + "items": { + "type": "string" + } + }, + "minItems": { + "type": "integer", + "description": "The minimum allowed items for the field value.", + "format": "int32", + "nullable": true + }, + "maxItems": { + "type": "integer", + "description": "The maximum allowed items for the field value.", + "format": "int32", + "nullable": true + }, + "allowedValues": { + "type": "array", + "description": "The allowed values for the field value.", + "nullable": true, + "items": { + "type": "string" + } + }, + "createEnum": { + "type": "boolean", + "description": "Indicates whether GraphQL Enum should be created." + }, + "editor": { + "description": "The editor that is used to manage this field.", + "$ref": "#/components/schemas/TagsFieldEditor" + } + } + } + ] + }, + "TagsFieldEditor": { + "type": "string", + "description": "", + "x-enumNames": [ + "Tags", + "Checkboxes", + "Dropdown" + ], + "enum": [ + "Tags", + "Checkboxes", + "Dropdown" + ] + }, + "UIFieldPropertiesDto": { + "allOf": [ + { + "$ref": "#/components/schemas/FieldPropertiesDto" + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "editor": { + "description": "The editor that is used to manage this field.", + "$ref": "#/components/schemas/UIFieldEditor" + } + } + } + ] + }, + "UIFieldEditor": { + "type": "string", + "description": "", + "x-enumNames": [ + "Separator" + ], + "enum": [ + "Separator" + ] + }, + "UserInfoFieldPropertiesDto": { + "allOf": [ + { + "$ref": "#/components/schemas/FieldPropertiesDto" + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "defaultRole": { + "type": "string", + "description": "The role to create a default value.", + "nullable": true + } + } + } + ] + }, + "NestedFieldDto": { + "allOf": [ + { + "$ref": "#/components/schemas/Resource" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "name", + "properties", + "fieldId", + "isHidden", + "isLocked", + "isDisabled" + ], + "properties": { + "fieldId": { + "type": "integer", + "description": "The ID of the field.", + "format": "int64" + }, + "name": { + "type": "string", + "description": "The name of the field. Must be unique within the schema.", + "minLength": 1, + "pattern": "^[a-z0-9]+(\\-[a-z0-9]+)*$" + }, + "isHidden": { + "type": "boolean", + "description": "Defines if the field is hidden." + }, + "isLocked": { + "type": "boolean", + "description": "Defines if the field is locked." + }, + "isDisabled": { + "type": "boolean", + "description": "Defines if the field is disabled." + }, + "properties": { + "description": "The field properties.", + "$ref": "#/components/schemas/FieldPropertiesDto" + } + } + } + ] + }, + "AddFieldDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "name", + "properties" + ], + "properties": { + "name": { + "type": "string", + "description": "The name of the field. Must be unique within the schema.", + "minLength": 1, + "pattern": "^[a-zA-Z0-9]+(\\-[a-zA-Z0-9]+)*$" + }, + "partitioning": { + "type": "string", + "description": "Determines the optional partitioning of the field.", + "nullable": true + }, + "properties": { + "description": "The field properties.", + "$ref": "#/components/schemas/FieldPropertiesDto" + } + } + }, + "ConfigureUIFieldsDto": { + "type": "object", + "additionalProperties": false, + "properties": { + "fieldsInLists": { + "type": "array", + "description": "The name of fields that are used in content lists.", + "nullable": true, + "items": { + "type": "string" + } + }, + "fieldsInReferences": { + "type": "array", + "description": "The name of fields that are used in content references.", + "nullable": true, + "items": { + "type": "string" + } + } + } + }, + "ReorderFieldsDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "fieldIds" + ], + "properties": { + "fieldIds": { + "type": "array", + "description": "The field ids in the target order.", + "items": { + "type": "integer", + "format": "int64" + } + } + } + }, + "UpdateFieldDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "properties" + ], + "properties": { + "properties": { + "description": "The field properties.", + "$ref": "#/components/schemas/FieldPropertiesDto" + } + } + }, + "IndexesDto": { + "allOf": [ + { + "$ref": "#/components/schemas/Resource" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "items" + ], + "properties": { + "items": { + "type": "array", + "description": "The indexes.", + "items": { + "$ref": "#/components/schemas/IndexDto" + } + } + } + } + ] + }, + "IndexDto": { + "allOf": [ + { + "$ref": "#/components/schemas/Resource" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "name", + "fields" + ], + "properties": { + "name": { + "type": "string", + "description": "The name of the index.", + "minLength": 1 + }, + "fields": { + "type": "array", + "description": "The index fields.", + "items": { + "$ref": "#/components/schemas/IndexFieldDto" + } + } + } + } + ] + }, + "IndexFieldDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "name", + "order" + ], + "properties": { + "name": { + "type": "string", + "description": "The name of the field.", + "minLength": 1 + }, + "order": { + "description": "The sort order of the field.", + "$ref": "#/components/schemas/SortOrder" + } + } + }, + "SortOrder": { + "type": "string", + "description": "", + "x-enumNames": [ + "Ascending", + "Descending" + ], + "enum": [ + "Ascending", + "Descending" + ] + }, + "CreateIndexDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "fields" + ], + "properties": { + "fields": { + "type": "array", + "description": "The index fields.", + "items": { + "$ref": "#/components/schemas/IndexFieldDto" + } + } + } + }, + "SchemasDto": { + "allOf": [ + { + "$ref": "#/components/schemas/Resource" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "items" + ], + "properties": { + "items": { + "type": "array", + "description": "The schemas.", + "items": { + "$ref": "#/components/schemas/SchemaDto" + } + } + } + } + ] + }, + "CreateSchemaDto": { + "allOf": [ + { + "$ref": "#/components/schemas/UpsertSchemaDto" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string", + "description": "The name of the schema.", + "minLength": 1, + "pattern": "^[a-z0-9]+(\\-[a-z0-9]+)*$" + }, + "type": { + "description": "The type of the schema.", + "$ref": "#/components/schemas/SchemaType" + }, + "isSingleton": { + "type": "boolean", + "description": "Set to true to allow a single content item only.", + "deprecated": true, + "x-deprecatedMessage": "Use 'type' field now." + } + } + } + ] + }, + "UpsertSchemaDto": { + "type": "object", + "x-abstract": true, + "additionalProperties": false, + "properties": { + "properties": { + "description": "The optional properties.", + "nullable": true, + "$ref": "#/components/schemas/SchemaPropertiesDto" + }, + "scripts": { + "description": "The optional scripts.", + "nullable": true, + "$ref": "#/components/schemas/SchemaScriptsDto" + }, + "fieldsInReferences": { + "type": "array", + "description": "The names of the fields that should be used in references.", + "nullable": true, + "items": { + "type": "string" + } + }, + "fieldsInLists": { + "type": "array", + "description": "The names of the fields that should be shown in lists, including meta fields.", + "nullable": true, + "items": { + "type": "string" + } + }, + "fields": { + "type": "array", + "description": "Optional fields.", + "nullable": true, + "items": { + "$ref": "#/components/schemas/UpsertSchemaFieldDto" + } + }, + "previewUrls": { + "type": "object", + "description": "The optional preview urls.", + "nullable": true, + "additionalProperties": { + "type": "string" + } + }, + "fieldRules": { + "type": "array", + "description": "The optional field Rules.", + "nullable": true, + "items": { + "$ref": "#/components/schemas/FieldRuleDto" + } + }, + "category": { + "type": "string", + "description": "The category.", + "nullable": true + }, + "isPublished": { + "type": "boolean", + "description": "Set it to true to autopublish the schema." + } + } + }, + "UpsertSchemaFieldDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "name", + "properties" + ], + "properties": { + "name": { + "type": "string", + "description": "The name of the field. Must be unique within the schema.", + "minLength": 1, + "pattern": "^[a-zA-Z0-9]+(\\-[a-zA-Z0-9]+)*$" + }, + "isHidden": { + "type": "boolean", + "description": "Defines if the field is hidden." + }, + "isLocked": { + "type": "boolean", + "description": "Defines if the field is locked." + }, + "isDisabled": { + "type": "boolean", + "description": "Defines if the field is disabled." + }, + "partitioning": { + "type": "string", + "description": "Determines the optional partitioning of the field.", + "nullable": true + }, + "properties": { + "description": "The field properties.", + "$ref": "#/components/schemas/FieldPropertiesDto" + }, + "nested": { + "type": "array", + "description": "The nested fields.", + "nullable": true, + "items": { + "$ref": "#/components/schemas/UpsertSchemaNestedFieldDto" + } + } + } + }, + "UpsertSchemaNestedFieldDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "name", + "properties" + ], + "properties": { + "name": { + "type": "string", + "description": "The name of the field. Must be unique within the schema.", + "minLength": 1, + "pattern": "^[a-zA-Z0-9]+(\\-[a-zA-Z0-9]+)*$" + }, + "isHidden": { + "type": "boolean", + "description": "Defines if the field is hidden." + }, + "isLocked": { + "type": "boolean", + "description": "Defines if the field is locked." + }, + "isDisabled": { + "type": "boolean", + "description": "Defines if the field is disabled." + }, + "properties": { + "description": "The field properties.", + "$ref": "#/components/schemas/FieldPropertiesDto" + } + } + }, + "GenerateSchemaResponseDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "log" + ], + "properties": { + "log": { + "type": "array", + "description": "The status log.", + "items": { + "type": "string" + } + }, + "schemaName": { + "type": "string", + "description": "The name of the created schema.", + "nullable": true + } + } + }, + "GenerateSchemaDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "prompt", + "execute", + "numberOfContentItems" + ], + "properties": { + "prompt": { + "type": "string", + "description": "The prompt to generate.", + "minLength": 1 + }, + "execute": { + "type": "boolean", + "description": "Indicates if the schema should actually be generated." + }, + "numberOfContentItems": { + "type": "integer", + "description": "The number of content items to generate.", + "format": "int32" + } + } + }, + "UpdateSchemaDto": { + "type": "object", + "additionalProperties": false, + "properties": { + "label": { + "type": "string", + "description": "Optional label for the editor.", + "maxLength": 100, + "minLength": 0, + "nullable": true + }, + "hints": { + "type": "string", + "description": "Hints to describe the schema.", + "maxLength": 1000, + "minLength": 0, + "nullable": true + }, + "contentsSidebarUrl": { + "type": "string", + "description": "The url to a the sidebar plugin for content lists.", + "nullable": true + }, + "contentSidebarUrl": { + "type": "string", + "description": "The url to a the sidebar plugin for content items.", + "nullable": true + }, + "contentsListUrl": { + "type": "string", + "description": "The url to the content list plugin.", + "nullable": true + }, + "validateOnPublish": { + "type": "boolean", + "description": "True to validate the content items on publish." + }, + "tags": { + "type": "array", + "description": "Tags for automation processes.", + "nullable": true, + "items": { + "type": "string" + } + } + } + }, + "SynchronizeSchemaDto": { + "allOf": [ + { + "$ref": "#/components/schemas/UpsertSchemaDto" + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "noFieldDeletion": { + "type": "boolean", + "description": "True, when fields should not be deleted." + }, + "noFieldRecreation": { + "type": "boolean", + "description": "True, when fields with different types should not be recreated." + } + } + } + ] + }, + "ChangeCategoryDto": { + "type": "object", + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "The name of the category.", + "nullable": true + } + } + }, + "ConfigurePreviewUrlsDto": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "ConfigureFieldRulesDto": { + "type": "object", + "additionalProperties": false, + "properties": { + "fieldRules": { + "type": "array", + "description": "The field rules to configure.", + "nullable": true, + "items": { + "$ref": "#/components/schemas/FieldRuleDto" + } + } + } + }, + "RuleElementDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "description", + "display", + "properties" + ], + "properties": { + "description": { + "type": "string", + "description": "Describes the action or trigger type." + }, + "display": { + "type": "string", + "description": "The label for the action or trigger type." + }, + "title": { + "type": "string", + "description": "Optional title.", + "nullable": true + }, + "iconColor": { + "type": "string", + "description": "The color for the icon.", + "nullable": true + }, + "iconImage": { + "type": "string", + "description": "The image for the icon.", + "nullable": true + }, + "readMore": { + "type": "string", + "description": "The optional link to the product that is integrated.", + "nullable": true + }, + "properties": { + "type": "array", + "description": "The properties.", + "items": { + "$ref": "#/components/schemas/RuleElementPropertyDto" + } + } + } + }, + "RuleElementPropertyDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "editor", + "name", + "display", + "isFormattable", + "isRequired" + ], + "properties": { + "editor": { + "type": "string", + "description": "The html editor." + }, + "name": { + "type": "string", + "description": "The name of the editor." + }, + "display": { + "type": "string", + "description": "The label to use." + }, + "options": { + "type": "array", + "description": "The options, if the editor is a dropdown.", + "nullable": true, + "items": { + "type": "string" + } + }, + "description": { + "type": "string", + "description": "The optional description.", + "nullable": true + }, + "isFormattable": { + "type": "boolean", + "description": "Indicates if the property is formattable." + }, + "isRequired": { + "type": "boolean", + "description": "Indicates if the property is required." + } + } + }, + "RulesDto": { + "allOf": [ + { + "$ref": "#/components/schemas/Resource" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "items" + ], + "properties": { + "items": { + "type": "array", + "description": "The rules.", + "items": { + "$ref": "#/components/schemas/RuleDto" + } + }, + "runningRuleId": { + "type": "string", + "description": "The ID of the rule that is currently rerunning.", + "nullable": true + } + } + } + ] + }, + "RuleDto": { + "allOf": [ + { + "$ref": "#/components/schemas/Resource" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "createdBy", + "lastModifiedBy", + "created", + "lastModified", + "version", + "isEnabled", + "trigger", + "flow", + "action", + "numSucceeded", + "numFailed" + ], + "properties": { + "id": { + "type": "string", + "description": "The ID of the rule." + }, + "createdBy": { + "type": "string", + "description": "The user that has created the rule." + }, + "lastModifiedBy": { + "type": "string", + "description": "The user that has updated the rule." + }, + "created": { + "type": "string", + "description": "The date and time when the rule has been created.", + "format": "date-time" + }, + "lastModified": { + "type": "string", + "description": "The date and time when the rule has been modified last.", + "format": "date-time" + }, + "version": { + "type": "integer", + "description": "The version of the rule.", + "format": "int64" + }, + "isEnabled": { + "type": "boolean", + "description": "Determines if the rule is enabled." + }, + "name": { + "type": "string", + "description": "Optional rule name.", + "nullable": true + }, + "trigger": { + "description": "The trigger properties.", + "$ref": "#/components/schemas/RuleTriggerDto" + }, + "flow": { + "description": "The flow to describe the sequence of actions to perform.", + "$ref": "#/components/schemas/FlowDefinitionDto" + }, + "action": { + "description": "The action properties.", + "deprecated": true, + "x-deprecatedMessage": "Use the new 'Flow' property to define actions. Can be null if the flow cannot be converted.", + "$ref": "#/components/schemas/RuleActionDto" + }, + "numSucceeded": { + "type": "integer", + "description": "The number of completed executions.", + "format": "int64" + }, + "numFailed": { + "type": "integer", + "description": "The number of failed executions.", + "format": "int64" + }, + "lastExecuted": { + "type": "string", + "description": "The date and time when the rule was executed the last time.", + "format": "date-time", + "deprecated": true, + "x-deprecatedMessage": "Removed when migrated to new rule statistics.", + "nullable": true + } + } + } + ] + }, + "RuleTriggerDto": { + "type": "object", + "discriminator": { + "propertyName": "triggerType", + "mapping": { + "AssetChanged": "#/components/schemas/AssetChangedRuleTriggerDto", + "Comment": "#/components/schemas/CommentRuleTriggerDto", + "ContentChanged": "#/components/schemas/ContentChangedRuleTriggerDto", + "CronJob": "#/components/schemas/CronJobRuleTriggerDto", + "Manual": "#/components/schemas/ManualRuleTriggerDto", + "SchemaChanged": "#/components/schemas/SchemaChangedRuleTriggerDto", + "Usage": "#/components/schemas/UsageRuleTriggerDto" + } + }, + "x-abstract": true, + "additionalProperties": false, + "required": [ + "triggerType" + ], + "properties": { + "triggerType": { + "type": "string" + } + } + }, + "AssetChangedRuleTriggerDto": { + "allOf": [ + { + "$ref": "#/components/schemas/RuleTriggerDto" + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "condition": { + "type": "string", + "description": "Javascript condition when to trigger.", + "nullable": true + } + } + } + ] + }, + "CommentRuleTriggerDto": { + "allOf": [ + { + "$ref": "#/components/schemas/RuleTriggerDto" + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "condition": { + "type": "string", + "description": "Javascript condition when to trigger.", + "nullable": true + } + } + } + ] + }, + "ContentChangedRuleTriggerDto": { + "allOf": [ + { + "$ref": "#/components/schemas/RuleTriggerDto" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "handleAll" + ], + "properties": { + "schemas": { + "type": "array", + "description": "The schema settings.", + "nullable": true, + "items": { + "$ref": "#/components/schemas/SchemaCondition" + } + }, + "referencedSchemas": { + "type": "array", + "description": "The schema references.", + "nullable": true, + "items": { + "$ref": "#/components/schemas/SchemaCondition" + } + }, + "handleAll": { + "type": "boolean", + "description": "Determines whether the trigger should handle all content changes events." + } + } + } + ] + }, + "SchemaCondition": { + "type": "object", + "additionalProperties": false, + "required": [ + "schemaId" + ], + "properties": { + "schemaId": { + "type": "string" + }, + "condition": { + "type": "string", + "nullable": true + } + } + }, + "CronJobRuleTriggerDto": { + "allOf": [ + { + "$ref": "#/components/schemas/RuleTriggerDto" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "cronExpression", + "value" + ], + "properties": { + "cronExpression": { + "type": "string", + "description": "The cron expression that defines the interval.", + "minLength": 1 + }, + "cronTimezone": { + "type": "string", + "description": "The optional timezone.", + "nullable": true + }, + "value": { + "description": "The value sent to the flow." + } + } + } + ] + }, + "ManualRuleTriggerDto": { + "allOf": [ + { + "$ref": "#/components/schemas/RuleTriggerDto" + }, + { + "type": "object", + "additionalProperties": false + } + ] + }, + "SchemaChangedRuleTriggerDto": { + "allOf": [ + { + "$ref": "#/components/schemas/RuleTriggerDto" + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "condition": { + "type": "string", + "description": "Javascript condition when to trigger.", + "nullable": true + } + } + } + ] + }, + "UsageRuleTriggerDto": { + "allOf": [ + { + "$ref": "#/components/schemas/RuleTriggerDto" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "limit" + ], + "properties": { + "limit": { + "type": "integer", + "description": "The number of monthly api calls.", + "format": "int32" + }, + "numDays": { + "type": "integer", + "description": "The number of days to check or null for the current month.", + "format": "int32", + "maximum": 30.0, + "minimum": 1.0, + "nullable": true + } + } + } + ] + }, + "FlowDefinitionDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "initialStepId", + "steps" + ], + "properties": { + "initialStepId": { + "type": "string", + "description": "The ID of the initial step.", + "format": "guid", + "minLength": 1 + }, + "steps": { + "type": "object", + "description": "The steps.", + "additionalProperties": { + "$ref": "#/components/schemas/FlowStepDefinitionDto" + } + } + } + }, + "FlowStepDefinitionDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "step" + ], + "properties": { + "step": { + "description": "The actual step.", + "$ref": "#/components/schemas/FlowStepDto" + }, + "name": { + "type": "string", + "description": "The optional descriptive name.", + "nullable": true + }, + "nextStepId": { + "type": "string", + "description": "The next step.", + "format": "guid", + "nullable": true + }, + "ignoreError": { + "type": "boolean", + "description": "Indicates if errors should be ignored." + } + } + }, + "FlowStepDto": { + "type": "object", + "discriminator": { + "propertyName": "stepType", + "mapping": { + "Algolia": "#/components/schemas/AlgoliaFlowStepDto", + "AzureQueue": "#/components/schemas/AzureQueueFlowStepDto", + "Comment": "#/components/schemas/CommentFlowStepDto", + "CreateContent": "#/components/schemas/CreateContentFlowStepDto", + "Delay": "#/components/schemas/DelayFlowStepDto", + "Discourse": "#/components/schemas/DiscourseFlowStepDto", + "ElasticSearch": "#/components/schemas/ElasticSearchFlowStepDto", + "Email": "#/components/schemas/EmailFlowStepDto", + "Fastly": "#/components/schemas/FastlyFlowStepDto", + "If": "#/components/schemas/IfFlowStepDto", + "Medium": "#/components/schemas/MediumFlowStepDto", + "Notification": "#/components/schemas/NotificationFlowStepDto", + "OpenSearch": "#/components/schemas/OpenSearchFlowStepDto", + "Prerender": "#/components/schemas/PrerenderFlowStepDto", + "Script": "#/components/schemas/ScriptFlowStepDto", + "SignalR": "#/components/schemas/SignalRFlowStepDto", + "Slack": "#/components/schemas/SlackFlowStepDto", + "Tweet": "#/components/schemas/TweetFlowStepDto", + "Typesense": "#/components/schemas/TypesenseFlowStepDto", + "Webhook": "#/components/schemas/WebhookFlowStepDto" + } + }, + "x-abstract": true, + "additionalProperties": false, + "required": [ + "stepType" + ], + "properties": { + "stepType": { + "type": "string" + } + } + }, + "AlgoliaFlowStepDto": { + "allOf": [ + { + "$ref": "#/components/schemas/FlowStepDto" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "appId", + "apiKey", + "indexName" + ], + "properties": { + "appId": { + "title": "Application Id", + "type": "string", + "description": "The application ID.", + "minLength": 1 + }, + "apiKey": { + "title": "Api Key", + "type": "string", + "description": "The API key to grant access to Squidex.", + "minLength": 1 + }, + "indexName": { + "title": "Index Name", + "type": "string", + "description": "The name of the index.", + "minLength": 1 + }, + "document": { + "title": "Document", + "type": "string", + "description": "The optional custom document.", + "nullable": true + }, + "delete": { + "title": "Deletion", + "type": "string", + "description": "The condition when to delete the entry.", + "nullable": true + } + } + } + ] + }, + "AzureQueueFlowStepDto": { + "allOf": [ + { + "$ref": "#/components/schemas/FlowStepDto" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "connectionString", + "queue" + ], + "properties": { + "connectionString": { + "title": "Connection", + "type": "string", + "description": "The connection string to the storage account.", + "minLength": 1 + }, + "queue": { + "title": "Queue", + "type": "string", + "description": "The name of the queue.", + "minLength": 1 + }, + "payload": { + "title": "Payload (Optional)", + "type": "string", + "description": "Leave it empty to use the full event as body.", + "nullable": true + } + } + } + ] + }, + "CommentFlowStepDto": { + "allOf": [ + { + "$ref": "#/components/schemas/FlowStepDto" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "text" + ], + "properties": { + "text": { + "title": "Text", + "type": "string", + "description": "The comment text.", + "minLength": 1 + }, + "client": { + "title": "Client", + "type": "string", + "description": "An optional client name.", + "nullable": true + } + } + } + ] + }, + "CreateContentFlowStepDto": { + "allOf": [ + { + "$ref": "#/components/schemas/FlowStepDto" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "data", + "schema", + "publish" + ], + "properties": { + "data": { + "title": "Data", + "type": "string", + "description": "The content data.", + "minLength": 1 + }, + "schema": { + "title": "Schema", + "type": "string", + "description": "The name of the schema.", + "minLength": 1 + }, + "client": { + "title": "Client", + "type": "string", + "description": "An optional client name.", + "nullable": true + }, + "publish": { + "title": "Publish", + "type": "boolean", + "description": "Publish the content." + } + } + } + ] + }, + "DelayFlowStepDto": { + "allOf": [ + { + "$ref": "#/components/schemas/FlowStepDto" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "delayInSec" + ], + "properties": { + "delayInSec": { + "title": "Delay", + "type": "integer", + "description": "The delay in seconds.", + "format": "int32" + } + } + } + ] + }, + "DiscourseFlowStepDto": { + "allOf": [ + { + "$ref": "#/components/schemas/FlowStepDto" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "url", + "apiKey", + "apiUsername", + "text" + ], + "properties": { + "url": { + "title": "Server Url", + "type": "string", + "description": "The url to the discourse server.", + "format": "uri", + "minLength": 1 + }, + "apiKey": { + "title": "Api Key", + "type": "string", + "description": "The api key to authenticate to your discourse server.", + "minLength": 1 + }, + "apiUsername": { + "title": "Api User", + "type": "string", + "description": "The api username to authenticate to your discourse server.", + "minLength": 1 + }, + "text": { + "title": "Text", + "type": "string", + "description": "The text as markdown.", + "minLength": 1 + }, + "title": { + "title": "Title", + "type": "string", + "description": "The optional title when creating new topics.", + "nullable": true + }, + "topic": { + "title": "Topic", + "type": "integer", + "description": "The optional topic id.", + "format": "int32", + "nullable": true + }, + "category": { + "title": "Category", + "type": "integer", + "description": "The optional category id.", + "format": "int32", + "nullable": true + } + } + } + ] + }, + "ElasticSearchFlowStepDto": { + "allOf": [ + { + "$ref": "#/components/schemas/FlowStepDto" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "host", + "indexName" + ], + "properties": { + "host": { + "title": "Server Url", + "type": "string", + "description": "The url to the instance or cluster.", + "format": "uri", + "minLength": 1 + }, + "indexName": { + "title": "Index Name", + "type": "string", + "description": "The name of the index.", + "minLength": 1 + }, + "username": { + "title": "Username", + "type": "string", + "description": "The optional username.", + "nullable": true + }, + "password": { + "title": "Password", + "type": "string", + "description": "The optional password.", + "nullable": true + }, + "document": { + "title": "Document", + "type": "string", + "description": "The optional custom document.", + "nullable": true + }, + "delete": { + "title": "Deletion", + "type": "string", + "description": "The condition when to delete the document.", + "nullable": true + } + } + } + ] + }, + "EmailFlowStepDto": { + "allOf": [ + { + "$ref": "#/components/schemas/FlowStepDto" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "serverHost", + "serverPort", + "messageFrom", + "messageTo", + "messageSubject", + "messageBody", + "serverUsername", + "serverPassword" + ], + "properties": { + "serverHost": { + "title": "Server Host", + "type": "string", + "description": "The IP address or host to the SMTP server.", + "minLength": 1 + }, + "serverPort": { + "title": "Server Port", + "type": "integer", + "description": "The port to the SMTP server.", + "format": "int32" + }, + "serverUsername": { + "title": "Username", + "type": "string", + "description": "The username for the SMTP server." + }, + "serverPassword": { + "title": "Password", + "type": "string", + "description": "The password for the SMTP server." + }, + "messageFrom": { + "title": "From Address", + "type": "string", + "description": "The email sending address.", + "minLength": 1 + }, + "messageTo": { + "title": "To Address", + "type": "string", + "description": "The email message will be sent to.", + "minLength": 1 + }, + "messageSubject": { + "title": "Subject", + "type": "string", + "description": "The subject line for this email message.", + "minLength": 1 + }, + "messageBody": { + "title": "Body", + "type": "string", + "description": "The message body.", + "minLength": 1 + } + } + } + ] + }, + "FastlyFlowStepDto": { + "allOf": [ + { + "$ref": "#/components/schemas/FlowStepDto" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "apiKey", + "serviceId" + ], + "properties": { + "apiKey": { + "title": "Api Key", + "type": "string", + "description": "The API key to grant access to Squidex.", + "minLength": 1 + }, + "serviceId": { + "title": "Service Id", + "type": "string", + "description": "The ID of the fastly service.", + "minLength": 1 + } + } + } + ] + }, + "IfFlowStepDto": { + "allOf": [ + { + "$ref": "#/components/schemas/FlowStepDto" + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "branches": { + "title": "Branches", + "type": "array", + "description": "The delay in seconds.", + "nullable": true, + "items": { + "$ref": "#/components/schemas/IfFlowBranch" + } + }, + "elseStepId": { + "type": "string", + "format": "guid", + "nullable": true + } + } + } + ] + }, + "IfFlowBranch": { + "type": "object", + "additionalProperties": false, + "properties": { + "condition": { + "type": "string", + "nullable": true + }, + "nextStepId": { + "type": "string", + "format": "guid", + "nullable": true + } + } + }, + "MediumFlowStepDto": { + "allOf": [ + { + "$ref": "#/components/schemas/FlowStepDto" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "accessToken", + "title", + "content", + "isHtml" + ], + "properties": { + "accessToken": { + "title": "Access Token", + "type": "string", + "description": "The self issued access token.", + "minLength": 1 + }, + "title": { + "title": "Title", + "type": "string", + "description": "The title, used for the url.", + "minLength": 1 + }, + "content": { + "title": "Content", + "type": "string", + "description": "The content, either html or markdown.", + "minLength": 1 + }, + "canonicalUrl": { + "title": "Canonical Url", + "type": "string", + "description": "The original home of this content, if it was originally published elsewhere.", + "nullable": true + }, + "tags": { + "title": "Tags", + "type": "string", + "description": "The optional comma separated list of tags.", + "nullable": true + }, + "publicationId": { + "title": "Publication Id", + "type": "string", + "description": "Optional publication id.", + "nullable": true + }, + "isHtml": { + "title": "Is Html", + "type": "boolean", + "description": "Indicates whether the content is markdown or html." + } + } + } + ] + }, + "NotificationFlowStepDto": { + "allOf": [ + { + "$ref": "#/components/schemas/FlowStepDto" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "user", + "text" + ], + "properties": { + "user": { + "title": "User", + "type": "string", + "description": "The user id or email.", + "minLength": 1 + }, + "text": { + "title": "Title", + "type": "string", + "description": "The text to send.", + "minLength": 1 + }, + "url": { + "title": "Url", + "type": "string", + "description": "The optional url to attach to the notification.", + "nullable": true + }, + "client": { + "title": "Client", + "type": "string", + "description": "An optional client name.", + "nullable": true + } + } + } + ] + }, + "OpenSearchFlowStepDto": { + "allOf": [ + { + "$ref": "#/components/schemas/FlowStepDto" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "host", + "indexName" + ], + "properties": { + "host": { + "title": "Server Url", + "type": "string", + "description": "The url to the instance or cluster.", + "format": "uri", + "minLength": 1 + }, + "indexName": { + "title": "Index Name", + "type": "string", + "description": "The name of the index.", + "minLength": 1 + }, + "username": { + "title": "Username", + "type": "string", + "description": "The optional username.", + "nullable": true + }, + "password": { + "title": "Password", + "type": "string", + "description": "The optional password.", + "nullable": true + }, + "document": { + "title": "Document", + "type": "string", + "description": "The optional custom document.", + "nullable": true + }, + "delete": { + "title": "Deletion", + "type": "string", + "description": "The condition when to delete the document.", + "nullable": true + } + } + } + ] + }, + "PrerenderFlowStepDto": { + "allOf": [ + { + "$ref": "#/components/schemas/FlowStepDto" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "token", + "url" + ], + "properties": { + "token": { + "title": "Token", + "type": "string", + "description": "The prerender token from your account.", + "minLength": 1 + }, + "url": { + "title": "Url", + "type": "string", + "description": "The url to recache.", + "minLength": 1 + } + } + } + ] + }, + "ScriptFlowStepDto": { + "allOf": [ + { + "$ref": "#/components/schemas/FlowStepDto" + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "script": { + "title": "Script", + "type": "string", + "description": "The script to execute.", + "nullable": true + } + } + } + ] + }, + "SignalRFlowStepDto": { + "allOf": [ + { + "$ref": "#/components/schemas/FlowStepDto" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "connectionString", + "hubName", + "action" + ], + "properties": { + "connectionString": { + "title": "Connection", + "type": "string", + "description": "The connection string to the Azure SignalR.", + "minLength": 1 + }, + "hubName": { + "title": "Hub Name", + "type": "string", + "description": "The name of the hub.", + "minLength": 1 + }, + "action": { + "title": "Action", + "description": "* Broadcast = send to all users.\n * User = send to all target users(s).\n * Group = send to all target group(s).", + "$ref": "#/components/schemas/SignalRActionType" + }, + "methodName": { + "title": "Methode Name", + "type": "string", + "description": "Set the Name of the hub method received by the customer.", + "nullable": true + }, + "target": { + "title": "Target (Optional)", + "type": "string", + "description": "Define target users or groups by id or name. One item per line. Not needed for Broadcast action.", + "nullable": true + }, + "payload": { + "title": "Payload (Optional)", + "type": "string", + "description": "Leave it empty to use the full event as body.", + "nullable": true + } + } + } + ] + }, + "SignalRActionType": { + "type": "string", + "description": "", + "x-enumNames": [ + "Broadcast", + "User", + "Group" + ], + "enum": [ + "Broadcast", + "User", + "Group" + ] + }, + "SlackFlowStepDto": { + "allOf": [ + { + "$ref": "#/components/schemas/FlowStepDto" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "webhookUrl", + "text" + ], + "properties": { + "webhookUrl": { + "title": "Webhook Url", + "type": "string", + "description": "The slack webhook url.", + "format": "uri", + "minLength": 1 + }, + "text": { + "title": "Text", + "type": "string", + "description": "The text that is sent as message to slack.", + "minLength": 1 + } + } + } + ] + }, + "TweetFlowStepDto": { + "allOf": [ + { + "$ref": "#/components/schemas/FlowStepDto" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "accessToken", + "accessSecret", + "text" + ], + "properties": { + "accessToken": { + "title": "Access Token", + "type": "string", + "description": " The generated access token.", + "minLength": 1 + }, + "accessSecret": { + "title": "Access Secret", + "type": "string", + "description": " The generated access secret.", + "minLength": 1 + }, + "text": { + "title": "Text", + "type": "string", + "description": "The text that is sent as tweet to twitter.", + "minLength": 1 + } + } + } + ] + }, + "TypesenseFlowStepDto": { + "allOf": [ + { + "$ref": "#/components/schemas/FlowStepDto" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "host", + "indexName", + "apiKey" + ], + "properties": { + "host": { + "title": "Server Url", + "type": "string", + "description": "The url to the instance or cluster.", + "format": "uri", + "minLength": 1 + }, + "indexName": { + "title": "Index Name", + "type": "string", + "description": "The name of the index.", + "minLength": 1 + }, + "apiKey": { + "title": "Api Key", + "type": "string", + "description": "The api key.", + "minLength": 1 + }, + "document": { + "title": "Document", + "type": "string", + "description": "The optional custom document.", + "nullable": true + }, + "delete": { + "title": "Deletion", + "type": "string", + "description": "The condition when to delete the document.", + "nullable": true + } + } + } + ] + }, + "WebhookFlowStepDto": { + "allOf": [ + { + "$ref": "#/components/schemas/FlowStepDto" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "method", + "url" + ], + "properties": { + "method": { + "title": "Method", + "description": "The type of the request.", + "$ref": "#/components/schemas/WebhookMethod" + }, + "url": { + "title": "Url", + "type": "string", + "description": "The URL to the webhook.", + "minLength": 1 + }, + "payload": { + "title": "Payload (Optional)", + "type": "string", + "description": "Leave it empty to use the full event as body.", + "nullable": true + }, + "headers": { + "title": "Headers (Optional)", + "type": "string", + "description": "The message headers in the format '[Key]=[Value]', one entry per line.", + "nullable": true + }, + "payloadType": { + "title": "Payload Type", + "type": "string", + "description": "The mime type of the payload.", + "nullable": true + }, + "sharedSecret": { + "title": "Shared Secret", + "type": "string", + "description": "The shared secret that is used to calculate the payload signature.", + "nullable": true + } + } + } + ] + }, + "WebhookMethod": { + "type": "string", + "description": "", + "x-enumNames": [ + "POST", + "PUT", + "GET", + "DELETE", + "PATCH" + ], + "enum": [ + "POST", + "PUT", + "GET", + "DELETE", + "PATCH" + ] + }, + "RuleActionDto": { + "type": "object", + "discriminator": { + "propertyName": "actionType", + "mapping": { + "Algolia": "#/components/schemas/AlgoliaRuleActionDto", + "AzureQueue": "#/components/schemas/AzureQueueRuleActionDto", + "Comment": "#/components/schemas/CommentRuleActionDto", + "CreateContent": "#/components/schemas/CreateContentRuleActionDto", + "Discourse": "#/components/schemas/DiscourseRuleActionDto", + "ElasticSearch": "#/components/schemas/ElasticSearchRuleActionDto", + "Email": "#/components/schemas/EmailRuleActionDto", + "Fastly": "#/components/schemas/FastlyRuleActionDto", + "Medium": "#/components/schemas/MediumRuleActionDto", + "Notification": "#/components/schemas/NotificationRuleActionDto", + "OpenSearch": "#/components/schemas/OpenSearchRuleActionDto", + "Prerender": "#/components/schemas/PrerenderRuleActionDto", + "Script": "#/components/schemas/ScriptRuleActionDto", + "SignalR": "#/components/schemas/SignalRRuleActionDto", + "Slack": "#/components/schemas/SlackRuleActionDto", + "Tweet": "#/components/schemas/TweetRuleActionDto", + "Typesense": "#/components/schemas/TypesenseRuleActionDto", + "Webhook": "#/components/schemas/WebhookRuleActionDto" + } + }, + "deprecated": true, + "x-deprecatedMessage": "Has been replaced by flows.", + "x-abstract": true, + "additionalProperties": false, + "required": [ + "actionType" + ], + "properties": { + "actionType": { + "type": "string" + } + } + }, + "AlgoliaRuleActionDto": { + "allOf": [ + { + "$ref": "#/components/schemas/RuleActionDto" + }, + { + "type": "object", + "deprecated": true, + "x-deprecatedMessage": "Has been replaced by flows.", + "additionalProperties": false, + "required": [ + "appId", + "apiKey", + "indexName" + ], + "properties": { + "appId": { + "type": "string", + "minLength": 1 + }, + "apiKey": { + "type": "string", + "minLength": 1 + }, + "indexName": { + "type": "string", + "minLength": 1 + }, + "document": { + "type": "string", + "nullable": true + }, + "delete": { + "type": "string", + "nullable": true + } + } + } + ] + }, + "AzureQueueRuleActionDto": { + "allOf": [ + { + "$ref": "#/components/schemas/RuleActionDto" + }, + { + "type": "object", + "deprecated": true, + "x-deprecatedMessage": "Has been replaced by flows.", + "additionalProperties": false, + "required": [ + "connectionString", + "queue" + ], + "properties": { + "connectionString": { + "type": "string", + "minLength": 1 + }, + "queue": { + "type": "string", + "minLength": 1 + }, + "payload": { + "type": "string", + "nullable": true + } + } + } + ] + }, + "CommentRuleActionDto": { + "allOf": [ + { + "$ref": "#/components/schemas/RuleActionDto" + }, + { + "type": "object", + "deprecated": true, + "x-deprecatedMessage": "Has been replaced by flows.", + "additionalProperties": false, + "required": [ + "text" + ], + "properties": { + "text": { + "type": "string", + "minLength": 1 + }, + "client": { + "type": "string", + "nullable": true + } + } + } + ] + }, + "CreateContentRuleActionDto": { + "allOf": [ + { + "$ref": "#/components/schemas/RuleActionDto" + }, + { + "type": "object", + "deprecated": true, + "x-deprecatedMessage": "Has been replaced by flows.", + "additionalProperties": false, + "required": [ + "data", + "schema", + "publish" + ], + "properties": { + "data": { + "type": "string", + "minLength": 1 + }, + "schema": { + "type": "string", + "minLength": 1 + }, + "client": { + "type": "string", + "nullable": true + }, + "publish": { + "type": "boolean" + } + } + } + ] + }, + "DiscourseRuleActionDto": { + "allOf": [ + { + "$ref": "#/components/schemas/RuleActionDto" + }, + { + "type": "object", + "deprecated": true, + "x-deprecatedMessage": "Has been replaced by flows.", + "additionalProperties": false, + "required": [ + "url", + "apiKey", + "apiUsername", + "text" + ], + "properties": { + "url": { + "type": "string", + "format": "uri", + "minLength": 1 + }, + "apiKey": { + "type": "string", + "minLength": 1 + }, + "apiUsername": { + "type": "string", + "minLength": 1 + }, + "text": { + "type": "string", + "minLength": 1 + }, + "title": { + "type": "string", + "nullable": true + }, + "topic": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "category": { + "type": "integer", + "format": "int32", + "nullable": true + } + } + } + ] + }, + "ElasticSearchRuleActionDto": { + "allOf": [ + { + "$ref": "#/components/schemas/RuleActionDto" + }, + { + "type": "object", + "deprecated": true, + "x-deprecatedMessage": "Has been replaced by flows.", + "additionalProperties": false, + "required": [ + "host", + "indexName" + ], + "properties": { + "host": { + "type": "string", + "format": "uri", + "minLength": 1 + }, + "indexName": { + "type": "string", + "minLength": 1 + }, + "username": { + "type": "string", + "nullable": true + }, + "password": { + "type": "string", + "nullable": true + }, + "document": { + "type": "string", + "nullable": true + }, + "delete": { + "type": "string", + "nullable": true + } + } + } + ] + }, + "EmailRuleActionDto": { + "allOf": [ + { + "$ref": "#/components/schemas/RuleActionDto" + }, + { + "type": "object", + "deprecated": true, + "x-deprecatedMessage": "Has been replaced by flows.", + "additionalProperties": false, + "required": [ + "serverHost", + "serverPort", + "messageFrom", + "messageTo", + "messageSubject", + "messageBody", + "serverUsername", + "serverPassword" + ], + "properties": { + "serverHost": { + "type": "string", + "minLength": 1 + }, + "serverPort": { + "type": "integer", + "format": "int32" + }, + "messageFrom": { + "type": "string", + "minLength": 1 + }, + "messageTo": { + "type": "string", + "minLength": 1 + }, + "messageSubject": { + "type": "string", + "minLength": 1 + }, + "messageBody": { + "type": "string", + "minLength": 1 + }, + "serverUsername": { + "type": "string" + }, + "serverPassword": { + "type": "string" + } + } + } + ] + }, + "FastlyRuleActionDto": { + "allOf": [ + { + "$ref": "#/components/schemas/RuleActionDto" + }, + { + "type": "object", + "deprecated": true, + "x-deprecatedMessage": "Has been replaced by flows.", + "additionalProperties": false, + "required": [ + "apiKey", + "serviceId" + ], + "properties": { + "apiKey": { + "type": "string", + "minLength": 1 + }, + "serviceId": { + "type": "string", + "minLength": 1 + } + } + } + ] + }, + "MediumRuleActionDto": { + "allOf": [ + { + "$ref": "#/components/schemas/RuleActionDto" + }, + { + "type": "object", + "deprecated": true, + "x-deprecatedMessage": "Has been replaced by flows.", + "additionalProperties": false, + "required": [ + "accessToken", + "title", + "content", + "isHtml" + ], + "properties": { + "accessToken": { + "type": "string", + "minLength": 1 + }, + "title": { + "type": "string", + "minLength": 1 + }, + "content": { + "type": "string", + "minLength": 1 + }, + "canonicalUrl": { + "type": "string", + "nullable": true + }, + "tags": { + "type": "string", + "nullable": true + }, + "publicationId": { + "type": "string", + "nullable": true + }, + "isHtml": { + "type": "boolean" + } + } + } + ] + }, + "NotificationRuleActionDto": { + "allOf": [ + { + "$ref": "#/components/schemas/RuleActionDto" + }, + { + "type": "object", + "deprecated": true, + "x-deprecatedMessage": "Has been replaced by flows.", + "additionalProperties": false, + "required": [ + "user", + "text" + ], + "properties": { + "user": { + "type": "string", + "minLength": 1 + }, + "text": { + "type": "string", + "minLength": 1 + }, + "url": { + "type": "string", + "nullable": true + }, + "client": { + "type": "string", + "nullable": true + } + } + } + ] + }, + "OpenSearchRuleActionDto": { + "allOf": [ + { + "$ref": "#/components/schemas/RuleActionDto" + }, + { + "type": "object", + "deprecated": true, + "x-deprecatedMessage": "Has been replaced by flows.", + "additionalProperties": false, + "required": [ + "host", + "indexName" + ], + "properties": { + "host": { + "type": "string", + "format": "uri", + "minLength": 1 + }, + "indexName": { + "type": "string", + "minLength": 1 + }, + "username": { + "type": "string", + "nullable": true + }, + "password": { + "type": "string", + "nullable": true + }, + "document": { + "type": "string", + "nullable": true + }, + "delete": { + "type": "string", + "nullable": true + } + } + } + ] + }, + "PrerenderRuleActionDto": { + "allOf": [ + { + "$ref": "#/components/schemas/RuleActionDto" + }, + { + "type": "object", + "deprecated": true, + "x-deprecatedMessage": "Has been replaced by flows.", + "additionalProperties": false, + "required": [ + "token", + "url" + ], + "properties": { + "token": { + "type": "string", + "minLength": 1 + }, + "url": { + "type": "string", + "minLength": 1 + } + } + } + ] + }, + "ScriptRuleActionDto": { + "allOf": [ + { + "$ref": "#/components/schemas/RuleActionDto" + }, + { + "type": "object", + "deprecated": true, + "x-deprecatedMessage": "Has been replaced by flows.", + "additionalProperties": false, + "required": [ + "script" + ], + "properties": { + "script": { + "type": "string", + "minLength": 1 + } + } + } + ] + }, + "SignalRRuleActionDto": { + "allOf": [ + { + "$ref": "#/components/schemas/RuleActionDto" + }, + { + "type": "object", + "deprecated": true, + "x-deprecatedMessage": "Has been replaced by flows.", + "additionalProperties": false, + "required": [ + "connectionString", + "hubName", + "action" + ], + "properties": { + "connectionString": { + "type": "string", + "minLength": 1 + }, + "hubName": { + "type": "string", + "minLength": 1 + }, + "action": { + "$ref": "#/components/schemas/SignalRActionType" + }, + "methodName": { + "type": "string", + "nullable": true + }, + "target": { + "type": "string", + "nullable": true + }, + "payload": { + "type": "string", + "nullable": true + } + } + } + ] + }, + "SlackRuleActionDto": { + "allOf": [ + { + "$ref": "#/components/schemas/RuleActionDto" + }, + { + "type": "object", + "deprecated": true, + "x-deprecatedMessage": "Has been replaced by flows.", + "additionalProperties": false, + "required": [ + "webhookUrl", + "text" + ], + "properties": { + "webhookUrl": { + "type": "string", + "format": "uri", + "minLength": 1 + }, + "text": { + "type": "string", + "minLength": 1 + } + } + } + ] + }, + "TweetRuleActionDto": { + "allOf": [ + { + "$ref": "#/components/schemas/RuleActionDto" + }, + { + "type": "object", + "deprecated": true, + "x-deprecatedMessage": "Has been replaced by flows.", + "additionalProperties": false, + "required": [ + "accessToken", + "accessSecret", + "text" + ], + "properties": { + "accessToken": { + "type": "string", + "minLength": 1 + }, + "accessSecret": { + "type": "string", + "minLength": 1 + }, + "text": { + "type": "string", + "minLength": 1 + } + } + } + ] + }, + "TypesenseRuleActionDto": { + "allOf": [ + { + "$ref": "#/components/schemas/RuleActionDto" + }, + { + "type": "object", + "deprecated": true, + "x-deprecatedMessage": "Has been replaced by flows.", + "additionalProperties": false, + "required": [ + "host", + "indexName", + "apiKey" + ], + "properties": { + "host": { + "type": "string", + "format": "uri", + "minLength": 1 + }, + "indexName": { + "type": "string", + "minLength": 1 + }, + "apiKey": { + "type": "string" + }, + "document": { + "type": "string", + "nullable": true + }, + "delete": { + "type": "string", + "nullable": true + } + } + } + ] + }, + "WebhookRuleActionDto": { + "allOf": [ + { + "$ref": "#/components/schemas/RuleActionDto" + }, + { + "type": "object", + "deprecated": true, + "x-deprecatedMessage": "Has been replaced by flows.", + "additionalProperties": false, + "required": [ + "url", + "method" + ], + "properties": { + "url": { + "type": "string", + "format": "uri", + "minLength": 1 + }, + "method": { + "$ref": "#/components/schemas/WebhookMethod" + }, + "payload": { + "type": "string", + "nullable": true + }, + "payloadType": { + "type": "string", + "nullable": true + }, + "headers": { + "type": "string", + "nullable": true + }, + "sharedSecret": { + "type": "string", + "nullable": true + } + } + } + ] + }, + "CreateRuleDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "trigger", + "flow" + ], + "properties": { + "name": { + "type": "string", + "description": "Optional rule name.", + "nullable": true + }, + "trigger": { + "description": "The trigger properties.", + "$ref": "#/components/schemas/RuleTriggerDto" + }, + "action": { + "description": "The action properties.", + "deprecated": true, + "x-deprecatedMessage": "Use the new 'Flow' property to define actions", + "nullable": true, + "$ref": "#/components/schemas/RuleActionDto" + }, + "flow": { + "description": "The flow to describe the sequence of actions to perform.", + "$ref": "#/components/schemas/FlowDefinitionDto" + }, + "isEnabled": { + "type": "boolean", + "description": "Enable or disable the rule.", + "nullable": true + } + } + }, + "UpdateRuleDto": { + "type": "object", + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Optional rule name.", + "nullable": true + }, + "trigger": { + "description": "The trigger properties.", + "nullable": true, + "$ref": "#/components/schemas/RuleTriggerDto" + }, + "action": { + "description": "The flow to describe the sequence of actions to perform.", + "deprecated": true, + "x-deprecatedMessage": "Use the new 'Flow' property to define actions", + "nullable": true, + "$ref": "#/components/schemas/RuleActionDto" + }, + "flow": { + "description": "The flow.", + "nullable": true, + "$ref": "#/components/schemas/FlowDefinitionDto" + }, + "isEnabled": { + "type": "boolean", + "description": "Enable or disable the rule.", + "nullable": true + } + } + }, + "TriggerRuleDto": { + "type": "object", + "additionalProperties": false, + "properties": { + "value": { + "description": "The optional value to send to the flow." + } + } + }, + "SimulatedRuleEventsDto": { + "allOf": [ + { + "$ref": "#/components/schemas/Resource" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "total", + "items" + ], + "properties": { + "total": { + "type": "integer", + "description": "The total number of simulated rule events.", + "format": "int64" + }, + "items": { + "type": "array", + "description": "The simulated rule events.", + "items": { + "$ref": "#/components/schemas/SimulatedRuleEventDto" + } + } + } + } + ] + }, + "SimulatedRuleEventDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "eventId", + "uniqueId", + "eventName", + "event", + "skipReasons" + ], + "properties": { + "eventId": { + "type": "string", + "description": "The unique event id.", + "format": "guid" + }, + "uniqueId": { + "type": "string", + "description": "The the unique id of the simulated event." + }, + "eventName": { + "type": "string", + "description": "The name of the event." + }, + "event": { + "description": "The source event." + }, + "enrichedEvent": { + "description": "The enriched event.", + "nullable": true + }, + "flowState": { + "description": "The flow state.", + "nullable": true, + "$ref": "#/components/schemas/FlowExecutionStateDto" + }, + "skipReasons": { + "type": "array", + "description": "The reason why the event has been skipped.", + "items": { + "$ref": "#/components/schemas/SkipReason" + } + } + } + }, + "FlowExecutionStateDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "definition", + "context", + "description", + "steps", + "nextStepId", + "created", + "completed", + "status" + ], + "properties": { + "definition": { + "description": "The actual definition of the the steps to be executed.", + "$ref": "#/components/schemas/FlowDefinitionDto" + }, + "context": { + "description": "The context." + }, + "description": { + "type": "string", + "description": "The description of the execution state (usually the event name)." + }, + "steps": { + "type": "object", + "description": "The state of each step.", + "additionalProperties": { + "$ref": "#/components/schemas/FlowExecutionStepStateDto" + } + }, + "nextStepId": { + "type": "string", + "description": "The next step to be executed.", + "format": "guid" + }, + "nextRun": { + "type": "string", + "description": "THe time when the next step will be executed.", + "format": "date-time", + "nullable": true + }, + "created": { + "type": "string", + "description": "The creation time.", + "format": "date-time" + }, + "completed": { + "type": "string", + "description": "The completion time.", + "format": "date-time" + }, + "status": { + "description": "The overall status.", + "$ref": "#/components/schemas/FlowExecutionStatus" + } + } + }, + "FlowExecutionStepStateDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "status", + "attempts" + ], + "properties": { + "status": { + "description": "The status of this step.", + "$ref": "#/components/schemas/FlowExecutionStatus" + }, + "attempts": { + "type": "array", + "description": "The different attempts.", + "items": { + "$ref": "#/components/schemas/FlowExecutionStepAttemptDto" + } + } + } + }, + "FlowExecutionStatus": { + "type": "string", + "description": "", + "x-enumNames": [ + "Pending", + "Scheduled", + "Completed", + "Failed", + "Running", + "Cancelled" + ], + "enum": [ + "Pending", + "Scheduled", + "Completed", + "Failed", + "Running", + "Cancelled" + ] + }, + "FlowExecutionStepAttemptDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "log", + "started", + "completed" + ], + "properties": { + "log": { + "type": "array", + "description": "The log messages.", + "items": { + "$ref": "#/components/schemas/FlowExecutionStepLogEntryDto" + } + }, + "started": { + "type": "string", + "description": "The time when the attempt has been started.", + "format": "date-time" + }, + "completed": { + "type": "string", + "description": "The time when the attempt has been completed.", + "format": "date-time" + }, + "error": { + "type": "string", + "description": "The error, if there is any.", + "nullable": true + } + } + }, + "FlowExecutionStepLogEntryDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "timestamp", + "message" + ], + "properties": { + "timestamp": { + "type": "string", + "description": "The timestamp.", + "format": "date-time" + }, + "message": { + "type": "string", + "description": "The log message." + }, + "dump": { + "type": "string", + "description": "A detailed dump.", + "nullable": true + } + } + }, + "SkipReason": { + "type": "string", + "description": "", + "x-enumFlags": true, + "x-enumNames": [ + "None", + "ConditionDoesNotMatch", + "ConditionPrecheckDoesNotMatch", + "Disabled", + "Failed", + "FromRule", + "NoTrigger", + "TooOld", + "WrongEvent", + "WrongEventForTrigger" + ], + "enum": [ + "None", + "ConditionDoesNotMatch", + "ConditionPrecheckDoesNotMatch", + "Disabled", + "Failed", + "FromRule", + "NoTrigger", + "TooOld", + "WrongEvent", + "WrongEventForTrigger" + ] + }, + "RuleEventsDto": { + "allOf": [ + { + "$ref": "#/components/schemas/Resource" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "total", + "items" + ], + "properties": { + "total": { + "type": "integer", + "description": "The total number of rule events.", + "format": "int64" + }, + "items": { + "type": "array", + "description": "The rule events.", + "items": { + "$ref": "#/components/schemas/RuleEventDto" + } + } + } + } + ] + }, + "RuleEventDto": { + "allOf": [ + { + "$ref": "#/components/schemas/Resource" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "flowState" + ], + "properties": { + "id": { + "type": "string", + "description": "The ID of the event.", + "format": "guid" + }, + "flowState": { + "description": "The flow state.", + "$ref": "#/components/schemas/FlowExecutionStateDto" + } + } + } + ] + }, + "PlansDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "plans", + "locked" + ], + "properties": { + "plans": { + "type": "array", + "description": "The available plans.", + "items": { + "$ref": "#/components/schemas/PlanDto" + } + }, + "currentPlanId": { + "type": "string", + "description": "The current plan id.", + "nullable": true + }, + "planOwner": { + "type": "string", + "description": "The plan owner.", + "nullable": true + }, + "portalLink": { + "type": "string", + "description": "The link to the management portal.", + "format": "uri", + "nullable": true + }, + "referral": { + "description": "The referral management.", + "nullable": true, + "$ref": "#/components/schemas/ReferralInfo" + }, + "locked": { + "description": "The reason why the plan cannot be changed.", + "$ref": "#/components/schemas/PlansLockedReason" + } + } + }, + "PlanDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "name", + "costs", + "maxApiBytes", + "maxApiCalls", + "maxAssetSize", + "maxContributors" + ], + "properties": { + "id": { + "type": "string", + "description": "The ID of the plan." + }, + "name": { + "type": "string", + "description": "The name of the plan." + }, + "costs": { + "type": "string", + "description": "The monthly costs of the plan." + }, + "confirmText": { + "type": "string", + "description": "An optional confirm text for the monthly subscription.", + "nullable": true + }, + "yearlyConfirmText": { + "type": "string", + "description": "An optional confirm text for the yearly subscription.", + "nullable": true + }, + "yearlyCosts": { + "type": "string", + "description": "The yearly costs of the plan.", + "nullable": true + }, + "yearlyId": { + "type": "string", + "description": "The yearly ID of the plan.", + "nullable": true + }, + "maxApiBytes": { + "type": "integer", + "description": "The maximum number of API traffic.", + "format": "int64" + }, + "maxApiCalls": { + "type": "integer", + "description": "The maximum number of API calls.", + "format": "int64" + }, + "maxAssetSize": { + "type": "integer", + "description": "The maximum allowed asset size.", + "format": "int64" + }, + "maxContributors": { + "type": "integer", + "description": "The maximum number of contributors.", + "format": "int32" + } + } + }, + "ReferralInfo": { + "type": "object", + "additionalProperties": false, + "required": [ + "code", + "earned", + "condition" + ], + "properties": { + "code": { + "type": "string" + }, + "earned": { + "type": "string" + }, + "condition": { + "type": "string" + } + } + }, + "PlansLockedReason": { + "type": "string", + "description": "", + "x-enumNames": [ + "None", + "NotOwner", + "NoPermission", + "ManagedByTeam" + ], + "enum": [ + "None", + "NotOwner", + "NoPermission", + "ManagedByTeam" + ] + }, + "PlanChangedDto": { + "type": "object", + "additionalProperties": false, + "properties": { + "redirectUri": { + "type": "string", + "description": "Optional redirect uri.", + "nullable": true + } + } + }, + "ChangePlanDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "planId" + ], + "properties": { + "planId": { + "type": "string", + "description": "The new plan id.", + "minLength": 1 + } + } + }, + "ExposedValues": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "FeaturesDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "features", + "version" + ], + "properties": { + "features": { + "type": "array", + "description": "The latest features.", + "items": { + "$ref": "#/components/schemas/FeatureDto" + } + }, + "version": { + "type": "integer", + "description": "The recent version.", + "format": "int32" + } + } + }, + "FeatureDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "name", + "text" + ], + "properties": { + "name": { + "type": "string", + "description": "The name of the feature." + }, + "text": { + "type": "string", + "description": "The description text." + } + } + }, + "LanguageDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "iso2Code", + "englishName", + "nativeName" + ], + "properties": { + "iso2Code": { + "type": "string", + "description": "The iso code of the language." + }, + "englishName": { + "type": "string", + "description": "The english name of the language." + }, + "nativeName": { + "type": "string", + "description": "The native name of the language." + } + } + }, + "JobsDto": { + "allOf": [ + { + "$ref": "#/components/schemas/Resource" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "items" + ], + "properties": { + "items": { + "type": "array", + "description": "The jobs.", + "items": { + "$ref": "#/components/schemas/JobDto" + } + } + } + } + ] + }, + "JobDto": { + "allOf": [ + { + "$ref": "#/components/schemas/Resource" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "started", + "status", + "taskName", + "description", + "taskArguments", + "log", + "canDownload" + ], + "properties": { + "id": { + "type": "string", + "description": "The ID of the job." + }, + "started": { + "type": "string", + "description": "The time when the job has been started.", + "format": "date-time" + }, + "stopped": { + "type": "string", + "description": "The time when the job has been stopped.", + "format": "date-time", + "nullable": true + }, + "status": { + "description": "The status of the operation.", + "$ref": "#/components/schemas/JobStatus" + }, + "taskName": { + "type": "string", + "description": "The name of the task." + }, + "description": { + "type": "string", + "description": "The description of the job." + }, + "taskArguments": { + "type": "object", + "description": "The arguments for the job.", + "additionalProperties": { + "type": "string" + } + }, + "log": { + "type": "array", + "description": "The list of log items.", + "items": { + "$ref": "#/components/schemas/JobLogMessageDto" + } + }, + "canDownload": { + "type": "boolean", + "description": "Indicates whether the job can be downloaded." + } + } + } + ] + }, + "JobStatus": { + "type": "string", + "description": "", + "x-enumNames": [ + "Created", + "Started", + "Completed", + "Cancelled", + "Failed" + ], + "enum": [ + "Created", + "Started", + "Completed", + "Cancelled", + "Failed" + ] + }, + "JobLogMessageDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "timestamp", + "message" + ], + "properties": { + "timestamp": { + "type": "string", + "description": "The timestamp.", + "format": "date-time" + }, + "message": { + "type": "string", + "description": "The log message." + } + } + }, + "HistoryEventDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "message", + "eventType", + "actor", + "eventId", + "created", + "version" + ], + "properties": { + "message": { + "type": "string", + "description": "The message for the event." + }, + "eventType": { + "type": "string", + "description": "The type of the original event." + }, + "actor": { + "type": "string", + "description": "The user who called the action." + }, + "eventId": { + "type": "string", + "description": "Gets a unique id for the event." + }, + "created": { + "type": "string", + "description": "The time when the event happened.", + "format": "date-time" + }, + "version": { + "type": "integer", + "description": "The version identifier.", + "format": "int64" + } + } + }, + "EventConsumersDto": { + "allOf": [ + { + "$ref": "#/components/schemas/Resource" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "items" + ], + "properties": { + "items": { + "type": "array", + "description": "The event consumers.", + "items": { + "$ref": "#/components/schemas/EventConsumerDto" + } + } + } + } + ] + }, + "EventConsumerDto": { + "allOf": [ + { + "$ref": "#/components/schemas/Resource" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "name", + "isStopped", + "isResetting", + "count" + ], + "properties": { + "isStopped": { + "type": "boolean", + "description": "Indicates if the event consumer has been started." + }, + "isResetting": { + "type": "boolean", + "description": "Indicates if the event consumer is resetting at the moment." + }, + "count": { + "type": "integer", + "description": "The number of handled events.", + "format": "int32" + }, + "name": { + "type": "string", + "description": "The name of the event consumer.", + "minLength": 1 + }, + "error": { + "type": "string", + "description": "The error details if the event consumer has been stopped after a failure.", + "nullable": true + }, + "position": { + "type": "string", + "description": "The position within the vent stream.", + "nullable": true + } + } + } + ] + }, + "ContentsDto": { + "allOf": [ + { + "$ref": "#/components/schemas/Resource" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "total", + "items", + "statuses" + ], + "properties": { + "total": { + "type": "integer", + "description": "The total number of content items.", + "format": "int64" + }, + "items": { + "type": "array", + "description": "The content items.", + "items": { + "$ref": "#/components/schemas/ContentDto" + } + }, + "statuses": { + "type": "array", + "description": "The possible statuses.", + "items": { + "$ref": "#/components/schemas/StatusInfoDto" + } + } + } + } + ] + }, + "ContentDto": { + "allOf": [ + { + "$ref": "#/components/schemas/Resource" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "createdBy", + "lastModifiedBy", + "data", + "created", + "lastModified", + "status", + "statusColor", + "schemaId", + "isDeleted", + "version" + ], + "properties": { + "id": { + "type": "string", + "description": "The if of the content item." + }, + "createdBy": { + "type": "string", + "description": "The user that has created the content item." + }, + "lastModifiedBy": { + "type": "string", + "description": "The user that has updated the content item." + }, + "data": { + "description": "The data of the content item." + }, + "referenceData": { + "description": "The reference data for the frontend UI.", + "nullable": true, + "$ref": "#/components/schemas/ContentData" + }, + "created": { + "type": "string", + "description": "The date and time when the content item has been created.", + "format": "date-time" + }, + "lastModified": { + "type": "string", + "description": "The date and time when the content item has been modified last.", + "format": "date-time" + }, + "status": { + "type": "string", + "description": "The status of the content." + }, + "newStatus": { + "type": "string", + "description": "The new status of the content.", + "nullable": true + }, + "statusColor": { + "type": "string", + "description": "The color of the status." + }, + "newStatusColor": { + "type": "string", + "description": "The color of the new status.", + "nullable": true + }, + "editToken": { + "type": "string", + "description": "The UI token.", + "nullable": true + }, + "scheduleJob": { + "description": "The scheduled status.", + "nullable": true, + "$ref": "#/components/schemas/ScheduleJobDto" + }, + "schemaId": { + "type": "string", + "description": "The ID of the schema." + }, + "schemaName": { + "type": "string", + "description": "The name of the schema.", + "nullable": true + }, + "schemaDisplayName": { + "type": "string", + "description": "The display name of the schema.", + "nullable": true + }, + "referenceFields": { + "type": "array", + "description": "The reference fields.", + "nullable": true, + "items": { + "$ref": "#/components/schemas/FieldDto" + } + }, + "isDeleted": { + "type": "boolean", + "description": "Indicates whether the content is deleted." + }, + "version": { + "type": "integer", + "description": "The version of the content.", + "format": "int64" + } + } + } + ] + }, + "ContentData": { + "type": "object", + "additionalProperties": { + "nullable": true, + "$ref": "#/components/schemas/ContentFieldData" + } + }, + "ContentFieldData": { + "type": "object", + "additionalProperties": {} + }, + "ScheduleJobDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "status", + "dueTime", + "color", + "scheduledBy" + ], + "properties": { + "id": { + "type": "string", + "description": "The ID of the schedule job." + }, + "status": { + "type": "string", + "description": "The new status." + }, + "dueTime": { + "type": "string", + "description": "The target date and time when the content should be scheduled.", + "format": "date-time" + }, + "color": { + "type": "string", + "description": "The color of the scheduled status." + }, + "scheduledBy": { + "type": "string", + "description": "The user who schedule the content." + } + } + }, + "StatusInfoDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "status", + "color" + ], + "properties": { + "status": { + "type": "string", + "description": "The name of the status." + }, + "color": { + "type": "string", + "description": "The color of the status." + } + } + }, + "QueryDto": { + "type": "object", + "additionalProperties": false, + "properties": { + "ids": { + "type": "array", + "description": "The optional list of ids to query.", + "nullable": true, + "items": { + "type": "string" + } + }, + "oData": { + "type": "string", + "description": "The optional odata query.", + "nullable": true + }, + "q": { + "description": "The optional json query.", + "nullable": true + }, + "parentId": { + "type": "string", + "description": "The parent id (for assets).", + "nullable": true + } + } + }, + "BulkResultDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "jobIndex" + ], + "properties": { + "error": { + "description": "The error when the bulk job failed.", + "nullable": true, + "$ref": "#/components/schemas/ErrorDto" + }, + "jobIndex": { + "type": "integer", + "description": "The index of the bulk job where the result belongs to. The order can change.", + "format": "int32" + }, + "id": { + "type": "string", + "description": "The ID of the entity that has been handled successfully or not.", + "nullable": true + }, + "contentId": { + "type": "string", + "description": "The ID of the entity that has been handled successfully or not.", + "deprecated": true, + "x-deprecatedMessage": "Use 'id' field now.", + "nullable": true + } + } + }, + "ImportContentsDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "datas" + ], + "properties": { + "datas": { + "type": "array", + "description": "The data to import.", + "items": { + "$ref": "#/components/schemas/ContentData" + } + }, + "publish": { + "type": "boolean", + "description": "True to automatically publish the content.", + "deprecated": true, + "x-deprecatedMessage": "Use bulk endpoint now." + }, + "doNotScript": { + "type": "boolean", + "description": "True to turn off scripting for faster inserts. Default: true." + }, + "optimizeValidation": { + "type": "boolean", + "description": "True to turn off costly validation: Unique checks, asset checks and reference checks. Default: true." + } + } + }, + "BulkUpdateContentsDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "jobs" + ], + "properties": { + "jobs": { + "type": "array", + "description": "The contents to update or insert.", + "items": { + "$ref": "#/components/schemas/BulkUpdateContentsJobDto" + } + }, + "publish": { + "type": "boolean", + "description": "True to automatically publish the content.", + "deprecated": true, + "x-deprecatedMessage": "Use 'jobs.status' fields now." + }, + "doNotScript": { + "type": "boolean", + "description": "True to turn off scripting for faster inserts. Default: true." + }, + "enrichRequiredFields": { + "type": "boolean", + "description": "True, to also enrich required fields. Default: false." + }, + "doNotValidate": { + "type": "boolean", + "description": "True to turn off validation for faster inserts. Default: false." + }, + "doNotValidateWorkflow": { + "type": "boolean", + "description": "True to turn off validation of workflow rules. Default: false." + }, + "checkReferrers": { + "type": "boolean", + "description": "True to check referrers of deleted contents." + }, + "optimizeValidation": { + "type": "boolean", + "description": "True to turn off costly validation: Unique checks, asset checks and reference checks. Default: true." + } + } + }, + "BulkUpdateContentsJobDto": { + "type": "object", + "additionalProperties": false, + "properties": { + "query": { + "description": "An optional query to identify the content to update.", + "nullable": true, + "$ref": "#/components/schemas/QueryJsonDto" + }, + "id": { + "type": "string", + "description": "An optional ID of the content to update.", + "nullable": true + }, + "data": { + "description": "The data of the content when type is set to 'Upsert', 'Create', 'Update' or 'Patch.", + "nullable": true, + "$ref": "#/components/schemas/ContentData" + }, + "status": { + "type": "string", + "description": "The new status when the type is set to 'ChangeStatus' or 'Upsert'.", + "nullable": true + }, + "dueTime": { + "type": "string", + "description": "The due time.", + "format": "date-time", + "nullable": true + }, + "type": { + "description": "The update type.", + "$ref": "#/components/schemas/BulkUpdateContentType" + }, + "schema": { + "type": "string", + "description": "The optional schema id or name.", + "nullable": true + }, + "patch": { + "type": "boolean", + "description": "Makes the update as patch." + }, + "permanent": { + "type": "boolean", + "description": "True to delete the content permanently." + }, + "enrichDefaults": { + "type": "boolean", + "description": "Enrich the data with the default values when updating a content item." + }, + "expectedCount": { + "type": "integer", + "description": "The number of expected items. Set it to a higher number to update multiple items when a query is defined.", + "format": "int64" + }, + "expectedVersion": { + "type": "integer", + "description": "The expected version.", + "format": "int64" + } + } + }, + "QueryJsonDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "skip", + "take", + "random", + "top" + ], + "properties": { + "filter": { + "nullable": true + }, + "fullText": { + "type": "string", + "nullable": true + }, + "collation": { + "type": "string", + "nullable": true + }, + "skip": { + "type": "integer", + "format": "int64" + }, + "take": { + "type": "integer", + "format": "int64" + }, + "random": { + "type": "integer", + "format": "int64" + }, + "top": { + "type": "integer", + "format": "int64" + }, + "sort": { + "type": "array", + "nullable": true, + "items": { + "$ref": "#/components/schemas/SortNode" + } + } + } + }, + "SortNode": { + "type": "object", + "additionalProperties": false, + "required": [ + "path", + "order" + ], + "properties": { + "path": { + "type": "string" + }, + "order": { + "$ref": "#/components/schemas/SortOrder" + } + } + }, + "BulkUpdateContentType": { + "type": "string", + "description": "", + "x-enumNames": [ + "Upsert", + "ChangeStatus", + "Create", + "Delete", + "Patch", + "Update", + "Validate", + "EnrichDefaults" + ], + "enum": [ + "Upsert", + "ChangeStatus", + "Create", + "Delete", + "Patch", + "Update", + "Validate", + "EnrichDefaults" + ] + }, + "ChangeStatusDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "status" + ], + "properties": { + "status": { + "type": "string", + "description": "The new status." + }, + "dueTime": { + "type": "string", + "description": "The due time.", + "format": "date-time", + "nullable": true + }, + "checkReferrers": { + "type": "boolean", + "description": "True to check referrers of this content." + } + } + }, + "AllContentsByPostDto": { + "type": "object", + "additionalProperties": false, + "properties": { + "ids": { + "type": "array", + "description": "The list of ids to query.", + "nullable": true, + "items": { + "type": "string" + } + }, + "scheduledFrom": { + "type": "string", + "description": "The start time of the scheduled content period (see scheduledTo).", + "format": "date-time", + "nullable": true + }, + "scheduledTo": { + "type": "string", + "description": "The end time of the scheduled content period (see scheduledFrom).", + "format": "date-time", + "nullable": true + }, + "referencing": { + "type": "string", + "description": "The ID of the referencing content item.", + "nullable": true + }, + "references": { + "type": "string", + "description": "The ID of the reference content item.", + "nullable": true + }, + "oData": { + "type": "string", + "description": "The optional odata query.", + "nullable": true + }, + "q": { + "description": "The optional json query.", + "nullable": true + } + } + }, + "BackupJobsDto": { + "allOf": [ + { + "$ref": "#/components/schemas/Resource" + }, + { + "type": "object", + "deprecated": true, + "x-deprecatedMessage": "Use Jobs endpoint.", + "additionalProperties": false, + "required": [ + "items" + ], + "properties": { + "items": { + "type": "array", + "description": "The backups.", + "items": { + "$ref": "#/components/schemas/BackupJobDto" + } + } + } + } + ] + }, + "BackupJobDto": { + "allOf": [ + { + "$ref": "#/components/schemas/Resource" + }, + { + "type": "object", + "deprecated": true, + "x-deprecatedMessage": "Use Jobs endpoint.", + "additionalProperties": false, + "required": [ + "id", + "started", + "handledEvents", + "handledAssets", + "status" + ], + "properties": { + "id": { + "type": "string", + "description": "The ID of the backup job." + }, + "started": { + "type": "string", + "description": "The time when the job has been started.", + "format": "date-time" + }, + "stopped": { + "type": "string", + "description": "The time when the job has been stopped.", + "format": "date-time", + "nullable": true + }, + "handledEvents": { + "type": "integer", + "description": "The number of handled events.", + "format": "int32" + }, + "handledAssets": { + "type": "integer", + "description": "The number of handled assets.", + "format": "int32" + }, + "status": { + "description": "The status of the operation.", + "$ref": "#/components/schemas/JobStatus" + } + } + } + ] + }, + "RestoreJobDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "url", + "log", + "started", + "status" + ], + "properties": { + "url": { + "type": "string", + "description": "The uri to load from.", + "format": "uri" + }, + "log": { + "type": "array", + "description": "The status log.", + "items": { + "type": "string" + } + }, + "started": { + "type": "string", + "description": "The time when the job has been started.", + "format": "date-time" + }, + "stopped": { + "type": "string", + "description": "The time when the job has been stopped.", + "format": "date-time", + "nullable": true + }, + "status": { + "description": "The status of the operation.", + "$ref": "#/components/schemas/JobStatus" + } + } + }, + "RestoreRequestDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "url" + ], + "properties": { + "name": { + "type": "string", + "description": "The name of the app.", + "pattern": "^[a-z0-9]+(\\-[a-z0-9]+)*$", + "nullable": true + }, + "url": { + "type": "string", + "description": "The url to the restore file.", + "format": "uri", + "minLength": 1 + } + } + }, + "ResizeMode": { + "type": "string", + "description": "", + "x-enumNames": [ + "Crop", + "CropUpsize", + "Pad", + "BoxPad", + "Max", + "Min", + "Stretch" + ], + "enum": [ + "Crop", + "CropUpsize", + "Pad", + "BoxPad", + "Max", + "Min", + "Stretch" + ] + }, + "ImageFormat": { + "type": "string", + "description": "", + "x-enumNames": [ + "AVIF", + "BMP", + "GIF", + "JPEG", + "PNG", + "TGA", + "TIFF", + "WEBP" + ], + "enum": [ + "AVIF", + "BMP", + "GIF", + "JPEG", + "PNG", + "TGA", + "TIFF", + "WEBP" + ] + }, + "WatermarkAnchor": { + "type": "string", + "description": "", + "x-enumNames": [ + "TopLeft", + "TopRight", + "BottomLeft", + "BottomRight", + "Center" + ], + "enum": [ + "TopLeft", + "TopRight", + "BottomLeft", + "BottomRight", + "Center" + ] + }, + "AssetFoldersDto": { + "allOf": [ + { + "$ref": "#/components/schemas/Resource" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "total", + "items", + "path" + ], + "properties": { + "total": { + "type": "integer", + "description": "The total number of assets.", + "format": "int64" + }, + "items": { + "type": "array", + "description": "The assets folders.", + "items": { + "$ref": "#/components/schemas/AssetFolderDto" + } + }, + "path": { + "type": "array", + "description": "The path to the current folder.", + "items": { + "$ref": "#/components/schemas/AssetFolderDto" + } + } + } + } + ] + }, + "AssetFolderDto": { + "allOf": [ + { + "$ref": "#/components/schemas/Resource" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "parentId", + "folderName", + "version" + ], + "properties": { + "id": { + "type": "string", + "description": "The ID of the asset." + }, + "parentId": { + "type": "string", + "description": "The ID of the parent folder. Empty for files without parent." + }, + "folderName": { + "type": "string", + "description": "The folder name." + }, + "version": { + "type": "integer", + "description": "The version of the asset folder.", + "format": "int64" + } + } + } + ] + }, + "AssetFolderScope": { + "type": "string", + "description": "", + "x-enumNames": [ + "PathAndItems", + "Path", + "Items" + ], + "enum": [ + "PathAndItems", + "Path", + "Items" + ] + }, + "CreateAssetFolderDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "folderName" + ], + "properties": { + "folderName": { + "type": "string", + "description": "The name of the folder.", + "minLength": 1 + }, + "parentId": { + "type": "string", + "description": "The ID of the parent folder." + } + } + }, + "RenameAssetFolderDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "folderName" + ], + "properties": { + "folderName": { + "type": "string", + "description": "The name of the folder.", + "minLength": 1 + } + } + }, + "MoveAssetFolderDto": { + "type": "object", + "additionalProperties": false, + "properties": { + "parentId": { + "type": "string", + "description": "The parent folder id." + } + } + }, + "RenameTagDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "tagName" + ], + "properties": { + "tagName": { + "type": "string", + "description": "The new name for the tag.", + "minLength": 1 + } + } + }, + "AssetsDto": { + "allOf": [ + { + "$ref": "#/components/schemas/Resource" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "total", + "items" + ], + "properties": { + "total": { + "type": "integer", + "description": "The total number of assets.", + "format": "int64" + }, + "items": { + "type": "array", + "description": "The assets.", + "items": { + "$ref": "#/components/schemas/AssetDto" + } + } + } + } + ] + }, + "AssetDto": { + "allOf": [ + { + "$ref": "#/components/schemas/Resource" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "parentId", + "fileName", + "isProtected", + "slug", + "mimeType", + "fileType", + "metadataText", + "metadata", + "fileSize", + "fileVersion", + "type", + "createdBy", + "lastModifiedBy", + "created", + "lastModified", + "version", + "isImage" + ], + "properties": { + "id": { + "type": "string", + "description": "The ID of the asset." + }, + "parentId": { + "type": "string", + "description": "The ID of the parent folder. Empty for files without parent." + }, + "fileName": { + "type": "string", + "description": "The file name." + }, + "fileHash": { + "type": "string", + "description": "The file hash.", + "nullable": true + }, + "isProtected": { + "type": "boolean", + "description": "True, when the asset is not public." + }, + "slug": { + "type": "string", + "description": "The slug." + }, + "mimeType": { + "type": "string", + "description": "The mime type." + }, + "fileType": { + "type": "string", + "description": "The file type." + }, + "metadataText": { + "type": "string", + "description": "The formatted text representation of the metadata." + }, + "editToken": { + "type": "string", + "description": "The UI token.", + "nullable": true + }, + "metadata": { + "type": "object", + "description": "The asset metadata.", + "additionalProperties": { + "description": "Any" + } + }, + "tags": { + "type": "array", + "description": "The asset tags.", + "nullable": true, + "items": { + "type": "string" + } + }, + "fileSize": { + "type": "integer", + "description": "The size of the file in bytes.", + "format": "int64" + }, + "fileVersion": { + "type": "integer", + "description": "The version of the file.", + "format": "int64" + }, + "type": { + "description": "The type of the asset.", + "$ref": "#/components/schemas/AssetType" + }, + "createdBy": { + "type": "string", + "description": "The user that has created the schema." + }, + "lastModifiedBy": { + "type": "string", + "description": "The user that has updated the asset." + }, + "created": { + "type": "string", + "description": "The date and time when the asset has been created.", + "format": "date-time" + }, + "lastModified": { + "type": "string", + "description": "The date and time when the asset has been modified last.", + "format": "date-time" + }, + "version": { + "type": "integer", + "description": "The version of the asset.", + "format": "int64" + }, + "_meta": { + "description": "The metadata.", + "nullable": true, + "$ref": "#/components/schemas/AssetMeta" + }, + "isImage": { + "type": "boolean", + "description": "Determines of the created file is an image.", + "deprecated": true, + "x-deprecatedMessage": "Use 'type' field now." + }, + "pixelWidth": { + "type": "integer", + "description": "The width of the image in pixels if the asset is an image.", + "format": "int32", + "deprecated": true, + "x-deprecatedMessage": "Use 'metadata' field now.", + "nullable": true + }, + "pixelHeight": { + "type": "integer", + "description": "The height of the image in pixels if the asset is an image.", + "format": "int32", + "deprecated": true, + "x-deprecatedMessage": "Use 'metadata' field now.", + "nullable": true + } + } + } + ] + }, + "AssetMeta": { + "type": "object", + "additionalProperties": false, + "required": [ + "isDuplicate" + ], + "properties": { + "isDuplicate": { + "type": "string", + "description": "Indicates whether the asset is a duplicate." + } + } + }, + "BulkUpdateAssetsDto": { + "type": "object", + "additionalProperties": false, + "properties": { + "jobs": { + "type": "array", + "description": "The contents to update or insert.", + "nullable": true, + "items": { + "$ref": "#/components/schemas/BulkUpdateAssetsJobDto" + } + }, + "checkReferrers": { + "type": "boolean", + "description": "True to check referrers of deleted assets." + }, + "optimizeValidation": { + "type": "boolean", + "description": "True to turn off costly validation: Folder checks. Default: true." + }, + "doNotScript": { + "type": "boolean", + "description": "True to turn off scripting for faster inserts. Default: true." + } + } + }, + "BulkUpdateAssetsJobDto": { + "type": "object", + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "description": "An optional ID of the asset to update." + }, + "type": { + "description": "The update type.", + "$ref": "#/components/schemas/BulkUpdateAssetType" + }, + "parentId": { + "type": "string", + "description": "The parent folder id." + }, + "fileName": { + "type": "string", + "description": "The new name of the asset.", + "nullable": true + }, + "slug": { + "type": "string", + "description": "The new slug of the asset.", + "nullable": true + }, + "isProtected": { + "type": "boolean", + "description": "True, when the asset is not public.", + "nullable": true + }, + "tags": { + "type": "array", + "description": "The new asset tags.", + "nullable": true, + "items": { + "type": "string" + } + }, + "metadata": { + "type": "object", + "description": "The asset metadata.", + "nullable": true, + "additionalProperties": { + "description": "Any" + } + }, + "permanent": { + "type": "boolean", + "description": "True to delete the asset permanently." + }, + "expectedVersion": { + "type": "integer", + "description": "The expected version.", + "format": "int64" + } + } + }, + "BulkUpdateAssetType": { + "type": "string", + "description": "", + "x-enumNames": [ + "Annotate", + "Move", + "Delete" + ], + "enum": [ + "Annotate", + "Move", + "Delete" + ] + }, + "AnnotateAssetDto": { + "type": "object", + "additionalProperties": false, + "properties": { + "fileName": { + "type": "string", + "description": "The new name of the asset.", + "nullable": true + }, + "slug": { + "type": "string", + "description": "The new slug of the asset.", + "nullable": true + }, + "isProtected": { + "type": "boolean", + "description": "True, when the asset is not public.", + "nullable": true + }, + "tags": { + "type": "array", + "description": "The new asset tags.", + "nullable": true, + "items": { + "type": "string" + } + }, + "metadata": { + "type": "object", + "description": "The asset metadata.", + "nullable": true, + "additionalProperties": { + "description": "Any" + } + } + } + }, + "MoveAssetDto": { + "type": "object", + "additionalProperties": false, + "properties": { + "parentId": { + "type": "string", + "description": "The parent folder id." + } + } + }, + "AssetScriptsDto": { + "allOf": [ + { + "$ref": "#/components/schemas/Resource" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "version" + ], + "properties": { + "query": { + "type": "string", + "description": "The script that is executed for each asset when querying assets.", + "nullable": true + }, + "queryPre": { + "type": "string", + "description": "The script that is executed for all assets when querying assets.", + "nullable": true + }, + "create": { + "type": "string", + "description": "The script that is executed when creating an asset.", + "nullable": true + }, + "update": { + "type": "string", + "description": "The script that is executed when updating a content.", + "nullable": true + }, + "annotate": { + "type": "string", + "description": "The script that is executed when annotating a content.", + "nullable": true + }, + "move": { + "type": "string", + "description": "The script that is executed when moving a content.", + "nullable": true + }, + "delete": { + "type": "string", + "description": "The script that is executed when deleting a content.", + "nullable": true + }, + "version": { + "type": "integer", + "description": "The version of the app.", + "format": "int64" + } + } + } + ] + }, + "UpdateAssetScriptsDto": { + "type": "object", + "additionalProperties": false, + "properties": { + "query": { + "type": "string", + "description": "The script that is executed for each asset when querying assets.", + "nullable": true + }, + "queryPre": { + "type": "string", + "description": "The script that is executed for all assets when querying assets.", + "nullable": true + }, + "create": { + "type": "string", + "description": "The script that is executed when creating an asset.", + "nullable": true + }, + "update": { + "type": "string", + "description": "The script that is executed when updating a content.", + "nullable": true + }, + "annotate": { + "type": "string", + "description": "The script that is executed when annotating a content.", + "nullable": true + }, + "move": { + "type": "string", + "description": "The script that is executed when moving a content.", + "nullable": true + }, + "delete": { + "type": "string", + "description": "The script that is executed when deleting a content.", + "nullable": true + } + } + }, + "ClientsDto": { + "allOf": [ + { + "$ref": "#/components/schemas/Resource" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "items" + ], + "properties": { + "items": { + "type": "array", + "description": "The clients.", + "items": { + "$ref": "#/components/schemas/ClientDto" + } + } + } + } + ] + }, + "ClientDto": { + "allOf": [ + { + "$ref": "#/components/schemas/Resource" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "secret", + "name", + "apiCallsLimit", + "apiTrafficLimit", + "allowAnonymous" + ], + "properties": { + "id": { + "type": "string", + "description": "The client id." + }, + "secret": { + "type": "string", + "description": "The client secret." + }, + "name": { + "type": "string", + "description": "The client name." + }, + "role": { + "type": "string", + "description": "The role of the client.", + "nullable": true + }, + "apiCallsLimit": { + "type": "integer", + "description": "The number of allowed api calls per month for this client.", + "format": "int64" + }, + "apiTrafficLimit": { + "type": "integer", + "description": "The number of allowed api traffic bytes per month for this client.", + "format": "int64" + }, + "allowAnonymous": { + "type": "boolean", + "description": "True to allow anonymous access without an access token for this client." + } + } + } + ] + }, + "CreateClientDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "id" + ], + "properties": { + "id": { + "type": "string", + "description": "The ID of the client.", + "minLength": 1, + "pattern": "^[a-z0-9]+(\\-[a-z0-9]+)*$" + } + } + }, + "UpdateClientDto": { + "type": "object", + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "The new display name of the client.", + "maxLength": 20, + "minLength": 0, + "nullable": true + }, + "role": { + "type": "string", + "description": "The role of the client.", + "nullable": true + }, + "allowAnonymous": { + "type": "boolean", + "description": "True to allow anonymous access without an access token for this client.", + "nullable": true + }, + "apiCallsLimit": { + "type": "integer", + "description": "The number of allowed api calls per month for this client.", + "format": "int64", + "nullable": true + }, + "apiTrafficLimit": { + "type": "integer", + "description": "The number of allowed api traffic bytes per month for this client.", + "format": "int64", + "nullable": true + } + } + }, + "AppLanguagesDto": { + "allOf": [ + { + "$ref": "#/components/schemas/Resource" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "items" + ], + "properties": { + "items": { + "type": "array", + "description": "The languages.", + "items": { + "$ref": "#/components/schemas/AppLanguageDto" + } + } + } + } + ] + }, + "AppLanguageDto": { + "allOf": [ + { + "$ref": "#/components/schemas/Resource" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "iso2Code", + "englishName", + "fallback", + "isMaster", + "isOptional" + ], + "properties": { + "iso2Code": { + "type": "string", + "description": "The iso code of the language." + }, + "englishName": { + "type": "string", + "description": "The english name of the language." + }, + "fallback": { + "type": "array", + "description": "The fallback languages.", + "items": { + "type": "string" + } + }, + "isMaster": { + "type": "boolean", + "description": "Indicates if the language is the master language." + }, + "isOptional": { + "type": "boolean", + "description": "Indicates if the language is optional." + } + } + } + ] + }, + "AddLanguageDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "language" + ], + "properties": { + "language": { + "type": "string", + "description": "The language to add." + } + } + }, + "UpdateLanguageDto": { + "type": "object", + "additionalProperties": false, + "properties": { + "isMaster": { + "type": "boolean", + "description": "Set the value to true to make the language the master.", + "nullable": true + }, + "isOptional": { + "type": "boolean", + "description": "Set the value to true to make the language optional." + }, + "fallback": { + "type": "array", + "description": "Optional fallback languages.", + "nullable": true, + "items": { + "type": "string" + } + } + } + }, + "RolesDto": { + "allOf": [ + { + "$ref": "#/components/schemas/Resource" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "items" + ], + "properties": { + "items": { + "type": "array", + "description": "The roles.", + "items": { + "$ref": "#/components/schemas/RoleDto" + } + } + } + } + ] + }, + "RoleDto": { + "allOf": [ + { + "$ref": "#/components/schemas/Resource" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "name", + "numClients", + "numContributors", + "isDefaultRole", + "permissions", + "properties" + ], + "properties": { + "name": { + "type": "string", + "description": "The role name." + }, + "numClients": { + "type": "integer", + "description": "The number of clients with this role.", + "format": "int32" + }, + "numContributors": { + "type": "integer", + "description": "The number of contributors with this role.", + "format": "int32" + }, + "isDefaultRole": { + "type": "boolean", + "description": "Indicates if the role is an builtin default role." + }, + "permissions": { + "type": "array", + "description": "Associated list of permissions.", + "items": { + "type": "string" + } + }, + "properties": { + "type": "object", + "description": "Associated list of UI properties.", + "additionalProperties": { + "description": "Any" + } + } + } + } + ] + }, + "AddRoleDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string", + "description": "The role name.", + "minLength": 1 + } + } + }, + "UpdateRoleDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "permissions" + ], + "properties": { + "permissions": { + "type": "array", + "description": "Associated list of permissions.", + "items": { + "type": "string" + } + }, + "properties": { + "type": "object", + "description": "Associated list of UI properties.", + "additionalProperties": { + "description": "Any" + } + } + } + }, + "AppDto": { + "allOf": [ + { + "$ref": "#/components/schemas/Resource" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "name", + "version", + "created", + "lastModified", + "permissions", + "canAccessApi", + "canAccessContent", + "roleProperties" + ], + "properties": { + "id": { + "type": "string", + "description": "The ID of the app." + }, + "name": { + "type": "string", + "description": "The name of the app.", + "pattern": "^[a-z0-9]+(\\-[a-z0-9]+)*$" + }, + "label": { + "type": "string", + "description": "The optional label of the app.", + "nullable": true + }, + "description": { + "type": "string", + "description": "The optional description of the app.", + "nullable": true + }, + "version": { + "type": "integer", + "description": "The version of the app.", + "format": "int64" + }, + "created": { + "type": "string", + "description": "The timestamp when the app has been created.", + "format": "date-time" + }, + "lastModified": { + "type": "string", + "description": "The timestamp when the app has been modified last.", + "format": "date-time" + }, + "teamId": { + "type": "string", + "description": "The ID of the team.", + "nullable": true + }, + "permissions": { + "type": "array", + "description": "The permission level of the user.", + "items": { + "type": "string" + } + }, + "canAccessApi": { + "type": "boolean", + "description": "Indicates if the user can access the api.", + "deprecated": true, + "x-deprecatedMessage": "Use 'roleProperties' field now." + }, + "canAccessContent": { + "type": "boolean", + "description": "Indicates if the user can access at least one content." + }, + "roleName": { + "type": "string", + "description": "The role name of the user.", + "nullable": true + }, + "roleProperties": { + "type": "object", + "description": "The properties from the role.", + "additionalProperties": { + "description": "Any" + } + } + } + } + ] + }, + "CreateAppDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string", + "description": "The name of the app.", + "minLength": 1, + "pattern": "^[a-z0-9]+(\\-[a-z0-9]+)*$" + }, + "template": { + "type": "string", + "description": "Initialize the app with the inbuilt template.", + "nullable": true + } + } + }, + "UpdateAppDto": { + "type": "object", + "additionalProperties": false, + "properties": { + "label": { + "type": "string", + "description": "The optional label of your app.", + "nullable": true + }, + "description": { + "type": "string", + "description": "The optional description of your app.", + "nullable": true + } + } + }, + "TransferToTeamDto": { + "type": "object", + "additionalProperties": false, + "properties": { + "teamId": { + "type": "string", + "description": "The ID of the team.", + "nullable": true + } + } + }, + "AppSettingsDto": { + "allOf": [ + { + "$ref": "#/components/schemas/Resource" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "patterns", + "editors", + "hideScheduler", + "hideDateTimeModeButton", + "version" + ], + "properties": { + "patterns": { + "type": "array", + "description": "The configured app patterns.", + "items": { + "$ref": "#/components/schemas/PatternDto" + } + }, + "editors": { + "type": "array", + "description": "The configured UI editors.", + "items": { + "$ref": "#/components/schemas/EditorDto" + } + }, + "hideScheduler": { + "type": "boolean", + "description": "Hide the scheduler for content items." + }, + "hideDateTimeModeButton": { + "type": "boolean", + "description": "Hide the datetime mode button." + }, + "version": { + "type": "integer", + "description": "The version of the app.", + "format": "int64" + } + } + } + ] + }, + "PatternDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "name", + "regex" + ], + "properties": { + "name": { + "type": "string", + "description": "The name of the suggestion." + }, + "regex": { + "type": "string", + "description": "The regex pattern." + }, + "message": { + "type": "string", + "description": "The regex message.", + "nullable": true + } + } + }, + "EditorDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "name", + "url" + ], + "properties": { + "name": { + "type": "string", + "description": "The name of the editor." + }, + "url": { + "type": "string", + "description": "The url to the editor." + } + } + }, + "UpdateAppSettingsDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "patterns", + "editors" + ], + "properties": { + "patterns": { + "type": "array", + "description": "The configured app patterns.", + "items": { + "$ref": "#/components/schemas/PatternDto" + } + }, + "editors": { + "type": "array", + "description": "The configured UI editors.", + "items": { + "$ref": "#/components/schemas/EditorDto" + } + }, + "hideScheduler": { + "type": "boolean", + "description": "Hide the scheduler for content items." + }, + "hideDateTimeModeButton": { + "type": "boolean", + "description": "Hide the datetime mode button." + } + } + }, + "WorkflowsDto": { + "allOf": [ + { + "$ref": "#/components/schemas/Resource" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "items", + "errors" + ], + "properties": { + "items": { + "type": "array", + "description": "The workflow.", + "items": { + "$ref": "#/components/schemas/WorkflowDto" + } + }, + "errors": { + "type": "array", + "description": "The errros that should be fixed.", + "items": { + "type": "string" + } + } + } + } + ] + }, + "WorkflowDto": { + "allOf": [ + { + "$ref": "#/components/schemas/Resource" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "steps", + "initial" + ], + "properties": { + "id": { + "type": "string", + "description": "The workflow id." + }, + "name": { + "type": "string", + "description": "The name of the workflow.", + "nullable": true + }, + "steps": { + "type": "object", + "description": "The workflow steps.", + "additionalProperties": { + "$ref": "#/components/schemas/WorkflowStepDto" + } + }, + "schemaIds": { + "type": "array", + "description": "The schema ids.", + "nullable": true, + "items": { + "type": "string" + } + }, + "initial": { + "type": "string", + "description": "The initial step." + } + } + } + ] + }, + "WorkflowStepDto": { + "type": "object", + "additionalProperties": false, + "properties": { + "transitions": { + "type": "object", + "description": "The transitions.", + "additionalProperties": { + "$ref": "#/components/schemas/WorkflowTransitionDto" + } + }, + "color": { + "type": "string", + "description": "The optional color.", + "nullable": true + }, + "validate": { + "type": "boolean", + "description": "True if the content should be validated when moving to this step." + }, + "noUpdate": { + "type": "boolean", + "description": "Indicates if updates should not be allowed." + }, + "noUpdateExpression": { + "type": "string", + "description": "Optional expression that must evaluate to true when you want to prevent updates.", + "nullable": true + }, + "noUpdateRoles": { + "type": "array", + "description": "Optional list of roles to restrict the updates for users with these roles.", + "nullable": true, + "items": { + "type": "string" + } + } + } + }, + "WorkflowTransitionDto": { + "type": "object", + "additionalProperties": false, + "properties": { + "expression": { + "type": "string", + "description": "The optional expression.", + "nullable": true + }, + "roles": { + "type": "array", + "description": "The optional restricted role.", + "nullable": true, + "items": { + "type": "string" + } + } + } + }, + "AddWorkflowDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string", + "description": "The name of the workflow.", + "minLength": 1 + } + } + }, + "UpdateWorkflowDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "steps", + "initial" + ], + "properties": { + "name": { + "type": "string", + "description": "The name of the workflow.", + "nullable": true + }, + "steps": { + "type": "object", + "description": "The workflow steps.", + "additionalProperties": { + "$ref": "#/components/schemas/WorkflowStepDto" + } + }, + "schemaIds": { + "type": "array", + "description": "The schema ids.", + "nullable": true, + "items": { + "type": "string" + } + }, + "initial": { + "type": "string", + "description": "The initial step." + } + } + }, + "EnrichedEventDto": { + "type": "object", + "discriminator": { + "propertyName": "$type", + "mapping": { + "EnrichedAssetEvent": "#/components/schemas/EnrichedAssetEventDto", + "EnrichedCommentEvent": "#/components/schemas/EnrichedCommentEventDto", + "EnrichedContentEvent": "#/components/schemas/EnrichedContentEventDto", + "EnrichedCronJobEvent": "#/components/schemas/EnrichedCronJobEventDto", + "EnrichedManualEvent": "#/components/schemas/EnrichedManualEventDto", + "EnrichedSchemaEvent": "#/components/schemas/EnrichedSchemaEventDto", + "EnrichedUsageExceededEvent": "#/components/schemas/EnrichedUsageExceededEventDto" + } + }, + "x-abstract": true, + "additionalProperties": false, + "required": [ + "$type", + "appId", + "timestamp", + "name", + "version", + "partition" + ], + "properties": { + "appId": { + "type": "string" + }, + "timestamp": { + "type": "string", + "format": "date-time" + }, + "name": { + "type": "string" + }, + "version": { + "type": "integer", + "format": "int64" + }, + "partition": { + "type": "integer", + "format": "int64" + }, + "$type": { + "type": "string" + } + } + }, + "EnrichedAssetEventDto": { + "allOf": [ + { + "$ref": "#/components/schemas/EnrichedUserEventBaseEventDto" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "id", + "created", + "lastModified", + "createdBy", + "lastModifiedBy", + "parentId", + "mimeType", + "fileName", + "fileHash", + "slug", + "fileVersion", + "fileSize", + "isProtected", + "assetType", + "metadata", + "isImage", + "partition" + ], + "properties": { + "type": { + "$ref": "#/components/schemas/EnrichedAssetEventType" + }, + "id": { + "type": "string" + }, + "created": { + "type": "string", + "format": "date-time" + }, + "lastModified": { + "type": "string", + "format": "date-time" + }, + "createdBy": { + "type": "string" + }, + "lastModifiedBy": { + "type": "string" + }, + "parentId": { + "type": "string" + }, + "mimeType": { + "type": "string" + }, + "fileName": { + "type": "string" + }, + "fileHash": { + "type": "string" + }, + "slug": { + "type": "string" + }, + "fileVersion": { + "type": "integer", + "format": "int64" + }, + "fileSize": { + "type": "integer", + "format": "int64" + }, + "isProtected": { + "type": "boolean" + }, + "pixelWidth": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "pixelHeight": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "assetType": { + "$ref": "#/components/schemas/AssetType" + }, + "metadata": { + "type": "object", + "additionalProperties": { + "description": "Any" + } + }, + "isImage": { + "type": "boolean" + }, + "partition": { + "type": "integer", + "format": "int64" + } + } + } + ] + }, + "EnrichedAssetEventType": { + "type": "string", + "description": "", + "x-enumNames": [ + "Created", + "Deleted", + "Annotated", + "Updated" + ], + "enum": [ + "Created", + "Deleted", + "Annotated", + "Updated" + ] + }, + "EnrichedUserEventBaseEventDto": { + "allOf": [ + { + "$ref": "#/components/schemas/EnrichedEventDto" + }, + { + "type": "object", + "x-abstract": true, + "additionalProperties": false, + "required": [ + "actor" + ], + "properties": { + "actor": { + "type": "string" + } + } + } + ] + }, + "EnrichedCommentEventDto": { + "allOf": [ + { + "$ref": "#/components/schemas/EnrichedUserEventBaseEventDto" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "text" + ], + "properties": { + "text": { + "type": "string" + }, + "url": { + "type": "string", + "format": "uri", + "nullable": true + } + } + } + ] + }, + "EnrichedContentEventDto": { + "allOf": [ + { + "$ref": "#/components/schemas/EnrichedSchemaEventBaseEventDto" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "id", + "created", + "lastModified", + "createdBy", + "lastModifiedBy", + "data", + "status", + "partition" + ], + "properties": { + "type": { + "$ref": "#/components/schemas/EnrichedContentEventType" + }, + "id": { + "type": "string" + }, + "created": { + "type": "string", + "format": "date-time" + }, + "lastModified": { + "type": "string", + "format": "date-time" + }, + "createdBy": { + "type": "string" + }, + "lastModifiedBy": { + "type": "string" + }, + "data": { + "$ref": "#/components/schemas/ContentData" + }, + "dataOld": { + "nullable": true, + "$ref": "#/components/schemas/ContentData" + }, + "status": { + "type": "string" + }, + "newStatus": { + "type": "string", + "nullable": true + }, + "partition": { + "type": "integer", + "format": "int64" + } + } + } + ] + }, + "EnrichedContentEventType": { + "type": "string", + "description": "", + "x-enumNames": [ + "Created", + "Deleted", + "Published", + "StatusChanged", + "Updated", + "Unpublished", + "ReferenceUpdated" + ], + "enum": [ + "Created", + "Deleted", + "Published", + "StatusChanged", + "Updated", + "Unpublished", + "ReferenceUpdated" + ] + }, + "EnrichedSchemaEventBaseEventDto": { + "allOf": [ + { + "$ref": "#/components/schemas/EnrichedUserEventBaseEventDto" + }, + { + "type": "object", + "x-abstract": true, + "additionalProperties": false, + "required": [ + "schemaId" + ], + "properties": { + "schemaId": { + "type": "string" + } + } + } + ] + }, + "EnrichedCronJobEventDto": { + "allOf": [ + { + "$ref": "#/components/schemas/EnrichedUserEventBaseEventDto" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "value", + "partition" + ], + "properties": { + "value": {}, + "partition": { + "type": "integer", + "format": "int64" + } + } + } + ] + }, + "EnrichedManualEventDto": { + "allOf": [ + { + "$ref": "#/components/schemas/EnrichedUserEventBaseEventDto" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "value", + "partition" + ], + "properties": { + "value": {}, + "partition": { + "type": "integer", + "format": "int64" + } + } + } + ] + }, + "EnrichedSchemaEventDto": { + "allOf": [ + { + "$ref": "#/components/schemas/EnrichedSchemaEventBaseEventDto" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "id", + "partition" + ], + "properties": { + "type": { + "$ref": "#/components/schemas/EnrichedSchemaEventType" + }, + "id": { + "type": "string" + }, + "partition": { + "type": "integer", + "format": "int64" + } + } + } + ] + }, + "EnrichedSchemaEventType": { + "type": "string", + "description": "", + "x-enumNames": [ + "Created", + "Deleted", + "Published", + "Unpublished", + "Updated" + ], + "enum": [ + "Created", + "Deleted", + "Published", + "Unpublished", + "Updated" + ] + }, + "EnrichedUsageExceededEventDto": { + "allOf": [ + { + "$ref": "#/components/schemas/EnrichedEventDto" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "callsCurrent", + "callsLimit", + "partition" + ], + "properties": { + "callsCurrent": { + "type": "integer", + "format": "int64" + }, + "callsLimit": { + "type": "integer", + "format": "int64" + }, + "partition": { + "type": "integer", + "format": "int64" + } + } + } + ] + }, + "DynamicCreateRuleDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "trigger", + "flow" + ], + "properties": { + "name": { + "type": "string", + "description": "Optional rule name.", + "nullable": true + }, + "trigger": { + "description": "The trigger properties.", + "$ref": "#/components/schemas/RuleTriggerDto" + }, + "action": { + "type": "object", + "description": "The action properties.", + "deprecated": true, + "x-deprecatedMessage": "Use the new 'Flow' property to define actions", + "nullable": true, + "additionalProperties": {} + }, + "flow": { + "description": "The flow to describe the sequence of actions to perform.", + "$ref": "#/components/schemas/DynamicFlowDefinitionDto" + }, + "isEnabled": { + "type": "boolean", + "description": "Enable or disable the rule.", + "nullable": true + } + } + }, + "DynamicFlowDefinitionDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "initialStepId", + "steps" + ], + "properties": { + "initialStepId": { + "type": "string", + "description": "The ID of the initial step.", + "format": "guid", + "minLength": 1 + }, + "steps": { + "type": "object", + "description": "The steps.", + "additionalProperties": { + "$ref": "#/components/schemas/DynamicFlowStepDefinitionDto" + } + } + } + }, + "DynamicFlowStepDefinitionDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "step" + ], + "properties": { + "step": { + "type": "object", + "description": "The actual step.", + "additionalProperties": {} + }, + "name": { + "type": "string", + "description": "The optional descriptive name.", + "nullable": true + }, + "nextStepId": { + "type": "string", + "description": "The next step.", + "format": "guid", + "nullable": true + }, + "ignoreError": { + "type": "boolean", + "description": "Indicates if errors should be ignored." + } + } + }, + "DynamicFlowExecutionStateDto": { + "type": "object", + "additionalProperties": false, + "required": [ + "definition", + "context", + "steps", + "nextStepId", + "created", + "completed", + "status" + ], + "properties": { + "definition": { + "description": "The actual definition of the the steps to be executed.", + "$ref": "#/components/schemas/DynamicFlowDefinitionDto" + }, + "context": { + "description": "The context." + }, + "steps": { + "type": "object", + "description": "The state of each step.", + "additionalProperties": { + "$ref": "#/components/schemas/FlowExecutionStepStateDto" + } + }, + "nextStepId": { + "type": "string", + "description": "The next step to be executed.", + "format": "guid" + }, + "nextRun": { + "type": "string", + "description": "THe time when the next step will be executed.", + "format": "date-time", + "nullable": true + }, + "created": { + "type": "string", + "description": "The creation time.", + "format": "date-time" + }, + "completed": { + "type": "string", + "description": "The completion time.", + "format": "date-time" + }, + "status": { + "description": "The overall status.", + "$ref": "#/components/schemas/FlowExecutionStatus" + } + } + }, + "DynamicRulesDto": { + "allOf": [ + { + "$ref": "#/components/schemas/Resource" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "items" + ], + "properties": { + "items": { + "type": "array", + "description": "The rules.", + "items": { + "$ref": "#/components/schemas/DynamicRuleDto" + } + }, + "runningRuleId": { + "type": "string", + "description": "The ID of the rule that is currently rerunning.", + "nullable": true + } + } + } + ] + }, + "DynamicRuleDto": { + "allOf": [ + { + "$ref": "#/components/schemas/Resource" + }, + { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "createdBy", + "lastModifiedBy", + "created", + "lastModified", + "version", + "isEnabled", + "trigger", + "flow", + "action", + "numSucceeded", + "numFailed" + ], + "properties": { + "id": { + "type": "string", + "description": "The ID of the rule." + }, + "createdBy": { + "type": "string", + "description": "The user that has created the rule." + }, + "lastModifiedBy": { + "type": "string", + "description": "The user that has updated the rule." + }, + "created": { + "type": "string", + "description": "The date and time when the rule has been created.", + "format": "date-time" + }, + "lastModified": { + "type": "string", + "description": "The date and time when the rule has been modified last.", + "format": "date-time" + }, + "version": { + "type": "integer", + "description": "The version of the rule.", + "format": "int64" + }, + "isEnabled": { + "type": "boolean", + "description": "Determines if the rule is enabled." + }, + "name": { + "type": "string", + "description": "Optional rule name.", + "nullable": true + }, + "trigger": { + "description": "The trigger properties.", + "$ref": "#/components/schemas/RuleTriggerDto" + }, + "flow": { + "description": "The flow to describe the sequence of actions to perform.", + "$ref": "#/components/schemas/DynamicFlowDefinitionDto" + }, + "action": { + "type": "object", + "description": "The action properties.", + "deprecated": true, + "x-deprecatedMessage": "Use the new 'Flow' property to define actions. Can be null if the flow cannot be converted.", + "additionalProperties": {} + }, + "numSucceeded": { + "type": "integer", + "description": "The number of completed executions.", + "format": "int64" + }, + "numFailed": { + "type": "integer", + "description": "The number of failed executions.", + "format": "int64" + }, + "lastExecuted": { + "type": "string", + "description": "The date and time when the rule was executed the last time.", + "format": "date-time", + "deprecated": true, + "x-deprecatedMessage": "Removed when migrated to new rule statistics.", + "nullable": true + } + } + } + ] + }, + "DynamicUpdateRuleDto": { + "type": "object", + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "description": "Optional rule name.", + "nullable": true + }, + "trigger": { + "description": "The trigger properties.", + "nullable": true, + "$ref": "#/components/schemas/RuleTriggerDto" + }, + "action": { + "type": "object", + "description": "The action properties.", + "deprecated": true, + "x-deprecatedMessage": "Use the new 'Flow' property to define actions", + "nullable": true, + "additionalProperties": {} + }, + "flow": { + "description": "The flow to describe the sequence of actions to perform.", + "nullable": true, + "$ref": "#/components/schemas/DynamicFlowDefinitionDto" + }, + "isEnabled": { + "type": "boolean", + "description": "Enable or disable the rule.", + "nullable": true + } + } + } + }, + "securitySchemes": { + "squidex-oauth-auth": { + "type": "openIdConnect", + "description": "Squidex uses OpenId Connect (OIDC) with the Client Credentials Flow (defined in OAuth 2.0 RFC 6749, section 4.4).\r\n\r\nThe OpenId Connect Client Credentials flow can be used for machine to machine authentication. In this grant a specific user is not authorized but rather the credentials are verified and a generic `access_token` is returned.\r\n\r\nThe `access_token` is a signed JSON Web Token (JWT) which contains expiry information. \r\n\r\nTo retrieve an access token you must pass the Client ID and Client Secret to the token endpoint to authenticate yourself and get a token:\r\n\r\n $ curl\r\n -X POST 'https://localhost:5001/identity-server/connect/token' \r\n -H 'Content-Type: application/x-www-form-urlencoded' \r\n -d 'grant_type=client_credentials&\r\n client_id=[CLIENT_ID]&\r\n client_secret=[CLIENT_SECRET]&\r\n\t\t\tscope=squidex-api'\r\n\r\nPass this token to all consecutiv requests to the API via the `Authorization` header:\r\n\r\n Authorization: Bearer ", + "openIdConnectUrl": "https://localhost:5001/identity-server/.well-known/openid-configuration" + } + } + }, + "security": [ + { + "squidex-oauth-auth": [ + "squidex-api" + ] + } + ], + "externalDocs": { + "url": "https://docs.squidex.io" + } +} \ No newline at end of file diff --git a/frontend/src/app/features/content/pages/content/editor/content-editor.component.html b/frontend/src/app/features/content/pages/content/editor/content-editor.component.html index 1c5a5a947..1e0ee0492 100644 --- a/frontend/src/app/features/content/pages/content/editor/content-editor.component.html +++ b/frontend/src/app/features/content/pages/content/editor/content-editor.component.html @@ -12,11 +12,11 @@ @if (isDeleted) { -
+
} @if (!isDeleted) { -
+
} } diff --git a/frontend/src/app/features/content/shared/forms/assets-editor.component.html b/frontend/src/app/features/content/shared/forms/assets-editor.component.html index 9f3b7893b..3c33f21e0 100644 --- a/frontend/src/app/features/content/shared/forms/assets-editor.component.html +++ b/frontend/src/app/features/content/shared/forms/assets-editor.component.html @@ -1,7 +1,7 @@ -
+
@@ -11,7 +11,7 @@
-
diff --git a/frontend/src/app/features/content/shared/forms/assets-editor.component.scss b/frontend/src/app/features/content/shared/forms/assets-editor.component.scss index 7f3d5fc26..b6684668b 100644 --- a/frontend/src/app/features/content/shared/forms/assets-editor.component.scss +++ b/frontend/src/app/features/content/shared/forms/assets-editor.component.scss @@ -31,6 +31,10 @@ pointer-events: none; } +.header { + margin-bottom: -.25rem; +} + .list-view { margin-bottom: 1rem; } diff --git a/frontend/src/app/features/content/shared/forms/component-section.component.html b/frontend/src/app/features/content/shared/forms/component-section.component.html index ab726b772..98706f09c 100644 --- a/frontend/src/app/features/content/shared/forms/component-section.component.html +++ b/frontend/src/app/features/content/shared/forms/component-section.component.html @@ -4,7 +4,7 @@

{{ separator!.displayName }}

@if (separator.properties.hints && separator.properties.hints.length > 0) { - + }
} @@ -24,8 +24,8 @@ [formModel]="child" [hasChatBot]="hasChatBot" [index]="index" - [isComparing]="isComparing" [isCollapsed]="false" + [isComparing]="isComparing" [language]="language" [languages]="languages" /> } diff --git a/frontend/src/app/features/content/shared/forms/content-section.component.html b/frontend/src/app/features/content/shared/forms/content-section.component.html index 453421d4a..b8de8b5cf 100644 --- a/frontend/src/app/features/content/shared/forms/content-section.component.html +++ b/frontend/src/app/features/content/shared/forms/content-section.component.html @@ -13,7 +13,7 @@ @if (separator.properties.hints && separator.properties.hints.length > 0) { - + }
diff --git a/frontend/src/app/features/content/shared/forms/field-editor.component.html b/frontend/src/app/features/content/shared/forms/field-editor.component.html index dd2d4eb36..b9baf60ad 100644 --- a/frontend/src/app/features/content/shared/forms/field-editor.component.html +++ b/frontend/src/app/features/content/shared/forms/field-editor.component.html @@ -354,12 +354,16 @@ @case ("UI") {

{{ field.displayName }}

} + + @case ("UserInfo") { + + } } }
@if (field.properties.hints && field.properties.hints.length > 0) { - + } } diff --git a/frontend/src/app/features/content/shared/forms/field-editor.component.ts b/frontend/src/app/features/content/shared/forms/field-editor.component.ts index 06eb50f19..99f2d8bb4 100644 --- a/frontend/src/app/features/content/shared/forms/field-editor.component.ts +++ b/frontend/src/app/features/content/shared/forms/field-editor.component.ts @@ -20,6 +20,7 @@ import { AssetsEditorComponent } from './assets-editor.component'; import { ComponentComponent } from './component.component'; import { IFrameEditorComponent } from './iframe-editor.component'; import { StockPhotoEditorComponent } from './stock-photo-editor.component'; +import { UserInfoEditorComponent } from './user-info-editor.component'; @Component({ selector: 'sqx-field-editor', @@ -42,9 +43,9 @@ import { StockPhotoEditorComponent } from './stock-photo-editor.component'; IFrameEditorComponent, IndeterminateValueDirective, MarkdownDirective, - ModalDirective, MenuComponent, MenuItemComponent, + ModalDirective, RadioGroupComponent, ReactiveFormsModule, ReferenceDropdownComponent, @@ -59,6 +60,7 @@ import { StockPhotoEditorComponent } from './stock-photo-editor.component'; TagEditorComponent, ToggleComponent, TransformInputDirective, + UserInfoEditorComponent, ], }) export class FieldEditorComponent { diff --git a/frontend/src/app/features/content/shared/forms/user-info-editor.component.html b/frontend/src/app/features/content/shared/forms/user-info-editor.component.html new file mode 100644 index 000000000..f65359112 --- /dev/null +++ b/frontend/src/app/features/content/shared/forms/user-info-editor.component.html @@ -0,0 +1,31 @@ +
+ +
+ + +
+
+ + + + + + + + +
Authorization: ApiKey {{ rolesState.appName }}:{{ apiKey | async }}
+
+ + {{ 'common.or' | sqxTranslate }} + + +
ApiKey: {{ rolesState.appName }}:{{ apiKey | async }}
+
+
+
diff --git a/frontend/src/app/features/content/shared/forms/user-info-editor.component.scss b/frontend/src/app/features/content/shared/forms/user-info-editor.component.scss new file mode 100644 index 000000000..62d8b41a2 --- /dev/null +++ b/frontend/src/app/features/content/shared/forms/user-info-editor.component.scss @@ -0,0 +1,24 @@ +@import 'mixins'; +@import 'vars'; + +.form { + border: 1px solid $color-border; + border-radius: $border-radius; + padding: 1.5rem; +} + +.form-group { + position: relative; +} + +.key { + padding-right: 6rem; +} + +.key-generate { + @include absolute(auto, 10px, 3px, auto); + + &:focus { + box-shadow: none; + } +} \ No newline at end of file diff --git a/frontend/src/app/features/content/shared/forms/user-info-editor.component.ts b/frontend/src/app/features/content/shared/forms/user-info-editor.component.ts new file mode 100644 index 000000000..fe958d84d --- /dev/null +++ b/frontend/src/app/features/content/shared/forms/user-info-editor.component.ts @@ -0,0 +1,97 @@ +/* + * Squidex Headless CMS + * + * @license + * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. + */ + +import { AsyncPipe } from '@angular/common'; +import { booleanAttribute, ChangeDetectionStrategy, Component, forwardRef, Input, OnInit } from '@angular/core'; +import { FormsModule, NG_VALUE_ACCESSOR, ReactiveFormsModule, UntypedFormControl, Validators } from '@angular/forms'; +import { map } from 'rxjs'; +import { CodeComponent, ExtendedFormGroup, FormHintComponent, FormRowComponent, generateApiKey, MarkdownDirective, RolesState, StatefulControlComponent, Subscriptions, TranslatePipe, Types, value$ } from '@app/shared'; + +export const SQX_USER_INFO_EDITOR_CONTROL_VALUE_ACCESSOR: any = { + provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => UserInfoEditorComponent), multi: true, +}; + +type UserInfo = { apiKey: string; role: string }; + +@Component({ + selector: 'sqx-user-info-editor', + styleUrls: ['./user-info-editor.component.scss'], + templateUrl: './user-info-editor.component.html', + providers: [ + SQX_USER_INFO_EDITOR_CONTROL_VALUE_ACCESSOR, + ], + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [ + AsyncPipe, + CodeComponent, + FormsModule, + FormHintComponent, + MarkdownDirective, + ReactiveFormsModule, + FormRowComponent, + TranslatePipe, + ], +}) +export class UserInfoEditorComponent extends StatefulControlComponent implements OnInit { + private readonly subscriptions = new Subscriptions(); + + @Input({ required: true }) + public formId!: string; + + @Input({ transform: booleanAttribute }) + public set disabled(value: boolean | undefined | null) { + this.setDisabledState(value === true); + } + + public readonly form = new ExtendedFormGroup({ + apiKey: new UntypedFormControl('', + Validators.required, + ), + role: new UntypedFormControl('', + Validators.required, + ), + }); + + public readonly apiKey = + value$(this.form.get('apiKey')!) + .pipe(map(x => x || 'NONE')); + + constructor( + public readonly rolesState: RolesState, + ) { + super({}); + + this.subscriptions.add( + value$(this.form).subscribe(value => { + if (this.form.valid) { + this.callChange(value); + } else { + this.callChange(null); + } + + this.callTouched(); + })); + } + + public ngOnInit() { + this.rolesState.loadIfNotLoaded(); + } + + public writeValue(obj: UserInfo | undefined | null) { + if (Types.isObject(obj)) { + this.form.setValue(obj, { emitEvent: true }); + } else { + this.form.reset(); + } + } + + public async generateApiKey() { + const apiKey = generateApiKey(); + + this.form.patchValue({ apiKey }); + } +} \ No newline at end of file diff --git a/frontend/src/app/features/rules/pages/rule/step-dialog.component.html b/frontend/src/app/features/rules/pages/rule/step-dialog.component.html index 8de2aab03..d9e53c103 100644 --- a/frontend/src/app/features/rules/pages/rule/step-dialog.component.html +++ b/frontend/src/app/features/rules/pages/rule/step-dialog.component.html @@ -85,7 +85,7 @@ } } - + @if (property.isFormattable) {
{{ "rules.advancedFormattingHint" | sqxTranslate }}: diff --git a/frontend/src/app/features/schemas/pages/schema/fields/forms/field-form-ui.component.html b/frontend/src/app/features/schemas/pages/schema/fields/forms/field-form-ui.component.html index 3703c21fc..2f48b85f9 100644 --- a/frontend/src/app/features/schemas/pages/schema/fields/forms/field-form-ui.component.html +++ b/frontend/src/app/features/schemas/pages/schema/fields/forms/field-form-ui.component.html @@ -56,6 +56,10 @@ @case ("Tags") { } + + @case ("UserInfo") { + + } }
diff --git a/frontend/src/app/features/schemas/pages/schema/fields/forms/field-form-ui.component.ts b/frontend/src/app/features/schemas/pages/schema/fields/forms/field-form-ui.component.ts index 47ffed079..4eb324952 100644 --- a/frontend/src/app/features/schemas/pages/schema/fields/forms/field-form-ui.component.ts +++ b/frontend/src/app/features/schemas/pages/schema/fields/forms/field-form-ui.component.ts @@ -22,6 +22,7 @@ import { ReferencesUIComponent } from '../types/references-ui.component'; import { RichTextUIComponent } from '../types/rich-text-ui.component'; import { StringUIComponent } from '../types/string-ui.component'; import { TagsUIComponent } from '../types/tags-ui.component'; +import { UserInfoUIComponent } from '../types/user-info-ui.component'; @Component({ selector: 'sqx-field-form-ui', @@ -44,6 +45,7 @@ import { TagsUIComponent } from '../types/tags-ui.component'; ReferencesUIComponent, StringUIComponent, TagsUIComponent, + UserInfoUIComponent, ], }) export class FieldFormUIComponent { diff --git a/frontend/src/app/features/schemas/pages/schema/fields/forms/field-form-validation.component.html b/frontend/src/app/features/schemas/pages/schema/fields/forms/field-form-validation.component.html index 5eeb11c04..c78220453 100644 --- a/frontend/src/app/features/schemas/pages/schema/fields/forms/field-form-validation.component.html +++ b/frontend/src/app/features/schemas/pages/schema/fields/forms/field-form-validation.component.html @@ -1,4 +1,4 @@ -
+
@@ -102,4 +102,8 @@ [languages]="languages" [properties]="field.rawProperties" /> } + + @case ("UserInfo") { + + } } diff --git a/frontend/src/app/features/schemas/pages/schema/fields/forms/field-form-validation.component.ts b/frontend/src/app/features/schemas/pages/schema/fields/forms/field-form-validation.component.ts index 717b98e37..6fb002d8e 100644 --- a/frontend/src/app/features/schemas/pages/schema/fields/forms/field-form-validation.component.ts +++ b/frontend/src/app/features/schemas/pages/schema/fields/forms/field-form-validation.component.ts @@ -22,6 +22,7 @@ import { ReferencesValidationComponent } from '../types/references-validation.co import { RichTextValidationComponent } from '../types/rich-text-validation.component'; import { StringValidationComponent } from '../types/string-validation.component'; import { TagsValidationComponent } from '../types/tags-validation.component'; +import { UserInfoValidationComponent } from '../types/user-info-validation.component'; @Component({ selector: 'sqx-field-form-validation', @@ -44,6 +45,7 @@ import { TagsValidationComponent } from '../types/tags-validation.component'; RichTextValidationComponent, StringValidationComponent, TagsValidationComponent, + UserInfoValidationComponent, ], }) export class FieldFormValidationComponent { diff --git a/frontend/src/app/features/schemas/pages/schema/fields/types/user-info-ui.component.html b/frontend/src/app/features/schemas/pages/schema/fields/types/user-info-ui.component.html new file mode 100644 index 000000000..e69de29bb diff --git a/frontend/src/app/features/schemas/pages/schema/fields/types/user-info-ui.component.scss b/frontend/src/app/features/schemas/pages/schema/fields/types/user-info-ui.component.scss new file mode 100644 index 000000000..2742d895e --- /dev/null +++ b/frontend/src/app/features/schemas/pages/schema/fields/types/user-info-ui.component.scss @@ -0,0 +1,2 @@ +@import 'mixins'; +@import 'vars'; \ No newline at end of file diff --git a/frontend/src/app/features/schemas/pages/schema/fields/types/user-info-ui.component.ts b/frontend/src/app/features/schemas/pages/schema/fields/types/user-info-ui.component.ts new file mode 100644 index 000000000..bdaa075cc --- /dev/null +++ b/frontend/src/app/features/schemas/pages/schema/fields/types/user-info-ui.component.ts @@ -0,0 +1,26 @@ +/* + * Squidex Headless CMS + * + * @license + * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. + */ + +import { Component, Input } from '@angular/core'; +import { UntypedFormGroup } from '@angular/forms'; +import { FieldDto, UserInfoFieldPropertiesDto } from '@app/shared'; + +@Component({ + selector: 'sqx-user-info-ui', + styleUrls: ['user-info-ui.component.scss'], + templateUrl: 'user-info-ui.component.html', +}) +export class UserInfoUIComponent { + @Input({ required: true }) + public fieldForm!: UntypedFormGroup; + + @Input({ required: true }) + public field!: FieldDto; + + @Input({ required: true }) + public properties!: UserInfoFieldPropertiesDto; +} diff --git a/frontend/src/app/features/schemas/pages/schema/fields/types/user-info-validation.component.html b/frontend/src/app/features/schemas/pages/schema/fields/types/user-info-validation.component.html new file mode 100644 index 000000000..944b40cf4 --- /dev/null +++ b/frontend/src/app/features/schemas/pages/schema/fields/types/user-info-validation.component.html @@ -0,0 +1,14 @@ +
+ + + +
diff --git a/frontend/src/app/features/schemas/pages/schema/fields/types/user-info-validation.component.scss b/frontend/src/app/features/schemas/pages/schema/fields/types/user-info-validation.component.scss new file mode 100644 index 000000000..2742d895e --- /dev/null +++ b/frontend/src/app/features/schemas/pages/schema/fields/types/user-info-validation.component.scss @@ -0,0 +1,2 @@ +@import 'mixins'; +@import 'vars'; \ No newline at end of file diff --git a/frontend/src/app/features/schemas/pages/schema/fields/types/user-info-validation.component.ts b/frontend/src/app/features/schemas/pages/schema/fields/types/user-info-validation.component.ts new file mode 100644 index 000000000..2df7b11b8 --- /dev/null +++ b/frontend/src/app/features/schemas/pages/schema/fields/types/user-info-validation.component.ts @@ -0,0 +1,42 @@ +/* + * Squidex Headless CMS + * + * @license + * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. + */ + +import { AsyncPipe } from '@angular/common'; +import { Component, Input, OnInit } from '@angular/core'; +import { FormsModule, ReactiveFormsModule, UntypedFormGroup } from '@angular/forms'; +import { FieldDto, FormRowComponent, RolesState, UserInfoFieldPropertiesDto } from '@app/shared'; + +@Component({ + selector: 'sqx-user-info-validation', + styleUrls: ['user-info-validation.component.scss'], + templateUrl: 'user-info-validation.component.html', + imports: [ + AsyncPipe, + FormRowComponent, + FormsModule, + ReactiveFormsModule, + ], +}) +export class UserInfoValidationComponent implements OnInit { + @Input({ required: true }) + public fieldForm!: UntypedFormGroup; + + @Input({ required: true }) + public field!: FieldDto; + + @Input({ required: true }) + public properties!: UserInfoFieldPropertiesDto; + + constructor( + public readonly rolesState: RolesState, + ) { + } + + public ngOnInit() { + this.rolesState.loadIfNotLoaded(); + } +} diff --git a/frontend/src/app/features/schemas/pages/schema/indexes/index-form.component.html b/frontend/src/app/features/schemas/pages/schema/indexes/index-form.component.html index a086dca59..45e050dc2 100644 --- a/frontend/src/app/features/schemas/pages/schema/indexes/index-form.component.html +++ b/frontend/src/app/features/schemas/pages/schema/indexes/index-form.component.html @@ -3,7 +3,7 @@ {{ "schemas.indexes.addTitle" | sqxTranslate }} - + @for (form of createForm.controls; track form; let i = $index) {
diff --git a/frontend/src/app/features/settings/pages/clients/client-connect-form.component.html b/frontend/src/app/features/settings/pages/clients/client-connect-form.component.html index 44f7a8091..363e549ad 100644 --- a/frontend/src/app/features/settings/pages/clients/client-connect-form.component.html +++ b/frontend/src/app/features/settings/pages/clients/client-connect-form.component.html @@ -25,7 +25,7 @@ @case ("Start") {

{{ "clients.connectWizard.step1Title" | sqxTranslate }}

- +
diff --git a/frontend/src/app/framework/angular/forms/form-row.component.html b/frontend/src/app/framework/angular/forms/form-row.component.html index c78650c97..5258dede3 100644 --- a/frontend/src/app/framework/angular/forms/form-row.component.html +++ b/frontend/src/app/framework/angular/forms/form-row.component.html @@ -12,7 +12,7 @@ } -
+
@@ -33,7 +33,7 @@
@if (hint) { - + } @if (alert) { diff --git a/frontend/src/app/framework/angular/modals/tour-template.component.html b/frontend/src/app/framework/angular/modals/tour-template.component.html index 5f726f63b..b77773549 100644 --- a/frontend/src/app/framework/angular/modals/tour-template.component.html +++ b/frontend/src/app/framework/angular/modals/tour-template.component.html @@ -17,9 +17,9 @@
-
+
-
+
diff --git a/frontend/src/app/shared/components/assets/asset-dialog.component.scss b/frontend/src/app/shared/components/assets/asset-dialog.component.scss index 797bfbb4f..b6e7cc94d 100644 --- a/frontend/src/app/shared/components/assets/asset-dialog.component.scss +++ b/frontend/src/app/shared/components/assets/asset-dialog.component.scss @@ -1,10 +1,6 @@ @import 'mixins'; @import 'vars'; -.form-group { - position: relative; -} - .editor { @include absolute(0, 0, 0, 0); @@ -41,6 +37,10 @@ } } +.form-group { + position: relative; +} + .slug { padding-right: 6rem; } diff --git a/frontend/src/app/shared/model/custom.ts b/frontend/src/app/shared/model/custom.ts index a1d59d7ed..400021d95 100644 --- a/frontend/src/app/shared/model/custom.ts +++ b/frontend/src/app/shared/model/custom.ts @@ -964,3 +964,21 @@ export class UIFieldPropertiesDto extends generated.UIFieldPropertiesDto { return visitor.visitUI(this); } } + +export class UserInfoFieldPropertiesDto extends generated.UserInfoFieldPropertiesDto { + public get isComplexUI() { + return true; + } + + public get isSortable() { + return false; + } + + public get isContentField() { + return true; + } + + public accept(visitor: FieldPropertiesVisitor): T { + return visitor.visitUserInfo(this); + } +} diff --git a/frontend/src/app/shared/model/generated.ts b/frontend/src/app/shared/model/generated.ts index e22577ac1..b82d06b0b 100644 --- a/frontend/src/app/shared/model/generated.ts +++ b/frontend/src/app/shared/model/generated.ts @@ -3132,6 +3132,9 @@ export abstract class FieldPropertiesDto implements IFieldPropertiesDto { if (data["fieldType"] === "UI") { return new UIFieldPropertiesDto().init(data); } + if (data["fieldType"] === "UserInfo") { + return new UserInfoFieldPropertiesDto().init(data); + } throw new Error("The abstract class 'FieldPropertiesDto' cannot be instantiated."); } @@ -4656,6 +4659,58 @@ export const UIFieldEditorValues: ReadonlyArray = [ "Separator" ]; +export class UserInfoFieldPropertiesDto extends FieldPropertiesDto implements IUserInfoFieldPropertiesDto { + /** The role to create a default value. */ + readonly defaultRole?: string | undefined; + + public get isComplexUI() { + return true; + } + + public get isSortable() { + return false; + } + + public get isContentField() { + return true; + } + + public accept(visitor: FieldPropertiesVisitor): T { + return visitor.visitUserInfo(this); + } + + constructor(data?: IUserInfoFieldPropertiesDto) { + super(data); + (this).fieldType = "UserInfo"; + } + + init(_data: any) { + super.init(_data); + (this).defaultRole = _data["defaultRole"]; + this.cleanup(this); + return this; + } + + static fromJSON(data: any): UserInfoFieldPropertiesDto { + const result = new UserInfoFieldPropertiesDto().init(data); + result.cleanup(this); + return result; + } + + toJSON(data?: any) { + data = typeof data === 'object' ? data : {}; + data["defaultRole"] = this.defaultRole; + super.toJSON(data); + this.cleanup(data); + return data; + } +} + +export interface IUserInfoFieldPropertiesDto extends IFieldPropertiesDto { + /** The role to create a default value. */ + readonly defaultRole?: string | undefined; +} + export class NestedFieldDto extends ResourceDto implements INestedFieldDto { /** The ID of the field. */ readonly fieldId!: number; @@ -12507,9 +12562,9 @@ export class AllContentsByPostDto implements IAllContentsByPostDto { private readonly cachedValues: { [key: string]: any } = {}; /** The list of ids to query. */ readonly ids?: string[] | undefined; - /** The start of the schedule. */ + /** The start time of the scheduled content period (see scheduledTo). */ readonly scheduledFrom?: DateTime | undefined; - /** The end of the schedule. */ + /** The end time of the scheduled content period (see scheduledFrom). */ readonly scheduledTo?: DateTime | undefined; /** The ID of the referencing content item. */ readonly referencing?: string | undefined; @@ -12593,9 +12648,9 @@ export class AllContentsByPostDto implements IAllContentsByPostDto { export interface IAllContentsByPostDto { /** The list of ids to query. */ readonly ids?: string[] | undefined; - /** The start of the schedule. */ + /** The start time of the scheduled content period (see scheduledTo). */ readonly scheduledFrom?: DateTime | undefined; - /** The end of the schedule. */ + /** The end time of the scheduled content period (see scheduledFrom). */ readonly scheduledTo?: DateTime | undefined; /** The ID of the referencing content item. */ readonly referencing?: string | undefined; diff --git a/frontend/src/app/shared/model/schemas.ts b/frontend/src/app/shared/model/schemas.ts index b3d6fc895..74cf1c4d6 100644 --- a/frontend/src/app/shared/model/schemas.ts +++ b/frontend/src/app/shared/model/schemas.ts @@ -5,7 +5,7 @@ * Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. */ -import { ArrayFieldPropertiesDto, AssetsFieldPropertiesDto, BooleanFieldPropertiesDto, ComponentFieldPropertiesDto, ComponentsFieldPropertiesDto, DateTimeFieldPropertiesDto, FieldDto, FieldPropertiesDto, FieldRuleAction, GeolocationFieldPropertiesDto, JsonFieldPropertiesDto, NumberFieldPropertiesDto, ReferencesFieldPropertiesDto, RichTextFieldPropertiesDto, StringFieldPropertiesDto, TagsFieldPropertiesDto, UIFieldPropertiesDto } from './generated'; +import { ArrayFieldPropertiesDto, AssetsFieldPropertiesDto, BooleanFieldPropertiesDto, ComponentFieldPropertiesDto, ComponentsFieldPropertiesDto, DateTimeFieldPropertiesDto, FieldDto, FieldPropertiesDto, FieldRuleAction, GeolocationFieldPropertiesDto, JsonFieldPropertiesDto, NumberFieldPropertiesDto, ReferencesFieldPropertiesDto, RichTextFieldPropertiesDto, StringFieldPropertiesDto, TagsFieldPropertiesDto, UIFieldPropertiesDto, UserInfoFieldPropertiesDto } from './generated'; export type FieldType = 'Array' | @@ -21,7 +21,8 @@ export type FieldType = 'RichText' | 'String' | 'Tags' | - 'UI'; + 'UI' | + 'UserInfo'; export const fieldTypes: ReadonlyArray<{ type: FieldType; description: string }> = [ { @@ -66,6 +67,9 @@ export const fieldTypes: ReadonlyArray<{ type: FieldType; description: string }> }, { type: 'UI', description: 'i18n:schemas.fieldTypes.ui.description', + }, { + type: 'UserInfo', + description: 'i18n:schemas.fieldTypes.user.description', }, ]; @@ -117,6 +121,9 @@ export function createProperties(fieldType: FieldType, values?: any): FieldPrope case 'UI': properties = new UIFieldPropertiesDto(values); break; + case 'UserInfo': + properties = new UserInfoFieldPropertiesDto(values); + break; default: throw new Error(`Unknown field type ${fieldType}.`); } @@ -152,6 +159,8 @@ export interface FieldPropertiesVisitor { visitTags(properties: TagsFieldPropertiesDto): T; visitUI(properties: UIFieldPropertiesDto): T; + + visitUserInfo(properties: UserInfoFieldPropertiesDto): T; } export const META_FIELDS = { diff --git a/frontend/src/app/shared/state/contents.forms.visitors.spec.ts b/frontend/src/app/shared/state/contents.forms.visitors.spec.ts index ad4d93c54..d97ba8b85 100644 --- a/frontend/src/app/shared/state/contents.forms.visitors.spec.ts +++ b/frontend/src/app/shared/state/contents.forms.visitors.spec.ts @@ -489,6 +489,32 @@ describe('TagsField', () => { }); }); +describe('UserInfoField', () => { + const field = createField({ properties: createProperties('UserInfo') }); + + it('should create validators', () => { + expect(FieldsValidators.create(field, false).length).toBe(0); + }); + + it('should format to empty string if null', () => { + expect(FieldFormatter.format(field, null)).toBe(''); + }); + + it('should format to user constant', () => { + expect(FieldFormatter.format(field, {})).toBe('User'); + }); + + it('should return default value as null if role is not defined', () => { + expect(FieldDefaultValue.get(field, 'iv')).toBeNull(); + }); + + it('should return default value from properties', () => { + const field2 = createField({ properties: createProperties('UserInfo', { defaultRole: 'Reader' }) }); + + expect(FieldDefaultValue.get(field2, 'iv').role).toEqual('Reader'); + }); +}); + function isUtc() { return new Date().getTimezoneOffset() === 0; } diff --git a/frontend/src/app/shared/state/contents.forms.visitors.ts b/frontend/src/app/shared/state/contents.forms.visitors.ts index 00318306e..16983e6a0 100644 --- a/frontend/src/app/shared/state/contents.forms.visitors.ts +++ b/frontend/src/app/shared/state/contents.forms.visitors.ts @@ -7,7 +7,7 @@ import { ValidatorFn, Validators } from '@angular/forms'; import { DateTime, Types, ValidatorsEx } from '@app/framework'; -import { AppLanguageDto, ContentDto, FieldDto, NestedFieldDto } from '../model'; +import { AppLanguageDto, ContentDto, FieldDto, NestedFieldDto, UserInfoFieldPropertiesDto } from '../model'; import { ArrayFieldPropertiesDto, AssetsFieldPropertiesDto, BooleanFieldPropertiesDto, ComponentFieldPropertiesDto, ComponentsFieldPropertiesDto, DateTimeFieldPropertiesDto, fieldInvariant, FieldPropertiesVisitor, GeolocationFieldPropertiesDto, JsonFieldPropertiesDto, NumberFieldPropertiesDto, ReferencesFieldPropertiesDto, RichTextFieldPropertiesDto, StringFieldPropertiesDto, TagsFieldPropertiesDto, UIFieldPropertiesDto } from '../model'; export class HtmlValue { @@ -276,6 +276,10 @@ export class FieldFormatter implements FieldPropertiesVisitor { return this.value; } + public visitUserInfo(_: UserInfoFieldPropertiesDto): string { + return 'User'; + } + private formatArray(singularName: string, pluralName: string) { if (!Types.isArray(this.value)) { return `0 ${pluralName}`; @@ -448,6 +452,10 @@ export class FieldsValidators implements FieldPropertiesVisitor { return []; } + + public visitUserInfo(_: UserInfoFieldPropertiesDto): ReadonlyArray { + return []; + } } export class FieldDefaultValue implements FieldPropertiesVisitor { @@ -533,6 +541,14 @@ export class FieldDefaultValue implements FieldPropertiesVisitor { return null; } + public visitUserInfo(properties: UserInfoFieldPropertiesDto): any { + if (!!properties.defaultRole) { + return { apiKey: generateApiKey(), role: properties.defaultRole }; + } + + return null; + } + private getValue(value: any, values?: any) { if (values && values.hasOwnProperty(this.partitionKey)) { return values[this.partitionKey]; @@ -541,3 +557,16 @@ export class FieldDefaultValue implements FieldPropertiesVisitor { return value; } } + +export function generateApiKey() { + const uuid = crypto.randomUUID(); + + const base64 = btoa(uuid); + + const cleaned = base64 + .replace(/\+/g, '') + .replace(/\//g, '') + .replace(/=+$/, ''); + + return cleaned; +} \ No newline at end of file diff --git a/frontend/src/app/shared/state/roles.state.ts b/frontend/src/app/shared/state/roles.state.ts index a11464a01..aeb928095 100644 --- a/frontend/src/app/shared/state/roles.state.ts +++ b/frontend/src/app/shared/state/roles.state.ts @@ -6,7 +6,7 @@ */ import { Injectable } from '@angular/core'; -import { Observable } from 'rxjs'; +import { EMPTY, Observable } from 'rxjs'; import { finalize, tap } from 'rxjs/operators'; import { debug, DialogService, LoadingState, shareSubscribed, State, VersionTag } from '@app/framework'; import { AddRoleDto, RoleDto, RolesDto, UpdateRoleDto } from '../model'; @@ -64,6 +64,14 @@ export class RolesState extends State { debug(this, 'roles'); } + public loadIfNotLoaded(): Observable { + if (this.snapshot.isLoaded) { + return EMPTY; + } + + return this.loadInternal(false); + } + public load(isReload = false): Observable { if (!isReload) { this.resetState('Loading Initial'); diff --git a/frontend/src/app/shared/state/schemas.forms.ts b/frontend/src/app/shared/state/schemas.forms.ts index 9e3e4be8b..59942f87e 100644 --- a/frontend/src/app/shared/state/schemas.forms.ts +++ b/frontend/src/app/shared/state/schemas.forms.ts @@ -386,6 +386,10 @@ export class EditFieldFormVisitor implements FieldPropertiesVisitor { this.config['minItems'] = new UntypedFormControl(undefined); } + public visitUserInfo() { + this.config['defaultRole'] = new UntypedFormControl(undefined); + } + public visitGeolocation() { return undefined; } diff --git a/frontend/src/app/theme/icomoon/Read Me.txt b/frontend/src/app/theme/icomoon/Read Me.txt index 723a49eee..6fceb3881 100644 --- a/frontend/src/app/theme/icomoon/Read Me.txt +++ b/frontend/src/app/theme/icomoon/Read Me.txt @@ -1,6 +1,6 @@ Open *demo.html* to see a list of all the glyphs in your font along with their codes/ligatures. -To use the generated font in desktop programs, you can install the TTF font. In order to copy the character associated with each icon, refer to the text box at the bottom right corner of each glyph in demo.html. The character inside this text box may be invisible; but it can still be copied. See this guide for more info: https://icomoon.io/docs/#local-fonts +To use the generated font in desktop programs, you can install the TTF font. In order to copy the character associated with each icon, refer to the text box at the bottom right corner of each glyph in demo.html. The character inside this text box may be invisible; but it can still be copied. See this guide for more info: https://icomoon.io/docs#install You won't need any of the files located under the *demo-files* directory when including the generated font in your own projects. diff --git a/frontend/src/app/theme/icomoon/demo.html b/frontend/src/app/theme/icomoon/demo.html index c632f3241..e22a6d4f3 100644 --- a/frontend/src/app/theme/icomoon/demo.html +++ b/frontend/src/app/theme/icomoon/demo.html @@ -1178,6 +1178,20 @@
+
+
+ + icon-type-UserInfo +
+
+ + +
+
+ liga: + +
+
diff --git a/frontend/src/app/theme/icomoon/fonts/icomoon.eot b/frontend/src/app/theme/icomoon/fonts/icomoon.eot index 1ec0b9fad23571d4e1a3e3de0fb490653d15a4c8..0adc71481e35678c3be4a55b42c41d6a96ae0013 100644 GIT binary patch delta 59 zcmeBKz|^yVX@U()qTlv!6CJj&=r^*KZv0`>Df4Z+Ut&DJ%~u9)76uS_Ix(REMsE)2 H+QSL}t05K2 delta 59 zcmeBKz|^yVX@U*Q*;?Zt6CJj&=pA~yf8!6EPMIIZwP)k`ZN4&avoL_bQ=^cjFnV)9 H*B({?<*F9q diff --git a/frontend/src/app/theme/icomoon/fonts/icomoon.svg b/frontend/src/app/theme/icomoon/fonts/icomoon.svg index 83b032f61..e1da95dfa 100644 --- a/frontend/src/app/theme/icomoon/fonts/icomoon.svg +++ b/frontend/src/app/theme/icomoon/fonts/icomoon.svg @@ -57,7 +57,7 @@ - + diff --git a/frontend/src/app/theme/icomoon/fonts/icomoon.ttf b/frontend/src/app/theme/icomoon/fonts/icomoon.ttf index ba598c157562aea1b86844b0cc991bed6c9c24ee..0c0401f7e716edb4b4ff3d55722be3a6fe231fcf 100644 GIT binary patch delta 51 zcmaDckLkrcrU?No`i-om8$)b5Wxj3qON{5Y`O3h}!TtPaP delta 51 zcmaDckLkrcrU?NodWYWb-xy-kDf7d)_G~=A%~u9)76uS_Y80{*MsHrzxrY@1AVd>m diff --git a/frontend/src/app/theme/icomoon/fonts/icomoon.woff b/frontend/src/app/theme/icomoon/fonts/icomoon.woff index 6bd7cd0bf413ad964be3b9272b24af6c7f929848..eca7bb50c3e9697d581a5598674a5940a4ded302 100644 GIT binary patch delta 51 zcmdlopJ~f{rU^YP`i-om8z=a5%6!}Iml)4)^Ob>{g#iSfPE2Tk(VKsC?qLN0?h+Ex delta 51 zcmdlopJ~f{rU^YPdWYWb-#EdiQ|5 +{ + private readonly string schemaName = $"schema-{Guid.NewGuid()}"; + + public CreatedAppFixture _ { get; } = fixture; + + [Fact] + public async Task Should_login_with_user_credentials() + { + var apiKey = Guid.NewGuid().ToString(); + + // STEP 1: Create schema. + var createSchemaRequest = new CreateSchemaDto + { + Name = schemaName, + Fields = + [ + new UpsertSchemaFieldDto + { + Name = "userInfo", + Properties = new UserInfoFieldPropertiesDto(), + }, + ], + IsPublished = true, + }; + + await _.Client.Schemas.PostSchemaAsync(createSchemaRequest); + + + // STEP 2: Create user. + var client = _.Client.DynamicContents(schemaName); + + await client.CreateAsync( + new DynamicData + { + ["userInfo"] = new JObject + { + ["iv"] = new JObject + { + ["role"] = "Reader", + // This API key is used for authentication later. + ["apiKey"] = apiKey, + }, + }, + }, + ContentCreateOptions.AsPublish); + + // STEP 3: Login. + var apiKeyClient = new SquidexClient(new SquidexOptions + { + Url = _.Url, + ApiKey = apiKey, + ClientId = null!, + ClientSecret = null!, + AppName = _.AppName, + }); + + var apiKeyContents = apiKeyClient.DynamicContents(schemaName); + + try + { + using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30)); + + while (!cts.IsCancellationRequested) + { + try + { + await apiKeyContents.GetAsync(ct: cts.Token); + return; + } + catch (SquidexException ex) when (ex.StatusCode == 401) + { + } + + await Task.Delay(200, cts.Token); + } + } + catch (OperationCanceledException) + { + } + + Assert.Fail(); + } +} diff --git a/tools/TestSuite/TestSuite.ApiTests/GraphQLSubscriptionTests.cs b/tools/TestSuite/TestSuite.ApiTests/GraphQLSubscriptionTests.cs index fcd02b62b..c93386336 100644 --- a/tools/TestSuite/TestSuite.ApiTests/GraphQLSubscriptionTests.cs +++ b/tools/TestSuite/TestSuite.ApiTests/GraphQLSubscriptionTests.cs @@ -124,11 +124,12 @@ public class GraphQLSubscriptionTests(ContentFixture fixture) : IClassFixture CreateClient() { - var accessToken = await _.Client.Options.Authenticator.GetBearerTokenAsync(_.AppName, default); + var accessToken = await _.Client.Options.Authenticator.GetAuthTokenAsync(_.AppName, default); + var (queryName, queryValue) = accessToken.SerializeAsQuery(); var options = new GraphQLHttpClientOptions { - EndPoint = new Uri(_.Client.GenerateUrl($"/api/content/{_.AppName}/graphql?access_token={accessToken}")!), + EndPoint = new Uri(_.Client.GenerateUrl($"/api/content/{_.AppName}/graphql?{queryName}={queryValue}")!), }; var client = new GraphQLHttpClient(options, new NewtonsoftJsonSerializer()); diff --git a/tools/TestSuite/TestSuite.ApiTests/TestSuite.ApiTests.csproj b/tools/TestSuite/TestSuite.ApiTests/TestSuite.ApiTests.csproj index 48293e319..62a35c251 100644 --- a/tools/TestSuite/TestSuite.ApiTests/TestSuite.ApiTests.csproj +++ b/tools/TestSuite/TestSuite.ApiTests/TestSuite.ApiTests.csproj @@ -16,8 +16,8 @@ - - + + diff --git a/tools/TestSuite/TestSuite.Shared/TestSuite.Shared.csproj b/tools/TestSuite/TestSuite.Shared/TestSuite.Shared.csproj index 54753ea80..4b4ee6fde 100644 --- a/tools/TestSuite/TestSuite.Shared/TestSuite.Shared.csproj +++ b/tools/TestSuite/TestSuite.Shared/TestSuite.Shared.csproj @@ -17,9 +17,9 @@ - - - + + +