Merge branch 'release/11.1' into v11/dev

This commit is contained in:
Nikolaj
2022-12-21 13:54:29 +01:00
7 changed files with 65 additions and 51 deletions

View File

@@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Extensions;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.ManagementApi.Services;
@@ -13,18 +14,15 @@ namespace Umbraco.Cms.ManagementApi.Controllers.Dictionary;
public class ImportDictionaryController : DictionaryControllerBase
{
private readonly IHostingEnvironment _hostingEnvironment;
private readonly IDictionaryService _dictionaryService;
private readonly IWebHostEnvironment _webHostEnvironment;
private readonly ILoadDictionaryItemService _loadDictionaryItemService;
public ImportDictionaryController(
IHostingEnvironment hostingEnvironment,
IDictionaryService dictionaryService,
IWebHostEnvironment webHostEnvironment,
ILoadDictionaryItemService loadDictionaryItemService)
{
_hostingEnvironment = hostingEnvironment;
_dictionaryService = dictionaryService;
_webHostEnvironment = webHostEnvironment;
_loadDictionaryItemService = loadDictionaryItemService;
@@ -41,7 +39,7 @@ public class ImportDictionaryController : DictionaryControllerBase
return NotFound();
}
var filePath = Path.Combine(_hostingEnvironment.MapPathContentRoot(Constants.SystemDirectories.Data), file);
var filePath = Path.Combine(_webHostEnvironment.MapPathContentRoot(Constants.SystemDirectories.Data), file);
if (_webHostEnvironment.ContentRootFileProvider.GetFileInfo(filePath) is null)
{
return await Task.FromResult(NotFound());

View File

@@ -4,9 +4,9 @@ public static class Paths
{
public const string BackOfficeApiEndpointTemplate = "security/back-office";
public static string BackOfficeApiAuthorizationEndpoint = BackOfficeApiEndpointPath($"{BackOfficeApiEndpointTemplate}/authorize");
public static readonly string BackOfficeApiAuthorizationEndpoint = BackOfficeApiEndpointPath($"{BackOfficeApiEndpointTemplate}/authorize");
public static string BackOfficeApiTokenEndpoint = BackOfficeApiEndpointPath($"{BackOfficeApiEndpointTemplate}/token");
public static readonly string BackOfficeApiTokenEndpoint = BackOfficeApiEndpointPath($"{BackOfficeApiEndpointTemplate}/token");
private static string BackOfficeApiEndpointPath(string relativePath) => $"/umbraco/management/api/v1.0/{relativePath}";
}

View File

@@ -10,15 +10,16 @@ using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using Microsoft.OpenApi.Models;
using Umbraco.Cms.Core;
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.Controllers.Security;
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;
@@ -77,18 +78,22 @@ public class ManagementApiComposer : IComposer
if (string.IsNullOrWhiteSpace(relativePath))
{
throw new Exception($"There is no relative path for controller action {e.ActionDescriptor.RouteValues["controller"]}");
throw new Exception(
$"There is no relative path for controller action {e.ActionDescriptor.RouteValues["controller"]}");
}
// Remove the prefixed base path with version, e.g. /umbraco/management/api/v1/tracked-reference/{id} => tracked-reference/{id}
var unprefixedRelativePath = OperationIdRegexes.VersionPrefixRegex().Replace(relativePath, string.Empty);
var unprefixedRelativePath =
OperationIdRegexes.VersionPrefixRegex().Replace(relativePath, string.Empty);
// Remove template placeholders, e.g. tracked-reference/{id} => tracked-reference/Id
var formattedOperationId = OperationIdRegexes.TemplatePlaceholdersRegex().Replace(unprefixedRelativePath, m => $"By{m.Groups[1].Value.ToFirstUpper()}");
var formattedOperationId = OperationIdRegexes.TemplatePlaceholdersRegex()
.Replace(unprefixedRelativePath, m => $"By{m.Groups[1].Value.ToFirstUpper()}");
// Remove dashes (-) and slashes (/) and convert the following letter to uppercase with
// the word "By" in front, e.g. tracked-reference/Id => TrackedReferenceById
formattedOperationId = OperationIdRegexes.ToCamelCaseRegex().Replace(formattedOperationId, m => m.Groups[1].Value.ToUpper());
formattedOperationId = OperationIdRegexes.ToCamelCaseRegex()
.Replace(formattedOperationId, m => m.Groups[1].Value.ToUpper());
// Return the operation ID with the formatted http method verb in front, e.g. GetTrackedReferenceById
return $"{httpMethod}{formattedOperationId.ToFirstUpper()}";
@@ -99,33 +104,41 @@ public class ManagementApiComposer : IComposer
{
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"
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 });
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}";
{
return
$"{apiDesc.GroupName}_{apiDesc.ActionDescriptor.AttributeRouteInfo?.Template ?? apiDesc.ActionDescriptor.RouteValues["controller"]}_{apiDesc.ActionDescriptor.RouteValues["action"]}_{apiDesc.HttpMethod}";
}
swaggerGenOptions.OrderActionsBy(ActionSortKeySelector);
swaggerGenOptions.AddSecurityDefinition("OAuth", new OpenApiSecurityScheme
{
In = ParameterLocation.Header,
Name = "Umbraco",
Type = SecuritySchemeType.OAuth2,
Description = "Umbraco Authentication",
Flows = new OpenApiOAuthFlows
swaggerGenOptions.AddSecurityDefinition(
"OAuth",
new OpenApiSecurityScheme
{
AuthorizationCode = new OpenApiOAuthFlow
In = ParameterLocation.Header,
Name = "Umbraco",
Type = SecuritySchemeType.OAuth2,
Description = "Umbraco Authentication",
Flows = new OpenApiOAuthFlows
{
AuthorizationUrl = new Uri(Controllers.Security.Paths.BackOfficeApiAuthorizationEndpoint, UriKind.Relative),
TokenUrl = new Uri(Controllers.Security.Paths.BackOfficeApiTokenEndpoint, UriKind.Relative)
AuthorizationCode = new OpenApiOAuthFlow
{
AuthorizationUrl =
new Uri(Paths.BackOfficeApiAuthorizationEndpoint, UriKind.Relative),
TokenUrl = new Uri(Paths.BackOfficeApiTokenEndpoint, UriKind.Relative)
}
}
}
});
});
swaggerGenOptions.AddSecurityRequirement(new OpenApiSecurityRequirement
{
@@ -134,13 +147,9 @@ public class ManagementApiComposer : IComposer
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Id = "OAuth",
Type = ReferenceType.SecurityScheme
}
Reference = new OpenApiReference { Id = "OAuth", Type = ReferenceType.SecurityScheme }
},
new List<string> { }
new List<string>()
}
});
@@ -175,8 +184,10 @@ public class ManagementApiComposer : IComposer
applicationBuilder.UseWhen(
httpContext =>
{
GlobalSettings? settings = httpContext.RequestServices.GetRequiredService<IOptions<GlobalSettings>>().Value;
IHostingEnvironment hostingEnvironment = httpContext.RequestServices.GetRequiredService<IHostingEnvironment>();
GlobalSettings? settings = httpContext.RequestServices
.GetRequiredService<IOptions<GlobalSettings>>().Value;
IHostingEnvironment hostingEnvironment =
httpContext.RequestServices.GetRequiredService<IHostingEnvironment>();
var officePath = settings.GetBackOfficePath(hostingEnvironment);
return httpContext.Request.Path.Value?.StartsWith($"{officePath}/management/api/") ?? false;
@@ -197,7 +208,7 @@ public class ManagementApiComposer : IComposer
Detail = exception.StackTrace,
Status = StatusCodes.Status500InternalServerError,
Instance = exception.GetType().Name,
Type = "Error",
Type = "Error"
};
await context.Response.WriteAsJsonAsync(response);
}));
@@ -216,14 +227,19 @@ public class ManagementApiComposer : IComposer
applicationBuilder.UseSwagger(swaggerOptions =>
{
swaggerOptions.RouteTemplate = $"{officePath.TrimStart(Core.Constants.CharArrays.ForwardSlash)}/swagger/{{documentName}}/swagger.json";
swaggerOptions.RouteTemplate =
$"{officePath.TrimStart(Constants.CharArrays.ForwardSlash)}/swagger/{{documentName}}/swagger.json";
});
applicationBuilder.UseSwaggerUI(swaggerUiOptions =>
applicationBuilder.UseSwaggerUI(
swaggerUiOptions =>
{
swaggerUiOptions.SwaggerEndpoint($"{officePath}/swagger/v1/swagger.json", $"{ApiTitle} {DefaultApiVersion}");
swaggerUiOptions.RoutePrefix = $"{officePath.TrimStart(Core.Constants.CharArrays.ForwardSlash)}/swagger";
swaggerUiOptions.SwaggerEndpoint(
$"{officePath}/swagger/v1/swagger.json",
$"{ApiTitle} {DefaultApiVersion}");
swaggerUiOptions.RoutePrefix =
$"{officePath.TrimStart(Constants.CharArrays.ForwardSlash)}/swagger";
swaggerUiOptions.OAuthClientId(Constants.OauthClientIds.Swagger);
swaggerUiOptions.OAuthClientId(New.Cms.Core.Constants.OauthClientIds.Swagger);
swaggerUiOptions.OAuthUsePkce();
});
}
@@ -243,11 +259,12 @@ public class ManagementApiComposer : IComposer
// Serve contract
endpoints.MapGet($"{officePath}/management/api/openapi.json", async context =>
{
await context.Response.SendFileAsync(new EmbeddedFileProvider(GetType().Assembly).GetFileInfo("OpenApi.json"));
await context.Response.SendFileAsync(
new EmbeddedFileProvider(GetType().Assembly).GetFileInfo("OpenApi.json"));
});
});
}
));
}));
});
}
}

View File

@@ -1,22 +1,24 @@
using System.Xml;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Hosting;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Hosting;
using Umbraco.Cms.Core.Extensions;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.ManagementApi.Models;
using Umbraco.Extensions;
using IHostingEnvironment = Umbraco.Cms.Core.Hosting.IHostingEnvironment;
namespace Umbraco.Cms.ManagementApi.Services;
public class UploadFileService : IUploadFileService
{
private readonly IHostingEnvironment _hostingEnvironment;
private readonly IHostEnvironment _hostEnvironment;
private readonly ILocalizedTextService _localizedTextService;
public UploadFileService(IHostingEnvironment hostingEnvironment, ILocalizedTextService localizedTextService)
public UploadFileService(IHostEnvironment hostEnvironment, ILocalizedTextService localizedTextService)
{
_hostingEnvironment = hostingEnvironment;
_hostEnvironment = hostEnvironment;
_localizedTextService = localizedTextService;
}
@@ -25,7 +27,7 @@ public class UploadFileService : IUploadFileService
var formFileUploadResult = new FormFileUploadResult();
var fileName = file.FileName.Trim(Constants.CharArrays.DoubleQuote);
var ext = fileName.Substring(fileName.LastIndexOf('.') + 1).ToLower();
var root = _hostingEnvironment.MapPathContentRoot(Constants.SystemDirectories.TempFileUploads);
var root = _hostEnvironment.MapPathContentRoot(Constants.SystemDirectories.TempFileUploads);
formFileUploadResult.TemporaryPath = Path.Combine(root, fileName);
if (!Path.GetFullPath(formFileUploadResult.TemporaryPath).StartsWith(Path.GetFullPath(root)))

View File

@@ -13,9 +13,6 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="7.0.1" />
<PackageReference Include="OpenIddict.AspNetCore" Version="3.1.1" />
<PackageReference Include="OpenIddict.EntityFrameworkCore" Version="3.1.1" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="7.0.0" />
<PackageReference Include="OpenIddict.AspNetCore" Version="3.1.1" />
<PackageReference Include="OpenIddict.EntityFrameworkCore" Version="3.1.1" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
</ItemGroup>