V14: Add reserved fields to config endpoints (#15919)
* Add reserved fields to documents * Add member configuration endpoint * Add reserved field to media configuration * Refactor to use service instead on hardcoded methods * Clean up, aligning * Update OpenApi --------- Co-authored-by: Elitsa <elm@umbraco.dk>
This commit is contained in:
@@ -1,43 +1,26 @@
|
||||
using Asp.Versioning;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Umbraco.Cms.Api.Management.Factories;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Document;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.Document;
|
||||
|
||||
[ApiVersion("1.0")]
|
||||
public class ConfigurationDocumentController : DocumentControllerBase
|
||||
{
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly ContentSettings _contentSettings;
|
||||
private readonly SegmentSettings _segmentSettings;
|
||||
private readonly IConfigurationPresentationFactory _configurationPresentationFactory;
|
||||
|
||||
public ConfigurationDocumentController(
|
||||
IOptionsSnapshot<GlobalSettings> globalSettings,
|
||||
IOptionsSnapshot<ContentSettings> contentSettings,
|
||||
IOptionsSnapshot<SegmentSettings> segmentSettings)
|
||||
{
|
||||
_contentSettings = contentSettings.Value;
|
||||
_globalSettings = globalSettings.Value;
|
||||
_segmentSettings = segmentSettings.Value;
|
||||
}
|
||||
IConfigurationPresentationFactory configurationPresentationFactory) =>
|
||||
_configurationPresentationFactory = configurationPresentationFactory;
|
||||
|
||||
[HttpGet("configuration")]
|
||||
[MapToApiVersion("1.0")]
|
||||
[ProducesResponseType(typeof(DocumentConfigurationResponseModel), StatusCodes.Status200OK)]
|
||||
public Task<IActionResult> Configuration()
|
||||
{
|
||||
var responseModel = new DocumentConfigurationResponseModel
|
||||
{
|
||||
DisableDeleteWhenReferenced = _contentSettings.DisableDeleteWhenReferenced,
|
||||
DisableUnpublishWhenReferenced = _contentSettings.DisableUnpublishWhenReferenced,
|
||||
SanitizeTinyMce = _globalSettings.SanitizeTinyMce,
|
||||
AllowEditInvariantFromNonDefault = _contentSettings.AllowEditInvariantFromNonDefault,
|
||||
AllowNonExistingSegmentsCreation = _segmentSettings.AllowCreation,
|
||||
};
|
||||
|
||||
DocumentConfigurationResponseModel responseModel = _configurationPresentationFactory.CreateDocumentConfigurationResponseModel();
|
||||
return Task.FromResult<IActionResult>(Ok(responseModel));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,35 +1,26 @@
|
||||
using Asp.Versioning;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Umbraco.Cms.Api.Management.Factories;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Media;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.Media;
|
||||
|
||||
[ApiVersion("1.0")]
|
||||
public class ConfigurationMediaController : MediaControllerBase
|
||||
{
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly ContentSettings _contentSettings;
|
||||
private readonly IConfigurationPresentationFactory _configurationPresentationFactory;
|
||||
|
||||
public ConfigurationMediaController(IOptionsSnapshot<GlobalSettings> globalSettings, IOptionsSnapshot<ContentSettings> contentSettings)
|
||||
{
|
||||
_contentSettings = contentSettings.Value;
|
||||
_globalSettings = globalSettings.Value;
|
||||
}
|
||||
|
||||
public ConfigurationMediaController(IConfigurationPresentationFactory configurationPresentationFactory)
|
||||
=> _configurationPresentationFactory = configurationPresentationFactory;
|
||||
|
||||
[HttpGet("configuration")]
|
||||
[MapToApiVersion("1.0")]
|
||||
[ProducesResponseType(typeof(MediaConfigurationResponseModel), StatusCodes.Status200OK)]
|
||||
public Task<IActionResult> Configuration()
|
||||
{
|
||||
var responseModel = new MediaConfigurationResponseModel
|
||||
{
|
||||
DisableDeleteWhenReferenced = _contentSettings.DisableDeleteWhenReferenced,
|
||||
DisableUnpublishWhenReferenced = _contentSettings.DisableUnpublishWhenReferenced,
|
||||
SanitizeTinyMce = _globalSettings.SanitizeTinyMce,
|
||||
};
|
||||
MediaConfigurationResponseModel responseModel = _configurationPresentationFactory.CreateMediaConfigurationResponseModel();
|
||||
return Task.FromResult<IActionResult>(Ok(responseModel));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
using Asp.Versioning;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Umbraco.Cms.Api.Management.Factories;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Member;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Controllers.Member;
|
||||
|
||||
[ApiVersion("1.0")]
|
||||
public class ConfigurationMemberController : MemberControllerBase
|
||||
{
|
||||
private readonly IConfigurationPresentationFactory _configurationPresentationFactory;
|
||||
|
||||
public ConfigurationMemberController(
|
||||
IConfigurationPresentationFactory configurationPresentationFactory) =>
|
||||
_configurationPresentationFactory = configurationPresentationFactory;
|
||||
|
||||
[HttpGet("configuration")]
|
||||
[MapToApiVersion("1.0")]
|
||||
[ProducesResponseType(typeof(MemberConfigurationResponseModel), StatusCodes.Status200OK)]
|
||||
public Task<IActionResult> Configuration()
|
||||
{
|
||||
MemberConfigurationResponseModel responseModel = _configurationPresentationFactory.CreateMemberConfigurationResponseModel();
|
||||
return Task.FromResult<IActionResult>(Ok(responseModel));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Umbraco.Cms.Api.Management.Factories;
|
||||
using Umbraco.Cms.Core.DependencyInjection;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.DependencyInjection;
|
||||
|
||||
public static class ConfigurationBuilderExtensions
|
||||
{
|
||||
internal static IUmbracoBuilder AddConfigurationFactories(this IUmbracoBuilder builder)
|
||||
{
|
||||
builder.Services.AddTransient<IConfigurationPresentationFactory, ConfigurationPresentationFactory>();
|
||||
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,7 @@ public static partial class UmbracoBuilderExtensions
|
||||
.AddSearchManagement()
|
||||
.AddTrees()
|
||||
.AddAuditLogs()
|
||||
.AddConfigurationFactories()
|
||||
.AddDocuments()
|
||||
.AddDocumentTypes()
|
||||
.AddMedia()
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
using Microsoft.Extensions.Options;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Document;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Media;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Member;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Factories;
|
||||
|
||||
public class ConfigurationPresentationFactory : IConfigurationPresentationFactory
|
||||
{
|
||||
private readonly IReservedFieldNamesService _reservedFieldNamesService;
|
||||
private readonly GlobalSettings _globalSettings;
|
||||
private readonly ContentSettings _contentSettings;
|
||||
private readonly SegmentSettings _segmentSettings;
|
||||
|
||||
public ConfigurationPresentationFactory(
|
||||
IReservedFieldNamesService reservedFieldNamesService,
|
||||
IOptions<GlobalSettings> globalSettings,
|
||||
IOptions<ContentSettings> contentSettings,
|
||||
IOptions<SegmentSettings> segmentSettings)
|
||||
{
|
||||
_reservedFieldNamesService = reservedFieldNamesService;
|
||||
_globalSettings = globalSettings.Value;
|
||||
_contentSettings = contentSettings.Value;
|
||||
_segmentSettings = segmentSettings.Value;
|
||||
}
|
||||
|
||||
public DocumentConfigurationResponseModel CreateDocumentConfigurationResponseModel() =>
|
||||
new()
|
||||
{
|
||||
DisableDeleteWhenReferenced = _contentSettings.DisableDeleteWhenReferenced,
|
||||
DisableUnpublishWhenReferenced = _contentSettings.DisableUnpublishWhenReferenced,
|
||||
SanitizeTinyMce = _globalSettings.SanitizeTinyMce,
|
||||
AllowEditInvariantFromNonDefault = _contentSettings.AllowEditInvariantFromNonDefault,
|
||||
AllowNonExistingSegmentsCreation = _segmentSettings.AllowCreation,
|
||||
ReservedFieldNames = _reservedFieldNamesService.GetDocumentReservedFieldNames(),
|
||||
};
|
||||
|
||||
public MemberConfigurationResponseModel CreateMemberConfigurationResponseModel() =>
|
||||
new()
|
||||
{
|
||||
ReservedFieldNames = _reservedFieldNamesService.GetMemberReservedFieldNames(),
|
||||
};
|
||||
|
||||
public MediaConfigurationResponseModel CreateMediaConfigurationResponseModel() =>
|
||||
new()
|
||||
{
|
||||
DisableDeleteWhenReferenced = _contentSettings.DisableDeleteWhenReferenced,
|
||||
DisableUnpublishWhenReferenced = _contentSettings.DisableUnpublishWhenReferenced,
|
||||
SanitizeTinyMce = _globalSettings.SanitizeTinyMce,
|
||||
ReservedFieldNames = _reservedFieldNamesService.GetMediaReservedFieldNames(),
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Document;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Media;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.Member;
|
||||
|
||||
namespace Umbraco.Cms.Api.Management.Factories;
|
||||
|
||||
public interface IConfigurationPresentationFactory
|
||||
{
|
||||
DocumentConfigurationResponseModel CreateDocumentConfigurationResponseModel();
|
||||
|
||||
MemberConfigurationResponseModel CreateMemberConfigurationResponseModel();
|
||||
|
||||
MediaConfigurationResponseModel CreateMediaConfigurationResponseModel();
|
||||
}
|
||||
@@ -17429,6 +17429,56 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"/umbraco/management/api/v1/member/configuration": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Member"
|
||||
],
|
||||
"operationId": "GetMemberConfiguration",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "Success",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/MemberConfigurationResponseModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"text/json": {
|
||||
"schema": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/MemberConfigurationResponseModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"text/plain": {
|
||||
"schema": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/MemberConfigurationResponseModel"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"401": {
|
||||
"description": "The resource is protected and requires an authentication token"
|
||||
}
|
||||
},
|
||||
"security": [
|
||||
{
|
||||
"Backoffice User": [ ]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"/umbraco/management/api/v1/member/validate": {
|
||||
"post": {
|
||||
"tags": [
|
||||
@@ -34442,6 +34492,7 @@
|
||||
"allowNonExistingSegmentsCreation",
|
||||
"disableDeleteWhenReferenced",
|
||||
"disableUnpublishWhenReferenced",
|
||||
"reservedFieldNames",
|
||||
"sanitizeTinyMce"
|
||||
],
|
||||
"type": "object",
|
||||
@@ -34460,6 +34511,13 @@
|
||||
},
|
||||
"allowNonExistingSegmentsCreation": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"reservedFieldNames": {
|
||||
"uniqueItems": true,
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
@@ -36156,6 +36214,7 @@
|
||||
"required": [
|
||||
"disableDeleteWhenReferenced",
|
||||
"disableUnpublishWhenReferenced",
|
||||
"reservedFieldNames",
|
||||
"sanitizeTinyMce"
|
||||
],
|
||||
"type": "object",
|
||||
@@ -36168,6 +36227,13 @@
|
||||
},
|
||||
"sanitizeTinyMce": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"reservedFieldNames": {
|
||||
"uniqueItems": true,
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
@@ -36506,6 +36572,22 @@
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"MemberConfigurationResponseModel": {
|
||||
"required": [
|
||||
"reservedFieldNames"
|
||||
],
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"reservedFieldNames": {
|
||||
"uniqueItems": true,
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"MemberGroupItemResponseModel": {
|
||||
"type": "object",
|
||||
"allOf": [
|
||||
|
||||
@@ -11,4 +11,6 @@ public class DocumentConfigurationResponseModel
|
||||
public required bool AllowEditInvariantFromNonDefault { get; set; }
|
||||
|
||||
public required bool AllowNonExistingSegmentsCreation { get; set; }
|
||||
|
||||
public required ISet<string> ReservedFieldNames { get; set; }
|
||||
}
|
||||
|
||||
@@ -7,4 +7,6 @@ public class MediaConfigurationResponseModel
|
||||
public required bool DisableUnpublishWhenReferenced { get; set; }
|
||||
|
||||
public required bool SanitizeTinyMce { get; set; }
|
||||
|
||||
public required ISet<string> ReservedFieldNames { get; set; }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Umbraco.Cms.Api.Management.ViewModels.Member;
|
||||
|
||||
public class MemberConfigurationResponseModel
|
||||
{
|
||||
public required ISet<string> ReservedFieldNames { get; set; }
|
||||
}
|
||||
13
src/Umbraco.Core/Models/ContentPropertySettings.cs
Normal file
13
src/Umbraco.Core/Models/ContentPropertySettings.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace Umbraco.Cms.Core.Models;
|
||||
|
||||
public class ContentPropertySettings
|
||||
{
|
||||
private readonly HashSet<string> _reservedFieldNames = new();
|
||||
|
||||
/// <summary>
|
||||
/// Gets a set of standard names for fields that cannot be used for custom properties.
|
||||
/// </summary>
|
||||
public ISet<string> ReservedFieldNames => _reservedFieldNames;
|
||||
|
||||
public bool AddReservedFieldName(string name) => _reservedFieldNames.Add(name);
|
||||
}
|
||||
13
src/Umbraco.Core/Models/MediaPropertySettings.cs
Normal file
13
src/Umbraco.Core/Models/MediaPropertySettings.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace Umbraco.Cms.Core.Models;
|
||||
|
||||
public class MediaPropertySettings
|
||||
{
|
||||
private readonly HashSet<string> _reservedFieldNames = new();
|
||||
|
||||
/// <summary>
|
||||
/// Gets a set of standard names for fields that cannot be used for custom properties.
|
||||
/// </summary>
|
||||
public ISet<string> ReservedFieldNames => _reservedFieldNames;
|
||||
|
||||
public bool AddReservedFieldName(string name) => _reservedFieldNames.Add(name);
|
||||
}
|
||||
13
src/Umbraco.Core/Models/MemberPropertySettings.cs
Normal file
13
src/Umbraco.Core/Models/MemberPropertySettings.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace Umbraco.Cms.Core.Models;
|
||||
|
||||
public class MemberPropertySettings
|
||||
{
|
||||
private readonly HashSet<string> _reservedFieldNames = new();
|
||||
|
||||
/// <summary>
|
||||
/// Gets a set of standard names for fields that cannot be used for custom properties.
|
||||
/// </summary>
|
||||
public ISet<string> ReservedFieldNames => _reservedFieldNames;
|
||||
|
||||
public bool AddReservedFieldName(string name) => _reservedFieldNames.Add(name);
|
||||
}
|
||||
10
src/Umbraco.Core/Services/IReservedFieldNamesService.cs
Normal file
10
src/Umbraco.Core/Services/IReservedFieldNamesService.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
namespace Umbraco.Cms.Core.Services;
|
||||
|
||||
public interface IReservedFieldNamesService
|
||||
{
|
||||
ISet<string> GetDocumentReservedFieldNames();
|
||||
|
||||
ISet<string> GetMediaReservedFieldNames();
|
||||
|
||||
ISet<string> GetMemberReservedFieldNames();
|
||||
}
|
||||
@@ -35,6 +35,7 @@ public static class UmbracoBuilderExtensions
|
||||
builder.Services.TryAddTransient(factory => new PublishedSnapshotServiceOptions());
|
||||
builder.SetPublishedSnapshotService<PublishedSnapshotService>();
|
||||
builder.Services.TryAddSingleton<IPublishedSnapshotStatus, PublishedSnapshotStatus>();
|
||||
builder.Services.TryAddTransient<IReservedFieldNamesService, ReservedFieldNamesService>();
|
||||
|
||||
// replace this service since we want to improve the content/media
|
||||
// mapping lookups if we are using nucache.
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
using Microsoft.Extensions.Options;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.PublishedContent;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.PublishedCache;
|
||||
|
||||
internal class ReservedFieldNamesService : IReservedFieldNamesService
|
||||
{
|
||||
private readonly ContentPropertySettings _contentPropertySettings;
|
||||
private readonly MemberPropertySettings _memberPropertySettings;
|
||||
private readonly MediaPropertySettings _mediaPropertySettings;
|
||||
|
||||
public ReservedFieldNamesService(
|
||||
IOptions<ContentPropertySettings> contentPropertySettings,
|
||||
IOptions<MemberPropertySettings> memberPropertySettings,
|
||||
IOptions<MediaPropertySettings> mediaPropertySettings)
|
||||
{
|
||||
_contentPropertySettings = contentPropertySettings.Value;
|
||||
_memberPropertySettings = memberPropertySettings.Value;
|
||||
_mediaPropertySettings = mediaPropertySettings.Value;
|
||||
}
|
||||
|
||||
public ISet<string> GetDocumentReservedFieldNames()
|
||||
{
|
||||
var reservedProperties = typeof(IPublishedContent).GetPublicProperties().Select(x => x.Name).ToHashSet();
|
||||
var reservedMethods = typeof(IPublishedContent).GetPublicMethods().Select(x => x.Name).ToHashSet();
|
||||
reservedProperties.UnionWith(reservedMethods);
|
||||
reservedProperties.UnionWith(_contentPropertySettings.ReservedFieldNames);
|
||||
|
||||
return reservedProperties;
|
||||
}
|
||||
|
||||
public ISet<string> GetMediaReservedFieldNames()
|
||||
{
|
||||
var reservedProperties = typeof(IPublishedContent).GetPublicProperties().Select(x => x.Name).ToHashSet();
|
||||
var reservedMethods = typeof(IPublishedContent).GetPublicMethods().Select(x => x.Name).ToHashSet();
|
||||
reservedProperties.UnionWith(reservedMethods);
|
||||
reservedProperties.UnionWith(_mediaPropertySettings.ReservedFieldNames);
|
||||
|
||||
return reservedProperties;
|
||||
}
|
||||
|
||||
public ISet<string> GetMemberReservedFieldNames()
|
||||
{
|
||||
var reservedProperties = typeof(PublishedMember).GetPublicProperties().Select(x => x.Name).ToHashSet();
|
||||
var reservedMethods = typeof(PublishedMember).GetPublicMethods().Select(x => x.Name).ToHashSet();
|
||||
reservedProperties.UnionWith(reservedMethods);
|
||||
reservedProperties.UnionWith(_memberPropertySettings.ReservedFieldNames);
|
||||
|
||||
return reservedProperties;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user