diff --git a/src/JsonSchema/AppSettings.cs b/src/JsonSchema/AppSettings.cs index a8ea2f5dbb..f9c7c224be 100644 --- a/src/JsonSchema/AppSettings.cs +++ b/src/JsonSchema/AppSettings.cs @@ -12,11 +12,12 @@ internal class AppSettings public CmsDefinition? CMS { get; set; } /// - /// Configurations for the Umbraco CMS + /// Configurations for the Umbraco CMS /// public class CmsDefinition { public ContentSettings? Content { get; set; } + public CoreDebugSettings? Debug { get; set; } public ExceptionFilterSettings? ExceptionFilter { get; set; } @@ -37,7 +38,7 @@ internal class AppSettings public LoggingSettings? Logging { get; set; } - public NuCacheSettings? NuCache { get; set; } + public NuCacheSettings? NuCache { get; set; } public RequestHandlerSettings? RequestHandler { get; set; } @@ -49,7 +50,7 @@ internal class AppSettings public TypeFinderSettings? TypeFinder { get; set; } - public WebRoutingSettings? WebRouting { get; set; } + public WebRoutingSettings? WebRouting { get; set; } public UmbracoPluginSettings? Plugins { get; set; } @@ -72,5 +73,7 @@ internal class AppSettings public InstallDefaultDataSettings? DefaultDataCreation { get; set; } public DataTypesSettings? DataTypes { get; set; } + + public LicensesSettings? Licenses { get; set; } } } diff --git a/src/JsonSchema/appsettings-schema.json b/src/JsonSchema/appsettings-schema.json index 95c9a9b4c1..44b006b853 100644 --- a/src/JsonSchema/appsettings-schema.json +++ b/src/JsonSchema/appsettings-schema.json @@ -41,6 +41,17 @@ "$ref": "appsettings-schema.Umbraco.Deploy.json#/definitions/JsonSchemaDeployDefinition" } ] + }, + "Workflow": { + "description": "Configuration of Umbraco Workflow", + "oneOf": [ + { + "type": "null" + }, + { + "$ref": "appsettings-schema.Umbraco.Workflow.json#/definitions/JsonSchemaWorkflowDefinition" + } + ] } } } diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/Analytics/AllAnalyticsController.cs b/src/Umbraco.Cms.ManagementApi/Controllers/Analytics/AllAnalyticsController.cs deleted file mode 100644 index 780d6f90d3..0000000000 --- a/src/Umbraco.Cms.ManagementApi/Controllers/Analytics/AllAnalyticsController.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using Umbraco.Cms.Core.Models; -using Umbraco.Cms.ManagementApi.ViewModels.Pagination; - -namespace Umbraco.Cms.ManagementApi.Controllers.Analytics; - -public class AllAnalyticsController : AnalyticsControllerBase -{ - [HttpGet("all")] - [MapToApiVersion("1.0")] - [ProducesResponseType(typeof(PagedViewModel), StatusCodes.Status200OK)] - public async Task> GetAll(int skip, int take) - { - TelemetryLevel[] levels = Enum.GetValues(); - return await Task.FromResult(new PagedViewModel - { - Total = levels.Length, - Items = levels.Skip(skip).Take(take), - }); - } -} diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/Analytics/AnalyticsControllerBase.cs b/src/Umbraco.Cms.ManagementApi/Controllers/Analytics/AnalyticsControllerBase.cs deleted file mode 100644 index 1ce29ea5c6..0000000000 --- a/src/Umbraco.Cms.ManagementApi/Controllers/Analytics/AnalyticsControllerBase.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Microsoft.AspNetCore.Mvc; -using NSwag.Annotations; -using Umbraco.New.Cms.Web.Common.Routing; - -namespace Umbraco.Cms.ManagementApi.Controllers.Analytics; - -[ApiController] -[VersionedApiBackOfficeRoute("analytics")] -[OpenApiTag("Analytics")] -[ApiVersion("1.0")] -public abstract class AnalyticsControllerBase : ManagementApiControllerBase -{ -} diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/Analytics/GetAnalyticsController.cs b/src/Umbraco.Cms.ManagementApi/Controllers/Analytics/GetAnalyticsController.cs deleted file mode 100644 index 1c45e41e71..0000000000 --- a/src/Umbraco.Cms.ManagementApi/Controllers/Analytics/GetAnalyticsController.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Mvc; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.ManagementApi.ViewModels.Analytics; - -namespace Umbraco.Cms.ManagementApi.Controllers.Analytics; - -public class GetAnalyticsController : AnalyticsControllerBase -{ - private readonly IMetricsConsentService _metricsConsentService; - - public GetAnalyticsController(IMetricsConsentService metricsConsentService) => _metricsConsentService = metricsConsentService; - - [HttpGet] - [MapToApiVersion("1.0")] - [ProducesResponseType(typeof(AnalyticsLevelViewModel), StatusCodes.Status200OK)] - public async Task Get() => await Task.FromResult(new AnalyticsLevelViewModel { AnalyticsLevel = _metricsConsentService.GetConsentLevel() }); -} diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/Culture/CultureControllerBase.cs b/src/Umbraco.Cms.ManagementApi/Controllers/Culture/CultureControllerBase.cs index 7ea0b77ae2..3ab1257824 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/Culture/CultureControllerBase.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/Culture/CultureControllerBase.cs @@ -1,12 +1,11 @@ using Microsoft.AspNetCore.Mvc; -using NSwag.Annotations; using Umbraco.New.Cms.Web.Common.Routing; namespace Umbraco.Cms.ManagementApi.Controllers.Culture; [ApiController] [VersionedApiBackOfficeRoute("culture")] -[OpenApiTag("Culture")] +[ApiExplorerSettings(GroupName = "Culture")] [ApiVersion("1.0")] public abstract class CultureControllerBase : ManagementApiControllerBase { diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/DataType/Tree/DataTypeTreeControllerBase.cs b/src/Umbraco.Cms.ManagementApi/Controllers/DataType/Tree/DataTypeTreeControllerBase.cs index 4bdae5a2fa..e5948770db 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/DataType/Tree/DataTypeTreeControllerBase.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/DataType/Tree/DataTypeTreeControllerBase.cs @@ -1,5 +1,4 @@ using Microsoft.AspNetCore.Mvc; -using NSwag.Annotations; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.Entities; @@ -12,8 +11,8 @@ namespace Umbraco.Cms.ManagementApi.Controllers.DataType.Tree; [ApiVersion("1.0")] [ApiController] -[VersionedApiBackOfficeRoute($"{Constants.UdiEntityType.DataType}/tree")] -[OpenApiTag(nameof(Constants.UdiEntityType.DataType))] +[VersionedApiBackOfficeRoute($"{Constants.Web.RoutePath.Tree}/{Constants.UdiEntityType.DataType}")] +[ApiExplorerSettings(GroupName = "Data Type")] public class DataTypeTreeControllerBase : FolderTreeControllerBase { private readonly IDataTypeService _dataTypeService; diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/DataType/Tree/ItemsDataTypeTreeController.cs b/src/Umbraco.Cms.ManagementApi/Controllers/DataType/Tree/ItemsDataTypeTreeController.cs index 82eabcb6f4..34779cca3d 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/DataType/Tree/ItemsDataTypeTreeController.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/DataType/Tree/ItemsDataTypeTreeController.cs @@ -12,7 +12,7 @@ public class ItemsDataTypeTreeController : DataTypeTreeControllerBase { } - [HttpGet("items")] + [HttpGet("item")] [MapToApiVersion("1.0")] [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] public async Task>> Items([FromQuery(Name = "key")] Guid[] keys) diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/Dictionary/DictionaryControllerBase.cs b/src/Umbraco.Cms.ManagementApi/Controllers/Dictionary/DictionaryControllerBase.cs index f102d497ac..cfdba7cec1 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/Dictionary/DictionaryControllerBase.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/Dictionary/DictionaryControllerBase.cs @@ -1,12 +1,11 @@ using Microsoft.AspNetCore.Mvc; -using NSwag.Annotations; using Umbraco.New.Cms.Web.Common.Routing; namespace Umbraco.Cms.ManagementApi.Controllers.Dictionary; [ApiController] [VersionedApiBackOfficeRoute("dictionary")] -[OpenApiTag("Dictionary")] +[ApiExplorerSettings(GroupName = "Dictionary")] [ApiVersion("1.0")] // TODO: Add authentication public abstract class DictionaryControllerBase : ManagementApiControllerBase diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/Dictionary/ExportDictionaryController.cs b/src/Umbraco.Cms.ManagementApi/Controllers/Dictionary/ExportDictionaryController.cs index f4944220d5..5145db1076 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/Dictionary/ExportDictionaryController.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/Dictionary/ExportDictionaryController.cs @@ -23,13 +23,13 @@ public class ExportDictionaryController : DictionaryControllerBase [HttpGet("export/{key:guid}")] [MapToApiVersion("1.0")] [ProducesResponseType(typeof(FileContentResult), StatusCodes.Status200OK)] - [ProducesResponseType(typeof(NotFoundObjectResult), StatusCodes.Status404NotFound)] + [ProducesResponseType(typeof(NotFoundResult), StatusCodes.Status404NotFound)] public async Task ExportDictionary(Guid key, bool includeChildren = false) { IDictionaryItem? dictionaryItem = _localizationService.GetDictionaryItemById(key); if (dictionaryItem is null) { - return await Task.FromResult(NotFound("No dictionary item found with id ")); + return await Task.FromResult(NotFound()); } XElement xml = _entityXmlSerializer.Serialize(dictionaryItem, includeChildren); diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/DictionaryItem/Tree/ChildrenDictionaryItemTreeController.cs b/src/Umbraco.Cms.ManagementApi/Controllers/Dictionary/Tree/ChildrenDictionaryTreeController.cs similarity index 82% rename from src/Umbraco.Cms.ManagementApi/Controllers/DictionaryItem/Tree/ChildrenDictionaryItemTreeController.cs rename to src/Umbraco.Cms.ManagementApi/Controllers/Dictionary/Tree/ChildrenDictionaryTreeController.cs index 0969b808c9..8b2e6b2328 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/DictionaryItem/Tree/ChildrenDictionaryItemTreeController.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/Dictionary/Tree/ChildrenDictionaryTreeController.cs @@ -6,11 +6,11 @@ using Umbraco.Cms.ManagementApi.Services.Paging; using Umbraco.Cms.ManagementApi.ViewModels.Pagination; using Umbraco.Cms.ManagementApi.ViewModels.Tree; -namespace Umbraco.Cms.ManagementApi.Controllers.DictionaryItem.Tree; +namespace Umbraco.Cms.ManagementApi.Controllers.Dictionary.Tree; -public class ChildrenDictionaryItemTreeController : DictionaryItemTreeControllerBase +public class ChildrenDictionaryTreeController : DictionaryTreeControllerBase { - public ChildrenDictionaryItemTreeController(IEntityService entityService, ILocalizationService localizationService) + public ChildrenDictionaryTreeController(IEntityService entityService, ILocalizationService localizationService) : base(entityService, localizationService) { } diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/DictionaryItem/Tree/DictionaryItemTreeControllerBase.cs b/src/Umbraco.Cms.ManagementApi/Controllers/Dictionary/Tree/DictionaryTreeControllerBase.cs similarity index 77% rename from src/Umbraco.Cms.ManagementApi/Controllers/DictionaryItem/Tree/DictionaryItemTreeControllerBase.cs rename to src/Umbraco.Cms.ManagementApi/Controllers/Dictionary/Tree/DictionaryTreeControllerBase.cs index 0d6a513e2d..4959789809 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/DictionaryItem/Tree/DictionaryItemTreeControllerBase.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/Dictionary/Tree/DictionaryTreeControllerBase.cs @@ -1,5 +1,4 @@ using Microsoft.AspNetCore.Mvc; -using NSwag.Annotations; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Services; @@ -7,17 +6,17 @@ using Umbraco.Cms.ManagementApi.Controllers.Tree; using Umbraco.Cms.ManagementApi.ViewModels.Tree; using Umbraco.New.Cms.Web.Common.Routing; -namespace Umbraco.Cms.ManagementApi.Controllers.DictionaryItem.Tree; +namespace Umbraco.Cms.ManagementApi.Controllers.Dictionary.Tree; [ApiVersion("1.0")] [ApiController] -[VersionedApiBackOfficeRoute($"{Constants.UdiEntityType.DictionaryItem}/tree")] -[OpenApiTag(nameof(Constants.UdiEntityType.DictionaryItem))] -// NOTE: at the moment dictionary items aren't supported by EntityService, so we have little use of the +[VersionedApiBackOfficeRoute($"{Constants.Web.RoutePath.Tree}/dictionary")] +[ApiExplorerSettings(GroupName = "Dictionary")] +// NOTE: at the moment dictionary items (renamed to dictionary tree) aren't supported by EntityService, so we have little use of the // tree controller base. We'll keep it though, in the hope that we can mend EntityService. -public class DictionaryItemTreeControllerBase : EntityTreeControllerBase +public class DictionaryTreeControllerBase : EntityTreeControllerBase { - public DictionaryItemTreeControllerBase(IEntityService entityService, ILocalizationService localizationService) + public DictionaryTreeControllerBase(IEntityService entityService, ILocalizationService localizationService) : base(entityService) => LocalizationService = localizationService; diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/DictionaryItem/Tree/ItemsDictionaryItemTreeController.cs b/src/Umbraco.Cms.ManagementApi/Controllers/Dictionary/Tree/ItemsDictionaryTreeController.cs similarity index 72% rename from src/Umbraco.Cms.ManagementApi/Controllers/DictionaryItem/Tree/ItemsDictionaryItemTreeController.cs rename to src/Umbraco.Cms.ManagementApi/Controllers/Dictionary/Tree/ItemsDictionaryTreeController.cs index 69d2fda33d..ea2de2058a 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/DictionaryItem/Tree/ItemsDictionaryItemTreeController.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/Dictionary/Tree/ItemsDictionaryTreeController.cs @@ -4,16 +4,16 @@ using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Services; using Umbraco.Cms.ManagementApi.ViewModels.Tree; -namespace Umbraco.Cms.ManagementApi.Controllers.DictionaryItem.Tree; +namespace Umbraco.Cms.ManagementApi.Controllers.Dictionary.Tree; -public class ItemsDictionaryItemTreeController : DictionaryItemTreeControllerBase +public class ItemsDictionaryTreeController : DictionaryTreeControllerBase { - public ItemsDictionaryItemTreeController(IEntityService entityService, ILocalizationService localizationService) + public ItemsDictionaryTreeController(IEntityService entityService, ILocalizationService localizationService) : base(entityService, localizationService) { } - [HttpGet("items")] + [HttpGet("item")] [MapToApiVersion("1.0")] [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] public async Task>> Items([FromQuery(Name = "key")] Guid[] keys) diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/DictionaryItem/Tree/RootDictionaryItemTreeController.cs b/src/Umbraco.Cms.ManagementApi/Controllers/Dictionary/Tree/RootDictionaryTreeController.cs similarity index 82% rename from src/Umbraco.Cms.ManagementApi/Controllers/DictionaryItem/Tree/RootDictionaryItemTreeController.cs rename to src/Umbraco.Cms.ManagementApi/Controllers/Dictionary/Tree/RootDictionaryTreeController.cs index 18abf7a728..65981cb518 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/DictionaryItem/Tree/RootDictionaryItemTreeController.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/Dictionary/Tree/RootDictionaryTreeController.cs @@ -6,11 +6,11 @@ using Umbraco.Cms.ManagementApi.Services.Paging; using Umbraco.Cms.ManagementApi.ViewModels.Pagination; using Umbraco.Cms.ManagementApi.ViewModels.Tree; -namespace Umbraco.Cms.ManagementApi.Controllers.DictionaryItem.Tree; +namespace Umbraco.Cms.ManagementApi.Controllers.Dictionary.Tree; -public class RootDictionaryItemTreeController : DictionaryItemTreeControllerBase +public class RootDictionaryTreeController : DictionaryTreeControllerBase { - public RootDictionaryItemTreeController(IEntityService entityService, ILocalizationService localizationService) + public RootDictionaryTreeController(IEntityService entityService, ILocalizationService localizationService) : base(entityService, localizationService) { } diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/Document/RecycleBin/DocumentRecycleBinControllerBase.cs b/src/Umbraco.Cms.ManagementApi/Controllers/Document/RecycleBin/DocumentRecycleBinControllerBase.cs index 747b6b3296..2edcb07a39 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/Document/RecycleBin/DocumentRecycleBinControllerBase.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/Document/RecycleBin/DocumentRecycleBinControllerBase.cs @@ -1,6 +1,5 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; -using NSwag.Annotations; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.Entities; @@ -14,10 +13,10 @@ namespace Umbraco.Cms.ManagementApi.Controllers.Document.RecycleBin; [ApiVersion("1.0")] [ApiController] -[VersionedApiBackOfficeRoute($"{Constants.UdiEntityType.Document}/recycle-bin")] +[VersionedApiBackOfficeRoute($"{Constants.Web.RoutePath.RecycleBin}/{Constants.UdiEntityType.Document}")] [RequireDocumentTreeRootAccess] [ProducesResponseType(StatusCodes.Status401Unauthorized)] -[OpenApiTag(nameof(Constants.UdiEntityType.Document))] +[ApiExplorerSettings(GroupName = nameof(Constants.UdiEntityType.Document))] public class DocumentRecycleBinControllerBase : RecycleBinControllerBase { public DocumentRecycleBinControllerBase(IEntityService entityService) diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/Document/Tree/DocumentTreeControllerBase.cs b/src/Umbraco.Cms.ManagementApi/Controllers/Document/Tree/DocumentTreeControllerBase.cs index a20237537d..b838c03790 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/Document/Tree/DocumentTreeControllerBase.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/Document/Tree/DocumentTreeControllerBase.cs @@ -1,5 +1,4 @@ using Microsoft.AspNetCore.Mvc; -using NSwag.Annotations; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Cache; using Umbraco.Cms.Core.Models; @@ -16,8 +15,8 @@ namespace Umbraco.Cms.ManagementApi.Controllers.Document.Tree; [ApiVersion("1.0")] [ApiController] -[VersionedApiBackOfficeRoute($"{Constants.UdiEntityType.Document}/tree")] -[OpenApiTag(nameof(Constants.UdiEntityType.Document))] +[VersionedApiBackOfficeRoute($"{Constants.Web.RoutePath.Tree}/{Constants.UdiEntityType.Document}")] +[ApiExplorerSettings(GroupName = nameof(Constants.UdiEntityType.Document))] public abstract class DocumentTreeControllerBase : UserStartNodeTreeControllerBase { private readonly IPublicAccessService _publicAccessService; diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/Document/Tree/ItemsDocumentTreeController.cs b/src/Umbraco.Cms.ManagementApi/Controllers/Document/Tree/ItemsDocumentTreeController.cs index a18dfea069..a9dd8326d6 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/Document/Tree/ItemsDocumentTreeController.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/Document/Tree/ItemsDocumentTreeController.cs @@ -21,7 +21,7 @@ public class ItemsDocumentTreeController : DocumentTreeControllerBase { } - [HttpGet("items")] + [HttpGet("item")] [MapToApiVersion("1.0")] [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] public async Task>> Items([FromQuery(Name = "key")] Guid[] keys, Guid? dataTypeKey = null, string? culture = null) diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/DocumentBlueprint/Tree/DocumentBlueprintTreeControllerBase.cs b/src/Umbraco.Cms.ManagementApi/Controllers/DocumentBlueprint/Tree/DocumentBlueprintTreeControllerBase.cs index c6247da3a9..ad4e32cd87 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/DocumentBlueprint/Tree/DocumentBlueprintTreeControllerBase.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/DocumentBlueprint/Tree/DocumentBlueprintTreeControllerBase.cs @@ -1,5 +1,4 @@ using Microsoft.AspNetCore.Mvc; -using NSwag.Annotations; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.Entities; @@ -12,8 +11,8 @@ namespace Umbraco.Cms.ManagementApi.Controllers.DocumentBlueprint.Tree; [ApiVersion("1.0")] [ApiController] -[VersionedApiBackOfficeRoute($"{Constants.UdiEntityType.DocumentBlueprint}/tree")] -[OpenApiTag(nameof(Constants.UdiEntityType.DocumentBlueprint))] +[VersionedApiBackOfficeRoute($"{Constants.Web.RoutePath.Tree}/{Constants.UdiEntityType.DocumentBlueprint}")] +[ApiExplorerSettings(GroupName = "Document Blueprint")] public class DocumentBlueprintTreeControllerBase : EntityTreeControllerBase { private readonly IContentTypeService _contentTypeService; diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/DocumentBlueprint/Tree/ItemsDocumentBlueprintTreeController.cs b/src/Umbraco.Cms.ManagementApi/Controllers/DocumentBlueprint/Tree/ItemsDocumentBlueprintTreeController.cs index 6b7edb6fab..e077d7eb49 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/DocumentBlueprint/Tree/ItemsDocumentBlueprintTreeController.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/DocumentBlueprint/Tree/ItemsDocumentBlueprintTreeController.cs @@ -13,7 +13,7 @@ public class ItemsDocumentBlueprintTreeController : DocumentBlueprintTreeControl { } - [HttpGet("items")] + [HttpGet("item")] [MapToApiVersion("1.0")] [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] public async Task>> Items([FromQuery(Name = "key")] Guid[] keys) diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/DocumentType/Tree/DocumentTypeTreeControllerBase.cs b/src/Umbraco.Cms.ManagementApi/Controllers/DocumentType/Tree/DocumentTypeTreeControllerBase.cs index cc4c224ef5..91676b9f80 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/DocumentType/Tree/DocumentTypeTreeControllerBase.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/DocumentType/Tree/DocumentTypeTreeControllerBase.cs @@ -1,5 +1,4 @@ using Microsoft.AspNetCore.Mvc; -using NSwag.Annotations; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.Entities; @@ -12,8 +11,8 @@ namespace Umbraco.Cms.ManagementApi.Controllers.DocumentType.Tree; [ApiVersion("1.0")] [ApiController] -[VersionedApiBackOfficeRoute($"{Constants.UdiEntityType.DocumentType}/tree")] -[OpenApiTag(nameof(Constants.UdiEntityType.DocumentType))] +[VersionedApiBackOfficeRoute($"{Constants.Web.RoutePath.Tree}/{Constants.UdiEntityType.DocumentType}")] +[ApiExplorerSettings(GroupName = "Document Type")] public class DocumentTypeTreeControllerBase : FolderTreeControllerBase { private readonly IContentTypeService _contentTypeService; diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/DocumentType/Tree/ItemsDocumentTypeTreeController.cs b/src/Umbraco.Cms.ManagementApi/Controllers/DocumentType/Tree/ItemsDocumentTypeTreeController.cs index e19bf249c6..28da775a58 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/DocumentType/Tree/ItemsDocumentTypeTreeController.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/DocumentType/Tree/ItemsDocumentTypeTreeController.cs @@ -12,7 +12,7 @@ public class ItemsDocumentTypeTreeController : DocumentTypeTreeControllerBase { } - [HttpGet("items")] + [HttpGet("item")] [MapToApiVersion("1.0")] [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] public async Task>> Items([FromQuery(Name = "key")] Guid[] keys) diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/Help/HelpControllerBase.cs b/src/Umbraco.Cms.ManagementApi/Controllers/Help/HelpControllerBase.cs index 7220b8738b..9a50d45186 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/Help/HelpControllerBase.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/Help/HelpControllerBase.cs @@ -1,12 +1,11 @@ using Microsoft.AspNetCore.Mvc; -using NSwag.Annotations; using Umbraco.New.Cms.Web.Common.Routing; namespace Umbraco.Cms.ManagementApi.Controllers.Help; [ApiController] [VersionedApiBackOfficeRoute("help")] -[OpenApiTag("Help")] +[ApiExplorerSettings(GroupName = "Help")] [ApiVersion("1.0")] public abstract class HelpControllerBase : ManagementApiControllerBase { diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/Install/InstallControllerBase.cs b/src/Umbraco.Cms.ManagementApi/Controllers/Install/InstallControllerBase.cs index 359e62b4b8..04cd4885bb 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/Install/InstallControllerBase.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/Install/InstallControllerBase.cs @@ -1,5 +1,4 @@ using Microsoft.AspNetCore.Mvc; -using NSwag.Annotations; using Umbraco.Cms.Core; using Umbraco.Cms.ManagementApi.Filters; using Umbraco.New.Cms.Web.Common.Routing; @@ -8,7 +7,7 @@ namespace Umbraco.Cms.ManagementApi.Controllers.Install; [ApiController] [VersionedApiBackOfficeRoute("install")] -[OpenApiTag("Install")] +[ApiExplorerSettings(GroupName = "Install")] [RequireRuntimeLevel(RuntimeLevel.Install)] public abstract class InstallControllerBase : ManagementApiControllerBase { diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/Language/LanguageControllerBase.cs b/src/Umbraco.Cms.ManagementApi/Controllers/Language/LanguageControllerBase.cs index b84088906c..c316486fed 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/Language/LanguageControllerBase.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/Language/LanguageControllerBase.cs @@ -1,12 +1,11 @@ using Microsoft.AspNetCore.Mvc; -using NSwag.Annotations; using Umbraco.New.Cms.Web.Common.Routing; namespace Umbraco.Cms.ManagementApi.Controllers.Language; [ApiController] [VersionedApiBackOfficeRoute("language")] -[OpenApiTag("Language")] +[ApiExplorerSettings(GroupName = "Language")] [ApiVersion("1.0")] public abstract class LanguageControllerBase : ManagementApiControllerBase { diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/Media/RecycleBin/MediaRecycleBinControllerBase.cs b/src/Umbraco.Cms.ManagementApi/Controllers/Media/RecycleBin/MediaRecycleBinControllerBase.cs index 157e1099de..787a12f957 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/Media/RecycleBin/MediaRecycleBinControllerBase.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/Media/RecycleBin/MediaRecycleBinControllerBase.cs @@ -1,6 +1,5 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; -using NSwag.Annotations; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.Entities; @@ -14,10 +13,10 @@ namespace Umbraco.Cms.ManagementApi.Controllers.Media.RecycleBin; [ApiVersion("1.0")] [ApiController] -[VersionedApiBackOfficeRoute($"{Constants.UdiEntityType.Media}/recycle-bin")] +[VersionedApiBackOfficeRoute($"{Constants.Web.RoutePath.RecycleBin}/{Constants.UdiEntityType.Media}")] [RequireMediaTreeRootAccess] [ProducesResponseType(StatusCodes.Status401Unauthorized)] -[OpenApiTag(nameof(Constants.UdiEntityType.Media))] +[ApiExplorerSettings(GroupName = nameof(Constants.UdiEntityType.Media))] public class MediaRecycleBinControllerBase : RecycleBinControllerBase { public MediaRecycleBinControllerBase(IEntityService entityService) diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/Media/Tree/ItemsMediaTreeController.cs b/src/Umbraco.Cms.ManagementApi/Controllers/Media/Tree/ItemsMediaTreeController.cs index 2ebf1a559f..cc6074d49b 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/Media/Tree/ItemsMediaTreeController.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/Media/Tree/ItemsMediaTreeController.cs @@ -20,7 +20,7 @@ public class ItemsMediaTreeController : MediaTreeControllerBase { } - [HttpGet("items")] + [HttpGet("item")] [MapToApiVersion("1.0")] [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] public async Task>> Items([FromQuery(Name = "key")] Guid[] keys, Guid? dataTypeKey = null) diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/Media/Tree/MediaTreeControllerBase.cs b/src/Umbraco.Cms.ManagementApi/Controllers/Media/Tree/MediaTreeControllerBase.cs index c03f05c71d..67e90efe8e 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/Media/Tree/MediaTreeControllerBase.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/Media/Tree/MediaTreeControllerBase.cs @@ -1,5 +1,5 @@ -using Microsoft.AspNetCore.Mvc; -using NSwag.Annotations; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Mvc; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Cache; using Umbraco.Cms.Core.Models; @@ -15,8 +15,8 @@ namespace Umbraco.Cms.ManagementApi.Controllers.Media.Tree; [ApiVersion("1.0")] [ApiController] -[VersionedApiBackOfficeRoute($"{Constants.UdiEntityType.Media}/tree")] -[OpenApiTag(nameof(Constants.UdiEntityType.Media))] +[VersionedApiBackOfficeRoute($"{Constants.Web.RoutePath.Tree}/{Constants.UdiEntityType.Media}")] +[ApiExplorerSettings(GroupName = nameof(Constants.UdiEntityType.Media))] public class MediaTreeControllerBase : UserStartNodeTreeControllerBase { private readonly AppCaches _appCaches; diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/MediaType/Tree/ItemsMediaTypeTreeController.cs b/src/Umbraco.Cms.ManagementApi/Controllers/MediaType/Tree/ItemsMediaTypeTreeController.cs index 363751fee7..309711cd7d 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/MediaType/Tree/ItemsMediaTypeTreeController.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/MediaType/Tree/ItemsMediaTypeTreeController.cs @@ -12,7 +12,7 @@ public class ItemsMediaTypeTreeController : MediaTypeTreeControllerBase { } - [HttpGet("items")] + [HttpGet("item")] [MapToApiVersion("1.0")] [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] public async Task>> Items([FromQuery(Name = "key")] Guid[] keys) diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/MediaType/Tree/MediaTypeTreeControllerBase.cs b/src/Umbraco.Cms.ManagementApi/Controllers/MediaType/Tree/MediaTypeTreeControllerBase.cs index 5b06c46439..d47691df4e 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/MediaType/Tree/MediaTypeTreeControllerBase.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/MediaType/Tree/MediaTypeTreeControllerBase.cs @@ -1,5 +1,4 @@ using Microsoft.AspNetCore.Mvc; -using NSwag.Annotations; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.Entities; @@ -12,8 +11,8 @@ namespace Umbraco.Cms.ManagementApi.Controllers.MediaType.Tree; [ApiVersion("1.0")] [ApiController] -[VersionedApiBackOfficeRoute($"{Constants.UdiEntityType.MediaType}/tree")] -[OpenApiTag(nameof(Constants.UdiEntityType.MediaType))] +[VersionedApiBackOfficeRoute($"{Constants.Web.RoutePath.Tree}/{Constants.UdiEntityType.MediaType}")] +[ApiExplorerSettings(GroupName = "Media Type")] public class MediaTypeTreeControllerBase : FolderTreeControllerBase { private readonly IMediaTypeService _mediaTypeService; diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/MemberGroup/Tree/ItemsMemberGroupTreeController.cs b/src/Umbraco.Cms.ManagementApi/Controllers/MemberGroup/Tree/ItemsMemberGroupTreeController.cs index 94db46be4e..d3be627d30 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/MemberGroup/Tree/ItemsMemberGroupTreeController.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/MemberGroup/Tree/ItemsMemberGroupTreeController.cs @@ -12,7 +12,7 @@ public class ItemsMemberGroupTreeController : MemberGroupTreeControllerBase { } - [HttpGet("items")] + [HttpGet("item")] [MapToApiVersion("1.0")] [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] public async Task>> Items([FromQuery(Name = "key")] Guid[] keys) diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/MemberGroup/Tree/MemberGroupTreeControllerBase.cs b/src/Umbraco.Cms.ManagementApi/Controllers/MemberGroup/Tree/MemberGroupTreeControllerBase.cs index b3ee033a25..455fcf64f7 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/MemberGroup/Tree/MemberGroupTreeControllerBase.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/MemberGroup/Tree/MemberGroupTreeControllerBase.cs @@ -1,5 +1,4 @@ using Microsoft.AspNetCore.Mvc; -using NSwag.Annotations; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.Entities; @@ -12,8 +11,8 @@ namespace Umbraco.Cms.ManagementApi.Controllers.MemberGroup.Tree; [ApiVersion("1.0")] [ApiController] -[VersionedApiBackOfficeRoute($"{Constants.UdiEntityType.MemberGroup}/tree")] -[OpenApiTag(nameof(Constants.UdiEntityType.MemberGroup))] +[VersionedApiBackOfficeRoute($"{Constants.Web.RoutePath.Tree}/{Constants.UdiEntityType.MemberGroup}")] +[ApiExplorerSettings(GroupName = "Member Group")] public class MemberGroupTreeControllerBase : EntityTreeControllerBase { public MemberGroupTreeControllerBase(IEntityService entityService) diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/MemberType/Tree/ItemsMemberTypeTreeController.cs b/src/Umbraco.Cms.ManagementApi/Controllers/MemberType/Tree/ItemsMemberTypeTreeController.cs index 249cdd5d67..e70ca8f0ee 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/MemberType/Tree/ItemsMemberTypeTreeController.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/MemberType/Tree/ItemsMemberTypeTreeController.cs @@ -12,7 +12,7 @@ public class ItemsMemberTypeTreeController : MemberTypeTreeControllerBase { } - [HttpGet("items")] + [HttpGet("item")] [MapToApiVersion("1.0")] [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] public async Task>> Items([FromQuery(Name = "key")] Guid[] keys) diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/MemberType/Tree/MemberTypeTreeControllerBase.cs b/src/Umbraco.Cms.ManagementApi/Controllers/MemberType/Tree/MemberTypeTreeControllerBase.cs index 88183dfd58..2924ad3ba1 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/MemberType/Tree/MemberTypeTreeControllerBase.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/MemberType/Tree/MemberTypeTreeControllerBase.cs @@ -1,5 +1,4 @@ using Microsoft.AspNetCore.Mvc; -using NSwag.Annotations; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.Entities; @@ -12,8 +11,8 @@ namespace Umbraco.Cms.ManagementApi.Controllers.MemberType.Tree; [ApiVersion("1.0")] [ApiController] -[VersionedApiBackOfficeRoute($"{Constants.UdiEntityType.MemberType}/tree")] -[OpenApiTag(nameof(Constants.UdiEntityType.MemberType))] +[VersionedApiBackOfficeRoute($"{Constants.Web.RoutePath.Tree}/{Constants.UdiEntityType.MemberType}")] +[ApiExplorerSettings(GroupName = "Member Type")] public class MemberTypeTreeControllerBase : EntityTreeControllerBase { public MemberTypeTreeControllerBase(IEntityService entityService) diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/ModelsBuilderDashboard/BuildModelsBuilderController.cs b/src/Umbraco.Cms.ManagementApi/Controllers/ModelsBuilder/BuildModelsBuilderController.cs similarity index 96% rename from src/Umbraco.Cms.ManagementApi/Controllers/ModelsBuilderDashboard/BuildModelsBuilderController.cs rename to src/Umbraco.Cms.ManagementApi/Controllers/ModelsBuilder/BuildModelsBuilderController.cs index c219a5128e..7fcf5b5888 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/ModelsBuilderDashboard/BuildModelsBuilderController.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/ModelsBuilder/BuildModelsBuilderController.cs @@ -8,7 +8,7 @@ using Umbraco.Cms.Infrastructure.ModelsBuilder; using Umbraco.Cms.Infrastructure.ModelsBuilder.Building; using Umbraco.Extensions; -namespace Umbraco.Cms.ManagementApi.Controllers.ModelsBuilderDashboard; +namespace Umbraco.Cms.ManagementApi.Controllers.ModelsBuilder; public class BuildModelsBuilderController : ModelsBuilderControllerBase { diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/ModelsBuilderDashboard/GetModelsBuilderController.cs b/src/Umbraco.Cms.ManagementApi/Controllers/ModelsBuilder/GetModelsBuilderController.cs similarity index 73% rename from src/Umbraco.Cms.ManagementApi/Controllers/ModelsBuilderDashboard/GetModelsBuilderController.cs rename to src/Umbraco.Cms.ManagementApi/Controllers/ModelsBuilder/GetModelsBuilderController.cs index aa993cd1f4..b2080ee610 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/ModelsBuilderDashboard/GetModelsBuilderController.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/ModelsBuilder/GetModelsBuilderController.cs @@ -1,10 +1,9 @@ -using System.Threading.Tasks; -using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Umbraco.Cms.ManagementApi.Factories; using Umbraco.Cms.ManagementApi.ViewModels.ModelsBuilderDashboard; -namespace Umbraco.Cms.ManagementApi.Controllers.ModelsBuilderDashboard; +namespace Umbraco.Cms.ManagementApi.Controllers.ModelsBuilder; public class GetModelsBuilderController : ModelsBuilderControllerBase { @@ -12,8 +11,8 @@ public class GetModelsBuilderController : ModelsBuilderControllerBase public GetModelsBuilderController(IModelsBuilderViewModelFactory modelsBuilderViewModelFactory) => _modelsBuilderViewModelFactory = modelsBuilderViewModelFactory; - [HttpGet] - [ProducesResponseType(typeof(CreatedResult), StatusCodes.Status200OK)] + [HttpGet("dashboard")] + [ProducesResponseType(typeof(ModelsBuilderViewModel), StatusCodes.Status200OK)] [MapToApiVersion("1.0")] public async Task> GetDashboard() => await Task.FromResult(Ok(_modelsBuilderViewModelFactory.Create())); } diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/ModelsBuilderDashboard/ModelsBuilderControllerBase.cs b/src/Umbraco.Cms.ManagementApi/Controllers/ModelsBuilder/ModelsBuilderControllerBase.cs similarity index 65% rename from src/Umbraco.Cms.ManagementApi/Controllers/ModelsBuilderDashboard/ModelsBuilderControllerBase.cs rename to src/Umbraco.Cms.ManagementApi/Controllers/ModelsBuilder/ModelsBuilderControllerBase.cs index 4871d3b9d6..aa428d6005 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/ModelsBuilderDashboard/ModelsBuilderControllerBase.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/ModelsBuilder/ModelsBuilderControllerBase.cs @@ -1,12 +1,11 @@ using Microsoft.AspNetCore.Mvc; -using NSwag.Annotations; using Umbraco.New.Cms.Web.Common.Routing; -namespace Umbraco.Cms.ManagementApi.Controllers.ModelsBuilderDashboard; +namespace Umbraco.Cms.ManagementApi.Controllers.ModelsBuilder; [ApiController] [VersionedApiBackOfficeRoute("models-builder")] -[OpenApiTag("ModelsBuilder")] +[ApiExplorerSettings(GroupName = "Models Builder")] [ApiVersion("1.0")] public class ModelsBuilderControllerBase : ManagementApiControllerBase diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/ModelsBuilderDashboard/StatusModelsBuilderController.cs b/src/Umbraco.Cms.ManagementApi/Controllers/ModelsBuilder/StatusModelsBuilderController.cs similarity index 94% rename from src/Umbraco.Cms.ManagementApi/Controllers/ModelsBuilderDashboard/StatusModelsBuilderController.cs rename to src/Umbraco.Cms.ManagementApi/Controllers/ModelsBuilder/StatusModelsBuilderController.cs index 9b2cb22e0a..1f130ffb5c 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/ModelsBuilderDashboard/StatusModelsBuilderController.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/ModelsBuilder/StatusModelsBuilderController.cs @@ -5,7 +5,7 @@ using Umbraco.Cms.Infrastructure.ModelsBuilder; using Umbraco.Cms.ManagementApi.ViewModels.ModelsBuilderDashboard; using Umbraco.New.Cms.Core.Models; -namespace Umbraco.Cms.ManagementApi.Controllers.ModelsBuilderDashboard; +namespace Umbraco.Cms.ManagementApi.Controllers.ModelsBuilder; public class StatusModelsBuilderController : ModelsBuilderControllerBase { diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/PartialView/Tree/ItemsPartialViewTreeController.cs b/src/Umbraco.Cms.ManagementApi/Controllers/PartialView/Tree/ItemsPartialViewTreeController.cs index d6107a844a..5a1567028c 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/PartialView/Tree/ItemsPartialViewTreeController.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/PartialView/Tree/ItemsPartialViewTreeController.cs @@ -12,7 +12,7 @@ public class ItemsPartialViewTreeController : PartialViewTreeControllerBase { } - [HttpGet("items")] + [HttpGet("item")] [MapToApiVersion("1.0")] [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] public async Task>> Items([FromQuery(Name = "path")] string[] paths) diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/PartialView/Tree/PartialViewTreeControllerBase.cs b/src/Umbraco.Cms.ManagementApi/Controllers/PartialView/Tree/PartialViewTreeControllerBase.cs index 95ad0eb6cf..ba2420e851 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/PartialView/Tree/PartialViewTreeControllerBase.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/PartialView/Tree/PartialViewTreeControllerBase.cs @@ -1,5 +1,4 @@ using Microsoft.AspNetCore.Mvc; -using NSwag.Annotations; using Umbraco.Cms.Core; using Umbraco.Cms.Core.IO; using Umbraco.Cms.ManagementApi.Controllers.Tree; @@ -9,8 +8,8 @@ namespace Umbraco.Cms.ManagementApi.Controllers.PartialView.Tree; [ApiVersion("1.0")] [ApiController] -[VersionedApiBackOfficeRoute($"{Constants.UdiEntityType.PartialView}/tree")] -[OpenApiTag(nameof(Constants.UdiEntityType.PartialView))] +[VersionedApiBackOfficeRoute($"{Constants.Web.RoutePath.Tree}/{Constants.UdiEntityType.PartialView}")] +[ApiExplorerSettings(GroupName = "Partial View")] public class PartialViewTreeControllerBase : FileSystemTreeControllerBase { public PartialViewTreeControllerBase(FileSystems fileSystems) diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/Profiling/ProfilingControllerBase.cs b/src/Umbraco.Cms.ManagementApi/Controllers/Profiling/ProfilingControllerBase.cs index c081f74fe0..f1919b2501 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/Profiling/ProfilingControllerBase.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/Profiling/ProfilingControllerBase.cs @@ -1,5 +1,4 @@ using Microsoft.AspNetCore.Mvc; -using NSwag.Annotations; using Umbraco.New.Cms.Web.Common.Routing; namespace Umbraco.Cms.ManagementApi.Controllers.Profiling; @@ -7,7 +6,7 @@ namespace Umbraco.Cms.ManagementApi.Controllers.Profiling; [ApiVersion("1.0")] [ApiController] [VersionedApiBackOfficeRoute("profiling")] -[OpenApiTag("Profiling")] +[ApiExplorerSettings(GroupName = "Profiling")] public class ProfilingControllerBase : ManagementApiControllerBase { } diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/PublishedCache/PublishedCacheControllerBase.cs b/src/Umbraco.Cms.ManagementApi/Controllers/PublishedCache/PublishedCacheControllerBase.cs index 78dcd539f4..914775a563 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/PublishedCache/PublishedCacheControllerBase.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/PublishedCache/PublishedCacheControllerBase.cs @@ -1,5 +1,4 @@ using Microsoft.AspNetCore.Mvc; -using NSwag.Annotations; using Umbraco.New.Cms.Web.Common.Routing; namespace Umbraco.Cms.ManagementApi.Controllers.PublishedCache; @@ -7,7 +6,7 @@ namespace Umbraco.Cms.ManagementApi.Controllers.PublishedCache; [ApiVersion("1.0")] [ApiController] [VersionedApiBackOfficeRoute("published-cache")] -[OpenApiTag("PublishedCache")] +[ApiExplorerSettings(GroupName = "Published Cache")] public class PublishedCacheControllerBase : ManagementApiControllerBase { } diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/Relation/ByChildRelationController.cs b/src/Umbraco.Cms.ManagementApi/Controllers/Relation/ByChildRelationController.cs index 4639fa7bea..8d1e88c806 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/Relation/ByChildRelationController.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/Relation/ByChildRelationController.cs @@ -22,7 +22,7 @@ public class ByChildRelationController : RelationControllerBase _relationViewModelFactory = relationViewModelFactory; } - [HttpGet("child-relations/{childId:int}")] + [HttpGet("child-relation/{childId:int}")] [MapToApiVersion("1.0")] [ProducesResponseType(typeof(PagedViewModel), StatusCodes.Status200OK)] public async Task> ByChild(int childId, int skip, int take, string? relationTypeAlias = "") diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/Relation/RelationControllerBase.cs b/src/Umbraco.Cms.ManagementApi/Controllers/Relation/RelationControllerBase.cs index 7ec26735d1..65266ef356 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/Relation/RelationControllerBase.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/Relation/RelationControllerBase.cs @@ -1,12 +1,11 @@ using Microsoft.AspNetCore.Mvc; -using NSwag.Annotations; using Umbraco.New.Cms.Web.Common.Routing; namespace Umbraco.Cms.ManagementApi.Controllers.Relation; [ApiController] [VersionedApiBackOfficeRoute("relation")] -[OpenApiTag("Relation")] +[ApiExplorerSettings(GroupName = "Relation")] [ApiVersion("1.0")] // TODO: Implement Authentication public abstract class RelationControllerBase : ManagementApiControllerBase diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/RelationType/Tree/ItemsRelationTypeTreeController.cs b/src/Umbraco.Cms.ManagementApi/Controllers/RelationType/Tree/ItemsRelationTypeTreeController.cs index 7e2054a594..ca3f6ff7de 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/RelationType/Tree/ItemsRelationTypeTreeController.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/RelationType/Tree/ItemsRelationTypeTreeController.cs @@ -14,7 +14,7 @@ public class ItemsRelationTypeTreeController : RelationTypeTreeControllerBase : base(entityService) => _relationService = relationService; - [HttpGet("items")] + [HttpGet("item")] [MapToApiVersion("1.0")] [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] public async Task>> Items([FromQuery(Name = "key")] Guid[] keys) diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/RelationType/Tree/RelationTypeTreeControllerBase.cs b/src/Umbraco.Cms.ManagementApi/Controllers/RelationType/Tree/RelationTypeTreeControllerBase.cs index c90c124686..c3497e7a1d 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/RelationType/Tree/RelationTypeTreeControllerBase.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/RelationType/Tree/RelationTypeTreeControllerBase.cs @@ -1,5 +1,4 @@ using Microsoft.AspNetCore.Mvc; -using NSwag.Annotations; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Services; @@ -11,8 +10,8 @@ namespace Umbraco.Cms.ManagementApi.Controllers.RelationType.Tree; [ApiVersion("1.0")] [ApiController] -[VersionedApiBackOfficeRoute($"{Constants.UdiEntityType.RelationType}/tree")] -[OpenApiTag(nameof(Constants.UdiEntityType.RelationType))] +[VersionedApiBackOfficeRoute($"{Constants.Web.RoutePath.Tree}/{Constants.UdiEntityType.RelationType}")] +[ApiExplorerSettings(GroupName = "Relation Type")] // NOTE: at the moment relation types aren't supported by EntityService, so we have little use of the // tree controller base. We'll keep it though, in the hope that we can mend EntityService. public class RelationTypeTreeControllerBase : EntityTreeControllerBase diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/Script/Tree/ItemsScriptTreeController.cs b/src/Umbraco.Cms.ManagementApi/Controllers/Script/Tree/ItemsScriptTreeController.cs index 99cd6d990e..642fcb63be 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/Script/Tree/ItemsScriptTreeController.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/Script/Tree/ItemsScriptTreeController.cs @@ -12,7 +12,7 @@ public class ItemsScriptTreeController : ScriptTreeControllerBase { } - [HttpGet("items")] + [HttpGet("item")] [MapToApiVersion("1.0")] [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] public async Task>> Items([FromQuery(Name = "path")] string[] paths) diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/Script/Tree/ScriptTreeControllerBase.cs b/src/Umbraco.Cms.ManagementApi/Controllers/Script/Tree/ScriptTreeControllerBase.cs index 4e204da4ee..f0f7398141 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/Script/Tree/ScriptTreeControllerBase.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/Script/Tree/ScriptTreeControllerBase.cs @@ -1,5 +1,4 @@ using Microsoft.AspNetCore.Mvc; -using NSwag.Annotations; using Umbraco.Cms.Core; using Umbraco.Cms.Core.IO; using Umbraco.Cms.ManagementApi.Controllers.Tree; @@ -9,8 +8,8 @@ namespace Umbraco.Cms.ManagementApi.Controllers.Script.Tree; [ApiVersion("1.0")] [ApiController] -[VersionedApiBackOfficeRoute($"{Constants.UdiEntityType.Script}/tree")] -[OpenApiTag(nameof(Constants.UdiEntityType.Script))] +[VersionedApiBackOfficeRoute($"{Constants.Web.RoutePath.Tree}/{Constants.UdiEntityType.Script}")] +[ApiExplorerSettings(GroupName = nameof(Constants.UdiEntityType.Script))] public class ScriptTreeControllerBase : FileSystemTreeControllerBase { public ScriptTreeControllerBase(FileSystems fileSystems) diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/Search/SearchControllerBase.cs b/src/Umbraco.Cms.ManagementApi/Controllers/Search/SearchControllerBase.cs index 2ab98aa2ff..9d3befc022 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/Search/SearchControllerBase.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/Search/SearchControllerBase.cs @@ -1,12 +1,11 @@ using Microsoft.AspNetCore.Mvc; -using NSwag.Annotations; using Umbraco.New.Cms.Web.Common.Routing; namespace Umbraco.Cms.ManagementApi.Controllers.Search; [ApiController] [VersionedApiBackOfficeRoute("search")] -[OpenApiTag("Search")] +[ApiExplorerSettings(GroupName = "Search")] public class SearchControllerBase : ManagementApiControllerBase { } diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/Security/BackOfficeController.cs b/src/Umbraco.Cms.ManagementApi/Controllers/Security/BackOfficeController.cs new file mode 100644 index 0000000000..74ce67ed03 --- /dev/null +++ b/src/Umbraco.Cms.ManagementApi/Controllers/Security/BackOfficeController.cs @@ -0,0 +1,76 @@ +using System.Security.Claims; +using Microsoft.AspNetCore; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using OpenIddict.Abstractions; +using OpenIddict.Server.AspNetCore; +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Security; +using Umbraco.Cms.Web.BackOffice.Security; +using Umbraco.Extensions; +using Umbraco.New.Cms.Web.Common.Routing; + +namespace Umbraco.Cms.ManagementApi.Controllers.Security; + +[ApiController] +[VersionedApiBackOfficeRoute(Paths.BackOfficeApiEndpointTemplate)] +[ApiExplorerSettings(GroupName = "Security")] +public class BackOfficeController : ManagementApiControllerBase +{ + private readonly IHttpContextAccessor _httpContextAccessor; + private readonly IBackOfficeSignInManager _backOfficeSignInManager; + private readonly IBackOfficeUserManager _backOfficeUserManager; + + public BackOfficeController(IHttpContextAccessor httpContextAccessor, IBackOfficeSignInManager backOfficeSignInManager, IBackOfficeUserManager backOfficeUserManager) + { + _httpContextAccessor = httpContextAccessor; + _backOfficeSignInManager = backOfficeSignInManager; + _backOfficeUserManager = backOfficeUserManager; + } + + [HttpGet("authorize")] + [HttpPost("authorize")] + [MapToApiVersion("1.0")] + public async Task Authorize() + { + HttpContext context = _httpContextAccessor.GetRequiredHttpContext(); + OpenIddictRequest? request = context.GetOpenIddictServerRequest(); + if (request == null) + { + return BadRequest("Unable to obtain OpenID data from the current request"); + } + + // retrieve the user principal stored in the authentication cookie. + AuthenticateResult cookieAuthResult = await HttpContext.AuthenticateAsync(Constants.Security.BackOfficeAuthenticationType); + if (cookieAuthResult.Succeeded && cookieAuthResult.Principal?.Identity?.Name != null) + { + BackOfficeIdentityUser? backOfficeUser = await _backOfficeUserManager.FindByNameAsync(cookieAuthResult.Principal.Identity.Name); + if (backOfficeUser != null) + { + ClaimsPrincipal backOfficePrincipal = await _backOfficeSignInManager.CreateUserPrincipalAsync(backOfficeUser); + backOfficePrincipal.SetClaim(OpenIddictConstants.Claims.Subject, backOfficeUser.Key.ToString()); + + // TODO: it is not optimal to append all claims to the token. + // the token size grows with each claim, although it is still smaller than the old cookie. + // see if we can find a better way so we do not risk leaking sensitive data in bearer tokens. + // maybe work with scopes instead? + Claim[] backOfficeClaims = backOfficePrincipal.Claims.ToArray(); + foreach (Claim backOfficeClaim in backOfficeClaims) + { + backOfficeClaim.SetDestinations(OpenIddictConstants.Destinations.AccessToken); + } + + if (request.GetScopes().Contains(OpenIddictConstants.Scopes.OfflineAccess)) + { + // "offline_access" scope is required to use refresh tokens + backOfficePrincipal.SetScopes(OpenIddictConstants.Scopes.OfflineAccess); + } + + return new SignInResult(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, backOfficePrincipal); + } + } + + return new ChallengeResult(new[] { Constants.Security.BackOfficeAuthenticationType }); + } +} diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/Security/Paths.cs b/src/Umbraco.Cms.ManagementApi/Controllers/Security/Paths.cs new file mode 100644 index 0000000000..3ce1b7c3c6 --- /dev/null +++ b/src/Umbraco.Cms.ManagementApi/Controllers/Security/Paths.cs @@ -0,0 +1,12 @@ +namespace Umbraco.Cms.ManagementApi.Controllers.Security; + +public static class Paths +{ + public const string BackOfficeApiEndpointTemplate = "security/back-office"; + + public static string BackOfficeApiAuthorizationEndpoint = BackOfficeApiEndpointPath($"{BackOfficeApiEndpointTemplate}/authorize"); + + public static string BackOfficeApiTokenEndpoint = BackOfficeApiEndpointPath($"{BackOfficeApiEndpointTemplate}/token"); + + private static string BackOfficeApiEndpointPath(string relativePath) => $"/umbraco/management/api/v1.0/{relativePath}"; +} diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/Server/ServerControllerBase.cs b/src/Umbraco.Cms.ManagementApi/Controllers/Server/ServerControllerBase.cs index 9dd6b3a192..11674dcc23 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/Server/ServerControllerBase.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/Server/ServerControllerBase.cs @@ -1,12 +1,11 @@ using Microsoft.AspNetCore.Mvc; -using NSwag.Annotations; using Umbraco.New.Cms.Web.Common.Routing; namespace Umbraco.Cms.ManagementApi.Controllers.Server; [ApiController] [VersionedApiBackOfficeRoute("server")] -[OpenApiTag("Server")] +[ApiExplorerSettings(GroupName = "Server")] public abstract class ServerControllerBase : ManagementApiControllerBase { diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/StaticFile/Tree/ItemsStaticFileTreeController.cs b/src/Umbraco.Cms.ManagementApi/Controllers/StaticFile/Tree/ItemsStaticFileTreeController.cs index 205f92d94f..1b8bb4b8b8 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/StaticFile/Tree/ItemsStaticFileTreeController.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/StaticFile/Tree/ItemsStaticFileTreeController.cs @@ -12,7 +12,7 @@ public class ItemsStaticFileTreeController : StaticFileTreeControllerBase { } - [HttpGet("items")] + [HttpGet("item")] [MapToApiVersion("1.0")] [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] public async Task>> Items([FromQuery(Name = "path")] string[] paths) diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/StaticFile/Tree/StaticFileTreeControllerBase.cs b/src/Umbraco.Cms.ManagementApi/Controllers/StaticFile/Tree/StaticFileTreeControllerBase.cs index ec50a54495..a66898619a 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/StaticFile/Tree/StaticFileTreeControllerBase.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/StaticFile/Tree/StaticFileTreeControllerBase.cs @@ -1,5 +1,4 @@ using Microsoft.AspNetCore.Mvc; -using NSwag.Annotations; using Umbraco.Cms.Core; using Umbraco.Cms.Core.IO; using Umbraco.Cms.ManagementApi.Controllers.Tree; @@ -9,8 +8,8 @@ namespace Umbraco.Cms.ManagementApi.Controllers.StaticFile.Tree; [ApiVersion("1.0")] [ApiController] -[VersionedApiBackOfficeRoute("static-file/tree")] -[OpenApiTag("StaticFile")] +[VersionedApiBackOfficeRoute($"{Constants.Web.RoutePath.Tree}/static-file")] +[ApiExplorerSettings(GroupName = "Static File")] public class StaticFileTreeControllerBase : FileSystemTreeControllerBase { private static readonly string[] _allowedRootFolders = { "App_Plugins", "wwwroot" }; diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/Stylesheet/Tree/ItemsStylesheetTreeController.cs b/src/Umbraco.Cms.ManagementApi/Controllers/Stylesheet/Tree/ItemsStylesheetTreeController.cs index de2e779ba1..12b04a9c08 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/Stylesheet/Tree/ItemsStylesheetTreeController.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/Stylesheet/Tree/ItemsStylesheetTreeController.cs @@ -12,7 +12,7 @@ public class ItemsStylesheetTreeController : StylesheetTreeControllerBase { } - [HttpGet("items")] + [HttpGet("item")] [MapToApiVersion("1.0")] [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] public async Task>> Items([FromQuery(Name = "path")] string[] paths) diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/Stylesheet/Tree/StylesheetTreeControllerBase.cs b/src/Umbraco.Cms.ManagementApi/Controllers/Stylesheet/Tree/StylesheetTreeControllerBase.cs index b529752293..c0fe829806 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/Stylesheet/Tree/StylesheetTreeControllerBase.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/Stylesheet/Tree/StylesheetTreeControllerBase.cs @@ -1,5 +1,4 @@ using Microsoft.AspNetCore.Mvc; -using NSwag.Annotations; using Umbraco.Cms.Core; using Umbraco.Cms.Core.IO; using Umbraco.Cms.ManagementApi.Controllers.Tree; @@ -9,8 +8,8 @@ namespace Umbraco.Cms.ManagementApi.Controllers.Stylesheet.Tree; [ApiVersion("1.0")] [ApiController] -[VersionedApiBackOfficeRoute($"{Constants.UdiEntityType.Stylesheet}/tree")] -[OpenApiTag(nameof(Constants.UdiEntityType.Stylesheet))] +[VersionedApiBackOfficeRoute($"{Constants.Web.RoutePath.Tree}/{Constants.UdiEntityType.Stylesheet}")] +[ApiExplorerSettings(GroupName = nameof(Constants.UdiEntityType.Stylesheet))] public class StylesheetTreeControllerBase : FileSystemTreeControllerBase { public StylesheetTreeControllerBase(FileSystems fileSystems) diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/Telemetry/AllTelemetryController.cs b/src/Umbraco.Cms.ManagementApi/Controllers/Telemetry/AllTelemetryController.cs new file mode 100644 index 0000000000..7e3eed886b --- /dev/null +++ b/src/Umbraco.Cms.ManagementApi/Controllers/Telemetry/AllTelemetryController.cs @@ -0,0 +1,23 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.ManagementApi.ViewModels.Pagination; +using Umbraco.Cms.ManagementApi.ViewModels.Telemetry; + +namespace Umbraco.Cms.ManagementApi.Controllers.Telemetry; + +public class AllTelemetryController : TelemetryControllerBase +{ + [HttpGet] + [MapToApiVersion("1.0")] + [ProducesResponseType(typeof(PagedViewModel), StatusCodes.Status200OK)] + public async Task> GetAll(int skip, int take) + { + TelemetryLevel[] levels = Enum.GetValues(); + return await Task.FromResult(new PagedViewModel + { + Total = levels.Length, + Items = levels.Skip(skip).Take(take).Select(level => new TelemetryViewModel { TelemetryLevel = level }), + }); + } +} diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/Telemetry/GetTelemetryController.cs b/src/Umbraco.Cms.ManagementApi/Controllers/Telemetry/GetTelemetryController.cs new file mode 100644 index 0000000000..3e6323343b --- /dev/null +++ b/src/Umbraco.Cms.ManagementApi/Controllers/Telemetry/GetTelemetryController.cs @@ -0,0 +1,18 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.ManagementApi.ViewModels.Telemetry; + +namespace Umbraco.Cms.ManagementApi.Controllers.Telemetry; + +public class GetTelemetryController : TelemetryControllerBase +{ + private readonly IMetricsConsentService _metricsConsentService; + + public GetTelemetryController(IMetricsConsentService metricsConsentService) => _metricsConsentService = metricsConsentService; + + [HttpGet("level")] + [MapToApiVersion("1.0")] + [ProducesResponseType(typeof(TelemetryViewModel), StatusCodes.Status200OK)] + public async Task Get() => await Task.FromResult(new TelemetryViewModel { TelemetryLevel = _metricsConsentService.GetConsentLevel() }); +} diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/Analytics/SetAnalyticsController.cs b/src/Umbraco.Cms.ManagementApi/Controllers/Telemetry/SetTelemetryController.cs similarity index 51% rename from src/Umbraco.Cms.ManagementApi/Controllers/Analytics/SetAnalyticsController.cs rename to src/Umbraco.Cms.ManagementApi/Controllers/Telemetry/SetTelemetryController.cs index cfdd1e8b4f..0687997ff0 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/Analytics/SetAnalyticsController.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/Telemetry/SetTelemetryController.cs @@ -1,36 +1,35 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Umbraco.Cms.Core.Services; -using Umbraco.Cms.ManagementApi.ViewModels.Analytics; -using Umbraco.Cms.ManagementApi.ViewModels.Server; +using Umbraco.Cms.ManagementApi.ViewModels.Telemetry; -namespace Umbraco.Cms.ManagementApi.Controllers.Analytics; +namespace Umbraco.Cms.ManagementApi.Controllers.Telemetry; -public class SetAnalyticsController : AnalyticsControllerBase +public class SetTelemetryController : TelemetryControllerBase { private readonly IMetricsConsentService _metricsConsentService; - public SetAnalyticsController(IMetricsConsentService metricsConsentService) => _metricsConsentService = metricsConsentService; + public SetTelemetryController(IMetricsConsentService metricsConsentService) => _metricsConsentService = metricsConsentService; - [HttpPost] + [HttpPost("level")] [MapToApiVersion("1.0")] [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)] [ProducesResponseType(StatusCodes.Status200OK)] - public async Task SetConsentLevel(AnalyticsLevelViewModel analyticsLevelViewModel) + public async Task SetConsentLevel(TelemetryViewModel telemetryViewModel) { - if (!Enum.IsDefined(analyticsLevelViewModel.AnalyticsLevel)) + if (!Enum.IsDefined(telemetryViewModel.TelemetryLevel)) { var invalidModelProblem = new ProblemDetails { - Title = "Invalid AnalyticsLevel value", - Detail = "The provided value for AnalyticsLevel is not valid", + Title = "Invalid TelemetryLevel value", + Detail = "The provided value for TelemetryLevel is not valid", Status = StatusCodes.Status400BadRequest, Type = "Error", }; return BadRequest(invalidModelProblem); } - _metricsConsentService.SetConsentLevel(analyticsLevelViewModel.AnalyticsLevel); + _metricsConsentService.SetConsentLevel(telemetryViewModel.TelemetryLevel); return await Task.FromResult(Ok()); } } diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/Telemetry/TelemetryControllerBase.cs b/src/Umbraco.Cms.ManagementApi/Controllers/Telemetry/TelemetryControllerBase.cs new file mode 100644 index 0000000000..ea5835b2ca --- /dev/null +++ b/src/Umbraco.Cms.ManagementApi/Controllers/Telemetry/TelemetryControllerBase.cs @@ -0,0 +1,12 @@ +using Microsoft.AspNetCore.Mvc; +using Umbraco.New.Cms.Web.Common.Routing; + +namespace Umbraco.Cms.ManagementApi.Controllers.Telemetry; + +[ApiController] +[VersionedApiBackOfficeRoute("telemetry")] +[ApiExplorerSettings(GroupName = "Telemetry")] +[ApiVersion("1.0")] +public abstract class TelemetryControllerBase : ManagementApiControllerBase +{ +} diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/Template/Tree/ItemsTemplateTreeController.cs b/src/Umbraco.Cms.ManagementApi/Controllers/Template/Tree/ItemsTemplateTreeController.cs index fb4a29c621..877f740df7 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/Template/Tree/ItemsTemplateTreeController.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/Template/Tree/ItemsTemplateTreeController.cs @@ -12,7 +12,7 @@ public class ItemsTemplateTreeController : TemplateTreeControllerBase { } - [HttpGet("items")] + [HttpGet("item")] [MapToApiVersion("1.0")] [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] public async Task>> Items([FromQuery(Name = "key")] Guid[] keys) diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/Template/Tree/TemplateTreeControllerBase.cs b/src/Umbraco.Cms.ManagementApi/Controllers/Template/Tree/TemplateTreeControllerBase.cs index be885f26be..c27206c665 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/Template/Tree/TemplateTreeControllerBase.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/Template/Tree/TemplateTreeControllerBase.cs @@ -1,5 +1,4 @@ using Microsoft.AspNetCore.Mvc; -using NSwag.Annotations; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.Entities; @@ -12,8 +11,8 @@ namespace Umbraco.Cms.ManagementApi.Controllers.Template.Tree; [ApiVersion("1.0")] [ApiController] -[VersionedApiBackOfficeRoute($"{Constants.UdiEntityType.Template}/tree")] -[OpenApiTag(nameof(Constants.UdiEntityType.Template))] +[VersionedApiBackOfficeRoute($"{Constants.Web.RoutePath.Tree}/{Constants.UdiEntityType.Template}")] +[ApiExplorerSettings(GroupName = nameof(Constants.UdiEntityType.Template))] public class TemplateTreeControllerBase : EntityTreeControllerBase { public TemplateTreeControllerBase(IEntityService entityService) diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/TrackedReferences/ForItemTrackedReferencesController.cs b/src/Umbraco.Cms.ManagementApi/Controllers/TrackedReference/ByIdTrackedReferenceController.cs similarity index 89% rename from src/Umbraco.Cms.ManagementApi/Controllers/TrackedReferences/ForItemTrackedReferencesController.cs rename to src/Umbraco.Cms.ManagementApi/Controllers/TrackedReference/ByIdTrackedReferenceController.cs index a415cf08bf..3c1998a7e4 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/TrackedReferences/ForItemTrackedReferencesController.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/TrackedReference/ByIdTrackedReferenceController.cs @@ -7,14 +7,14 @@ using Umbraco.Cms.ManagementApi.ViewModels.Pagination; using Umbraco.Cms.ManagementApi.ViewModels.TrackedReferences; using Umbraco.New.Cms.Core.Models; -namespace Umbraco.Cms.ManagementApi.Controllers.TrackedReferences; +namespace Umbraco.Cms.ManagementApi.Controllers.TrackedReference; -public class ForItemTrackedReferencesController : TrackedReferencesControllerBase +public class ByIdTrackedReferenceController : TrackedReferenceControllerBase { private readonly ITrackedReferencesService _trackedReferencesService; private readonly IUmbracoMapper _umbracoMapper; - public ForItemTrackedReferencesController(ITrackedReferencesService trackedReferencesService, IUmbracoMapper umbracoMapper) + public ByIdTrackedReferenceController(ITrackedReferencesService trackedReferencesService, IUmbracoMapper umbracoMapper) { _trackedReferencesService = trackedReferencesService; _umbracoMapper = umbracoMapper; diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/TrackedReferences/DescendantsTrackedReferencesController.cs b/src/Umbraco.Cms.ManagementApi/Controllers/TrackedReference/DescendantsTrackedReferenceController.cs similarity index 89% rename from src/Umbraco.Cms.ManagementApi/Controllers/TrackedReferences/DescendantsTrackedReferencesController.cs rename to src/Umbraco.Cms.ManagementApi/Controllers/TrackedReference/DescendantsTrackedReferenceController.cs index ecac832a84..20f119d173 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/TrackedReferences/DescendantsTrackedReferencesController.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/TrackedReference/DescendantsTrackedReferenceController.cs @@ -7,14 +7,14 @@ using Umbraco.Cms.ManagementApi.ViewModels.Pagination; using Umbraco.Cms.ManagementApi.ViewModels.TrackedReferences; using Umbraco.New.Cms.Core.Models; -namespace Umbraco.Cms.ManagementApi.Controllers.TrackedReferences; +namespace Umbraco.Cms.ManagementApi.Controllers.TrackedReference; -public class DescendantsTrackedReferencesController : TrackedReferencesControllerBase +public class DescendantsTrackedReferenceController : TrackedReferenceControllerBase { private readonly ITrackedReferencesService _trackedReferencesSkipTakeService; private readonly IUmbracoMapper _umbracoMapper; - public DescendantsTrackedReferencesController(ITrackedReferencesService trackedReferencesSkipTakeService, IUmbracoMapper umbracoMapper) + public DescendantsTrackedReferenceController(ITrackedReferencesService trackedReferencesSkipTakeService, IUmbracoMapper umbracoMapper) { _trackedReferencesSkipTakeService = trackedReferencesSkipTakeService; _umbracoMapper = umbracoMapper; diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/TrackedReferences/MultipleTrackedReferencesController.cs b/src/Umbraco.Cms.ManagementApi/Controllers/TrackedReference/ItemsTrackedReferenceController.cs similarity index 87% rename from src/Umbraco.Cms.ManagementApi/Controllers/TrackedReferences/MultipleTrackedReferencesController.cs rename to src/Umbraco.Cms.ManagementApi/Controllers/TrackedReference/ItemsTrackedReferenceController.cs index 041d208915..39ad9c2560 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/TrackedReferences/MultipleTrackedReferencesController.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/TrackedReference/ItemsTrackedReferenceController.cs @@ -7,14 +7,14 @@ using Umbraco.Cms.ManagementApi.ViewModels.Pagination; using Umbraco.Cms.ManagementApi.ViewModels.TrackedReferences; using Umbraco.New.Cms.Core.Models; -namespace Umbraco.Cms.ManagementApi.Controllers.TrackedReferences; +namespace Umbraco.Cms.ManagementApi.Controllers.TrackedReference; -public class MultipleTrackedReferencesController : TrackedReferencesControllerBase +public class ItemsTrackedReferenceController : TrackedReferenceControllerBase { private readonly ITrackedReferencesService _trackedReferencesSkipTakeService; private readonly IUmbracoMapper _umbracoMapper; - public MultipleTrackedReferencesController(ITrackedReferencesService trackedReferencesSkipTakeService, IUmbracoMapper umbracoMapper) + public ItemsTrackedReferenceController(ITrackedReferencesService trackedReferencesSkipTakeService, IUmbracoMapper umbracoMapper) { _trackedReferencesSkipTakeService = trackedReferencesSkipTakeService; _umbracoMapper = umbracoMapper; @@ -27,7 +27,7 @@ public class MultipleTrackedReferencesController : TrackedReferencesControllerBa /// Used when bulk deleting content/media and bulk unpublishing content (delete and unpublish on List view). /// This is basically finding children of relations. /// - [HttpGet("multiple")] + [HttpGet("item")] [MapToApiVersion("1.0")] [ProducesResponseType(typeof(PagedViewModel), StatusCodes.Status200OK)] public async Task>> GetPagedReferencedItems([FromQuery]int[] ids, long skip, long take, bool? filterMustBeIsDependency) diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/TrackedReference/TrackedReferencesControllerBase.cs b/src/Umbraco.Cms.ManagementApi/Controllers/TrackedReference/TrackedReferencesControllerBase.cs new file mode 100644 index 0000000000..3b62a0fe69 --- /dev/null +++ b/src/Umbraco.Cms.ManagementApi/Controllers/TrackedReference/TrackedReferencesControllerBase.cs @@ -0,0 +1,12 @@ +using Microsoft.AspNetCore.Mvc; +using Umbraco.New.Cms.Web.Common.Routing; + +namespace Umbraco.Cms.ManagementApi.Controllers.TrackedReference; + +[ApiController] +[VersionedApiBackOfficeRoute("tracked-reference")] +[ApiExplorerSettings(GroupName = "Tracked Reference")] +[ApiVersion("1.0")] +public abstract class TrackedReferenceControllerBase : ManagementApiControllerBase +{ +} diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/TrackedReferences/TrackedReferencesControllerBase.cs b/src/Umbraco.Cms.ManagementApi/Controllers/TrackedReferences/TrackedReferencesControllerBase.cs deleted file mode 100644 index be40c80bf1..0000000000 --- a/src/Umbraco.Cms.ManagementApi/Controllers/TrackedReferences/TrackedReferencesControllerBase.cs +++ /dev/null @@ -1,13 +0,0 @@ -using Microsoft.AspNetCore.Mvc; -using NSwag.Annotations; -using Umbraco.New.Cms.Web.Common.Routing; - -namespace Umbraco.Cms.ManagementApi.Controllers.TrackedReferences; - -[ApiController] -[VersionedApiBackOfficeRoute("tracked-references")] -[OpenApiTag("TrackedReferences")] -[ApiVersion("1.0")] -public abstract class TrackedReferencesControllerBase : ManagementApiControllerBase -{ -} diff --git a/src/Umbraco.Cms.ManagementApi/Controllers/Upgrade/UpgradeControllerBase.cs b/src/Umbraco.Cms.ManagementApi/Controllers/Upgrade/UpgradeControllerBase.cs index 084515aba2..6e8e056280 100644 --- a/src/Umbraco.Cms.ManagementApi/Controllers/Upgrade/UpgradeControllerBase.cs +++ b/src/Umbraco.Cms.ManagementApi/Controllers/Upgrade/UpgradeControllerBase.cs @@ -1,5 +1,4 @@ using Microsoft.AspNetCore.Mvc; -using NSwag.Annotations; using Umbraco.Cms.Core; using Umbraco.Cms.ManagementApi.Filters; using Umbraco.New.Cms.Web.Common.Routing; @@ -11,7 +10,7 @@ namespace Umbraco.Cms.ManagementApi.Controllers.Upgrade; [ApiController] [RequireRuntimeLevel(RuntimeLevel.Upgrade)] [VersionedApiBackOfficeRoute("upgrade")] -[OpenApiTag("Upgrade")] +[ApiExplorerSettings(GroupName = "Upgrade")] public abstract class UpgradeControllerBase : ManagementApiControllerBase { diff --git a/src/Umbraco.Cms.ManagementApi/DependencyInjection/BackOfficeAuthBuilderExtensions.cs b/src/Umbraco.Cms.ManagementApi/DependencyInjection/BackOfficeAuthBuilderExtensions.cs new file mode 100644 index 0000000000..5331acaaa9 --- /dev/null +++ b/src/Umbraco.Cms.ManagementApi/DependencyInjection/BackOfficeAuthBuilderExtensions.cs @@ -0,0 +1,145 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Hosting; +using OpenIddict.Validation.AspNetCore; +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.DependencyInjection; +using Umbraco.Cms.ManagementApi.Middleware; +using Umbraco.Cms.ManagementApi.Security; +using Umbraco.Cms.Web.Common.Authorization; +using Umbraco.New.Cms.Infrastructure.HostedServices; +using Umbraco.New.Cms.Infrastructure.Security; + +namespace Umbraco.Cms.ManagementApi.DependencyInjection; + +public static class BackOfficeAuthBuilderExtensions +{ + public static IUmbracoBuilder AddBackOfficeAuthentication(this IUmbracoBuilder builder) + { + builder + .AddDbContext() + .AddOpenIddict(); + + return builder; + } + + private static IUmbracoBuilder AddDbContext(this IUmbracoBuilder builder) + { + builder.Services.AddDbContext(options => + { + // Configure the DB context + // TODO: use actual Umbraco DbContext once EF is implemented - and remove dependency on Microsoft.EntityFrameworkCore.InMemory + options.UseInMemoryDatabase(nameof(DbContext)); + + // Register the entity sets needed by OpenIddict. + options.UseOpenIddict(); + }); + + return builder; + } + + private static IUmbracoBuilder AddOpenIddict(this IUmbracoBuilder builder) + { + builder.Services.AddAuthentication(); + builder.Services.AddAuthorization(CreatePolicies); + + builder.Services.AddOpenIddict() + + // Register the OpenIddict core components. + .AddCore(options => + { + options + .UseEntityFrameworkCore() + .UseDbContext(); + }) + + // Register the OpenIddict server components. + .AddServer(options => + { + // Enable the authorization and token endpoints. + options + .SetAuthorizationEndpointUris(Controllers.Security.Paths.BackOfficeApiAuthorizationEndpoint) + .SetTokenEndpointUris(Controllers.Security.Paths.BackOfficeApiTokenEndpoint); + + // Enable authorization code flow with PKCE + options + .AllowAuthorizationCodeFlow() + .RequireProofKeyForCodeExchange() + .AllowRefreshTokenFlow(); + + // Register the encryption and signing credentials. + // - see https://documentation.openiddict.com/configuration/encryption-and-signing-credentials.html + options + // TODO: use actual certificates here, see docs above + .AddDevelopmentEncryptionCertificate() + .AddDevelopmentSigningCertificate() + .DisableAccessTokenEncryption(); + + // Register the ASP.NET Core host and configure for custom authentication endpoint. + options + .UseAspNetCore() + .EnableAuthorizationEndpointPassthrough(); + }) + + // Register the OpenIddict validation components. + .AddValidation(options => + { + // Import the configuration from the local OpenIddict server instance. + options.UseLocalServer(); + + // Register the ASP.NET Core host. + options.UseAspNetCore(); + }); + + builder.Services.AddTransient(); + builder.Services.AddSingleton(); + + builder.Services.AddHostedService(); + builder.Services.AddHostedService(); + + return builder; + } + + // TODO: remove this once EF is implemented + public class DatabaseManager : IHostedService + { + private readonly IServiceProvider _serviceProvider; + + public DatabaseManager(IServiceProvider serviceProvider) => _serviceProvider = serviceProvider; + + public async Task StartAsync(CancellationToken cancellationToken) + { + using IServiceScope scope = _serviceProvider.CreateScope(); + + DbContext context = scope.ServiceProvider.GetRequiredService(); + await context.Database.EnsureCreatedAsync(cancellationToken); + + // TODO: add BackOfficeAuthorizationInitializationMiddleware before UseAuthorization (to make it run for unauthorized API requests) and remove this + IBackOfficeApplicationManager backOfficeApplicationManager = scope.ServiceProvider.GetRequiredService(); + await backOfficeApplicationManager.EnsureBackOfficeApplicationAsync(new Uri("https://localhost:44331/"), cancellationToken); + } + + public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask; + } + + // TODO: move this to an appropriate location and implement the policy scheme that should be used for the new management APIs + private static void CreatePolicies(AuthorizationOptions options) + { + void AddPolicy(string policyName, string claimType, params string[] allowedClaimValues) + { + options.AddPolicy($"New{policyName}", policy => + { + policy.AuthenticationSchemes.Add(OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme); + policy.RequireClaim(claimType, allowedClaimValues); + }); + } + + // NOTE: these are ONLY sample policies that allow us to test the new management APIs + AddPolicy(AuthorizationPolicies.SectionAccessContent, Constants.Security.AllowedApplicationsClaimType, Constants.Applications.Content); + AddPolicy(AuthorizationPolicies.SectionAccessForContentTree, Constants.Security.AllowedApplicationsClaimType, Constants.Applications.Content); + AddPolicy(AuthorizationPolicies.SectionAccessForMediaTree, Constants.Security.AllowedApplicationsClaimType, Constants.Applications.Media); + AddPolicy(AuthorizationPolicies.SectionAccessMedia, Constants.Security.AllowedApplicationsClaimType, Constants.Applications.Media); + AddPolicy(AuthorizationPolicies.SectionAccessContentOrMedia, Constants.Security.AllowedApplicationsClaimType, Constants.Applications.Content, Constants.Applications.Media); + } +} diff --git a/src/Umbraco.Cms.ManagementApi/DependencyInjection/ServicesBuilderExtensions.cs b/src/Umbraco.Cms.ManagementApi/DependencyInjection/ServicesBuilderExtensions.cs index cb739478c5..9a05c17bfe 100644 --- a/src/Umbraco.Cms.ManagementApi/DependencyInjection/ServicesBuilderExtensions.cs +++ b/src/Umbraco.Cms.ManagementApi/DependencyInjection/ServicesBuilderExtensions.cs @@ -1,7 +1,9 @@ using Microsoft.Extensions.DependencyInjection; using Umbraco.Cms.Core.DependencyInjection; +using Umbraco.Cms.Core.Routing; using Umbraco.Cms.ManagementApi.Serialization; using Umbraco.Cms.ManagementApi.Services; +using Umbraco.Extensions; using Umbraco.New.Cms.Core.Services.Installer; using Umbraco.New.Cms.Core.Services.Languages; @@ -17,6 +19,12 @@ public static class ServicesBuilderExtensions builder.Services.AddTransient(); builder.Services.AddTransient(); + // TODO: handle new management API path in core UmbracoRequestPaths (it's a behavioural breaking change so it goes here for now) + builder.Services.Configure(options => + { + options.IsBackOfficeRequest = urlPath => urlPath.InvariantStartsWith($"/umbraco/management/api/"); + }); + return builder; } } diff --git a/src/Umbraco.Cms.ManagementApi/ManagementApiComposer.cs b/src/Umbraco.Cms.ManagementApi/ManagementApiComposer.cs index 071b6de63a..fa1d34a30a 100644 --- a/src/Umbraco.Cms.ManagementApi/ManagementApiComposer.cs +++ b/src/Umbraco.Cms.ManagementApi/ManagementApiComposer.cs @@ -3,22 +3,23 @@ using Microsoft.AspNetCore.Diagnostics; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.ApiExplorer; using Microsoft.AspNetCore.Mvc.Versioning; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Options; -using Newtonsoft.Json; -using Newtonsoft.Json.Converters; -using Newtonsoft.Json.Serialization; -using NSwag.AspNetCore; +using Microsoft.OpenApi.Models; using Umbraco.Cms.Core.Composing; using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.ManagementApi.Configuration; using Umbraco.Cms.ManagementApi.DependencyInjection; +using Umbraco.Cms.ManagementApi.OpenApi; using Umbraco.Cms.Web.Common.ApplicationBuilder; using Umbraco.Extensions; +using Umbraco.New.Cms.Core; +using Umbraco.New.Cms.Core.Models.Configuration; using IHostingEnvironment = Umbraco.Cms.Core.Hosting.IHostingEnvironment; namespace Umbraco.Cms.ManagementApi; @@ -26,7 +27,7 @@ namespace Umbraco.Cms.ManagementApi; public class ManagementApiComposer : IComposer { private const string ApiTitle = "Umbraco Backoffice API"; - private const string ApiAllName = "All"; + private const string ApiDefaultDocumentName = "v1"; private ApiVersion DefaultApiVersion => new(1, 0); @@ -44,7 +45,8 @@ public class ManagementApiComposer : IComposer .AddTrees() .AddFactories() .AddServices() - .AddMappers(); + .AddMappers() + .AddBackOfficeAuthentication(); services.AddApiVersioning(options => { @@ -55,16 +57,63 @@ public class ManagementApiComposer : IComposer options.UseApiBehavior = false; }); - services.AddOpenApiDocument(options => + services.AddSwaggerGen(swaggerGenOptions => { - options.Title = ApiTitle; - options.Version = ApiAllName; - options.DocumentName = ApiAllName; - options.Description = "This shows all APIs available in this version of Umbraco - Including all the legacy apis that is available for backward compatibility"; - options.PostProcess = document => + swaggerGenOptions.SwaggerDoc( + ApiDefaultDocumentName, + new OpenApiInfo + { + Title = ApiTitle, + Version = DefaultApiVersion.ToString(), + Description = "This shows all APIs available in this version of Umbraco - including all the legacy apis that are available for backward compatibility" + }); + + swaggerGenOptions.DocInclusionPredicate((_, api) => !string.IsNullOrWhiteSpace(api.GroupName)); + + swaggerGenOptions.TagActionsBy(api => new [] { api.GroupName }); + + // see https://github.com/domaindrivendev/Swashbuckle.AspNetCore#change-operation-sort-order-eg-for-ui-sorting + string ActionSortKeySelector(ApiDescription apiDesc) + => $"{apiDesc.GroupName}_{apiDesc.ActionDescriptor.AttributeRouteInfo?.Template ?? apiDesc.ActionDescriptor.RouteValues["controller"]}_{apiDesc.ActionDescriptor.RouteValues["action"]}_{apiDesc.HttpMethod}"; + swaggerGenOptions.OrderActionsBy(ActionSortKeySelector); + + swaggerGenOptions.AddSecurityDefinition("OAuth", new OpenApiSecurityScheme { - document.Tags = document.Tags.OrderBy(tag => tag.Name).ToList(); - }; + In = ParameterLocation.Header, + Name = "Umbraco", + Type = SecuritySchemeType.OAuth2, + Description = "Umbraco Authentication", + Flows = new OpenApiOAuthFlows + { + AuthorizationCode = new OpenApiOAuthFlow + { + AuthorizationUrl = new Uri(Controllers.Security.Paths.BackOfficeApiAuthorizationEndpoint, UriKind.Relative), + TokenUrl = new Uri(Controllers.Security.Paths.BackOfficeApiTokenEndpoint, UriKind.Relative) + } + } + }); + + swaggerGenOptions.AddSecurityRequirement(new OpenApiSecurityRequirement + { + // this weird looking construct works because OpenApiSecurityRequirement + // is a specialization of Dictionary<,> + { + new OpenApiSecurityScheme + { + Reference = new OpenApiReference + { + Id = "OAuth", + Type = ReferenceType.SecurityScheme + } + }, + new List { } + } + }); + + swaggerGenOptions.DocumentFilter(); + swaggerGenOptions.SchemaFilter(); + + swaggerGenOptions.CustomSchemaIds(SchemaIdGenerator.Generate); }); services.AddVersionedApiExplorer(options => @@ -78,6 +127,10 @@ public class ManagementApiComposer : IComposer services.AddControllers(); builder.Services.ConfigureOptions(); + // TODO: when this is moved to core, make the AddUmbracoOptions extension private again and remove core InternalsVisibleTo for Umbraco.Cms.ManagementApi + builder.AddUmbracoOptions(); + builder.Services.AddSingleton, NewBackOfficeSettingsValidator>(); + builder.Services.Configure(options => { options.AddFilter(new UmbracoPipelineFilter( @@ -126,21 +179,18 @@ public class ManagementApiComposer : IComposer GlobalSettings? settings = provider.GetRequiredService>().Value; IHostingEnvironment hostingEnvironment = provider.GetRequiredService(); var officePath = settings.GetBackOfficePath(hostingEnvironment); - // serve documents (same as app.UseSwagger()) - applicationBuilder.UseOpenApi(config => - { - config.Path = $"{officePath}/swagger/{{documentName}}/swagger.json"; - }); - // Serve Swagger UI - applicationBuilder.UseSwaggerUi3(config => + applicationBuilder.UseSwagger(swaggerOptions => { - config.Path = officePath + "/swagger"; - config.SwaggerRoutes.Clear(); - var swaggerPath = $"{officePath}/swagger/{ApiAllName}/swagger.json"; - config.SwaggerRoutes.Add(new SwaggerUi3Route(ApiAllName, swaggerPath)); - config.OperationsSorter = "alpha"; - config.TagsSorter = "alpha"; + swaggerOptions.RouteTemplate = $"{officePath.TrimStart(Core.Constants.CharArrays.ForwardSlash)}/swagger/{{documentName}}/swagger.json"; + }); + applicationBuilder.UseSwaggerUI(swaggerUiOptions => + { + swaggerUiOptions.SwaggerEndpoint($"{officePath}/swagger/v1/swagger.json", $"{ApiTitle} {DefaultApiVersion}"); + swaggerUiOptions.RoutePrefix = $"{officePath.TrimStart(Core.Constants.CharArrays.ForwardSlash)}/swagger"; + + swaggerUiOptions.OAuthClientId(Constants.OauthClientIds.Swagger); + swaggerUiOptions.OAuthUsePkce(); }); } }, diff --git a/src/Umbraco.Cms.ManagementApi/Middleware/BackOfficeAuthorizationInitializationMiddleware.cs b/src/Umbraco.Cms.ManagementApi/Middleware/BackOfficeAuthorizationInitializationMiddleware.cs new file mode 100644 index 0000000000..6ecebb3362 --- /dev/null +++ b/src/Umbraco.Cms.ManagementApi/Middleware/BackOfficeAuthorizationInitializationMiddleware.cs @@ -0,0 +1,62 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Extensions; +using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.Routing; +using Umbraco.New.Cms.Infrastructure.Security; + +namespace Umbraco.Cms.ManagementApi.Middleware; + +public class BackOfficeAuthorizationInitializationMiddleware : IMiddleware +{ + private static bool _firstBackOfficeRequest; + private static SemaphoreSlim _firstBackOfficeRequestLocker = new(1); + + private readonly UmbracoRequestPaths _umbracoRequestPaths; + private readonly IServiceProvider _serviceProvider; + + public BackOfficeAuthorizationInitializationMiddleware(UmbracoRequestPaths umbracoRequestPaths, IServiceProvider serviceProvider) + { + _umbracoRequestPaths = umbracoRequestPaths; + _serviceProvider = serviceProvider; + } + + public async Task InvokeAsync(HttpContext context, RequestDelegate next) + { + await InitializeBackOfficeAuthorizationOnceAsync(context); + await next(context); + } + + private async Task InitializeBackOfficeAuthorizationOnceAsync(HttpContext context) + { + if (_firstBackOfficeRequest) + { + return; + } + + if (_umbracoRequestPaths.IsBackOfficeRequest(context.Request.Path) == false) + { + return; + } + + await _firstBackOfficeRequestLocker.WaitAsync(); + if (_firstBackOfficeRequest == false) + { + using IServiceScope scope = _serviceProvider.CreateScope(); + IBackOfficeApplicationManager backOfficeApplicationManager = scope.ServiceProvider.GetRequiredService(); + await backOfficeApplicationManager.EnsureBackOfficeApplicationAsync(new Uri(context.Request.GetDisplayUrl())); + _firstBackOfficeRequest = true; + } + + _firstBackOfficeRequestLocker.Release(); + } +} + +// TODO: remove this (used for testing BackOfficeAuthorizationInitializationMiddleware until it can be added to the existing UseBackOffice extension) +// public static class UmbracoApplicationBuilderExtensions +// { +// public static IUmbracoApplicationBuilderContext UseNewBackOffice(this IUmbracoApplicationBuilderContext builder) +// { +// builder.AppBuilder.UseMiddleware(); +// return builder; +// } +// } diff --git a/src/Umbraco.Cms.ManagementApi/OpenApi.json b/src/Umbraco.Cms.ManagementApi/OpenApi.json index b821f26e24..c0b9f4ef0b 100644 --- a/src/Umbraco.Cms.ManagementApi/OpenApi.json +++ b/src/Umbraco.Cms.ManagementApi/OpenApi.json @@ -1,195 +1,41 @@ { - "x-generator": "NSwag v13.17.0.0 (NJsonSchema v10.8.0.0 (Newtonsoft.Json v13.0.0.0))", - "openapi": "3.0.0", + "openapi": "3.0.1", "info": { "title": "Umbraco Backoffice API", - "description": "This shows all APIs available in this version of Umbraco - Including all the legacy apis that is available for backward compatibility", - "version": "All" + "description": "This shows all APIs available in this version of Umbraco - including all the legacy apis that are available for backward compatibility", + "version": "1.0" }, - "servers": [ - { - "url": "https://localhost:44331" - } - ], "paths": { - "/umbraco/management/api/v1/upgrade/authorize": { - "post": { - "tags": [ - "Upgrade" - ], - "operationId": "AuthorizeUpgrade_Authorize", - "responses": { - "200": { - "description": "" - }, - "428": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetails" - } - } - } - }, - "500": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetails" - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/upgrade/settings": { + "/umbraco/management/api/v1/culture": { "get": { "tags": [ - "Upgrade" + "Culture" ], - "operationId": "SettingsUpgrade_Settings", - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/UpgradeSettingsViewModel" - } - } - } - }, - "428": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetails" - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/tracked-references/descendants/{parentId}": { - "get": { - "tags": [ - "TrackedReferences" - ], - "summary": "Gets a page list of the child nodes of the current item used in any kind of relation.", - "description": "Used when deleting and unpublishing a single item to check if this item has any descending items that are in any\nkind of relation.\nThis is basically finding the descending items which are children in relations.", - "operationId": "DescendantsTrackedReferences_Descendants", "parameters": [ { - "name": "parentId", - "in": "path", - "required": true, + "name": "skip", + "in": "query", "schema": { "type": "integer", "format": "int32" - }, - "x-position": 1 - }, - { - "name": "skip", - "in": "query", - "schema": { - "type": "integer", - "format": "int64" - }, - "x-position": 2 + } }, { "name": "take", "in": "query", - "schema": { - "type": "integer", - "format": "int64" - }, - "x-position": 3 - }, - { - "name": "filterMustBeIsDependency", - "in": "query", - "schema": { - "type": "boolean", - "nullable": true - }, - "x-position": 4 - } - ], - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PagedViewModelOfRelationItemViewModel" - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/tracked-references/{id}": { - "get": { - "tags": [ - "TrackedReferences" - ], - "summary": "Gets a page list of tracked references for the current item, so you can see where an item is being used.", - "description": "Used by info tabs on content, media etc. and for the delete and unpublish of single items.\nThis is basically finding parents of relations.", - "operationId": "ForItemTrackedReferences_Get", - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, "schema": { "type": "integer", "format": "int32" - }, - "x-position": 1 - }, - { - "name": "skip", - "in": "query", - "schema": { - "type": "integer", - "format": "int64" - }, - "x-position": 2 - }, - { - "name": "take", - "in": "query", - "schema": { - "type": "integer", - "format": "int64" - }, - "x-position": 3 - }, - { - "name": "filterMustBeIsDependency", - "in": "query", - "schema": { - "type": "boolean", - "nullable": true - }, - "x-position": 4 + } } ], "responses": { "200": { - "description": "", + "description": "Success", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/PagedViewModelOfRelationItemViewModel" + "$ref": "#/components/schemas/PagedCulture" } } } @@ -197,87 +43,19 @@ } } }, - "/umbraco/management/api/v1/tracked-references/multiple": { + "/umbraco/management/api/v1/tree/data-type/children": { "get": { "tags": [ - "TrackedReferences" + "Data Type" ], - "summary": "Gets a page list of the items used in any kind of relation from selected integer ids.", - "description": "Used when bulk deleting content/media and bulk unpublishing content (delete and unpublish on List view).\nThis is basically finding children of relations.", - "operationId": "MultipleTrackedReferences_GetPagedReferencedItems", - "parameters": [ - { - "name": "ids", - "in": "query", - "style": "form", - "explode": true, - "schema": { - "type": "array", - "nullable": true, - "items": { - "type": "integer", - "format": "int32" - } - }, - "x-position": 1 - }, - { - "name": "skip", - "in": "query", - "schema": { - "type": "integer", - "format": "int64" - }, - "x-position": 2 - }, - { - "name": "take", - "in": "query", - "schema": { - "type": "integer", - "format": "int64" - }, - "x-position": 3 - }, - { - "name": "filterMustBeIsDependency", - "in": "query", - "schema": { - "type": "boolean", - "nullable": true - }, - "x-position": 4 - } - ], - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PagedViewModelOfRelationItemViewModel" - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/template/tree/children": { - "get": { - "tags": [ - "Template" - ], - "operationId": "ChildrenTemplateTree_Children", "parameters": [ { "name": "parentKey", "in": "query", "schema": { "type": "string", - "format": "guid" - }, - "x-position": 1 + "format": "uuid" + } }, { "name": "skip", @@ -286,8 +64,7 @@ "type": "integer", "format": "int32", "default": 0 - }, - "x-position": 2 + } }, { "name": "take", @@ -296,1753 +73,7 @@ "type": "integer", "format": "int32", "default": 100 - }, - "x-position": 3 - } - ], - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PagedViewModelOfEntityTreeItemViewModel" - } - } } - } - } - } - }, - "/umbraco/management/api/v1/template/tree/items": { - "get": { - "tags": [ - "Template" - ], - "operationId": "ItemsTemplateTree_Items", - "parameters": [ - { - "name": "key", - "x-originalName": "keys", - "in": "query", - "style": "form", - "explode": true, - "schema": { - "type": "array", - "nullable": true, - "items": { - "type": "string", - "format": "guid" - } - }, - "x-position": 1 - } - ], - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/EntityTreeItemViewModel" - } - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/template/tree/root": { - "get": { - "tags": [ - "Template" - ], - "operationId": "RootTemplateTree_Root", - "parameters": [ - { - "name": "skip", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 0 - }, - "x-position": 1 - }, - { - "name": "take", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 100 - }, - "x-position": 2 - } - ], - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PagedViewModelOfEntityTreeItemViewModel" - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/stylesheet/tree/children": { - "get": { - "tags": [ - "Stylesheet" - ], - "operationId": "ChildrenStylesheetTree_Children", - "parameters": [ - { - "name": "path", - "in": "query", - "schema": { - "type": "string", - "nullable": true - }, - "x-position": 1 - }, - { - "name": "skip", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 0 - }, - "x-position": 2 - }, - { - "name": "take", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 100 - }, - "x-position": 3 - } - ], - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PagedViewModelOfFileSystemTreeItemViewModel" - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/stylesheet/tree/items": { - "get": { - "tags": [ - "Stylesheet" - ], - "operationId": "ItemsStylesheetTree_Items", - "parameters": [ - { - "name": "path", - "x-originalName": "paths", - "in": "query", - "style": "form", - "explode": true, - "schema": { - "type": "array", - "nullable": true, - "items": { - "type": "string" - } - }, - "x-position": 1 - } - ], - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/FileSystemTreeItemViewModel" - } - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/stylesheet/tree/root": { - "get": { - "tags": [ - "Stylesheet" - ], - "operationId": "RootStylesheetTree_Root", - "parameters": [ - { - "name": "skip", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 0 - }, - "x-position": 1 - }, - { - "name": "take", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 100 - }, - "x-position": 2 - } - ], - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PagedViewModelOfFileSystemTreeItemViewModel" - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/static-file/tree/children": { - "get": { - "tags": [ - "StaticFile" - ], - "operationId": "ChildrenStaticFileTree_Children", - "parameters": [ - { - "name": "path", - "in": "query", - "schema": { - "type": "string", - "nullable": true - }, - "x-position": 1 - }, - { - "name": "skip", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 0 - }, - "x-position": 2 - }, - { - "name": "take", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 100 - }, - "x-position": 3 - } - ], - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PagedViewModelOfFileSystemTreeItemViewModel" - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/static-file/tree/items": { - "get": { - "tags": [ - "StaticFile" - ], - "operationId": "ItemsStaticFileTree_Items", - "parameters": [ - { - "name": "path", - "x-originalName": "paths", - "in": "query", - "style": "form", - "explode": true, - "schema": { - "type": "array", - "nullable": true, - "items": { - "type": "string" - } - }, - "x-position": 1 - } - ], - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/FileSystemTreeItemViewModel" - } - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/static-file/tree/root": { - "get": { - "tags": [ - "StaticFile" - ], - "operationId": "RootStaticFileTree_Root", - "parameters": [ - { - "name": "skip", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 0 - }, - "x-position": 1 - }, - { - "name": "take", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 100 - }, - "x-position": 2 - } - ], - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PagedViewModelOfFileSystemTreeItemViewModel" - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/server/status": { - "get": { - "tags": [ - "Server" - ], - "operationId": "StatusServer_Get", - "responses": { - "400": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetails" - } - } - } - }, - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ServerStatusViewModel" - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/server/version": { - "get": { - "tags": [ - "Server" - ], - "operationId": "VersionServer_Get", - "responses": { - "400": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetails" - } - } - } - }, - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/VersionViewModel" - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/search/index/{indexName}": { - "get": { - "tags": [ - "Search" - ], - "summary": "Check if the index has been rebuilt", - "description": "This is kind of rudimentary since there's no way we can know that the index has rebuilt, we\nhave a listener for the index op complete so we'll just check if that key is no longer there in the runtime cache", - "operationId": "IndexDetailsSearch_Index", - "parameters": [ - { - "name": "indexName", - "in": "path", - "required": true, - "schema": { - "type": "string", - "nullable": true - }, - "x-position": 1 - } - ], - "responses": { - "400": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetails" - } - } - } - }, - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/IndexViewModel" - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/search/index": { - "get": { - "tags": [ - "Search" - ], - "summary": "Get the details for indexers", - "operationId": "IndexListSearch_Indexes", - "parameters": [ - { - "name": "skip", - "in": "query", - "schema": { - "type": "integer", - "format": "int32" - }, - "x-position": 1 - }, - { - "name": "take", - "in": "query", - "schema": { - "type": "integer", - "format": "int32" - }, - "x-position": 2 - } - ], - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PagedViewModelOfIndexViewModel" - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/search/index/{indexName}/rebuild": { - "post": { - "tags": [ - "Search" - ], - "summary": "Rebuilds the index", - "operationId": "IndexRebuildSearch_Rebuild", - "parameters": [ - { - "name": "indexName", - "in": "path", - "required": true, - "schema": { - "type": "string", - "nullable": true - }, - "x-position": 1 - } - ], - "responses": { - "400": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetails" - } - } - } - }, - "200": { - "description": "", - "content": { - "application/octet-stream": { - "schema": { - "type": "string", - "format": "binary" - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/search/searcher": { - "get": { - "tags": [ - "Search" - ], - "summary": "Get the details for searchers", - "operationId": "SearcherListSearch_Searchers", - "parameters": [ - { - "name": "skip", - "in": "query", - "schema": { - "type": "integer", - "format": "int32" - }, - "x-position": 1 - }, - { - "name": "take", - "in": "query", - "schema": { - "type": "integer", - "format": "int32" - }, - "x-position": 2 - } - ], - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PagedViewModelOfSearcherViewModel" - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/search/searcher/{searcherName}/search": { - "get": { - "tags": [ - "Search" - ], - "operationId": "SearcherSearchSearch_GetSearchResults", - "parameters": [ - { - "name": "searcherName", - "in": "path", - "required": true, - "schema": { - "type": "string", - "nullable": true - }, - "x-position": 1 - }, - { - "name": "query", - "in": "query", - "schema": { - "type": "string", - "nullable": true - }, - "x-position": 2 - }, - { - "name": "skip", - "in": "query", - "schema": { - "type": "integer", - "format": "int32" - }, - "x-position": 3 - }, - { - "name": "take", - "in": "query", - "schema": { - "type": "integer", - "format": "int32" - }, - "x-position": 4 - } - ], - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PagedViewModelOfPagedViewModelOfSearchResultViewModel" - } - } - } - }, - "404": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetails" - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/script/tree/children": { - "get": { - "tags": [ - "Script" - ], - "operationId": "ChildrenScriptTree_Children", - "parameters": [ - { - "name": "path", - "in": "query", - "schema": { - "type": "string", - "nullable": true - }, - "x-position": 1 - }, - { - "name": "skip", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 0 - }, - "x-position": 2 - }, - { - "name": "take", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 100 - }, - "x-position": 3 - } - ], - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PagedViewModelOfFileSystemTreeItemViewModel" - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/script/tree/items": { - "get": { - "tags": [ - "Script" - ], - "operationId": "ItemsScriptTree_Items", - "parameters": [ - { - "name": "path", - "x-originalName": "paths", - "in": "query", - "style": "form", - "explode": true, - "schema": { - "type": "array", - "nullable": true, - "items": { - "type": "string" - } - }, - "x-position": 1 - } - ], - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/FileSystemTreeItemViewModel" - } - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/script/tree/root": { - "get": { - "tags": [ - "Script" - ], - "operationId": "RootScriptTree_Root", - "parameters": [ - { - "name": "skip", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 0 - }, - "x-position": 1 - }, - { - "name": "take", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 100 - }, - "x-position": 2 - } - ], - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PagedViewModelOfFileSystemTreeItemViewModel" - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/relation/child-relations/{childId}": { - "get": { - "tags": [ - "Relation" - ], - "operationId": "ByChildRelation_ByChild", - "parameters": [ - { - "name": "childId", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - }, - "x-position": 1 - }, - { - "name": "skip", - "in": "query", - "schema": { - "type": "integer", - "format": "int32" - }, - "x-position": 2 - }, - { - "name": "take", - "in": "query", - "schema": { - "type": "integer", - "format": "int32" - }, - "x-position": 3 - }, - { - "name": "relationTypeAlias", - "in": "query", - "schema": { - "type": "string", - "default": "", - "nullable": true - }, - "x-position": 4 - } - ], - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PagedViewModelOfRelationViewModel" - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/relation/{id}": { - "get": { - "tags": [ - "Relation" - ], - "operationId": "ByIdRelation_ById", - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - }, - "x-position": 1 - } - ], - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/RelationViewModel" - } - } - } - }, - "404": { - "description": "", - "content": { - "application/octet-stream": { - "schema": { - "type": "string", - "format": "binary" - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/relation-type/tree/items": { - "get": { - "tags": [ - "RelationType" - ], - "operationId": "ItemsRelationTypeTree_Items", - "parameters": [ - { - "name": "key", - "x-originalName": "keys", - "in": "query", - "style": "form", - "explode": true, - "schema": { - "type": "array", - "nullable": true, - "items": { - "type": "string", - "format": "guid" - } - }, - "x-position": 1 - } - ], - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/FolderTreeItemViewModel" - } - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/relation-type/tree/root": { - "get": { - "tags": [ - "RelationType" - ], - "operationId": "RootRelationTypeTree_Root", - "parameters": [ - { - "name": "skip", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 0 - }, - "x-position": 1 - }, - { - "name": "take", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 100 - }, - "x-position": 2 - } - ], - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PagedViewModelOfEntityTreeItemViewModel" - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/published-cache/collect": { - "post": { - "tags": [ - "PublishedCache" - ], - "operationId": "CollectPublishedCache_Collect", - "responses": { - "200": { - "description": "" - } - } - } - }, - "/umbraco/management/api/v1/published-cache/rebuild": { - "post": { - "tags": [ - "PublishedCache" - ], - "operationId": "RebuildPublishedCache_Collect", - "responses": { - "200": { - "description": "" - } - } - } - }, - "/umbraco/management/api/v1/published-cache/reload": { - "post": { - "tags": [ - "PublishedCache" - ], - "operationId": "ReloadPublishedCache_Reload", - "responses": { - "200": { - "description": "" - } - } - } - }, - "/umbraco/management/api/v1/published-cache/status": { - "get": { - "tags": [ - "PublishedCache" - ], - "operationId": "StatusPublishedCache_Status", - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "type": "string" - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/profiling/status": { - "get": { - "tags": [ - "Profiling" - ], - "operationId": "StatusProfiling_Status", - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProfilingStatusViewModel" - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/partial-view/tree/children": { - "get": { - "tags": [ - "PartialView" - ], - "operationId": "ChildrenPartialViewTree_Children", - "parameters": [ - { - "name": "path", - "in": "query", - "schema": { - "type": "string", - "nullable": true - }, - "x-position": 1 - }, - { - "name": "skip", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 0 - }, - "x-position": 2 - }, - { - "name": "take", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 100 - }, - "x-position": 3 - } - ], - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PagedViewModelOfFileSystemTreeItemViewModel" - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/partial-view/tree/items": { - "get": { - "tags": [ - "PartialView" - ], - "operationId": "ItemsPartialViewTree_Items", - "parameters": [ - { - "name": "path", - "x-originalName": "paths", - "in": "query", - "style": "form", - "explode": true, - "schema": { - "type": "array", - "nullable": true, - "items": { - "type": "string" - } - }, - "x-position": 1 - } - ], - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/FileSystemTreeItemViewModel" - } - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/partial-view/tree/root": { - "get": { - "tags": [ - "PartialView" - ], - "operationId": "RootPartialViewTree_Root", - "parameters": [ - { - "name": "skip", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 0 - }, - "x-position": 1 - }, - { - "name": "take", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 100 - }, - "x-position": 2 - } - ], - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PagedViewModelOfFileSystemTreeItemViewModel" - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/models-builder/build": { - "post": { - "tags": [ - "ModelsBuilder" - ], - "operationId": "BuildModelsBuilder_BuildModels", - "responses": { - "201": { - "description": "", - "content": { - "application/octet-stream": { - "schema": { - "type": "string", - "format": "binary" - } - } - } - }, - "428": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetails" - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/models-builder": { - "get": { - "tags": [ - "ModelsBuilder" - ], - "operationId": "GetModelsBuilder_GetDashboard", - "responses": { - "200": { - "description": "", - "content": { - "application/octet-stream": { - "schema": { - "type": "string", - "format": "binary" - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/models-builder/status": { - "get": { - "tags": [ - "ModelsBuilder" - ], - "operationId": "StatusModelsBuilder_GetModelsOutOfDateStatus", - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/OutOfDateStatusViewModel" - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/member-type/tree/items": { - "get": { - "tags": [ - "MemberType" - ], - "operationId": "ItemsMemberTypeTree_Items", - "parameters": [ - { - "name": "key", - "x-originalName": "keys", - "in": "query", - "style": "form", - "explode": true, - "schema": { - "type": "array", - "nullable": true, - "items": { - "type": "string", - "format": "guid" - } - }, - "x-position": 1 - } - ], - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/EntityTreeItemViewModel" - } - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/member-type/tree/root": { - "get": { - "tags": [ - "MemberType" - ], - "operationId": "RootMemberTypeTree_Root", - "parameters": [ - { - "name": "skip", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 0 - }, - "x-position": 1 - }, - { - "name": "take", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 100 - }, - "x-position": 2 - } - ], - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PagedViewModelOfEntityTreeItemViewModel" - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/member-group/tree/items": { - "get": { - "tags": [ - "MemberGroup" - ], - "operationId": "ItemsMemberGroupTree_Items", - "parameters": [ - { - "name": "key", - "x-originalName": "keys", - "in": "query", - "style": "form", - "explode": true, - "schema": { - "type": "array", - "nullable": true, - "items": { - "type": "string", - "format": "guid" - } - }, - "x-position": 1 - } - ], - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/EntityTreeItemViewModel" - } - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/member-group/tree/root": { - "get": { - "tags": [ - "MemberGroup" - ], - "operationId": "RootMemberGroupTree_Root", - "parameters": [ - { - "name": "skip", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 0 - }, - "x-position": 1 - }, - { - "name": "take", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 100 - }, - "x-position": 2 - } - ], - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PagedViewModelOfEntityTreeItemViewModel" - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/media/tree/children": { - "get": { - "tags": [ - "Media" - ], - "operationId": "ChildrenMediaTree_Children", - "parameters": [ - { - "name": "parentKey", - "in": "query", - "schema": { - "type": "string", - "format": "guid" - }, - "x-position": 1 - }, - { - "name": "skip", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 0 - }, - "x-position": 2 - }, - { - "name": "take", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 100 - }, - "x-position": 3 - }, - { - "name": "dataTypeKey", - "in": "query", - "schema": { - "type": "string", - "format": "guid", - "nullable": true - }, - "x-position": 4 - } - ], - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PagedViewModelOfContentTreeItemViewModel" - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/media/tree/items": { - "get": { - "tags": [ - "Media" - ], - "operationId": "ItemsMediaTree_Items", - "parameters": [ - { - "name": "key", - "x-originalName": "keys", - "in": "query", - "style": "form", - "explode": true, - "schema": { - "type": "array", - "nullable": true, - "items": { - "type": "string", - "format": "guid" - } - }, - "x-position": 1 - }, - { - "name": "dataTypeKey", - "in": "query", - "schema": { - "type": "string", - "format": "guid", - "nullable": true - }, - "x-position": 2 - } - ], - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ContentTreeItemViewModel" - } - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/media/tree/root": { - "get": { - "tags": [ - "Media" - ], - "operationId": "RootMediaTree_Root", - "parameters": [ - { - "name": "skip", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 0 - }, - "x-position": 1 - }, - { - "name": "take", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 100 - }, - "x-position": 2 - }, - { - "name": "dataTypeKey", - "in": "query", - "schema": { - "type": "string", - "format": "guid", - "nullable": true - }, - "x-position": 3 - } - ], - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PagedViewModelOfContentTreeItemViewModel" - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/media/recycle-bin/children": { - "get": { - "tags": [ - "Media" - ], - "operationId": "ChildrenMediaRecycleBin_Children", - "parameters": [ - { - "name": "parentKey", - "in": "query", - "schema": { - "type": "string", - "format": "guid" - }, - "x-position": 1 - }, - { - "name": "skip", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 0 - }, - "x-position": 2 - }, - { - "name": "take", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 100 - }, - "x-position": 3 - } - ], - "responses": { - "401": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetails" - } - } - } - }, - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PagedViewModelOfRecycleBinItemViewModel" - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/media/recycle-bin/root": { - "get": { - "tags": [ - "Media" - ], - "operationId": "RootMediaRecycleBin_Root", - "parameters": [ - { - "name": "skip", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 0 - }, - "x-position": 1 - }, - { - "name": "take", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 100 - }, - "x-position": 2 - } - ], - "responses": { - "401": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetails" - } - } - } - }, - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PagedViewModelOfRecycleBinItemViewModel" - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/media-type/tree/children": { - "get": { - "tags": [ - "MediaType" - ], - "operationId": "ChildrenMediaTypeTree_Children", - "parameters": [ - { - "name": "parentKey", - "in": "query", - "schema": { - "type": "string", - "format": "guid" - }, - "x-position": 1 - }, - { - "name": "skip", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 0 - }, - "x-position": 2 - }, - { - "name": "take", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 100 - }, - "x-position": 3 }, { "name": "foldersOnly", @@ -2050,17 +81,16 @@ "schema": { "type": "boolean", "default": false - }, - "x-position": 4 + } } ], "responses": { "200": { - "description": "", + "description": "Success", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/PagedViewModelOfFolderTreeItemViewModel" + "$ref": "#/components/schemas/PagedFolderTreeItem" } } } @@ -2068,39 +98,33 @@ } } }, - "/umbraco/management/api/v1/media-type/tree/items": { + "/umbraco/management/api/v1/tree/data-type/item": { "get": { "tags": [ - "MediaType" + "Data Type" ], - "operationId": "ItemsMediaTypeTree_Items", "parameters": [ { "name": "key", - "x-originalName": "keys", "in": "query", - "style": "form", - "explode": true, "schema": { "type": "array", - "nullable": true, "items": { "type": "string", - "format": "guid" + "format": "uuid" } - }, - "x-position": 1 + } } ], "responses": { "200": { - "description": "", + "description": "Success", "content": { "application/json": { "schema": { "type": "array", "items": { - "$ref": "#/components/schemas/FolderTreeItemViewModel" + "$ref": "#/components/schemas/FolderTreeItem" } } } @@ -2109,12 +133,11 @@ } } }, - "/umbraco/management/api/v1/media-type/tree/root": { + "/umbraco/management/api/v1/tree/data-type/root": { "get": { "tags": [ - "MediaType" + "Data Type" ], - "operationId": "RootMediaTypeTree_Root", "parameters": [ { "name": "skip", @@ -2123,8 +146,7 @@ "type": "integer", "format": "int32", "default": 0 - }, - "x-position": 1 + } }, { "name": "take", @@ -2133,8 +155,7 @@ "type": "integer", "format": "int32", "default": 100 - }, - "x-position": 2 + } }, { "name": "foldersOnly", @@ -2142,965 +163,16 @@ "schema": { "type": "boolean", "default": false - }, - "x-position": 3 + } } ], "responses": { "200": { - "description": "", + "description": "Success", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/PagedViewModelOfFolderTreeItemViewModel" - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/language": { - "get": { - "tags": [ - "Language" - ], - "summary": "1\n Returns all currently configured languages.", - "operationId": "AllLanguage_GetAll", - "parameters": [ - { - "name": "skip", - "in": "query", - "schema": { - "type": "integer", - "format": "int32" - }, - "x-position": 1 - }, - { - "name": "take", - "in": "query", - "schema": { - "type": "integer", - "format": "int32" - }, - "x-position": 2 - } - ], - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PagedViewModelOfLanguageViewModel" - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/language/{id}": { - "get": { - "tags": [ - "Language" - ], - "operationId": "ByIdLanguage_ById", - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - }, - "x-position": 1 - } - ], - "responses": { - "404": { - "description": "", - "content": { - "application/octet-stream": { - "schema": { - "type": "string", - "format": "binary" - } - } - } - }, - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/LanguageViewModel" - } - } - } - } - } - }, - "delete": { - "tags": [ - "Language" - ], - "summary": "Deletes a language with a given ID", - "operationId": "DeleteLanguage_Delete", - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "integer", - "format": "int32" - }, - "x-position": 1 - } - ], - "responses": { - "400": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetails" - } - } - } - }, - "404": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetails" - } - } - } - }, - "200": { - "description": "" - } - } - } - }, - "/umbraco/management/api/v1/language/create": { - "post": { - "tags": [ - "Language" - ], - "summary": "Creates or saves a language", - "operationId": "CreateLanguage_Create", - "requestBody": { - "x-name": "language", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/LanguageViewModel" - } - } - }, - "required": true, - "x-position": 1 - }, - "responses": { - "400": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetails" - } - } - } - }, - "201": { - "description": "" - } - } - } - }, - "/umbraco/management/api/v1/language/update": { - "put": { - "tags": [ - "Language" - ], - "summary": "Updates a language", - "operationId": "UpdateLanguage_Update", - "requestBody": { - "x-name": "language", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/LanguageViewModel" - } - } - }, - "required": true, - "x-position": 1 - }, - "responses": { - "404": { - "description": "", - "content": { - "application/octet-stream": { - "schema": { - "type": "string", - "format": "binary" - } - } - } - }, - "400": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetails" - } - } - } - }, - "200": { - "description": "" - } - } - } - }, - "/umbraco/management/api/v1/install/settings": { - "get": { - "tags": [ - "Install" - ], - "operationId": "SettingsInstall_Settings", - "responses": { - "400": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetails" - } - } - } - }, - "428": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetails" - } - } - } - }, - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InstallSettingsViewModel" - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/install/setup": { - "post": { - "tags": [ - "Install" - ], - "operationId": "SetupInstall_Setup", - "requestBody": { - "x-name": "installData", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/InstallViewModel" - } - } - }, - "required": true, - "x-position": 1 - }, - "responses": { - "400": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetails" - } - } - } - }, - "428": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetails" - } - } - } - }, - "200": { - "description": "" - } - } - } - }, - "/umbraco/management/api/v1/install/validate-database": { - "post": { - "tags": [ - "Install" - ], - "operationId": "ValidateDatabaseInstall_ValidateDatabase", - "requestBody": { - "x-name": "viewModel", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DatabaseInstallViewModel" - } - } - }, - "required": true, - "x-position": 1 - }, - "responses": { - "400": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetails" - } - } - } - }, - "200": { - "description": "" - } - } - } - }, - "/umbraco/management/api/v1/help": { - "get": { - "tags": [ - "Help" - ], - "operationId": "GetHelp_Get", - "parameters": [ - { - "name": "section", - "in": "query", - "schema": { - "type": "string", - "nullable": true - }, - "x-position": 1 - }, - { - "name": "tree", - "in": "query", - "schema": { - "type": "string", - "nullable": true - }, - "x-position": 2 - }, - { - "name": "skip", - "in": "query", - "schema": { - "type": "integer", - "format": "int32" - }, - "x-position": 3 - }, - { - "name": "take", - "in": "query", - "schema": { - "type": "integer", - "format": "int32" - }, - "x-position": 4 - }, - { - "name": "baseUrl", - "in": "query", - "schema": { - "type": "string", - "default": "https://our.umbraco.com", - "nullable": true - }, - "x-position": 5 - } - ], - "responses": { - "400": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetails" - } - } - } - }, - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PagedViewModelOfHelpPageViewModel" - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/document/tree/children": { - "get": { - "tags": [ - "Document" - ], - "operationId": "ChildrenDocumentTree_Children", - "parameters": [ - { - "name": "parentKey", - "in": "query", - "schema": { - "type": "string", - "format": "guid" - }, - "x-position": 1 - }, - { - "name": "skip", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 0 - }, - "x-position": 2 - }, - { - "name": "take", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 100 - }, - "x-position": 3 - }, - { - "name": "dataTypeKey", - "in": "query", - "schema": { - "type": "string", - "format": "guid", - "nullable": true - }, - "x-position": 4 - }, - { - "name": "culture", - "in": "query", - "schema": { - "type": "string", - "nullable": true - }, - "x-position": 5 - } - ], - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PagedViewModelOfDocumentTreeItemViewModel" - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/document/tree/items": { - "get": { - "tags": [ - "Document" - ], - "operationId": "ItemsDocumentTree_Items", - "parameters": [ - { - "name": "key", - "x-originalName": "keys", - "in": "query", - "style": "form", - "explode": true, - "schema": { - "type": "array", - "nullable": true, - "items": { - "type": "string", - "format": "guid" - } - }, - "x-position": 1 - }, - { - "name": "dataTypeKey", - "in": "query", - "schema": { - "type": "string", - "format": "guid", - "nullable": true - }, - "x-position": 2 - }, - { - "name": "culture", - "in": "query", - "schema": { - "type": "string", - "nullable": true - }, - "x-position": 3 - } - ], - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DocumentTreeItemViewModel" - } - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/document/tree/root": { - "get": { - "tags": [ - "Document" - ], - "operationId": "RootDocumentTree_Root", - "parameters": [ - { - "name": "skip", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 0 - }, - "x-position": 1 - }, - { - "name": "take", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 100 - }, - "x-position": 2 - }, - { - "name": "dataTypeKey", - "in": "query", - "schema": { - "type": "string", - "format": "guid", - "nullable": true - }, - "x-position": 3 - }, - { - "name": "culture", - "in": "query", - "schema": { - "type": "string", - "nullable": true - }, - "x-position": 4 - } - ], - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PagedViewModelOfDocumentTreeItemViewModel" - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/document/recycle-bin/children": { - "get": { - "tags": [ - "Document" - ], - "operationId": "ChildrenDocumentRecycleBin_Children", - "parameters": [ - { - "name": "parentKey", - "in": "query", - "schema": { - "type": "string", - "format": "guid" - }, - "x-position": 1 - }, - { - "name": "skip", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 0 - }, - "x-position": 2 - }, - { - "name": "take", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 100 - }, - "x-position": 3 - } - ], - "responses": { - "401": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetails" - } - } - } - }, - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PagedViewModelOfRecycleBinItemViewModel" - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/document/recycle-bin/root": { - "get": { - "tags": [ - "Document" - ], - "operationId": "RootDocumentRecycleBin_Root", - "parameters": [ - { - "name": "skip", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 0 - }, - "x-position": 1 - }, - { - "name": "take", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 100 - }, - "x-position": 2 - } - ], - "responses": { - "401": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ProblemDetails" - } - } - } - }, - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PagedViewModelOfRecycleBinItemViewModel" - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/document-type/tree/children": { - "get": { - "tags": [ - "DocumentType" - ], - "operationId": "ChildrenDocumentTypeTree_Children", - "parameters": [ - { - "name": "parentKey", - "in": "query", - "schema": { - "type": "string", - "format": "guid" - }, - "x-position": 1 - }, - { - "name": "skip", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 0 - }, - "x-position": 2 - }, - { - "name": "take", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 100 - }, - "x-position": 3 - }, - { - "name": "foldersOnly", - "in": "query", - "schema": { - "type": "boolean", - "default": false - }, - "x-position": 4 - } - ], - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PagedViewModelOfDocumentTypeTreeItemViewModel" - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/document-type/tree/items": { - "get": { - "tags": [ - "DocumentType" - ], - "operationId": "ItemsDocumentTypeTree_Items", - "parameters": [ - { - "name": "key", - "x-originalName": "keys", - "in": "query", - "style": "form", - "explode": true, - "schema": { - "type": "array", - "nullable": true, - "items": { - "type": "string", - "format": "guid" - } - }, - "x-position": 1 - } - ], - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DocumentTypeTreeItemViewModel" - } - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/document-type/tree/root": { - "get": { - "tags": [ - "DocumentType" - ], - "operationId": "RootDocumentTypeTree_Root", - "parameters": [ - { - "name": "skip", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 0 - }, - "x-position": 1 - }, - { - "name": "take", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 100 - }, - "x-position": 2 - }, - { - "name": "foldersOnly", - "in": "query", - "schema": { - "type": "boolean", - "default": false - }, - "x-position": 3 - } - ], - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PagedViewModelOfDocumentTypeTreeItemViewModel" - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/document-blueprint/tree/items": { - "get": { - "tags": [ - "DocumentBlueprint" - ], - "operationId": "ItemsDocumentBlueprintTree_Items", - "parameters": [ - { - "name": "key", - "x-originalName": "keys", - "in": "query", - "style": "form", - "explode": true, - "schema": { - "type": "array", - "nullable": true, - "items": { - "type": "string", - "format": "guid" - } - }, - "x-position": 1 - } - ], - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DocumentBlueprintTreeItemViewModel" - } - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/document-blueprint/tree/root": { - "get": { - "tags": [ - "DocumentBlueprint" - ], - "operationId": "RootDocumentBlueprintTree_Root", - "parameters": [ - { - "name": "skip", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 0 - }, - "x-position": 1 - }, - { - "name": "take", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 100 - }, - "x-position": 2 - } - ], - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PagedViewModelOfDocumentBlueprintTreeItemViewModel" + "$ref": "#/components/schemas/PagedFolderTreeItem" } } } @@ -3113,8 +185,6 @@ "tags": [ "Dictionary" ], - "summary": "Retrieves a list with all dictionary items", - "operationId": "AllDictionary_All", "parameters": [ { "name": "skip", @@ -3122,8 +192,7 @@ "schema": { "type": "integer", "format": "int32" - }, - "x-position": 1 + } }, { "name": "take", @@ -3131,17 +200,68 @@ "schema": { "type": "integer", "format": "int32" - }, - "x-position": 2 + } } ], "responses": { "200": { - "description": "The IEnumerable`1.\n ", + "description": "Success", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/PagedViewModelOfDictionaryOverviewViewModel" + "$ref": "#/components/schemas/PagedDictionaryOverview" + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/dictionary/{id}": { + "patch": { + "tags": [ + "Dictionary" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/JsonPatch" + } + } + } + } + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ContentResult" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotFoundResult" } } } @@ -3154,39 +274,34 @@ "tags": [ "Dictionary" ], - "summary": "Gets a dictionary item by guid", - "operationId": "ByIdDictionary_ByKey", "parameters": [ { "name": "key", "in": "path", "required": true, - "description": "The id.\n ", "schema": { "type": "string", - "format": "guid" - }, - "x-position": 1 + "format": "uuid" + } } ], "responses": { "200": { - "description": "The DictionaryDisplay. Returns a not found response when dictionary item does not exist\n ", + "description": "Success", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DictionaryViewModel" + "$ref": "#/components/schemas/Dictionary" } } } }, "404": { - "description": "", + "description": "Not Found", "content": { - "application/octet-stream": { + "application/json": { "schema": { - "type": "string", - "format": "binary" + "$ref": "#/components/schemas/NotFoundResult" } } } @@ -3197,32 +312,27 @@ "tags": [ "Dictionary" ], - "summary": "Deletes a data type with a given ID", - "operationId": "DeleteDictionary_Delete", "parameters": [ { "name": "key", "in": "path", "required": true, - "description": "The key of the dictionary item to delete", "schema": { "type": "string", - "format": "guid" - }, - "x-position": 1 + "format": "uuid" + } } ], "responses": { "200": { - "description": "HttpResponseMessage\n " + "description": "Success" }, "404": { - "description": "", + "description": "Not Found", "content": { - "application/octet-stream": { + "application/json": { "schema": { - "type": "string", - "format": "binary" + "$ref": "#/components/schemas/NotFoundResult" } } } @@ -3235,35 +345,28 @@ "tags": [ "Dictionary" ], - "summary": "Creates a new dictionary item", - "operationId": "CreateDictionary_Create", "requestBody": { - "x-name": "dictionaryViewModel", - "description": "The viewmodel to pass to the action", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DictionaryItemViewModel" + "$ref": "#/components/schemas/DictionaryItem" } } - }, - "required": true, - "x-position": 1 + } }, "responses": { "201": { - "description": "The HttpResponseMessage.\n ", + "description": "Created", "content": { - "application/octet-stream": { + "application/json": { "schema": { - "type": "string", - "format": "binary" + "$ref": "#/components/schemas/CreatedResult" } } } }, "400": { - "description": "", + "description": "Bad Request", "content": { "application/json": { "schema": { @@ -3280,7 +383,6 @@ "tags": [ "Dictionary" ], - "operationId": "ExportDictionary_ExportDictionary", "parameters": [ { "name": "key", @@ -3288,9 +390,8 @@ "required": true, "schema": { "type": "string", - "format": "guid" - }, - "x-position": 1 + "format": "uuid" + } }, { "name": "includeChildren", @@ -3298,15 +399,14 @@ "schema": { "type": "boolean", "default": false - }, - "x-position": 2 + } } ], "responses": { "200": { - "description": "", + "description": "Success", "content": { - "application/octet-stream": { + "application/json": { "schema": { "type": "string", "format": "binary" @@ -3315,12 +415,11 @@ } }, "404": { - "description": "", + "description": "Not Found", "content": { - "application/octet-stream": { + "application/json": { "schema": { - "type": "string", - "format": "binary" + "$ref": "#/components/schemas/NotFoundResult" } } } @@ -3333,106 +432,40 @@ "tags": [ "Dictionary" ], - "operationId": "ImportDictionary_ImportDictionary", "parameters": [ { "name": "file", "in": "query", "schema": { - "type": "string", - "nullable": true - }, - "x-position": 1 + "type": "string" + } }, { "name": "parentId", "in": "query", "schema": { "type": "integer", - "format": "int32", - "nullable": true - }, - "x-position": 2 + "format": "int32" + } } ], "responses": { "200": { - "description": "", + "description": "Success", "content": { - "application/octet-stream": { + "application/json": { "schema": { - "type": "string", - "format": "binary" + "$ref": "#/components/schemas/ContentResult" } } } }, "404": { - "description": "", + "description": "Not Found", "content": { - "application/octet-stream": { + "application/json": { "schema": { - "type": "string", - "format": "binary" - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/dictionary/{id}": { - "patch": { - "tags": [ - "Dictionary" - ], - "operationId": "UpdateDictionary_Update", - "parameters": [ - { - "name": "id", - "in": "path", - "required": true, - "schema": { - "type": "string", - "format": "guid" - }, - "x-position": 1 - } - ], - "requestBody": { - "x-name": "updateViewModel", - "content": { - "application/json": { - "schema": { - "type": "array", - "items": { - "$ref": "#/components/schemas/JsonPatchViewModel" - } - } - } - }, - "required": true, - "x-position": 2 - }, - "responses": { - "200": { - "description": "", - "content": { - "application/octet-stream": { - "schema": { - "type": "string", - "format": "binary" - } - } - } - }, - "404": { - "description": "", - "content": { - "application/octet-stream": { - "schema": { - "type": "string", - "format": "binary" + "$ref": "#/components/schemas/NotFoundResult" } } } @@ -3445,36 +478,22 @@ "tags": [ "Dictionary" ], - "operationId": "UploadDictionary_Upload", "requestBody": { - "content": { - "multipart/form-data": { - "schema": { - "type": "object", - "properties": { - "file": { - "type": "string", - "format": "binary", - "nullable": true - } - } - } - } - } + "content": { } }, "responses": { "200": { - "description": "", + "description": "Success", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DictionaryImportViewModel" + "$ref": "#/components/schemas/DictionaryImport" } } } }, "400": { - "description": "", + "description": "Bad Request", "content": { "application/json": { "schema": { @@ -3486,21 +505,19 @@ } } }, - "/umbraco/management/api/v1/dictionary-item/tree/children": { + "/umbraco/management/api/v1/tree/dictionary/children": { "get": { "tags": [ - "DictionaryItem" + "Dictionary" ], - "operationId": "ChildrenDictionaryItemTree_Children", "parameters": [ { "name": "parentKey", "in": "query", "schema": { "type": "string", - "format": "guid" - }, - "x-position": 1 + "format": "uuid" + } }, { "name": "skip", @@ -3509,8 +526,7 @@ "type": "integer", "format": "int32", "default": 0 - }, - "x-position": 2 + } }, { "name": "take", @@ -3519,17 +535,16 @@ "type": "integer", "format": "int32", "default": 100 - }, - "x-position": 3 + } } ], "responses": { "200": { - "description": "", + "description": "Success", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/PagedViewModelOfEntityTreeItemViewModel" + "$ref": "#/components/schemas/PagedEntityTreeItem" } } } @@ -3537,39 +552,33 @@ } } }, - "/umbraco/management/api/v1/dictionary-item/tree/items": { + "/umbraco/management/api/v1/tree/dictionary/item": { "get": { "tags": [ - "DictionaryItem" + "Dictionary" ], - "operationId": "ItemsDictionaryItemTree_Items", "parameters": [ { "name": "key", - "x-originalName": "keys", "in": "query", - "style": "form", - "explode": true, "schema": { "type": "array", - "nullable": true, "items": { "type": "string", - "format": "guid" + "format": "uuid" } - }, - "x-position": 1 + } } ], "responses": { "200": { - "description": "", + "description": "Success", "content": { "application/json": { "schema": { "type": "array", "items": { - "$ref": "#/components/schemas/FolderTreeItemViewModel" + "$ref": "#/components/schemas/FolderTreeItem" } } } @@ -3578,12 +587,11 @@ } } }, - "/umbraco/management/api/v1/dictionary-item/tree/root": { + "/umbraco/management/api/v1/tree/dictionary/root": { "get": { "tags": [ - "DictionaryItem" + "Dictionary" ], - "operationId": "RootDictionaryItemTree_Root", "parameters": [ { "name": "skip", @@ -3592,8 +600,7 @@ "type": "integer", "format": "int32", "default": 0 - }, - "x-position": 1 + } }, { "name": "take", @@ -3602,17 +609,16 @@ "type": "integer", "format": "int32", "default": 100 - }, - "x-position": 2 + } } ], "responses": { "200": { - "description": "", + "description": "Success", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/PagedViewModelOfEntityTreeItemViewModel" + "$ref": "#/components/schemas/PagedEntityTreeItem" } } } @@ -3620,99 +626,33 @@ } } }, - "/umbraco/management/api/v1/data-type/tree/children": { + "/umbraco/management/api/v1/tree/document-blueprint/item": { "get": { "tags": [ - "DataType" + "Document Blueprint" ], - "operationId": "ChildrenDataTypeTree_Children", - "parameters": [ - { - "name": "parentKey", - "in": "query", - "schema": { - "type": "string", - "format": "guid" - }, - "x-position": 1 - }, - { - "name": "skip", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 0 - }, - "x-position": 2 - }, - { - "name": "take", - "in": "query", - "schema": { - "type": "integer", - "format": "int32", - "default": 100 - }, - "x-position": 3 - }, - { - "name": "foldersOnly", - "in": "query", - "schema": { - "type": "boolean", - "default": false - }, - "x-position": 4 - } - ], - "responses": { - "200": { - "description": "", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/PagedViewModelOfFolderTreeItemViewModel" - } - } - } - } - } - } - }, - "/umbraco/management/api/v1/data-type/tree/items": { - "get": { - "tags": [ - "DataType" - ], - "operationId": "ItemsDataTypeTree_Items", "parameters": [ { "name": "key", - "x-originalName": "keys", "in": "query", - "style": "form", - "explode": true, "schema": { "type": "array", - "nullable": true, "items": { "type": "string", - "format": "guid" + "format": "uuid" } - }, - "x-position": 1 + } } ], "responses": { "200": { - "description": "", + "description": "Success", "content": { "application/json": { "schema": { "type": "array", "items": { - "$ref": "#/components/schemas/FolderTreeItemViewModel" + "$ref": "#/components/schemas/DocumentBlueprintTreeItem" } } } @@ -3721,12 +661,11 @@ } } }, - "/umbraco/management/api/v1/data-type/tree/root": { + "/umbraco/management/api/v1/tree/document-blueprint/root": { "get": { "tags": [ - "DataType" + "Document Blueprint" ], - "operationId": "RootDataTypeTree_Root", "parameters": [ { "name": "skip", @@ -3735,8 +674,7 @@ "type": "integer", "format": "int32", "default": 0 - }, - "x-position": 1 + } }, { "name": "take", @@ -3745,8 +683,54 @@ "type": "integer", "format": "int32", "default": 100 - }, - "x-position": 2 + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PagedDocumentBlueprintTreeItem" + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/tree/document-type/children": { + "get": { + "tags": [ + "Document Type" + ], + "parameters": [ + { + "name": "parentKey", + "in": "query", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "skip", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 0 + } + }, + { + "name": "take", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 100 + } }, { "name": "foldersOnly", @@ -3754,17 +738,16 @@ "schema": { "type": "boolean", "default": false - }, - "x-position": 3 + } } ], "responses": { "200": { - "description": "", + "description": "Success", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/PagedViewModelOfFolderTreeItemViewModel" + "$ref": "#/components/schemas/PagedDocumentTypeTreeItem" } } } @@ -3772,22 +755,387 @@ } } }, - "/umbraco/management/api/v1/culture": { + "/umbraco/management/api/v1/tree/document-type/item": { "get": { "tags": [ - "Culture" + "Document Type" + ], + "parameters": [ + { + "name": "key", + "in": "query", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DocumentTypeTreeItem" + } + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/tree/document-type/root": { + "get": { + "tags": [ + "Document Type" ], - "summary": "Returns all cultures available for creating languages.", - "operationId": "AllCulture_GetAll", "parameters": [ + { + "name": "skip", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 0 + } + }, + { + "name": "take", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 100 + } + }, + { + "name": "foldersOnly", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PagedDocumentTypeTreeItem" + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/recycle-bin/document/children": { + "get": { + "tags": [ + "Document" + ], + "parameters": [ + { + "name": "parentKey", + "in": "query", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "skip", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 0 + } + }, + { + "name": "take", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 100 + } + } + ], + "responses": { + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PagedRecycleBinItem" + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/recycle-bin/document/root": { + "get": { + "tags": [ + "Document" + ], + "parameters": [ + { + "name": "skip", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 0 + } + }, + { + "name": "take", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 100 + } + } + ], + "responses": { + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PagedRecycleBinItem" + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/tree/document/children": { + "get": { + "tags": [ + "Document" + ], + "parameters": [ + { + "name": "parentKey", + "in": "query", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "skip", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 0 + } + }, + { + "name": "take", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 100 + } + }, + { + "name": "dataTypeKey", + "in": "query", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "culture", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PagedDocumentTreeItem" + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/tree/document/item": { + "get": { + "tags": [ + "Document" + ], + "parameters": [ + { + "name": "key", + "in": "query", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + }, + { + "name": "dataTypeKey", + "in": "query", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "culture", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DocumentTreeItem" + } + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/tree/document/root": { + "get": { + "tags": [ + "Document" + ], + "parameters": [ + { + "name": "skip", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 0 + } + }, + { + "name": "take", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 100 + } + }, + { + "name": "dataTypeKey", + "in": "query", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "culture", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PagedDocumentTreeItem" + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/help": { + "get": { + "tags": [ + "Help" + ], + "parameters": [ + { + "name": "section", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "tree", + "in": "query", + "schema": { + "type": "string" + } + }, { "name": "skip", "in": "query", "schema": { "type": "integer", "format": "int32" - }, - "x-position": 1 + } }, { "name": "take", @@ -3795,17 +1143,34 @@ "schema": { "type": "integer", "format": "int32" - }, - "x-position": 2 + } + }, + { + "name": "baseUrl", + "in": "query", + "schema": { + "type": "string", + "default": "https://our.umbraco.com" + } } ], "responses": { - "200": { - "description": "", + "400": { + "description": "Bad Request", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/PagedViewModelOfCultureViewModel" + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PagedHelpPage" } } } @@ -3813,12 +1178,122 @@ } } }, - "/umbraco/management/api/v1/analytics/all": { + "/umbraco/management/api/v1/install/settings": { "get": { "tags": [ - "Analytics" + "Install" + ], + "responses": { + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "428": { + "description": "Client Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InstallSettings" + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/install/setup": { + "post": { + "tags": [ + "Install" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Install" + } + } + } + }, + "responses": { + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "428": { + "description": "Client Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "200": { + "description": "Success" + } + } + } + }, + "/umbraco/management/api/v1/install/validate-database": { + "post": { + "tags": [ + "Install" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DatabaseInstall" + } + } + } + }, + "responses": { + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "200": { + "description": "Success" + } + } + } + }, + "/umbraco/management/api/v1/language": { + "get": { + "tags": [ + "Language" ], - "operationId": "AllAnalytics_GetAll", "parameters": [ { "name": "skip", @@ -3826,8 +1301,7 @@ "schema": { "type": "integer", "format": "int32" - }, - "x-position": 1 + } }, { "name": "take", @@ -3835,17 +1309,16 @@ "schema": { "type": "integer", "format": "int32" - }, - "x-position": 2 + } } ], "responses": { "200": { - "description": "", + "description": "Success", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/PagedViewModelOfTelemetryLevel" + "$ref": "#/components/schemas/PagedLanguage" } } } @@ -3853,19 +1326,1823 @@ } } }, - "/umbraco/management/api/v1/analytics": { + "/umbraco/management/api/v1/language/{id}": { "get": { "tags": [ - "Analytics" + "Language" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } ], - "operationId": "GetAnalytics_Get", "responses": { - "200": { - "description": "", + "404": { + "description": "Not Found", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/AnalyticsLevelViewModel" + "$ref": "#/components/schemas/NotFoundResult" + } + } + } + }, + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Language" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Language" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "200": { + "description": "Success" + } + } + } + }, + "/umbraco/management/api/v1/language/create": { + "post": { + "tags": [ + "Language" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Language" + } + } + } + }, + "responses": { + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "201": { + "description": "Created" + } + } + } + }, + "/umbraco/management/api/v1/language/update": { + "put": { + "tags": [ + "Language" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Language" + } + } + } + }, + "responses": { + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotFoundResult" + } + } + } + }, + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "200": { + "description": "Success" + } + } + } + }, + "/umbraco/management/api/v1/tree/media-type/children": { + "get": { + "tags": [ + "Media Type" + ], + "parameters": [ + { + "name": "parentKey", + "in": "query", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "skip", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 0 + } + }, + { + "name": "take", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 100 + } + }, + { + "name": "foldersOnly", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PagedFolderTreeItem" + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/tree/media-type/item": { + "get": { + "tags": [ + "Media Type" + ], + "parameters": [ + { + "name": "key", + "in": "query", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FolderTreeItem" + } + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/tree/media-type/root": { + "get": { + "tags": [ + "Media Type" + ], + "parameters": [ + { + "name": "skip", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 0 + } + }, + { + "name": "take", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 100 + } + }, + { + "name": "foldersOnly", + "in": "query", + "schema": { + "type": "boolean", + "default": false + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PagedFolderTreeItem" + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/recycle-bin/media/children": { + "get": { + "tags": [ + "Media" + ], + "parameters": [ + { + "name": "parentKey", + "in": "query", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "skip", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 0 + } + }, + { + "name": "take", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 100 + } + } + ], + "responses": { + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PagedRecycleBinItem" + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/recycle-bin/media/root": { + "get": { + "tags": [ + "Media" + ], + "parameters": [ + { + "name": "skip", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 0 + } + }, + { + "name": "take", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 100 + } + } + ], + "responses": { + "401": { + "description": "Unauthorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PagedRecycleBinItem" + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/tree/media/children": { + "get": { + "tags": [ + "Media" + ], + "parameters": [ + { + "name": "parentKey", + "in": "query", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "skip", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 0 + } + }, + { + "name": "take", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 100 + } + }, + { + "name": "dataTypeKey", + "in": "query", + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PagedContentTreeItem" + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/tree/media/item": { + "get": { + "tags": [ + "Media" + ], + "parameters": [ + { + "name": "key", + "in": "query", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + }, + { + "name": "dataTypeKey", + "in": "query", + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ContentTreeItem" + } + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/tree/media/root": { + "get": { + "tags": [ + "Media" + ], + "parameters": [ + { + "name": "skip", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 0 + } + }, + { + "name": "take", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 100 + } + }, + { + "name": "dataTypeKey", + "in": "query", + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PagedContentTreeItem" + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/tree/member-group/item": { + "get": { + "tags": [ + "Member Group" + ], + "parameters": [ + { + "name": "key", + "in": "query", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EntityTreeItem" + } + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/tree/member-group/root": { + "get": { + "tags": [ + "Member Group" + ], + "parameters": [ + { + "name": "skip", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 0 + } + }, + { + "name": "take", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 100 + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PagedEntityTreeItem" + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/tree/member-type/item": { + "get": { + "tags": [ + "Member Type" + ], + "parameters": [ + { + "name": "key", + "in": "query", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EntityTreeItem" + } + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/tree/member-type/root": { + "get": { + "tags": [ + "Member Type" + ], + "parameters": [ + { + "name": "skip", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 0 + } + }, + { + "name": "take", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 100 + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PagedEntityTreeItem" + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/models-builder/build": { + "post": { + "tags": [ + "Models Builder" + ], + "responses": { + "201": { + "description": "Created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreatedResult" + } + } + } + }, + "428": { + "description": "Client Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/models-builder/dashboard": { + "get": { + "tags": [ + "Models Builder" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ModelsBuilder" + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/models-builder/status": { + "get": { + "tags": [ + "Models Builder" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OutOfDateStatus" + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/tree/partial-view/children": { + "get": { + "tags": [ + "Partial View" + ], + "parameters": [ + { + "name": "path", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "skip", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 0 + } + }, + { + "name": "take", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 100 + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PagedFileSystemTreeItem" + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/tree/partial-view/item": { + "get": { + "tags": [ + "Partial View" + ], + "parameters": [ + { + "name": "path", + "in": "query", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FileSystemTreeItem" + } + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/tree/partial-view/root": { + "get": { + "tags": [ + "Partial View" + ], + "parameters": [ + { + "name": "skip", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 0 + } + }, + { + "name": "take", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 100 + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PagedFileSystemTreeItem" + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/profiling/status": { + "get": { + "tags": [ + "Profiling" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProfilingStatus" + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/published-cache/collect": { + "post": { + "tags": [ + "Published Cache" + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/umbraco/management/api/v1/published-cache/rebuild": { + "post": { + "tags": [ + "Published Cache" + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/umbraco/management/api/v1/published-cache/reload": { + "post": { + "tags": [ + "Published Cache" + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/umbraco/management/api/v1/published-cache/status": { + "get": { + "tags": [ + "Published Cache" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/tree/relation-type/item": { + "get": { + "tags": [ + "Relation Type" + ], + "parameters": [ + { + "name": "key", + "in": "query", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FolderTreeItem" + } + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/tree/relation-type/root": { + "get": { + "tags": [ + "Relation Type" + ], + "parameters": [ + { + "name": "skip", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 0 + } + }, + { + "name": "take", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 100 + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PagedEntityTreeItem" + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/relation/{id}": { + "get": { + "tags": [ + "Relation" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Relation" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotFoundResult" + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/relation/child-relation/{childId}": { + "get": { + "tags": [ + "Relation" + ], + "parameters": [ + { + "name": "childId", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "skip", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "take", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "relationTypeAlias", + "in": "query", + "schema": { + "type": "string", + "default": "" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PagedRelation" + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/tree/script/children": { + "get": { + "tags": [ + "Script" + ], + "parameters": [ + { + "name": "path", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "skip", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 0 + } + }, + { + "name": "take", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 100 + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PagedFileSystemTreeItem" + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/tree/script/item": { + "get": { + "tags": [ + "Script" + ], + "parameters": [ + { + "name": "path", + "in": "query", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FileSystemTreeItem" + } + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/tree/script/root": { + "get": { + "tags": [ + "Script" + ], + "parameters": [ + { + "name": "skip", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 0 + } + }, + { + "name": "take", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 100 + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PagedFileSystemTreeItem" + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/search/index": { + "get": { + "tags": [ + "Search" + ], + "parameters": [ + { + "name": "skip", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "take", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PagedIndex" + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/search/index/{indexName}": { + "get": { + "tags": [ + "Search" + ], + "parameters": [ + { + "name": "indexName", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Index" + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/search/index/{indexName}/rebuild": { + "post": { + "tags": [ + "Search" + ], + "parameters": [ + { + "name": "indexName", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OkResult" + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/search/searcher": { + "get": { + "tags": [ + "Search" + ], + "parameters": [ + { + "name": "skip", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "take", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PagedSearcher" + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/search/searcher/{searcherName}/search": { + "get": { + "tags": [ + "Search" + ], + "parameters": [ + { + "name": "searcherName", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "query", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "skip", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "take", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PagedPaged" + } + } + } + }, + "404": { + "description": "Not Found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/security/back-office/authorize": { + "get": { + "tags": [ + "Security" + ], + "responses": { + "200": { + "description": "Success" + } + } + }, + "post": { + "tags": [ + "Security" + ], + "responses": { + "200": { + "description": "Success" + } + } + } + }, + "/umbraco/management/api/v1/server/status": { + "get": { + "tags": [ + "Server" + ], + "responses": { + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServerStatus" + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/server/version": { + "get": { + "tags": [ + "Server" + ], + "responses": { + "400": { + "description": "Bad Request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Version" + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/tree/static-file/children": { + "get": { + "tags": [ + "Static File" + ], + "parameters": [ + { + "name": "path", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "skip", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 0 + } + }, + { + "name": "take", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 100 + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PagedFileSystemTreeItem" + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/tree/static-file/item": { + "get": { + "tags": [ + "Static File" + ], + "parameters": [ + { + "name": "path", + "in": "query", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FileSystemTreeItem" + } + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/tree/static-file/root": { + "get": { + "tags": [ + "Static File" + ], + "parameters": [ + { + "name": "skip", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 0 + } + }, + { + "name": "take", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 100 + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PagedFileSystemTreeItem" + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/tree/stylesheet/children": { + "get": { + "tags": [ + "Stylesheet" + ], + "parameters": [ + { + "name": "path", + "in": "query", + "schema": { + "type": "string" + } + }, + { + "name": "skip", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 0 + } + }, + { + "name": "take", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 100 + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PagedFileSystemTreeItem" + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/tree/stylesheet/item": { + "get": { + "tags": [ + "Stylesheet" + ], + "parameters": [ + { + "name": "path", + "in": "query", + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FileSystemTreeItem" + } + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/tree/stylesheet/root": { + "get": { + "tags": [ + "Stylesheet" + ], + "parameters": [ + { + "name": "skip", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 0 + } + }, + { + "name": "take", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 100 + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PagedFileSystemTreeItem" + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/telemetry": { + "get": { + "tags": [ + "Telemetry" + ], + "parameters": [ + { + "name": "skip", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "take", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PagedTelemetry" + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/telemetry/level": { + "get": { + "tags": [ + "Telemetry" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Telemetry" } } } @@ -3874,24 +3151,20 @@ }, "post": { "tags": [ - "Analytics" + "Telemetry" ], - "operationId": "SetAnalytics_SetConsentLevel", "requestBody": { - "x-name": "analyticsLevelViewModel", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/AnalyticsLevelViewModel" + "$ref": "#/components/schemas/Telemetry" } } - }, - "required": true, - "x-position": 1 + } }, "responses": { "400": { - "description": "", + "description": "Bad Request", "content": { "application/json": { "schema": { @@ -3901,7 +3174,350 @@ } }, "200": { - "description": "" + "description": "Success" + } + } + } + }, + "/umbraco/management/api/v1/tree/template/children": { + "get": { + "tags": [ + "Template" + ], + "parameters": [ + { + "name": "parentKey", + "in": "query", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "skip", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 0 + } + }, + { + "name": "take", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 100 + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PagedEntityTreeItem" + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/tree/template/item": { + "get": { + "tags": [ + "Template" + ], + "parameters": [ + { + "name": "key", + "in": "query", + "schema": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + } + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EntityTreeItem" + } + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/tree/template/root": { + "get": { + "tags": [ + "Template" + ], + "parameters": [ + { + "name": "skip", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 0 + } + }, + { + "name": "take", + "in": "query", + "schema": { + "type": "integer", + "format": "int32", + "default": 100 + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PagedEntityTreeItem" + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/tracked-reference/{id}": { + "get": { + "tags": [ + "Tracked Reference" + ], + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "skip", + "in": "query", + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "take", + "in": "query", + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "filterMustBeIsDependency", + "in": "query", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PagedRelationItem" + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/tracked-reference/descendants/{parentId}": { + "get": { + "tags": [ + "Tracked Reference" + ], + "parameters": [ + { + "name": "parentId", + "in": "path", + "required": true, + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "skip", + "in": "query", + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "take", + "in": "query", + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "filterMustBeIsDependency", + "in": "query", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PagedRelationItem" + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/tracked-reference/item": { + "get": { + "tags": [ + "Tracked Reference" + ], + "parameters": [ + { + "name": "ids", + "in": "query", + "schema": { + "type": "array", + "items": { + "type": "integer", + "format": "int32" + } + } + }, + { + "name": "skip", + "in": "query", + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "take", + "in": "query", + "schema": { + "type": "integer", + "format": "int64" + } + }, + { + "name": "filterMustBeIsDependency", + "in": "query", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PagedRelationItem" + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/upgrade/authorize": { + "post": { + "tags": [ + "Upgrade" + ], + "responses": { + "200": { + "description": "Success" + }, + "428": { + "description": "Client Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + }, + "500": { + "description": "Server Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } + } + } + } + }, + "/umbraco/management/api/v1/upgrade/settings": { + "get": { + "tags": [ + "Upgrade" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpgradeSettings" + } + } + } + }, + "428": { + "description": "Client Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } } } @@ -3909,11 +3525,2317 @@ }, "components": { "schemas": { + "Assembly": { + "type": "object", + "properties": { + "definedTypes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TypeInfo" + }, + "nullable": true, + "readOnly": true + }, + "exportedTypes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Type" + }, + "nullable": true, + "readOnly": true + }, + "codeBase": { + "type": "string", + "nullable": true, + "readOnly": true, + "deprecated": true + }, + "entryPoint": { + "$ref": "#/components/schemas/MethodInfo" + }, + "fullName": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "imageRuntimeVersion": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "isDynamic": { + "type": "boolean", + "readOnly": true + }, + "location": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "reflectionOnly": { + "type": "boolean", + "readOnly": true + }, + "isCollectible": { + "type": "boolean", + "readOnly": true + }, + "isFullyTrusted": { + "type": "boolean", + "readOnly": true + }, + "customAttributes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CustomAttributeData" + }, + "nullable": true, + "readOnly": true + }, + "escapedCodeBase": { + "type": "string", + "nullable": true, + "readOnly": true, + "deprecated": true + }, + "manifestModule": { + "$ref": "#/components/schemas/Module" + }, + "modules": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Module" + }, + "nullable": true, + "readOnly": true + }, + "globalAssemblyCache": { + "type": "boolean", + "readOnly": true, + "deprecated": true + }, + "hostContext": { + "type": "integer", + "format": "int64", + "readOnly": true + }, + "securityRuleSet": { + "$ref": "#/components/schemas/SecurityRuleSet" + } + }, + "additionalProperties": false + }, + "BackOfficeNotification": { + "type": "object", + "properties": { + "header": { + "type": "string", + "nullable": true + }, + "message": { + "type": "string", + "nullable": true + }, + "notificationType": { + "$ref": "#/components/schemas/NotificationStyle" + } + }, + "additionalProperties": false + }, + "CallingConventions": { + "enum": [ + "Standard", + "VarArgs", + "Any", + "HasThis", + "ExplicitThis" + ], + "type": "integer", + "format": "int32" + }, + "ConsentLevel": { + "type": "object", + "properties": { + "level": { + "$ref": "#/components/schemas/TelemetryLevel" + }, + "description": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "ConstructorInfo": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "declaringType": { + "$ref": "#/components/schemas/Type" + }, + "reflectedType": { + "$ref": "#/components/schemas/Type" + }, + "module": { + "$ref": "#/components/schemas/Module" + }, + "customAttributes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CustomAttributeData" + }, + "nullable": true, + "readOnly": true + }, + "isCollectible": { + "type": "boolean", + "readOnly": true + }, + "metadataToken": { + "type": "integer", + "format": "int32", + "readOnly": true + }, + "attributes": { + "$ref": "#/components/schemas/MethodAttributes" + }, + "methodImplementationFlags": { + "$ref": "#/components/schemas/MethodImplAttributes" + }, + "callingConvention": { + "$ref": "#/components/schemas/CallingConventions" + }, + "isAbstract": { + "type": "boolean", + "readOnly": true + }, + "isConstructor": { + "type": "boolean", + "readOnly": true + }, + "isFinal": { + "type": "boolean", + "readOnly": true + }, + "isHideBySig": { + "type": "boolean", + "readOnly": true + }, + "isSpecialName": { + "type": "boolean", + "readOnly": true + }, + "isStatic": { + "type": "boolean", + "readOnly": true + }, + "isVirtual": { + "type": "boolean", + "readOnly": true + }, + "isAssembly": { + "type": "boolean", + "readOnly": true + }, + "isFamily": { + "type": "boolean", + "readOnly": true + }, + "isFamilyAndAssembly": { + "type": "boolean", + "readOnly": true + }, + "isFamilyOrAssembly": { + "type": "boolean", + "readOnly": true + }, + "isPrivate": { + "type": "boolean", + "readOnly": true + }, + "isPublic": { + "type": "boolean", + "readOnly": true + }, + "isConstructedGenericMethod": { + "type": "boolean", + "readOnly": true + }, + "isGenericMethod": { + "type": "boolean", + "readOnly": true + }, + "isGenericMethodDefinition": { + "type": "boolean", + "readOnly": true + }, + "containsGenericParameters": { + "type": "boolean", + "readOnly": true + }, + "methodHandle": { + "$ref": "#/components/schemas/RuntimeMethodHandle" + }, + "isSecurityCritical": { + "type": "boolean", + "readOnly": true + }, + "isSecuritySafeCritical": { + "type": "boolean", + "readOnly": true + }, + "isSecurityTransparent": { + "type": "boolean", + "readOnly": true + }, + "memberType": { + "$ref": "#/components/schemas/MemberTypes" + } + }, + "additionalProperties": false + }, + "ContentApp": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true + }, + "alias": { + "type": "string", + "nullable": true + }, + "weight": { + "type": "integer", + "format": "int32" + }, + "icon": { + "type": "string", + "nullable": true + }, + "view": { + "type": "string", + "nullable": true + }, + "viewModel": { + "nullable": true + }, + "active": { + "type": "boolean" + }, + "badge": { + "$ref": "#/components/schemas/ContentAppBadge" + } + }, + "additionalProperties": false + }, + "ContentAppBadge": { + "type": "object", + "properties": { + "count": { + "type": "integer", + "format": "int32" + }, + "type": { + "$ref": "#/components/schemas/ContentAppBadgeType" + } + }, + "additionalProperties": false + }, + "ContentAppBadgeType": { + "enum": [ + "default", + "warning", + "alert" + ], + "type": "integer", + "format": "int32" + }, + "ContentResult": { + "type": "object", + "properties": { + "content": { + "type": "string", + "nullable": true + }, + "contentType": { + "type": "string", + "nullable": true + }, + "statusCode": { + "type": "integer", + "format": "int32", + "nullable": true + } + }, + "additionalProperties": false + }, + "ContentTreeItem": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true + }, + "type": { + "type": "string", + "nullable": true + }, + "icon": { + "type": "string", + "nullable": true + }, + "hasChildren": { + "type": "boolean" + }, + "key": { + "type": "string", + "format": "uuid" + }, + "isContainer": { + "type": "boolean" + }, + "parentKey": { + "type": "string", + "format": "uuid", + "nullable": true + }, + "noAccess": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "CreatedResult": { + "type": "object", + "properties": { + "value": { + "nullable": true + }, + "formatters": { + "type": "array", + "items": { + "$ref": "#/components/schemas/IOutputFormatter" + }, + "nullable": true + }, + "contentTypes": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + }, + "declaredType": { + "$ref": "#/components/schemas/Type" + }, + "statusCode": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "location": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "Culture": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true + }, + "englishName": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "CustomAttributeData": { + "type": "object", + "properties": { + "attributeType": { + "$ref": "#/components/schemas/Type" + }, + "constructor": { + "$ref": "#/components/schemas/ConstructorInfo" + }, + "constructorArguments": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CustomAttributeTypedArgument" + }, + "nullable": true, + "readOnly": true + }, + "namedArguments": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CustomAttributeNamedArgument" + }, + "nullable": true, + "readOnly": true + } + }, + "additionalProperties": false + }, + "CustomAttributeNamedArgument": { + "type": "object", + "properties": { + "memberInfo": { + "$ref": "#/components/schemas/MemberInfo" + }, + "typedValue": { + "$ref": "#/components/schemas/CustomAttributeTypedArgument" + }, + "memberName": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "isField": { + "type": "boolean", + "readOnly": true + } + }, + "additionalProperties": false + }, + "CustomAttributeTypedArgument": { + "type": "object", + "properties": { + "argumentType": { + "$ref": "#/components/schemas/Type" + }, + "value": { + "nullable": true + } + }, + "additionalProperties": false + }, + "DatabaseInstall": { + "required": [ + "id", + "providerName" + ], + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "providerName": { + "minLength": 1, + "type": "string" + }, + "server": { + "type": "string", + "nullable": true + }, + "name": { + "type": "string", + "nullable": true + }, + "username": { + "type": "string", + "nullable": true + }, + "password": { + "type": "string", + "nullable": true + }, + "useIntegratedAuthentication": { + "type": "boolean" + }, + "connectionString": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "DatabaseSettings": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid" + }, + "sortOrder": { + "type": "integer", + "format": "int32" + }, + "displayName": { + "type": "string", + "nullable": true + }, + "defaultDatabaseName": { + "type": "string", + "nullable": true + }, + "providerName": { + "type": "string", + "nullable": true + }, + "isConfigured": { + "type": "boolean" + }, + "requiresServer": { + "type": "boolean" + }, + "serverPlaceholder": { + "type": "string", + "nullable": true + }, + "requiresCredentials": { + "type": "boolean" + }, + "supportsIntegratedAuthentication": { + "type": "boolean" + }, + "requiresConnectionTest": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "Dictionary": { + "required": [ + "name" + ], + "type": "object", + "properties": { + "parentId": { + "type": "string", + "format": "uuid", + "nullable": true + }, + "translations": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DictionaryTranslation" + }, + "nullable": true + }, + "contentApps": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ContentApp" + }, + "nullable": true + }, + "notifications": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BackOfficeNotification" + }, + "nullable": true, + "readOnly": true + }, + "name": { + "minLength": 1, + "type": "string" + }, + "key": { + "type": "string", + "format": "uuid" + }, + "path": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "DictionaryImport": { + "type": "object", + "properties": { + "dictionaryItems": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DictionaryItemsImport" + }, + "nullable": true + }, + "tempFileName": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "DictionaryItem": { + "type": "object", + "properties": { + "parentId": { + "type": "string", + "format": "uuid", + "nullable": true + }, + "key": { + "type": "string", + "format": "uuid" + } + }, + "additionalProperties": false + }, + "DictionaryItemsImport": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true + }, + "level": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + }, + "DictionaryOverview": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true + }, + "key": { + "type": "string", + "format": "uuid" + }, + "level": { + "type": "integer", + "format": "int32" + }, + "translations": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DictionaryTranslationOverview" + }, + "nullable": true, + "readOnly": true + } + }, + "additionalProperties": false + }, + "DictionaryTranslation": { + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "key": { + "type": "string", + "format": "uuid" + }, + "displayName": { + "type": "string", + "nullable": true + }, + "isoCode": { + "type": "string", + "nullable": true + }, + "translation": { + "type": "string", + "nullable": true + }, + "languageId": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + }, + "DictionaryTranslationOverview": { + "type": "object", + "properties": { + "displayName": { + "type": "string", + "nullable": true + }, + "hasTranslation": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "DocumentBlueprintTreeItem": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true + }, + "type": { + "type": "string", + "nullable": true + }, + "icon": { + "type": "string", + "nullable": true + }, + "hasChildren": { + "type": "boolean" + }, + "key": { + "type": "string", + "format": "uuid" + }, + "isContainer": { + "type": "boolean" + }, + "parentKey": { + "type": "string", + "format": "uuid", + "nullable": true + }, + "documentTypeKey": { + "type": "string", + "format": "uuid" + }, + "documentTypeAlias": { + "type": "string", + "nullable": true + }, + "documentTypeName": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "DocumentTreeItem": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true + }, + "type": { + "type": "string", + "nullable": true + }, + "icon": { + "type": "string", + "nullable": true + }, + "hasChildren": { + "type": "boolean" + }, + "key": { + "type": "string", + "format": "uuid" + }, + "isContainer": { + "type": "boolean" + }, + "parentKey": { + "type": "string", + "format": "uuid", + "nullable": true + }, + "noAccess": { + "type": "boolean" + }, + "isProtected": { + "type": "boolean" + }, + "isPublished": { + "type": "boolean" + }, + "isEdited": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "DocumentTypeTreeItem": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true + }, + "type": { + "type": "string", + "nullable": true + }, + "icon": { + "type": "string", + "nullable": true + }, + "hasChildren": { + "type": "boolean" + }, + "key": { + "type": "string", + "format": "uuid" + }, + "isContainer": { + "type": "boolean" + }, + "parentKey": { + "type": "string", + "format": "uuid", + "nullable": true + }, + "isFolder": { + "type": "boolean" + }, + "isElement": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "EntityTreeItem": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true + }, + "type": { + "type": "string", + "nullable": true + }, + "icon": { + "type": "string", + "nullable": true + }, + "hasChildren": { + "type": "boolean" + }, + "key": { + "type": "string", + "format": "uuid" + }, + "isContainer": { + "type": "boolean" + }, + "parentKey": { + "type": "string", + "format": "uuid", + "nullable": true + } + }, + "additionalProperties": false + }, + "EventAttributes": { + "enum": [ + "None", + "SpecialName", + "RTSpecialName", + "ReservedMask" + ], + "type": "integer", + "format": "int32" + }, + "EventInfo": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "declaringType": { + "$ref": "#/components/schemas/Type" + }, + "reflectedType": { + "$ref": "#/components/schemas/Type" + }, + "module": { + "$ref": "#/components/schemas/Module" + }, + "customAttributes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CustomAttributeData" + }, + "nullable": true, + "readOnly": true + }, + "isCollectible": { + "type": "boolean", + "readOnly": true + }, + "metadataToken": { + "type": "integer", + "format": "int32", + "readOnly": true + }, + "memberType": { + "$ref": "#/components/schemas/MemberTypes" + }, + "attributes": { + "$ref": "#/components/schemas/EventAttributes" + }, + "isSpecialName": { + "type": "boolean", + "readOnly": true + }, + "addMethod": { + "$ref": "#/components/schemas/MethodInfo" + }, + "removeMethod": { + "$ref": "#/components/schemas/MethodInfo" + }, + "raiseMethod": { + "$ref": "#/components/schemas/MethodInfo" + }, + "isMulticast": { + "type": "boolean", + "readOnly": true + }, + "eventHandlerType": { + "$ref": "#/components/schemas/Type" + } + }, + "additionalProperties": false + }, + "Field": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true + }, + "values": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "FieldAttributes": { + "enum": [ + "PrivateScope", + "Private", + "FamANDAssem", + "Assembly", + "Family", + "FamORAssem", + "Public", + "FieldAccessMask", + "Static", + "InitOnly", + "Literal", + "NotSerialized", + "HasFieldRVA", + "SpecialName", + "RTSpecialName", + "HasFieldMarshal", + "PinvokeImpl", + "HasDefault", + "ReservedMask" + ], + "type": "integer", + "format": "int32" + }, + "FieldInfo": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "declaringType": { + "$ref": "#/components/schemas/Type" + }, + "reflectedType": { + "$ref": "#/components/schemas/Type" + }, + "module": { + "$ref": "#/components/schemas/Module" + }, + "customAttributes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CustomAttributeData" + }, + "nullable": true, + "readOnly": true + }, + "isCollectible": { + "type": "boolean", + "readOnly": true + }, + "metadataToken": { + "type": "integer", + "format": "int32", + "readOnly": true + }, + "memberType": { + "$ref": "#/components/schemas/MemberTypes" + }, + "attributes": { + "$ref": "#/components/schemas/FieldAttributes" + }, + "fieldType": { + "$ref": "#/components/schemas/Type" + }, + "isInitOnly": { + "type": "boolean", + "readOnly": true + }, + "isLiteral": { + "type": "boolean", + "readOnly": true + }, + "isNotSerialized": { + "type": "boolean", + "readOnly": true + }, + "isPinvokeImpl": { + "type": "boolean", + "readOnly": true + }, + "isSpecialName": { + "type": "boolean", + "readOnly": true + }, + "isStatic": { + "type": "boolean", + "readOnly": true + }, + "isAssembly": { + "type": "boolean", + "readOnly": true + }, + "isFamily": { + "type": "boolean", + "readOnly": true + }, + "isFamilyAndAssembly": { + "type": "boolean", + "readOnly": true + }, + "isFamilyOrAssembly": { + "type": "boolean", + "readOnly": true + }, + "isPrivate": { + "type": "boolean", + "readOnly": true + }, + "isPublic": { + "type": "boolean", + "readOnly": true + }, + "isSecurityCritical": { + "type": "boolean", + "readOnly": true + }, + "isSecuritySafeCritical": { + "type": "boolean", + "readOnly": true + }, + "isSecurityTransparent": { + "type": "boolean", + "readOnly": true + }, + "fieldHandle": { + "$ref": "#/components/schemas/RuntimeFieldHandle" + } + }, + "additionalProperties": false + }, + "FileSystemTreeItem": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true + }, + "type": { + "type": "string", + "nullable": true + }, + "icon": { + "type": "string", + "nullable": true + }, + "hasChildren": { + "type": "boolean" + }, + "path": { + "type": "string", + "nullable": true + }, + "isFolder": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "FolderTreeItem": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true + }, + "type": { + "type": "string", + "nullable": true + }, + "icon": { + "type": "string", + "nullable": true + }, + "hasChildren": { + "type": "boolean" + }, + "key": { + "type": "string", + "format": "uuid" + }, + "isContainer": { + "type": "boolean" + }, + "parentKey": { + "type": "string", + "format": "uuid", + "nullable": true + }, + "isFolder": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "GenericParameterAttributes": { + "enum": [ + "None", + "Covariant", + "Contravariant", + "VarianceMask", + "ReferenceTypeConstraint", + "NotNullableValueTypeConstraint", + "DefaultConstructorConstraint", + "SpecialConstraintMask" + ], + "type": "integer", + "format": "int32" + }, + "HelpPage": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true + }, + "description": { + "type": "string", + "nullable": true + }, + "url": { + "type": "string", + "nullable": true + }, + "type": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "ICustomAttributeProvider": { + "type": "object", + "additionalProperties": false + }, + "IOutputFormatter": { + "type": "object", + "additionalProperties": false + }, + "Index": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true + }, + "healthStatus": { + "type": "string", + "nullable": true + }, + "isHealthy": { + "type": "boolean", + "readOnly": true + }, + "canRebuild": { + "type": "boolean" + }, + "searcherName": { + "type": "string", + "nullable": true + }, + "documentCount": { + "type": "integer", + "format": "int64" + }, + "fieldCount": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + }, + "Install": { + "required": [ + "database", + "user" + ], + "type": "object", + "properties": { + "user": { + "$ref": "#/components/schemas/UserInstall" + }, + "database": { + "$ref": "#/components/schemas/DatabaseInstall" + }, + "telemetryLevel": { + "$ref": "#/components/schemas/TelemetryLevel" + } + }, + "additionalProperties": false + }, + "InstallSettings": { + "type": "object", + "properties": { + "user": { + "$ref": "#/components/schemas/UserSettings" + }, + "databases": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DatabaseSettings" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "IntPtr": { + "type": "object", + "additionalProperties": false + }, + "JsonPatch": { + "type": "object", + "properties": { + "op": { + "type": "string", + "nullable": true + }, + "path": { + "type": "string", + "nullable": true + }, + "value": { + "nullable": true + } + }, + "additionalProperties": false + }, + "Language": { + "required": [ + "isoCode" + ], + "type": "object", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "isoCode": { + "minLength": 1, + "type": "string" + }, + "name": { + "type": "string", + "nullable": true + }, + "isDefault": { + "type": "boolean" + }, + "isMandatory": { + "type": "boolean" + }, + "fallbackLanguageId": { + "type": "integer", + "format": "int32", + "nullable": true + } + }, + "additionalProperties": false + }, + "LayoutKind": { + "enum": [ + "Sequential", + "Explicit", + "Auto" + ], + "type": "integer", + "format": "int32" + }, + "MemberInfo": { + "type": "object", + "properties": { + "memberType": { + "$ref": "#/components/schemas/MemberTypes" + }, + "name": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "declaringType": { + "$ref": "#/components/schemas/Type" + }, + "reflectedType": { + "$ref": "#/components/schemas/Type" + }, + "module": { + "$ref": "#/components/schemas/Module" + }, + "customAttributes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CustomAttributeData" + }, + "nullable": true, + "readOnly": true + }, + "isCollectible": { + "type": "boolean", + "readOnly": true + }, + "metadataToken": { + "type": "integer", + "format": "int32", + "readOnly": true + } + }, + "additionalProperties": false + }, + "MemberTypes": { + "enum": [ + "Constructor", + "Event", + "Field", + "Method", + "Property", + "TypeInfo", + "Custom", + "NestedType", + "All" + ], + "type": "integer", + "format": "int32" + }, + "MethodAttributes": { + "enum": [ + "ReuseSlot", + "PrivateScope", + "Private", + "FamANDAssem", + "Assembly", + "Family", + "FamORAssem", + "Public", + "MemberAccessMask", + "UnmanagedExport", + "Static", + "Final", + "Virtual", + "HideBySig", + "NewSlot", + "VtableLayoutMask", + "CheckAccessOnOverride", + "Abstract", + "SpecialName", + "RTSpecialName", + "PinvokeImpl", + "HasSecurity", + "RequireSecObject", + "ReservedMask" + ], + "type": "integer", + "format": "int32" + }, + "MethodBase": { + "type": "object", + "properties": { + "memberType": { + "$ref": "#/components/schemas/MemberTypes" + }, + "name": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "declaringType": { + "$ref": "#/components/schemas/Type" + }, + "reflectedType": { + "$ref": "#/components/schemas/Type" + }, + "module": { + "$ref": "#/components/schemas/Module" + }, + "customAttributes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CustomAttributeData" + }, + "nullable": true, + "readOnly": true + }, + "isCollectible": { + "type": "boolean", + "readOnly": true + }, + "metadataToken": { + "type": "integer", + "format": "int32", + "readOnly": true + }, + "attributes": { + "$ref": "#/components/schemas/MethodAttributes" + }, + "methodImplementationFlags": { + "$ref": "#/components/schemas/MethodImplAttributes" + }, + "callingConvention": { + "$ref": "#/components/schemas/CallingConventions" + }, + "isAbstract": { + "type": "boolean", + "readOnly": true + }, + "isConstructor": { + "type": "boolean", + "readOnly": true + }, + "isFinal": { + "type": "boolean", + "readOnly": true + }, + "isHideBySig": { + "type": "boolean", + "readOnly": true + }, + "isSpecialName": { + "type": "boolean", + "readOnly": true + }, + "isStatic": { + "type": "boolean", + "readOnly": true + }, + "isVirtual": { + "type": "boolean", + "readOnly": true + }, + "isAssembly": { + "type": "boolean", + "readOnly": true + }, + "isFamily": { + "type": "boolean", + "readOnly": true + }, + "isFamilyAndAssembly": { + "type": "boolean", + "readOnly": true + }, + "isFamilyOrAssembly": { + "type": "boolean", + "readOnly": true + }, + "isPrivate": { + "type": "boolean", + "readOnly": true + }, + "isPublic": { + "type": "boolean", + "readOnly": true + }, + "isConstructedGenericMethod": { + "type": "boolean", + "readOnly": true + }, + "isGenericMethod": { + "type": "boolean", + "readOnly": true + }, + "isGenericMethodDefinition": { + "type": "boolean", + "readOnly": true + }, + "containsGenericParameters": { + "type": "boolean", + "readOnly": true + }, + "methodHandle": { + "$ref": "#/components/schemas/RuntimeMethodHandle" + }, + "isSecurityCritical": { + "type": "boolean", + "readOnly": true + }, + "isSecuritySafeCritical": { + "type": "boolean", + "readOnly": true + }, + "isSecurityTransparent": { + "type": "boolean", + "readOnly": true + } + }, + "additionalProperties": false + }, + "MethodImplAttributes": { + "enum": [ + "IL", + "Managed", + "Native", + "OPTIL", + "Runtime", + "CodeTypeMask", + "Unmanaged", + "ManagedMask", + "NoInlining", + "ForwardRef", + "Synchronized", + "NoOptimization", + "PreserveSig", + "AggressiveInlining", + "AggressiveOptimization", + "InternalCall", + "MaxMethodImplVal" + ], + "type": "integer", + "format": "int32" + }, + "MethodInfo": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "declaringType": { + "$ref": "#/components/schemas/Type" + }, + "reflectedType": { + "$ref": "#/components/schemas/Type" + }, + "module": { + "$ref": "#/components/schemas/Module" + }, + "customAttributes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CustomAttributeData" + }, + "nullable": true, + "readOnly": true + }, + "isCollectible": { + "type": "boolean", + "readOnly": true + }, + "metadataToken": { + "type": "integer", + "format": "int32", + "readOnly": true + }, + "attributes": { + "$ref": "#/components/schemas/MethodAttributes" + }, + "methodImplementationFlags": { + "$ref": "#/components/schemas/MethodImplAttributes" + }, + "callingConvention": { + "$ref": "#/components/schemas/CallingConventions" + }, + "isAbstract": { + "type": "boolean", + "readOnly": true + }, + "isConstructor": { + "type": "boolean", + "readOnly": true + }, + "isFinal": { + "type": "boolean", + "readOnly": true + }, + "isHideBySig": { + "type": "boolean", + "readOnly": true + }, + "isSpecialName": { + "type": "boolean", + "readOnly": true + }, + "isStatic": { + "type": "boolean", + "readOnly": true + }, + "isVirtual": { + "type": "boolean", + "readOnly": true + }, + "isAssembly": { + "type": "boolean", + "readOnly": true + }, + "isFamily": { + "type": "boolean", + "readOnly": true + }, + "isFamilyAndAssembly": { + "type": "boolean", + "readOnly": true + }, + "isFamilyOrAssembly": { + "type": "boolean", + "readOnly": true + }, + "isPrivate": { + "type": "boolean", + "readOnly": true + }, + "isPublic": { + "type": "boolean", + "readOnly": true + }, + "isConstructedGenericMethod": { + "type": "boolean", + "readOnly": true + }, + "isGenericMethod": { + "type": "boolean", + "readOnly": true + }, + "isGenericMethodDefinition": { + "type": "boolean", + "readOnly": true + }, + "containsGenericParameters": { + "type": "boolean", + "readOnly": true + }, + "methodHandle": { + "$ref": "#/components/schemas/RuntimeMethodHandle" + }, + "isSecurityCritical": { + "type": "boolean", + "readOnly": true + }, + "isSecuritySafeCritical": { + "type": "boolean", + "readOnly": true + }, + "isSecurityTransparent": { + "type": "boolean", + "readOnly": true + }, + "memberType": { + "$ref": "#/components/schemas/MemberTypes" + }, + "returnParameter": { + "$ref": "#/components/schemas/ParameterInfo" + }, + "returnType": { + "$ref": "#/components/schemas/Type" + }, + "returnTypeCustomAttributes": { + "$ref": "#/components/schemas/ICustomAttributeProvider" + } + }, + "additionalProperties": false + }, + "ModelsBuilder": { + "type": "object", + "properties": { + "mode": { + "$ref": "#/components/schemas/ModelsMode" + }, + "canGenerate": { + "type": "boolean" + }, + "outOfDateModels": { + "type": "boolean" + }, + "lastError": { + "type": "string", + "nullable": true + }, + "version": { + "type": "string", + "nullable": true + }, + "modelsNamespace": { + "type": "string", + "nullable": true + }, + "trackingOutOfDateModels": { + "type": "boolean" + } + }, + "additionalProperties": false + }, + "ModelsMode": { + "enum": [ + "Nothing", + "InMemoryAuto", + "SourceCodeManual", + "SourceCodeAuto" + ], + "type": "integer", + "format": "int32" + }, + "Module": { + "type": "object", + "properties": { + "assembly": { + "$ref": "#/components/schemas/Assembly" + }, + "fullyQualifiedName": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "name": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "mdStreamVersion": { + "type": "integer", + "format": "int32", + "readOnly": true + }, + "moduleVersionId": { + "type": "string", + "format": "uuid", + "readOnly": true + }, + "scopeName": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "moduleHandle": { + "$ref": "#/components/schemas/ModuleHandle" + }, + "customAttributes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CustomAttributeData" + }, + "nullable": true, + "readOnly": true + }, + "metadataToken": { + "type": "integer", + "format": "int32", + "readOnly": true + } + }, + "additionalProperties": false + }, + "ModuleHandle": { + "type": "object", + "properties": { + "mdStreamVersion": { + "type": "integer", + "format": "int32", + "readOnly": true + } + }, + "additionalProperties": false + }, + "NotFoundResult": { + "type": "object", + "properties": { + "statusCode": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + }, + "NotificationStyle": { + "enum": [ + "Save", + "Info", + "Error", + "Success", + "Warning" + ], + "type": "integer", + "format": "int32" + }, + "OkResult": { + "type": "object", + "properties": { + "statusCode": { + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + }, + "OutOfDateStatus": { + "type": "object", + "properties": { + "status": { + "$ref": "#/components/schemas/OutOfDateType" + } + }, + "additionalProperties": false + }, + "OutOfDateType": { + "enum": [ + "OutOfDate", + "Current", + "Unknown" + ], + "type": "integer", + "format": "int32" + }, + "PagedContentTreeItem": { + "type": "object", + "properties": { + "total": { + "type": "integer", + "format": "int64" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ContentTreeItem" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "PagedCulture": { + "type": "object", + "properties": { + "total": { + "type": "integer", + "format": "int64" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Culture" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "PagedDictionaryOverview": { + "type": "object", + "properties": { + "total": { + "type": "integer", + "format": "int64" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DictionaryOverview" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "PagedDocumentBlueprintTreeItem": { + "type": "object", + "properties": { + "total": { + "type": "integer", + "format": "int64" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DocumentBlueprintTreeItem" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "PagedDocumentTreeItem": { + "type": "object", + "properties": { + "total": { + "type": "integer", + "format": "int64" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DocumentTreeItem" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "PagedDocumentTypeTreeItem": { + "type": "object", + "properties": { + "total": { + "type": "integer", + "format": "int64" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DocumentTypeTreeItem" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "PagedEntityTreeItem": { + "type": "object", + "properties": { + "total": { + "type": "integer", + "format": "int64" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EntityTreeItem" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "PagedFileSystemTreeItem": { + "type": "object", + "properties": { + "total": { + "type": "integer", + "format": "int64" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FileSystemTreeItem" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "PagedFolderTreeItem": { + "type": "object", + "properties": { + "total": { + "type": "integer", + "format": "int64" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FolderTreeItem" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "PagedHelpPage": { + "type": "object", + "properties": { + "total": { + "type": "integer", + "format": "int64" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/HelpPage" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "PagedIndex": { + "type": "object", + "properties": { + "total": { + "type": "integer", + "format": "int64" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Index" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "PagedLanguage": { + "type": "object", + "properties": { + "total": { + "type": "integer", + "format": "int64" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Language" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "PagedPaged": { + "type": "object", + "properties": { + "total": { + "type": "integer", + "format": "int64" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PagedSearchResult" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "PagedRecycleBinItem": { + "type": "object", + "properties": { + "total": { + "type": "integer", + "format": "int64" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RecycleBinItem" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "PagedRelation": { + "type": "object", + "properties": { + "total": { + "type": "integer", + "format": "int64" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Relation" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "PagedRelationItem": { + "type": "object", + "properties": { + "total": { + "type": "integer", + "format": "int64" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RelationItem" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "PagedSearchResult": { + "type": "object", + "properties": { + "total": { + "type": "integer", + "format": "int64" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SearchResult" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "PagedSearcher": { + "type": "object", + "properties": { + "total": { + "type": "integer", + "format": "int64" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Searcher" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "PagedTelemetry": { + "type": "object", + "properties": { + "total": { + "type": "integer", + "format": "int64" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Telemetry" + }, + "nullable": true + } + }, + "additionalProperties": false + }, + "ParameterAttributes": { + "enum": [ + "None", + "In", + "Out", + "Lcid", + "Retval", + "Optional", + "HasDefault", + "HasFieldMarshal", + "Reserved3", + "Reserved4", + "ReservedMask" + ], + "type": "integer", + "format": "int32" + }, + "ParameterInfo": { + "type": "object", + "properties": { + "attributes": { + "$ref": "#/components/schemas/ParameterAttributes" + }, + "member": { + "$ref": "#/components/schemas/MemberInfo" + }, + "name": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "parameterType": { + "$ref": "#/components/schemas/Type" + }, + "position": { + "type": "integer", + "format": "int32", + "readOnly": true + }, + "isIn": { + "type": "boolean", + "readOnly": true + }, + "isLcid": { + "type": "boolean", + "readOnly": true + }, + "isOptional": { + "type": "boolean", + "readOnly": true + }, + "isOut": { + "type": "boolean", + "readOnly": true + }, + "isRetval": { + "type": "boolean", + "readOnly": true + }, + "defaultValue": { + "nullable": true, + "readOnly": true + }, + "rawDefaultValue": { + "nullable": true, + "readOnly": true + }, + "hasDefaultValue": { + "type": "boolean", + "readOnly": true + }, + "customAttributes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CustomAttributeData" + }, + "nullable": true, + "readOnly": true + }, + "metadataToken": { + "type": "integer", + "format": "int32", + "readOnly": true + } + }, + "additionalProperties": false + }, "ProblemDetails": { "type": "object", - "additionalProperties": { - "nullable": true - }, "properties": { "type": { "type": "string", @@ -3936,52 +5858,165 @@ "type": "string", "nullable": true } - } + }, + "additionalProperties": { } }, - "UpgradeSettingsViewModel": { + "ProfilingStatus": { "type": "object", - "additionalProperties": false, "properties": { - "currentState": { - "type": "string" - }, - "newState": { - "type": "string" - }, - "newVersion": { - "type": "string" - }, - "oldVersion": { - "type": "string" - }, - "reportUrl": { - "type": "string" + "enabled": { + "type": "boolean" } - } + }, + "additionalProperties": false }, - "PagedViewModelOfRelationItemViewModel": { + "PropertyAttributes": { + "enum": [ + "None", + "SpecialName", + "RTSpecialName", + "HasDefault", + "Reserved2", + "Reserved3", + "Reserved4", + "ReservedMask" + ], + "type": "integer", + "format": "int32" + }, + "PropertyInfo": { "type": "object", - "additionalProperties": false, "properties": { - "total": { - "type": "integer", - "format": "int64" + "name": { + "type": "string", + "nullable": true, + "readOnly": true }, - "items": { + "declaringType": { + "$ref": "#/components/schemas/Type" + }, + "reflectedType": { + "$ref": "#/components/schemas/Type" + }, + "module": { + "$ref": "#/components/schemas/Module" + }, + "customAttributes": { "type": "array", "items": { - "$ref": "#/components/schemas/RelationItemViewModel" - } + "$ref": "#/components/schemas/CustomAttributeData" + }, + "nullable": true, + "readOnly": true + }, + "isCollectible": { + "type": "boolean", + "readOnly": true + }, + "metadataToken": { + "type": "integer", + "format": "int32", + "readOnly": true + }, + "memberType": { + "$ref": "#/components/schemas/MemberTypes" + }, + "propertyType": { + "$ref": "#/components/schemas/Type" + }, + "attributes": { + "$ref": "#/components/schemas/PropertyAttributes" + }, + "isSpecialName": { + "type": "boolean", + "readOnly": true + }, + "canRead": { + "type": "boolean", + "readOnly": true + }, + "canWrite": { + "type": "boolean", + "readOnly": true + }, + "getMethod": { + "$ref": "#/components/schemas/MethodInfo" + }, + "setMethod": { + "$ref": "#/components/schemas/MethodInfo" } - } + }, + "additionalProperties": false }, - "RelationItemViewModel": { + "RecycleBinItem": { + "type": "object", + "properties": { + "key": { + "type": "string", + "format": "uuid" + }, + "name": { + "type": "string", + "nullable": true + }, + "type": { + "type": "string", + "nullable": true + }, + "icon": { + "type": "string", + "nullable": true + }, + "hasChildren": { + "type": "boolean" + }, + "isContainer": { + "type": "boolean" + }, + "parentKey": { + "type": "string", + "format": "uuid", + "nullable": true + } + }, + "additionalProperties": false + }, + "Relation": { + "type": "object", + "properties": { + "parentId": { + "type": "integer", + "format": "int32" + }, + "parentName": { + "type": "string", + "nullable": true + }, + "childId": { + "type": "integer", + "format": "int32" + }, + "childName": { + "type": "string", + "nullable": true + }, + "createDate": { + "type": "string", + "format": "date-time" + }, + "comment": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "RelationItem": { "type": "object", - "additionalProperties": false, "properties": { "nodeKey": { "type": "string", - "format": "guid" + "format": "uuid" }, "nodeName": { "type": "string", @@ -4013,122 +6048,19 @@ "relationTypeIsDependency": { "type": "boolean" } - } + }, + "additionalProperties": false }, - "PagedViewModelOfEntityTreeItemViewModel": { + "RuntimeFieldHandle": { "type": "object", - "additionalProperties": false, "properties": { - "total": { - "type": "integer", - "format": "int64" - }, - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/EntityTreeItemViewModel" - } + "value": { + "$ref": "#/components/schemas/IntPtr" } - } - }, - "EntityTreeItemViewModel": { - "allOf": [ - { - "$ref": "#/components/schemas/TreeItemViewModel" - }, - { - "type": "object", - "additionalProperties": false, - "properties": { - "key": { - "type": "string", - "format": "guid" - }, - "isContainer": { - "type": "boolean" - }, - "parentKey": { - "type": "string", - "format": "guid", - "nullable": true - } - } - } - ] - }, - "TreeItemViewModel": { - "type": "object", - "additionalProperties": false, - "properties": { - "name": { - "type": "string" - }, - "type": { - "type": "string" - }, - "icon": { - "type": "string" - }, - "hasChildren": { - "type": "boolean" - } - } - }, - "PagedViewModelOfFileSystemTreeItemViewModel": { - "type": "object", - "additionalProperties": false, - "properties": { - "total": { - "type": "integer", - "format": "int64" - }, - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/FileSystemTreeItemViewModel" - } - } - } - }, - "FileSystemTreeItemViewModel": { - "allOf": [ - { - "$ref": "#/components/schemas/TreeItemViewModel" - }, - { - "type": "object", - "additionalProperties": false, - "properties": { - "path": { - "type": "string" - }, - "isFolder": { - "type": "boolean" - } - } - } - ] - }, - "ServerStatusViewModel": { - "type": "object", - "additionalProperties": false, - "properties": { - "serverStatus": { - "$ref": "#/components/schemas/RuntimeLevel" - } - } + }, + "additionalProperties": false }, "RuntimeLevel": { - "type": "string", - "description": "Describes the levels in which the runtime can run.\n ", - "x-enumNames": [ - "Unknown", - "Boot", - "Install", - "Upgrade", - "Run", - "BootFailed" - ], "enum": [ "Unknown", "Boot", @@ -4136,126 +6068,34 @@ "Upgrade", "Run", "BootFailed" - ] + ], + "type": "integer", + "format": "int32" }, - "VersionViewModel": { + "RuntimeMethodHandle": { "type": "object", - "additionalProperties": false, "properties": { - "version": { - "type": "string" + "value": { + "$ref": "#/components/schemas/IntPtr" } - } + }, + "additionalProperties": false }, - "IndexViewModel": { + "RuntimeTypeHandle": { "type": "object", - "additionalProperties": false, "properties": { - "name": { - "type": "string" - }, - "healthStatus": { - "type": "string", - "nullable": true - }, - "isHealthy": { - "type": "boolean" - }, - "canRebuild": { - "type": "boolean" - }, - "searcherName": { - "type": "string" - }, - "documentCount": { - "type": "integer", - "format": "int64" - }, - "fieldCount": { - "type": "integer", - "format": "int32" + "value": { + "$ref": "#/components/schemas/IntPtr" } - } + }, + "additionalProperties": false }, - "PagedViewModelOfIndexViewModel": { + "SearchResult": { "type": "object", - "additionalProperties": false, - "properties": { - "total": { - "type": "integer", - "format": "int64" - }, - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/IndexViewModel" - } - } - } - }, - "PagedViewModelOfSearcherViewModel": { - "type": "object", - "additionalProperties": false, - "properties": { - "total": { - "type": "integer", - "format": "int64" - }, - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SearcherViewModel" - } - } - } - }, - "SearcherViewModel": { - "type": "object", - "additionalProperties": false, - "properties": { - "name": { - "type": "string" - } - } - }, - "PagedViewModelOfPagedViewModelOfSearchResultViewModel": { - "type": "object", - "additionalProperties": false, - "properties": { - "total": { - "type": "integer", - "format": "int64" - }, - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/PagedViewModelOfSearchResultViewModel" - } - } - } - }, - "PagedViewModelOfSearchResultViewModel": { - "type": "object", - "additionalProperties": false, - "properties": { - "total": { - "type": "integer", - "format": "int64" - }, - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SearchResultViewModel" - } - } - } - }, - "SearchResultViewModel": { - "type": "object", - "additionalProperties": false, "properties": { "id": { - "type": "string" + "type": "string", + "nullable": true }, "score": { "type": "number", @@ -4263,297 +6103,830 @@ }, "fieldCount": { "type": "integer", - "format": "int32" + "format": "int32", + "readOnly": true }, "fields": { "type": "array", "items": { - "$ref": "#/components/schemas/FieldViewModel" - } + "$ref": "#/components/schemas/Field" + }, + "nullable": true } - } + }, + "additionalProperties": false }, - "FieldViewModel": { + "Searcher": { "type": "object", - "additionalProperties": false, "properties": { "name": { - "type": "string" - }, - "values": { - "type": "array", - "items": { - "type": "string" - } - } - } - }, - "PagedViewModelOfRelationViewModel": { - "type": "object", - "additionalProperties": false, - "properties": { - "total": { - "type": "integer", - "format": "int64" - }, - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/RelationViewModel" - } - } - } - }, - "RelationViewModel": { - "type": "object", - "additionalProperties": false, - "properties": { - "parentId": { - "type": "integer", - "readOnly": true, - "description": "Gets or sets the Parent Id of the Relation (Source).\n ", - "format": "int32" - }, - "parentName": { "type": "string", - "readOnly": true, - "description": "Gets or sets the Parent Name of the relation (Source).\n ", - "nullable": true - }, - "childId": { - "type": "integer", - "readOnly": true, - "description": "Gets or sets the Child Id of the Relation (Destination).\n ", - "format": "int32" - }, - "childName": { - "type": "string", - "readOnly": true, - "description": "Gets or sets the Child Name of the relation (Destination).\n ", - "nullable": true - }, - "createDate": { - "type": "string", - "readOnly": true, - "description": "Gets or sets the date when the Relation was created.\n ", - "format": "date-time" - }, - "comment": { - "type": "string", - "readOnly": true, - "description": "Gets or sets a comment for the Relation.\n ", "nullable": true } - } + }, + "additionalProperties": false }, - "FolderTreeItemViewModel": { - "allOf": [ - { - "$ref": "#/components/schemas/EntityTreeItemViewModel" - }, - { - "type": "object", - "additionalProperties": false, - "properties": { - "isFolder": { - "type": "boolean" - } - } - } - ] - }, - "ProfilingStatusViewModel": { - "type": "object", - "additionalProperties": false, - "properties": { - "enabled": { - "type": "boolean" - } - } - }, - "OutOfDateStatusViewModel": { - "type": "object", - "additionalProperties": false, - "properties": { - "status": { - "$ref": "#/components/schemas/OutOfDateType" - } - } - }, - "OutOfDateType": { - "type": "integer", - "description": "", - "x-enumNames": [ - "OutOfDate", - "Current", - "Unknown" - ], + "SecurityRuleSet": { "enum": [ - 0, - 1, - 100 - ] - }, - "PagedViewModelOfContentTreeItemViewModel": { - "type": "object", - "additionalProperties": false, - "properties": { - "total": { - "type": "integer", - "format": "int64" - }, - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ContentTreeItemViewModel" - } - } - } - }, - "ContentTreeItemViewModel": { - "allOf": [ - { - "$ref": "#/components/schemas/EntityTreeItemViewModel" - }, - { - "type": "object", - "additionalProperties": false, - "properties": { - "noAccess": { - "type": "boolean" - } - } - } - ] - }, - "PagedViewModelOfRecycleBinItemViewModel": { - "type": "object", - "additionalProperties": false, - "properties": { - "total": { - "type": "integer", - "format": "int64" - }, - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/RecycleBinItemViewModel" - } - } - } - }, - "RecycleBinItemViewModel": { - "type": "object", - "additionalProperties": false, - "properties": { - "key": { - "type": "string", - "format": "guid" - }, - "name": { - "type": "string" - }, - "type": { - "type": "string" - }, - "icon": { - "type": "string" - }, - "hasChildren": { - "type": "boolean" - }, - "isContainer": { - "type": "boolean" - }, - "parentKey": { - "type": "string", - "format": "guid", - "nullable": true - } - } - }, - "PagedViewModelOfFolderTreeItemViewModel": { - "type": "object", - "additionalProperties": false, - "properties": { - "total": { - "type": "integer", - "format": "int64" - }, - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/FolderTreeItemViewModel" - } - } - } - }, - "PagedViewModelOfLanguageViewModel": { - "type": "object", - "additionalProperties": false, - "properties": { - "total": { - "type": "integer", - "format": "int64" - }, - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/LanguageViewModel" - } - } - } - }, - "LanguageViewModel": { - "type": "object", - "additionalProperties": false, - "required": [ - "isoCode" + "None", + "Level1", + "Level2" ], + "type": "integer", + "format": "int32" + }, + "ServerStatus": { + "type": "object", "properties": { - "id": { - "type": "integer", - "format": "int32" - }, - "isoCode": { - "type": "string", - "minLength": 1 + "serverStatus": { + "$ref": "#/components/schemas/RuntimeLevel" + } + }, + "additionalProperties": false + }, + "StructLayoutAttribute": { + "type": "object", + "properties": { + "typeId": { + "nullable": true, + "readOnly": true }, + "value": { + "$ref": "#/components/schemas/LayoutKind" + } + }, + "additionalProperties": false + }, + "Telemetry": { + "type": "object", + "properties": { + "telemetryLevel": { + "$ref": "#/components/schemas/TelemetryLevel" + } + }, + "additionalProperties": false + }, + "TelemetryLevel": { + "enum": [ + "Minimal", + "Basic", + "Detailed" + ], + "type": "integer", + "format": "int32" + }, + "Type": { + "type": "object", + "properties": { "name": { "type": "string", - "nullable": true + "nullable": true, + "readOnly": true }, - "isDefault": { - "type": "boolean" + "customAttributes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CustomAttributeData" + }, + "nullable": true, + "readOnly": true }, - "isMandatory": { - "type": "boolean" + "isCollectible": { + "type": "boolean", + "readOnly": true }, - "fallbackLanguageId": { + "metadataToken": { "type": "integer", "format": "int32", - "nullable": true - } - } - }, - "InstallSettingsViewModel": { - "type": "object", - "additionalProperties": false, - "properties": { - "user": { - "$ref": "#/components/schemas/UserSettingsViewModel" + "readOnly": true }, - "databases": { + "isInterface": { + "type": "boolean", + "readOnly": true + }, + "memberType": { + "$ref": "#/components/schemas/MemberTypes" + }, + "namespace": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "assemblyQualifiedName": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "fullName": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "assembly": { + "$ref": "#/components/schemas/Assembly" + }, + "module": { + "$ref": "#/components/schemas/Module" + }, + "isNested": { + "type": "boolean", + "readOnly": true + }, + "declaringType": { + "$ref": "#/components/schemas/Type" + }, + "declaringMethod": { + "$ref": "#/components/schemas/MethodBase" + }, + "reflectedType": { + "$ref": "#/components/schemas/Type" + }, + "underlyingSystemType": { + "$ref": "#/components/schemas/Type" + }, + "isTypeDefinition": { + "type": "boolean", + "readOnly": true + }, + "isArray": { + "type": "boolean", + "readOnly": true + }, + "isByRef": { + "type": "boolean", + "readOnly": true + }, + "isPointer": { + "type": "boolean", + "readOnly": true + }, + "isConstructedGenericType": { + "type": "boolean", + "readOnly": true + }, + "isGenericParameter": { + "type": "boolean", + "readOnly": true + }, + "isGenericTypeParameter": { + "type": "boolean", + "readOnly": true + }, + "isGenericMethodParameter": { + "type": "boolean", + "readOnly": true + }, + "isGenericType": { + "type": "boolean", + "readOnly": true + }, + "isGenericTypeDefinition": { + "type": "boolean", + "readOnly": true + }, + "isSZArray": { + "type": "boolean", + "readOnly": true + }, + "isVariableBoundArray": { + "type": "boolean", + "readOnly": true + }, + "isByRefLike": { + "type": "boolean", + "readOnly": true + }, + "hasElementType": { + "type": "boolean", + "readOnly": true + }, + "genericTypeArguments": { "type": "array", "items": { - "$ref": "#/components/schemas/DatabaseSettingsViewModel" - } + "$ref": "#/components/schemas/Type" + }, + "nullable": true, + "readOnly": true + }, + "genericParameterPosition": { + "type": "integer", + "format": "int32", + "readOnly": true + }, + "genericParameterAttributes": { + "$ref": "#/components/schemas/GenericParameterAttributes" + }, + "attributes": { + "$ref": "#/components/schemas/TypeAttributes" + }, + "isAbstract": { + "type": "boolean", + "readOnly": true + }, + "isImport": { + "type": "boolean", + "readOnly": true + }, + "isSealed": { + "type": "boolean", + "readOnly": true + }, + "isSpecialName": { + "type": "boolean", + "readOnly": true + }, + "isClass": { + "type": "boolean", + "readOnly": true + }, + "isNestedAssembly": { + "type": "boolean", + "readOnly": true + }, + "isNestedFamANDAssem": { + "type": "boolean", + "readOnly": true + }, + "isNestedFamily": { + "type": "boolean", + "readOnly": true + }, + "isNestedFamORAssem": { + "type": "boolean", + "readOnly": true + }, + "isNestedPrivate": { + "type": "boolean", + "readOnly": true + }, + "isNestedPublic": { + "type": "boolean", + "readOnly": true + }, + "isNotPublic": { + "type": "boolean", + "readOnly": true + }, + "isPublic": { + "type": "boolean", + "readOnly": true + }, + "isAutoLayout": { + "type": "boolean", + "readOnly": true + }, + "isExplicitLayout": { + "type": "boolean", + "readOnly": true + }, + "isLayoutSequential": { + "type": "boolean", + "readOnly": true + }, + "isAnsiClass": { + "type": "boolean", + "readOnly": true + }, + "isAutoClass": { + "type": "boolean", + "readOnly": true + }, + "isUnicodeClass": { + "type": "boolean", + "readOnly": true + }, + "isCOMObject": { + "type": "boolean", + "readOnly": true + }, + "isContextful": { + "type": "boolean", + "readOnly": true + }, + "isEnum": { + "type": "boolean", + "readOnly": true + }, + "isMarshalByRef": { + "type": "boolean", + "readOnly": true + }, + "isPrimitive": { + "type": "boolean", + "readOnly": true + }, + "isValueType": { + "type": "boolean", + "readOnly": true + }, + "isSignatureType": { + "type": "boolean", + "readOnly": true + }, + "isSecurityCritical": { + "type": "boolean", + "readOnly": true + }, + "isSecuritySafeCritical": { + "type": "boolean", + "readOnly": true + }, + "isSecurityTransparent": { + "type": "boolean", + "readOnly": true + }, + "structLayoutAttribute": { + "$ref": "#/components/schemas/StructLayoutAttribute" + }, + "typeInitializer": { + "$ref": "#/components/schemas/ConstructorInfo" + }, + "typeHandle": { + "$ref": "#/components/schemas/RuntimeTypeHandle" + }, + "guid": { + "type": "string", + "format": "uuid", + "readOnly": true + }, + "baseType": { + "$ref": "#/components/schemas/Type" + }, + "isSerializable": { + "type": "boolean", + "readOnly": true + }, + "containsGenericParameters": { + "type": "boolean", + "readOnly": true + }, + "isVisible": { + "type": "boolean", + "readOnly": true } - } + }, + "additionalProperties": false }, - "UserSettingsViewModel": { + "TypeAttributes": { + "enum": [ + "NotPublic", + "AutoLayout", + "AnsiClass", + "Class", + "Public", + "NestedPublic", + "NestedPrivate", + "NestedFamily", + "NestedAssembly", + "NestedFamANDAssem", + "NestedFamORAssem", + "VisibilityMask", + "SequentialLayout", + "ExplicitLayout", + "LayoutMask", + "Interface", + "ClassSemanticsMask", + "Abstract", + "Sealed", + "SpecialName", + "RTSpecialName", + "Import", + "Serializable", + "WindowsRuntime", + "UnicodeClass", + "AutoClass", + "CustomFormatClass", + "StringFormatMask", + "HasSecurity", + "ReservedMask", + "BeforeFieldInit", + "CustomFormatMask" + ], + "type": "integer", + "format": "int32" + }, + "TypeInfo": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "customAttributes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CustomAttributeData" + }, + "nullable": true, + "readOnly": true + }, + "isCollectible": { + "type": "boolean", + "readOnly": true + }, + "metadataToken": { + "type": "integer", + "format": "int32", + "readOnly": true + }, + "isInterface": { + "type": "boolean", + "readOnly": true + }, + "memberType": { + "$ref": "#/components/schemas/MemberTypes" + }, + "namespace": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "assemblyQualifiedName": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "fullName": { + "type": "string", + "nullable": true, + "readOnly": true + }, + "assembly": { + "$ref": "#/components/schemas/Assembly" + }, + "module": { + "$ref": "#/components/schemas/Module" + }, + "isNested": { + "type": "boolean", + "readOnly": true + }, + "declaringType": { + "$ref": "#/components/schemas/Type" + }, + "declaringMethod": { + "$ref": "#/components/schemas/MethodBase" + }, + "reflectedType": { + "$ref": "#/components/schemas/Type" + }, + "underlyingSystemType": { + "$ref": "#/components/schemas/Type" + }, + "isTypeDefinition": { + "type": "boolean", + "readOnly": true + }, + "isArray": { + "type": "boolean", + "readOnly": true + }, + "isByRef": { + "type": "boolean", + "readOnly": true + }, + "isPointer": { + "type": "boolean", + "readOnly": true + }, + "isConstructedGenericType": { + "type": "boolean", + "readOnly": true + }, + "isGenericParameter": { + "type": "boolean", + "readOnly": true + }, + "isGenericTypeParameter": { + "type": "boolean", + "readOnly": true + }, + "isGenericMethodParameter": { + "type": "boolean", + "readOnly": true + }, + "isGenericType": { + "type": "boolean", + "readOnly": true + }, + "isGenericTypeDefinition": { + "type": "boolean", + "readOnly": true + }, + "isSZArray": { + "type": "boolean", + "readOnly": true + }, + "isVariableBoundArray": { + "type": "boolean", + "readOnly": true + }, + "isByRefLike": { + "type": "boolean", + "readOnly": true + }, + "hasElementType": { + "type": "boolean", + "readOnly": true + }, + "genericTypeArguments": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Type" + }, + "nullable": true, + "readOnly": true + }, + "genericParameterPosition": { + "type": "integer", + "format": "int32", + "readOnly": true + }, + "genericParameterAttributes": { + "$ref": "#/components/schemas/GenericParameterAttributes" + }, + "attributes": { + "$ref": "#/components/schemas/TypeAttributes" + }, + "isAbstract": { + "type": "boolean", + "readOnly": true + }, + "isImport": { + "type": "boolean", + "readOnly": true + }, + "isSealed": { + "type": "boolean", + "readOnly": true + }, + "isSpecialName": { + "type": "boolean", + "readOnly": true + }, + "isClass": { + "type": "boolean", + "readOnly": true + }, + "isNestedAssembly": { + "type": "boolean", + "readOnly": true + }, + "isNestedFamANDAssem": { + "type": "boolean", + "readOnly": true + }, + "isNestedFamily": { + "type": "boolean", + "readOnly": true + }, + "isNestedFamORAssem": { + "type": "boolean", + "readOnly": true + }, + "isNestedPrivate": { + "type": "boolean", + "readOnly": true + }, + "isNestedPublic": { + "type": "boolean", + "readOnly": true + }, + "isNotPublic": { + "type": "boolean", + "readOnly": true + }, + "isPublic": { + "type": "boolean", + "readOnly": true + }, + "isAutoLayout": { + "type": "boolean", + "readOnly": true + }, + "isExplicitLayout": { + "type": "boolean", + "readOnly": true + }, + "isLayoutSequential": { + "type": "boolean", + "readOnly": true + }, + "isAnsiClass": { + "type": "boolean", + "readOnly": true + }, + "isAutoClass": { + "type": "boolean", + "readOnly": true + }, + "isUnicodeClass": { + "type": "boolean", + "readOnly": true + }, + "isCOMObject": { + "type": "boolean", + "readOnly": true + }, + "isContextful": { + "type": "boolean", + "readOnly": true + }, + "isEnum": { + "type": "boolean", + "readOnly": true + }, + "isMarshalByRef": { + "type": "boolean", + "readOnly": true + }, + "isPrimitive": { + "type": "boolean", + "readOnly": true + }, + "isValueType": { + "type": "boolean", + "readOnly": true + }, + "isSignatureType": { + "type": "boolean", + "readOnly": true + }, + "isSecurityCritical": { + "type": "boolean", + "readOnly": true + }, + "isSecuritySafeCritical": { + "type": "boolean", + "readOnly": true + }, + "isSecurityTransparent": { + "type": "boolean", + "readOnly": true + }, + "structLayoutAttribute": { + "$ref": "#/components/schemas/StructLayoutAttribute" + }, + "typeInitializer": { + "$ref": "#/components/schemas/ConstructorInfo" + }, + "typeHandle": { + "$ref": "#/components/schemas/RuntimeTypeHandle" + }, + "guid": { + "type": "string", + "format": "uuid", + "readOnly": true + }, + "baseType": { + "$ref": "#/components/schemas/Type" + }, + "isSerializable": { + "type": "boolean", + "readOnly": true + }, + "containsGenericParameters": { + "type": "boolean", + "readOnly": true + }, + "isVisible": { + "type": "boolean", + "readOnly": true + }, + "genericTypeParameters": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Type" + }, + "nullable": true, + "readOnly": true + }, + "declaredConstructors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ConstructorInfo" + }, + "nullable": true, + "readOnly": true + }, + "declaredEvents": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EventInfo" + }, + "nullable": true, + "readOnly": true + }, + "declaredFields": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FieldInfo" + }, + "nullable": true, + "readOnly": true + }, + "declaredMembers": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MemberInfo" + }, + "nullable": true, + "readOnly": true + }, + "declaredMethods": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MethodInfo" + }, + "nullable": true, + "readOnly": true + }, + "declaredNestedTypes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TypeInfo" + }, + "nullable": true, + "readOnly": true + }, + "declaredProperties": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PropertyInfo" + }, + "nullable": true, + "readOnly": true + }, + "implementedInterfaces": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Type" + }, + "nullable": true, + "readOnly": true + } + }, + "additionalProperties": false + }, + "UpgradeSettings": { + "type": "object", + "properties": { + "currentState": { + "type": "string", + "nullable": true + }, + "newState": { + "type": "string", + "nullable": true + }, + "newVersion": { + "type": "string", + "nullable": true + }, + "oldVersion": { + "type": "string", + "nullable": true + }, + "reportUrl": { + "type": "string", + "nullable": true, + "readOnly": true + } + }, + "additionalProperties": false + }, + "UserInstall": { + "required": [ + "email", + "name", + "password" + ], + "type": "object", + "properties": { + "name": { + "maxLength": 255, + "minLength": 0, + "type": "string" + }, + "email": { + "minLength": 1, + "type": "string", + "format": "email" + }, + "password": { + "minLength": 1, + "type": "string" + }, + "subscribeToNewsletter": { + "type": "boolean", + "readOnly": true + } + }, + "additionalProperties": false + }, + "UserSettings": { "type": "object", - "additionalProperties": false, "properties": { "minCharLength": { "type": "integer", @@ -4566,789 +6939,41 @@ "consentLevels": { "type": "array", "items": { - "$ref": "#/components/schemas/ConsentLevelViewModel" - } - } - } - }, - "ConsentLevelViewModel": { - "type": "object", - "additionalProperties": false, - "properties": { - "level": { - "$ref": "#/components/schemas/TelemetryLevel" - }, - "description": { - "type": "string" - } - } - }, - "TelemetryLevel": { - "type": "string", - "description": "", - "x-enumNames": [ - "Minimal", - "Basic", - "Detailed" - ], - "enum": [ - "Minimal", - "Basic", - "Detailed" - ] - }, - "DatabaseSettingsViewModel": { - "type": "object", - "additionalProperties": false, - "properties": { - "id": { - "type": "string", - "format": "guid" - }, - "sortOrder": { - "type": "integer", - "format": "int32" - }, - "displayName": { - "type": "string" - }, - "defaultDatabaseName": { - "type": "string" - }, - "providerName": { - "type": "string" - }, - "isConfigured": { - "type": "boolean" - }, - "requiresServer": { - "type": "boolean" - }, - "serverPlaceholder": { - "type": "string" - }, - "requiresCredentials": { - "type": "boolean" - }, - "supportsIntegratedAuthentication": { - "type": "boolean" - }, - "requiresConnectionTest": { - "type": "boolean" - } - } - }, - "InstallViewModel": { - "type": "object", - "additionalProperties": false, - "required": [ - "user", - "database" - ], - "properties": { - "user": { - "$ref": "#/components/schemas/UserInstallViewModel" - }, - "database": { - "$ref": "#/components/schemas/DatabaseInstallViewModel" - }, - "telemetryLevel": { - "$ref": "#/components/schemas/TelemetryLevel" - } - } - }, - "UserInstallViewModel": { - "type": "object", - "additionalProperties": false, - "required": [ - "name", - "email", - "password" - ], - "properties": { - "name": { - "type": "string", - "maxLength": 255, - "minLength": 0 - }, - "email": { - "type": "string", - "format": "email", - "minLength": 1 - }, - "password": { - "type": "string", - "minLength": 1 - }, - "subscribeToNewsletter": { - "type": "boolean" - } - } - }, - "DatabaseInstallViewModel": { - "type": "object", - "additionalProperties": false, - "required": [ - "id", - "providerName" - ], - "properties": { - "id": { - "type": "string", - "format": "guid", - "minLength": 1 - }, - "providerName": { - "type": "string", - "minLength": 1 - }, - "server": { - "type": "string", + "$ref": "#/components/schemas/ConsentLevel" + }, "nullable": true - }, - "name": { - "type": "string", - "nullable": true - }, - "username": { - "type": "string", - "nullable": true - }, - "password": { - "type": "string", - "nullable": true - }, - "useIntegratedAuthentication": { - "type": "boolean" - }, - "connectionString": { + } + }, + "additionalProperties": false + }, + "Version": { + "type": "object", + "properties": { + "version": { "type": "string", "nullable": true } - } - }, - "PagedViewModelOfHelpPageViewModel": { - "type": "object", - "additionalProperties": false, - "properties": { - "total": { - "type": "integer", - "format": "int64" - }, - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/HelpPageViewModel" - } - } - } - }, - "HelpPageViewModel": { - "type": "object", - "additionalProperties": false, - "properties": { - "name": { - "type": "string", - "nullable": true - }, - "description": { - "type": "string", - "nullable": true - }, - "url": { - "type": "string", - "nullable": true - }, - "type": { - "type": "string", - "nullable": true - } - } - }, - "PagedViewModelOfDocumentTreeItemViewModel": { - "type": "object", - "additionalProperties": false, - "properties": { - "total": { - "type": "integer", - "format": "int64" - }, - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DocumentTreeItemViewModel" - } - } - } - }, - "DocumentTreeItemViewModel": { - "allOf": [ - { - "$ref": "#/components/schemas/ContentTreeItemViewModel" - }, - { - "type": "object", - "additionalProperties": false, - "properties": { - "isProtected": { - "type": "boolean" - }, - "isPublished": { - "type": "boolean" - }, - "isEdited": { - "type": "boolean" - } - } - } - ] - }, - "PagedViewModelOfDocumentTypeTreeItemViewModel": { - "type": "object", - "additionalProperties": false, - "properties": { - "total": { - "type": "integer", - "format": "int64" - }, - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DocumentTypeTreeItemViewModel" - } - } - } - }, - "DocumentTypeTreeItemViewModel": { - "allOf": [ - { - "$ref": "#/components/schemas/FolderTreeItemViewModel" - }, - { - "type": "object", - "additionalProperties": false, - "properties": { - "isElement": { - "type": "boolean" - } - } - } - ] - }, - "DocumentBlueprintTreeItemViewModel": { - "allOf": [ - { - "$ref": "#/components/schemas/EntityTreeItemViewModel" - }, - { - "type": "object", - "additionalProperties": false, - "properties": { - "documentTypeKey": { - "type": "string", - "format": "guid" - }, - "documentTypeAlias": { - "type": "string" - }, - "documentTypeName": { - "type": "string", - "nullable": true - } - } - } - ] - }, - "PagedViewModelOfDocumentBlueprintTreeItemViewModel": { - "type": "object", - "additionalProperties": false, - "properties": { - "total": { - "type": "integer", - "format": "int64" - }, - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DocumentBlueprintTreeItemViewModel" - } - } - } - }, - "PagedViewModelOfDictionaryOverviewViewModel": { - "type": "object", - "additionalProperties": false, - "properties": { - "total": { - "type": "integer", - "format": "int64" - }, - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DictionaryOverviewViewModel" - } - } - } - }, - "DictionaryOverviewViewModel": { - "type": "object", - "additionalProperties": false, - "properties": { - "name": { - "type": "string", - "description": "Gets or sets the key.\n ", - "nullable": true - }, - "key": { - "type": "string", - "description": "Gets or sets the key.\n ", - "format": "guid" - }, - "level": { - "type": "integer", - "description": "Gets or sets the level.\n ", - "format": "int32" - }, - "translations": { - "type": "array", - "description": "Sets the translations.\n ", - "items": { - "$ref": "#/components/schemas/DictionaryTranslationOverviewViewModel" - } - } - } - }, - "DictionaryTranslationOverviewViewModel": { - "type": "object", - "additionalProperties": false, - "properties": { - "displayName": { - "type": "string", - "description": "Gets or sets the display name.\n ", - "nullable": true - }, - "hasTranslation": { - "type": "boolean", - "description": "Gets or sets a value indicating whether has translation.\n " - } - } - }, - "DictionaryViewModel": { - "type": "object", - "description": "The dictionary display model\n ", - "additionalProperties": false, - "required": [ - "name" - ], - "properties": { - "parentId": { - "type": "string", - "description": "Gets or sets the parent id.\n ", - "format": "guid", - "nullable": true - }, - "translations": { - "type": "array", - "description": "Gets or sets the translations.\n ", - "items": { - "$ref": "#/components/schemas/DictionaryTranslationViewModel" - } - }, - "contentApps": { - "type": "array", - "description": "Apps for the dictionary item\n ", - "items": { - "$ref": "#/components/schemas/ContentApp" - } - }, - "notifications": { - "type": "array", - "description": "This is used to add custom localized messages/strings to the response for the app to use for localized UI purposes.\n ", - "items": { - "$ref": "#/components/schemas/BackOfficeNotification" - } - }, - "name": { - "type": "string", - "minLength": 1 - }, - "key": { - "type": "string", - "description": "Gets or sets the Key for the object\n ", - "format": "guid" - }, - "path": { - "type": "string", - "description": "The path of the entity\n " - } - } - }, - "DictionaryTranslationViewModel": { - "type": "object", - "additionalProperties": false, - "properties": { - "id": { - "type": "integer", - "format": "int32" - }, - "key": { - "type": "string", - "format": "guid" - }, - "displayName": { - "type": "string", - "description": "Gets or sets the display name.\n ", - "nullable": true - }, - "isoCode": { - "type": "string", - "description": "Gets or sets the ISO code.\n ", - "nullable": true - }, - "translation": { - "type": "string", - "description": "Gets or sets the translation.\n " - }, - "languageId": { - "type": "integer", - "description": "Gets or sets the language id.\n ", - "format": "int32" - } - } - }, - "ContentApp": { - "type": "object", - "description": "Represents a content app.\n ", - "additionalProperties": false, - "properties": { - "name": { - "type": "string", - "description": "Gets the name of the content app.\n ", - "nullable": true - }, - "alias": { - "type": "string", - "description": "Gets the unique alias of the content app.\n ", - "nullable": true - }, - "weight": { - "type": "integer", - "description": "Gets or sets the weight of the content app.\n ", - "format": "int32" - }, - "icon": { - "type": "string", - "description": "Gets the icon of the content app.\n ", - "nullable": true - }, - "view": { - "type": "string", - "description": "Gets the view for rendering the content app.\n ", - "nullable": true - }, - "viewModel": { - "description": "The view model specific to this app\n ", - "nullable": true - }, - "active": { - "type": "boolean", - "description": "Gets a value indicating whether the app is active.\n " - }, - "badge": { - "description": "Gets or sets the content app badge.\n ", - "nullable": true, - "oneOf": [ - { - "$ref": "#/components/schemas/ContentAppBadge" - } - ] - } - } - }, - "ContentAppBadge": { - "type": "object", - "description": "Represents a content app badge\n ", - "additionalProperties": false, - "properties": { - "count": { - "type": "integer", - "description": "Gets or sets the number displayed in the badge\n ", - "format": "int32" - }, - "type": { - "description": "Gets or sets the type of badge to display\n ", - "oneOf": [ - { - "$ref": "#/components/schemas/ContentAppBadgeType" - } - ] - } - } - }, - "ContentAppBadgeType": { - "type": "integer", - "description": "Represent the content app badge types\n ", - "x-enumNames": [ - "Default", - "Warning", - "Alert" - ], - "enum": [ - 0, - 1, - 2 - ] - }, - "BackOfficeNotification": { - "type": "object", - "additionalProperties": false, - "properties": { - "header": { - "type": "string", - "nullable": true - }, - "message": { - "type": "string", - "nullable": true - }, - "notificationType": { - "$ref": "#/components/schemas/NotificationStyle" - } - } - }, - "NotificationStyle": { - "type": "integer", - "description": "", - "x-enumNames": [ - "Save", - "Info", - "Error", - "Success", - "Warning" - ], - "enum": [ - 0, - 1, - 2, - 3, - 4 - ] - }, - "DictionaryItemViewModel": { - "type": "object", - "additionalProperties": false, - "properties": { - "parentId": { - "type": "string", - "format": "guid", - "nullable": true - }, - "key": { - "type": "string", - "format": "guid" - } - } - }, - "JsonPatchViewModel": { - "type": "object", - "additionalProperties": false, - "properties": { - "op": { - "type": "string" - }, - "path": { - "type": "string" - }, - "value": {} - } - }, - "DictionaryImportViewModel": { - "type": "object", - "additionalProperties": false, - "properties": { - "dictionaryItems": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DictionaryItemsImportViewModel" - } - }, - "tempFileName": { - "type": "string", - "nullable": true - } - } - }, - "DictionaryItemsImportViewModel": { - "type": "object", - "additionalProperties": false, - "properties": { - "name": { - "type": "string", - "nullable": true - }, - "level": { - "type": "integer", - "format": "int32" - } - } - }, - "PagedViewModelOfCultureViewModel": { - "type": "object", - "additionalProperties": false, - "properties": { - "total": { - "type": "integer", - "format": "int64" - }, - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/CultureViewModel" - } - } - } - }, - "CultureViewModel": { - "type": "object", - "additionalProperties": false, - "properties": { - "name": { - "type": "string" - }, - "englishName": { - "type": "string" - } - } - }, - "PagedViewModelOfTelemetryLevel": { - "type": "object", - "additionalProperties": false, - "properties": { - "total": { - "type": "integer", - "format": "int64" - }, - "items": { - "type": "array", - "items": { - "$ref": "#/components/schemas/TelemetryLevel2" - } - } - } - }, - "TelemetryLevel2": { - "type": "integer", - "description": "", - "x-enumNames": [ - "Minimal", - "Basic", - "Detailed" - ], - "enum": [ - 0, - 1, - 2 - ] - }, - "AnalyticsLevelViewModel": { - "type": "object", - "additionalProperties": false, - "properties": { - "analyticsLevel": { - "$ref": "#/components/schemas/TelemetryLevel" + }, + "additionalProperties": false + } + }, + "securitySchemes": { + "OAuth": { + "type": "oauth2", + "description": "Umbraco Authentication", + "flows": { + "authorizationCode": { + "authorizationUrl": "/umbraco/management/api/v1.0/security/back-office/authorize", + "tokenUrl": "/umbraco/management/api/v1.0/security/back-office/token", + "scopes": { } } } } } }, - "tags": [ + "security": [ { - "name": "Analytics" - }, - { - "name": "Culture" - }, - { - "name": "DataType" - }, - { - "name": "Dictionary" - }, - { - "name": "DictionaryItem" - }, - { - "name": "Document" - }, - { - "name": "DocumentBlueprint" - }, - { - "name": "DocumentType" - }, - { - "name": "Help" - }, - { - "name": "Install" - }, - { - "name": "Language" - }, - { - "name": "Media" - }, - { - "name": "MediaType" - }, - { - "name": "MemberGroup" - }, - { - "name": "MemberType" - }, - { - "name": "ModelsBuilder" - }, - { - "name": "PartialView" - }, - { - "name": "Profiling" - }, - { - "name": "PublishedCache" - }, - { - "name": "Relation" - }, - { - "name": "RelationType" - }, - { - "name": "Script" - }, - { - "name": "Search" - }, - { - "name": "Server" - }, - { - "name": "StaticFile" - }, - { - "name": "Stylesheet" - }, - { - "name": "Template" - }, - { - "name": "TrackedReferences" - }, - { - "name": "Upgrade" + "OAuth": [ ] } ] } diff --git a/src/Umbraco.Cms.ManagementApi/OpenApi/EnumSchemaFilter.cs b/src/Umbraco.Cms.ManagementApi/OpenApi/EnumSchemaFilter.cs new file mode 100644 index 0000000000..2b8dd3f469 --- /dev/null +++ b/src/Umbraco.Cms.ManagementApi/OpenApi/EnumSchemaFilter.cs @@ -0,0 +1,23 @@ +using System.Reflection; +using System.Runtime.Serialization; +using Microsoft.OpenApi.Any; +using Microsoft.OpenApi.Models; +using Swashbuckle.AspNetCore.SwaggerGen; + +namespace Umbraco.Cms.ManagementApi.OpenApi; + +public class EnumSchemaFilter : ISchemaFilter +{ + public void Apply(OpenApiSchema model, SchemaFilterContext context) + { + if (context.Type.IsEnum) + { + model.Enum.Clear(); + foreach (var name in Enum.GetNames(context.Type)) + { + var actualName = context.Type.GetField(name)?.GetCustomAttribute()?.Value ?? name; + model.Enum.Add(new OpenApiString(actualName)); + } + } + } +} diff --git a/src/Umbraco.Cms.ManagementApi/OpenApi/MimeTypeDocumentFilter.cs b/src/Umbraco.Cms.ManagementApi/OpenApi/MimeTypeDocumentFilter.cs new file mode 100644 index 0000000000..f49a89e22f --- /dev/null +++ b/src/Umbraco.Cms.ManagementApi/OpenApi/MimeTypeDocumentFilter.cs @@ -0,0 +1,33 @@ +using Microsoft.OpenApi.Models; +using Swashbuckle.AspNetCore.SwaggerGen; +using Umbraco.Extensions; + +namespace Umbraco.Cms.ManagementApi.OpenApi; + +/// +/// This filter explicitly removes all other mime types than application/json from the produced OpenAPI document +/// +public class MimeTypeDocumentFilter : IDocumentFilter +{ + public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context) + { + OpenApiOperation[] operations = swaggerDoc.Paths + .SelectMany(path => path.Value.Operations.Values) + .ToArray(); + + void RemoveUnwantedMimeTypes(IDictionary content) => + content.RemoveAll(r => r.Key != "application/json"); + + OpenApiRequestBody[] requestBodies = operations.Select(operation => operation.RequestBody).WhereNotNull().ToArray(); + foreach (OpenApiRequestBody requestBody in requestBodies) + { + RemoveUnwantedMimeTypes(requestBody.Content); + } + + OpenApiResponse[] responses = operations.SelectMany(operation => operation.Responses.Values).WhereNotNull().ToArray(); + foreach (OpenApiResponse response in responses) + { + RemoveUnwantedMimeTypes(response.Content); + } + } +} diff --git a/src/Umbraco.Cms.ManagementApi/OpenApi/SchemaIdGenerator.cs b/src/Umbraco.Cms.ManagementApi/OpenApi/SchemaIdGenerator.cs new file mode 100644 index 0000000000..71c15620fd --- /dev/null +++ b/src/Umbraco.Cms.ManagementApi/OpenApi/SchemaIdGenerator.cs @@ -0,0 +1,26 @@ +using System.Text.RegularExpressions; +using Umbraco.Extensions; + +namespace Umbraco.Cms.ManagementApi.OpenApi; + +internal static class SchemaIdGenerator +{ + public static string Generate(Type type) + { + string SanitizedTypeName(Type t) => t.Name + // first grab the "non generic" part of any generic type name (i.e. "PagedViewModel`1" becomes "PagedViewModel") + .Split('`').First() + // then remove the "ViewModel" postfix from type names + .TrimEnd("ViewModel"); + + var name = SanitizedTypeName(type); + if (type.IsGenericType) + { + // append the generic type names, ultimately turning i.e. "PagedViewModel" into "PagedRelationItem" + name += string.Join(string.Empty, type.GenericTypeArguments.Select(SanitizedTypeName)); + } + + // make absolutely sure we don't pass any invalid named by removing all non-word chars + return Regex.Replace(name, @"[^\w]", string.Empty); + } +} diff --git a/src/Umbraco.Cms.ManagementApi/Security/BackOfficeApplicationManager.cs b/src/Umbraco.Cms.ManagementApi/Security/BackOfficeApplicationManager.cs new file mode 100644 index 0000000000..87f63f2f6e --- /dev/null +++ b/src/Umbraco.Cms.ManagementApi/Security/BackOfficeApplicationManager.cs @@ -0,0 +1,131 @@ +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.Hosting; +using Microsoft.Extensions.Options; +using OpenIddict.Abstractions; +using Umbraco.New.Cms.Core; +using Umbraco.New.Cms.Core.Models.Configuration; +using Umbraco.New.Cms.Infrastructure.Security; + +namespace Umbraco.Cms.ManagementApi.Security; + +public class BackOfficeApplicationManager : IBackOfficeApplicationManager +{ + private readonly IOpenIddictApplicationManager _applicationManager; + private readonly IWebHostEnvironment _webHostEnvironment; + private readonly Uri? _backOfficeHost; + + public BackOfficeApplicationManager( + IOpenIddictApplicationManager applicationManager, + IWebHostEnvironment webHostEnvironment, + IOptionsMonitor securitySettingsMonitor) + { + _applicationManager = applicationManager; + _webHostEnvironment = webHostEnvironment; + _backOfficeHost = securitySettingsMonitor.CurrentValue.BackOfficeHost; + } + + public async Task EnsureBackOfficeApplicationAsync(Uri backOfficeUrl, CancellationToken cancellationToken = default) + { + if (backOfficeUrl.IsAbsoluteUri is false) + { + throw new ArgumentException($"Expected an absolute URL, got: {backOfficeUrl}", nameof(backOfficeUrl)); + } + + await CreateOrUpdate( + new OpenIddictApplicationDescriptor + { + DisplayName = "Umbraco back-office access", + ClientId = Constants.OauthClientIds.BackOffice, + RedirectUris = + { + CallbackUrlFor(_backOfficeHost ?? backOfficeUrl, "/umbraco/login/callback/") + }, + Type = OpenIddictConstants.ClientTypes.Public, + Permissions = + { + OpenIddictConstants.Permissions.Endpoints.Authorization, + OpenIddictConstants.Permissions.Endpoints.Token, + OpenIddictConstants.Permissions.GrantTypes.AuthorizationCode, + OpenIddictConstants.Permissions.GrantTypes.RefreshToken, + OpenIddictConstants.Permissions.ResponseTypes.Code + } + }, + cancellationToken); + + if (_webHostEnvironment.IsProduction()) + { + await Delete(Constants.OauthClientIds.Swagger, cancellationToken); + await Delete(Constants.OauthClientIds.Postman, cancellationToken); + } + else + { + await CreateOrUpdate( + new OpenIddictApplicationDescriptor + { + DisplayName = "Umbraco Swagger access", + ClientId = Constants.OauthClientIds.Swagger, + RedirectUris = + { + CallbackUrlFor(backOfficeUrl, "/umbraco/swagger/oauth2-redirect.html") + }, + Type = OpenIddictConstants.ClientTypes.Public, + Permissions = + { + OpenIddictConstants.Permissions.Endpoints.Authorization, + OpenIddictConstants.Permissions.Endpoints.Token, + OpenIddictConstants.Permissions.GrantTypes.AuthorizationCode, + OpenIddictConstants.Permissions.ResponseTypes.Code + } + }, + cancellationToken); + + await CreateOrUpdate( + new OpenIddictApplicationDescriptor + { + DisplayName = "Umbraco Postman access", + ClientId = Constants.OauthClientIds.Postman, + RedirectUris = + { + new Uri("https://oauth.pstmn.io/v1/callback") + }, + Type = OpenIddictConstants.ClientTypes.Public, + Permissions = + { + OpenIddictConstants.Permissions.Endpoints.Authorization, + OpenIddictConstants.Permissions.Endpoints.Token, + OpenIddictConstants.Permissions.GrantTypes.AuthorizationCode, + OpenIddictConstants.Permissions.ResponseTypes.Code + } + }, + cancellationToken); + } + } + + private async Task CreateOrUpdate(OpenIddictApplicationDescriptor clientDescriptor, CancellationToken cancellationToken) + { + var identifier = clientDescriptor.ClientId ?? + throw new ApplicationException($"ClientId is missing for application: {clientDescriptor.DisplayName ?? "(no name)"}"); + var client = await _applicationManager.FindByClientIdAsync(identifier, cancellationToken); + if (client is null) + { + await _applicationManager.CreateAsync(clientDescriptor, cancellationToken); + } + else + { + await _applicationManager.UpdateAsync(client, clientDescriptor, cancellationToken); + } + } + + private async Task Delete(string identifier, CancellationToken cancellationToken) + { + var client = await _applicationManager.FindByClientIdAsync(identifier, cancellationToken); + if (client is null) + { + return; + } + + await _applicationManager.DeleteAsync(client, cancellationToken); + } + + private static Uri CallbackUrlFor(Uri url, string relativePath) => new Uri( $"{url.GetLeftPart(UriPartial.Authority)}/{relativePath.TrimStart(Core.Constants.CharArrays.ForwardSlash)}"); +} diff --git a/src/Umbraco.Cms.ManagementApi/Umbraco.Cms.ManagementApi.csproj b/src/Umbraco.Cms.ManagementApi/Umbraco.Cms.ManagementApi.csproj index 592f328ec2..37c95e98ee 100644 --- a/src/Umbraco.Cms.ManagementApi/Umbraco.Cms.ManagementApi.csproj +++ b/src/Umbraco.Cms.ManagementApi/Umbraco.Cms.ManagementApi.csproj @@ -10,7 +10,12 @@ - + + + + + + diff --git a/src/Umbraco.Cms.ManagementApi/ViewModels/Analytics/AnalyticsLevelViewModel.cs b/src/Umbraco.Cms.ManagementApi/ViewModels/Analytics/AnalyticsLevelViewModel.cs deleted file mode 100644 index 73d442992e..0000000000 --- a/src/Umbraco.Cms.ManagementApi/ViewModels/Analytics/AnalyticsLevelViewModel.cs +++ /dev/null @@ -1,10 +0,0 @@ -using System.Text.Json.Serialization; -using Umbraco.Cms.Core.Models; - -namespace Umbraco.Cms.ManagementApi.ViewModels.Analytics; - -public class AnalyticsLevelViewModel -{ - [JsonConverter(typeof(JsonStringEnumConverter))] - public TelemetryLevel AnalyticsLevel { get; set; } -} diff --git a/src/Umbraco.Cms.ManagementApi/ViewModels/Telemetry/TelemetryViewModel.cs b/src/Umbraco.Cms.ManagementApi/ViewModels/Telemetry/TelemetryViewModel.cs new file mode 100644 index 0000000000..574ae86360 --- /dev/null +++ b/src/Umbraco.Cms.ManagementApi/ViewModels/Telemetry/TelemetryViewModel.cs @@ -0,0 +1,10 @@ +using System.Text.Json.Serialization; +using Umbraco.Cms.Core.Models; + +namespace Umbraco.Cms.ManagementApi.ViewModels.Telemetry; + +public class TelemetryViewModel +{ + [JsonConverter(typeof(JsonStringEnumConverter))] + public TelemetryLevel TelemetryLevel { get; set; } +} diff --git a/src/Umbraco.Cms.Persistence.SqlServer/Umbraco.Cms.Persistence.SqlServer.csproj b/src/Umbraco.Cms.Persistence.SqlServer/Umbraco.Cms.Persistence.SqlServer.csproj index 4431cf2558..7d477069ed 100644 --- a/src/Umbraco.Cms.Persistence.SqlServer/Umbraco.Cms.Persistence.SqlServer.csproj +++ b/src/Umbraco.Cms.Persistence.SqlServer/Umbraco.Cms.Persistence.SqlServer.csproj @@ -5,7 +5,7 @@ - + diff --git a/src/Umbraco.Core/Configuration/Grid/GridConfig.cs b/src/Umbraco.Core/Configuration/Grid/GridConfig.cs index 44c9c37dfd..be13776da8 100644 --- a/src/Umbraco.Core/Configuration/Grid/GridConfig.cs +++ b/src/Umbraco.Core/Configuration/Grid/GridConfig.cs @@ -1,8 +1,11 @@ +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Umbraco.Cms.Core.Cache; using Umbraco.Cms.Core.Hosting; +using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Manifest; using Umbraco.Cms.Core.Serialization; +using Umbraco.Cms.Web.Common.DependencyInjection; namespace Umbraco.Cms.Core.Configuration.Grid; @@ -13,9 +16,27 @@ public class GridConfig : IGridConfig IManifestParser manifestParser, IJsonSerializer jsonSerializer, IHostingEnvironment hostingEnvironment, - ILoggerFactory loggerFactory) + ILoggerFactory loggerFactory, + IGridEditorsConfigFileProviderFactory gridEditorsConfigFileProviderFactory) => EditorsConfig = - new GridEditorsConfig(appCaches, hostingEnvironment, manifestParser, jsonSerializer, loggerFactory.CreateLogger()); + new GridEditorsConfig(appCaches, hostingEnvironment, manifestParser, jsonSerializer, loggerFactory.CreateLogger(), gridEditorsConfigFileProviderFactory); + + [Obsolete("Use other ctor - Will be removed in Umbraco 13")] + public GridConfig( + AppCaches appCaches, + IManifestParser manifestParser, + IJsonSerializer jsonSerializer, + IHostingEnvironment hostingEnvironment, + ILoggerFactory loggerFactory) + : this( + appCaches, + manifestParser, + jsonSerializer, + hostingEnvironment, + loggerFactory, + StaticServiceProvider.Instance.GetRequiredService()) + { + } public IGridEditorsConfig EditorsConfig { get; } } diff --git a/src/Umbraco.Core/Configuration/Grid/GridEditorsConfig.cs b/src/Umbraco.Core/Configuration/Grid/GridEditorsConfig.cs index 11ae329192..ab0ec8b182 100644 --- a/src/Umbraco.Core/Configuration/Grid/GridEditorsConfig.cs +++ b/src/Umbraco.Core/Configuration/Grid/GridEditorsConfig.cs @@ -1,12 +1,15 @@ -using System.Reflection; using System.Text; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.Logging; using Umbraco.Cms.Core.Cache; -using Umbraco.Cms.Core.Hosting; +using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Manifest; using Umbraco.Cms.Core.PropertyEditors; using Umbraco.Cms.Core.Serialization; +using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Extensions; +using IHostingEnvironment = Umbraco.Cms.Core.Hosting.IHostingEnvironment; namespace Umbraco.Cms.Core.Configuration.Grid; @@ -17,6 +20,7 @@ internal class GridEditorsConfig : IGridEditorsConfig private readonly IJsonSerializer _jsonSerializer; private readonly ILogger _logger; + private readonly IGridEditorsConfigFileProviderFactory _gridEditorsConfigFileProviderFactory; private readonly IManifestParser _manifestParser; public GridEditorsConfig( @@ -24,13 +28,32 @@ internal class GridEditorsConfig : IGridEditorsConfig IHostingEnvironment hostingEnvironment, IManifestParser manifestParser, IJsonSerializer jsonSerializer, - ILogger logger) + ILogger logger, + IGridEditorsConfigFileProviderFactory gridEditorsConfigFileProviderFactory) { _appCaches = appCaches; _hostingEnvironment = hostingEnvironment; _manifestParser = manifestParser; _jsonSerializer = jsonSerializer; _logger = logger; + _gridEditorsConfigFileProviderFactory = gridEditorsConfigFileProviderFactory; + } + + [Obsolete("Use other ctor - Will be removed in Umbraco 13")] + public GridEditorsConfig( + AppCaches appCaches, + IHostingEnvironment hostingEnvironment, + IManifestParser manifestParser, + IJsonSerializer jsonSerializer, + ILogger logger) + : this( + appCaches, + hostingEnvironment, + manifestParser, + jsonSerializer, + logger, + StaticServiceProvider.Instance.GetRequiredService()) + { } public IEnumerable Editors @@ -39,13 +62,37 @@ internal class GridEditorsConfig : IGridEditorsConfig { List GetResult() { - var configFolder = - new DirectoryInfo(_hostingEnvironment.MapPathContentRoot(Constants.SystemDirectories.Config)); + IFileInfo? gridConfig = null; var editors = new List(); - var gridConfig = Path.Combine(configFolder.FullName, "grid.editors.config.js"); - if (File.Exists(gridConfig)) + var configPath = Constants.SystemDirectories.Config.TrimStart(Constants.CharArrays.Tilde); + + // Get physical file if it exists + var configPhysicalDirPath = _hostingEnvironment.MapPathContentRoot(configPath); + + if (Directory.Exists(configPhysicalDirPath) == true) { - var sourceString = File.ReadAllText(gridConfig); + var physicalFileProvider = new PhysicalFileProvider(configPhysicalDirPath); + gridConfig = GetConfigFile(physicalFileProvider, string.Empty); + } + + // If there is no physical file, check in RCLs + if (gridConfig is null) + { + IFileProvider? compositeFileProvider = _gridEditorsConfigFileProviderFactory.Create(); + + if (compositeFileProvider is null) + { + throw new ArgumentNullException(nameof(compositeFileProvider)); + } + + gridConfig = GetConfigFile(compositeFileProvider, configPath); + } + + if (gridConfig is not null) + { + using Stream stream = gridConfig.CreateReadStream(); + using var reader = new StreamReader(stream, Encoding.UTF8); + var sourceString = reader.ReadToEnd(); try { @@ -63,19 +110,16 @@ internal class GridEditorsConfig : IGridEditorsConfig // Read default from embedded file else { - Assembly assembly = GetType().Assembly; - Stream? resourceStream = assembly.GetManifestResourceStream( - "Umbraco.Cms.Core.EmbeddedResources.Grid.grid.editors.config.js"); + IFileProvider configFileProvider = new EmbeddedFileProvider(GetType().Assembly, "Umbraco.Cms.Core.EmbeddedResources.Grid"); + IFileInfo embeddedConfig = configFileProvider.GetFileInfo("grid.editors.config.js"); - if (resourceStream is not null) - { - using var reader = new StreamReader(resourceStream, Encoding.UTF8); - var sourceString = reader.ReadToEnd(); - editors.AddRange(_jsonSerializer.Deserialize>(sourceString)!); - } + using Stream stream = embeddedConfig.CreateReadStream(); + using var reader = new StreamReader(stream, Encoding.UTF8); + var sourceString = reader.ReadToEnd(); + editors.AddRange(_jsonSerializer.Deserialize>(sourceString)!); } - // add manifest editors, skip duplicates + // Add manifest editors, skip duplicates foreach (GridEditor gridEditor in _manifestParser.CombinedManifest.GridEditors) { if (editors.Contains(gridEditor) == false) @@ -95,4 +139,10 @@ internal class GridEditorsConfig : IGridEditorsConfig return result!; } } + + private static IFileInfo? GetConfigFile(IFileProvider fileProvider, string path) + { + IFileInfo fileInfo = fileProvider.GetFileInfo($"{path}/grid.editors.config.js"); + return fileInfo.Exists ? fileInfo : null; + } } diff --git a/src/Umbraco.Core/Configuration/Models/LicensesSettings.cs b/src/Umbraco.Core/Configuration/Models/LicensesSettings.cs new file mode 100644 index 0000000000..f8de1d7265 --- /dev/null +++ b/src/Umbraco.Core/Configuration/Models/LicensesSettings.cs @@ -0,0 +1,11 @@ +// Copyright (c) Umbraco. +// See LICENSE for more details. + +namespace Umbraco.Cms.Core.Configuration.Models; + +/// +/// Typed configuration options for license settings. +/// +public class LicensesSettings : Dictionary +{ +} diff --git a/src/Umbraco.Core/Constants-Web.cs b/src/Umbraco.Core/Constants-Web.cs index bbeae780d8..6eb184fb40 100644 --- a/src/Umbraco.Core/Constants-Web.cs +++ b/src/Umbraco.Core/Constants-Web.cs @@ -63,6 +63,12 @@ public static partial class Constants public const string AreaToken = "area"; } + public static class RoutePath + { + public const string Tree = "tree"; + public const string RecycleBin = "recycle-bin"; + } + public static class AttributeRouting { public const string BackOfficeToken = "umbracoBackOffice"; diff --git a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Configuration.cs b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Configuration.cs index 31ef06c400..3be3815afa 100644 --- a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Configuration.cs +++ b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Configuration.cs @@ -14,7 +14,7 @@ namespace Umbraco.Cms.Core.DependencyInjection; /// public static partial class UmbracoBuilderExtensions { - private static IUmbracoBuilder AddUmbracoOptions(this IUmbracoBuilder builder, Action>? configure = null) + internal static IUmbracoBuilder AddUmbracoOptions(this IUmbracoBuilder builder, Action>? configure = null) where TOptions : class { UmbracoOptionsAttribute? umbracoOptionsAttribute = typeof(TOptions).GetCustomAttribute(); diff --git a/src/Umbraco.Core/Deploy/ArtifactBase.cs b/src/Umbraco.Core/Deploy/ArtifactBase.cs index cc2415f4cd..0d354b65de 100644 --- a/src/Umbraco.Core/Deploy/ArtifactBase.cs +++ b/src/Umbraco.Core/Deploy/ArtifactBase.cs @@ -1,50 +1,49 @@ -namespace Umbraco.Cms.Core.Deploy +namespace Umbraco.Cms.Core.Deploy; + +/// +/// Provides a base class to all artifacts. +/// +public abstract class ArtifactBase : IArtifact + where TUdi : Udi { - /// - /// Provides a base class to all artifacts. - /// - public abstract class ArtifactBase : IArtifact - where TUdi : Udi + protected ArtifactBase(TUdi udi, IEnumerable? dependencies = null) { - protected ArtifactBase(TUdi udi, IEnumerable? dependencies = null) - { - Udi = udi ?? throw new ArgumentNullException("udi"); - Name = Udi.ToString(); + Udi = udi ?? throw new ArgumentNullException("udi"); + Name = Udi.ToString(); - _dependencies = dependencies ?? Enumerable.Empty(); - _checksum = new Lazy(GetChecksum); - } - - private readonly Lazy _checksum; - - private IEnumerable _dependencies; - - protected abstract string GetChecksum(); - - Udi IArtifactSignature.Udi => Udi; - - public TUdi Udi { get; set; } - - public string Checksum => _checksum.Value; - - /// - /// Prevents the property from being serialized. - /// - /// - /// Note that we can't use here as that works only on fields, not properties. And we want to avoid using [JsonIgnore] - /// as that would require an external dependency in Umbraco.Cms.Core. - /// So using this method of excluding properties from serialized data, documented here: https://www.newtonsoft.com/json/help/html/ConditionalProperties.htm - /// - public bool ShouldSerializeChecksum() => false; - - public IEnumerable Dependencies - { - get => _dependencies; - set => _dependencies = value.OrderBy(x => x.Udi); - } - - public string Name { get; set; } - - public string Alias { get; set; } = string.Empty; + _dependencies = dependencies ?? Enumerable.Empty(); + _checksum = new Lazy(GetChecksum); } + + private readonly Lazy _checksum; + + private IEnumerable _dependencies; + + protected abstract string GetChecksum(); + + Udi IArtifactSignature.Udi => Udi; + + public TUdi Udi { get; set; } + + public string Checksum => _checksum.Value; + + /// + /// Prevents the property from being serialized. + /// + /// + /// Note that we can't use here as that works only on fields, not properties. And we want to avoid using [JsonIgnore] + /// as that would require an external dependency in Umbraco.Cms.Core. + /// So using this method of excluding properties from serialized data, documented here: https://www.newtonsoft.com/json/help/html/ConditionalProperties.htm + /// + public bool ShouldSerializeChecksum() => false; + + public IEnumerable Dependencies + { + get => _dependencies; + set => _dependencies = value.OrderBy(x => x.Udi); + } + + public string Name { get; set; } + + public string Alias { get; set; } = string.Empty; } diff --git a/src/Umbraco.Core/Deploy/ArtifactDeployState.cs b/src/Umbraco.Core/Deploy/ArtifactDeployState.cs index 1b75fe11c0..e2dd343af1 100644 --- a/src/Umbraco.Core/Deploy/ArtifactDeployState.cs +++ b/src/Umbraco.Core/Deploy/ArtifactDeployState.cs @@ -44,3 +44,40 @@ public abstract class ArtifactDeployState /// protected abstract IArtifact GetArtifactAsIArtifact(); } + +/// +/// Represent the state of an artifact being deployed. +/// +/// The type of the artifact. +/// The type of the entity. +public class ArtifactDeployState : ArtifactDeployState + where TArtifact : IArtifact +{ + /// + /// Initializes a new instance of the class. + /// + /// The artifact. + /// The entity. + /// The service connector deploying the artifact. + /// The next pass number. + public ArtifactDeployState(TArtifact art, TEntity? entity, IServiceConnector connector, int nextPass) + { + Artifact = art; + Entity = entity; + Connector = connector; + NextPass = nextPass; + } + + /// + /// Gets or sets the artifact. + /// + public new TArtifact Artifact { get; set; } + + /// + /// Gets or sets the entity. + /// + public TEntity? Entity { get; set; } + + /// + protected sealed override IArtifact GetArtifactAsIArtifact() => Artifact; +} diff --git a/src/Umbraco.Core/Deploy/ArtifactDeployStateOfTArtifactTEntity.cs b/src/Umbraco.Core/Deploy/ArtifactDeployStateOfTArtifactTEntity.cs deleted file mode 100644 index 0ff1e20e87..0000000000 --- a/src/Umbraco.Core/Deploy/ArtifactDeployStateOfTArtifactTEntity.cs +++ /dev/null @@ -1,38 +0,0 @@ -namespace Umbraco.Cms.Core.Deploy; - -/// -/// Represent the state of an artifact being deployed. -/// -/// The type of the artifact. -/// The type of the entity. -public class ArtifactDeployState : ArtifactDeployState - where TArtifact : IArtifact -{ - /// - /// Initializes a new instance of the class. - /// - /// The artifact. - /// The entity. - /// The service connector deploying the artifact. - /// The next pass number. - public ArtifactDeployState(TArtifact art, TEntity? entity, IServiceConnector connector, int nextPass) - { - Artifact = art; - Entity = entity; - Connector = connector; - NextPass = nextPass; - } - - /// - /// Gets or sets the artifact. - /// - public new TArtifact Artifact { get; set; } - - /// - /// Gets or sets the entity. - /// - public TEntity? Entity { get; set; } - - /// - protected sealed override IArtifact GetArtifactAsIArtifact() => Artifact; -} diff --git a/src/Umbraco.Core/Deploy/IContextCache.cs b/src/Umbraco.Core/Deploy/IContextCache.cs new file mode 100644 index 0000000000..d175064905 --- /dev/null +++ b/src/Umbraco.Core/Deploy/IContextCache.cs @@ -0,0 +1,31 @@ +namespace Umbraco.Cms.Core.Deploy; + +/// +/// Represents a context cache used by Deploy operations. +/// +public interface IContextCache +{ + /// + /// Creates the item on the context cache using the specified . + /// + /// The type of the cached item. + /// The key of the cached item. + /// The item. + void Create(string key, T item); + + /// + /// Gets an item from the context cache or creates and stores it using the specified . + /// + /// The type of the cached item. + /// The key of the cached item. + /// The factory method to create the item (if it doesn't exist yet). + /// + /// The item. + /// + T? GetOrCreate(string key, Func factory); + + /// + /// Clears all cached items on this context. + /// + void Clear(); +} diff --git a/src/Umbraco.Core/Deploy/IDataTypeConfigurationConnector.cs b/src/Umbraco.Core/Deploy/IDataTypeConfigurationConnector.cs index 6b91926b57..506d1f5745 100644 --- a/src/Umbraco.Core/Deploy/IDataTypeConfigurationConnector.cs +++ b/src/Umbraco.Core/Deploy/IDataTypeConfigurationConnector.cs @@ -1,37 +1,67 @@ -using System.Diagnostics.CodeAnalysis; using Umbraco.Cms.Core.Models; namespace Umbraco.Cms.Core.Deploy; /// -/// Defines methods that can convert data type configuration to / from an environment-agnostic string. +/// Defines methods that can convert data type configuration to / from an environment-agnostic string. /// /// -/// Configuration may contain values such as content identifiers, that would be local -/// to one environment, and need to be converted in order to be deployed. +/// Configuration may contain values such as content identifiers, that would be local +/// to one environment, and need to be converted in order to be deployed. /// -[SuppressMessage( - "ReSharper", - "UnusedMember.Global", - Justification = "This is actual only used by Deploy, but we don't want third parties to have references on deploy, that's why this interface is part of core.")] public interface IDataTypeConfigurationConnector { /// - /// Gets the property editor aliases that the value converter supports by default. + /// Gets the property editor aliases that the value converter supports by default. /// + /// + /// The property editor aliases. + /// IEnumerable PropertyEditorAliases { get; } /// - /// Gets the artifact datatype configuration corresponding to the actual datatype configuration. + /// Gets the artifact configuration value corresponding to a data type configuration and gather dependencies. /// - /// The datatype. + /// The data type. /// The dependencies. - string? ToArtifact(IDataType dataType, ICollection dependencies); + /// + /// The artifact configuration value. + /// + [Obsolete("Use the overload accepting IContextCache instead. This overload will be removed in a future version.")] + string? ToArtifact(IDataType dataType, ICollection dependencies) + => ToArtifact(dataType, dependencies, PassThroughCache.Instance); /// - /// Gets the actual datatype configuration corresponding to the artifact configuration. + /// Gets the artifact configuration value corresponding to a data type configuration and gather dependencies. /// - /// The datatype. - /// The artifact configuration. - object? FromArtifact(IDataType dataType, string? configuration); + /// The data type. + /// The dependencies. + /// The context cache. + /// + /// The artifact configuration value. + /// + string? ToArtifact(IDataType dataType, ICollection dependencies, IContextCache contextCache); + + /// + /// Gets the data type configuration corresponding to an artifact configuration value. + /// + /// The data type. + /// The artifact configuration value. + /// + /// The data type configuration. + /// + [Obsolete("Use the overload accepting IContextCache instead. This overload will be removed in a future version.")] + object? FromArtifact(IDataType dataType, string? configuration) + => FromArtifact(dataType, configuration, PassThroughCache.Instance); + + /// + /// Gets the data type configuration corresponding to an artifact configuration value. + /// + /// The data type. + /// The artifact configuration value. + /// The context cache. + /// + /// The data type configuration. + /// + object? FromArtifact(IDataType dataType, string? configuration, IContextCache contextCache); } diff --git a/src/Umbraco.Core/Deploy/IServiceConnector.cs b/src/Umbraco.Core/Deploy/IServiceConnector.cs index f6cd7c8002..b4f530fb35 100644 --- a/src/Umbraco.Core/Deploy/IServiceConnector.cs +++ b/src/Umbraco.Core/Deploy/IServiceConnector.cs @@ -3,34 +3,65 @@ using Umbraco.Cms.Core.Composing; namespace Umbraco.Cms.Core.Deploy; /// -/// Connects to an Umbraco service. +/// Connects to an Umbraco service. /// +/// public interface IServiceConnector : IDiscoverable { /// - /// Gets an artifact. + /// Gets an artifact. /// /// The entity identifier of the artifact. - /// The corresponding artifact, or null. - IArtifact? GetArtifact(Udi udi); + /// + /// The corresponding artifact, or null. + /// + [Obsolete("Use the overload accepting IContextCache instead. This overload will be removed in a future version.")] + IArtifact? GetArtifact(Udi udi) + => GetArtifact(udi, PassThroughCache.Instance); /// - /// Gets an artifact. + /// Gets an artifact. + /// + /// The entity identifier of the artifact. + /// The context cache. + /// + /// The corresponding artifact, or null. + /// + IArtifact? GetArtifact(Udi udi, IContextCache contextCache); + + /// + /// Gets an artifact. /// /// The entity. - /// The corresponding artifact. - IArtifact GetArtifact(object entity); + /// + /// The corresponding artifact. + /// + [Obsolete("Use the overload accepting IContextCache instead. This overload will be removed in a future version.")] + IArtifact GetArtifact(object entity) + => GetArtifact(entity, PassThroughCache.Instance); /// - /// Initializes processing for an artifact. + /// Gets an artifact. + /// + /// The entity. + /// The context cache. + /// + /// The corresponding artifact. + /// + IArtifact GetArtifact(object entity, IContextCache contextCache); + + /// + /// Initializes processing for an artifact. /// /// The artifact. /// The deploy context. - /// The mapped artifact. + /// + /// The mapped artifact. + /// ArtifactDeployState ProcessInit(IArtifact art, IDeployContext context); /// - /// Processes an artifact. + /// Processes an artifact. /// /// The mapped artifact. /// The deploy context. @@ -38,46 +69,56 @@ public interface IServiceConnector : IDiscoverable void Process(ArtifactDeployState dart, IDeployContext context, int pass); /// - /// Explodes a range into udis. + /// Explodes a range into udis. /// /// The range. /// The list of udis where to add the new udis. - /// Also, it's cool to have a method named Explode. Kaboom! + /// + /// Also, it's cool to have a method named Explode. Kaboom! + /// void Explode(UdiRange range, List udis); /// - /// Gets a named range for a specified udi and selector. + /// Gets a named range for a specified udi and selector. /// /// The udi. /// The selector. - /// The named range for the specified udi and selector. + /// + /// The named range for the specified udi and selector. + /// NamedUdiRange GetRange(Udi udi, string selector); /// - /// Gets a named range for specified entity type, identifier and selector. + /// Gets a named range for specified entity type, identifier and selector. /// /// The entity type. /// The identifier. /// The selector. - /// The named range for the specified entity type, identifier and selector. + /// + /// The named range for the specified entity type, identifier and selector. + /// /// - /// This is temporary. At least we thought it would be, in sept. 2016. What day is it now? - /// - /// At the moment our UI has a hard time returning proper udis, mainly because Core's tree do - /// not manage guids but only ints... so we have to provide a way to support it. The string id here - /// can be either a real string (for string udis) or an "integer as a string", using the value "-1" to - /// indicate the "root" i.e. an open udi. - /// + /// This is temporary. At least we thought it would be, in sept. 2016. What day is it now? + /// + /// At the moment our UI has a hard time returning proper udis, mainly because Core's tree do + /// not manage guids but only ints... so we have to provide a way to support it. The string id here + /// can be either a real string (for string udis) or an "integer as a string", using the value "-1" to + /// indicate the "root" i.e. an open udi. + /// /// NamedUdiRange GetRange(string entityType, string sid, string selector); /// - /// Compares two artifacts. + /// Compares two artifacts. /// /// The first artifact. /// The second artifact. /// A collection of differences to append to, if not null. - /// A boolean value indicating whether the artifacts are identical. - /// ServiceConnectorBase{TArtifact} provides a very basic default implementation. + /// + /// A boolean value indicating whether the artifacts are identical. + /// + /// + /// ServiceConnectorBase{TArtifact} provides a very basic default implementation. + /// bool Compare(IArtifact? art1, IArtifact? art2, ICollection? differences = null); } diff --git a/src/Umbraco.Core/Deploy/IValueConnector.cs b/src/Umbraco.Core/Deploy/IValueConnector.cs index f2a776c7ca..9f3b17f71c 100644 --- a/src/Umbraco.Core/Deploy/IValueConnector.cs +++ b/src/Umbraco.Core/Deploy/IValueConnector.cs @@ -3,35 +3,70 @@ using Umbraco.Cms.Core.Models; namespace Umbraco.Cms.Core.Deploy; /// -/// Defines methods that can convert a property value to / from an environment-agnostic string. +/// Defines methods that can convert a property value to and from an environment-agnostic string. /// /// -/// Property values may contain values such as content identifiers, that would be local -/// to one environment, and need to be converted in order to be deployed. Connectors also deal -/// with serializing to / from string. +/// Property values may contain values such as content identifiers, that would be local +/// to one environment and need to be converted in order to be deployed. Connectors also deal +/// with serializing and deserializing the content value to an environment-agnostic string. /// public interface IValueConnector { /// - /// Gets the property editor aliases that the value converter supports by default. + /// Gets the property editor aliases that the value converter supports by default. /// + /// + /// The property editor aliases. + /// IEnumerable PropertyEditorAliases { get; } /// - /// Gets the deploy property value corresponding to a content property value, and gather dependencies. + /// Gets the deploy property value corresponding to a content property value, and gather dependencies. /// /// The content property value. /// The value property type /// The content dependencies. - /// The deploy property value. - string? ToArtifact(object? value, IPropertyType propertyType, ICollection dependencies); + /// + /// The deploy property value. + /// + [Obsolete("Use the overload accepting IContextCache instead. This overload will be removed in a future version.")] + string? ToArtifact(object? value, IPropertyType propertyType, ICollection dependencies) + => ToArtifact(value, propertyType, dependencies, PassThroughCache.Instance); /// - /// Gets the content property value corresponding to a deploy property value. + /// Gets the deploy property value corresponding to a content property value, and gather dependencies. + /// + /// The content property value. + /// The value property type + /// The content dependencies. + /// The context cache. + /// + /// The deploy property value. + /// + string? ToArtifact(object? value, IPropertyType propertyType, ICollection dependencies, IContextCache contextCache); + + /// + /// Gets the content property value corresponding to a deploy property value. /// /// The deploy property value. /// The value property type /// The current content property value. - /// The content property value. - object? FromArtifact(string? value, IPropertyType propertyType, object? currentValue); + /// + /// The content property value. + /// + [Obsolete("Use the overload accepting IContextCache instead. This overload will be removed in a future version.")] + object? FromArtifact(string? value, IPropertyType propertyType, object? currentValue) + => FromArtifact(value, propertyType, currentValue, PassThroughCache.Instance); + + /// + /// Gets the content property value corresponding to a deploy property value. + /// + /// The deploy property value. + /// The value property type + /// The current content property value. + /// The context cache. + /// + /// The content property value. + /// + object? FromArtifact(string? value, IPropertyType propertyType, object? currentValue, IContextCache contextCache); } diff --git a/src/Umbraco.Core/Deploy/PassThroughCache.cs b/src/Umbraco.Core/Deploy/PassThroughCache.cs new file mode 100644 index 0000000000..064fc10ad5 --- /dev/null +++ b/src/Umbraco.Core/Deploy/PassThroughCache.cs @@ -0,0 +1,34 @@ +namespace Umbraco.Cms.Core.Deploy; + +/// +/// A pass through context cache that always creates the items. +/// +/// +public sealed class PassThroughCache : IContextCache +{ + /// + /// Gets the instance. + /// + /// + /// The instance. + /// + public static PassThroughCache Instance { get; } = new PassThroughCache(); + + /// + /// Prevents a default instance of the class from being created. + /// + private PassThroughCache() + { } + + /// + public void Create(string key, T item) + { } + + /// + public T? GetOrCreate(string key, Func factory) + => factory(); + + /// + public void Clear() + { } +} diff --git a/src/Umbraco.Core/IO/IGridEditorsConfigFileProviderFactory.cs b/src/Umbraco.Core/IO/IGridEditorsConfigFileProviderFactory.cs new file mode 100644 index 0000000000..2c401a3f99 --- /dev/null +++ b/src/Umbraco.Core/IO/IGridEditorsConfigFileProviderFactory.cs @@ -0,0 +1,10 @@ +using Microsoft.Extensions.FileProviders; + +namespace Umbraco.Cms.Core.IO; + +/// +/// Factory for creating instances for providing the grid.editors.config.js file. +/// +public interface IGridEditorsConfigFileProviderFactory : IFileProviderFactory +{ +} diff --git a/src/Umbraco.Core/IO/IManifestFileProviderFactory.cs b/src/Umbraco.Core/IO/IManifestFileProviderFactory.cs new file mode 100644 index 0000000000..982b029c27 --- /dev/null +++ b/src/Umbraco.Core/IO/IManifestFileProviderFactory.cs @@ -0,0 +1,10 @@ +using Microsoft.Extensions.FileProviders; + +namespace Umbraco.Cms.Core.IO; + +/// +/// Factory for creating instances for providing the package.manifest file. +/// +public interface IManifestFileProviderFactory : IFileProviderFactory +{ +} diff --git a/src/Umbraco.Core/Routing/UmbracoRequestPaths.cs b/src/Umbraco.Core/Routing/UmbracoRequestPaths.cs index fe1e83d254..960be851ff 100644 --- a/src/Umbraco.Core/Routing/UmbracoRequestPaths.cs +++ b/src/Umbraco.Core/Routing/UmbracoRequestPaths.cs @@ -1,6 +1,8 @@ +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.Hosting; +using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Extensions; namespace Umbraco.Cms.Core.Routing; @@ -19,11 +21,18 @@ public class UmbracoRequestPaths private readonly string _mvcArea; private readonly string _previewMvcPath; private readonly string _surfaceMvcPath; + private readonly IOptions _umbracoRequestPathsOptions; + + [Obsolete("Use constructor that takes IOptions - Will be removed in Umbraco 13")] + public UmbracoRequestPaths(IOptions globalSettings, IHostingEnvironment hostingEnvironment) + : this(globalSettings, hostingEnvironment, StaticServiceProvider.Instance.GetRequiredService>()) + { + } /// /// Initializes a new instance of the class. /// - public UmbracoRequestPaths(IOptions globalSettings, IHostingEnvironment hostingEnvironment) + public UmbracoRequestPaths(IOptions globalSettings, IHostingEnvironment hostingEnvironment, IOptions umbracoRequestPathsOptions) { var applicationPath = hostingEnvironment.ApplicationVirtualPath; _appPath = applicationPath.TrimStart(Constants.CharArrays.ForwardSlash); @@ -38,6 +47,7 @@ public class UmbracoRequestPaths _surfaceMvcPath = "/" + _mvcArea + "/Surface/"; _apiMvcPath = "/" + _mvcArea + "/Api/"; _installPath = hostingEnvironment.ToAbsolute(Constants.SystemDirectories.Install); + _umbracoRequestPathsOptions = umbracoRequestPathsOptions; } /// @@ -51,6 +61,7 @@ public class UmbracoRequestPaths /// These are def back office: /// /Umbraco/BackOffice = back office /// /Umbraco/Preview = back office + /// /Umbraco/Management/Api = back office /// /// /// If it's not any of the above then we cannot determine if it's back office or front-end @@ -99,6 +110,11 @@ public class UmbracoRequestPaths return false; } + if (_umbracoRequestPathsOptions.Value.IsBackOfficeRequest(urlPath)) + { + return true; + } + // if its none of the above, we will have to try to detect if it's a PluginController route, we can detect this by // checking how many parts the route has, for example, all PluginController routes will be routed like // Umbraco/MYPLUGINAREA/MYCONTROLLERNAME/{action}/{id} diff --git a/src/Umbraco.Core/Routing/UmbracoRequestPathsOptions.cs b/src/Umbraco.Core/Routing/UmbracoRequestPathsOptions.cs new file mode 100644 index 0000000000..91f13eab3b --- /dev/null +++ b/src/Umbraco.Core/Routing/UmbracoRequestPathsOptions.cs @@ -0,0 +1,10 @@ +namespace Umbraco.Cms.Core.Routing; + +public class UmbracoRequestPathsOptions +{ + /// + /// Gets the delegate that allows us to handle additional URLs as back-office requests. + /// This returns false by default and can be overwritten in Startup.cs. + /// + public Func IsBackOfficeRequest { get; set; } = _ => false; +} diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 03a292c880..dc480b160f 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -47,6 +47,10 @@ <_Parameter1>DynamicProxyGenAssembly2 + + + <_Parameter1>Umbraco.Cms.ManagementApi + diff --git a/src/Umbraco.Infrastructure/Deploy/IGridCellValueConnector.cs b/src/Umbraco.Infrastructure/Deploy/IGridCellValueConnector.cs index eb1bc518ac..a9ed5fd84d 100644 --- a/src/Umbraco.Infrastructure/Deploy/IGridCellValueConnector.cs +++ b/src/Umbraco.Infrastructure/Deploy/IGridCellValueConnector.cs @@ -1,44 +1,77 @@ using Umbraco.Cms.Core.Models; +using static Umbraco.Cms.Core.Models.GridValue; namespace Umbraco.Cms.Core.Deploy; /// -/// Defines methods that can convert a grid cell value to / from an environment-agnostic string. +/// Defines methods that can convert a grid cell value to / from an environment-agnostic string. /// /// -/// Grid cell values may contain values such as content identifiers, that would be local -/// to one environment, and need to be converted in order to be deployed. +/// Grid cell values may contain values such as content identifiers, that would be local +/// to one environment, and need to be converted in order to be deployed. /// public interface IGridCellValueConnector { /// - /// Gets a value indicating whether the connector supports a specified grid editor view. + /// Gets a value indicating whether the connector supports a specified grid editor view. /// - /// - /// The grid editor view. It needs to be the view instead of the alias as the view is really what - /// identifies what kind of connector should be used. Alias can be anything and you can have multiple different aliases - /// using the same kind of view. - /// - /// A value indicating whether the connector supports the grid editor view. - /// Note that can be string.Empty to indicate the "default" connector. + /// The grid editor view. It needs to be the view instead of the alias as the view is really what + /// identifies what kind of connector should be used. Alias can be anything and you can have multiple different aliases + /// using the same kind of view. + /// + /// true if the specified view is connector; otherwise, false. + /// + /// + /// A value indicating whether the connector supports the grid editor view. + /// bool IsConnector(string view); /// - /// Gets the value to be deployed from the control value as a string. + /// Gets the value to be deployed from the control value as a string. /// /// The control containing the value. /// The dependencies of the property. - /// The grid cell value to be deployed. - /// Note that - string? GetValue(GridValue.GridControl gridControl, ICollection dependencies); + /// + /// The grid cell value to be deployed. + /// + /// + /// Note that + /// + [Obsolete("Use the overload accepting IContextCache instead. This overload will be removed in a future version.")] + string? GetValue(GridValue.GridControl gridControl, ICollection dependencies) + => GetValue(gridControl, dependencies, PassThroughCache.Instance); /// - /// Allows you to modify the value of a control being deployed. + /// Gets the value to be deployed from the control value as a string. + /// + /// The control containing the value. + /// The dependencies of the property. + /// The context cache. + /// + /// The grid cell value to be deployed. + /// + string? GetValue(GridValue.GridControl gridControl, ICollection dependencies, IContextCache contextCache); + + /// + /// Allows you to modify the value of a control being deployed. /// /// The control being deployed. /// - /// Follows the pattern of the property value connectors (). The SetValue method is - /// used to modify the value of the . + /// Follows the pattern of the property value connectors (). + /// The SetValue method is used to modify the value of the . /// - void SetValue(GridValue.GridControl gridControl); + [Obsolete("Use the overload accepting IContextCache instead. This overload will be removed in a future version.")] + void SetValue(GridValue.GridControl gridControl) + => SetValue(gridControl, PassThroughCache.Instance); + + /// + /// Allows you to modify the value of a control being deployed. + /// + /// The control being deployed. + /// The context cache. + /// + /// Follows the pattern of the property value connectors (). + /// The SetValue method is used to modify the value of the . + /// + void SetValue(GridValue.GridControl gridControl, IContextCache contextCache); } diff --git a/src/Umbraco.Infrastructure/Manifest/ManifestParser.cs b/src/Umbraco.Infrastructure/Manifest/ManifestParser.cs index 4dbd6abd40..887ac05dc4 100644 --- a/src/Umbraco.Infrastructure/Manifest/ManifestParser.cs +++ b/src/Umbraco.Infrastructure/Manifest/ManifestParser.cs @@ -1,13 +1,17 @@ using System.Text; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using Umbraco.Cms.Core.Cache; using Umbraco.Cms.Core.Hosting; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Cms.Core.Routing; using Umbraco.Cms.Core.Serialization; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Strings; +using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Extensions; namespace Umbraco.Cms.Core.Manifest; @@ -21,6 +25,7 @@ public class ManifestParser : IManifestParser private readonly IAppPolicyCache _cache; private readonly IDataValueEditorFactory _dataValueEditorFactory; + private readonly IManifestFileProviderFactory _manifestFileProviderFactory; private readonly ManifestFilterCollection _filters; private readonly IHostingEnvironment _hostingEnvironment; @@ -46,7 +51,8 @@ public class ManifestParser : IManifestParser IJsonSerializer jsonSerializer, ILocalizedTextService localizedTextService, IShortStringHelper shortStringHelper, - IDataValueEditorFactory dataValueEditorFactory) + IDataValueEditorFactory dataValueEditorFactory, + IManifestFileProviderFactory manifestFileProviderFactory) { if (appCaches == null) { @@ -64,6 +70,34 @@ public class ManifestParser : IManifestParser _localizedTextService = localizedTextService; _shortStringHelper = shortStringHelper; _dataValueEditorFactory = dataValueEditorFactory; + _manifestFileProviderFactory = manifestFileProviderFactory; + } + + [Obsolete("Use other ctor - Will be removed in Umbraco 13")] + public ManifestParser( + AppCaches appCaches, + ManifestValueValidatorCollection validators, + ManifestFilterCollection filters, + ILogger logger, + IIOHelper ioHelper, + IHostingEnvironment hostingEnvironment, + IJsonSerializer jsonSerializer, + ILocalizedTextService localizedTextService, + IShortStringHelper shortStringHelper, + IDataValueEditorFactory dataValueEditorFactory) + : this( + appCaches, + validators, + filters, + logger, + ioHelper, + hostingEnvironment, + jsonSerializer, + localizedTextService, + shortStringHelper, + dataValueEditorFactory, + StaticServiceProvider.Instance.GetRequiredService()) + { } public string AppPluginsPath @@ -89,12 +123,20 @@ public class ManifestParser : IManifestParser public IEnumerable GetManifests() { var manifests = new List(); + IFileProvider? manifestFileProvider = _manifestFileProviderFactory.Create(); - foreach (var path in GetManifestFiles()) + if (manifestFileProvider is null) + { + throw new ArgumentNullException(nameof(manifestFileProvider)); + } + + foreach (IFileInfo file in GetManifestFiles(manifestFileProvider, Constants.SystemDirectories.AppPlugins)) { try { - var text = File.ReadAllText(path); + using Stream stream = file.CreateReadStream(); + using var reader = new StreamReader(stream, Encoding.UTF8); + var text = reader.ReadToEnd(); text = TrimPreamble(text); if (string.IsNullOrWhiteSpace(text)) { @@ -102,12 +144,12 @@ public class ManifestParser : IManifestParser } PackageManifest manifest = ParseManifest(text); - manifest.Source = path; + manifest.Source = file.PhysicalPath!; // We assure that the PhysicalPath is not null in GetManifestFiles() manifests.Add(manifest); } catch (Exception e) { - _logger.LogError(e, "Failed to parse manifest at '{Path}', ignoring.", path); + _logger.LogError(e, "Failed to parse manifest at '{Path}', ignoring.", file.PhysicalPath); } } @@ -242,14 +284,44 @@ public class ManifestParser : IManifestParser return text; } - // gets all manifest files (recursively) - private IEnumerable GetManifestFiles() + // Gets all manifest files + private static IEnumerable GetManifestFiles(IFileProvider fileProvider, string path) { - if (Directory.Exists(_path) == false) + var manifestFiles = new List(); + IEnumerable pluginFolders = fileProvider.GetDirectoryContents(path); + + foreach (IFileInfo pluginFolder in pluginFolders) { - return Array.Empty(); + if (!pluginFolder.IsDirectory) + { + continue; + } + + manifestFiles.AddRange(GetNestedManifestFiles(fileProvider, $"{path}/{pluginFolder.Name}")); } - return Directory.GetFiles(_path, "package.manifest", SearchOption.AllDirectories); + return manifestFiles; + } + + // Helper method to get all nested package.manifest files (recursively) + private static IEnumerable GetNestedManifestFiles(IFileProvider fileProvider, string path) + { + foreach (IFileInfo file in fileProvider.GetDirectoryContents(path)) + { + if (file.IsDirectory) + { + var virtualPath = WebPath.Combine(path, file.Name); + + // Recursively find nested package.manifest files + foreach (IFileInfo nested in GetNestedManifestFiles(fileProvider, virtualPath)) + { + yield return nested; + } + } + else if (file.Name.InvariantEquals("package.manifest") && !string.IsNullOrEmpty(file.PhysicalPath)) + { + yield return file; + } + } } } diff --git a/src/Umbraco.Infrastructure/Umbraco.Infrastructure.csproj b/src/Umbraco.Infrastructure/Umbraco.Infrastructure.csproj index 19ac4606d1..6b922545bb 100644 --- a/src/Umbraco.Infrastructure/Umbraco.Infrastructure.csproj +++ b/src/Umbraco.Infrastructure/Umbraco.Infrastructure.csproj @@ -14,7 +14,7 @@ - + @@ -25,7 +25,7 @@ - + diff --git a/src/Umbraco.New.Cms.Core/Constants-OauthClientIds.cs b/src/Umbraco.New.Cms.Core/Constants-OauthClientIds.cs new file mode 100644 index 0000000000..2fdc54e011 --- /dev/null +++ b/src/Umbraco.New.Cms.Core/Constants-OauthClientIds.cs @@ -0,0 +1,23 @@ +namespace Umbraco.New.Cms.Core; + +// TODO: move this class to Umbraco.Cms.Core as a partial class +public static class Constants +{ + public static partial class OauthClientIds + { + /// + /// Client ID used for default back-office access + /// + public const string BackOffice = "umbraco-back-office"; + + /// + /// Client ID used for Swagger API access + /// + public const string Swagger = "umbraco-swagger"; + + /// + /// Client ID used for Postman API access + /// + public const string Postman = "umbraco-postman"; + } +} diff --git a/src/Umbraco.New.Cms.Core/Models/Configuration/NewBackOfficeSettings.cs b/src/Umbraco.New.Cms.Core/Models/Configuration/NewBackOfficeSettings.cs new file mode 100644 index 0000000000..cad7b8868d --- /dev/null +++ b/src/Umbraco.New.Cms.Core/Models/Configuration/NewBackOfficeSettings.cs @@ -0,0 +1,10 @@ +using Umbraco.Cms.Core.Configuration.Models; + +namespace Umbraco.New.Cms.Core.Models.Configuration; + +// TODO: merge this class with relevant existing settings from Core and clean up +[UmbracoOptions($"{Umbraco.Cms.Core.Constants.Configuration.ConfigPrefix}NewBackOffice")] +public class NewBackOfficeSettings +{ + public Uri? BackOfficeHost { get; set; } = null; +} diff --git a/src/Umbraco.New.Cms.Core/Models/Configuration/NewBackOfficeSettingsValidator.cs b/src/Umbraco.New.Cms.Core/Models/Configuration/NewBackOfficeSettingsValidator.cs new file mode 100644 index 0000000000..bb1a2eda3d --- /dev/null +++ b/src/Umbraco.New.Cms.Core/Models/Configuration/NewBackOfficeSettingsValidator.cs @@ -0,0 +1,25 @@ +using Microsoft.Extensions.Options; +using Umbraco.Cms.Core.Configuration.Models.Validation; + +namespace Umbraco.New.Cms.Core.Models.Configuration; + +// TODO: merge this class with relevant existing settings validators from Core and clean up +public class NewBackOfficeSettingsValidator : ConfigurationValidatorBase, IValidateOptions +{ + public ValidateOptionsResult Validate(string? name, NewBackOfficeSettings options) + { + if (options.BackOfficeHost != null) + { + if (options.BackOfficeHost.IsAbsoluteUri == false) + { + return ValidateOptionsResult.Fail($"{nameof(NewBackOfficeSettings.BackOfficeHost)} must be an absolute URL"); + } + if (options.BackOfficeHost.PathAndQuery != "/") + { + return ValidateOptionsResult.Fail($"{nameof(NewBackOfficeSettings.BackOfficeHost)} must not have any path or query"); + } + } + + return ValidateOptionsResult.Success; + } +} diff --git a/src/Umbraco.New.Cms.Infrastructure/HostedServices/OpenIddictCleanup.cs b/src/Umbraco.New.Cms.Infrastructure/HostedServices/OpenIddictCleanup.cs new file mode 100644 index 0000000000..37a6e4caa6 --- /dev/null +++ b/src/Umbraco.New.Cms.Infrastructure/HostedServices/OpenIddictCleanup.cs @@ -0,0 +1,56 @@ +using System.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using OpenIddict.Abstractions; +using Umbraco.Cms.Infrastructure.HostedServices; + +namespace Umbraco.New.Cms.Infrastructure.HostedServices; + +// port of the OpenIddict Quartz job for cleaning up - see https://github.com/openiddict/openiddict-core/tree/dev/src/OpenIddict.Quartz +public class OpenIddictCleanup : RecurringHostedServiceBase +{ + // keep tokens and authorizations in the database for 7 days + // - NOTE: this is NOT the same as access token lifetime, which is likely very short + private const int LifespanInSeconds = 7 * 24 * 60 * 60; + + private readonly ILogger _logger; + private readonly IServiceProvider _provider; + + public OpenIddictCleanup( + ILogger logger, IServiceProvider provider) + : base(logger, TimeSpan.FromHours(1), TimeSpan.FromMinutes(5)) + { + _logger = logger; + _provider = provider; + } + + public override async Task PerformExecuteAsync(object? state) + { + // hosted services are registered as singletons, but this particular one consumes scoped services... so + // we have to fetch the service dependencies manually using a new scope per invocation. + IServiceScope scope = _provider.CreateScope(); + DateTimeOffset threshold = DateTimeOffset.UtcNow - TimeSpan.FromSeconds(LifespanInSeconds); + + try + { + IOpenIddictTokenManager tokenManager = scope.ServiceProvider.GetService() + ?? throw new ConfigurationErrorsException($"Could not retrieve an {nameof(IOpenIddictTokenManager)} service from the current scope"); + await tokenManager.PruneAsync(threshold); + } + catch (Exception exception) + { + _logger.LogError(exception, "Unable to prune OpenIddict tokens"); + } + + try + { + IOpenIddictAuthorizationManager authorizationManager = scope.ServiceProvider.GetService() + ?? throw new ConfigurationErrorsException($"Could not retrieve an {nameof(IOpenIddictAuthorizationManager)} service from the current scope"); + await authorizationManager.PruneAsync(threshold); + } + catch (Exception exception) + { + _logger.LogError(exception, "Unable to prune OpenIddict authorizations"); + } + } +} diff --git a/src/Umbraco.New.Cms.Infrastructure/Security/IBackOfficeApplicationManager.cs b/src/Umbraco.New.Cms.Infrastructure/Security/IBackOfficeApplicationManager.cs new file mode 100644 index 0000000000..068f5df472 --- /dev/null +++ b/src/Umbraco.New.Cms.Infrastructure/Security/IBackOfficeApplicationManager.cs @@ -0,0 +1,6 @@ +namespace Umbraco.New.Cms.Infrastructure.Security; + +public interface IBackOfficeApplicationManager +{ + Task EnsureBackOfficeApplicationAsync(Uri backOfficeUrl, CancellationToken cancellationToken = default); +} diff --git a/src/Umbraco.New.Cms.Infrastructure/Umbraco.New.Cms.Infrastructure.csproj b/src/Umbraco.New.Cms.Infrastructure/Umbraco.New.Cms.Infrastructure.csproj index 8dc5d3cc00..82159079a4 100644 --- a/src/Umbraco.New.Cms.Infrastructure/Umbraco.New.Cms.Infrastructure.csproj +++ b/src/Umbraco.New.Cms.Infrastructure/Umbraco.New.Cms.Infrastructure.csproj @@ -10,4 +10,8 @@ + + + + diff --git a/src/Umbraco.Web.BackOffice/Controllers/TourController.cs b/src/Umbraco.Web.BackOffice/Controllers/TourController.cs index ae31876ac5..4d708b4fc8 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/TourController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/TourController.cs @@ -1,16 +1,21 @@ using System.Text; +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.Options; using Newtonsoft.Json; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Configuration.Models; -using Umbraco.Cms.Core.Hosting; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.Membership; +using Umbraco.Cms.Core.Routing; using Umbraco.Cms.Core.Security; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Tour; using Umbraco.Cms.Web.Common.Attributes; +using Umbraco.Cms.Web.Common.DependencyInjection; using Umbraco.Extensions; +using IHostingEnvironment = Umbraco.Cms.Core.Hosting.IHostingEnvironment; namespace Umbraco.Cms.Web.BackOffice.Controllers; @@ -20,22 +25,44 @@ public class TourController : UmbracoAuthorizedJsonController private readonly IBackOfficeSecurityAccessor _backofficeSecurityAccessor; private readonly IContentTypeService _contentTypeService; private readonly TourFilterCollection _filters; - private readonly IHostingEnvironment _hostingEnvironment; + private readonly IWebHostEnvironment _webHostEnvironment; private readonly TourSettings _tourSettings; + // IHostingEnvironment is still injected as when removing it, the number of + // parameters matches with the obsolete ctor and the two ctors become ambiguous + // [ActivatorUtilitiesConstructor] won't solve the problem in this case + // IHostingEnvironment can be removed when the obsolete ctor is removed + [ActivatorUtilitiesConstructor] + public TourController( + TourFilterCollection filters, + IHostingEnvironment hostingEnvironment, + IOptionsSnapshot tourSettings, + IBackOfficeSecurityAccessor backofficeSecurityAccessor, + IContentTypeService contentTypeService, + IWebHostEnvironment webHostEnvironment) + { + _filters = filters; + _tourSettings = tourSettings.Value; + _backofficeSecurityAccessor = backofficeSecurityAccessor; + _contentTypeService = contentTypeService; + _webHostEnvironment = webHostEnvironment; + } + + [Obsolete("Use other ctor - Will be removed in Umbraco 13")] public TourController( TourFilterCollection filters, IHostingEnvironment hostingEnvironment, IOptionsSnapshot tourSettings, IBackOfficeSecurityAccessor backofficeSecurityAccessor, IContentTypeService contentTypeService) + : this( + filters, + hostingEnvironment, + tourSettings, + backofficeSecurityAccessor, + contentTypeService, + StaticServiceProvider.Instance.GetRequiredService()) { - _filters = filters; - _hostingEnvironment = hostingEnvironment; - - _tourSettings = tourSettings.Value; - _backofficeSecurityAccessor = backofficeSecurityAccessor; - _contentTypeService = contentTypeService; } public async Task> GetTours() @@ -53,69 +80,55 @@ public class TourController : UmbracoAuthorizedJsonController return result; } - //get all filters that will be applied to all tour aliases + // Get all filters that will be applied to all tour aliases var aliasOnlyFilters = _filters.Where(x => x.PluginName == null && x.TourFileName == null).ToList(); - //don't pass in any filters for core tours that have a plugin name assigned + // Don't pass in any filters for core tours that have a plugin name assigned var nonPluginFilters = _filters.Where(x => x.PluginName == null).ToList(); - //add core tour files - IEnumerable embeddedTourNames = GetType() - .Assembly - .GetManifestResourceNames() - .Where(x => x.StartsWith("Umbraco.Cms.Web.BackOffice.EmbeddedResources.Tours.")); - foreach (var embeddedTourName in embeddedTourNames) + // Get core tour files + IFileProvider toursProvider = new EmbeddedFileProvider(GetType().Assembly, "Umbraco.Cms.Web.BackOffice.EmbeddedResources.Tours"); + + IEnumerable embeddedTourFiles = toursProvider.GetDirectoryContents(string.Empty) + .Where(x => !x.IsDirectory && x.Name.EndsWith(".json")); + + foreach (var embeddedTour in embeddedTourFiles) { - await TryParseTourFile(embeddedTourName, result, nonPluginFilters, aliasOnlyFilters, async x => await GetContentFromEmbeddedResource(x)); + using Stream stream = embeddedTour.CreateReadStream(); + await TryParseTourFile(embeddedTour.Name, result, nonPluginFilters, aliasOnlyFilters, stream); } + // Collect all tour files from packages - /App_Plugins physical or virtual locations + IEnumerable> toursFromPackages = GetTourFiles(_webHostEnvironment.WebRootFileProvider, Constants.SystemDirectories.AppPlugins); - //collect all tour files in packages - var appPlugins = _hostingEnvironment.MapPathContentRoot(Constants.SystemDirectories.AppPlugins); - if (Directory.Exists(appPlugins)) + foreach (var tuple in toursFromPackages) { - foreach (var plugin in Directory.EnumerateDirectories(appPlugins)) + string pluginName = tuple.Item2; + var pluginFilters = _filters.Where(x => x.PluginName != null && x.PluginName.IsMatch(pluginName)).ToList(); + + // Combine matched package filters with filters not specific to a package + var combinedFilters = nonPluginFilters.Concat(pluginFilters).ToList(); + + IFileInfo tourFile = tuple.Item1; + using (Stream stream = tourFile.CreateReadStream()) { - var pluginName = Path.GetFileName(plugin.TrimEnd(Constants.CharArrays.Backslash)); - var pluginFilters = _filters.Where(x => x.PluginName != null && x.PluginName.IsMatch(pluginName)) - .ToList(); - - //If there is any filter applied to match the plugin only (no file or tour alias) then ignore the plugin entirely - var isPluginFiltered = pluginFilters.Any(x => x.TourFileName == null && x.TourAlias == null); - if (isPluginFiltered) - { - continue; - } - - //combine matched package filters with filters not specific to a package - var combinedFilters = nonPluginFilters.Concat(pluginFilters).ToList(); - - foreach (var backofficeDir in Directory.EnumerateDirectories(plugin, "backoffice")) - { - foreach (var tourDir in Directory.EnumerateDirectories(backofficeDir, "tours")) - { - foreach (var tourFile in Directory.EnumerateFiles(tourDir, "*.json")) - { - await TryParseTourFile( - tourFile, - result, - combinedFilters, - aliasOnlyFilters, - async x => await System.IO.File.ReadAllTextAsync(x), - pluginName); - } - } - } + await TryParseTourFile( + tourFile.Name, + result, + combinedFilters, + aliasOnlyFilters, + stream, + pluginName); } } - //Get all allowed sections for the current user + // Get all allowed sections for the current user var allowedSections = user.AllowedSections.ToList(); var toursToBeRemoved = new List(); - //Checking to see if the user has access to the required tour sections, else we remove the tour + // Checking to see if the user has access to the required tour sections, else we remove the tour foreach (BackOfficeTourFile backOfficeTourFile in result) { if (backOfficeTourFile.Tours != null) @@ -140,21 +153,70 @@ public class TourController : UmbracoAuthorizedJsonController return result.Except(toursToBeRemoved).OrderBy(x => x.FileName, StringComparer.InvariantCultureIgnoreCase); } - private async Task GetContentFromEmbeddedResource(string fileName) + private IEnumerable> GetTourFiles(IFileProvider fileProvider, string folder) { - Stream? resourceStream = GetType().Assembly.GetManifestResourceStream(fileName); + IEnumerable pluginFolders = fileProvider.GetDirectoryContents(folder).Where(x => x.IsDirectory); - if (resourceStream is null) + foreach (IFileInfo pluginFolder in pluginFolders) { - return string.Empty; - } + var pluginFilters = _filters.Where(x => x.PluginName != null && x.PluginName.IsMatch(pluginFolder.Name)).ToList(); - using var reader = new StreamReader(resourceStream, Encoding.UTF8); - return await reader.ReadToEndAsync(); + // If there is any filter applied to match the plugin only (no file or tour alias) then ignore the plugin entirely + var isPluginFiltered = pluginFilters.Any(x => x.TourFileName == null && x.TourAlias == null); + if (isPluginFiltered) + { + continue; + } + + // get the full virtual path for the plugin folder + var pluginFolderPath = WebPath.Combine(folder, pluginFolder.Name); + + // loop through the folder(s) in order to find tours + // - there could be multiple on case sensitive file system + // Hard-coding the "backoffice" directory name to gain a better performance when traversing the App_Plugins directory + foreach (var subDir in GetToursFolderPaths(fileProvider, pluginFolderPath, "backoffice")) + { + IEnumerable tourFiles = fileProvider + .GetDirectoryContents(subDir) + .Where(x => x.Name.InvariantEndsWith(".json")); + + foreach (IFileInfo file in tourFiles) + { + yield return new Tuple(file, pluginFolder.Name); + } + } + } + } + + private static IEnumerable GetToursFolderPaths(IFileProvider fileProvider, string path, string subDirName) + { + // Hard-coding the "tours" directory name to gain a better performance when traversing the sub directories + const string toursDirName = "tours"; + + // It is necessary to iterate through the subfolders because on Linux we'll get casing issues when + // we try to access {path}/{pluginDirectory.Name}/backoffice/tours directly + foreach (IFileInfo subDir in fileProvider.GetDirectoryContents(path)) + { + // InvariantEquals({dirName}) is used to gain a better performance when looking for the tours folder + if (subDir.IsDirectory && subDir.Name.InvariantEquals(subDirName)) + { + var virtualPath = WebPath.Combine(path, subDir.Name); + + if (subDir.Name.InvariantEquals(toursDirName)) + { + yield return virtualPath; + } + + foreach (var nested in GetToursFolderPaths(fileProvider, virtualPath, toursDirName)) + { + yield return nested; + } + } + } } /// - /// Gets a tours for a specific doctype + /// Gets a tours for a specific doctype. /// /// The documenttype alias /// A @@ -190,7 +252,7 @@ public class TourController : UmbracoAuthorizedJsonController ICollection result, List filters, List aliasOnlyFilters, - Func> fileNameToFileContent, + Stream fileStream, string? pluginName = null) { var fileName = Path.GetFileNameWithoutExtension(tourFile); @@ -199,24 +261,25 @@ public class TourController : UmbracoAuthorizedJsonController return; } - //get the filters specific to this file + // Get the filters specific to this file var fileFilters = filters.Where(x => x.TourFileName != null && x.TourFileName.IsMatch(fileName)).ToList(); - //If there is any filter applied to match the file only (no tour alias) then ignore the file entirely + // If there is any filter applied to match the file only (no tour alias) then ignore the file entirely var isFileFiltered = fileFilters.Any(x => x.TourAlias == null); if (isFileFiltered) { return; } - //now combine all aliases to filter below + // Now combine all aliases to filter below var aliasFilters = aliasOnlyFilters.Concat(filters.Where(x => x.TourAlias != null)) .Select(x => x.TourAlias) .ToList(); try { - var contents = await fileNameToFileContent(tourFile); + using var reader = new StreamReader(fileStream, Encoding.UTF8); + var contents = reader.ReadToEnd(); BackOfficeTour[]? tours = JsonConvert.DeserializeObject(contents); IEnumerable? backOfficeTours = tours?.Where(x => @@ -234,7 +297,7 @@ public class TourController : UmbracoAuthorizedJsonController Tours = localizedTours ?? new List() }; - //don't add if all of the tours are filtered + // Don't add if all of the tours are filtered if (tour.Tours.Any()) { result.Add(tour); diff --git a/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilder.LocalizedText.cs b/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilder.LocalizedText.cs index 60a946a553..7a92a77b3c 100644 --- a/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilder.LocalizedText.cs +++ b/src/Umbraco.Web.BackOffice/DependencyInjection/UmbracoBuilder.LocalizedText.cs @@ -1,8 +1,6 @@ -using System.IO; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.FileProviders; -using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Routing; using Umbraco.Cms.Core.Services; @@ -31,7 +29,7 @@ namespace Umbraco.Extensions /// - /// Loads the suplimentary localization files from plugins and user config + /// Loads the suplimentary localization files from plugins and user config. /// private static IEnumerable GetSupplementaryFileSources( IWebHostEnvironment webHostEnvironment) @@ -41,10 +39,10 @@ namespace Umbraco.Extensions IEnumerable localPluginFileSources = GetPluginLanguageFileSources(contentFileProvider, Cms.Core.Constants.SystemDirectories.AppPlugins, false); - // gets all langs files in /app_plugins real or virtual locations + // Gets all language files in /app_plugins real or virtual locations IEnumerable pluginLangFileSources = GetPluginLanguageFileSources(webFileProvider, Cms.Core.Constants.SystemDirectories.AppPlugins, false); - // user defined language files that overwrite the default, these should not be used by plugin creators + // User defined language files that overwrite the default, these should not be used by plugin creators var userConfigLangFolder = Cms.Core.Constants.SystemDirectories.Config .TrimStart(Cms.Core.Constants.CharArrays.Tilde); @@ -56,7 +54,7 @@ namespace Umbraco.Extensions { foreach (IFileInfo langFile in contentFileProvider.GetDirectoryContents($"{userConfigLangFolder}/{langFileSource.Name}")) { - if (langFile.Name.InvariantEndsWith(".xml") && langFile.PhysicalPath is not null) + if (langFile.Name.InvariantEndsWith(".xml")) { configLangFileSources.Add(new LocalizedTextServiceSupplementaryFileSource(langFile, true)); } @@ -64,10 +62,9 @@ namespace Umbraco.Extensions } } - return - localPluginFileSources - .Concat(pluginLangFileSources) - .Concat(configLangFileSources); + return localPluginFileSources + .Concat(pluginLangFileSources) + .Concat(configLangFileSources); } @@ -75,7 +72,7 @@ namespace Umbraco.Extensions /// Loads the suplimentary localaization files via the file provider. /// /// - /// locates all *.xml files in the lang folder of any sub folder of the one provided. + /// Locates all *.xml files in the lang folder of any sub folder of the one provided. /// e.g /app_plugins/plugin-name/lang/*.xml /// private static IEnumerable GetPluginLanguageFileSources( @@ -87,17 +84,16 @@ namespace Umbraco.Extensions foreach (IFileInfo pluginFolder in pluginFolders) { - // get the full virtual path for the plugin folder + // Get the full virtual path for the plugin folder var pluginFolderPath = WebPath.Combine(folder, pluginFolder.Name); - // loop through the lang folder(s) + // Loop through the lang folder(s) // - there could be multiple on case sensitive file system foreach (var langFolder in GetLangFolderPaths(fileProvider, pluginFolderPath)) { - // request all the files out of the path, these will have physicalPath set. + // Request all the files out of the path IEnumerable localizationFiles = fileProvider .GetDirectoryContents(langFolder) - .Where(x => !string.IsNullOrEmpty(x.PhysicalPath)) .Where(x => x.Name.InvariantEndsWith(".xml")); foreach (IFileInfo file in localizationFiles) diff --git a/src/Umbraco.Web.BackOffice/Services/IconService.cs b/src/Umbraco.Web.BackOffice/Services/IconService.cs index ac7ae2455e..068db52be6 100644 --- a/src/Umbraco.Web.BackOffice/Services/IconService.cs +++ b/src/Umbraco.Web.BackOffice/Services/IconService.cs @@ -34,7 +34,6 @@ public class IconService : IIconService { } - [Obsolete("Use other ctor - Will be removed in Umbraco 12")] public IconService( IOptionsMonitor globalSettings, IHostingEnvironment hostingEnvironment, @@ -101,6 +100,7 @@ public class IconService : IIconService } } + // TODO: Refactor to return IEnumerable private IEnumerable GetAllIconsFiles() { var icons = new HashSet(new CaseInsensitiveFileInfoComparer()); @@ -161,46 +161,45 @@ public class IconService : IIconService /// A collection of representing the found SVG icon files. private static IEnumerable GetIconsFiles(IFileProvider fileProvider, string path) { - // Iterate through all plugin folders, this is necessary because on Linux we'll get casing issues when + // Iterate through all plugin folders and their subfolders, this is necessary because on Linux we'll get casing issues when // we directly try to access {path}/{pluginDirectory.Name}/{Constants.SystemDirectories.PluginIcons} foreach (IFileInfo pluginDirectory in fileProvider.GetDirectoryContents(path)) { - // Ideally there shouldn't be any files, but we'd better check to be sure if (!pluginDirectory.IsDirectory) { continue; } - // Iterate through the sub directories of each plugin folder + // Iterate through the sub directories of each plugin folder in order to support case insensitive paths (for Linux) foreach (IFileInfo subDir1 in fileProvider.GetDirectoryContents($"{path}/{pluginDirectory.Name}")) { - // Skip files again - if (!subDir1.IsDirectory) + // Hard-coding the "backoffice" directory name to gain a better performance when traversing the pluginDirectory directories + if (subDir1.IsDirectory && subDir1.Name.InvariantEquals("backoffice")) { - continue; - } - - // Iterate through second level sub directories - foreach (IFileInfo subDir2 in fileProvider.GetDirectoryContents($"{path}/{pluginDirectory.Name}/{subDir1.Name}")) - { - // Skip files again - if (!subDir2.IsDirectory) + // Iterate through second level sub directories in order to support case insensitive paths (for Linux) + foreach (IFileInfo subDir2 in fileProvider.GetDirectoryContents($"{path}/{pluginDirectory.Name}/{subDir1.Name}")) { - continue; - } - - // Does the directory match the plugin icons folder? (case insensitive for legacy support) - if (!$"/{subDir1.Name}/{subDir2.Name}".InvariantEquals(Constants.SystemDirectories.PluginIcons)) - { - continue; - } - - // Iterate though the files of the second level sub directory. This should be where the SVG files are located :D - foreach (IFileInfo file in fileProvider.GetDirectoryContents($"{path}/{pluginDirectory.Name}/{subDir1.Name}/{subDir2.Name}")) - { - if (file.Name.InvariantEndsWith(".svg") && file.PhysicalPath != null) + if (!subDir2.IsDirectory) { - yield return new FileInfo(file.PhysicalPath); + continue; + } + + // Does the directory match the plugin icons folder? (case insensitive for legacy support) + if (!$"/{subDir1.Name}/{subDir2.Name}".InvariantEquals(Constants.SystemDirectories.PluginIcons)) + { + continue; + } + + // Iterate though the files of the second level sub directory. This should be where the SVG files are located :D + foreach (IFileInfo file in fileProvider.GetDirectoryContents($"{path}/{pluginDirectory.Name}/{subDir1.Name}/{subDir2.Name}")) + { + // TODO: Refactor to work with IFileInfo, then we can also remove the .PhysicalPath check + // as this won't work for files that aren't located on a physical file system + // (e.g. embedded resource, Azure Blob Storage, etc.) + if (file.Name.InvariantEndsWith(".svg") && !string.IsNullOrEmpty(file.PhysicalPath)) + { + yield return new FileInfo(file.PhysicalPath); + } } } } diff --git a/src/Umbraco.Web.BackOffice/Trees/MemberGroupTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/MemberGroupTreeController.cs index af49c43e90..275e28d9aa 100644 --- a/src/Umbraco.Web.BackOffice/Trees/MemberGroupTreeController.cs +++ b/src/Umbraco.Web.BackOffice/Trees/MemberGroupTreeController.cs @@ -20,8 +20,7 @@ public class MemberGroupTreeController : MemberTypeAndGroupTreeControllerBase { private readonly IMemberGroupService _memberGroupService; - [ - ActivatorUtilitiesConstructor] + [ActivatorUtilitiesConstructor] public MemberGroupTreeController( ILocalizedTextService localizedTextService, UmbracoApiControllerTypeCollection umbracoApiControllerTypeCollection, diff --git a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs index 500bc22447..edfe999d20 100644 --- a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs @@ -6,7 +6,6 @@ using Microsoft.AspNetCore.DataProtection.Infrastructure; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.ApplicationModels; -using Microsoft.AspNetCore.Mvc.Razor.Compilation; using Microsoft.AspNetCore.Server.Kestrel.Core; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; @@ -27,6 +26,7 @@ using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Diagnostics; using Umbraco.Cms.Core.Extensions; using Umbraco.Cms.Core.Hosting; +using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Logging; using Umbraco.Cms.Core.Macros; using Umbraco.Cms.Core.Net; @@ -48,6 +48,7 @@ using Umbraco.Cms.Web.Common.ApplicationModels; using Umbraco.Cms.Web.Common.AspNetCore; using Umbraco.Cms.Web.Common.Controllers; using Umbraco.Cms.Web.Common.DependencyInjection; +using Umbraco.Cms.Web.Common.FileProviders; using Umbraco.Cms.Web.Common.Localization; using Umbraco.Cms.Web.Common.Macros; using Umbraco.Cms.Web.Common.Middleware; @@ -146,6 +147,11 @@ public static partial class UmbracoBuilderExtensions builder.Services.TryAddEnumerable(ServiceDescriptor .Singleton()); + // WebRootFileProviderFactory is just a wrapper around the IWebHostEnvironment.WebRootFileProvider, + // therefore no need to register it as singleton + builder.Services.AddSingleton(); + builder.Services.AddSingleton(); + // Must be added here because DbProviderFactories is netstandard 2.1 so cannot exist in Infra for now builder.Services.AddSingleton(factory => new DbProviderFactoryCreator( DbProviderFactories.GetFactory, diff --git a/src/Umbraco.Web.Common/FileProviders/WebRootFileProviderFactory.cs b/src/Umbraco.Web.Common/FileProviders/WebRootFileProviderFactory.cs new file mode 100644 index 0000000000..64824dd090 --- /dev/null +++ b/src/Umbraco.Web.Common/FileProviders/WebRootFileProviderFactory.cs @@ -0,0 +1,27 @@ +using Microsoft.AspNetCore.Hosting; +using Microsoft.Extensions.FileProviders; +using Umbraco.Cms.Core.IO; + +namespace Umbraco.Cms.Web.Common.FileProviders; + +public class WebRootFileProviderFactory : IManifestFileProviderFactory, IGridEditorsConfigFileProviderFactory +{ + private readonly IWebHostEnvironment _webHostEnvironment; + + /// + /// Initializes a new instance of the class. + /// + /// The web hosting environment an application is running in. + public WebRootFileProviderFactory(IWebHostEnvironment webHostEnvironment) + { + _webHostEnvironment = webHostEnvironment; + } + + /// + /// Creates a new instance, pointing at . + /// + /// + /// The newly created instance. + /// + public IFileProvider Create() => _webHostEnvironment.WebRootFileProvider; +} diff --git a/src/Umbraco.Web.Common/Umbraco.Web.Common.csproj b/src/Umbraco.Web.Common/Umbraco.Web.Common.csproj index 7d5bc5ca74..00feb6d8b6 100644 --- a/src/Umbraco.Web.Common/Umbraco.Web.Common.csproj +++ b/src/Umbraco.Web.Common/Umbraco.Web.Common.csproj @@ -15,8 +15,8 @@ - - + + diff --git a/src/Umbraco.Web.UI.Client/src/views/common/login.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/login.controller.js index 5827f7e530..13ca4cb193 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/login.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/login.controller.js @@ -11,7 +11,11 @@ angular.module('umbraco').controller("Umbraco.LoginController", function (events //check if there's a returnPath query string, if so redirect to it var locationObj = $location.search(); if (locationObj.returnPath) { - path = decodeURIComponent(locationObj.returnPath); + // decodeURIComponent(...) does not play nice with OAuth redirect URLs, so until we have a + // dedicated login screen for the new back-office, we need to hardcode this exception + path = locationObj.returnPath.indexOf("/security/back-office/authorize") > 0 + ? locationObj.returnPath + : decodeURIComponent(locationObj.returnPath); } // Ensure path is not absolute diff --git a/tests/Umbraco.Tests.Common/TestHelpers/TestDatabase.cs b/tests/Umbraco.Tests.Common/TestHelpers/TestDatabase.cs index 26cc13949c..2d387dcdff 100644 --- a/tests/Umbraco.Tests.Common/TestHelpers/TestDatabase.cs +++ b/tests/Umbraco.Tests.Common/TestHelpers/TestDatabase.cs @@ -78,6 +78,7 @@ public class TestDatabase : IUmbracoDatabase public DbTransaction Transaction { get; } public IDictionary Data { get; } + public int CommandTimeout { get; set; } public ISqlContext SqlContext { get; } diff --git a/tests/Umbraco.Tests.Integration/NewBackoffice/OpenAPIContractTest.cs b/tests/Umbraco.Tests.Integration/NewBackoffice/OpenAPIContractTest.cs index 9178234e74..c4c0bad3a9 100644 --- a/tests/Umbraco.Tests.Integration/NewBackoffice/OpenAPIContractTest.cs +++ b/tests/Umbraco.Tests.Integration/NewBackoffice/OpenAPIContractTest.cs @@ -1,15 +1,11 @@ -using System; -using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using NUnit.Framework; using Umbraco.Cms.Core.Configuration.Models; -using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Hosting; using Umbraco.Cms.Tests.Integration.TestServerTest; -using Umbraco.Extensions; namespace Umbraco.Cms.Tests.Integration.NewBackoffice; @@ -39,7 +35,7 @@ internal sealed class OpenAPIContractTest : UmbracoTestServerTestBase var officePath = GlobalSettings.GetBackOfficePath(HostingEnvironment); var urlToContract = $"{officePath}/management/api/openapi.json"; - var swaggerPath = $"{officePath}/swagger/All/swagger.json"; + var swaggerPath = $"{officePath}/swagger/v1/swagger.json"; var apiContract = JObject.Parse(await Client.GetStringAsync(urlToContract)); var generatedJsonString = await Client.GetStringAsync(swaggerPath); diff --git a/tests/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs b/tests/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs index 5babe9aa0b..a174476acd 100644 --- a/tests/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs +++ b/tests/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs @@ -1,5 +1,3 @@ -using System; -using System.Linq; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; @@ -9,7 +7,6 @@ using Moq; using NUnit.Framework; using Umbraco.Cms.Core.Cache; using Umbraco.Cms.Core.Configuration.Models; -using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Strings; @@ -22,8 +19,6 @@ using Umbraco.Cms.Persistence.SqlServer; using Umbraco.Cms.Tests.Common.Builders; using Umbraco.Cms.Tests.Integration.DependencyInjection; using Umbraco.Cms.Tests.Integration.Extensions; -using Umbraco.Cms.Web.Common.Hosting; -using Umbraco.Extensions; using Constants = Umbraco.Cms.Core.Constants; namespace Umbraco.Cms.Tests.Integration.Testing; diff --git a/tests/Umbraco.Tests.UnitTests/TestHelpers/Objects/TestUmbracoContextFactory.cs b/tests/Umbraco.Tests.UnitTests/TestHelpers/Objects/TestUmbracoContextFactory.cs index 94a64b31c9..2099d1d537 100644 --- a/tests/Umbraco.Tests.UnitTests/TestHelpers/Objects/TestUmbracoContextFactory.cs +++ b/tests/Umbraco.Tests.UnitTests/TestHelpers/Objects/TestUmbracoContextFactory.cs @@ -23,7 +23,8 @@ public class TestUmbracoContextFactory GlobalSettings globalSettings = null, IUmbracoContextAccessor umbracoContextAccessor = null, IHttpContextAccessor httpContextAccessor = null, - IPublishedUrlProvider publishedUrlProvider = null) + IPublishedUrlProvider publishedUrlProvider = null, + UmbracoRequestPathsOptions umbracoRequestPathsOptions = null) { if (globalSettings == null) { @@ -45,6 +46,11 @@ public class TestUmbracoContextFactory publishedUrlProvider = Mock.Of(); } + if (umbracoRequestPathsOptions == null) + { + umbracoRequestPathsOptions = new UmbracoRequestPathsOptions(); + } + var contentCache = new Mock(); var mediaCache = new Mock(); var snapshot = new Mock(); @@ -58,7 +64,7 @@ public class TestUmbracoContextFactory var umbracoContextFactory = new UmbracoContextFactory( umbracoContextAccessor, snapshotService.Object, - new UmbracoRequestPaths(Options.Create(globalSettings), hostingEnvironment), + new UmbracoRequestPaths(Options.Create(globalSettings), hostingEnvironment, Options.Create(umbracoRequestPathsOptions)), hostingEnvironment, new UriUtility(hostingEnvironment), new AspNetCoreCookieManager(httpContextAccessor), diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/UdiTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/UdiTests.cs index 1596bf9888..3cc54f4933 100644 --- a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/UdiTests.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/CoreThings/UdiTests.cs @@ -307,9 +307,9 @@ public class UdiTests [UdiDefinition("foo", UdiType.GuidUdi)] public class FooConnector : IServiceConnector { - public IArtifact GetArtifact(Udi udi) => throw new NotImplementedException(); + public IArtifact GetArtifact(Udi udi, IContextCache contextCache) => throw new NotImplementedException(); - public IArtifact GetArtifact(object entity) => throw new NotImplementedException(); + public IArtifact GetArtifact(object entity, IContextCache contextCache) => throw new NotImplementedException(); public ArtifactDeployState ProcessInit(IArtifact art, IDeployContext context) => throw new NotImplementedException(); diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Manifest/ManifestParserTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Manifest/ManifestParserTests.cs index 03f635b2cd..71d1a25228 100644 --- a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Manifest/ManifestParserTests.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Manifest/ManifestParserTests.cs @@ -47,7 +47,8 @@ public class ManifestParserTests new JsonNetSerializer(), Mock.Of(), Mock.Of(), - Mock.Of()); + Mock.Of(), + Mock.Of()); } private ManifestParser _parser; diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/UmbracoRequestPathsTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/UmbracoRequestPathsTests.cs index 744febae67..4ed6ce842c 100644 --- a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/UmbracoRequestPathsTests.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Routing/UmbracoRequestPathsTests.cs @@ -18,10 +18,12 @@ public class UmbracoRequestPathsTests { _hostEnvironment = Mock.Of(); _globalSettings = new GlobalSettings(); + _umbracoRequestPathsOptions = new UmbracoRequestPathsOptions(); } private IWebHostEnvironment _hostEnvironment; private GlobalSettings _globalSettings; + private UmbracoRequestPathsOptions _umbracoRequestPathsOptions; private IHostingEnvironment CreateHostingEnvironment(string virtualPath = "") { @@ -49,7 +51,7 @@ public class UmbracoRequestPathsTests public void Is_Client_Side_Request(string url, bool assert) { var hostingEnvironment = CreateHostingEnvironment(); - var umbracoRequestPaths = new UmbracoRequestPaths(Options.Create(_globalSettings), hostingEnvironment); + var umbracoRequestPaths = new UmbracoRequestPaths(Options.Create(_globalSettings), hostingEnvironment, Options.Create(_umbracoRequestPathsOptions)); var uri = new Uri("http://test.com" + url); var result = umbracoRequestPaths.IsClientSideRequest(uri.AbsolutePath); @@ -60,7 +62,7 @@ public class UmbracoRequestPathsTests public void Is_Client_Side_Request_InvalidPath_ReturnFalse() { var hostingEnvironment = CreateHostingEnvironment(); - var umbracoRequestPaths = new UmbracoRequestPaths(Options.Create(_globalSettings), hostingEnvironment); + var umbracoRequestPaths = new UmbracoRequestPaths(Options.Create(_globalSettings), hostingEnvironment, Options.Create(_umbracoRequestPathsOptions)); // This URL is invalid. Default to false when the extension cannot be determined var uri = new Uri("http://test.com/installing-modules+foobar+\"yipee\""); @@ -85,11 +87,13 @@ public class UmbracoRequestPathsTests [TestCase("http://www.domain.com/myvdir/umbraco/api/blah", "myvdir", false)] [TestCase("http://www.domain.com/MyVdir/umbraco/api/blah", "/myvdir", false)] [TestCase("http://www.domain.com/MyVdir/Umbraco/", "myvdir", true)] + // NOTE: this test case is false for now - will be true once the IsBackOfficeRequest tweak from the new management API is put into UmbracoRequestPaths + [TestCase("http://www.domain.com/umbraco/management/api/v1.0/my/controller/action/", "", false)] public void Is_Back_Office_Request(string input, string virtualPath, bool expected) { var source = new Uri(input); var hostingEnvironment = CreateHostingEnvironment(virtualPath); - var umbracoRequestPaths = new UmbracoRequestPaths(Options.Create(_globalSettings), hostingEnvironment); + var umbracoRequestPaths = new UmbracoRequestPaths(Options.Create(_globalSettings), hostingEnvironment, Options.Create(_umbracoRequestPathsOptions)); Assert.AreEqual(expected, umbracoRequestPaths.IsBackOfficeRequest(source.AbsolutePath)); } @@ -106,7 +110,21 @@ public class UmbracoRequestPathsTests { var source = new Uri(input); var hostingEnvironment = CreateHostingEnvironment(); - var umbracoRequestPaths = new UmbracoRequestPaths(Options.Create(_globalSettings), hostingEnvironment); + var umbracoRequestPaths = new UmbracoRequestPaths(Options.Create(_globalSettings), hostingEnvironment, Options.Create(_umbracoRequestPathsOptions)); Assert.AreEqual(expected, umbracoRequestPaths.IsInstallerRequest(source.AbsolutePath)); } + + [TestCase("http://www.domain.com/some/path", false)] + [TestCase("http://www.domain.com/umbraco/surface/blah", false)] + [TestCase("http://www.domain.com/umbraco/api/blah", false)] + [TestCase("http://www.domain.com/umbraco/management/api/v1.0/my/controller/action/", true)] + public void Force_Back_Office_Request_With_Request_Paths_Options(string input, bool expected) + { + var source = new Uri(input); + var hostingEnvironment = CreateHostingEnvironment(); + var umbracoRequestPathsOptions = new UmbracoRequestPathsOptions(); + umbracoRequestPathsOptions.IsBackOfficeRequest = _ => true; + var umbracoRequestPaths = new UmbracoRequestPaths(Options.Create(_globalSettings), hostingEnvironment, Options.Create(umbracoRequestPathsOptions)); + Assert.AreEqual(expected, umbracoRequestPaths.IsBackOfficeRequest(source.AbsolutePath)); + } } diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Security/BackOfficeCookieManagerTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Security/BackOfficeCookieManagerTests.cs index b1881c132e..c59f9db68f 100644 --- a/tests/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Security/BackOfficeCookieManagerTests.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Web.BackOffice/Security/BackOfficeCookieManagerTests.cs @@ -24,12 +24,13 @@ public class BackOfficeCookieManagerTests public void ShouldAuthenticateRequest_When_Not_Configured() { var globalSettings = new GlobalSettings(); + var umbracoRequestPathsOptions = new UmbracoRequestPathsOptions(); var runtime = Mock.Of(x => x.Level == RuntimeLevel.Install); var mgr = new BackOfficeCookieManager( Mock.Of(), runtime, - new UmbracoRequestPaths(Options.Create(globalSettings), TestHelper.GetHostingEnvironment()), + new UmbracoRequestPaths(Options.Create(globalSettings), TestHelper.GetHostingEnvironment(), Options.Create(umbracoRequestPathsOptions)), Mock.Of()); var result = mgr.ShouldAuthenticateRequest("/umbraco"); @@ -41,6 +42,7 @@ public class BackOfficeCookieManagerTests public void ShouldAuthenticateRequest_When_Configured() { var globalSettings = new GlobalSettings(); + var umbracoRequestPathsOptions = new UmbracoRequestPathsOptions(); var runtime = Mock.Of(x => x.Level == RuntimeLevel.Run); var mgr = new BackOfficeCookieManager( @@ -49,7 +51,8 @@ public class BackOfficeCookieManagerTests new UmbracoRequestPaths( Options.Create(globalSettings), Mock.Of(x => - x.ApplicationVirtualPath == "/" && x.ToAbsolute(globalSettings.UmbracoPath) == "/umbraco")), + x.ApplicationVirtualPath == "/" && x.ToAbsolute(globalSettings.UmbracoPath) == "/umbraco"), + Options.Create(umbracoRequestPathsOptions)), Mock.Of()); var result = mgr.ShouldAuthenticateRequest("/umbraco"); @@ -61,6 +64,7 @@ public class BackOfficeCookieManagerTests public void ShouldAuthenticateRequest_Is_Back_Office() { var globalSettings = new GlobalSettings(); + var umbracoRequestPathsOptions = new UmbracoRequestPathsOptions(); var runtime = Mock.Of(x => x.Level == RuntimeLevel.Run); @@ -73,7 +77,8 @@ public class BackOfficeCookieManagerTests Options.Create(globalSettings), Mock.Of(x => x.ApplicationVirtualPath == "/" && x.ToAbsolute(globalSettings.UmbracoPath) == "/umbraco" && - x.ToAbsolute(Constants.SystemDirectories.Install) == "/install")), + x.ToAbsolute(Constants.SystemDirectories.Install) == "/install"), + Options.Create(umbracoRequestPathsOptions)), Mock.Of()); var result = mgr.ShouldAuthenticateRequest(remainingTimeoutSecondsPath); @@ -87,6 +92,7 @@ public class BackOfficeCookieManagerTests public void ShouldAuthenticateRequest_Not_Back_Office() { var globalSettings = new GlobalSettings(); + var umbracoRequestPathsOptions = new UmbracoRequestPathsOptions(); var runtime = Mock.Of(x => x.Level == RuntimeLevel.Run); @@ -97,7 +103,8 @@ public class BackOfficeCookieManagerTests Options.Create(globalSettings), Mock.Of(x => x.ApplicationVirtualPath == "/" && x.ToAbsolute(globalSettings.UmbracoPath) == "/umbraco" && - x.ToAbsolute(Constants.SystemDirectories.Install) == "/install")), + x.ToAbsolute(Constants.SystemDirectories.Install) == "/install"), + Options.Create(umbracoRequestPathsOptions)), Mock.Of()); var result = mgr.ShouldAuthenticateRequest("/notbackoffice"); diff --git a/version.json b/version.json index 579911bae3..e8639110f4 100644 --- a/version.json +++ b/version.json @@ -1,6 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", - "version": "11.0.0-rc1", + "version": "11.1.0-rc", "assemblyVersion": { "precision": "build" },