From 5d968afb7ef8b5e632167576ded9363635f7e89a Mon Sep 17 00:00:00 2001 From: Laura Neto <12862535+lauraneto@users.noreply.github.com> Date: Tue, 15 Jul 2025 09:01:04 +0200 Subject: [PATCH 01/23] Fix failing integration tests in SQL Server (#19725) Co-authored-by: Kenn Jacobsen --- tests/Umbraco.Tests.Common/Builders/DataTypeBuilder.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/Umbraco.Tests.Common/Builders/DataTypeBuilder.cs b/tests/Umbraco.Tests.Common/Builders/DataTypeBuilder.cs index 9226d42474..284e68592f 100644 --- a/tests/Umbraco.Tests.Common/Builders/DataTypeBuilder.cs +++ b/tests/Umbraco.Tests.Common/Builders/DataTypeBuilder.cs @@ -178,10 +178,9 @@ public class DataTypeBuilder elementSettingKey, editorAlias == Constants.PropertyEditors.Aliases.BlockGrid ? true : null); - var dataTypeBuilder = new DataTypeBuilder() .WithId(0) - .WithDatabaseType(ValueStorageType.Nvarchar) + .WithDatabaseType(ValueStorageType.Ntext) .AddEditor() .WithAlias(editorAlias); From 698d566b76609a0c530398655699d8180cec3849 Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Tue, 15 Jul 2025 14:31:33 +0200 Subject: [PATCH 02/23] Populate name for content and media on URL picker if title is left empty (#19677) * Populate name for content and media on URL picker if title is left empty. * Display URL for manually entered URLs. * Updates from code review. * Reverted `elementName` constant * Sorted imports * Small code tidy-ups * Added logic to render the `url` as the `name` fallback In this case, the `detail` is left empty, giving prominence to the `url` value. * Refactored the get name/url methods for code consistency. * Updated `#requestRemoveItem()` to use the item's resolved name with a fallback to "item". Also localized the "Remove" button label --------- Co-authored-by: leekelleher --- .../MultiUrlPickerValueConverter.cs | 5 + .../input-multi-url.element.ts | 104 +++++++++++++----- 2 files changed, 82 insertions(+), 27 deletions(-) diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/MultiUrlPickerValueConverter.cs b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/MultiUrlPickerValueConverter.cs index a520fa35ef..4b285caf1c 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/MultiUrlPickerValueConverter.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/MultiUrlPickerValueConverter.cs @@ -101,6 +101,11 @@ public class MultiUrlPickerValueConverter : PropertyValueConverterBase, IDeliver continue; } + if (string.IsNullOrEmpty(dto.Name)) + { + dto.Name = content.Name; + } + url = content.Url(_publishedUrlProvider); } diff --git a/src/Umbraco.Web.UI.Client/src/packages/multi-url-picker/components/input-multi-url/input-multi-url.element.ts b/src/Umbraco.Web.UI.Client/src/packages/multi-url-picker/components/input-multi-url/input-multi-url.element.ts index f7e23b6231..5b9116e45d 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/multi-url-picker/components/input-multi-url/input-multi-url.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/multi-url-picker/components/input-multi-url/input-multi-url.element.ts @@ -12,17 +12,21 @@ import { when, } from '@umbraco-cms/backoffice/external/lit'; import { simpleHashCode } from '@umbraco-cms/backoffice/observable-api'; +import { umbConfirmModal } from '@umbraco-cms/backoffice/modal'; import { UmbChangeEvent } from '@umbraco-cms/backoffice/event'; import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element'; -import { umbConfirmModal } from '@umbraco-cms/backoffice/modal'; +import { + UmbDocumentItemRepository, + UmbDocumentUrlRepository, + UmbDocumentUrlsDataResolver, +} from '@umbraco-cms/backoffice/document'; +import { UmbMediaItemRepository, UmbMediaUrlRepository } from '@umbraco-cms/backoffice/media'; import { UmbModalRouteRegistrationController } from '@umbraco-cms/backoffice/router'; import { UmbSorterController } from '@umbraco-cms/backoffice/sorter'; import { UUIFormControlMixin } from '@umbraco-cms/backoffice/external/uui'; import type { UmbModalRouteBuilder } from '@umbraco-cms/backoffice/router'; import type { UmbVariantId } from '@umbraco-cms/backoffice/variant'; import type { UUIModalSidebarSize } from '@umbraco-cms/backoffice/external/uui'; -import { UmbDocumentUrlRepository, UmbDocumentUrlsDataResolver } from '@umbraco-cms/backoffice/document'; -import { UmbMediaUrlRepository } from '@umbraco-cms/backoffice/media'; /** * @element umb-input-multi-url @@ -30,8 +34,7 @@ import { UmbMediaUrlRepository } from '@umbraco-cms/backoffice/media'; * @fires blur - when the input loses focus * @fires focus - when the input gains focus */ -const elementName = 'umb-input-multi-url'; -@customElement(elementName) +@customElement('umb-input-multi-url') export class UmbInputMultiUrlElement extends UUIFormControlMixin(UmbLitElement, '') { #sorter = new UmbSorterController(this, { getUniqueOfElement: (element) => { @@ -131,7 +134,7 @@ export class UmbInputMultiUrlElement extends UUIFormControlMixin(UmbLitElement, this.#urls = [...data]; // Unfreeze data coming from State, so we can manipulate it. super.value = this.#urls.map((x) => x.url).join(','); this.#sorter.setModel(this.#urls); - this.#populateLinksUrl(); + this.#populateLinksNameAndUrl(); } get urls(): Array { return this.#urls; @@ -139,6 +142,13 @@ export class UmbInputMultiUrlElement extends UUIFormControlMixin(UmbLitElement, #urls: Array = []; + #documentItemRepository = new UmbDocumentItemRepository(this); + #documentUrlRepository = new UmbDocumentUrlRepository(this); + #documentUrlsDataResolver = new UmbDocumentUrlsDataResolver(this); + + #mediaItemRepository = new UmbMediaItemRepository(this); + #mediaUrlRepository = new UmbMediaUrlRepository(this); + /** * Sets the input to readonly mode, meaning value cannot be changed but still able to read and select its content. * @type {boolean} @@ -163,6 +173,9 @@ export class UmbInputMultiUrlElement extends UUIFormControlMixin(UmbLitElement, @state() private _modalRoute?: UmbModalRouteBuilder; + @state() + _resolvedLinkNames: Array<{ unique: string; name: string }> = []; + @state() _resolvedLinkUrls: Array<{ unique: string; url: string }> = []; @@ -235,19 +248,30 @@ export class UmbInputMultiUrlElement extends UUIFormControlMixin(UmbLitElement, }); } - #populateLinksUrl() { - // Documents and media have URLs saved in the local link format. Display the actual URL to align with what - // the user sees when they selected it initially. + #populateLinksNameAndUrl() { + this._resolvedLinkNames = []; + this._resolvedLinkUrls = []; + + // Documents and media have URLs saved in the local link format. + // Display the actual URL to align with what the user sees when they selected it initially. this.#urls.forEach(async (link) => { if (!link.unique) return; + let name: string | undefined = undefined; let url: string | undefined = undefined; + switch (link.type) { case 'document': { + if (!link.name || link.name.length === 0) { + name = await this.#getNameForDocument(link.unique); + } url = await this.#getUrlForDocument(link.unique); break; } case 'media': { + if (!link.name || link.name.length === 0) { + name = await this.#getNameForMedia(link.unique); + } url = await this.#getUrlForMedia(link.unique); break; } @@ -255,6 +279,11 @@ export class UmbInputMultiUrlElement extends UUIFormControlMixin(UmbLitElement, break; } + if (name) { + const resolvedName = { unique: link.unique, name }; + this._resolvedLinkNames = [...this._resolvedLinkNames, resolvedName]; + } + if (url) { const resolvedUrl = { unique: link.unique, url }; this._resolvedLinkUrls = [...this._resolvedLinkUrls, resolvedUrl]; @@ -263,30 +292,38 @@ export class UmbInputMultiUrlElement extends UUIFormControlMixin(UmbLitElement, } async #getUrlForDocument(unique: string) { - const documentUrlRepository = new UmbDocumentUrlRepository(this); - const { data: documentUrlData } = await documentUrlRepository.requestItems([unique]); - const urlsItem = documentUrlData?.[0]; - const dataResolver = new UmbDocumentUrlsDataResolver(this); - dataResolver.setData(urlsItem?.urls); - const resolvedUrls = await dataResolver.getUrls(); + const { data: data } = await this.#documentUrlRepository.requestItems([unique]); + + this.#documentUrlsDataResolver.setData(data?.[0]?.urls); + + const resolvedUrls = await this.#documentUrlsDataResolver.getUrls(); return resolvedUrls?.[0]?.url ?? ''; } async #getUrlForMedia(unique: string) { - const mediaUrlRepository = new UmbMediaUrlRepository(this); - const { data: mediaUrlData } = await mediaUrlRepository.requestItems([unique]); - return mediaUrlData?.[0].url ?? ''; + const { data } = await this.#mediaUrlRepository.requestItems([unique]); + return data?.[0].url ?? ''; } - async #requestRemoveItem(index: number) { + async #getNameForDocument(unique: string) { + const { data } = await this.#documentItemRepository.requestItems([unique]); + return data?.[0]?.name ?? ''; + } + + async #getNameForMedia(unique: string) { + const { data } = await this.#mediaItemRepository.requestItems([unique]); + return data?.[0]?.name ?? ''; + } + + async #requestRemoveItem(index: number, name?: string) { const item = this.#urls[index]; if (!item) throw new Error('Could not find item at index: ' + index); await umbConfirmModal(this, { color: 'danger', - headline: `Remove ${item.name}?`, - content: 'Are you sure you want to remove this item', - confirmLabel: 'Remove', + headline: `Remove ${name || item.name || 'item'}?`, + content: 'Are you sure you want to remove this item?', + confirmLabel: '#general_remove', }); this.#removeItem(index); @@ -320,6 +357,17 @@ export class UmbInputMultiUrlElement extends UUIFormControlMixin(UmbLitElement, this.dispatchEvent(new UmbChangeEvent()); } + #getResolvedItemName(link: UmbLinkPickerLink): string { + return (link.name || this._resolvedLinkNames.find((name) => name.unique === link.unique)?.name) ?? ''; + } + + #getResolvedItemUrl(link: UmbLinkPickerLink): string { + return ( + (this._resolvedLinkUrls.find((url) => url.unique === link.unique)?.url ?? link.url ?? '') + + (link.queryString || '') + ); + } + override render() { return html`${this.#renderItems()} ${this.#renderAddButton()}`; } @@ -356,13 +404,15 @@ export class UmbInputMultiUrlElement extends UUIFormControlMixin(UmbLitElement, #renderItem(link: UmbLinkPickerLink, index: number) { const unique = this.#getUnique(link); const href = this.readonly ? undefined : (this._modalRoute?.({ index }) ?? undefined); - const resolvedUrl = this._resolvedLinkUrls.find((url) => url.unique === link.unique)?.url ?? ''; + const name = this.#getResolvedItemName(link); + const url = this.#getResolvedItemUrl(link); + return html` ${when( @@ -371,7 +421,7 @@ export class UmbInputMultiUrlElement extends UUIFormControlMixin(UmbLitElement, this.#requestRemoveItem(index)}> + @click=${() => this.#requestRemoveItem(index, name)}> `, )} @@ -390,6 +440,6 @@ export class UmbInputMultiUrlElement extends UUIFormControlMixin(UmbLitElement, declare global { interface HTMLElementTagNameMap { - [elementName]: UmbInputMultiUrlElement; + 'umb-input-multi-url': UmbInputMultiUrlElement; } } From 5660c6c369d41c6302cb03cd5b7b0114d4ce5322 Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Fri, 18 Jul 2025 10:47:34 +0200 Subject: [PATCH 03/23] Forward merge #19720 to V16 (#19735) * Add support for programmatic creation of property types providing the data type key (#19720) * Add support for programmatic creation of property types providing the data type key. * Add integration tests --------- Co-authored-by: kjac * Don't use Lazy --------- Co-authored-by: Andy Butland --- .../Implement/ContentTypeRepository.cs | 6 +- .../Implement/ContentTypeRepositoryBase.cs | 79 +++++++++++++------ .../Implement/MediaTypeRepository.cs | 6 +- .../Implement/MemberTypeRepository.cs | 8 +- .../Testing/UmbracoIntegrationTest.cs | 2 + .../Repositories/DocumentRepositoryTest.cs | 2 +- .../Repositories/MediaRepositoryTest.cs | 2 +- .../Repositories/MediaTypeRepositoryTest.cs | 3 +- .../Repositories/MemberTypeRepositoryTest.cs | 3 +- .../Repositories/TemplateRepositoryTest.cs | 2 +- .../Services/ContentTypeServiceTests.cs | 59 ++++++++++++++ 11 files changed, 135 insertions(+), 37 deletions(-) diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepository.cs index f437c0cd0d..e1672beda9 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepository.cs @@ -5,6 +5,7 @@ using Umbraco.Cms.Core.Cache; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Persistence.Querying; using Umbraco.Cms.Core.Persistence.Repositories; +using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Strings; using Umbraco.Cms.Infrastructure.Persistence.Dtos; using Umbraco.Cms.Infrastructure.Persistence.Querying; @@ -25,8 +26,9 @@ internal class ContentTypeRepository : ContentTypeRepositoryBase, ILogger logger, IContentTypeCommonRepository commonRepository, ILanguageRepository languageRepository, - IShortStringHelper shortStringHelper) - : base(scopeAccessor, cache, logger, commonRepository, languageRepository, shortStringHelper) + IShortStringHelper shortStringHelper, + IIdKeyMap idKeyMap) + : base(scopeAccessor, cache, logger, commonRepository, languageRepository, shortStringHelper, idKeyMap) { } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs index 0d68cd39bf..ae843ddfad 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs @@ -29,15 +29,22 @@ internal abstract class ContentTypeRepositoryBase : EntityRepositoryBas where TEntity : class, IContentTypeComposition { private readonly IShortStringHelper _shortStringHelper; + private readonly IIdKeyMap _idKeyMap; - protected ContentTypeRepositoryBase(IScopeAccessor scopeAccessor, AppCaches cache, - ILogger> logger, IContentTypeCommonRepository commonRepository, - ILanguageRepository languageRepository, IShortStringHelper shortStringHelper) + protected ContentTypeRepositoryBase( + IScopeAccessor scopeAccessor, + AppCaches cache, + ILogger> logger, + IContentTypeCommonRepository commonRepository, + ILanguageRepository languageRepository, + IShortStringHelper shortStringHelper, + IIdKeyMap idKeyMap) : base(scopeAccessor, cache, logger) { _shortStringHelper = shortStringHelper; CommonRepository = commonRepository; LanguageRepository = languageRepository; + _idKeyMap = idKeyMap; } protected IContentTypeCommonRepository CommonRepository { get; } @@ -291,7 +298,7 @@ AND umbracoNode.nodeObjectType = @objectType", // If the Id of the DataType is not set, we resolve it from the db by its PropertyEditorAlias if (propertyType.DataTypeId == 0 || propertyType.DataTypeId == default) { - AssignDataTypeFromPropertyEditor(propertyType); + AssignDataTypeIdFromProvidedKeyOrPropertyEditor(propertyType); } PropertyTypeDto propertyTypeDto = @@ -592,7 +599,7 @@ AND umbracoNode.id <> @id", // if the Id of the DataType is not set, we resolve it from the db by its PropertyEditorAlias if (propertyType.DataTypeId == 0 || propertyType.DataTypeId == default) { - AssignDataTypeFromPropertyEditor(propertyType); + AssignDataTypeIdFromProvidedKeyOrPropertyEditor(propertyType); } // validate the alias @@ -1434,37 +1441,59 @@ AND umbracoNode.id <> @id", protected abstract TEntity? PerformGet(Guid id); /// - /// Try to set the data type id based on its ControlId + /// Try to set the data type Id based on the provided key or property editor alias. /// /// - private void AssignDataTypeFromPropertyEditor(IPropertyType propertyType) + private void AssignDataTypeIdFromProvidedKeyOrPropertyEditor(IPropertyType propertyType) { - // we cannot try to assign a data type of it's empty - if (propertyType.PropertyEditorAlias.IsNullOrWhiteSpace() == false) + // If a key is provided, use that. + if (propertyType.DataTypeKey != Guid.Empty) { - Sql sql = Sql() - .Select(dt => dt.Select(x => x.NodeDto)) - .From() - .InnerJoin().On((dt, n) => dt.NodeId == n.NodeId) - .Where( - "propertyEditorAlias = @propertyEditorAlias", - new { propertyEditorAlias = propertyType.PropertyEditorAlias }) - .OrderBy(typeDto => typeDto.NodeId); - DataTypeDto? datatype = Database.FirstOrDefault(sql); - - // we cannot assign a data type if one was not found - if (datatype != null) + Attempt dataTypeIdAttempt = _idKeyMap.GetIdForKey(propertyType.DataTypeKey, UmbracoObjectTypes.DataType); + if (dataTypeIdAttempt.Success) { - propertyType.DataTypeId = datatype.NodeId; - propertyType.DataTypeKey = datatype.NodeDto.UniqueId; + propertyType.DataTypeId = dataTypeIdAttempt.Result; + return; } else { Logger.LogWarning( - "Could not assign a data type for the property type {PropertyTypeAlias} since no data type was found with a property editor {PropertyEditorAlias}", - propertyType.Alias, propertyType.PropertyEditorAlias); + "Could not assign a data type for the property type {PropertyTypeAlias} since no integer Id was found matching the key {DataTypeKey}. Falling back to look up via the property editor alias.", + propertyType.Alias, + propertyType.DataTypeKey); } } + + // Otherwise if a property editor alias is provided, try to find a data type that uses that alias. + if (propertyType.PropertyEditorAlias.IsNullOrWhiteSpace()) + { + // We cannot try to assign a data type if it's empty. + return; + } + + Sql sql = Sql() + .Select(dt => dt.Select(x => x.NodeDto)) + .From() + .InnerJoin().On((dt, n) => dt.NodeId == n.NodeId) + .Where( + "propertyEditorAlias = @propertyEditorAlias", + new { propertyEditorAlias = propertyType.PropertyEditorAlias }) + .OrderBy(typeDto => typeDto.NodeId); + DataTypeDto? datatype = Database.FirstOrDefault(sql); + + // we cannot assign a data type if one was not found + if (datatype != null) + { + propertyType.DataTypeId = datatype.NodeId; + propertyType.DataTypeKey = datatype.NodeDto.UniqueId; + } + else + { + Logger.LogWarning( + "Could not assign a data type for the property type {PropertyTypeAlias} since no data type was found with a property editor {PropertyEditorAlias}", + propertyType.Alias, + propertyType.PropertyEditorAlias); + } } protected abstract TEntity? PerformGet(string alias); diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaTypeRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaTypeRepository.cs index 51a4c36752..792e984387 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaTypeRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaTypeRepository.cs @@ -5,6 +5,7 @@ using Umbraco.Cms.Core.Cache; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Persistence.Querying; using Umbraco.Cms.Core.Persistence.Repositories; +using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Strings; using Umbraco.Cms.Infrastructure.Persistence.Dtos; using Umbraco.Cms.Infrastructure.Persistence.Querying; @@ -24,8 +25,9 @@ internal class MediaTypeRepository : ContentTypeRepositoryBase, IMed ILogger logger, IContentTypeCommonRepository commonRepository, ILanguageRepository languageRepository, - IShortStringHelper shortStringHelper) - : base(scopeAccessor, cache, logger, commonRepository, languageRepository, shortStringHelper) + IShortStringHelper shortStringHelper, + IIdKeyMap idKeyMap) + : base(scopeAccessor, cache, logger, commonRepository, languageRepository, shortStringHelper, idKeyMap) { } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberTypeRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberTypeRepository.cs index 61127b766b..e764f54090 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberTypeRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberTypeRepository.cs @@ -5,6 +5,7 @@ using Umbraco.Cms.Core.Cache; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Persistence.Querying; using Umbraco.Cms.Core.Persistence.Repositories; +using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Strings; using Umbraco.Cms.Infrastructure.Persistence.Dtos; using Umbraco.Cms.Infrastructure.Persistence.Factories; @@ -27,9 +28,10 @@ internal class MemberTypeRepository : ContentTypeRepositoryBase, IM ILogger logger, IContentTypeCommonRepository commonRepository, ILanguageRepository languageRepository, - IShortStringHelper shortStringHelper) - : base(scopeAccessor, cache, logger, commonRepository, languageRepository, shortStringHelper) => - _shortStringHelper = shortStringHelper; + IShortStringHelper shortStringHelper, + IIdKeyMap idKeyMap) + : base(scopeAccessor, cache, logger, commonRepository, languageRepository, shortStringHelper, idKeyMap) + => _shortStringHelper = shortStringHelper; protected override bool SupportsPublishing => MemberType.SupportsPublishingConst; diff --git a/tests/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs b/tests/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs index d8fd5f48a4..ec92a40fe7 100644 --- a/tests/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs +++ b/tests/Umbraco.Tests.Integration/Testing/UmbracoIntegrationTest.cs @@ -60,6 +60,8 @@ public abstract class UmbracoIntegrationTest : UmbracoIntegrationTestBase protected IShortStringHelper ShortStringHelper => Services.GetRequiredService(); + protected IIdKeyMap IdKeyMap => Services.GetRequiredService(); + protected GlobalSettings GlobalSettings => Services.GetRequiredService>().Value; protected IMapperCollection Mappers => Services.GetRequiredService(); diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/DocumentRepositoryTest.cs b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/DocumentRepositoryTest.cs index 94a6c1884a..22cc35b424 100644 --- a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/DocumentRepositoryTest.cs +++ b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/DocumentRepositoryTest.cs @@ -123,7 +123,7 @@ internal sealed class DocumentRepositoryTest : UmbracoIntegrationTest new ContentTypeCommonRepository(scopeAccessor, templateRepository, appCaches, ShortStringHelper); var languageRepository = new LanguageRepository(scopeAccessor, appCaches, LoggerFactory.CreateLogger()); - contentTypeRepository = new ContentTypeRepository(scopeAccessor, appCaches, LoggerFactory.CreateLogger(), commonRepository, languageRepository, ShortStringHelper); + contentTypeRepository = new ContentTypeRepository(scopeAccessor, appCaches, LoggerFactory.CreateLogger(), commonRepository, languageRepository, ShortStringHelper, IdKeyMap); var relationTypeRepository = new RelationTypeRepository(scopeAccessor, AppCaches.Disabled, LoggerFactory.CreateLogger()); var entityRepository = new EntityRepository(scopeAccessor, AppCaches.Disabled); var relationRepository = new RelationRepository(scopeAccessor, LoggerFactory.CreateLogger(), relationTypeRepository, entityRepository); diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/MediaRepositoryTest.cs b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/MediaRepositoryTest.cs index 3b21605d07..1532846fc4 100644 --- a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/MediaRepositoryTest.cs +++ b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/MediaRepositoryTest.cs @@ -56,7 +56,7 @@ internal sealed class MediaRepositoryTest : UmbracoIntegrationTest new ContentTypeCommonRepository(scopeAccessor, TemplateRepository, appCaches, ShortStringHelper); var languageRepository = new LanguageRepository(scopeAccessor, appCaches, LoggerFactory.CreateLogger()); - mediaTypeRepository = new MediaTypeRepository(scopeAccessor, appCaches, LoggerFactory.CreateLogger(), commonRepository, languageRepository, ShortStringHelper); + mediaTypeRepository = new MediaTypeRepository(scopeAccessor, appCaches, LoggerFactory.CreateLogger(), commonRepository, languageRepository, ShortStringHelper, IdKeyMap); var tagRepository = new TagRepository(scopeAccessor, appCaches, LoggerFactory.CreateLogger()); var relationTypeRepository = new RelationTypeRepository(scopeAccessor, AppCaches.Disabled, LoggerFactory.CreateLogger()); var entityRepository = new EntityRepository(scopeAccessor, AppCaches.Disabled); diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/MediaTypeRepositoryTest.cs b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/MediaTypeRepositoryTest.cs index 34a9245636..a05d5b96c9 100644 --- a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/MediaTypeRepositoryTest.cs +++ b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/MediaTypeRepositoryTest.cs @@ -9,6 +9,7 @@ using Umbraco.Cms.Core.Cache; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Persistence; using Umbraco.Cms.Core.Persistence.Repositories; +using Umbraco.Cms.Core.Services; using Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement; using Umbraco.Cms.Infrastructure.Scoping; using Umbraco.Cms.Tests.Common.Builders; @@ -411,7 +412,7 @@ internal sealed class MediaTypeRepositoryTest : UmbracoIntegrationTest } private MediaTypeRepository CreateRepository(IScopeProvider provider) => - new((IScopeAccessor)provider, AppCaches.Disabled, LoggerFactory.CreateLogger(), CommonRepository, LanguageRepository, ShortStringHelper); + new((IScopeAccessor)provider, AppCaches.Disabled, LoggerFactory.CreateLogger(), CommonRepository, LanguageRepository, ShortStringHelper, IdKeyMap); private EntityContainerRepository CreateContainerRepository(IScopeProvider provider) => new((IScopeAccessor)provider, AppCaches.Disabled, LoggerFactory.CreateLogger(), Constants.ObjectTypes.MediaTypeContainer); diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/MemberTypeRepositoryTest.cs b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/MemberTypeRepositoryTest.cs index 0c1f071239..6392354a6f 100644 --- a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/MemberTypeRepositoryTest.cs +++ b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/MemberTypeRepositoryTest.cs @@ -10,6 +10,7 @@ using Umbraco.Cms.Core.Cache; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Persistence; using Umbraco.Cms.Core.Persistence.Repositories; +using Umbraco.Cms.Core.Services; using Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement; using Umbraco.Cms.Infrastructure.Scoping; using Umbraco.Cms.Tests.Common.Builders; @@ -26,7 +27,7 @@ internal sealed class MemberTypeRepositoryTest : UmbracoIntegrationTest { var commonRepository = GetRequiredService(); var languageRepository = GetRequiredService(); - return new MemberTypeRepository((IScopeAccessor)provider, AppCaches.Disabled, Mock.Of>(), commonRepository, languageRepository, ShortStringHelper); + return new MemberTypeRepository((IScopeAccessor)provider, AppCaches.Disabled, Mock.Of>(), commonRepository, languageRepository, ShortStringHelper, IdKeyMap); } [Test] diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/TemplateRepositoryTest.cs b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/TemplateRepositoryTest.cs index 973ea658dc..2350b1d1f5 100644 --- a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/TemplateRepositoryTest.cs +++ b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/TemplateRepositoryTest.cs @@ -266,7 +266,7 @@ internal sealed class TemplateRepositoryTest : UmbracoIntegrationTest var commonRepository = new ContentTypeCommonRepository(scopeAccessor, templateRepository, AppCaches, ShortStringHelper); var languageRepository = new LanguageRepository(scopeAccessor, AppCaches.Disabled, LoggerFactory.CreateLogger()); - var contentTypeRepository = new ContentTypeRepository(scopeAccessor, AppCaches.Disabled, LoggerFactory.CreateLogger(), commonRepository, languageRepository, ShortStringHelper); + var contentTypeRepository = new ContentTypeRepository(scopeAccessor, AppCaches.Disabled, LoggerFactory.CreateLogger(), commonRepository, languageRepository, ShortStringHelper, IdKeyMap); var relationTypeRepository = new RelationTypeRepository(scopeAccessor, AppCaches.Disabled, LoggerFactory.CreateLogger()); var entityRepository = new EntityRepository(scopeAccessor, AppCaches.Disabled); var relationRepository = new RelationRepository(scopeAccessor, LoggerFactory.CreateLogger(), relationTypeRepository, entityRepository); diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentTypeServiceTests.cs b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentTypeServiceTests.cs index 41064377a7..fd2c335112 100644 --- a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentTypeServiceTests.cs +++ b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/ContentTypeServiceTests.cs @@ -1971,6 +1971,65 @@ internal sealed class ContentTypeServiceTests : UmbracoIntegrationTest .Variations); } + [Test] + public void Can_Create_Property_Type_Based_On_DataTypeKey() + { + // Arrange + var cts = ContentTypeService; + var dtdYesNo = DataTypeService.GetDataType(-49); + IContentType ctBase = new ContentType(ShortStringHelper, -1) + { + Name = "Base", + Alias = "Base", + Icon = "folder.gif", + Thumbnail = "folder.png" + }; + ctBase.AddPropertyType(new PropertyType(ShortStringHelper, "ShouldNotMatter", ValueStorageType.Nvarchar) + { + Name = "Hide From Navigation", + Alias = Constants.Conventions.Content.NaviHide, + DataTypeKey = dtdYesNo.Key + }); + cts.Save(ctBase); + + // Assert + ctBase = cts.Get(ctBase.Key); + Assert.That(ctBase, Is.Not.Null); + Assert.That(ctBase.HasIdentity, Is.True); + Assert.That(ctBase.PropertyTypes.Count(), Is.EqualTo(1)); + Assert.That(ctBase.PropertyTypes.First().DataTypeId, Is.EqualTo(dtdYesNo.Id)); + Assert.That(ctBase.PropertyTypes.First().PropertyEditorAlias, Is.EqualTo(dtdYesNo.EditorAlias)); + } + + [Test] + public void Can_Create_Property_Type_Based_On_PropertyEditorAlias() + { + // Arrange + var cts = ContentTypeService; + var dtdYesNo = DataTypeService.GetDataType(-49); + IContentType ctBase = new ContentType(ShortStringHelper, -1) + { + Name = "Base", + Alias = "Base", + Icon = "folder.gif", + Thumbnail = "folder.png" + }; + ctBase.AddPropertyType(new PropertyType(ShortStringHelper, "Umbraco.TrueFalse", ValueStorageType.Nvarchar) + { + Name = "Hide From Navigation", + Alias = Constants.Conventions.Content.NaviHide, + }); + cts.Save(ctBase); + + // Assert + ctBase = cts.Get(ctBase.Key); + Assert.That(ctBase, Is.Not.Null); + Assert.That(ctBase.HasIdentity, Is.True); + Assert.That(ctBase.PropertyTypes.Count(), Is.EqualTo(1)); + Assert.That(ctBase.PropertyTypes.First().DataTypeId, Is.EqualTo(dtdYesNo.Id)); + Assert.That(ctBase.PropertyTypes.First().PropertyEditorAlias, Is.EqualTo(dtdYesNo.EditorAlias)); + } + private ContentType CreateComponent() { var component = new ContentType(ShortStringHelper, -1) From 71df46cc06ee7c50f0dc05cb769bf4ec49018adb Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Fri, 18 Jul 2025 13:48:22 +0200 Subject: [PATCH 04/23] Include /.well-known/jwks in the paths covered by OpenIddict (#19749) --- .../DependencyInjection/ProcessRequestContextHandler.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Cms.Api.Common/DependencyInjection/ProcessRequestContextHandler.cs b/src/Umbraco.Cms.Api.Common/DependencyInjection/ProcessRequestContextHandler.cs index 21776b740f..c45f80f467 100644 --- a/src/Umbraco.Cms.Api.Common/DependencyInjection/ProcessRequestContextHandler.cs +++ b/src/Umbraco.Cms.Api.Common/DependencyInjection/ProcessRequestContextHandler.cs @@ -18,7 +18,7 @@ public class ProcessRequestContextHandler var backOfficePathSegment = Constants.System.DefaultUmbracoPath.TrimStart(Constants.CharArrays.Tilde) .EnsureStartsWith('/') .EnsureEndsWith('/'); - _pathsToHandle = [backOfficePathSegment, "/.well-known/openid-configuration"]; + _pathsToHandle = [backOfficePathSegment, "/.well-known/openid-configuration", "/.well-known/jwks"]; } public ValueTask HandleAsync(OpenIddictServerEvents.ProcessRequestContext context) From 3b04d54ea39aef439a9bc78c14d69c7c8e9c0938 Mon Sep 17 00:00:00 2001 From: Lucas Bach Bisgaard Date: Fri, 18 Jul 2025 14:59:06 +0200 Subject: [PATCH 05/23] Add flag to exclude trashed media (#19746) Co-authored-by: Lucas Bach Bisgaard --- .../media/modals/media-picker/media-picker-modal.element.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts b/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts index b44135b5f7..cebd5b4738 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/media/media/modals/media-picker/media-picker-modal.element.ts @@ -210,6 +210,7 @@ export class UmbMediaPickerModalElement extends UmbModalBaseElement Date: Mon, 21 Jul 2025 10:21:21 +0700 Subject: [PATCH 06/23] V16 Added acceptance tests for the regression issue #16985 (#19712) * Updated tests for adding a thumbnail to a block grid * Added tests for adding a block thumbnail * Make tests run in the pipeline * Reverted npm command --- .../Block/BlockGridBlockAdvanced.spec.ts | 10 ++++----- .../BlockListEditor/BlockListBlocks.spec.ts | 21 +++++++++++++++++-- 2 files changed, 24 insertions(+), 7 deletions(-) diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/DataType/BlockGrid/Block/BlockGridBlockAdvanced.spec.ts b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/DataType/BlockGrid/Block/BlockGridBlockAdvanced.spec.ts index a678fe9d99..d05b35237c 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/DataType/BlockGrid/Block/BlockGridBlockAdvanced.spec.ts +++ b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/DataType/BlockGrid/Block/BlockGridBlockAdvanced.spec.ts @@ -240,27 +240,27 @@ test('can remove a icon color from a block', async ({umbracoApi, umbracoUi}) => expect(await umbracoApi.dataType.doesBlockEditorBlockContainIconColor(blockGridEditorName, contentElementTypeId, '')).toBeTruthy(); }); -// TODO: Remove skip when the code is updated due to UI changes -test.skip('can add a thumbnail to a block', async ({umbracoApi, umbracoUi}) => { +test('can add a thumbnail to a block', {tag: '@smoke'}, async ({umbracoApi, umbracoUi}) => { // Arrange const mediaName = 'TestMedia'; await umbracoApi.media.ensureNameNotExists(mediaName); - await umbracoApi.media.createDefaultMediaWithImage(mediaName); + const mediaId = await umbracoApi.media.createDefaultMediaWithImage(mediaName); const textStringData = await umbracoApi.dataType.getByName(dataTypeName); const contentElementTypeId = await umbracoApi.documentType.createDefaultElementType(elementTypeName, groupName, dataTypeName, textStringData.id); await umbracoApi.dataType.createBlockGridWithABlock(blockGridEditorName, contentElementTypeId); - const mediaUrl = await umbracoApi.media.getMediaPathByName(mediaName); + const mediaUrl = await umbracoApi.media.getMediaUrl(mediaId); // Act await umbracoUi.dataType.goToDataType(blockGridEditorName); await umbracoUi.dataType.goToBlockWithName(elementTypeName); await umbracoUi.dataType.goToBlockAdvancedTab(); - await umbracoUi.dataType.chooseBlockThumbnailWithPath(mediaUrl.fileName, mediaUrl.mediaPath); + await umbracoUi.dataType.chooseBlockThumbnailWithPath(mediaUrl); await umbracoUi.dataType.clickSubmitButton(); await umbracoUi.dataType.clickSaveButton(); // Assert await umbracoUi.dataType.isSuccessStateVisibleForSaveButton(); + await umbracoUi.dataType.doesBlockHaveThumbnailImage(mediaUrl); }); // TODO: Remove skip when the code is updated. Currently it is missing the assertion steps diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/DataType/BlockListEditor/BlockListBlocks.spec.ts b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/DataType/BlockListEditor/BlockListBlocks.spec.ts index 01c75a1e14..e2f5be0f5e 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/DataType/BlockListEditor/BlockListBlocks.spec.ts +++ b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/DataType/BlockListEditor/BlockListBlocks.spec.ts @@ -414,9 +414,26 @@ test('can disable hide content editor in a block', async ({umbracoApi, umbracoUi expect(blockData.values[0].value[0].forceHideContentEditorInOverlay).toEqual(false); }); -// TODO: Thumbnails are not showing in the UI -test.skip('can add a thumbnail to a block ', {tag: '@smoke'}, async ({umbracoApi, umbracoUi}) => { +test('can add a thumbnail to a block', {tag: '@release'}, async ({umbracoApi, umbracoUi}) => { + // Arrange + const mediaName = 'TestMedia'; + await umbracoApi.media.ensureNameNotExists(mediaName); + const mediaId = await umbracoApi.media.createDefaultMediaWithImage(mediaName); + const textStringData = await umbracoApi.dataType.getByName(dataTypeName); + const contentElementTypeId = await umbracoApi.documentType.createDefaultElementType(elementTypeName, groupName, dataTypeName, textStringData.id); + await umbracoApi.dataType.createBlockListDataTypeWithABlock(blockListEditorName, contentElementTypeId); + const mediaUrl = await umbracoApi.media.getMediaUrl(mediaId); + // Act + await umbracoUi.dataType.goToDataType(blockListEditorName); + await umbracoUi.dataType.goToBlockWithName(elementTypeName); + await umbracoUi.dataType.chooseBlockThumbnailWithPath(mediaUrl); + await umbracoUi.dataType.clickSubmitButton(); + await umbracoUi.dataType.clickSaveButton(); + + // Assert + await umbracoUi.dataType.isSuccessStateVisibleForSaveButton(); + await umbracoUi.dataType.doesBlockHaveThumbnailImage(mediaUrl); }); // TODO: Thumbnails are not showing in the UI From d31b88b94affc0f5d2d1362c5c9ac5db04ba5223 Mon Sep 17 00:00:00 2001 From: Nhu Dinh <150406148+nhudinh0309@users.noreply.github.com> Date: Mon, 21 Jul 2025 10:23:44 +0700 Subject: [PATCH 07/23] V16 Added acceptance tests for the regression issue #19529 (#19713) * Added tests for regression issue that cannot create a variant document blueprint * Make tests run in the pipeline * Reverted npm command --- .../DocumentBlueprint.spec.ts | 41 ++++++++++++++++--- 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Settings/DocumentBlueprint/DocumentBlueprint.spec.ts b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Settings/DocumentBlueprint/DocumentBlueprint.spec.ts index 56663d32fe..c387a03496 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Settings/DocumentBlueprint/DocumentBlueprint.spec.ts +++ b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Settings/DocumentBlueprint/DocumentBlueprint.spec.ts @@ -3,13 +3,10 @@ import {expect} from "@playwright/test"; const documentBlueprintName = 'TestDocumentBlueprints'; const documentTypeName = 'DocumentTypeForBlueprint'; -let documentTypeId = ''; -test.beforeEach(async ({umbracoApi, umbracoUi}) => { +test.beforeEach(async ({umbracoApi}) => { await umbracoApi.documentBlueprint.ensureNameNotExists(documentBlueprintName); await umbracoApi.documentType.ensureNameNotExists(documentTypeName); - documentTypeId = await umbracoApi.documentType.createDefaultDocumentType(documentTypeName); - await umbracoUi.goToBackOffice(); }); test.afterEach(async ({umbracoApi}) => { @@ -19,6 +16,8 @@ test.afterEach(async ({umbracoApi}) => { test('can create a document blueprint from the settings menu', {tag: '@smoke'}, async ({umbracoApi, umbracoUi}) => { // Arrange + await umbracoApi.documentType.createDefaultDocumentType(documentTypeName); + await umbracoUi.goToBackOffice(); await umbracoUi.documentBlueprint.goToSection(ConstantHelper.sections.settings); // Act @@ -29,17 +28,19 @@ test('can create a document blueprint from the settings menu', {tag: '@smoke'}, await umbracoUi.documentBlueprint.clickSaveButton(); // Assert - await umbracoUi.documentBlueprint.waitForDocumentBlueprintToBeCreated() + await umbracoUi.documentBlueprint.waitForDocumentBlueprintToBeCreated(); expect(await umbracoApi.documentBlueprint.doesNameExist(documentBlueprintName)).toBeTruthy(); await umbracoUi.documentBlueprint.isDocumentBlueprintRootTreeItemVisible(documentBlueprintName, true); }); test('can rename a document blueprint', async ({umbracoApi, umbracoUi}) => { // Arrange + const documentTypeId = await umbracoApi.documentType.createDefaultDocumentType(documentTypeName); const wrongDocumentBlueprintName = 'Wrong Document Blueprint'; await umbracoApi.documentBlueprint.ensureNameNotExists(wrongDocumentBlueprintName); await umbracoApi.documentBlueprint.createDefaultDocumentBlueprint(wrongDocumentBlueprintName, documentTypeId); expect(await umbracoApi.documentBlueprint.doesNameExist(wrongDocumentBlueprintName)).toBeTruthy(); + await umbracoUi.goToBackOffice(); await umbracoUi.documentBlueprint.goToSection(ConstantHelper.sections.settings); // Act @@ -57,8 +58,10 @@ test('can rename a document blueprint', async ({umbracoApi, umbracoUi}) => { test('can delete a document blueprint', async ({umbracoApi, umbracoUi}) => { // Arrange + const documentTypeId = await umbracoApi.documentType.createDefaultDocumentType(documentTypeName); await umbracoApi.documentBlueprint.createDefaultDocumentBlueprint(documentBlueprintName, documentTypeId); expect(await umbracoApi.documentBlueprint.doesNameExist(documentBlueprintName)).toBeTruthy(); + await umbracoUi.goToBackOffice(); await umbracoUi.documentBlueprint.goToSection(ConstantHelper.sections.settings); // Act @@ -75,9 +78,9 @@ test('can delete a document blueprint', async ({umbracoApi, umbracoUi}) => { test('can create a document blueprint from the content menu', async ({umbracoApi, umbracoUi}) => { // Arrange - const documentTypeName = 'DocumentTypeForContent'; const documentTypeId = await umbracoApi.documentType.createDefaultDocumentTypeWithAllowAsRoot(documentTypeName); await umbracoApi.document.createDefaultDocument(documentBlueprintName, documentTypeId); + await umbracoUi.goToBackOffice(); await umbracoUi.content.goToSection(ConstantHelper.sections.content); // Act @@ -94,3 +97,29 @@ test('can create a document blueprint from the content menu', async ({umbracoApi // Clean await umbracoApi.documentType.ensureNameNotExists(documentTypeName); }); + +test('can create a variant document blueprint', {tag: '@release'}, async ({umbracoApi, umbracoUi}) => { + // Arrange + await umbracoApi.language.createDanishLanguage(); + await umbracoApi.documentType.createDocumentTypeWithAllowVaryByCulture(documentTypeName); + await umbracoUi.goToBackOffice(); + await umbracoUi.documentBlueprint.goToSection(ConstantHelper.sections.settings); + + // Act + await umbracoUi.documentBlueprint.clickActionsMenuAtRoot(); + await umbracoUi.documentBlueprint.clickCreateActionMenuOption(); + await umbracoUi.documentBlueprint.clickTextButtonWithName(documentTypeName); + await umbracoUi.documentBlueprint.enterDocumentBlueprintName(documentBlueprintName); + await umbracoUi.documentBlueprint.clickSaveButton(); + + // Assert + await umbracoUi.documentBlueprint.waitForDocumentBlueprintToBeCreated(); + expect(await umbracoApi.documentBlueprint.doesNameExist(documentBlueprintName)).toBeTruthy(); + await umbracoUi.documentBlueprint.isDocumentBlueprintRootTreeItemVisible(documentBlueprintName, true); + await umbracoUi.documentBlueprint.page.on('console', message => { + expect(message.type()).not.toBe('error'); + }); + + // Clean + await umbracoApi.language.ensureIsoCodeNotExists('da'); +}); From 6d240b6a07814acd534d39985de3ca5c297eb533 Mon Sep 17 00:00:00 2001 From: Nhu Dinh <150406148+nhudinh0309@users.noreply.github.com> Date: Mon, 21 Jul 2025 10:33:30 +0700 Subject: [PATCH 08/23] V16 QA Added acceptance tests for creating a document using blueprint (#19708) * Added tests for creating content using document blueprint * Updated tests due to api helper for document blueprint changes * Bumped version * Make all Blueprint tests runs in the pipeline * Reverted npm command --- .../package-lock.json | 19 +- .../Umbraco.Tests.AcceptanceTest/package.json | 4 +- ...CreateContentFromDocumentBlueprint.spec.ts | 200 ++++++++++++++++++ 3 files changed, 211 insertions(+), 12 deletions(-) create mode 100644 tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Content/CreateContentFromDocumentBlueprint.spec.ts diff --git a/tests/Umbraco.Tests.AcceptanceTest/package-lock.json b/tests/Umbraco.Tests.AcceptanceTest/package-lock.json index 9c0cd687ff..84c12dec98 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/package-lock.json +++ b/tests/Umbraco.Tests.AcceptanceTest/package-lock.json @@ -7,8 +7,8 @@ "name": "acceptancetest", "hasInstallScript": true, "dependencies": { - "@umbraco/json-models-builders": "^2.0.36", - "@umbraco/playwright-testhelpers": "^16.0.27", + "@umbraco/json-models-builders": "^2.0.37", + "@umbraco/playwright-testhelpers": "^16.0.28", "camelize": "^1.0.0", "dotenv": "^16.3.1", "node-fetch": "^2.6.7" @@ -58,20 +58,19 @@ } }, "node_modules/@umbraco/json-models-builders": { - "version": "2.0.36", - "resolved": "https://registry.npmjs.org/@umbraco/json-models-builders/-/json-models-builders-2.0.36.tgz", - "integrity": "sha512-vQLL/y2ZIqrhCBe61W6YuA/C3KjGkva90WA09YfQuPL9HujOkJpVaP7KjJ0F8bBxwURy9tzMBFBLUz5fOdbkxQ==", + "version": "2.0.37", + "resolved": "https://registry.npmjs.org/@umbraco/json-models-builders/-/json-models-builders-2.0.37.tgz", + "integrity": "sha512-97cRUrD+oeEno9I+qFjq7lWVS0+aDEK44lQQYWmVPAkCuAG1HMpBTEblS45CflrmLtgrDuZx68WIVVGpk9JzgQ==", "dependencies": { "camelize": "^1.0.1" } }, "node_modules/@umbraco/playwright-testhelpers": { - "version": "16.0.27", - "resolved": "https://registry.npmjs.org/@umbraco/playwright-testhelpers/-/playwright-testhelpers-16.0.27.tgz", - "integrity": "sha512-KxjIpfFsiK5b1Au8QrlWceK88eo53VxogLs0LMrxsRS3rt4rdmD1YRP6U+yIucdPKnhVgfIsh40J/taGAZyPFQ==", - "license": "MIT", + "version": "16.0.28", + "resolved": "https://registry.npmjs.org/@umbraco/playwright-testhelpers/-/playwright-testhelpers-16.0.28.tgz", + "integrity": "sha512-l0RDfiXjQAtN2ykg7IX6ZSSW8GGLBm9RFO8WjsnRKAh7gZkH8+0DJdhx573m5bfZE6xa33TgyzIg9x+m/42/Lw==", "dependencies": { - "@umbraco/json-models-builders": "2.0.36", + "@umbraco/json-models-builders": "2.0.37", "node-fetch": "^2.6.7" } }, diff --git a/tests/Umbraco.Tests.AcceptanceTest/package.json b/tests/Umbraco.Tests.AcceptanceTest/package.json index b2e9ac7ada..f150d12952 100644 --- a/tests/Umbraco.Tests.AcceptanceTest/package.json +++ b/tests/Umbraco.Tests.AcceptanceTest/package.json @@ -20,8 +20,8 @@ "typescript": "^4.8.3" }, "dependencies": { - "@umbraco/json-models-builders": "^2.0.36", - "@umbraco/playwright-testhelpers": "^16.0.27", + "@umbraco/json-models-builders": "^2.0.37", + "@umbraco/playwright-testhelpers": "^16.0.28", "camelize": "^1.0.0", "dotenv": "^16.3.1", "node-fetch": "^2.6.7" diff --git a/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Content/CreateContentFromDocumentBlueprint.spec.ts b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Content/CreateContentFromDocumentBlueprint.spec.ts new file mode 100644 index 0000000000..7ec3a9223f --- /dev/null +++ b/tests/Umbraco.Tests.AcceptanceTest/tests/DefaultConfig/Content/CreateContentFromDocumentBlueprint.spec.ts @@ -0,0 +1,200 @@ +import {AliasHelper, ConstantHelper, test} from '@umbraco/playwright-testhelpers'; +import {expect} from "@playwright/test"; + +// Content +const contentName = 'TestContentFromBlueprint'; +const textContent = 'This is a block in document blueprint'; + +// Document Type +const documentTypeName = 'TestDocumentTypeForContent'; +const groupName = 'TestGroup'; + +// Document Blueprint +const documentBlueprintName = 'TestDocumentBlueprint'; +const documentBlueprintDanishName = 'TestDocumentBlueprint-DA'; + +// ElementType +const elementGroupName = 'ElementGroup'; +const elementTypeName = 'TestElement'; +const richTextDataTypeUiAlias = 'Richtext editor'; +const elementDataTypeUiAlias = 'Umbraco.RichText'; +const elementPropertyName = 'TipTapProperty' + +// DataType +const blockDataTypeName = 'TestBlockEditor'; + +test.beforeEach(async ({umbracoApi}) => { + await umbracoApi.documentType.ensureNameNotExists(documentTypeName); + await umbracoApi.document.ensureNameNotExists(contentName); + await umbracoApi.documentBlueprint.ensureNameNotExists(documentBlueprintName); +}); + +test.afterEach(async ({umbracoApi}) => { + await umbracoApi.documentType.ensureNameNotExists(documentTypeName); + await umbracoApi.document.ensureNameNotExists(contentName); + await umbracoApi.document.ensureNameNotExists(documentBlueprintName); + await umbracoApi.documentBlueprint.ensureNameNotExists(documentBlueprintName); + await umbracoApi.documentType.ensureNameNotExists(elementTypeName); + await umbracoApi.dataType.ensureNameNotExists(blockDataTypeName); +}); + +test('can create content using an invariant document blueprint', async ({umbracoApi, umbracoUi}) => { + // Arrange + const dataTypeName = 'Textstring'; + const dataTypeData = await umbracoApi.dataType.getByName(dataTypeName); + const documentTypeId = await umbracoApi.documentType.createDocumentTypeWithPropertyEditor(documentTypeName, dataTypeName, dataTypeData.id); + await umbracoApi.documentBlueprint.createDocumentBlueprintWithTextBoxValue(documentBlueprintName, documentTypeId, dataTypeName, textContent); + await umbracoUi.goToBackOffice(); + await umbracoUi.content.goToSection(ConstantHelper.sections.content); + + // Act + await umbracoUi.content.clickActionsMenuAtRoot(); + await umbracoUi.content.clickCreateActionMenuOption(); + await umbracoUi.content.chooseDocumentType(documentTypeName); + await umbracoUi.content.clickModalMenuItemWithName(documentBlueprintName); + await umbracoUi.content.clickSaveButtonForContent(); + + // Assert + await umbracoUi.content.waitForContentToBeCreated(); + expect(await umbracoApi.document.doesNameExist(documentBlueprintName)).toBeTruthy(); + const contentData = await umbracoApi.document.getByName(documentBlueprintName); + expect(contentData.values[0].value).toBe(textContent); +}); + +test('can create content using a variant document blueprint', async ({umbracoApi, umbracoUi}) => { + // Arrange + const dataTypeName = 'Textstring'; + await umbracoApi.language.createDanishLanguage(); + const dataTypeData = await umbracoApi.dataType.getByName(dataTypeName); + const documentTypeId = await umbracoApi.documentType.createVariantDocumentTypeWithInvariantPropertyEditor(documentTypeName, dataTypeName, dataTypeData.id); + await umbracoApi.documentBlueprint.createDocumenBlueprintWithEnglishCultureAndDanishCultureAndTextBoxValue(documentBlueprintName, documentBlueprintDanishName, documentTypeId, dataTypeName, textContent); + await umbracoUi.goToBackOffice(); + await umbracoUi.content.goToSection(ConstantHelper.sections.content); + + // Act + await umbracoUi.content.clickActionsMenuAtRoot(); + await umbracoUi.content.clickCreateActionMenuOption(); + await umbracoUi.content.chooseDocumentType(documentTypeName); + await umbracoUi.content.clickModalMenuItemWithName(documentBlueprintName); + await umbracoUi.content.clickSaveButtonForContent(); + await umbracoUi.content.clickSaveButton(); + + // Assert + await umbracoUi.content.waitForContentToBeCreated(); + expect(await umbracoApi.document.doesNameExist(documentBlueprintName)).toBeTruthy(); + const contentData = await umbracoApi.document.getByName(documentBlueprintName); + expect(contentData.values[0].value).toBe(textContent); + expect(contentData.variants[0].name).toBe(documentBlueprintName); + expect(contentData.variants[1].name).toBe(documentBlueprintDanishName); + + // Clean + await umbracoApi.language.ensureNameNotExists('Danish'); +}); + +test('can create content with different name using an invariant document blueprint', async ({umbracoApi, umbracoUi}) => { + // Arrange + const dataTypeName = 'Textstring'; + const dataTypeData = await umbracoApi.dataType.getByName(dataTypeName); + const documentTypeId = await umbracoApi.documentType.createDocumentTypeWithPropertyEditor(documentTypeName, dataTypeName, dataTypeData.id); + await umbracoApi.documentBlueprint.createDocumentBlueprintWithTextBoxValue(documentBlueprintName, documentTypeId, dataTypeName, textContent); + await umbracoUi.goToBackOffice(); + await umbracoUi.content.goToSection(ConstantHelper.sections.content); + + // Act + await umbracoUi.content.clickActionsMenuAtRoot(); + await umbracoUi.content.clickCreateActionMenuOption(); + await umbracoUi.content.chooseDocumentType(documentTypeName); + await umbracoUi.content.clickModalMenuItemWithName(documentBlueprintName); + await umbracoUi.content.enterContentName(contentName); + await umbracoUi.content.clickSaveButtonForContent(); + + // Assert + await umbracoUi.content.waitForContentToBeCreated(); + expect(await umbracoApi.document.doesNameExist(documentBlueprintName)).toBeFalsy(); + expect(await umbracoApi.document.doesNameExist(contentName)).toBeTruthy(); + const contentData = await umbracoApi.document.getByName(contentName); + expect(contentData.values[0].value).toBe(textContent); +}); + +test('can create content with different name using a variant document blueprint', async ({umbracoApi, umbracoUi}) => { + // Arrange + const dataTypeName = 'Textstring'; + await umbracoApi.language.createDanishLanguage(); + const dataTypeData = await umbracoApi.dataType.getByName(dataTypeName); + const documentTypeId = await umbracoApi.documentType.createVariantDocumentTypeWithInvariantPropertyEditor(documentTypeName, dataTypeName, dataTypeData.id); + await umbracoApi.documentBlueprint.createDocumenBlueprintWithEnglishCultureAndDanishCultureAndTextBoxValue(documentBlueprintName, documentBlueprintDanishName, documentTypeId, dataTypeName, textContent); + await umbracoUi.goToBackOffice(); + await umbracoUi.content.goToSection(ConstantHelper.sections.content); + + // Act + await umbracoUi.content.clickActionsMenuAtRoot(); + await umbracoUi.content.clickCreateActionMenuOption(); + await umbracoUi.content.chooseDocumentType(documentTypeName); + await umbracoUi.content.clickModalMenuItemWithName(documentBlueprintName); + await umbracoUi.content.enterContentName(contentName); + await umbracoUi.content.clickSaveButtonForContent(); + await umbracoUi.content.clickSaveButton(); + + // Assert + await umbracoUi.content.waitForContentToBeCreated(); + expect(await umbracoApi.document.doesNameExist(contentName)).toBeTruthy(); + const contentData = await umbracoApi.document.getByName(contentName); + expect(contentData.values[0].value).toBe(textContent); + expect(contentData.variants[0].name).toBe(contentName); + expect(contentData.variants[1].name).toBe(documentBlueprintDanishName); + + // Clean + await umbracoApi.language.ensureNameNotExists('Danish'); +}); + +test('can create content using a document blueprint with block list', async ({umbracoApi, umbracoUi}) => { + // Arrange + await umbracoApi.dataType.ensureNameNotExists(blockDataTypeName); + const tipTapDataType = await umbracoApi.dataType.getByName(richTextDataTypeUiAlias); + const tipTapDataTypeId = tipTapDataType.id; + const elementTypeId = await umbracoApi.documentType.createDefaultElementType(elementTypeName, elementGroupName, elementPropertyName, tipTapDataTypeId); + await umbracoApi.documentBlueprint.createDefaultDocumentBlueprintWithABlockListEditorAndBlockWithValue(documentBlueprintName, documentTypeName, blockDataTypeName, elementTypeId, AliasHelper.toAlias(elementPropertyName), elementDataTypeUiAlias, textContent, groupName); + await umbracoUi.goToBackOffice(); + await umbracoUi.content.goToSection(ConstantHelper.sections.content); + + // Act + await umbracoUi.content.clickActionsMenuAtRoot(); + await umbracoUi.content.clickCreateActionMenuOption(); + await umbracoUi.content.chooseDocumentType(documentTypeName); + await umbracoUi.content.clickModalMenuItemWithName(documentBlueprintName); + await umbracoUi.content.clickSaveButtonForContent(); + + // Assert + await umbracoUi.content.waitForContentToBeCreated(); + expect(await umbracoApi.document.doesNameExist(documentBlueprintName)).toBeTruthy(); + const contentData = await umbracoApi.document.getByName(documentBlueprintName); + expect(contentData.values[0].value.contentData[0].values[0].value.markup).toEqual(textContent); + const blockListValue = contentData.values.find(item => item.editorAlias === "Umbraco.BlockList")?.value; + expect(blockListValue).toBeTruthy(); +}); + +test('can create content using a document blueprint with block grid', async ({umbracoApi, umbracoUi}) => { + // Arrange + await umbracoApi.dataType.ensureNameNotExists(blockDataTypeName); + const tipTapDataType = await umbracoApi.dataType.getByName(richTextDataTypeUiAlias); + const tipTapDataTypeId = tipTapDataType.id; + const elementTypeId = await umbracoApi.documentType.createDefaultElementType(elementTypeName, elementGroupName, elementPropertyName, tipTapDataTypeId); + await umbracoApi.documentBlueprint.createDefaultDocumentBlueprintWithABlockGridEditorAndBlockWithValue(documentBlueprintName, documentTypeName, blockDataTypeName, elementTypeId, AliasHelper.toAlias(elementPropertyName), richTextDataTypeUiAlias, textContent); + await umbracoUi.goToBackOffice(); + await umbracoUi.content.goToSection(ConstantHelper.sections.content); + + // Act + await umbracoUi.content.clickActionsMenuAtRoot(); + await umbracoUi.content.clickCreateActionMenuOption(); + await umbracoUi.content.chooseDocumentType(documentTypeName); + await umbracoUi.content.clickModalMenuItemWithName(documentBlueprintName); + await umbracoUi.content.clickSaveButtonForContent(); + + // Assert + await umbracoUi.content.waitForContentToBeCreated(); + expect(await umbracoApi.document.doesNameExist(documentBlueprintName)).toBeTruthy(); + const contentData = await umbracoApi.document.getByName(documentBlueprintName); + expect(contentData.values[0].value.contentData[0].values[0].value.markup).toEqual(textContent); + const blockListValue = contentData.values.find(item => item.editorAlias === "Umbraco.BlockGrid")?.value; + expect(blockListValue).toBeTruthy(); +}); \ No newline at end of file From 0bcc26a8115a4b2b42b6186a8d2aa6be044e635a Mon Sep 17 00:00:00 2001 From: Laura Neto <12862535+lauraneto@users.noreply.github.com> Date: Mon, 21 Jul 2025 07:55:12 +0200 Subject: [PATCH 09/23] Allow saving blueprints with validation errors (#19748) Ignore validation result when saving blueprint --- .../workspace/document-blueprint-workspace-editor.element.ts | 5 +++++ .../workspace/document-blueprint-workspace.context.ts | 1 + 2 files changed, 6 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/document-blueprints/workspace/document-blueprint-workspace-editor.element.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/document-blueprints/workspace/document-blueprint-workspace-editor.element.ts index 936b481bb5..875b5b00d2 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/document-blueprints/workspace/document-blueprint-workspace-editor.element.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/document-blueprints/workspace/document-blueprint-workspace-editor.element.ts @@ -131,6 +131,11 @@ export class UmbDocumentBlueprintWorkspaceEditorElement extends UmbLitElement { display: block; width: 100%; height: 100%; + + --uui-color-invalid: var(--uui-color-warning); + --uui-color-invalid-emphasis: var(--uui-color-warning-emphasis); + --uui-color-invalid-standalone: var(--uui-color-warning-standalone); + --uui-color-invalid-contrast: var(--uui-color-warning-contrast); } `, ]; diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/document-blueprints/workspace/document-blueprint-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/document-blueprints/workspace/document-blueprint-workspace.context.ts index ab33e43fa5..04948583f7 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/document-blueprints/workspace/document-blueprint-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/document-blueprints/workspace/document-blueprint-workspace.context.ts @@ -45,6 +45,7 @@ export class UmbDocumentBlueprintWorkspaceContext contentTypeDetailRepository: UmbDocumentTypeDetailRepository, contentVariantScaffold: UMB_DOCUMENT_DETAIL_MODEL_VARIANT_SCAFFOLD, contentTypePropertyName: 'documentType', + ignoreValidationResultOnSubmit: true, }); this.observe( From 7f88013689476dd3b12a68d277820156635fee01 Mon Sep 17 00:00:00 2001 From: Henrik Date: Mon, 21 Jul 2025 08:32:54 +0200 Subject: [PATCH 10/23] Make internal & private classes sealed where possible, to avoid code for virtual dispatch (#19719) --- .../Configuration/ConfigureOpenIddict.cs | 2 +- .../Json/NamedSystemTextJsonInputFormatter.cs | 2 +- .../Json/NamedSystemTextJsonOutputFormatter.cs | 3 +-- ...erAuthenticationDeliveryApiSwaggerGenOptions.cs | 2 +- .../ContextualizeFromAcceptHeadersAttribute.cs | 2 +- .../Filters/DeliveryApiAccessAttribute.cs | 2 +- .../Filters/DeliveryApiMediaAccessAttribute.cs | 2 +- .../Filters/ValidateStartItemAttribute.cs | 2 +- .../RequestContextOutputExpansionStrategyV2.cs | 2 +- .../BackOfficeAuthBuilderExtensions.cs | 2 +- .../Factories/PackagePresentationFactory.cs | 2 +- .../Factories/WebhookPresentationFactory.cs | 2 +- .../Filters/AppendEventMessagesAttribute.cs | 2 +- ...erPasswordEnsureMinimumResponseTimeAttribute.cs | 4 ++-- .../Mapping/SectionMapper.cs | 2 +- ...ackOfficeSecurityRequirementsOperationFilter.cs | 2 +- .../OpenApi/NotificationHeaderFilter.cs | 2 +- .../OpenApi/ReponseHeaderOperationFilter.cs | 4 ++-- .../Security/BackOfficeAuthenticationBuilder.cs | 2 +- .../Security/BackOfficeSecureDataFormat.cs | 2 +- .../NoopMemberPartialViewCacheInvalidator.cs | 2 +- src/Umbraco.Core/Composing/ComposerGraph.cs | 4 ++-- .../Composing/FindAssembliesWithReferencesTo.cs | 2 +- src/Umbraco.Core/Composing/TypeLoader.cs | 2 +- .../Configuration/EntryAssemblyMetadata.cs | 2 +- .../Configuration/Models/ContentErrorPage.cs | 2 +- src/Umbraco.Core/Diagnostics/NoopMarchal.cs | 2 +- .../Dictionary/UmbracoCultureDictionary.cs | 2 +- src/Umbraco.Core/EnvironmentHelper.cs | 2 +- .../Events/EventAggregator.Notifications.cs | 8 ++++---- src/Umbraco.Core/Events/EventNameExtractor.cs | 2 +- .../Events/PassThroughEventDispatcher.cs | 2 +- .../Events/QueuingEventDispatcherBase.cs | 2 +- .../Events/ScopedNotificationPublisher.cs | 4 ++-- ...DocumentTypeElementSwitchNotificationHandler.cs | 2 +- .../Hosting/NoopApplicationShutdownRegistry.cs | 2 +- src/Umbraco.Core/IO/ShadowFileSystem.cs | 6 +++--- src/Umbraco.Core/IO/ShadowFileSystems.cs | 2 +- src/Umbraco.Core/IO/ShadowWrapper.cs | 2 +- src/Umbraco.Core/Logging/LogProfiler.cs | 2 +- src/Umbraco.Core/Logging/NoopProfiler.cs | 2 +- src/Umbraco.Core/Mail/NotImplementedEmailSender.cs | 2 +- src/Umbraco.Core/Mail/NotImplementedSmsSender.cs | 2 +- src/Umbraco.Core/Models/DefaultPayloadModel.cs | 2 +- src/Umbraco.Core/Models/Membership/User.cs | 2 +- .../Models/PublishedContent/ModelType.cs | 2 +- .../PublishedContentTypeConverter.cs | 2 +- .../PublishedContent/PublishedModelFactory.cs | 2 +- .../Repositories/UpgradeCheckRepository.cs | 2 +- .../ContentPickerConfigurationEditor.cs | 2 +- .../PropertyEditors/ContentPickerPropertyEditor.cs | 2 +- .../PropertyEditors/DateValueEditor.cs | 2 +- .../PropertyEditors/DecimalPropertyEditor.cs | 8 ++++---- .../PropertyEditors/IntegerPropertyEditor.cs | 6 +++--- .../PropertyEditors/LabelPropertyEditor.cs | 2 +- .../PropertyEditors/MarkDownPropertyValueEditor.cs | 3 +-- .../MemberGroupPickerPropertyEditor.cs | 2 +- .../PropertyEditors/MemberPickerPropertyEditor.cs | 2 +- .../PropertyEditors/TextOnlyValueEditor.cs | 2 +- .../PropertyEditors/UserPickerPropertyEditor.cs | 2 +- .../Validation/JsonPathValidationError.cs | 2 +- .../Validation/JsonPathValidator.cs | 2 +- .../PublishedCache/PublishedElementPropertyBase.cs | 2 +- .../DictionaryPermissionAuthorizer.cs | 2 +- src/Umbraco.Core/Services/ConsentService.cs | 2 +- src/Umbraco.Core/Services/ContentVersionService.cs | 2 +- src/Umbraco.Core/Services/DocumentUrlService.cs | 6 +++--- src/Umbraco.Core/Services/EntityXmlSerializer.cs | 2 +- .../FileSystem/PartialViewFolderService.cs | 2 +- .../Services/FileSystem/ScriptFolderService.cs | 2 +- .../Services/FileSystem/StylesheetFolderService.cs | 2 +- src/Umbraco.Core/Services/IdKeyMap.cs | 2 +- src/Umbraco.Core/Services/KeyValueService.cs | 2 +- src/Umbraco.Core/Services/MemberGroupService.cs | 2 +- .../Services/MemberTwoFactorLoginService.cs | 2 +- src/Umbraco.Core/Services/NotificationService.cs | 2 +- src/Umbraco.Core/Services/RedirectUrlService.cs | 2 +- .../Services/UserTwoFactorLoginService.cs | 2 +- src/Umbraco.Core/Strings/Diff.cs | 2 +- src/Umbraco.Core/SystemLock.cs | 4 ++-- .../Telemetry/SiteIdentifierService.cs | 2 +- src/Umbraco.Core/Telemetry/TelemetryService.cs | 2 +- src/Umbraco.Core/UdiTypeConverter.cs | 2 +- src/Umbraco.Core/Xml/XmlNodeListFactory.cs | 4 ++-- .../RecurringBackgroundJobHostedServiceRunner.cs | 2 +- .../Cache/FullDataSetRepositoryCachePolicy.cs | 2 +- .../Cache/SingleItemsOnlyRepositoryCachePolicy.cs | 2 +- .../Configuration/JsonConfigManipulator.cs | 2 +- .../DeliveryApiContentIndexHandleContentChanges.cs | 2 +- .../Examine/DeferredActions.cs | 2 +- .../Examine/ExamineIndexingMainDomHandler.cs | 2 +- .../Examine/ExamineUmbracoIndexingHandler.cs | 12 ++++++------ .../Enrichers/Log4NetLevelMapperEnricher.cs | 2 +- .../Logging/Viewer/CountingFilter.cs | 2 +- .../Logging/Viewer/ErrorCounterFilter.cs | 2 +- .../Logging/Viewer/ExpressionFilter.cs | 4 ++-- .../Logging/Viewer/MessageTemplateFilter.cs | 2 +- .../Logging/Viewer/SerilogJsonLogViewer.cs | 4 ++-- .../Migrations/Install/DatabaseDataCreator.cs | 2 +- .../Migrations/MigrationContext.cs | 3 +-- .../DatabaseSchemaCreatedNotification.cs | 2 +- .../DatabaseSchemaCreatingNotification.cs | 2 +- .../Packaging/ImportPackageBuilder.cs | 2 +- .../Packaging/ImportPackageBuilderExpression.cs | 2 +- .../DatabaseModelDefinitions/DbIndexDefinition.cs | 2 +- .../Persistence/Dtos/AccessDto.cs | 2 +- .../Persistence/Dtos/AccessRuleDto.cs | 2 +- .../Persistence/Dtos/AuditEntryDto.cs | 2 +- .../Persistence/Dtos/AxisDefintionDto.cs | 2 +- .../Persistence/Dtos/ContentScheduleDto.cs | 2 +- .../Persistence/Dtos/ContentType2ContentTypeDto.cs | 2 +- .../Dtos/ContentTypeAllowedContentTypeDto.cs | 2 +- .../Persistence/Dtos/ContentTypeTemplateDto.cs | 2 +- .../Dtos/ContentVersionCleanupPolicyDto.cs | 2 +- .../Dtos/ContentVersionCultureVariationDto.cs | 2 +- .../Dtos/DocumentCultureVariationDto.cs | 2 +- .../Dtos/DocumentPublishedReadOnlyDto.cs | 2 +- .../Persistence/Dtos/DomainDto.cs | 2 +- .../Persistence/Dtos/ExternalLoginDto.cs | 2 +- .../Persistence/Dtos/ExternalLoginTokenDto.cs | 2 +- .../Persistence/Dtos/KeyValueDto.cs | 2 +- .../Persistence/Dtos/LanguageDto.cs | 2 +- .../Persistence/Dtos/LockDto.cs | 2 +- .../Persistence/Dtos/LogDto.cs | 2 +- .../Persistence/Dtos/LogViewerQueryDto.cs | 2 +- .../Persistence/Dtos/MediaDto.cs | 2 +- .../Persistence/Dtos/MediaVersionDto.cs | 2 +- .../Persistence/Dtos/Member2MemberGroupDto.cs | 2 +- .../Persistence/Dtos/MemberDto.cs | 2 +- .../Persistence/Dtos/MemberPropertyTypeDto.cs | 2 +- .../Persistence/Dtos/NavigationDto.cs | 2 +- .../Persistence/Dtos/PropertyDataDto.cs | 2 +- .../Persistence/Dtos/PropertyTypeCommonDto.cs | 2 +- .../Persistence/Dtos/PropertyTypeGroupDto.cs | 2 +- .../Dtos/PropertyTypeGroupReadOnlyDto.cs | 2 +- .../Persistence/Dtos/PropertyTypeReadOnlyDto.cs | 2 +- .../Persistence/Dtos/RedirectUrlDto.cs | 2 +- .../Persistence/Dtos/RelationDto.cs | 2 +- .../Persistence/Dtos/RelationTypeDto.cs | 2 +- .../Persistence/Dtos/ServerRegistrationDto.cs | 2 +- .../Persistence/Dtos/TagDto.cs | 2 +- .../Persistence/Dtos/TagRelationshipDto.cs | 2 +- .../Persistence/Dtos/TemplateDto.cs | 2 +- .../Persistence/Dtos/TwoFactorLoginDto.cs | 2 +- .../Persistence/Dtos/User2NodeNotifyDto.cs | 2 +- .../Dtos/UserGroup2GranularPermissionDto.cs | 2 +- .../Persistence/Dtos/UserGroup2NodeDto.cs | 2 +- .../Persistence/Dtos/UserLoginDto.cs | 2 +- .../Persistence/Dtos/UserNotificationDto.cs | 2 +- .../Persistence/Dtos/WebhookDto.cs | 2 +- .../Persistence/Dtos/WebhookLogDto.cs | 2 +- .../Persistence/Factories/ContentBaseFactory.cs | 2 +- .../Persistence/FaultHandling/RetryDbConnection.cs | 2 +- .../Persistence/Querying/CachedExpression.cs | 2 +- .../Querying/ModelToSqlExpressionVisitor.cs | 2 +- .../Querying/PocoToSqlExpressionVisitor.cs | 12 ++++++------ .../Repositories/Implement/AuditEntryRepository.cs | 2 +- .../Repositories/Implement/AuditRepository.cs | 2 +- .../Implement/CacheInstructionRepository.cs | 2 +- .../Repositories/Implement/ConsentRepository.cs | 2 +- .../Implement/ContentRepositoryBase.cs | 2 +- .../Implement/ContentTypeCommonRepository.cs | 4 ++-- .../Implement/ContentTypeRepository.cs | 2 +- .../Implement/ContentTypeRepositoryBase.cs | 4 ++-- .../Implement/DataTypeContainerRepository.cs | 3 +-- .../Repositories/Implement/DataTypeRepository.cs | 9 +++------ .../Repositories/Implement/DictionaryRepository.cs | 14 +++++++------- .../DocumentBlueprintContainerRepository.cs | 2 +- .../Implement/DocumentBlueprintRepository.cs | 2 +- .../Repositories/Implement/DocumentRepository.cs | 8 ++++---- .../Implement/DocumentTypeContainerRepository.cs | 2 +- .../Implement/DocumentVersionRepository.cs | 2 +- .../Repositories/Implement/DomainRepository.cs | 2 +- .../Repositories/Implement/EntityRepository.cs | 14 +++++++------- .../Implement/ExternalLoginRepository.cs | 4 ++-- .../Repositories/Implement/KeyValueRepository.cs | 2 +- .../Repositories/Implement/LanguageRepository.cs | 2 +- .../LocalFileSystemTemporaryFileRepository.cs | 2 +- .../Implement/LogViewerQueryRepository.cs | 6 +++--- .../Repositories/Implement/MediaRepository.cs | 2 +- .../Implement/MediaTypeContainerRepository.cs | 2 +- .../Repositories/Implement/MediaTypeRepository.cs | 2 +- .../Implement/MemberGroupRepository.cs | 4 ++-- .../Implement/MemberTypeContainerRepository.cs | 2 +- .../Repositories/Implement/MemberTypeRepository.cs | 2 +- .../Implement/PartialViewRepository.cs | 2 +- .../Repositories/Implement/PermissionRepository.cs | 2 +- .../Implement/PropertyTypeUsageRepository.cs | 2 +- .../Implement/PublicAccessRepository.cs | 2 +- .../Implement/RedirectUrlRepository.cs | 2 +- .../Repositories/Implement/RelationRepository.cs | 8 ++++---- .../Repositories/Implement/ScriptRepository.cs | 2 +- .../Implement/ServerRegistrationRepository.cs | 2 +- .../Repositories/Implement/SimilarNodeName.cs | 4 ++-- .../Repositories/Implement/StylesheetRepository.cs | 2 +- .../Repositories/Implement/TagRepository.cs | 10 +++++----- .../Repositories/Implement/TemplateRepository.cs | 11 ++++------- .../Implement/TrackedReferencesRepository.cs | 4 ++-- .../Implement/TwoFactorLoginRepository.cs | 2 +- .../Repositories/Implement/UserDataRepository.cs | 10 +++++----- .../Repositories/Implement/UserGroupRepository.cs | 4 ++-- .../Repositories/Implement/UserRepository.cs | 10 ++-------- .../Persistence/SqlSyntax/DbTypesFactory.cs | 2 +- .../Persistence/UmbracoPocoDataBuilder.cs | 2 +- .../BlockGridConfigurationEditor.cs | 2 +- .../PropertyEditors/BlockGridPropertyEditorBase.cs | 4 ++-- .../BlockListConfigurationEditor.cs | 2 +- .../PropertyEditors/BlockListPropertyEditorBase.cs | 4 ++-- .../BlockValuePropertyIndexValueFactory.cs | 4 ++-- .../ColorPickerConfigurationEditor.cs | 4 ++-- .../PropertyEditors/ColorPickerPropertyEditor.cs | 4 ++-- .../DropDownFlexibleConfigurationEditor.cs | 2 +- .../FileUploadPropertyValueEditor.cs | 6 +++--- .../ImageCropperConfigurationEditor.cs | 2 +- .../PropertyEditors/ImageCropperPropertyEditor.cs | 2 +- .../ImageCropperPropertyValueEditor.cs | 2 +- .../PropertyEditors/MediaPicker3PropertyEditor.cs | 10 +++++----- .../MultiNodeTreePickerPropertyEditor.cs | 6 +++--- .../PropertyEditors/MultiUrlPickerValueEditor.cs | 2 +- .../MultipleTextStringConfigurationEditor.cs | 2 +- .../MultipleTextStringPropertyEditor.cs | 6 +++--- .../PropertyEditors/RadioButtonsPropertyEditor.cs | 4 ++-- .../RichTextEditorBlockValidator.cs | 2 +- .../PropertyEditors/RichTextPropertyEditor.cs | 4 ++-- .../RichTextPropertyIndexValueFactory.cs | 2 +- .../PropertyEditors/SliderPropertyEditor.cs | 12 ++++++------ .../PropertyEditors/TagsPropertyEditor.cs | 4 ++-- .../PropertyEditors/TrueFalsePropertyEditor.cs | 4 ++-- .../Validators/BlockListValueRequiredValidator.cs | 2 +- .../Validators/RichTextRegexValidator.cs | 2 +- .../Validators/RichTextRequiredValidator.cs | 5 ++--- .../Validators/TrueFalseValueRequiredValidator.cs | 2 +- .../BlockGridPropertyValueCreator.cs | 4 ++-- .../BlockListPropertyValueCreator.cs | 4 ++-- .../RichTextBlockPropertyValueCreator.cs | 4 ++-- .../RteBlockRenderingValueConverter.cs | 2 +- .../PublishedCache/ReservedFieldNamesService.cs | 2 +- .../PublishedContentQuery.cs | 4 ++-- .../Routing/NotFoundHandlerHelper.cs | 2 +- .../Routing/RedirectTracker.cs | 2 +- .../Runtime/DefaultMainDomKeyGenerator.cs | 2 +- .../Runtime/FileSystemMainDomLock.cs | 4 ++-- .../Runtime/RuntimeModeValidationService.cs | 2 +- .../Scoping/AmbientScopeContextStack.cs | 2 +- .../Scoping/AmbientScopeStack.cs | 2 +- .../Scoping/HttpScopeReference.cs | 4 ++-- src/Umbraco.Infrastructure/Scoping/Scope.cs | 2 +- src/Umbraco.Infrastructure/Scoping/ScopeContext.cs | 2 +- .../Scoping/ScopeProvider.cs | 2 +- .../Security/PasswordChanger.cs | 2 +- ...mTroubleshootingInformationTelemetryProvider.cs | 12 ++++++------ .../Telemetry/Services/UsageInformationService.cs | 2 +- .../DatabaseCacheRebuilder.cs | 2 +- .../Factories/CacheNodeFactory.cs | 11 ++++------- .../Factories/PublishedContentFactory.cs | 10 +++++----- .../SeedingNotificationHandler.cs | 2 +- .../Persistence/ContentSourceDto.cs | 2 +- .../PublishedMember.cs | 2 +- .../PublishedProperty.cs | 12 ++++++------ .../Serialization/HybridCacheSerializer.cs | 2 +- .../JsonContentNestedDataSerializer.cs | 5 ++--- .../JsonContentNestedDataSerializerFactory.cs | 2 +- .../MsgPackContentNestedDataSerializerFactory.cs | 2 +- .../Services/MediaCacheService.cs | 2 +- .../Services/MemberCacheService.cs | 2 +- .../ApplicationBuilder/UmbracoEndpointBuilder.cs | 2 +- ...pplicationUrlRequestBeginNotificationHandler.cs | 2 +- .../AspNetCoreApplicationShutdownRegistry.cs | 2 +- .../AspNetCore/AspNetCoreSessionManager.cs | 2 +- .../Cache/HttpContextRequestAppCache.cs | 2 +- .../Controllers/PublishedRequestFilterAttribute.cs | 6 +++--- .../DependencyInjection/ScopedServiceProvider.cs | 2 +- .../Filters/ModelBindingExceptionAttribute.cs | 2 +- .../Filters/UmbracoUserTimeoutFilterAttribute.cs | 2 +- .../ValidateUmbracoFormRouteStringAttribute.cs | 4 ++-- .../Hosting/UmbracoHostBuilderDecorator.cs | 2 +- .../Logging/Enrichers/ApplicationIdEnricher.cs | 2 +- .../Logging/Enrichers/NoopEnricher.cs | 2 +- .../Logging/RegisteredReloadableLogger.cs | 2 +- .../Media/MediaPrependBasePathFileProvider.cs | 4 ++-- .../Middleware/UmbracoRequestMiddleware.cs | 6 +++--- .../InMemoryAuto/CollectibleRuntimeViewCompiler.cs | 6 +++--- .../InMemoryAssemblyLoadContextManager.cs | 2 +- .../InMemoryAuto/InMemoryModelFactory.cs | 10 +++++----- .../InMemoryAuto/RuntimeCompilationCacheBuster.cs | 2 +- .../InMemoryAuto/UmbracoAssemblyLoadContext.cs | 2 +- .../InMemoryAuto/UmbracoCompilationException.cs | 2 +- .../InMemoryAuto/UmbracoRazorReferenceManager.cs | 4 ++-- .../InMemoryAuto/UmbracoViewCompilerProvider.cs | 2 +- .../ModelsBuilderNotificationHandler.cs | 2 +- .../Repositories/WebProfilerRepository.cs | 2 +- .../Routing/CustomRouteContentFinderDelegate.cs | 2 +- .../Security/UmbracoSignInManager.cs | 2 +- .../Templates/TemplateRenderer.cs | 2 +- ...passRenderingModelValidationMetadataProvider.cs | 2 +- .../BypassRenderingModelValidatorProvider.cs | 2 +- .../Extensions/HtmlHelperRenderExtensions.cs | 2 +- .../Routing/EagerMatcherPolicy.cs | 2 +- .../Routing/NotFoundSelectorPolicy.cs | 2 +- .../Routing/SurfaceControllerMatcherPolicy.cs | 2 +- .../Routing/UmbracoRouteValueTransformer.cs | 2 +- .../Security/MemberAuthenticationBuilder.cs | 2 +- .../PluginRazorViewEngineOptionsSetup.cs | 2 +- .../RenderRazorViewEngineOptionsSetup.cs | 2 +- .../Builders/ContentDataBuilder.cs | 2 +- .../UmbracoBuilderExtensions.cs | 2 +- .../Repositories/ContentTypeRepositoryTest.cs | 1 - .../Repositories/DocumentRepositoryTest.cs | 2 +- .../Repositories/TemplateRepositoryTest.cs | 2 +- .../Persistence/Repositories/UserRepositoryTest.cs | 6 ++---- .../Services/Importing/ImportResources.Designer.cs | 2 +- .../DbContext/UmbracoLock.cs | 2 +- .../Customizations/OmitRecursionCustomization.cs | 2 +- .../Customizations/UmbracoCustomizations.cs | 5 +---- tools/Umbraco.JsonSchema/Options.cs | 2 +- tools/Umbraco.JsonSchema/UmbracoCmsSchema.cs | 3 +-- .../UmbracoJsonSchemaGenerator.cs | 4 ++-- 317 files changed, 451 insertions(+), 479 deletions(-) diff --git a/src/Umbraco.Cms.Api.Common/Configuration/ConfigureOpenIddict.cs b/src/Umbraco.Cms.Api.Common/Configuration/ConfigureOpenIddict.cs index f428957bd9..8751cc1bb9 100644 --- a/src/Umbraco.Cms.Api.Common/Configuration/ConfigureOpenIddict.cs +++ b/src/Umbraco.Cms.Api.Common/Configuration/ConfigureOpenIddict.cs @@ -4,7 +4,7 @@ using Umbraco.Cms.Core.Configuration.Models; namespace Umbraco.Cms.Api.Common.Configuration; -internal class ConfigureOpenIddict : IConfigureOptions +internal sealed class ConfigureOpenIddict : IConfigureOptions { private readonly IOptions _globalSettings; diff --git a/src/Umbraco.Cms.Api.Common/Json/NamedSystemTextJsonInputFormatter.cs b/src/Umbraco.Cms.Api.Common/Json/NamedSystemTextJsonInputFormatter.cs index 1ae57bd8c4..0a3a6dd8be 100644 --- a/src/Umbraco.Cms.Api.Common/Json/NamedSystemTextJsonInputFormatter.cs +++ b/src/Umbraco.Cms.Api.Common/Json/NamedSystemTextJsonInputFormatter.cs @@ -4,7 +4,7 @@ using Microsoft.Extensions.Logging; namespace Umbraco.Cms.Api.Common.Json; -internal class NamedSystemTextJsonInputFormatter : SystemTextJsonInputFormatter +internal sealed class NamedSystemTextJsonInputFormatter : SystemTextJsonInputFormatter { private readonly string _jsonOptionsName; diff --git a/src/Umbraco.Cms.Api.Common/Json/NamedSystemTextJsonOutputFormatter.cs b/src/Umbraco.Cms.Api.Common/Json/NamedSystemTextJsonOutputFormatter.cs index bd1b17b81d..c78e5b8ef9 100644 --- a/src/Umbraco.Cms.Api.Common/Json/NamedSystemTextJsonOutputFormatter.cs +++ b/src/Umbraco.Cms.Api.Common/Json/NamedSystemTextJsonOutputFormatter.cs @@ -3,8 +3,7 @@ using Microsoft.AspNetCore.Mvc.Formatters; namespace Umbraco.Cms.Api.Common.Json; - -internal class NamedSystemTextJsonOutputFormatter : SystemTextJsonOutputFormatter +internal sealed class NamedSystemTextJsonOutputFormatter : SystemTextJsonOutputFormatter { private readonly string _jsonOptionsName; diff --git a/src/Umbraco.Cms.Api.Delivery/Configuration/ConfigureUmbracoMemberAuthenticationDeliveryApiSwaggerGenOptions.cs b/src/Umbraco.Cms.Api.Delivery/Configuration/ConfigureUmbracoMemberAuthenticationDeliveryApiSwaggerGenOptions.cs index 5eaa75002c..3161105dca 100644 --- a/src/Umbraco.Cms.Api.Delivery/Configuration/ConfigureUmbracoMemberAuthenticationDeliveryApiSwaggerGenOptions.cs +++ b/src/Umbraco.Cms.Api.Delivery/Configuration/ConfigureUmbracoMemberAuthenticationDeliveryApiSwaggerGenOptions.cs @@ -26,7 +26,7 @@ public class ConfigureUmbracoMemberAuthenticationDeliveryApiSwaggerGenOptions : options.OperationFilter(); } - private class DeliveryApiSecurityFilter : SwaggerFilterBase, IOperationFilter, IDocumentFilter + private sealed class DeliveryApiSecurityFilter : SwaggerFilterBase, IOperationFilter, IDocumentFilter { public void Apply(OpenApiOperation operation, OperationFilterContext context) { diff --git a/src/Umbraco.Cms.Api.Delivery/Filters/ContextualizeFromAcceptHeadersAttribute.cs b/src/Umbraco.Cms.Api.Delivery/Filters/ContextualizeFromAcceptHeadersAttribute.cs index aaa7dc8d4f..da8e9eeea0 100644 --- a/src/Umbraco.Cms.Api.Delivery/Filters/ContextualizeFromAcceptHeadersAttribute.cs +++ b/src/Umbraco.Cms.Api.Delivery/Filters/ContextualizeFromAcceptHeadersAttribute.cs @@ -13,7 +13,7 @@ internal sealed class ContextualizeFromAcceptHeadersAttribute : TypeFilterAttrib { } - private class LocalizeFromAcceptLanguageHeaderAttributeFilter : IActionFilter + private sealed class LocalizeFromAcceptLanguageHeaderAttributeFilter : IActionFilter { private readonly IRequestCultureService _requestCultureService; private readonly IRequestSegmmentService _requestSegmentService; diff --git a/src/Umbraco.Cms.Api.Delivery/Filters/DeliveryApiAccessAttribute.cs b/src/Umbraco.Cms.Api.Delivery/Filters/DeliveryApiAccessAttribute.cs index 01f0b04074..350b73112f 100644 --- a/src/Umbraco.Cms.Api.Delivery/Filters/DeliveryApiAccessAttribute.cs +++ b/src/Umbraco.Cms.Api.Delivery/Filters/DeliveryApiAccessAttribute.cs @@ -11,7 +11,7 @@ internal sealed class DeliveryApiAccessAttribute : TypeFilterAttribute { } - private class DeliveryApiAccessFilter : IActionFilter + private sealed class DeliveryApiAccessFilter : IActionFilter { private readonly IApiAccessService _apiAccessService; private readonly IRequestPreviewService _requestPreviewService; diff --git a/src/Umbraco.Cms.Api.Delivery/Filters/DeliveryApiMediaAccessAttribute.cs b/src/Umbraco.Cms.Api.Delivery/Filters/DeliveryApiMediaAccessAttribute.cs index e6dacce2c1..ac761e3be0 100644 --- a/src/Umbraco.Cms.Api.Delivery/Filters/DeliveryApiMediaAccessAttribute.cs +++ b/src/Umbraco.Cms.Api.Delivery/Filters/DeliveryApiMediaAccessAttribute.cs @@ -11,7 +11,7 @@ internal sealed class DeliveryApiMediaAccessAttribute : TypeFilterAttribute { } - private class DeliveryApiMediaAccessFilter : IActionFilter + private sealed class DeliveryApiMediaAccessFilter : IActionFilter { private readonly IApiAccessService _apiAccessService; diff --git a/src/Umbraco.Cms.Api.Delivery/Filters/ValidateStartItemAttribute.cs b/src/Umbraco.Cms.Api.Delivery/Filters/ValidateStartItemAttribute.cs index 54f2b06b14..8373a51ce4 100644 --- a/src/Umbraco.Cms.Api.Delivery/Filters/ValidateStartItemAttribute.cs +++ b/src/Umbraco.Cms.Api.Delivery/Filters/ValidateStartItemAttribute.cs @@ -12,7 +12,7 @@ internal sealed class ValidateStartItemAttribute : TypeFilterAttribute { } - private class ValidateStartItemFilter : IActionFilter + private sealed class ValidateStartItemFilter : IActionFilter { private readonly IRequestStartItemProviderAccessor _requestStartItemProviderAccessor; diff --git a/src/Umbraco.Cms.Api.Delivery/Rendering/RequestContextOutputExpansionStrategyV2.cs b/src/Umbraco.Cms.Api.Delivery/Rendering/RequestContextOutputExpansionStrategyV2.cs index 6cc2100e93..e1a29b3ec7 100644 --- a/src/Umbraco.Cms.Api.Delivery/Rendering/RequestContextOutputExpansionStrategyV2.cs +++ b/src/Umbraco.Cms.Api.Delivery/Rendering/RequestContextOutputExpansionStrategyV2.cs @@ -124,7 +124,7 @@ internal sealed class RequestContextOutputExpansionStrategyV2 : IOutputExpansion private object? GetPropertyValue(IPublishedProperty property) => _propertyRenderer.GetPropertyValue(property, _expandProperties.Peek() is not null); - private class Node + private sealed class Node { public string Key { get; private set; } = string.Empty; diff --git a/src/Umbraco.Cms.Api.Management/DependencyInjection/BackOfficeAuthBuilderExtensions.cs b/src/Umbraco.Cms.Api.Management/DependencyInjection/BackOfficeAuthBuilderExtensions.cs index 5ddb98b570..b633f7bdd6 100644 --- a/src/Umbraco.Cms.Api.Management/DependencyInjection/BackOfficeAuthBuilderExtensions.cs +++ b/src/Umbraco.Cms.Api.Management/DependencyInjection/BackOfficeAuthBuilderExtensions.cs @@ -79,7 +79,7 @@ public static class BackOfficeAuthBuilderExtensions } } -internal class BackofficePipelineFilter : UmbracoPipelineFilter +internal sealed class BackofficePipelineFilter : UmbracoPipelineFilter { public BackofficePipelineFilter(string name) : base(name) diff --git a/src/Umbraco.Cms.Api.Management/Factories/PackagePresentationFactory.cs b/src/Umbraco.Cms.Api.Management/Factories/PackagePresentationFactory.cs index 960b2fdbcd..f8e6eaf790 100644 --- a/src/Umbraco.Cms.Api.Management/Factories/PackagePresentationFactory.cs +++ b/src/Umbraco.Cms.Api.Management/Factories/PackagePresentationFactory.cs @@ -13,7 +13,7 @@ using Umbraco.Extensions; namespace Umbraco.Cms.Api.Management.Factories; -internal class PackagePresentationFactory : IPackagePresentationFactory +internal sealed class PackagePresentationFactory : IPackagePresentationFactory { private readonly IUmbracoMapper _umbracoMapper; private readonly IRuntimeState _runtimeState; diff --git a/src/Umbraco.Cms.Api.Management/Factories/WebhookPresentationFactory.cs b/src/Umbraco.Cms.Api.Management/Factories/WebhookPresentationFactory.cs index 95a69dfeb5..a063a8e228 100644 --- a/src/Umbraco.Cms.Api.Management/Factories/WebhookPresentationFactory.cs +++ b/src/Umbraco.Cms.Api.Management/Factories/WebhookPresentationFactory.cs @@ -8,7 +8,7 @@ using Umbraco.Cms.Core.Webhooks; namespace Umbraco.Cms.Api.Management.Factories; -internal class WebhookPresentationFactory : IWebhookPresentationFactory +internal sealed class WebhookPresentationFactory : IWebhookPresentationFactory { private readonly WebhookEventCollection _webhookEventCollection; private readonly IHostingEnvironment _hostingEnvironment; diff --git a/src/Umbraco.Cms.Api.Management/Filters/AppendEventMessagesAttribute.cs b/src/Umbraco.Cms.Api.Management/Filters/AppendEventMessagesAttribute.cs index d4333ece06..e13594ed71 100644 --- a/src/Umbraco.Cms.Api.Management/Filters/AppendEventMessagesAttribute.cs +++ b/src/Umbraco.Cms.Api.Management/Filters/AppendEventMessagesAttribute.cs @@ -21,7 +21,7 @@ public sealed class AppendEventMessagesAttribute : TypeFilterAttribute { } - private class AppendEventMessagesFilter : IActionFilter + private sealed class AppendEventMessagesFilter : IActionFilter { private readonly IEventMessagesFactory _eventMessagesFactory; private readonly IJsonSerializer _jsonSerializer; diff --git a/src/Umbraco.Cms.Api.Management/Filters/UserPasswordEnsureMinimumResponseTimeAttribute.cs b/src/Umbraco.Cms.Api.Management/Filters/UserPasswordEnsureMinimumResponseTimeAttribute.cs index ab4b1fcc82..dd60a73d21 100644 --- a/src/Umbraco.Cms.Api.Management/Filters/UserPasswordEnsureMinimumResponseTimeAttribute.cs +++ b/src/Umbraco.Cms.Api.Management/Filters/UserPasswordEnsureMinimumResponseTimeAttribute.cs @@ -4,14 +4,14 @@ using Umbraco.Cms.Core.Configuration.Models; namespace Umbraco.Cms.Api.Management.Filters; -internal class UserPasswordEnsureMinimumResponseTimeAttribute : TypeFilterAttribute +internal sealed class UserPasswordEnsureMinimumResponseTimeAttribute : TypeFilterAttribute { public UserPasswordEnsureMinimumResponseTimeAttribute() : base(typeof(UserPasswordEnsureMinimumResponseTimeFilter)) { } - private class UserPasswordEnsureMinimumResponseTimeFilter : EnsureMinimumResponseTimeFilter + private sealed class UserPasswordEnsureMinimumResponseTimeFilter : EnsureMinimumResponseTimeFilter { public UserPasswordEnsureMinimumResponseTimeFilter(IOptions options) : base(options.Value.MinimumResponseTime) diff --git a/src/Umbraco.Cms.Api.Management/Mapping/SectionMapper.cs b/src/Umbraco.Cms.Api.Management/Mapping/SectionMapper.cs index 41db2123e3..d125fcd735 100644 --- a/src/Umbraco.Cms.Api.Management/Mapping/SectionMapper.cs +++ b/src/Umbraco.Cms.Api.Management/Mapping/SectionMapper.cs @@ -45,7 +45,7 @@ public static class SectionMapper return name; } - private class SectionMapping + private sealed class SectionMapping { public required string Alias { get; init; } diff --git a/src/Umbraco.Cms.Api.Management/OpenApi/BackOfficeSecurityRequirementsOperationFilter.cs b/src/Umbraco.Cms.Api.Management/OpenApi/BackOfficeSecurityRequirementsOperationFilter.cs index 5e5f3f8653..d7b18acd93 100644 --- a/src/Umbraco.Cms.Api.Management/OpenApi/BackOfficeSecurityRequirementsOperationFilter.cs +++ b/src/Umbraco.Cms.Api.Management/OpenApi/BackOfficeSecurityRequirementsOperationFilter.cs @@ -2,7 +2,7 @@ using Umbraco.Cms.Api.Management.DependencyInjection; namespace Umbraco.Cms.Api.Management.OpenApi; -internal class BackOfficeSecurityRequirementsOperationFilter : BackOfficeSecurityRequirementsOperationFilterBase +internal sealed class BackOfficeSecurityRequirementsOperationFilter : BackOfficeSecurityRequirementsOperationFilterBase { protected override string ApiName => ManagementApiConfiguration.ApiName; } diff --git a/src/Umbraco.Cms.Api.Management/OpenApi/NotificationHeaderFilter.cs b/src/Umbraco.Cms.Api.Management/OpenApi/NotificationHeaderFilter.cs index bee1910f2c..f11c350aae 100644 --- a/src/Umbraco.Cms.Api.Management/OpenApi/NotificationHeaderFilter.cs +++ b/src/Umbraco.Cms.Api.Management/OpenApi/NotificationHeaderFilter.cs @@ -6,7 +6,7 @@ using Umbraco.Cms.Core; namespace Umbraco.Cms.Api.Management.OpenApi; -internal class NotificationHeaderFilter : IOperationFilter +internal sealed class NotificationHeaderFilter : IOperationFilter { public void Apply(OpenApiOperation operation, OperationFilterContext context) { diff --git a/src/Umbraco.Cms.Api.Management/OpenApi/ReponseHeaderOperationFilter.cs b/src/Umbraco.Cms.Api.Management/OpenApi/ReponseHeaderOperationFilter.cs index e579fe2ce9..e639a64091 100644 --- a/src/Umbraco.Cms.Api.Management/OpenApi/ReponseHeaderOperationFilter.cs +++ b/src/Umbraco.Cms.Api.Management/OpenApi/ReponseHeaderOperationFilter.cs @@ -7,7 +7,7 @@ using Umbraco.Extensions; namespace Umbraco.Cms.Api.Management.OpenApi; -internal class ResponseHeaderOperationFilter : IOperationFilter +internal sealed class ResponseHeaderOperationFilter : IOperationFilter { public void Apply(OpenApiOperation operation, OperationFilterContext context) { @@ -29,7 +29,7 @@ internal class ResponseHeaderOperationFilter : IOperationFilter } } - private void SetHeader(OpenApiResponse value, string headerName, string description, string type, string? format = null) + private static void SetHeader(OpenApiResponse value, string headerName, string description, string type, string? format = null) { if (value.Headers is null) diff --git a/src/Umbraco.Cms.Api.Management/Security/BackOfficeAuthenticationBuilder.cs b/src/Umbraco.Cms.Api.Management/Security/BackOfficeAuthenticationBuilder.cs index 0c00fa7e51..7729510029 100644 --- a/src/Umbraco.Cms.Api.Management/Security/BackOfficeAuthenticationBuilder.cs +++ b/src/Umbraco.Cms.Api.Management/Security/BackOfficeAuthenticationBuilder.cs @@ -61,7 +61,7 @@ public class BackOfficeAuthenticationBuilder : AuthenticationBuilder // TODO: We could override and throw NotImplementedException for other methods? // Ensures that the sign in scheme is always the Umbraco back office external type - internal class EnsureBackOfficeScheme : IPostConfigureOptions + internal sealed class EnsureBackOfficeScheme : IPostConfigureOptions where TOptions : RemoteAuthenticationOptions { public void PostConfigure(string? name, TOptions options) diff --git a/src/Umbraco.Cms.Api.Management/Security/BackOfficeSecureDataFormat.cs b/src/Umbraco.Cms.Api.Management/Security/BackOfficeSecureDataFormat.cs index d2e0e799a8..b8f7367946 100644 --- a/src/Umbraco.Cms.Api.Management/Security/BackOfficeSecureDataFormat.cs +++ b/src/Umbraco.Cms.Api.Management/Security/BackOfficeSecureDataFormat.cs @@ -7,7 +7,7 @@ namespace Umbraco.Cms.Api.Management.Security; /// /// Custom secure format that ensures the Identity in the ticket is verified /// -internal class BackOfficeSecureDataFormat : ISecureDataFormat +internal sealed class BackOfficeSecureDataFormat : ISecureDataFormat { private readonly TimeSpan _loginTimeout; private readonly ISecureDataFormat _ticketDataFormat; diff --git a/src/Umbraco.Core/Cache/PartialViewCacheInvalidators/NoopMemberPartialViewCacheInvalidator.cs b/src/Umbraco.Core/Cache/PartialViewCacheInvalidators/NoopMemberPartialViewCacheInvalidator.cs index 9b0b69ea6b..fa7bcb596e 100644 --- a/src/Umbraco.Core/Cache/PartialViewCacheInvalidators/NoopMemberPartialViewCacheInvalidator.cs +++ b/src/Umbraco.Core/Cache/PartialViewCacheInvalidators/NoopMemberPartialViewCacheInvalidator.cs @@ -7,7 +7,7 @@ namespace Umbraco.Cms.Core.Cache.PartialViewCacheInvalidators; /// The default implementation is added in Umbraco.Web.Website, but we need this to ensure we have a service /// registered for this interface even in headless setups). /// -internal class NoopMemberPartialViewCacheInvalidator : IMemberPartialViewCacheInvalidator +internal sealed class NoopMemberPartialViewCacheInvalidator : IMemberPartialViewCacheInvalidator { /// public void ClearPartialViewCacheItems(IEnumerable memberIds) diff --git a/src/Umbraco.Core/Composing/ComposerGraph.cs b/src/Umbraco.Core/Composing/ComposerGraph.cs index a4e8f189f7..0c376befd5 100644 --- a/src/Umbraco.Core/Composing/ComposerGraph.cs +++ b/src/Umbraco.Core/Composing/ComposerGraph.cs @@ -11,7 +11,7 @@ namespace Umbraco.Cms.Core.Composing; /// /// Handles the composers. /// -internal class ComposerGraph +internal sealed class ComposerGraph { private readonly IUmbracoBuilder _builder; private readonly IEnumerable _composerTypes; @@ -415,7 +415,7 @@ internal class ComposerGraph } } - private class EnableInfo + private sealed class EnableInfo { public bool Enabled { get; set; } diff --git a/src/Umbraco.Core/Composing/FindAssembliesWithReferencesTo.cs b/src/Umbraco.Core/Composing/FindAssembliesWithReferencesTo.cs index 1b516636b3..a1581ccfcb 100644 --- a/src/Umbraco.Core/Composing/FindAssembliesWithReferencesTo.cs +++ b/src/Umbraco.Core/Composing/FindAssembliesWithReferencesTo.cs @@ -11,7 +11,7 @@ namespace Umbraco.Cms.Core.Composing; /// borrowed and modified from here /// https://github.com/dotnet/aspnetcore-tooling/blob/master/src/Razor/src/Microsoft.NET.Sdk.Razor/FindAssembliesWithReferencesTo.cs /// -internal class FindAssembliesWithReferencesTo +internal sealed class FindAssembliesWithReferencesTo { private readonly bool _includeTargets; private readonly ILogger _logger; diff --git a/src/Umbraco.Core/Composing/TypeLoader.cs b/src/Umbraco.Core/Composing/TypeLoader.cs index 3c4fa06d54..9b9bbb11f2 100644 --- a/src/Umbraco.Core/Composing/TypeLoader.cs +++ b/src/Umbraco.Core/Composing/TypeLoader.cs @@ -408,7 +408,7 @@ public sealed class TypeLoader /// /// [Serializable] - internal class CachedTypeNotFoundInFileException : Exception + internal sealed class CachedTypeNotFoundInFileException : Exception { /// /// Initializes a new instance of the class. diff --git a/src/Umbraco.Core/Configuration/EntryAssemblyMetadata.cs b/src/Umbraco.Core/Configuration/EntryAssemblyMetadata.cs index 096eac6fe0..9b0c23d0a7 100644 --- a/src/Umbraco.Core/Configuration/EntryAssemblyMetadata.cs +++ b/src/Umbraco.Core/Configuration/EntryAssemblyMetadata.cs @@ -2,7 +2,7 @@ using System.Reflection; namespace Umbraco.Cms.Core.Configuration; -internal class EntryAssemblyMetadata : IEntryAssemblyMetadata +internal sealed class EntryAssemblyMetadata : IEntryAssemblyMetadata { public EntryAssemblyMetadata() { diff --git a/src/Umbraco.Core/Configuration/Models/ContentErrorPage.cs b/src/Umbraco.Core/Configuration/Models/ContentErrorPage.cs index 27c34f0394..5e194ffabb 100644 --- a/src/Umbraco.Core/Configuration/Models/ContentErrorPage.cs +++ b/src/Umbraco.Core/Configuration/Models/ContentErrorPage.cs @@ -37,7 +37,7 @@ public class ContentErrorPage : ValidatableEntryBase [Required] public string Culture { get; set; } = null!; - internal override bool IsValid() => + internal sealed override bool IsValid() => base.IsValid() && (HasContentId ^ HasContentKey); } diff --git a/src/Umbraco.Core/Diagnostics/NoopMarchal.cs b/src/Umbraco.Core/Diagnostics/NoopMarchal.cs index 770aefd50f..991426aab9 100644 --- a/src/Umbraco.Core/Diagnostics/NoopMarchal.cs +++ b/src/Umbraco.Core/Diagnostics/NoopMarchal.cs @@ -1,6 +1,6 @@ namespace Umbraco.Cms.Core.Diagnostics; -internal class NoopMarchal : IMarchal +internal sealed class NoopMarchal : IMarchal { public IntPtr GetExceptionPointers() => IntPtr.Zero; } diff --git a/src/Umbraco.Core/Dictionary/UmbracoCultureDictionary.cs b/src/Umbraco.Core/Dictionary/UmbracoCultureDictionary.cs index 01dea9b4ef..4a59ed9fd4 100644 --- a/src/Umbraco.Core/Dictionary/UmbracoCultureDictionary.cs +++ b/src/Umbraco.Core/Dictionary/UmbracoCultureDictionary.cs @@ -17,7 +17,7 @@ namespace Umbraco.Cms.Core.Dictionary; /// fast /// (even though there is caching involved, if there's lots of dictionary items the caching is not great) /// -internal class DefaultCultureDictionary : ICultureDictionary +internal sealed class DefaultCultureDictionary : ICultureDictionary { private readonly ILocalizationService _localizationService; private readonly IAppCache _requestCache; diff --git a/src/Umbraco.Core/EnvironmentHelper.cs b/src/Umbraco.Core/EnvironmentHelper.cs index 04b3bc91ff..d1448ac5c7 100644 --- a/src/Umbraco.Core/EnvironmentHelper.cs +++ b/src/Umbraco.Core/EnvironmentHelper.cs @@ -5,7 +5,7 @@ namespace Umbraco.Cms.Core; /// /// Currently just used to get the machine name for use with file names /// -internal class EnvironmentHelper +internal static class EnvironmentHelper { /// /// Returns the machine name that is safe to use in file paths. diff --git a/src/Umbraco.Core/Events/EventAggregator.Notifications.cs b/src/Umbraco.Core/Events/EventAggregator.Notifications.cs index 5676af3f3c..4bd6355fc5 100644 --- a/src/Umbraco.Core/Events/EventAggregator.Notifications.cs +++ b/src/Umbraco.Core/Events/EventAggregator.Notifications.cs @@ -102,7 +102,7 @@ public partial class EventAggregator : IEventAggregator } } - private void PublishCore(IEnumerable>> allHandlers, IEnumerable notifications) + private static void PublishCore(IEnumerable>> allHandlers, IEnumerable notifications) { foreach (Action> handler in allHandlers) { @@ -110,7 +110,7 @@ public partial class EventAggregator : IEventAggregator } } - private async Task PublishCoreAsync(IEnumerable, CancellationToken, Task>> allHandlers, IEnumerable notifications, CancellationToken cancellationToken) + private static async Task PublishCoreAsync(IEnumerable, CancellationToken, Task>> allHandlers, IEnumerable notifications, CancellationToken cancellationToken) { foreach (Func, CancellationToken, Task> handler in allHandlers) { @@ -192,7 +192,7 @@ internal abstract class NotificationAsyncHandlerWrapper where TNotificationHandler : INotificationHandler; } -internal class NotificationAsyncHandlerWrapperImpl : NotificationAsyncHandlerWrapper +internal sealed class NotificationAsyncHandlerWrapperImpl : NotificationAsyncHandlerWrapper where TNotificationType : INotification { /// @@ -260,7 +260,7 @@ internal class NotificationAsyncHandlerWrapperImpl : Notifica } } -internal class NotificationHandlerWrapperImpl : NotificationHandlerWrapper +internal sealed class NotificationHandlerWrapperImpl : NotificationHandlerWrapper where TNotificationType : INotification { /// diff --git a/src/Umbraco.Core/Events/EventNameExtractor.cs b/src/Umbraco.Core/Events/EventNameExtractor.cs index 16f772dcb2..67eb221238 100644 --- a/src/Umbraco.Core/Events/EventNameExtractor.cs +++ b/src/Umbraco.Core/Events/EventNameExtractor.cs @@ -169,7 +169,7 @@ public class EventNameExtractor return words[0].EndsWith("ing") == false; } - private class EventInfoArgs + private sealed class EventInfoArgs { public EventInfoArgs(EventInfo eventInfo, Type[] genericArgs) { diff --git a/src/Umbraco.Core/Events/PassThroughEventDispatcher.cs b/src/Umbraco.Core/Events/PassThroughEventDispatcher.cs index 20398502a1..a3b8dc02b5 100644 --- a/src/Umbraco.Core/Events/PassThroughEventDispatcher.cs +++ b/src/Umbraco.Core/Events/PassThroughEventDispatcher.cs @@ -7,7 +7,7 @@ namespace Umbraco.Cms.Core.Events; /// This means that events will be raised during the scope transaction, /// whatever happens, and the transaction could roll back in the end. /// -internal class PassThroughEventDispatcher : IEventDispatcher +internal sealed class PassThroughEventDispatcher : IEventDispatcher { public bool DispatchCancelable(EventHandler? eventHandler, object sender, CancellableEventArgs args, string? eventName = null) { diff --git a/src/Umbraco.Core/Events/QueuingEventDispatcherBase.cs b/src/Umbraco.Core/Events/QueuingEventDispatcherBase.cs index c259e271e5..d319a1cd71 100644 --- a/src/Umbraco.Core/Events/QueuingEventDispatcherBase.cs +++ b/src/Umbraco.Core/Events/QueuingEventDispatcherBase.cs @@ -414,7 +414,7 @@ public abstract class QueuingEventDispatcherBase : IEventDispatcher } } - private class EventDefinitionInfos + private sealed class EventDefinitionInfos { public IEventDefinition? EventDefinition { get; set; } diff --git a/src/Umbraco.Core/Events/ScopedNotificationPublisher.cs b/src/Umbraco.Core/Events/ScopedNotificationPublisher.cs index a3bf6d7682..0dc8b96054 100644 --- a/src/Umbraco.Core/Events/ScopedNotificationPublisher.cs +++ b/src/Umbraco.Core/Events/ScopedNotificationPublisher.cs @@ -116,7 +116,7 @@ public class ScopedNotificationPublisher : IScopedNotifica protected virtual void PublishScopedNotifications(IList notifications) => _eventAggregator.Publish(notifications); - private class Suppressor : IDisposable + private sealed class Suppressor : IDisposable { private readonly ScopedNotificationPublisher _scopedNotificationPublisher; private bool _disposedValue; @@ -129,7 +129,7 @@ public class ScopedNotificationPublisher : IScopedNotifica public void Dispose() => Dispose(true); - protected virtual void Dispose(bool disposing) + private void Dispose(bool disposing) { if (!_disposedValue) { diff --git a/src/Umbraco.Core/Handlers/WarnDocumentTypeElementSwitchNotificationHandler.cs b/src/Umbraco.Core/Handlers/WarnDocumentTypeElementSwitchNotificationHandler.cs index 86ad4ad95c..ab6b82c735 100644 --- a/src/Umbraco.Core/Handlers/WarnDocumentTypeElementSwitchNotificationHandler.cs +++ b/src/Umbraco.Core/Handlers/WarnDocumentTypeElementSwitchNotificationHandler.cs @@ -96,7 +96,7 @@ public class WarnDocumentTypeElementSwitchNotificationHandler : } } - private class DocumentTypeElementSwitchInformation + private sealed class DocumentTypeElementSwitchInformation { public bool WasElement { get; set; } } diff --git a/src/Umbraco.Core/Hosting/NoopApplicationShutdownRegistry.cs b/src/Umbraco.Core/Hosting/NoopApplicationShutdownRegistry.cs index e821102f09..824ce3249a 100644 --- a/src/Umbraco.Core/Hosting/NoopApplicationShutdownRegistry.cs +++ b/src/Umbraco.Core/Hosting/NoopApplicationShutdownRegistry.cs @@ -1,6 +1,6 @@ namespace Umbraco.Cms.Core.Hosting; -internal class NoopApplicationShutdownRegistry : IApplicationShutdownRegistry +internal sealed class NoopApplicationShutdownRegistry : IApplicationShutdownRegistry { public void RegisterObject(IRegisteredObject registeredObject) { diff --git a/src/Umbraco.Core/IO/ShadowFileSystem.cs b/src/Umbraco.Core/IO/ShadowFileSystem.cs index 95517f8054..ef35006ef5 100644 --- a/src/Umbraco.Core/IO/ShadowFileSystem.cs +++ b/src/Umbraco.Core/IO/ShadowFileSystem.cs @@ -2,7 +2,7 @@ using System.Text.RegularExpressions; namespace Umbraco.Cms.Core.IO; -internal class ShadowFileSystem : IFileSystem +internal sealed class ShadowFileSystem : IFileSystem { private readonly IFileSystem _sfs; @@ -392,7 +392,7 @@ internal class ShadowFileSystem : IFileSystem } // copied from System.Web.Util.Wildcard internal - internal class WildcardExpression + internal sealed class WildcardExpression { private static readonly Regex MetaRegex = new("[\\+\\{\\\\\\[\\|\\(\\)\\.\\^\\$]"); private static readonly Regex QuestRegex = new("\\?"); @@ -454,7 +454,7 @@ internal class ShadowFileSystem : IFileSystem } } - private class ShadowNode + private sealed class ShadowNode { public ShadowNode(bool isDelete, bool isdir) { diff --git a/src/Umbraco.Core/IO/ShadowFileSystems.cs b/src/Umbraco.Core/IO/ShadowFileSystems.cs index 3d69875dc4..6e3ce7ca19 100644 --- a/src/Umbraco.Core/IO/ShadowFileSystems.cs +++ b/src/Umbraco.Core/IO/ShadowFileSystems.cs @@ -1,7 +1,7 @@ namespace Umbraco.Cms.Core.IO; // shadow filesystems is definitively ... too convoluted -internal class ShadowFileSystems : ICompletable +internal sealed class ShadowFileSystems : ICompletable { private readonly FileSystems _fileSystems; private bool _completed; diff --git a/src/Umbraco.Core/IO/ShadowWrapper.cs b/src/Umbraco.Core/IO/ShadowWrapper.cs index ca82c67bd2..aa3d7c9b97 100644 --- a/src/Umbraco.Core/IO/ShadowWrapper.cs +++ b/src/Umbraco.Core/IO/ShadowWrapper.cs @@ -5,7 +5,7 @@ using Umbraco.Extensions; namespace Umbraco.Cms.Core.IO; -internal class ShadowWrapper : IFileSystem, IFileProviderFactory +internal sealed class ShadowWrapper : IFileSystem, IFileProviderFactory { private const string ShadowFsPath = "ShadowFs"; diff --git a/src/Umbraco.Core/Logging/LogProfiler.cs b/src/Umbraco.Core/Logging/LogProfiler.cs index cc93372d75..a16b4caa7c 100644 --- a/src/Umbraco.Core/Logging/LogProfiler.cs +++ b/src/Umbraco.Core/Logging/LogProfiler.cs @@ -39,7 +39,7 @@ public class LogProfiler : IProfiler public bool IsEnabled => _logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug); // a lightweight disposable timer - private class LightDisposableTimer : DisposableObjectSlim + private sealed class LightDisposableTimer : DisposableObjectSlim { private readonly Action _callback; private readonly Stopwatch _stopwatch = Stopwatch.StartNew(); diff --git a/src/Umbraco.Core/Logging/NoopProfiler.cs b/src/Umbraco.Core/Logging/NoopProfiler.cs index c7bcf34bc0..7c7b0b3234 100644 --- a/src/Umbraco.Core/Logging/NoopProfiler.cs +++ b/src/Umbraco.Core/Logging/NoopProfiler.cs @@ -17,7 +17,7 @@ public class NoopProfiler : IProfiler /// public bool IsEnabled => false; - private class VoidDisposable : DisposableObjectSlim + private sealed class VoidDisposable : DisposableObjectSlim { protected override void DisposeResources() { diff --git a/src/Umbraco.Core/Mail/NotImplementedEmailSender.cs b/src/Umbraco.Core/Mail/NotImplementedEmailSender.cs index 5b1fa0923a..7d0d2b4865 100644 --- a/src/Umbraco.Core/Mail/NotImplementedEmailSender.cs +++ b/src/Umbraco.Core/Mail/NotImplementedEmailSender.cs @@ -2,7 +2,7 @@ using Umbraco.Cms.Core.Models.Email; namespace Umbraco.Cms.Core.Mail; -internal class NotImplementedEmailSender : IEmailSender +internal sealed class NotImplementedEmailSender : IEmailSender { public Task SendAsync(EmailMessage message, string emailType) => throw new NotImplementedException( diff --git a/src/Umbraco.Core/Mail/NotImplementedSmsSender.cs b/src/Umbraco.Core/Mail/NotImplementedSmsSender.cs index b3901d5ab9..af3e0dff8b 100644 --- a/src/Umbraco.Core/Mail/NotImplementedSmsSender.cs +++ b/src/Umbraco.Core/Mail/NotImplementedSmsSender.cs @@ -3,7 +3,7 @@ namespace Umbraco.Cms.Core.Mail; /// /// An that throws /// -internal class NotImplementedSmsSender : ISmsSender +internal sealed class NotImplementedSmsSender : ISmsSender { public Task SendSmsAsync(string number, string message) => throw new NotImplementedException( diff --git a/src/Umbraco.Core/Models/DefaultPayloadModel.cs b/src/Umbraco.Core/Models/DefaultPayloadModel.cs index 45b2592b51..deccb4c427 100644 --- a/src/Umbraco.Core/Models/DefaultPayloadModel.cs +++ b/src/Umbraco.Core/Models/DefaultPayloadModel.cs @@ -1,6 +1,6 @@ namespace Umbraco.Cms.Core.Models; -internal class DefaultPayloadModel +internal sealed class DefaultPayloadModel { public Guid Id { get; set; } } diff --git a/src/Umbraco.Core/Models/Membership/User.cs b/src/Umbraco.Core/Models/Membership/User.cs index 487f9c4209..571449dcc3 100644 --- a/src/Umbraco.Core/Models/Membership/User.cs +++ b/src/Umbraco.Core/Models/Membership/User.cs @@ -426,7 +426,7 @@ public class User : EntityBase, IUser, IProfile /// /// Internal class used to wrap the user in a profile /// - private class WrappedUserProfile : IProfile + private sealed class WrappedUserProfile : IProfile { private readonly IUser _user; diff --git a/src/Umbraco.Core/Models/PublishedContent/ModelType.cs b/src/Umbraco.Core/Models/PublishedContent/ModelType.cs index 4588d47967..56df7dae23 100644 --- a/src/Umbraco.Core/Models/PublishedContent/ModelType.cs +++ b/src/Umbraco.Core/Models/PublishedContent/ModelType.cs @@ -373,7 +373,7 @@ public class ModelType : Type } /// -internal class ModelTypeArrayType : Type +internal sealed class ModelTypeArrayType : Type { private readonly Type _elementType; diff --git a/src/Umbraco.Core/Models/PublishedContent/PublishedContentTypeConverter.cs b/src/Umbraco.Core/Models/PublishedContent/PublishedContentTypeConverter.cs index 957246ccfe..c2b1cae7d7 100644 --- a/src/Umbraco.Core/Models/PublishedContent/PublishedContentTypeConverter.cs +++ b/src/Umbraco.Core/Models/PublishedContent/PublishedContentTypeConverter.cs @@ -3,7 +3,7 @@ using System.Globalization; namespace Umbraco.Cms.Core.Models.PublishedContent; -internal class PublishedContentTypeConverter : TypeConverter +internal sealed class PublishedContentTypeConverter : TypeConverter { private static readonly Type[] ConvertingTypes = { typeof(int) }; diff --git a/src/Umbraco.Core/Models/PublishedContent/PublishedModelFactory.cs b/src/Umbraco.Core/Models/PublishedContent/PublishedModelFactory.cs index b2d5da7876..7067b357fe 100644 --- a/src/Umbraco.Core/Models/PublishedContent/PublishedModelFactory.cs +++ b/src/Umbraco.Core/Models/PublishedContent/PublishedModelFactory.cs @@ -151,7 +151,7 @@ public class PublishedModelFactory : IPublishedModelFactory public Type MapModelType(Type type) => ModelType.Map(type, _modelTypeMap); - private class ModelInfo + private sealed class ModelInfo { public Type? ParameterType { get; set; } diff --git a/src/Umbraco.Core/Persistence/Repositories/UpgradeCheckRepository.cs b/src/Umbraco.Core/Persistence/Repositories/UpgradeCheckRepository.cs index e6190b049a..3dab741acc 100644 --- a/src/Umbraco.Core/Persistence/Repositories/UpgradeCheckRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/UpgradeCheckRepository.cs @@ -33,7 +33,7 @@ public class UpgradeCheckRepository : IUpgradeCheckRepository } } - private class CheckUpgradeDto + private sealed class CheckUpgradeDto { public CheckUpgradeDto(SemVersion version) { diff --git a/src/Umbraco.Core/PropertyEditors/ContentPickerConfigurationEditor.cs b/src/Umbraco.Core/PropertyEditors/ContentPickerConfigurationEditor.cs index be8a755dfc..7997db5f0f 100644 --- a/src/Umbraco.Core/PropertyEditors/ContentPickerConfigurationEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/ContentPickerConfigurationEditor.cs @@ -5,7 +5,7 @@ using Umbraco.Cms.Core.IO; namespace Umbraco.Cms.Core.PropertyEditors; -internal class ContentPickerConfigurationEditor : ConfigurationEditor +internal sealed class ContentPickerConfigurationEditor : ConfigurationEditor { public ContentPickerConfigurationEditor(IIOHelper ioHelper) : base(ioHelper) diff --git a/src/Umbraco.Core/PropertyEditors/ContentPickerPropertyEditor.cs b/src/Umbraco.Core/PropertyEditors/ContentPickerPropertyEditor.cs index 1c5d240c8f..ae8773defc 100644 --- a/src/Umbraco.Core/PropertyEditors/ContentPickerPropertyEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/ContentPickerPropertyEditor.cs @@ -37,7 +37,7 @@ public class ContentPickerPropertyEditor : DataEditor protected override IDataValueEditor CreateValueEditor() => DataValueEditorFactory.Create(Attribute!); - internal class ContentPickerPropertyValueEditor : DataValueEditor, IDataValueReference + internal sealed class ContentPickerPropertyValueEditor : DataValueEditor, IDataValueReference { public ContentPickerPropertyValueEditor( diff --git a/src/Umbraco.Core/PropertyEditors/DateValueEditor.cs b/src/Umbraco.Core/PropertyEditors/DateValueEditor.cs index d0c578d32b..c6c6387c2a 100644 --- a/src/Umbraco.Core/PropertyEditors/DateValueEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/DateValueEditor.cs @@ -12,7 +12,7 @@ namespace Umbraco.Cms.Core.PropertyEditors; /// CUstom value editor so we can serialize with the correct date format (excluding time) /// and includes the date validator /// -internal class DateValueEditor : DataValueEditor +internal sealed class DateValueEditor : DataValueEditor { public DateValueEditor( IShortStringHelper shortStringHelper, diff --git a/src/Umbraco.Core/PropertyEditors/DecimalPropertyEditor.cs b/src/Umbraco.Core/PropertyEditors/DecimalPropertyEditor.cs index fbce2b7a5d..5d10cf7e76 100644 --- a/src/Umbraco.Core/PropertyEditors/DecimalPropertyEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/DecimalPropertyEditor.cs @@ -41,7 +41,7 @@ public class DecimalPropertyEditor : DataEditor /// /// Defines the value editor for the decimal property editor. /// - internal class DecimalPropertyValueEditor : DataValueEditor + internal sealed class DecimalPropertyValueEditor : DataValueEditor { /// /// Initializes a new instance of the class. @@ -63,7 +63,7 @@ public class DecimalPropertyEditor : DataEditor public override object? FromEditor(ContentPropertyData editorValue, object? currentValue) => TryParsePropertyValue(editorValue.Value); - private decimal? TryParsePropertyValue(object? value) + private static decimal? TryParsePropertyValue(object? value) => value is decimal decimalValue ? decimalValue : decimal.TryParse(value?.ToString(), CultureInfo.InvariantCulture, out var parsedDecimalValue) @@ -108,7 +108,7 @@ public class DecimalPropertyEditor : DataEditor /// /// Validates the min/max configuration for the decimal property editor. /// - internal class MinMaxValidator : DecimalPropertyConfigurationValidatorBase, IValueValidator + internal sealed class MinMaxValidator : DecimalPropertyConfigurationValidatorBase, IValueValidator { /// /// Initializes a new instance of the class. @@ -145,7 +145,7 @@ public class DecimalPropertyEditor : DataEditor /// /// Validates the step configuration for the decimal property editor. /// - internal class StepValidator : DecimalPropertyConfigurationValidatorBase, IValueValidator + internal sealed class StepValidator : DecimalPropertyConfigurationValidatorBase, IValueValidator { /// /// Initializes a new instance of the class. diff --git a/src/Umbraco.Core/PropertyEditors/IntegerPropertyEditor.cs b/src/Umbraco.Core/PropertyEditors/IntegerPropertyEditor.cs index 5f282061b0..fd0ff93158 100644 --- a/src/Umbraco.Core/PropertyEditors/IntegerPropertyEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/IntegerPropertyEditor.cs @@ -39,7 +39,7 @@ public class IntegerPropertyEditor : DataEditor /// /// Defines the value editor for the integer property editor. /// - internal class IntegerPropertyValueEditor : DataValueEditor + internal sealed class IntegerPropertyValueEditor : DataValueEditor { /// /// Initializes a new instance of the class. @@ -106,7 +106,7 @@ public class IntegerPropertyEditor : DataEditor /// /// Validates the min/max configuration for the integer property editor. /// - internal class MinMaxValidator : IntegerPropertyConfigurationValidatorBase, IValueValidator + internal sealed class MinMaxValidator : IntegerPropertyConfigurationValidatorBase, IValueValidator { /// /// Initializes a new instance of the class. @@ -143,7 +143,7 @@ public class IntegerPropertyEditor : DataEditor /// /// Validates the step configuration for the integer property editor. /// - internal class StepValidator : IntegerPropertyConfigurationValidatorBase, IValueValidator + internal sealed class StepValidator : IntegerPropertyConfigurationValidatorBase, IValueValidator { /// /// Initializes a new instance of the class. diff --git a/src/Umbraco.Core/PropertyEditors/LabelPropertyEditor.cs b/src/Umbraco.Core/PropertyEditors/LabelPropertyEditor.cs index 646f20efe6..a7456a51a6 100644 --- a/src/Umbraco.Core/PropertyEditors/LabelPropertyEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/LabelPropertyEditor.cs @@ -37,7 +37,7 @@ public class LabelPropertyEditor : DataEditor new LabelConfigurationEditor(_ioHelper); // provides the property value editor - internal class LabelPropertyValueEditor : DataValueEditor + internal sealed class LabelPropertyValueEditor : DataValueEditor { public LabelPropertyValueEditor( IShortStringHelper shortStringHelper, diff --git a/src/Umbraco.Core/PropertyEditors/MarkDownPropertyValueEditor.cs b/src/Umbraco.Core/PropertyEditors/MarkDownPropertyValueEditor.cs index 2a7a97b027..ae78a456cd 100644 --- a/src/Umbraco.Core/PropertyEditors/MarkDownPropertyValueEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/MarkDownPropertyValueEditor.cs @@ -2,13 +2,12 @@ using Umbraco.Cms.Core.IO; using Umbraco.Cms.Core.Models.Editors; using Umbraco.Cms.Core.Security; using Umbraco.Cms.Core.Serialization; -using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Strings; using Umbraco.Extensions; namespace Umbraco.Cms.Core.PropertyEditors; -internal class MarkDownPropertyValueEditor : DataValueEditor +internal sealed class MarkDownPropertyValueEditor : DataValueEditor { private readonly IMarkdownSanitizer _markdownSanitizer; diff --git a/src/Umbraco.Core/PropertyEditors/MemberGroupPickerPropertyEditor.cs b/src/Umbraco.Core/PropertyEditors/MemberGroupPickerPropertyEditor.cs index f22c52b159..4f25dc74fe 100644 --- a/src/Umbraco.Core/PropertyEditors/MemberGroupPickerPropertyEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/MemberGroupPickerPropertyEditor.cs @@ -21,7 +21,7 @@ public class MemberGroupPickerPropertyEditor : DataEditor protected override IDataValueEditor CreateValueEditor() => DataValueEditorFactory.Create(Attribute!); - private class MemberGroupPickerPropertyValueEditor : DataValueEditor + private sealed class MemberGroupPickerPropertyValueEditor : DataValueEditor { private readonly IMemberGroupService _memberGroupService; diff --git a/src/Umbraco.Core/PropertyEditors/MemberPickerPropertyEditor.cs b/src/Umbraco.Core/PropertyEditors/MemberPickerPropertyEditor.cs index 8392f852b4..fd9fb503e3 100644 --- a/src/Umbraco.Core/PropertyEditors/MemberPickerPropertyEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/MemberPickerPropertyEditor.cs @@ -21,7 +21,7 @@ public class MemberPickerPropertyEditor : DataEditor protected override IDataValueEditor CreateValueEditor() => DataValueEditorFactory.Create(Attribute!); - private class MemberPickerPropertyValueEditor : DataValueEditor, IDataValueReference + private sealed class MemberPickerPropertyValueEditor : DataValueEditor, IDataValueReference { private readonly IMemberService _memberService; diff --git a/src/Umbraco.Core/PropertyEditors/TextOnlyValueEditor.cs b/src/Umbraco.Core/PropertyEditors/TextOnlyValueEditor.cs index 97b0643e58..143240df08 100644 --- a/src/Umbraco.Core/PropertyEditors/TextOnlyValueEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/TextOnlyValueEditor.cs @@ -63,7 +63,7 @@ public class TextOnlyValueEditor : DataValueEditor /// /// A common length validator for both textbox and text area. /// - internal class LengthValidator : IValueValidator + internal sealed class LengthValidator : IValueValidator { private readonly ILocalizedTextService _localizedTextService; diff --git a/src/Umbraco.Core/PropertyEditors/UserPickerPropertyEditor.cs b/src/Umbraco.Core/PropertyEditors/UserPickerPropertyEditor.cs index 261e8f27d8..c0026e917a 100644 --- a/src/Umbraco.Core/PropertyEditors/UserPickerPropertyEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/UserPickerPropertyEditor.cs @@ -21,7 +21,7 @@ public class UserPickerPropertyEditor : DataEditor protected override IDataValueEditor CreateValueEditor() => DataValueEditorFactory.Create(Attribute!); - private class UserPickerPropertyValueEditor : DataValueEditor + private sealed class UserPickerPropertyValueEditor : DataValueEditor { private readonly IUserService _userService; diff --git a/src/Umbraco.Core/PropertyEditors/Validation/JsonPathValidationError.cs b/src/Umbraco.Core/PropertyEditors/Validation/JsonPathValidationError.cs index 36e06633b6..0a973e888f 100644 --- a/src/Umbraco.Core/PropertyEditors/Validation/JsonPathValidationError.cs +++ b/src/Umbraco.Core/PropertyEditors/Validation/JsonPathValidationError.cs @@ -1,6 +1,6 @@ namespace Umbraco.Cms.Core.PropertyEditors.Validation; -internal class JsonPathValidationError +internal sealed class JsonPathValidationError { public required string JsonPath { get; init; } diff --git a/src/Umbraco.Core/PropertyEditors/Validation/JsonPathValidator.cs b/src/Umbraco.Core/PropertyEditors/Validation/JsonPathValidator.cs index 307abe22a5..fd8f462205 100644 --- a/src/Umbraco.Core/PropertyEditors/Validation/JsonPathValidator.cs +++ b/src/Umbraco.Core/PropertyEditors/Validation/JsonPathValidator.cs @@ -55,7 +55,7 @@ internal static class JsonPathValidator return errors; } - private class JsonPathValidationTreeItem + private sealed class JsonPathValidationTreeItem { public required string JsonPath { get; init; } diff --git a/src/Umbraco.Core/PublishedCache/PublishedElementPropertyBase.cs b/src/Umbraco.Core/PublishedCache/PublishedElementPropertyBase.cs index fb4ed21ef6..af5b658b9f 100644 --- a/src/Umbraco.Core/PublishedCache/PublishedElementPropertyBase.cs +++ b/src/Umbraco.Core/PublishedCache/PublishedElementPropertyBase.cs @@ -4,7 +4,7 @@ using Umbraco.Extensions; namespace Umbraco.Cms.Core.PublishedCache; -internal class PublishedElementPropertyBase : PublishedPropertyBase +internal sealed class PublishedElementPropertyBase : PublishedPropertyBase { protected readonly IPublishedElement Element; diff --git a/src/Umbraco.Core/Security/Authorization/DictionaryPermissionAuthorizer.cs b/src/Umbraco.Core/Security/Authorization/DictionaryPermissionAuthorizer.cs index 312ae37c44..b49b1c76c7 100644 --- a/src/Umbraco.Core/Security/Authorization/DictionaryPermissionAuthorizer.cs +++ b/src/Umbraco.Core/Security/Authorization/DictionaryPermissionAuthorizer.cs @@ -4,7 +4,7 @@ using Umbraco.Cms.Core.Services.AuthorizationStatus; namespace Umbraco.Cms.Core.Security.Authorization; -internal class DictionaryPermissionAuthorizer : IDictionaryPermissionAuthorizer +internal sealed class DictionaryPermissionAuthorizer : IDictionaryPermissionAuthorizer { private readonly IDictionaryPermissionService _dictionaryPermissionService; diff --git a/src/Umbraco.Core/Services/ConsentService.cs b/src/Umbraco.Core/Services/ConsentService.cs index d7bb7af13e..40b76f5a8e 100644 --- a/src/Umbraco.Core/Services/ConsentService.cs +++ b/src/Umbraco.Core/Services/ConsentService.cs @@ -10,7 +10,7 @@ namespace Umbraco.Cms.Core.Services; /// /// Implements . /// -internal class ConsentService : RepositoryService, IConsentService +internal sealed class ConsentService : RepositoryService, IConsentService { private readonly IConsentRepository _consentRepository; diff --git a/src/Umbraco.Core/Services/ContentVersionService.cs b/src/Umbraco.Core/Services/ContentVersionService.cs index 9d5d569b3a..d6562351d7 100644 --- a/src/Umbraco.Core/Services/ContentVersionService.cs +++ b/src/Umbraco.Core/Services/ContentVersionService.cs @@ -13,7 +13,7 @@ using Umbraco.Extensions; // ReSharper disable once CheckNamespace namespace Umbraco.Cms.Core.Services; -internal class ContentVersionService : IContentVersionService +internal sealed class ContentVersionService : IContentVersionService { private readonly IAuditRepository _auditRepository; private readonly IContentVersionCleanupPolicy _contentVersionCleanupPolicy; diff --git a/src/Umbraco.Core/Services/DocumentUrlService.cs b/src/Umbraco.Core/Services/DocumentUrlService.cs index 2b60d736cc..d0c08bbe59 100644 --- a/src/Umbraco.Core/Services/DocumentUrlService.cs +++ b/src/Umbraco.Core/Services/DocumentUrlService.cs @@ -45,7 +45,7 @@ public class DocumentUrlService : IDocumentUrlService /// Model used to cache a single published document along with all it's URL segments. /// /// Internal for the purpose of unit and benchmark testing. - internal class PublishedDocumentUrlSegments + internal sealed class PublishedDocumentUrlSegments { /// /// Gets or sets the document key. @@ -456,7 +456,7 @@ public class DocumentUrlService : IDocumentUrlService private static bool IsVariantAndPublishedForCulture(IContent document, string? culture) => document.PublishCultureInfos?.Values.Any(x => x.Culture == culture) ?? false; - private IEnumerable ConvertToPersistedModel(PublishedDocumentUrlSegments model) + private static IEnumerable ConvertToPersistedModel(PublishedDocumentUrlSegments model) { foreach (PublishedDocumentUrlSegments.UrlSegment urlSegment in model.UrlSegments) { @@ -816,7 +816,7 @@ public class DocumentUrlService : IDocumentUrlService return '/' + string.Join('/', urlSegments); } - private bool HideTopLevel(bool hideTopLevelNodeFromPath, bool isRootFirstItem, List urlSegments) + private static bool HideTopLevel(bool hideTopLevelNodeFromPath, bool isRootFirstItem, List urlSegments) { if (hideTopLevelNodeFromPath is false) { diff --git a/src/Umbraco.Core/Services/EntityXmlSerializer.cs b/src/Umbraco.Core/Services/EntityXmlSerializer.cs index 872b6b6868..5636b957e6 100644 --- a/src/Umbraco.Core/Services/EntityXmlSerializer.cs +++ b/src/Umbraco.Core/Services/EntityXmlSerializer.cs @@ -13,7 +13,7 @@ namespace Umbraco.Cms.Core.Services; /// /// Serializes entities to XML /// -internal class EntityXmlSerializer : IEntityXmlSerializer +internal sealed class EntityXmlSerializer : IEntityXmlSerializer { private readonly IConfigurationEditorJsonSerializer _configurationEditorJsonSerializer; private readonly IContentService _contentService; diff --git a/src/Umbraco.Core/Services/FileSystem/PartialViewFolderService.cs b/src/Umbraco.Core/Services/FileSystem/PartialViewFolderService.cs index 43b631d45b..0625ebf7d1 100644 --- a/src/Umbraco.Core/Services/FileSystem/PartialViewFolderService.cs +++ b/src/Umbraco.Core/Services/FileSystem/PartialViewFolderService.cs @@ -5,7 +5,7 @@ using Umbraco.Cms.Core.Services.OperationStatus; namespace Umbraco.Cms.Core.Services.FileSystem; -internal class PartialViewFolderService : FolderServiceOperationBase, IPartialViewFolderService +internal sealed class PartialViewFolderService : FolderServiceOperationBase, IPartialViewFolderService { public PartialViewFolderService(IPartialViewRepository repository, ICoreScopeProvider scopeProvider) : base(repository, scopeProvider) diff --git a/src/Umbraco.Core/Services/FileSystem/ScriptFolderService.cs b/src/Umbraco.Core/Services/FileSystem/ScriptFolderService.cs index dca28af69c..0bca13a1ed 100644 --- a/src/Umbraco.Core/Services/FileSystem/ScriptFolderService.cs +++ b/src/Umbraco.Core/Services/FileSystem/ScriptFolderService.cs @@ -5,7 +5,7 @@ using Umbraco.Cms.Core.Services.OperationStatus; namespace Umbraco.Cms.Core.Services.FileSystem; -internal class ScriptFolderService : FolderServiceOperationBase, IScriptFolderService +internal sealed class ScriptFolderService : FolderServiceOperationBase, IScriptFolderService { public ScriptFolderService(IScriptRepository repository, ICoreScopeProvider scopeProvider) : base(repository, scopeProvider) diff --git a/src/Umbraco.Core/Services/FileSystem/StylesheetFolderService.cs b/src/Umbraco.Core/Services/FileSystem/StylesheetFolderService.cs index b153ca0845..84bcbf3a18 100644 --- a/src/Umbraco.Core/Services/FileSystem/StylesheetFolderService.cs +++ b/src/Umbraco.Core/Services/FileSystem/StylesheetFolderService.cs @@ -5,7 +5,7 @@ using Umbraco.Cms.Core.Services.OperationStatus; namespace Umbraco.Cms.Core.Services.FileSystem; -internal class StylesheetFolderService : FolderServiceOperationBase, IStylesheetFolderService +internal sealed class StylesheetFolderService : FolderServiceOperationBase, IStylesheetFolderService { public StylesheetFolderService(IStylesheetRepository repository, ICoreScopeProvider scopeProvider) : base(repository, scopeProvider) diff --git a/src/Umbraco.Core/Services/IdKeyMap.cs b/src/Umbraco.Core/Services/IdKeyMap.cs index 2dff4e3cd3..65aa4c5d25 100644 --- a/src/Umbraco.Core/Services/IdKeyMap.cs +++ b/src/Umbraco.Core/Services/IdKeyMap.cs @@ -418,7 +418,7 @@ public class IdKeyMap : IIdKeyMap, IDisposable // ReSharper disable ClassNeverInstantiated.Local // ReSharper disable UnusedAutoPropertyAccessor.Local - private class TypedIdDto + private sealed class TypedIdDto { public int Id { get; set; } diff --git a/src/Umbraco.Core/Services/KeyValueService.cs b/src/Umbraco.Core/Services/KeyValueService.cs index 0a38e3c284..e2c318fd0b 100644 --- a/src/Umbraco.Core/Services/KeyValueService.cs +++ b/src/Umbraco.Core/Services/KeyValueService.cs @@ -4,7 +4,7 @@ using Umbraco.Cms.Core.Scoping; namespace Umbraco.Cms.Core.Services; -internal class KeyValueService : IKeyValueService +internal sealed class KeyValueService : IKeyValueService { private readonly IKeyValueRepository _repository; private readonly ICoreScopeProvider _scopeProvider; diff --git a/src/Umbraco.Core/Services/MemberGroupService.cs b/src/Umbraco.Core/Services/MemberGroupService.cs index bf490c2613..2fda732b3a 100644 --- a/src/Umbraco.Core/Services/MemberGroupService.cs +++ b/src/Umbraco.Core/Services/MemberGroupService.cs @@ -8,7 +8,7 @@ using Umbraco.Cms.Core.Services.OperationStatus; namespace Umbraco.Cms.Core.Services; -internal class MemberGroupService : RepositoryService, IMemberGroupService +internal sealed class MemberGroupService : RepositoryService, IMemberGroupService { private readonly IMemberGroupRepository _memberGroupRepository; diff --git a/src/Umbraco.Core/Services/MemberTwoFactorLoginService.cs b/src/Umbraco.Core/Services/MemberTwoFactorLoginService.cs index b21558b834..db09478dab 100644 --- a/src/Umbraco.Core/Services/MemberTwoFactorLoginService.cs +++ b/src/Umbraco.Core/Services/MemberTwoFactorLoginService.cs @@ -6,7 +6,7 @@ using Umbraco.Cms.Core.Services.OperationStatus; namespace Umbraco.Cms.Core.Services; /// -internal class MemberTwoFactorLoginService : TwoFactorLoginServiceBase, IMemberTwoFactorLoginService +internal sealed class MemberTwoFactorLoginService : TwoFactorLoginServiceBase, IMemberTwoFactorLoginService { private readonly IMemberService _memberService; diff --git a/src/Umbraco.Core/Services/NotificationService.cs b/src/Umbraco.Core/Services/NotificationService.cs index be896eb5f3..24dbb0089a 100644 --- a/src/Umbraco.Core/Services/NotificationService.cs +++ b/src/Umbraco.Core/Services/NotificationService.cs @@ -607,7 +607,7 @@ public class NotificationService : INotificationService } } - private class NotificationRequest + private sealed class NotificationRequest { public NotificationRequest(EmailMessage mail, string? action, string? userName, string? email) { diff --git a/src/Umbraco.Core/Services/RedirectUrlService.cs b/src/Umbraco.Core/Services/RedirectUrlService.cs index 0944b2a6a1..c2050f7ff0 100644 --- a/src/Umbraco.Core/Services/RedirectUrlService.cs +++ b/src/Umbraco.Core/Services/RedirectUrlService.cs @@ -7,7 +7,7 @@ using Umbraco.Cms.Core.Scoping; namespace Umbraco.Cms.Core.Services; -internal class RedirectUrlService : RepositoryService, IRedirectUrlService +internal sealed class RedirectUrlService : RepositoryService, IRedirectUrlService { private readonly IRedirectUrlRepository _redirectUrlRepository; diff --git a/src/Umbraco.Core/Services/UserTwoFactorLoginService.cs b/src/Umbraco.Core/Services/UserTwoFactorLoginService.cs index 10a9de140f..58352a242f 100644 --- a/src/Umbraco.Core/Services/UserTwoFactorLoginService.cs +++ b/src/Umbraco.Core/Services/UserTwoFactorLoginService.cs @@ -7,7 +7,7 @@ using Umbraco.Cms.Core.Services.OperationStatus; namespace Umbraco.Cms.Core.Services; /// -internal class UserTwoFactorLoginService : TwoFactorLoginServiceBase, IUserTwoFactorLoginService +internal sealed class UserTwoFactorLoginService : TwoFactorLoginServiceBase, IUserTwoFactorLoginService { private readonly IUserService _userService; diff --git a/src/Umbraco.Core/Strings/Diff.cs b/src/Umbraco.Core/Strings/Diff.cs index e8a5cc1324..e4c943d811 100644 --- a/src/Umbraco.Core/Strings/Diff.cs +++ b/src/Umbraco.Core/Strings/Diff.cs @@ -500,7 +500,7 @@ internal sealed class Diff /// /// Data on one input file being compared. /// - internal class DiffData + internal sealed class DiffData { /// Buffer of numbers that will be compared. internal int[] Data; diff --git a/src/Umbraco.Core/SystemLock.cs b/src/Umbraco.Core/SystemLock.cs index 0e47096c2e..75ca72e27c 100644 --- a/src/Umbraco.Core/SystemLock.cs +++ b/src/Umbraco.Core/SystemLock.cs @@ -89,7 +89,7 @@ public class SystemLock // note - before making those classes some structs, read // about "impure methods" and mutating readonly structs... - private class NamedSemaphoreReleaser : CriticalFinalizerObject, IDisposable + private sealed class NamedSemaphoreReleaser : CriticalFinalizerObject, IDisposable { private readonly Semaphore? _semaphore; @@ -156,7 +156,7 @@ public class SystemLock } } - private class SemaphoreSlimReleaser : IDisposable + private sealed class SemaphoreSlimReleaser : IDisposable { private readonly SemaphoreSlim _semaphore; diff --git a/src/Umbraco.Core/Telemetry/SiteIdentifierService.cs b/src/Umbraco.Core/Telemetry/SiteIdentifierService.cs index 6af5830cf5..0d2d3a3c8d 100644 --- a/src/Umbraco.Core/Telemetry/SiteIdentifierService.cs +++ b/src/Umbraco.Core/Telemetry/SiteIdentifierService.cs @@ -6,7 +6,7 @@ using Umbraco.Cms.Core.Configuration.Models; namespace Umbraco.Cms.Core.Telemetry; /// -internal class SiteIdentifierService : ISiteIdentifierService +internal sealed class SiteIdentifierService : ISiteIdentifierService { private readonly IConfigManipulator _configManipulator; private readonly ILogger _logger; diff --git a/src/Umbraco.Core/Telemetry/TelemetryService.cs b/src/Umbraco.Core/Telemetry/TelemetryService.cs index 5a31fec4f6..ea10679a5d 100644 --- a/src/Umbraco.Core/Telemetry/TelemetryService.cs +++ b/src/Umbraco.Core/Telemetry/TelemetryService.cs @@ -11,7 +11,7 @@ using Umbraco.Extensions; namespace Umbraco.Cms.Core.Telemetry; /// -internal class TelemetryService : ITelemetryService +internal sealed class TelemetryService : ITelemetryService { private readonly IPackagingService _packagingService; private readonly IMetricsConsentService _metricsConsentService; diff --git a/src/Umbraco.Core/UdiTypeConverter.cs b/src/Umbraco.Core/UdiTypeConverter.cs index 2a52a1e093..c058ce2a70 100644 --- a/src/Umbraco.Core/UdiTypeConverter.cs +++ b/src/Umbraco.Core/UdiTypeConverter.cs @@ -9,7 +9,7 @@ namespace Umbraco.Cms.Core; /// /// Primarily this is used so that WebApi can auto-bind a string parameter to a UDI instance /// -internal class UdiTypeConverter : TypeConverter +internal sealed class UdiTypeConverter : TypeConverter { public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType) { diff --git a/src/Umbraco.Core/Xml/XmlNodeListFactory.cs b/src/Umbraco.Core/Xml/XmlNodeListFactory.cs index 87b9bbc795..74c0861d66 100644 --- a/src/Umbraco.Core/Xml/XmlNodeListFactory.cs +++ b/src/Umbraco.Core/Xml/XmlNodeListFactory.cs @@ -13,7 +13,7 @@ public class XmlNodeListFactory #region XmlNodeListIterator - private class XmlNodeListIterator : XmlNodeList + private sealed class XmlNodeListIterator : XmlNodeList { private readonly XPathNodeIterator? _iterator; private readonly IList _nodes = new List(); @@ -108,7 +108,7 @@ public class XmlNodeListFactory #region XmlNodeListEnumerator - private class XmlNodeListEnumerator : IEnumerator + private sealed class XmlNodeListEnumerator : IEnumerator { private readonly XmlNodeListIterator _iterator; private int _position = -1; diff --git a/src/Umbraco.Infrastructure/BackgroundJobs/RecurringBackgroundJobHostedServiceRunner.cs b/src/Umbraco.Infrastructure/BackgroundJobs/RecurringBackgroundJobHostedServiceRunner.cs index e86b8c64bd..a2cfed23c2 100644 --- a/src/Umbraco.Infrastructure/BackgroundJobs/RecurringBackgroundJobHostedServiceRunner.cs +++ b/src/Umbraco.Infrastructure/BackgroundJobs/RecurringBackgroundJobHostedServiceRunner.cs @@ -71,7 +71,7 @@ public class RecurringBackgroundJobHostedServiceRunner : IHostedService _logger.LogInformation("Completed stopping recurring background jobs hosted services"); } - private class NamedServiceJob + private sealed class NamedServiceJob { public NamedServiceJob(string name, IHostedService hostedService) { diff --git a/src/Umbraco.Infrastructure/Cache/FullDataSetRepositoryCachePolicy.cs b/src/Umbraco.Infrastructure/Cache/FullDataSetRepositoryCachePolicy.cs index 91ae85c84f..f57319d122 100644 --- a/src/Umbraco.Infrastructure/Cache/FullDataSetRepositoryCachePolicy.cs +++ b/src/Umbraco.Infrastructure/Cache/FullDataSetRepositoryCachePolicy.cs @@ -21,7 +21,7 @@ namespace Umbraco.Cms.Core.Cache; /// keep as a whole in memory. /// /// -internal class FullDataSetRepositoryCachePolicy : RepositoryCachePolicyBase +internal sealed class FullDataSetRepositoryCachePolicy : RepositoryCachePolicyBase where TEntity : class, IEntity { protected static readonly TId[] EmptyIds = new TId[0]; // const diff --git a/src/Umbraco.Infrastructure/Cache/SingleItemsOnlyRepositoryCachePolicy.cs b/src/Umbraco.Infrastructure/Cache/SingleItemsOnlyRepositoryCachePolicy.cs index 16079d059a..d8b0e9bb04 100644 --- a/src/Umbraco.Infrastructure/Cache/SingleItemsOnlyRepositoryCachePolicy.cs +++ b/src/Umbraco.Infrastructure/Cache/SingleItemsOnlyRepositoryCachePolicy.cs @@ -18,7 +18,7 @@ namespace Umbraco.Cms.Core.Cache; /// /// Used by DictionaryRepository. /// -internal class SingleItemsOnlyRepositoryCachePolicy : DefaultRepositoryCachePolicy +internal sealed class SingleItemsOnlyRepositoryCachePolicy : DefaultRepositoryCachePolicy where TEntity : class, IEntity { public SingleItemsOnlyRepositoryCachePolicy(IAppPolicyCache cache, IScopeAccessor scopeAccessor, RepositoryCachePolicyOptions options) diff --git a/src/Umbraco.Infrastructure/Configuration/JsonConfigManipulator.cs b/src/Umbraco.Infrastructure/Configuration/JsonConfigManipulator.cs index 1978d554dd..1800954848 100644 --- a/src/Umbraco.Infrastructure/Configuration/JsonConfigManipulator.cs +++ b/src/Umbraco.Infrastructure/Configuration/JsonConfigManipulator.cs @@ -10,7 +10,7 @@ using Umbraco.Cms.Core.Configuration.Models; namespace Umbraco.Cms.Infrastructure.Configuration; -internal class JsonConfigManipulator : IConfigManipulator +internal sealed class JsonConfigManipulator : IConfigManipulator { private const string ConnectionStringObjectName = "ConnectionStrings"; private const string UmbracoConnectionStringPath = $"{ConnectionStringObjectName}:{Constants.System.UmbracoConnectionName}"; diff --git a/src/Umbraco.Infrastructure/Examine/Deferred/DeliveryApiContentIndexHandleContentChanges.cs b/src/Umbraco.Infrastructure/Examine/Deferred/DeliveryApiContentIndexHandleContentChanges.cs index 0b4310c4b4..fb0d2c9219 100644 --- a/src/Umbraco.Infrastructure/Examine/Deferred/DeliveryApiContentIndexHandleContentChanges.cs +++ b/src/Umbraco.Infrastructure/Examine/Deferred/DeliveryApiContentIndexHandleContentChanges.cs @@ -136,7 +136,7 @@ internal sealed class DeliveryApiContentIndexHandleContentChanges : DeliveryApiC } }); - private class CulturePublishStatus : IEquatable + private sealed class CulturePublishStatus : IEquatable { public required string Culture { get; set; } diff --git a/src/Umbraco.Infrastructure/Examine/DeferredActions.cs b/src/Umbraco.Infrastructure/Examine/DeferredActions.cs index 495c12e7a7..7c417c3f92 100644 --- a/src/Umbraco.Infrastructure/Examine/DeferredActions.cs +++ b/src/Umbraco.Infrastructure/Examine/DeferredActions.cs @@ -2,7 +2,7 @@ using Umbraco.Cms.Core.Scoping; namespace Umbraco.Cms.Infrastructure.Examine; -internal class DeferredActions +internal sealed class DeferredActions { // the default enlist priority is 100 // enlist with a lower priority to ensure that anything "default" runs after us diff --git a/src/Umbraco.Infrastructure/Examine/ExamineIndexingMainDomHandler.cs b/src/Umbraco.Infrastructure/Examine/ExamineIndexingMainDomHandler.cs index fa4d184dbd..e430ba3851 100644 --- a/src/Umbraco.Infrastructure/Examine/ExamineIndexingMainDomHandler.cs +++ b/src/Umbraco.Infrastructure/Examine/ExamineIndexingMainDomHandler.cs @@ -5,7 +5,7 @@ using Umbraco.Cms.Core.Runtime; namespace Umbraco.Cms.Infrastructure.Examine; -internal class ExamineIndexingMainDomHandler +internal sealed class ExamineIndexingMainDomHandler { private readonly IMainDom _mainDom; private readonly IProfilingLogger _profilingLogger; diff --git a/src/Umbraco.Infrastructure/Examine/ExamineUmbracoIndexingHandler.cs b/src/Umbraco.Infrastructure/Examine/ExamineUmbracoIndexingHandler.cs index 2ca1bc8f79..6a24337989 100644 --- a/src/Umbraco.Infrastructure/Examine/ExamineUmbracoIndexingHandler.cs +++ b/src/Umbraco.Infrastructure/Examine/ExamineUmbracoIndexingHandler.cs @@ -14,7 +14,7 @@ namespace Umbraco.Cms.Infrastructure.Examine; /// /// Indexing handler for Examine indexes /// -internal class ExamineUmbracoIndexingHandler : IUmbracoIndexingHandler +internal sealed class ExamineUmbracoIndexingHandler : IUmbracoIndexingHandler { private readonly IBackgroundTaskQueue _backgroundTaskQueue; private readonly IContentValueSetBuilder _contentValueSetBuilder; @@ -208,7 +208,7 @@ internal class ExamineUmbracoIndexingHandler : IUmbracoIndexingHandler /// /// Re-indexes an item on a background thread /// - private class DeferredReIndexForContent : IDeferredAction + private sealed class DeferredReIndexForContent : IDeferredAction { private readonly IBackgroundTaskQueue _backgroundTaskQueue; private readonly IContent _content; @@ -271,7 +271,7 @@ internal class ExamineUmbracoIndexingHandler : IUmbracoIndexingHandler /// /// Re-indexes an item on a background thread /// - private class DeferredReIndexForMedia : IDeferredAction + private sealed class DeferredReIndexForMedia : IDeferredAction { private readonly IBackgroundTaskQueue _backgroundTaskQueue; private readonly ExamineUmbracoIndexingHandler _examineUmbracoIndexingHandler; @@ -323,7 +323,7 @@ internal class ExamineUmbracoIndexingHandler : IUmbracoIndexingHandler /// /// Re-indexes an item on a background thread /// - private class DeferredReIndexForMember : IDeferredAction + private sealed class DeferredReIndexForMember : IDeferredAction { private readonly IBackgroundTaskQueue _backgroundTaskQueue; private readonly ExamineUmbracoIndexingHandler _examineUmbracoIndexingHandler; @@ -366,7 +366,7 @@ internal class ExamineUmbracoIndexingHandler : IUmbracoIndexingHandler }); } - private class DeferredDeleteIndex : IDeferredAction + private sealed class DeferredDeleteIndex : IDeferredAction { private readonly ExamineUmbracoIndexingHandler _examineUmbracoIndexingHandler; private readonly int _id; @@ -435,7 +435,7 @@ internal class ExamineUmbracoIndexingHandler : IUmbracoIndexingHandler /// /// Removes all protected content from applicable indexes on a background thread /// - private class DeferredRemoveProtectedContent : IDeferredAction + private sealed class DeferredRemoveProtectedContent : IDeferredAction { private readonly IBackgroundTaskQueue _backgroundTaskQueue; private readonly ExamineUmbracoIndexingHandler _examineUmbracoIndexingHandler; diff --git a/src/Umbraco.Infrastructure/Logging/Serilog/Enrichers/Log4NetLevelMapperEnricher.cs b/src/Umbraco.Infrastructure/Logging/Serilog/Enrichers/Log4NetLevelMapperEnricher.cs index a8a0610d2c..eaf89aff04 100644 --- a/src/Umbraco.Infrastructure/Logging/Serilog/Enrichers/Log4NetLevelMapperEnricher.cs +++ b/src/Umbraco.Infrastructure/Logging/Serilog/Enrichers/Log4NetLevelMapperEnricher.cs @@ -7,7 +7,7 @@ namespace Umbraco.Cms.Core.Logging.Serilog.Enrichers; /// This is used to create a new property in Logs called 'Log4NetLevel' /// So that we can map Serilog levels to Log4Net levels - so log files stay consistent /// -internal class Log4NetLevelMapperEnricher : ILogEventEnricher +internal sealed class Log4NetLevelMapperEnricher : ILogEventEnricher { public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory) { diff --git a/src/Umbraco.Infrastructure/Logging/Viewer/CountingFilter.cs b/src/Umbraco.Infrastructure/Logging/Viewer/CountingFilter.cs index c5692384f6..3746f1aeab 100644 --- a/src/Umbraco.Infrastructure/Logging/Viewer/CountingFilter.cs +++ b/src/Umbraco.Infrastructure/Logging/Viewer/CountingFilter.cs @@ -2,7 +2,7 @@ using Serilog.Events; namespace Umbraco.Cms.Core.Logging.Viewer; -internal class CountingFilter : ILogFilter +internal sealed class CountingFilter : ILogFilter { public CountingFilter() => Counts = new LogLevelCounts(); diff --git a/src/Umbraco.Infrastructure/Logging/Viewer/ErrorCounterFilter.cs b/src/Umbraco.Infrastructure/Logging/Viewer/ErrorCounterFilter.cs index 834da2952e..0517550b73 100644 --- a/src/Umbraco.Infrastructure/Logging/Viewer/ErrorCounterFilter.cs +++ b/src/Umbraco.Infrastructure/Logging/Viewer/ErrorCounterFilter.cs @@ -2,7 +2,7 @@ using Serilog.Events; namespace Umbraco.Cms.Core.Logging.Viewer; -internal class ErrorCounterFilter : ILogFilter +internal sealed class ErrorCounterFilter : ILogFilter { public int Count { get; private set; } diff --git a/src/Umbraco.Infrastructure/Logging/Viewer/ExpressionFilter.cs b/src/Umbraco.Infrastructure/Logging/Viewer/ExpressionFilter.cs index 5e2130b5d3..23499f2fb0 100644 --- a/src/Umbraco.Infrastructure/Logging/Viewer/ExpressionFilter.cs +++ b/src/Umbraco.Infrastructure/Logging/Viewer/ExpressionFilter.cs @@ -6,7 +6,7 @@ using Umbraco.Extensions; namespace Umbraco.Cms.Core.Logging.Viewer; // Log Expression Filters (pass in filter exp string) -internal class ExpressionFilter : ILogFilter +internal sealed class ExpressionFilter : ILogFilter { private const string ExpressionOperators = "()+=*<>%-"; private readonly Func? _filter; @@ -57,7 +57,7 @@ internal class ExpressionFilter : ILogFilter public bool TakeLogEvent(LogEvent e) => _filter == null || _filter(e); - private Func? PerformMessageLikeFilter(string filterExpression, SerilogLegacyNameResolver serilogLegacyNameResolver) + private static Func? PerformMessageLikeFilter(string filterExpression, SerilogLegacyNameResolver serilogLegacyNameResolver) { var filterSearch = $"@Message like '%{SerilogExpression.EscapeLikeExpressionContent(filterExpression)}%'"; if (SerilogExpression.TryCompile(filterSearch, null, serilogLegacyNameResolver, out CompiledExpression? compiled, out var error)) diff --git a/src/Umbraco.Infrastructure/Logging/Viewer/MessageTemplateFilter.cs b/src/Umbraco.Infrastructure/Logging/Viewer/MessageTemplateFilter.cs index 62b040f5f1..75069d764b 100644 --- a/src/Umbraco.Infrastructure/Logging/Viewer/MessageTemplateFilter.cs +++ b/src/Umbraco.Infrastructure/Logging/Viewer/MessageTemplateFilter.cs @@ -2,7 +2,7 @@ using Serilog.Events; namespace Umbraco.Cms.Core.Logging.Viewer; -internal class MessageTemplateFilter : ILogFilter +internal sealed class MessageTemplateFilter : ILogFilter { public readonly Dictionary Counts = new(); diff --git a/src/Umbraco.Infrastructure/Logging/Viewer/SerilogJsonLogViewer.cs b/src/Umbraco.Infrastructure/Logging/Viewer/SerilogJsonLogViewer.cs index 3cf2768259..9c8dace1cf 100644 --- a/src/Umbraco.Infrastructure/Logging/Viewer/SerilogJsonLogViewer.cs +++ b/src/Umbraco.Infrastructure/Logging/Viewer/SerilogJsonLogViewer.cs @@ -5,7 +5,7 @@ using ILogger = Serilog.ILogger; namespace Umbraco.Cms.Core.Logging.Viewer; -internal class SerilogJsonLogViewer : SerilogLogViewerSourceBase +internal sealed class SerilogJsonLogViewer : SerilogLogViewerSourceBase { private const int FileSizeCap = 100; private readonly ILogger _logger; @@ -112,7 +112,7 @@ internal class SerilogJsonLogViewer : SerilogLogViewerSourceBase return logs; } - private string GetSearchPattern(DateTime day) => $"*{day:yyyyMMdd}*.json"; + private static string GetSearchPattern(DateTime day) => $"*{day:yyyyMMdd}*.json"; private bool TryRead(LogEventReader reader, out LogEvent? evt) { diff --git a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseDataCreator.cs b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseDataCreator.cs index 4d01ca95d9..b30423be99 100644 --- a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseDataCreator.cs +++ b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseDataCreator.cs @@ -17,7 +17,7 @@ namespace Umbraco.Cms.Infrastructure.Migrations.Install; /// /// Creates the initial database data during install. /// -internal class DatabaseDataCreator +internal sealed class DatabaseDataCreator { internal const string EditorGroupAlias = "editor"; diff --git a/src/Umbraco.Infrastructure/Migrations/MigrationContext.cs b/src/Umbraco.Infrastructure/Migrations/MigrationContext.cs index 173ee942c4..d73dbbee17 100644 --- a/src/Umbraco.Infrastructure/Migrations/MigrationContext.cs +++ b/src/Umbraco.Infrastructure/Migrations/MigrationContext.cs @@ -8,10 +8,9 @@ namespace Umbraco.Cms.Infrastructure.Migrations; /// /// Implements . /// -internal class MigrationContext : IMigrationContext +internal sealed class MigrationContext : IMigrationContext { private readonly Action? _onCompleteAction; - private readonly List _postMigrations = new(); /// /// Initializes a new instance of the class. diff --git a/src/Umbraco.Infrastructure/Migrations/Notifications/DatabaseSchemaCreatedNotification.cs b/src/Umbraco.Infrastructure/Migrations/Notifications/DatabaseSchemaCreatedNotification.cs index 75875b9384..8d671a8f2f 100644 --- a/src/Umbraco.Infrastructure/Migrations/Notifications/DatabaseSchemaCreatedNotification.cs +++ b/src/Umbraco.Infrastructure/Migrations/Notifications/DatabaseSchemaCreatedNotification.cs @@ -3,7 +3,7 @@ using Umbraco.Cms.Core.Notifications; namespace Umbraco.Cms.Infrastructure.Migrations.Notifications; -internal class DatabaseSchemaCreatedNotification : StatefulNotification +internal sealed class DatabaseSchemaCreatedNotification : StatefulNotification { public DatabaseSchemaCreatedNotification(EventMessages eventMessages) => EventMessages = eventMessages; diff --git a/src/Umbraco.Infrastructure/Migrations/Notifications/DatabaseSchemaCreatingNotification.cs b/src/Umbraco.Infrastructure/Migrations/Notifications/DatabaseSchemaCreatingNotification.cs index d4dfb35df7..33c6736aa5 100644 --- a/src/Umbraco.Infrastructure/Migrations/Notifications/DatabaseSchemaCreatingNotification.cs +++ b/src/Umbraco.Infrastructure/Migrations/Notifications/DatabaseSchemaCreatingNotification.cs @@ -3,7 +3,7 @@ using Umbraco.Cms.Core.Notifications; namespace Umbraco.Cms.Infrastructure.Migrations.Notifications; -internal class DatabaseSchemaCreatingNotification : CancelableNotification +internal sealed class DatabaseSchemaCreatingNotification : CancelableNotification { public DatabaseSchemaCreatingNotification(EventMessages messages) : base(messages) diff --git a/src/Umbraco.Infrastructure/Packaging/ImportPackageBuilder.cs b/src/Umbraco.Infrastructure/Packaging/ImportPackageBuilder.cs index e557181a51..ae8e525c30 100644 --- a/src/Umbraco.Infrastructure/Packaging/ImportPackageBuilder.cs +++ b/src/Umbraco.Infrastructure/Packaging/ImportPackageBuilder.cs @@ -11,7 +11,7 @@ using Umbraco.Cms.Infrastructure.Migrations.Expressions.Common; namespace Umbraco.Cms.Infrastructure.Packaging; -internal class ImportPackageBuilder : ExpressionBuilderBase, IImportPackageBuilder, +internal sealed class ImportPackageBuilder : ExpressionBuilderBase, IImportPackageBuilder, IExecutableBuilder { public ImportPackageBuilder( diff --git a/src/Umbraco.Infrastructure/Packaging/ImportPackageBuilderExpression.cs b/src/Umbraco.Infrastructure/Packaging/ImportPackageBuilderExpression.cs index 0e4bf757e8..d8303a2d67 100644 --- a/src/Umbraco.Infrastructure/Packaging/ImportPackageBuilderExpression.cs +++ b/src/Umbraco.Infrastructure/Packaging/ImportPackageBuilderExpression.cs @@ -16,7 +16,7 @@ using Umbraco.Extensions; namespace Umbraco.Cms.Infrastructure.Packaging; -internal class ImportPackageBuilderExpression : MigrationExpressionBase +internal sealed class ImportPackageBuilderExpression : MigrationExpressionBase { private readonly IContentTypeBaseServiceProvider _contentTypeBaseServiceProvider; private readonly MediaFileManager _mediaFileManager; diff --git a/src/Umbraco.Infrastructure/Persistence/DatabaseModelDefinitions/DbIndexDefinition.cs b/src/Umbraco.Infrastructure/Persistence/DatabaseModelDefinitions/DbIndexDefinition.cs index 4c2cf0a69f..0143926751 100644 --- a/src/Umbraco.Infrastructure/Persistence/DatabaseModelDefinitions/DbIndexDefinition.cs +++ b/src/Umbraco.Infrastructure/Persistence/DatabaseModelDefinitions/DbIndexDefinition.cs @@ -3,7 +3,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.DatabaseModelDefinitions; /// /// Represents a database index definition retrieved by querying the database /// -internal class DbIndexDefinition +internal sealed class DbIndexDefinition { public DbIndexDefinition(Tuple data) { diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/AccessDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/AccessDto.cs index c5bfbc8c01..dcd62d54d3 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/AccessDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/AccessDto.cs @@ -8,7 +8,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos; [TableName(Constants.DatabaseSchema.Tables.Access)] [PrimaryKey("id", AutoIncrement = false)] [ExplicitColumns] -internal class AccessDto +internal sealed class AccessDto { [Column("id")] [PrimaryKeyColumn(Name = "PK_umbracoAccess", AutoIncrement = false)] diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/AccessRuleDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/AccessRuleDto.cs index ec843c1c54..bc8c92addf 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/AccessRuleDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/AccessRuleDto.cs @@ -8,7 +8,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos; [TableName(Constants.DatabaseSchema.Tables.AccessRule)] [PrimaryKey("id", AutoIncrement = false)] [ExplicitColumns] -internal class AccessRuleDto +internal sealed class AccessRuleDto { [Column("id")] [PrimaryKeyColumn(Name = "PK_umbracoAccessRule", AutoIncrement = false)] diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/AuditEntryDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/AuditEntryDto.cs index c94a680a1f..35e5121935 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/AuditEntryDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/AuditEntryDto.cs @@ -8,7 +8,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos; [TableName(Constants.DatabaseSchema.Tables.AuditEntry)] [PrimaryKey("id")] [ExplicitColumns] -internal class AuditEntryDto +internal sealed class AuditEntryDto { [Column("id")] [PrimaryKeyColumn] diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/AxisDefintionDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/AxisDefintionDto.cs index 2c1c68c1f0..760fe6ccdc 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/AxisDefintionDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/AxisDefintionDto.cs @@ -2,7 +2,7 @@ using NPoco; namespace Umbraco.Cms.Infrastructure.Persistence.Dtos; -internal class AxisDefintionDto +internal sealed class AxisDefintionDto { [Column("nodeId")] public int NodeId { get; set; } diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/ContentScheduleDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/ContentScheduleDto.cs index 8194448ce4..5f575b77ef 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/ContentScheduleDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/ContentScheduleDto.cs @@ -7,7 +7,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos; [TableName(TableName)] [PrimaryKey("id", AutoIncrement = false)] [ExplicitColumns] -internal class ContentScheduleDto +internal sealed class ContentScheduleDto { public const string TableName = Constants.DatabaseSchema.Tables.ContentSchedule; diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/ContentType2ContentTypeDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/ContentType2ContentTypeDto.cs index 3931f2c5e5..19a3922161 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/ContentType2ContentTypeDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/ContentType2ContentTypeDto.cs @@ -6,7 +6,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos; [TableName(Constants.DatabaseSchema.Tables.ElementTypeTree)] [ExplicitColumns] -internal class ContentType2ContentTypeDto +internal sealed class ContentType2ContentTypeDto { [Column("parentContentTypeId")] [PrimaryKeyColumn(AutoIncrement = false, Clustered = true, Name = "PK_cmsContentType2ContentType", OnColumns = "parentContentTypeId, childContentTypeId")] diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/ContentTypeAllowedContentTypeDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/ContentTypeAllowedContentTypeDto.cs index fec7983d1f..5f0bf8f608 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/ContentTypeAllowedContentTypeDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/ContentTypeAllowedContentTypeDto.cs @@ -7,7 +7,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos; [TableName(Constants.DatabaseSchema.Tables.ContentChildType)] [PrimaryKey("Id", AutoIncrement = false)] [ExplicitColumns] -internal class ContentTypeAllowedContentTypeDto +internal sealed class ContentTypeAllowedContentTypeDto { [Column("Id")] [ForeignKey(typeof(ContentTypeDto), Name = "FK_cmsContentTypeAllowedContentType_cmsContentType", Column = "nodeId")] diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/ContentTypeTemplateDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/ContentTypeTemplateDto.cs index ad653f2759..4239937d21 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/ContentTypeTemplateDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/ContentTypeTemplateDto.cs @@ -7,7 +7,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos; [TableName(Constants.DatabaseSchema.Tables.DocumentType)] [PrimaryKey("contentTypeNodeId", AutoIncrement = false)] [ExplicitColumns] -internal class ContentTypeTemplateDto +internal sealed class ContentTypeTemplateDto { [Column("contentTypeNodeId")] [PrimaryKeyColumn(AutoIncrement = false, Name = "PK_cmsDocumentType", OnColumns = "contentTypeNodeId, templateNodeId")] diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/ContentVersionCleanupPolicyDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/ContentVersionCleanupPolicyDto.cs index cdc36ad077..2e024541a7 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/ContentVersionCleanupPolicyDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/ContentVersionCleanupPolicyDto.cs @@ -7,7 +7,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos; [TableName(TableName)] [PrimaryKey("contentTypeId", AutoIncrement = false)] [ExplicitColumns] -internal class ContentVersionCleanupPolicyDto +internal sealed class ContentVersionCleanupPolicyDto { public const string TableName = Constants.DatabaseSchema.Tables.ContentVersionCleanupPolicy; diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/ContentVersionCultureVariationDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/ContentVersionCultureVariationDto.cs index d77872ae20..c868ba4afb 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/ContentVersionCultureVariationDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/ContentVersionCultureVariationDto.cs @@ -7,7 +7,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos; [TableName(TableName)] [PrimaryKey("id")] [ExplicitColumns] -internal class ContentVersionCultureVariationDto +internal sealed class ContentVersionCultureVariationDto { public const string TableName = Constants.DatabaseSchema.Tables.ContentVersionCultureVariation; private int? _updateUserId; diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/DocumentCultureVariationDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/DocumentCultureVariationDto.cs index e89d9cae63..e093a6ac54 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/DocumentCultureVariationDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/DocumentCultureVariationDto.cs @@ -7,7 +7,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos; [TableName(TableName)] [PrimaryKey("id")] [ExplicitColumns] -internal class DocumentCultureVariationDto +internal sealed class DocumentCultureVariationDto { public const string TableName = Constants.DatabaseSchema.Tables.DocumentCultureVariation; diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/DocumentPublishedReadOnlyDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/DocumentPublishedReadOnlyDto.cs index 0087298645..04fb1017e8 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/DocumentPublishedReadOnlyDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/DocumentPublishedReadOnlyDto.cs @@ -6,7 +6,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos; [TableName(Constants.DatabaseSchema.Tables.Document)] [PrimaryKey("versionId", AutoIncrement = false)] [ExplicitColumns] -internal class DocumentPublishedReadOnlyDto +internal sealed class DocumentPublishedReadOnlyDto { [Column("nodeId")] public int NodeId { get; set; } diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/DomainDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/DomainDto.cs index da5a8ad665..0d05268902 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/DomainDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/DomainDto.cs @@ -7,7 +7,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos; [TableName(TableName)] [PrimaryKey("id")] [ExplicitColumns] -internal class DomainDto +internal sealed class DomainDto { public const string TableName = Constants.DatabaseSchema.Tables.Domain; diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/ExternalLoginDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/ExternalLoginDto.cs index a34c1100a2..3d84dbafe6 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/ExternalLoginDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/ExternalLoginDto.cs @@ -8,7 +8,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos; [TableName(TableName)] [ExplicitColumns] [PrimaryKey("Id")] -internal class ExternalLoginDto +internal sealed class ExternalLoginDto { public const string TableName = Constants.DatabaseSchema.Tables.ExternalLogin; diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/ExternalLoginTokenDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/ExternalLoginTokenDto.cs index 9699a6ef13..7ff2622960 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/ExternalLoginTokenDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/ExternalLoginTokenDto.cs @@ -8,7 +8,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos; [TableName(TableName)] [ExplicitColumns] [PrimaryKey("Id")] -internal class ExternalLoginTokenDto +internal sealed class ExternalLoginTokenDto { public const string TableName = Constants.DatabaseSchema.Tables.ExternalLoginToken; diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/KeyValueDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/KeyValueDto.cs index 6bab9b91be..51d2a74121 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/KeyValueDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/KeyValueDto.cs @@ -9,7 +9,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos; [TableName(Constants.DatabaseSchema.Tables.KeyValue)] [PrimaryKey("key", AutoIncrement = false)] [ExplicitColumns] -internal class KeyValueDto +internal sealed class KeyValueDto { public const string TableName = Constants.DatabaseSchema.Tables.KeyValue; diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/LanguageDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/LanguageDto.cs index 3fe65f8322..ac63485a05 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/LanguageDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/LanguageDto.cs @@ -7,7 +7,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos; [TableName(TableName)] [PrimaryKey("id")] [ExplicitColumns] -internal class LanguageDto +internal sealed class LanguageDto { public const string TableName = Constants.DatabaseSchema.Tables.Language; diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/LockDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/LockDto.cs index 5b1fce4623..c3015bfe8c 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/LockDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/LockDto.cs @@ -7,7 +7,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos; [TableName(Constants.DatabaseSchema.Tables.Lock)] [PrimaryKey("id", AutoIncrement = false)] [ExplicitColumns] -internal class LockDto +internal sealed class LockDto { [Column("id")] [PrimaryKeyColumn(Name = "PK_umbracoLock", AutoIncrement = false)] diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/LogDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/LogDto.cs index 36f637fef3..20c2733bfe 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/LogDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/LogDto.cs @@ -8,7 +8,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos; [TableName(TableName)] [PrimaryKey("id")] [ExplicitColumns] -internal class LogDto +internal sealed class LogDto { public const string TableName = Constants.DatabaseSchema.Tables.Log; diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/LogViewerQueryDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/LogViewerQueryDto.cs index 6de89b1c64..c71cb9b6b3 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/LogViewerQueryDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/LogViewerQueryDto.cs @@ -7,7 +7,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos; [TableName(Constants.DatabaseSchema.Tables.LogViewerQuery)] [PrimaryKey("id")] [ExplicitColumns] -internal class LogViewerQueryDto +internal sealed class LogViewerQueryDto { [Column("id")] [PrimaryKeyColumn] diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/MediaDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/MediaDto.cs index bb6c672f32..6eedeca27e 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/MediaDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/MediaDto.cs @@ -5,7 +5,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos; // this is a special Dto that does not have a corresponding table // and is only used in our code to represent a media item, similar // to document items. -internal class MediaDto +internal sealed class MediaDto { public int NodeId { get; set; } diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/MediaVersionDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/MediaVersionDto.cs index 223414a976..fd47f17696 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/MediaVersionDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/MediaVersionDto.cs @@ -7,7 +7,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos; [TableName(TableName)] [PrimaryKey("id", AutoIncrement = false)] [ExplicitColumns] -internal class MediaVersionDto +internal sealed class MediaVersionDto { public const string TableName = Constants.DatabaseSchema.Tables.MediaVersion; diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/Member2MemberGroupDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/Member2MemberGroupDto.cs index 3fa9d3980a..99cb8d2a39 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/Member2MemberGroupDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/Member2MemberGroupDto.cs @@ -7,7 +7,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos; [TableName(Constants.DatabaseSchema.Tables.Member2MemberGroup)] [PrimaryKey("Member", AutoIncrement = false)] [ExplicitColumns] -internal class Member2MemberGroupDto +internal sealed class Member2MemberGroupDto { [Column("Member")] [PrimaryKeyColumn(AutoIncrement = false, Name = "PK_cmsMember2MemberGroup", OnColumns = "Member, MemberGroup")] diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/MemberDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/MemberDto.cs index 5a025c412e..99d07e2276 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/MemberDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/MemberDto.cs @@ -7,7 +7,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos; [TableName(TableName)] [PrimaryKey("nodeId", AutoIncrement = false)] [ExplicitColumns] -internal class MemberDto +internal sealed class MemberDto { private const string TableName = Constants.DatabaseSchema.Tables.Member; diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/MemberPropertyTypeDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/MemberPropertyTypeDto.cs index 5b27863c8a..e0487661ae 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/MemberPropertyTypeDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/MemberPropertyTypeDto.cs @@ -7,7 +7,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos; [TableName(Constants.DatabaseSchema.Tables.MemberPropertyType)] [PrimaryKey("pk")] [ExplicitColumns] -internal class MemberPropertyTypeDto +internal sealed class MemberPropertyTypeDto { [Column("pk")] [PrimaryKeyColumn] diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/NavigationDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/NavigationDto.cs index eada4a97a4..617212c83d 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/NavigationDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/NavigationDto.cs @@ -5,7 +5,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos; // Used internally for representing the data needed for constructing the in-memory navigation structure. [TableName(NodeDto.TableName)] -internal class NavigationDto : INavigationModel +internal sealed class NavigationDto : INavigationModel { // Public constants to bind properties between DTOs public const string ContentTypeKeyColumnName = "contentTypeKey"; diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/PropertyDataDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/PropertyDataDto.cs index 2158f6c586..ef7d2e85e9 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/PropertyDataDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/PropertyDataDto.cs @@ -8,7 +8,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos; [TableName(TableName)] [PrimaryKey("id")] [ExplicitColumns] -internal class PropertyDataDto +internal sealed class PropertyDataDto { public const string TableName = Constants.DatabaseSchema.Tables.PropertyData; public const int VarcharLength = 512; diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/PropertyTypeCommonDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/PropertyTypeCommonDto.cs index 2645735b82..74f547646c 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/PropertyTypeCommonDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/PropertyTypeCommonDto.cs @@ -4,7 +4,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos; // this is PropertyTypeDto + the special property type fields for members // it is used for querying everything needed for a property type, at once -internal class PropertyTypeCommonDto : PropertyTypeDto +internal sealed class PropertyTypeCommonDto : PropertyTypeDto { [Column("memberCanEdit")] public bool CanEdit { get; set; } diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/PropertyTypeGroupDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/PropertyTypeGroupDto.cs index 9910caaa7b..6e3bd0b70c 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/PropertyTypeGroupDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/PropertyTypeGroupDto.cs @@ -8,7 +8,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos; [TableName(TableName)] [PrimaryKey("id", AutoIncrement = true)] [ExplicitColumns] -internal class PropertyTypeGroupDto +internal sealed class PropertyTypeGroupDto { public const string TableName = Constants.DatabaseSchema.Tables.PropertyTypeGroup; diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/PropertyTypeGroupReadOnlyDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/PropertyTypeGroupReadOnlyDto.cs index 9829604193..effe2acdf7 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/PropertyTypeGroupReadOnlyDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/PropertyTypeGroupReadOnlyDto.cs @@ -6,7 +6,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos; [TableName(Constants.DatabaseSchema.Tables.PropertyTypeGroup)] [PrimaryKey("id", AutoIncrement = true)] [ExplicitColumns] -internal class PropertyTypeGroupReadOnlyDto +internal sealed class PropertyTypeGroupReadOnlyDto { [Column("PropertyTypeGroupId")] public int? Id { get; set; } diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/PropertyTypeReadOnlyDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/PropertyTypeReadOnlyDto.cs index 94d8436401..14c24499e6 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/PropertyTypeReadOnlyDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/PropertyTypeReadOnlyDto.cs @@ -6,7 +6,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos; [TableName(Constants.DatabaseSchema.Tables.PropertyType)] [PrimaryKey("id")] [ExplicitColumns] -internal class PropertyTypeReadOnlyDto +internal sealed class PropertyTypeReadOnlyDto { [Column("PropertyTypeId")] public int? Id { get; set; } diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/RedirectUrlDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/RedirectUrlDto.cs index 3582a7eee5..49ab6c8aa4 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/RedirectUrlDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/RedirectUrlDto.cs @@ -7,7 +7,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos; [TableName(Constants.DatabaseSchema.Tables.RedirectUrl)] [PrimaryKey("id", AutoIncrement = false)] [ExplicitColumns] -internal class RedirectUrlDto +internal sealed class RedirectUrlDto { public const string TableName = Constants.DatabaseSchema.Tables.RedirectUrl; diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/RelationDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/RelationDto.cs index 51c36126d5..a05fc94cd6 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/RelationDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/RelationDto.cs @@ -8,7 +8,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos; [TableName(Constants.DatabaseSchema.Tables.Relation)] [PrimaryKey("id")] [ExplicitColumns] -internal class RelationDto +internal sealed class RelationDto { [Column("id")] [PrimaryKeyColumn] diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/RelationTypeDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/RelationTypeDto.cs index adefd7ae38..3856d24ce2 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/RelationTypeDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/RelationTypeDto.cs @@ -7,7 +7,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos; [TableName(Constants.DatabaseSchema.Tables.RelationType)] [PrimaryKey("id")] [ExplicitColumns] -internal class RelationTypeDto +internal sealed class RelationTypeDto { public const int NodeIdSeed = 10; diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/ServerRegistrationDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/ServerRegistrationDto.cs index a91bfc6bd5..bc08d9a4a1 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/ServerRegistrationDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/ServerRegistrationDto.cs @@ -8,7 +8,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos; [TableName(Constants.DatabaseSchema.Tables.Server)] [PrimaryKey("id")] [ExplicitColumns] -internal class ServerRegistrationDto +internal sealed class ServerRegistrationDto { [Column("id")] [PrimaryKeyColumn(AutoIncrement = true)] diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/TagDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/TagDto.cs index d2a68cf971..628b08974c 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/TagDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/TagDto.cs @@ -7,7 +7,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos; [TableName(TableName)] [PrimaryKey("id")] [ExplicitColumns] -internal class TagDto +internal sealed class TagDto { public const string TableName = Constants.DatabaseSchema.Tables.Tag; diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/TagRelationshipDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/TagRelationshipDto.cs index f5f9fd0b38..627435b963 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/TagRelationshipDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/TagRelationshipDto.cs @@ -7,7 +7,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos; [TableName(TableName)] [PrimaryKey("nodeId", AutoIncrement = false)] [ExplicitColumns] -internal class TagRelationshipDto +internal sealed class TagRelationshipDto { public const string TableName = Constants.DatabaseSchema.Tables.TagRelationship; diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/TemplateDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/TemplateDto.cs index 4355a3c983..636e152bed 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/TemplateDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/TemplateDto.cs @@ -7,7 +7,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos; [TableName(Constants.DatabaseSchema.Tables.Template)] [PrimaryKey("pk")] [ExplicitColumns] -internal class TemplateDto +internal sealed class TemplateDto { [Column("pk")] [PrimaryKeyColumn] diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/TwoFactorLoginDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/TwoFactorLoginDto.cs index 760419a307..f40231cb6d 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/TwoFactorLoginDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/TwoFactorLoginDto.cs @@ -7,7 +7,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos; [TableName(TableName)] [ExplicitColumns] [PrimaryKey("Id")] -internal class TwoFactorLoginDto +internal sealed class TwoFactorLoginDto { public const string TableName = Constants.DatabaseSchema.Tables.TwoFactorLogin; diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/User2NodeNotifyDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/User2NodeNotifyDto.cs index a6aaba41ea..e25bad1f55 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/User2NodeNotifyDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/User2NodeNotifyDto.cs @@ -7,7 +7,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos; [TableName(Constants.DatabaseSchema.Tables.User2NodeNotify)] [PrimaryKey("userId", AutoIncrement = false)] [ExplicitColumns] -internal class User2NodeNotifyDto +internal sealed class User2NodeNotifyDto { [Column("userId")] [PrimaryKeyColumn(AutoIncrement = false, Name = "PK_umbracoUser2NodeNotify", OnColumns = "userId, nodeId, action")] diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/UserGroup2GranularPermissionDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/UserGroup2GranularPermissionDto.cs index 9a6ebe294c..68f2e35bcb 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/UserGroup2GranularPermissionDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/UserGroup2GranularPermissionDto.cs @@ -35,7 +35,7 @@ public class UserGroup2GranularPermissionDto // this is UserGroup2GranularPermissionDto + int ids // it is used for handling legacy cases where we use int Ids -internal class UserGroup2GranularPermissionWithIdsDto : UserGroup2GranularPermissionDto +internal sealed class UserGroup2GranularPermissionWithIdsDto : UserGroup2GranularPermissionDto { [Column("entityId")] public int EntityId { get; set; } diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/UserGroup2NodeDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/UserGroup2NodeDto.cs index 3c26abea76..afc21fb6f0 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/UserGroup2NodeDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/UserGroup2NodeDto.cs @@ -7,7 +7,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos; [Obsolete("Will be removed in Umbraco 18.")] [TableName(TableName)] [ExplicitColumns] -internal class UserGroup2NodeDto +internal sealed class UserGroup2NodeDto { public const string TableName = Constants.DatabaseSchema.Tables.UserGroup2Node; diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/UserLoginDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/UserLoginDto.cs index bf52e3fd9c..1c6d2d3464 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/UserLoginDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/UserLoginDto.cs @@ -7,7 +7,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos; [TableName(TableName)] [PrimaryKey("sessionId", AutoIncrement = false)] [ExplicitColumns] -internal class UserLoginDto +internal sealed class UserLoginDto { public const string TableName = Constants.DatabaseSchema.Tables.UserLogin; diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/UserNotificationDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/UserNotificationDto.cs index 327bb69b63..53242be6cb 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/UserNotificationDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/UserNotificationDto.cs @@ -2,7 +2,7 @@ using NPoco; namespace Umbraco.Cms.Infrastructure.Persistence.Dtos; -internal class UserNotificationDto +internal sealed class UserNotificationDto { [Column("nodeId")] public int NodeId { get; set; } diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/WebhookDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/WebhookDto.cs index dac753fb06..0851d40aad 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/WebhookDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/WebhookDto.cs @@ -8,7 +8,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos; [TableName(Constants.DatabaseSchema.Tables.Webhook)] [PrimaryKey("id")] [ExplicitColumns] -internal class WebhookDto +internal sealed class WebhookDto { [Column("id")] [PrimaryKeyColumn(AutoIncrement = true)] diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/WebhookLogDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/WebhookLogDto.cs index d5de4bd008..fe02955e07 100644 --- a/src/Umbraco.Infrastructure/Persistence/Dtos/WebhookLogDto.cs +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/WebhookLogDto.cs @@ -7,7 +7,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos; [TableName(Constants.DatabaseSchema.Tables.WebhookLog)] [PrimaryKey("id")] [ExplicitColumns] -internal class WebhookLogDto +internal sealed class WebhookLogDto { [Column("id")] [PrimaryKeyColumn(AutoIncrement = true)] diff --git a/src/Umbraco.Infrastructure/Persistence/Factories/ContentBaseFactory.cs b/src/Umbraco.Infrastructure/Persistence/Factories/ContentBaseFactory.cs index ffcc6447eb..01817252dc 100644 --- a/src/Umbraco.Infrastructure/Persistence/Factories/ContentBaseFactory.cs +++ b/src/Umbraco.Infrastructure/Persistence/Factories/ContentBaseFactory.cs @@ -6,7 +6,7 @@ using Umbraco.Cms.Infrastructure.Persistence.Dtos; namespace Umbraco.Cms.Infrastructure.Persistence.Factories; -internal class ContentBaseFactory +internal sealed class ContentBaseFactory { /// /// Builds an IContent item from a dto and content type. diff --git a/src/Umbraco.Infrastructure/Persistence/FaultHandling/RetryDbConnection.cs b/src/Umbraco.Infrastructure/Persistence/FaultHandling/RetryDbConnection.cs index c6a3976637..8e0820c833 100644 --- a/src/Umbraco.Infrastructure/Persistence/FaultHandling/RetryDbConnection.cs +++ b/src/Umbraco.Infrastructure/Persistence/FaultHandling/RetryDbConnection.cs @@ -87,7 +87,7 @@ public class RetryDbConnection : DbConnection OnStateChange(stateChangeEventArguments); } -internal class FaultHandlingDbCommand : DbCommand +internal sealed class FaultHandlingDbCommand : DbCommand { private readonly RetryPolicy _cmdRetryPolicy; private RetryDbConnection _connection; diff --git a/src/Umbraco.Infrastructure/Persistence/Querying/CachedExpression.cs b/src/Umbraco.Infrastructure/Persistence/Querying/CachedExpression.cs index 2f3041fb33..da50695064 100644 --- a/src/Umbraco.Infrastructure/Persistence/Querying/CachedExpression.cs +++ b/src/Umbraco.Infrastructure/Persistence/Querying/CachedExpression.cs @@ -5,7 +5,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Querying; /// /// Represents an expression which caches the visitor's result. /// -internal class CachedExpression : Expression +internal sealed class CachedExpression : Expression { private string _visitResult = null!; diff --git a/src/Umbraco.Infrastructure/Persistence/Querying/ModelToSqlExpressionVisitor.cs b/src/Umbraco.Infrastructure/Persistence/Querying/ModelToSqlExpressionVisitor.cs index 4c1044a411..42eb5e265c 100644 --- a/src/Umbraco.Infrastructure/Persistence/Querying/ModelToSqlExpressionVisitor.cs +++ b/src/Umbraco.Infrastructure/Persistence/Querying/ModelToSqlExpressionVisitor.cs @@ -10,7 +10,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Querying; /// based on Umbraco's business logic models. /// /// This object is stateful and cannot be re-used to parse an expression. -internal class ModelToSqlExpressionVisitor : ExpressionVisitorBase +internal sealed class ModelToSqlExpressionVisitor : ExpressionVisitorBase { private readonly BaseMapper? _mapper; private readonly IMapperCollection? _mappers; diff --git a/src/Umbraco.Infrastructure/Persistence/Querying/PocoToSqlExpressionVisitor.cs b/src/Umbraco.Infrastructure/Persistence/Querying/PocoToSqlExpressionVisitor.cs index f7aba72bf0..8ed39c6c10 100644 --- a/src/Umbraco.Infrastructure/Persistence/Querying/PocoToSqlExpressionVisitor.cs +++ b/src/Umbraco.Infrastructure/Persistence/Querying/PocoToSqlExpressionVisitor.cs @@ -9,7 +9,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Querying; /// /// The type of the DTO. /// This visitor is stateful and cannot be reused. -internal class PocoToSqlExpressionVisitor : ExpressionVisitorBase +internal sealed class PocoToSqlExpressionVisitor : ExpressionVisitorBase { private readonly string? _alias; private readonly PocoData _pd; @@ -96,7 +96,7 @@ internal class PocoToSqlExpressionVisitor : ExpressionVisitorBase return Visited ? string.Empty : "@" + (SqlParameters.Count - 1); } - protected virtual string GetFieldName(PocoData pocoData, string name, string? alias) + private string GetFieldName(PocoData pocoData, string name, string? alias) { KeyValuePair column = pocoData.Columns.FirstOrDefault(x => x.Value.MemberInfoData.Name == name); @@ -113,7 +113,7 @@ internal class PocoToSqlExpressionVisitor : ExpressionVisitorBase /// The type of DTO 1. /// The type of DTO 2. /// This visitor is stateful and cannot be reused. -internal class PocoToSqlExpressionVisitor : ExpressionVisitorBase +internal sealed class PocoToSqlExpressionVisitor : ExpressionVisitorBase { private readonly string? _alias1; private readonly string? _alias2; @@ -194,7 +194,7 @@ internal class PocoToSqlExpressionVisitor : ExpressionVisitorBase return Visited ? string.Empty : "@" + (SqlParameters.Count - 1); } - protected virtual string GetFieldName(PocoData pocoData, string name, string? alias) + private string GetFieldName(PocoData pocoData, string name, string? alias) { KeyValuePair column = pocoData.Columns.FirstOrDefault(x => x.Value.MemberInfoData.Name == name); @@ -212,7 +212,7 @@ internal class PocoToSqlExpressionVisitor : ExpressionVisitorBase /// The type of DTO 2. /// The type of DTO 3. /// This visitor is stateful and cannot be reused. -internal class PocoToSqlExpressionVisitor : ExpressionVisitorBase +internal sealed class PocoToSqlExpressionVisitor : ExpressionVisitorBase { private readonly string? _alias1; private readonly string? _alias2; @@ -309,7 +309,7 @@ internal class PocoToSqlExpressionVisitor : ExpressionVisit return Visited ? string.Empty : "@" + (SqlParameters.Count - 1); } - protected virtual string GetFieldName(PocoData pocoData, string name, string? alias) + private string GetFieldName(PocoData pocoData, string name, string? alias) { KeyValuePair column = pocoData.Columns.FirstOrDefault(x => x.Value.MemberInfoData.Name == name); diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/AuditEntryRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/AuditEntryRepository.cs index eab408823e..acaa37ba1b 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/AuditEntryRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/AuditEntryRepository.cs @@ -16,7 +16,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement; /// /// Represents the NPoco implementation of . /// -internal class AuditEntryRepository : EntityRepositoryBase, IAuditEntryRepository +internal sealed class AuditEntryRepository : EntityRepositoryBase, IAuditEntryRepository { /// /// Initializes a new instance of the class. diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/AuditRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/AuditRepository.cs index e112e360d0..35aa220880 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/AuditRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/AuditRepository.cs @@ -12,7 +12,7 @@ using Umbraco.Extensions; namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement; -internal class AuditRepository : EntityRepositoryBase, IAuditRepository +internal sealed class AuditRepository : EntityRepositoryBase, IAuditRepository { public AuditRepository(IScopeAccessor scopeAccessor, ILogger logger) : base(scopeAccessor, AppCaches.NoCache, logger) diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/CacheInstructionRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/CacheInstructionRepository.cs index 208d0928a3..9356ee1a7d 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/CacheInstructionRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/CacheInstructionRepository.cs @@ -11,7 +11,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement; /// /// Represents the NPoco implementation of . /// -internal class CacheInstructionRepository : ICacheInstructionRepository +internal sealed class CacheInstructionRepository : ICacheInstructionRepository { private readonly IScopeAccessor _scopeAccessor; diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ConsentRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ConsentRepository.cs index 74f3a419e5..c211bc590d 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ConsentRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ConsentRepository.cs @@ -15,7 +15,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement; /// /// Represents the NPoco implementation of . /// -internal class ConsentRepository : EntityRepositoryBase, IConsentRepository +internal sealed class ConsentRepository : EntityRepositoryBase, IConsentRepository { /// /// Initializes a new instance of the class. diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentRepositoryBase.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentRepositoryBase.cs index ce30372d35..bc5b2c7954 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentRepositoryBase.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentRepositoryBase.cs @@ -1231,7 +1231,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement } } - private class NodeIdKey + private sealed class NodeIdKey { [Column("id")] public int NodeId { get; set; } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeCommonRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeCommonRepository.cs index edb5d9e617..f4b041b629 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeCommonRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeCommonRepository.cs @@ -16,7 +16,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement; /// /// Implements . /// -internal class ContentTypeCommonRepository : IContentTypeCommonRepository +internal sealed class ContentTypeCommonRepository : IContentTypeCommonRepository { private const string CacheKey = "Umbraco.Core.Persistence.Repositories.Implement.ContentTypeCommonRepository::AllTypes"; @@ -369,7 +369,7 @@ internal class ContentTypeCommonRepository : IContentTypeCommonRepository } } - private PropertyGroup MapPropertyGroup(PropertyTypeGroupDto dto, bool isPublishing) => + private static PropertyGroup MapPropertyGroup(PropertyTypeGroupDto dto, bool isPublishing) => new(new PropertyTypeCollection(isPublishing)) { Id = dto.Id, diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepository.cs index e1672beda9..eece5ab48f 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepository.cs @@ -18,7 +18,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement; /// /// Represents a repository for doing CRUD operations for /// -internal class ContentTypeRepository : ContentTypeRepositoryBase, IContentTypeRepository +internal sealed class ContentTypeRepository : ContentTypeRepositoryBase, IContentTypeRepository { public ContentTypeRepository( IScopeAccessor scopeAccessor, diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs index ae843ddfad..d9dc0434be 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs @@ -1593,7 +1593,7 @@ WHERE {Constants.DatabaseSchema.Tables.Content}.nodeId IN (@ids) AND cmsContentT ?? Array.Empty<(TEntity, int)>(); } - private class NameCompareDto + private sealed class NameCompareDto { public int NodeId { get; set; } @@ -1612,7 +1612,7 @@ WHERE {Constants.DatabaseSchema.Tables.Content}.nodeId IN (@ids) AND cmsContentT public bool Edited { get; set; } } - private class PropertyValueVersionDto + private sealed class PropertyValueVersionDto { private decimal? _decimalValue; diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DataTypeContainerRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DataTypeContainerRepository.cs index c7321063ad..33d7201b31 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DataTypeContainerRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DataTypeContainerRepository.cs @@ -6,7 +6,7 @@ using Umbraco.Cms.Infrastructure.Scoping; namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement; -internal class DataTypeContainerRepository : EntityContainerRepository, IDataTypeContainerRepository +internal sealed class DataTypeContainerRepository : EntityContainerRepository, IDataTypeContainerRepository { public DataTypeContainerRepository( IScopeAccessor scopeAccessor, @@ -15,5 +15,4 @@ internal class DataTypeContainerRepository : EntityContainerRepository, IDataTyp : base(scopeAccessor, cache, logger, Constants.ObjectTypes.DataTypeContainer) { } - } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DataTypeRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DataTypeRepository.cs index a8f6031ca8..6dc12aa658 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DataTypeRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DataTypeRepository.cs @@ -1,7 +1,5 @@ using System.Data; using System.Globalization; -using System.Linq.Expressions; -using System.Reflection; using Microsoft.Extensions.Logging; using NPoco; using Umbraco.Cms.Core; @@ -16,7 +14,6 @@ using Umbraco.Cms.Core.Serialization; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Infrastructure.Persistence.Dtos; using Umbraco.Cms.Infrastructure.Persistence.Factories; -using Umbraco.Cms.Infrastructure.Persistence.Mappers; using Umbraco.Cms.Infrastructure.Persistence.Querying; using Umbraco.Cms.Infrastructure.Scoping; using Umbraco.Extensions; @@ -27,7 +24,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement; /// /// Represents a repository for doing CRUD operations for /// -internal class DataTypeRepository : EntityRepositoryBase, IDataTypeRepository +internal sealed class DataTypeRepository : EntityRepositoryBase, IDataTypeRepository { private readonly ILogger _dataTypeLogger; private readonly PropertyEditorCollection _editors; @@ -234,7 +231,7 @@ internal class DataTypeRepository : EntityRepositoryBase, IDataT } [TableName(Constants.DatabaseSchema.Tables.ContentType)] - private class ContentTypeReferenceDto : ContentTypeDto + private sealed class ContentTypeReferenceDto : ContentTypeDto { [ResultColumn] [Reference(ReferenceType.Many)] @@ -242,7 +239,7 @@ internal class DataTypeRepository : EntityRepositoryBase, IDataT } [TableName(Constants.DatabaseSchema.Tables.PropertyType)] - private class PropertyTypeReferenceDto + private sealed class PropertyTypeReferenceDto { [Column("ptAlias")] public string? Alias { get; set; } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DictionaryRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DictionaryRepository.cs index fc6c380dac..b8215b40ed 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DictionaryRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DictionaryRepository.cs @@ -17,7 +17,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement; /// /// Represents a repository for doing CRUD operations for /// -internal class DictionaryRepository : EntityRepositoryBase, IDictionaryRepository +internal sealed class DictionaryRepository : EntityRepositoryBase, IDictionaryRepository { private readonly ILoggerFactory _loggerFactory; private readonly ILanguageRepository _languageRepository; @@ -128,7 +128,7 @@ internal class DictionaryRepository : EntityRepositoryBase return new SingleItemsOnlyRepositoryCachePolicy(GlobalIsolatedCache, ScopeAccessor, options); } - private IDictionaryItem ConvertFromDto(DictionaryDto dto, IDictionary languagesById) + private static IDictionaryItem ConvertFromDto(DictionaryDto dto, IDictionary languagesById) { IDictionaryItem entity = DictionaryItemFactory.BuildEntity(dto); @@ -174,14 +174,14 @@ internal class DictionaryRepository : EntityRepositoryBase return Get(query); } - private class DictionaryItemKeyIdDto + private sealed class DictionaryItemKeyIdDto { public string Key { get; } = null!; public Guid Id { get; set; } } - private class DictionaryByUniqueIdRepository : SimpleGetRepository + private sealed class DictionaryByUniqueIdRepository : SimpleGetRepository { private readonly DictionaryRepository _dictionaryRepository; private readonly IDictionary _languagesById; @@ -204,7 +204,7 @@ internal class DictionaryRepository : EntityRepositoryBase "cmsDictionary." + SqlSyntax.GetQuotedColumnName("id") + " = @id"; protected override IDictionaryItem ConvertToEntity(DictionaryDto dto) => - _dictionaryRepository.ConvertFromDto(dto, _languagesById); + ConvertFromDto(dto, _languagesById); protected override object GetBaseWhereClauseArguments(Guid id) => new { id }; @@ -236,7 +236,7 @@ internal class DictionaryRepository : EntityRepositoryBase } } - private class DictionaryByKeyRepository : SimpleGetRepository + private sealed class DictionaryByKeyRepository : SimpleGetRepository { private readonly DictionaryRepository _dictionaryRepository; private readonly IDictionary _languagesById; @@ -259,7 +259,7 @@ internal class DictionaryRepository : EntityRepositoryBase "cmsDictionary." + SqlSyntax.GetQuotedColumnName("key") + " = @id"; protected override IDictionaryItem ConvertToEntity(DictionaryDto dto) => - _dictionaryRepository.ConvertFromDto(dto, _languagesById); + ConvertFromDto(dto, _languagesById); protected override object GetBaseWhereClauseArguments(string? id) => new { id }; diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentBlueprintContainerRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentBlueprintContainerRepository.cs index 720f94d04e..fd66e01ec0 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentBlueprintContainerRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentBlueprintContainerRepository.cs @@ -6,7 +6,7 @@ using Umbraco.Cms.Infrastructure.Scoping; namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement; -internal class DocumentBlueprintContainerRepository : EntityContainerRepository, IDocumentBlueprintContainerRepository +internal sealed class DocumentBlueprintContainerRepository : EntityContainerRepository, IDocumentBlueprintContainerRepository { public DocumentBlueprintContainerRepository( IScopeAccessor scopeAccessor, diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentBlueprintRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentBlueprintRepository.cs index 5bd2844405..87509a1cf4 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentBlueprintRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentBlueprintRepository.cs @@ -20,7 +20,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement; /// perform a lot of the underlying logic. /// TODO: Create a helper method to contain most of the underlying logic for the ContentRepository /// -internal class DocumentBlueprintRepository : DocumentRepository, IDocumentBlueprintRepository +internal sealed class DocumentBlueprintRepository : DocumentRepository, IDocumentBlueprintRepository { public DocumentBlueprintRepository( IScopeAccessor scopeAccessor, diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentRepository.cs index 1b4f2b1efd..687a878c83 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentRepository.cs @@ -576,14 +576,14 @@ public class DocumentRepository : ContentRepositoryBase IRepository -> IReadRepository which should all be separate things! // This sub-repository pattern is super old and totally unecessary anymore, caching can be handled in much nicer ways without this - private class ContentByGuidReadRepository : EntityRepositoryBase + private sealed class ContentByGuidReadRepository : EntityRepositoryBase { private readonly DocumentRepository _outerRepo; @@ -1821,7 +1821,7 @@ public class DocumentRepository : ContentRepositoryBase logger) : base(scopeAccessor, cache, logger, Constants.ObjectTypes.DocumentTypeContainer) diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentVersionRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentVersionRepository.cs index ef9dd67520..2f2ac7b368 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentVersionRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DocumentVersionRepository.cs @@ -9,7 +9,7 @@ using Umbraco.Extensions; namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement; -internal class DocumentVersionRepository : IDocumentVersionRepository +internal sealed class DocumentVersionRepository : IDocumentVersionRepository { private readonly IScopeAccessor _scopeAccessor; diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DomainRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DomainRepository.cs index b1ab5f9437..810dd5fe38 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DomainRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DomainRepository.cs @@ -13,7 +13,7 @@ using Umbraco.Extensions; namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement; -internal class DomainRepository : EntityRepositoryBase, IDomainRepository +internal sealed class DomainRepository : EntityRepositoryBase, IDomainRepository { public DomainRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger) diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/EntityRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/EntityRepository.cs index 5e107bd71d..c39545f6be 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/EntityRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/EntityRepository.cs @@ -21,7 +21,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement; /// Limited to objects that have a corresponding node (in umbracoNode table). /// Returns objects, i.e. lightweight representation of entities. /// -internal class EntityRepository : RepositoryBase, IEntityRepositoryExtended +internal sealed class EntityRepository : RepositoryBase, IEntityRepositoryExtended { public EntityRepository(IScopeAccessor scopeAccessor, AppCaches appCaches) : base(scopeAccessor, appCaches) @@ -782,7 +782,7 @@ internal class EntityRepository : RepositoryBase, IEntityRepositoryExtended /// /// The DTO used to fetch results for a generic content item which could be either a document, media or a member /// - private class GenericContentEntityDto : DocumentEntityDto + private sealed class GenericContentEntityDto : DocumentEntityDto { public string? MediaPath { get; set; } } @@ -801,7 +801,7 @@ internal class EntityRepository : RepositoryBase, IEntityRepositoryExtended /// /// The DTO used to fetch results for a media item with its media path info /// - private class MediaEntityDto : BaseDto + private sealed class MediaEntityDto : BaseDto { public string? MediaPath { get; set; } } @@ -809,7 +809,7 @@ internal class EntityRepository : RepositoryBase, IEntityRepositoryExtended /// /// The DTO used to fetch results for a member item /// - private class MemberEntityDto : BaseDto + private sealed class MemberEntityDto : BaseDto { } @@ -917,7 +917,7 @@ internal class EntityRepository : RepositoryBase, IEntityRepositoryExtended entity.ListViewKey = dto.ListView; } - private MediaEntitySlim BuildMediaEntity(BaseDto dto) + private static MediaEntitySlim BuildMediaEntity(BaseDto dto) { // EntitySlim does not track changes var entity = new MediaEntitySlim(); @@ -936,7 +936,7 @@ internal class EntityRepository : RepositoryBase, IEntityRepositoryExtended return entity; } - private DocumentEntitySlim BuildDocumentEntity(BaseDto dto) + private static DocumentEntitySlim BuildDocumentEntity(BaseDto dto) { // EntitySlim does not track changes var entity = new DocumentEntitySlim(); @@ -953,7 +953,7 @@ internal class EntityRepository : RepositoryBase, IEntityRepositoryExtended return entity; } - private MemberEntitySlim BuildMemberEntity(BaseDto dto) + private static MemberEntitySlim BuildMemberEntity(BaseDto dto) { // EntitySlim does not track changes var entity = new MemberEntitySlim(); diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ExternalLoginRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ExternalLoginRepository.cs index 1ba91ab3e1..fd64293b7a 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ExternalLoginRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ExternalLoginRepository.cs @@ -14,7 +14,7 @@ using Umbraco.Extensions; namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement; -internal class ExternalLoginRepository : EntityRepositoryBase, IExternalLoginWithKeyRepository +internal sealed class ExternalLoginRepository : EntityRepositoryBase, IExternalLoginWithKeyRepository { public ExternalLoginRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) @@ -263,7 +263,7 @@ internal class ExternalLoginRepository : EntityRepositoryBase ConvertFromDtos(IEnumerable dtos) + private static IEnumerable ConvertFromDtos(IEnumerable dtos) { foreach (IIdentityUserLogin entity in dtos.Select(ExternalLoginFactory.BuildEntity)) { diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/KeyValueRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/KeyValueRepository.cs index c7259df863..1d1a07802a 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/KeyValueRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/KeyValueRepository.cs @@ -12,7 +12,7 @@ using Umbraco.Extensions; namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement; -internal class KeyValueRepository : EntityRepositoryBase, IKeyValueRepository +internal sealed class KeyValueRepository : EntityRepositoryBase, IKeyValueRepository { public KeyValueRepository(IScopeAccessor scopeAccessor, ILogger logger) : base(scopeAccessor, AppCaches.NoCache, logger) diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/LanguageRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/LanguageRepository.cs index 5097c99fa4..cc78a4f648 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/LanguageRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/LanguageRepository.cs @@ -16,7 +16,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement; /// /// Represents a repository for doing CRUD operations for /// -internal class LanguageRepository : EntityRepositoryBase, ILanguageRepository +internal sealed class LanguageRepository : EntityRepositoryBase, ILanguageRepository { // We need to lock this dictionary every time we do an operation on it as the languageRepository is registered as a unique implementation // It is used to quickly get isoCodes by Id, or the reverse by avoiding (deep)cloning dtos diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/LocalFileSystemTemporaryFileRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/LocalFileSystemTemporaryFileRepository.cs index 94cb6a9bf0..0190cd2034 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/LocalFileSystemTemporaryFileRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/LocalFileSystemTemporaryFileRepository.cs @@ -158,7 +158,7 @@ internal sealed class LocalFileSystemTemporaryFileRepository : ITemporaryFileRep throw new InvalidOperationException("Unexpected content"); } - private class FileMetaData + private sealed class FileMetaData { public DateTime AvailableUntil { get; init; } } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/LogViewerQueryRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/LogViewerQueryRepository.cs index a00c35de6d..cd2cb7631e 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/LogViewerQueryRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/LogViewerQueryRepository.cs @@ -12,7 +12,7 @@ using Umbraco.Extensions; namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement; -internal class LogViewerQueryRepository : EntityRepositoryBase, ILogViewerQueryRepository +internal sealed class LogViewerQueryRepository : EntityRepositoryBase, ILogViewerQueryRepository { public LogViewerQueryRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger) @@ -101,14 +101,14 @@ internal class LogViewerQueryRepository : EntityRepositoryBase x.Id == id); - private ILogViewerQuery ConvertFromDto(LogViewerQueryDto dto) + private static ILogViewerQuery ConvertFromDto(LogViewerQueryDto dto) { var factory = new LogViewerQueryModelFactory(); ILogViewerQuery entity = factory.BuildEntity(dto); return entity; } - internal class LogViewerQueryModelFactory + internal sealed class LogViewerQueryModelFactory { public ILogViewerQuery BuildEntity(LogViewerQueryDto dto) { diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaRepository.cs index 2f037653a7..1b4dd2d8a9 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaRepository.cs @@ -522,7 +522,7 @@ public class MediaRepository : ContentRepositoryBase IRepository -> IReadRepository which should all be separate things! // This sub-repository pattern is super old and totally unecessary anymore, caching can be handled in much nicer ways without this - private class MediaByGuidReadRepository : EntityRepositoryBase + private sealed class MediaByGuidReadRepository : EntityRepositoryBase { private readonly MediaRepository _outerRepo; diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaTypeContainerRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaTypeContainerRepository.cs index 260cebef9f..9efd67f3aa 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaTypeContainerRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaTypeContainerRepository.cs @@ -6,7 +6,7 @@ using Umbraco.Cms.Infrastructure.Scoping; namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement; -internal class MediaTypeContainerRepository : EntityContainerRepository, IMediaTypeContainerRepository +internal sealed class MediaTypeContainerRepository : EntityContainerRepository, IMediaTypeContainerRepository { public MediaTypeContainerRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger, Constants.ObjectTypes.MediaTypeContainer) diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaTypeRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaTypeRepository.cs index 792e984387..9c7e22fa4d 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaTypeRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MediaTypeRepository.cs @@ -17,7 +17,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement; /// /// Represents a repository for doing CRUD operations for /// -internal class MediaTypeRepository : ContentTypeRepositoryBase, IMediaTypeRepository +internal sealed class MediaTypeRepository : ContentTypeRepositoryBase, IMediaTypeRepository { public MediaTypeRepository( IScopeAccessor scopeAccessor, diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberGroupRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberGroupRepository.cs index 96d797b057..9ae8df942a 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberGroupRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberGroupRepository.cs @@ -15,7 +15,7 @@ using Umbraco.Extensions; namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement; -internal class MemberGroupRepository : EntityRepositoryBase, IMemberGroupRepository +internal sealed class MemberGroupRepository : EntityRepositoryBase, IMemberGroupRepository { private readonly IEventMessagesFactory _eventMessagesFactory; @@ -302,7 +302,7 @@ internal class MemberGroupRepository : EntityRepositoryBase, }); } - private class AssignedRolesDto + private sealed class AssignedRolesDto { [Column("text")] public string? RoleName { get; set; } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberTypeContainerRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberTypeContainerRepository.cs index e781521a77..15c99d879b 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberTypeContainerRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberTypeContainerRepository.cs @@ -9,7 +9,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement /// /// Introduced to avoid inconsistencies with nullability of dependencies for type repositories for content, media and members. /// - internal class MemberTypeContainerRepository : IMemberTypeContainerRepository + internal sealed class MemberTypeContainerRepository : IMemberTypeContainerRepository { public void Delete(EntityContainer entity) { diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberTypeRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberTypeRepository.cs index e764f54090..ffbe444f81 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberTypeRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/MemberTypeRepository.cs @@ -18,7 +18,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement; /// /// Represents a repository for doing CRUD operations for /// -internal class MemberTypeRepository : ContentTypeRepositoryBase, IMemberTypeRepository +internal sealed class MemberTypeRepository : ContentTypeRepositoryBase, IMemberTypeRepository { private readonly IShortStringHelper _shortStringHelper; diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PartialViewRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PartialViewRepository.cs index 7e4d5d6817..35b1b0e8ef 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PartialViewRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PartialViewRepository.cs @@ -6,7 +6,7 @@ using Umbraco.Extensions; namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement; -internal class PartialViewRepository : FileRepository, IPartialViewRepository +internal sealed class PartialViewRepository : FileRepository, IPartialViewRepository { public PartialViewRepository(FileSystems fileSystems) : base(fileSystems.PartialViewsFileSystem) diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PermissionRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PermissionRepository.cs index c99ac14fce..5a3de2ab14 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PermissionRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PermissionRepository.cs @@ -23,7 +23,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement; /// like the normal repository pattern but the standard repository Get commands don't apply and will throw /// /// -internal class PermissionRepository : EntityRepositoryBase +internal sealed class PermissionRepository : EntityRepositoryBase where TEntity : class, IEntity { public PermissionRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger> logger) diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PropertyTypeUsageRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PropertyTypeUsageRepository.cs index e2dcbf77c7..ab9a03bcef 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PropertyTypeUsageRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PropertyTypeUsageRepository.cs @@ -8,7 +8,7 @@ using Umbraco.Extensions; namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement; -internal class PropertyTypeUsageRepository : IPropertyTypeUsageRepository +internal sealed class PropertyTypeUsageRepository : IPropertyTypeUsageRepository { private static readonly Guid?[] NodeObjectTypes = new Guid?[] { diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PublicAccessRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PublicAccessRepository.cs index 2716df9315..aaeba86db6 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PublicAccessRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PublicAccessRepository.cs @@ -13,7 +13,7 @@ using Umbraco.Extensions; namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement; -internal class PublicAccessRepository : EntityRepositoryBase, IPublicAccessRepository +internal sealed class PublicAccessRepository : EntityRepositoryBase, IPublicAccessRepository { public PublicAccessRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger) diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RedirectUrlRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RedirectUrlRepository.cs index f598df7168..2a78775c77 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RedirectUrlRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RedirectUrlRepository.cs @@ -12,7 +12,7 @@ using Umbraco.Extensions; namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement; -internal class RedirectUrlRepository : EntityRepositoryBase, IRedirectUrlRepository +internal sealed class RedirectUrlRepository : EntityRepositoryBase, IRedirectUrlRepository { public RedirectUrlRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger) diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RelationRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RelationRepository.cs index 5c403445e0..8b3dc4a891 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RelationRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/RelationRepository.cs @@ -21,7 +21,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement; /// /// Represents a repository for doing CRUD operations for /// -internal class RelationRepository : EntityRepositoryBase, IRelationRepository +internal sealed class RelationRepository : EntityRepositoryBase, IRelationRepository { private readonly IEntityRepositoryExtended _entityRepository; private readonly IRelationTypeRepository _relationTypeRepository; @@ -227,7 +227,7 @@ internal class RelationRepository : EntityRepositoryBase, IRelat /// Used for joining the entity query with relations for the paging methods /// /// - private void SqlJoinRelations(Sql sql) + private static void SqlJoinRelations(Sql sql) { // add left joins for relation tables (this joins on both child or parent, so beware that this will normally return entities for // both sides of the relation type unless the IUmbracoEntity query passed in filters one side out). @@ -304,7 +304,7 @@ internal class RelationRepository : EntityRepositoryBase, IRelat } } - private void ApplyOrdering(ref Sql sql, Ordering ordering) + private static void ApplyOrdering(ref Sql sql, Ordering ordering) { if (sql == null) { @@ -458,7 +458,7 @@ internal class RelationRepository : EntityRepositoryBase, IRelat #endregion } -internal class RelationItemDto +internal sealed class RelationItemDto { [Column(Name = "nodeId")] public int ChildNodeId { get; set; } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ScriptRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ScriptRepository.cs index 3094d0d04e..0065c7ee30 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ScriptRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ScriptRepository.cs @@ -8,7 +8,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement; /// /// Represents the Script Repository /// -internal class ScriptRepository : FileRepository, IScriptRepository +internal sealed class ScriptRepository : FileRepository, IScriptRepository { public ScriptRepository(FileSystems fileSystems) : base(fileSystems.ScriptsFileSystem) diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ServerRegistrationRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ServerRegistrationRepository.cs index b758150de1..80a19793cf 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ServerRegistrationRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/ServerRegistrationRepository.cs @@ -11,7 +11,7 @@ using Umbraco.Extensions; namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement; -internal class ServerRegistrationRepository : EntityRepositoryBase, +internal sealed class ServerRegistrationRepository : EntityRepositoryBase, IServerRegistrationRepository { public ServerRegistrationRepository(IScopeAccessor scopeAccessor, ILogger logger) diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/SimilarNodeName.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/SimilarNodeName.cs index 9f4bc451c9..0139a52bb7 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/SimilarNodeName.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/SimilarNodeName.cs @@ -17,7 +17,7 @@ internal static class ListExtensions items.Any(x => x.Suffix.HasValue); } -internal class SimilarNodeName +internal sealed class SimilarNodeName { public int Id { get; set; } @@ -181,7 +181,7 @@ internal class SimilarNodeName return current; } - internal class StructuredName + internal sealed class StructuredName { internal const uint Initialsuffix = 1; private const string Spacecharacter = " "; diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/StylesheetRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/StylesheetRepository.cs index ca1f995e2b..51de577152 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/StylesheetRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/StylesheetRepository.cs @@ -8,7 +8,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement; /// /// Represents the Stylesheet Repository /// -internal class StylesheetRepository : FileRepository, IStylesheetRepository +internal sealed class StylesheetRepository : FileRepository, IStylesheetRepository { public StylesheetRepository(FileSystems fileSystems) : base(fileSystems.StylesheetsFileSystem) diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TagRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TagRepository.cs index d0d688d332..8107abc3ef 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TagRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TagRepository.cs @@ -15,7 +15,7 @@ using static Umbraco.Cms.Core.Persistence.SqlExtensionsStatics; namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement; -internal class TagRepository : EntityRepositoryBase, ITagRepository +internal sealed class TagRepository : EntityRepositoryBase, ITagRepository { public TagRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) : base(scopeAccessor, cache, logger) @@ -245,7 +245,7 @@ WHERE r.tagId IS NULL"; } // used to run Distinct() on tags - private class TagComparer : IEqualityComparer + private sealed class TagComparer : IEqualityComparer { public bool Equals(ITag? x, ITag? y) => ReferenceEquals(x, y) // takes care of both being null @@ -276,7 +276,7 @@ WHERE r.tagId IS NULL"; // ReSharper disable once ClassNeverInstantiated.Local // ReSharper disable UnusedAutoPropertyAccessor.Local - private class TaggedEntityDto + private sealed class TaggedEntityDto { public int NodeId { get; set; } public string? PropertyTypeAlias { get; set; } @@ -538,7 +538,7 @@ WHERE r.tagId IS NULL"; return sql; } - private Sql AddTagsSqlWhere(Sql sql, string? culture) + private static Sql AddTagsSqlWhere(Sql sql, string? culture) { if (culture == null) { @@ -557,7 +557,7 @@ WHERE r.tagId IS NULL"; private IEnumerable ExecuteTagsQuery(Sql sql) => Database.Fetch(sql).Select(TagFactory.BuildEntity); - private Guid GetNodeObjectType(TaggableObjectTypes type) + private static Guid GetNodeObjectType(TaggableObjectTypes type) { switch (type) { diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TemplateRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TemplateRepository.cs index 94f184c92d..f3433a564d 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TemplateRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TemplateRepository.cs @@ -22,9 +22,8 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement; /// /// Represents the Template Repository /// -internal class TemplateRepository : EntityRepositoryBase, ITemplateRepository +internal sealed class TemplateRepository : EntityRepositoryBase, ITemplateRepository { - private readonly IIOHelper _ioHelper; private readonly IShortStringHelper _shortStringHelper; private readonly IFileSystem? _viewsFileSystem; private readonly IViewHelper _viewHelper; @@ -35,13 +34,11 @@ internal class TemplateRepository : EntityRepositoryBase, ITempl AppCaches cache, ILogger logger, FileSystems fileSystems, - IIOHelper ioHelper, IShortStringHelper shortStringHelper, IViewHelper viewHelper, IOptionsMonitor runtimeSettings) : base(scopeAccessor, cache, logger) { - _ioHelper = ioHelper; _shortStringHelper = shortStringHelper; _viewsFileSystem = fileSystems.MvcViewsFileSystem; _viewHelper = viewHelper; @@ -208,7 +205,7 @@ internal class TemplateRepository : EntityRepositoryBase, ITempl return string.Empty; } - private string? GetFileContent(ITemplate template, IFileSystem? fs, string filename, bool init) + private static string? GetFileContent(ITemplate template, IFileSystem? fs, string filename, bool init) { // do not update .UpdateDate as that would make it dirty (side-effect) // unless initializing, because we have to do it once @@ -229,7 +226,7 @@ internal class TemplateRepository : EntityRepositoryBase, ITempl return init ? null : GetFileContent(fs, filename); } - private string? GetFileContent(IFileSystem? fs, string filename) + private static string? GetFileContent(IFileSystem? fs, string filename) { if (fs is null) { @@ -627,7 +624,7 @@ internal class TemplateRepository : EntityRepositoryBase, ITempl return descendants; } - private void AddChildren(ITemplate[]? all, List descendants, string masterAlias) + private static void AddChildren(ITemplate[]? all, List descendants, string masterAlias) { ITemplate[]? c = all?.Where(x => x.MasterTemplateAlias.InvariantEquals(masterAlias)).ToArray(); if (c is null || c.Any() == false) diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TrackedReferencesRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TrackedReferencesRepository.cs index c3ccb06e4f..34b74ae3f4 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TrackedReferencesRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TrackedReferencesRepository.cs @@ -12,7 +12,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement /// /// Implements to provide database access for tracked references." /// - internal class TrackedReferencesRepository : ITrackedReferencesRepository + internal sealed class TrackedReferencesRepository : ITrackedReferencesRepository { private readonly IScopeAccessor _scopeAccessor; private readonly IUmbracoMapper _umbracoMapper; @@ -402,7 +402,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement return innerUnionSql; } - private class UnionHelperDto + private sealed class UnionHelperDto { [Column("id")] public int Id { get; set; } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TwoFactorLoginRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TwoFactorLoginRepository.cs index 9467ec9be4..b5a049f0f4 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TwoFactorLoginRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/TwoFactorLoginRepository.cs @@ -12,7 +12,7 @@ using Umbraco.Extensions; namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement; -internal class TwoFactorLoginRepository : EntityRepositoryBase, ITwoFactorLoginRepository +internal sealed class TwoFactorLoginRepository : EntityRepositoryBase, ITwoFactorLoginRepository { public TwoFactorLoginRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger logger) diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/UserDataRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/UserDataRepository.cs index 85bcceb698..024a10dc12 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/UserDataRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/UserDataRepository.cs @@ -9,7 +9,7 @@ using Umbraco.Extensions; namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement; -internal class UserDataRepository : IUserDataRepository +internal sealed class UserDataRepository : IUserDataRepository { private readonly IScopeAccessor _scopeAccessor; @@ -75,7 +75,7 @@ internal class UserDataRepository : IUserDataRepository await _scopeAccessor.AmbientScope?.Database.ExecuteAsync(sql)!; } - private Sql ApplyFilter(Sql sql, IUserDataFilter filter) + private static Sql ApplyFilter(Sql sql, IUserDataFilter filter) { if (filter.Groups?.Count > 0) { @@ -95,10 +95,10 @@ internal class UserDataRepository : IUserDataRepository return sql; } - private IEnumerable DtosToModels(IEnumerable dtos) + private static IEnumerable DtosToModels(IEnumerable dtos) => dtos.Select(Map); - private IUserData Map(UserDataDto dto) + private static IUserData Map(UserDataDto dto) => new UserData { Key = dto.Key, @@ -108,7 +108,7 @@ internal class UserDataRepository : IUserDataRepository UserKey = dto.UserKey, }; - private UserDataDto Map(IUserData userData) + private static UserDataDto Map(IUserData userData) => new() { Key = userData.Key, diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/UserGroupRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/UserGroupRepository.cs index 1eb3fa47a7..8168e6d142 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/UserGroupRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/UserGroupRepository.cs @@ -183,7 +183,7 @@ public class UserGroupRepository : EntityRepositoryBase, IUserG /// /// used to persist a user group with associated users at once /// - private class UserGroupWithUsers : EntityBase + private sealed class UserGroupWithUsers : EntityBase { public UserGroupWithUsers(IUserGroup userGroup, int[]? userIds) { @@ -201,7 +201,7 @@ public class UserGroupRepository : EntityRepositoryBase, IUserG /// /// used to persist a user group with associated users at once /// - private class UserGroupWithUsersRepository : EntityRepositoryBase + private sealed class UserGroupWithUsersRepository : EntityRepositoryBase { private readonly UserGroupRepository _userGroupRepo; diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/UserRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/UserRepository.cs index 187d5c5ce2..c56c40e02e 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/UserRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/UserRepository.cs @@ -25,7 +25,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement; /// /// Represents the UserRepository for doing CRUD operations for /// -internal class UserRepository : EntityRepositoryBase, IUserRepository +internal sealed class UserRepository : EntityRepositoryBase, IUserRepository { private readonly IMapperCollection _mapperCollection; private readonly GlobalSettings _globalSettings; @@ -36,8 +36,6 @@ internal class UserRepository : EntityRepositoryBase, IUserReposito private bool _passwordConfigInitialized; private readonly Lock _sqliteValidateSessionLock = new(); private readonly IDictionary _permissionMappers; - private readonly IAppPolicyCache _globalCache; - private readonly IScopeAccessor _scopeAccessor; /// /// Initializes a new instance of the class. @@ -54,7 +52,6 @@ internal class UserRepository : EntityRepositoryBase, IUserReposito /// The JSON serializer. /// State of the runtime. /// The permission mappers. - /// The app policy cache. /// /// mapperCollection /// or @@ -71,18 +68,15 @@ internal class UserRepository : EntityRepositoryBase, IUserReposito IOptions passwordConfiguration, IJsonSerializer jsonSerializer, IRuntimeState runtimeState, - IEnumerable permissionMappers, - IAppPolicyCache globalCache) + IEnumerable permissionMappers) : base(scopeAccessor, appCaches, logger) { - _scopeAccessor = scopeAccessor; _mapperCollection = mapperCollection ?? throw new ArgumentNullException(nameof(mapperCollection)); _globalSettings = globalSettings.Value ?? throw new ArgumentNullException(nameof(globalSettings)); _passwordConfiguration = passwordConfiguration.Value ?? throw new ArgumentNullException(nameof(passwordConfiguration)); _jsonSerializer = jsonSerializer; _runtimeState = runtimeState; - _globalCache = globalCache; _permissionMappers = permissionMappers.ToDictionary(x => x.Context); } diff --git a/src/Umbraco.Infrastructure/Persistence/SqlSyntax/DbTypesFactory.cs b/src/Umbraco.Infrastructure/Persistence/SqlSyntax/DbTypesFactory.cs index 343e42d9c5..b1cfc9628c 100644 --- a/src/Umbraco.Infrastructure/Persistence/SqlSyntax/DbTypesFactory.cs +++ b/src/Umbraco.Infrastructure/Persistence/SqlSyntax/DbTypesFactory.cs @@ -2,7 +2,7 @@ using System.Data; namespace Umbraco.Cms.Infrastructure.Persistence.SqlSyntax; -internal class DbTypesFactory +internal sealed class DbTypesFactory { private readonly Dictionary _columnDbTypeMap = new(); private readonly Dictionary _columnTypeMap = new(); diff --git a/src/Umbraco.Infrastructure/Persistence/UmbracoPocoDataBuilder.cs b/src/Umbraco.Infrastructure/Persistence/UmbracoPocoDataBuilder.cs index 7b62c212e3..a8e47306dc 100644 --- a/src/Umbraco.Infrastructure/Persistence/UmbracoPocoDataBuilder.cs +++ b/src/Umbraco.Infrastructure/Persistence/UmbracoPocoDataBuilder.cs @@ -23,7 +23,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence; /// Beware, the application MUST restart when this class behavior changes. /// You can override the GetColmunnInfo method to control which columns this includes /// -internal class UmbracoPocoDataBuilder : PocoDataBuilder +internal sealed class UmbracoPocoDataBuilder : PocoDataBuilder { private readonly bool _upgrading; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/BlockGridConfigurationEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/BlockGridConfigurationEditor.cs index c89bdd6ca7..8da525ab8e 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/BlockGridConfigurationEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/BlockGridConfigurationEditor.cs @@ -5,7 +5,7 @@ using Umbraco.Cms.Core.IO; namespace Umbraco.Cms.Core.PropertyEditors; -internal class BlockGridConfigurationEditor : ConfigurationEditor +internal sealed class BlockGridConfigurationEditor : ConfigurationEditor { public BlockGridConfigurationEditor(IIOHelper ioHelper) : base(ioHelper) { diff --git a/src/Umbraco.Infrastructure/PropertyEditors/BlockGridPropertyEditorBase.cs b/src/Umbraco.Infrastructure/PropertyEditors/BlockGridPropertyEditorBase.cs index 1975faabc2..0f0a48e992 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/BlockGridPropertyEditorBase.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/BlockGridPropertyEditorBase.cs @@ -40,7 +40,7 @@ public abstract class BlockGridPropertyEditorBase : DataEditor protected override IDataValueEditor CreateValueEditor() => DataValueEditorFactory.Create(Attribute!); - internal class BlockGridEditorPropertyValueEditor : BlockEditorPropertyValueEditor + internal sealed class BlockGridEditorPropertyValueEditor : BlockEditorPropertyValueEditor { public BlockGridEditorPropertyValueEditor( DataEditorAttribute attribute, @@ -65,7 +65,7 @@ public abstract class BlockGridPropertyEditorBase : DataEditor protected override BlockGridValue CreateWithLayout(IEnumerable layout) => new(layout); - private class MinMaxValidator : BlockEditorMinMaxValidatorBase + private sealed class MinMaxValidator : BlockEditorMinMaxValidatorBase { private readonly BlockEditorValues _blockEditorValues; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/BlockListConfigurationEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/BlockListConfigurationEditor.cs index d20cffa933..f883820833 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/BlockListConfigurationEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/BlockListConfigurationEditor.cs @@ -6,7 +6,7 @@ using Umbraco.Cms.Core.Services; namespace Umbraco.Cms.Core.PropertyEditors; -internal class BlockListConfigurationEditor : ConfigurationEditor +internal sealed class BlockListConfigurationEditor : ConfigurationEditor { public BlockListConfigurationEditor(IIOHelper ioHelper) : base(ioHelper) diff --git a/src/Umbraco.Infrastructure/PropertyEditors/BlockListPropertyEditorBase.cs b/src/Umbraco.Infrastructure/PropertyEditors/BlockListPropertyEditorBase.cs index 8c3e54ce12..9deb400923 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/BlockListPropertyEditorBase.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/BlockListPropertyEditorBase.cs @@ -49,7 +49,7 @@ public abstract class BlockListPropertyEditorBase : DataEditor /// /// Defines the value editor for the block list property editors. /// - internal class BlockListEditorPropertyValueEditor : BlockEditorPropertyValueEditor + internal sealed class BlockListEditorPropertyValueEditor : BlockEditorPropertyValueEditor { /// /// Initializes a new instance of the class. @@ -85,7 +85,7 @@ public abstract class BlockListPropertyEditorBase : DataEditor /// /// Validates the min/max configuration for block list property editors. /// - private class MinMaxValidator : BlockEditorMinMaxValidatorBase + private sealed class MinMaxValidator : BlockEditorMinMaxValidatorBase { private readonly BlockEditorValues _blockEditorValues; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/BlockValuePropertyIndexValueFactory.cs b/src/Umbraco.Infrastructure/PropertyEditors/BlockValuePropertyIndexValueFactory.cs index 27f9d9b40a..d6b91d8a73 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/BlockValuePropertyIndexValueFactory.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/BlockValuePropertyIndexValueFactory.cs @@ -8,7 +8,7 @@ using Umbraco.Cms.Core.Serialization; namespace Umbraco.Cms.Core.PropertyEditors; -internal class BlockValuePropertyIndexValueFactory : +internal sealed class BlockValuePropertyIndexValueFactory : BlockValuePropertyIndexValueFactoryBase, IBlockValuePropertyIndexValueFactory { @@ -24,7 +24,7 @@ internal class BlockValuePropertyIndexValueFactory : => GetDataItems(input.ContentData, input.Expose, published); // we only care about the content data when extracting values for indexing - not the layouts nor the settings - internal class IndexValueFactoryBlockValue + internal sealed class IndexValueFactoryBlockValue { public List ContentData { get; set; } = new(); diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ColorPickerConfigurationEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/ColorPickerConfigurationEditor.cs index 0ce5f4bfdf..fe419a6566 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ColorPickerConfigurationEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ColorPickerConfigurationEditor.cs @@ -10,7 +10,7 @@ using Umbraco.Extensions; namespace Umbraco.Cms.Core.PropertyEditors; -internal class ColorPickerConfigurationEditor : ConfigurationEditor +internal sealed class ColorPickerConfigurationEditor : ConfigurationEditor { public ColorPickerConfigurationEditor(IIOHelper ioHelper, IConfigurationEditorJsonSerializer configurationEditorJsonSerializer) : base(ioHelper) @@ -19,7 +19,7 @@ internal class ColorPickerConfigurationEditor : ConfigurationEditor /// Defines the value editor for the color picker property editor. /// - internal class ColorPickerPropertyValueEditor : DataValueEditor + internal sealed class ColorPickerPropertyValueEditor : DataValueEditor { /// /// Initializes a new instance of the class. @@ -68,7 +68,7 @@ public class ColorPickerPropertyEditor : DataEditor /// /// Validates the color selection for the color picker property editor. /// - internal class ConfiguredColorValidator : IValueValidator + internal sealed class ConfiguredColorValidator : IValueValidator { private readonly ILocalizedTextService _localizedTextService; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/DropDownFlexibleConfigurationEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/DropDownFlexibleConfigurationEditor.cs index ef6e6c7808..4b7533eb86 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/DropDownFlexibleConfigurationEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/DropDownFlexibleConfigurationEditor.cs @@ -6,7 +6,7 @@ using Umbraco.Cms.Core.Serialization; namespace Umbraco.Cms.Core.PropertyEditors; -internal class DropDownFlexibleConfigurationEditor : ConfigurationEditor +internal sealed class DropDownFlexibleConfigurationEditor : ConfigurationEditor { public DropDownFlexibleConfigurationEditor(IIOHelper ioHelper, IConfigurationEditorJsonSerializer configurationEditorJsonSerializer) : base(ioHelper) diff --git a/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyValueEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyValueEditor.cs index 241c817cec..d839aefd3b 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyValueEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/FileUploadPropertyValueEditor.cs @@ -21,7 +21,7 @@ namespace Umbraco.Cms.Core.PropertyEditors; /// /// The value editor for the file upload property editor. /// -internal class FileUploadPropertyValueEditor : DataValueEditor +internal sealed class FileUploadPropertyValueEditor : DataValueEditor { private readonly MediaFileManager _mediaFileManager; private readonly ITemporaryFileService _temporaryFileService; @@ -159,7 +159,7 @@ internal class FileUploadPropertyValueEditor : DataValueEditor private TemporaryFileModel? TryGetTemporaryFile(Guid temporaryFileKey) => _temporaryFileService.GetAsync(temporaryFileKey).GetAwaiter().GetResult(); - private bool IsAllowedInDataTypeConfiguration(string extension, object? dataTypeConfiguration) + private static bool IsAllowedInDataTypeConfiguration(string extension, object? dataTypeConfiguration) { if (dataTypeConfiguration is FileUploadConfiguration fileUploadConfiguration) { @@ -207,7 +207,7 @@ internal class FileUploadPropertyValueEditor : DataValueEditor /// Provides media path. /// /// File system relative path - protected virtual string GetMediaPath(TemporaryFileModel file, object? dataTypeConfiguration, Guid contentKey, Guid propertyTypeKey) + private string GetMediaPath(TemporaryFileModel file, object? dataTypeConfiguration, Guid contentKey, Guid propertyTypeKey) { // in case we are using the old path scheme, try to re-use numbers (bah...) return _mediaFileManager.GetMediaPath(file.FileName, contentKey, propertyTypeKey); diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperConfigurationEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperConfigurationEditor.cs index 27c52f48b0..4dcee03929 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperConfigurationEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperConfigurationEditor.cs @@ -8,7 +8,7 @@ namespace Umbraco.Cms.Core.PropertyEditors; /// /// Represents the configuration editor for the image cropper value editor. /// -internal class ImageCropperConfigurationEditor : ConfigurationEditor +internal sealed class ImageCropperConfigurationEditor : ConfigurationEditor { public ImageCropperConfigurationEditor(IIOHelper ioHelper) : base(ioHelper) diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyEditor.cs index 46f02863a9..fe978283c4 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyEditor.cs @@ -290,7 +290,7 @@ public class ImageCropperPropertyEditor : DataEditor, IMediaUrlGenerator, } // for efficient value deserialization, we don't want to deserialize more than we need to (we don't need crops, focal point etc.) - private class LightWeightImageCropperValue + private sealed class LightWeightImageCropperValue { public string? Src { get; set; } = string.Empty; } diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyValueEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyValueEditor.cs index 28a3ec87bc..869f10eac7 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyValueEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyValueEditor.cs @@ -22,7 +22,7 @@ namespace Umbraco.Cms.Core.PropertyEditors; /// /// The value editor for the image cropper property editor. /// -internal class ImageCropperPropertyValueEditor : DataValueEditor // TODO: core vs web? +internal sealed class ImageCropperPropertyValueEditor : DataValueEditor // TODO: core vs web? { private readonly IDataTypeConfigurationCache _dataTypeConfigurationCache; private readonly IFileStreamSecurityValidator _fileStreamSecurityValidator; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/MediaPicker3PropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/MediaPicker3PropertyEditor.cs index f23ce49fe7..ae43c493ef 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/MediaPicker3PropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/MediaPicker3PropertyEditor.cs @@ -52,7 +52,7 @@ public class MediaPicker3PropertyEditor : DataEditor /// /// Defines the value editor for the media picker property editor. /// - internal class MediaPicker3PropertyValueEditor : DataValueEditor, IDataValueReference + internal sealed class MediaPicker3PropertyValueEditor : DataValueEditor, IDataValueReference { private readonly IDataTypeConfigurationCache _dataTypeReadCache; private readonly IJsonSerializer _jsonSerializer; @@ -257,7 +257,7 @@ public class MediaPicker3PropertyEditor : DataEditor /// /// Model/DTO that represents the JSON that the MediaPicker3 stores. /// - internal class MediaWithCropsDto + internal sealed class MediaWithCropsDto { /// /// Gets or sets the key. @@ -338,7 +338,7 @@ public class MediaPicker3PropertyEditor : DataEditor /// /// Validates the min/max configuration for the media picker property editor. /// - internal class MinMaxValidator : ITypedJsonValidator, MediaPicker3Configuration> + internal sealed class MinMaxValidator : ITypedJsonValidator, MediaPicker3Configuration> { private readonly ILocalizedTextService _localizedTextService; @@ -399,7 +399,7 @@ public class MediaPicker3PropertyEditor : DataEditor /// /// Validates the allowed type configuration for the media picker property editor. /// - internal class AllowedTypeValidator : ITypedJsonValidator, MediaPicker3Configuration> + internal sealed class AllowedTypeValidator : ITypedJsonValidator, MediaPicker3Configuration> { private readonly ILocalizedTextService _localizedTextService; private readonly IMediaTypeService _mediaTypeService; @@ -472,7 +472,7 @@ public class MediaPicker3PropertyEditor : DataEditor /// /// Validates the start node configuration for the media picker property editor. /// - internal class StartNodeValidator : ITypedJsonValidator, MediaPicker3Configuration> + internal sealed class StartNodeValidator : ITypedJsonValidator, MediaPicker3Configuration> { private readonly ILocalizedTextService _localizedTextService; private readonly IMediaNavigationQueryService _mediaNavigationQueryService; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/MultiNodeTreePickerPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/MultiNodeTreePickerPropertyEditor.cs index c69f55f187..75c9b045d8 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/MultiNodeTreePickerPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/MultiNodeTreePickerPropertyEditor.cs @@ -189,7 +189,7 @@ public class MultiNodeTreePickerPropertyEditor : DataEditor /// /// Validates the min/max configuration for the multi-node tree picker property editor. /// - internal class MinMaxValidator : ITypedJsonValidator + internal sealed class MinMaxValidator : ITypedJsonValidator { private readonly ILocalizedTextService _localizedTextService; @@ -247,7 +247,7 @@ public class MultiNodeTreePickerPropertyEditor : DataEditor /// /// Validates the selected object type for the multi-node tree picker property editor. /// - internal class ObjectTypeValidator : ITypedJsonValidator + internal sealed class ObjectTypeValidator : ITypedJsonValidator { private readonly ILocalizedTextService _localizedTextService; private readonly ICoreScopeProvider _coreScopeProvider; @@ -335,7 +335,7 @@ public class MultiNodeTreePickerPropertyEditor : DataEditor /// /// Validates the selected content type for the multi-node tree picker property editor. /// - internal class ContentTypeValidator : ITypedJsonValidator + internal sealed class ContentTypeValidator : ITypedJsonValidator { private readonly ILocalizedTextService _localizedTextService; private readonly ICoreScopeProvider _coreScopeProvider; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/MultiUrlPickerValueEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/MultiUrlPickerValueEditor.cs index 37697701c8..2f0a2b279b 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/MultiUrlPickerValueEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/MultiUrlPickerValueEditor.cs @@ -217,7 +217,7 @@ public class MultiUrlPickerValueEditor : DataValueEditor, IDataValueReference public string? QueryString { get; set; } } - internal class MinMaxValidator : ITypedJsonValidator + internal sealed class MinMaxValidator : ITypedJsonValidator { private readonly ILocalizedTextService _localizedTextService; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/MultipleTextStringConfigurationEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/MultipleTextStringConfigurationEditor.cs index 7b6eebff33..a6ab562b78 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/MultipleTextStringConfigurationEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/MultipleTextStringConfigurationEditor.cs @@ -9,7 +9,7 @@ namespace Umbraco.Cms.Core.PropertyEditors; /// /// Represents the configuration editor for a multiple textstring value editor. /// -internal class MultipleTextStringConfigurationEditor : ConfigurationEditor +internal sealed class MultipleTextStringConfigurationEditor : ConfigurationEditor { public MultipleTextStringConfigurationEditor(IIOHelper ioHelper) : base(ioHelper) diff --git a/src/Umbraco.Infrastructure/PropertyEditors/MultipleTextStringPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/MultipleTextStringPropertyEditor.cs index 714d1e624b..9c6daeb63f 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/MultipleTextStringPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/MultipleTextStringPropertyEditor.cs @@ -47,7 +47,7 @@ public class MultipleTextStringPropertyEditor : DataEditor /// /// Defines the value editor for the multiple text string property editor. /// - internal class MultipleTextStringPropertyValueEditor : DataValueEditor + internal sealed class MultipleTextStringPropertyValueEditor : DataValueEditor { private static readonly string _newLine = "\n"; private static readonly string[] _newLineDelimiters = { "\r\n", "\r", "\n" }; @@ -110,7 +110,7 @@ public class MultipleTextStringPropertyEditor : DataEditor /// /// A custom to check each string against the configured format. /// - internal class MultipleTextStringFormatValidator : IValueFormatValidator + internal sealed class MultipleTextStringFormatValidator : IValueFormatValidator { /// public IEnumerable ValidateFormat(object? value, string valueType, string format) @@ -137,7 +137,7 @@ public class MultipleTextStringPropertyEditor : DataEditor /// /// Validates the min/max configuration for the multiple text strings property editor. /// - internal class MinMaxValidator : IValueValidator + internal sealed class MinMaxValidator : IValueValidator { private readonly ILocalizedTextService _localizedTextService; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/RadioButtonsPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/RadioButtonsPropertyEditor.cs index 248457153e..cf2c4ad3fa 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/RadioButtonsPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/RadioButtonsPropertyEditor.cs @@ -48,7 +48,7 @@ public class RadioButtonsPropertyEditor : DataEditor /// /// Defines the value editor for the radio buttons property editor. /// - internal class RadioButtonsPropertyValueEditor : DataValueEditor + internal sealed class RadioButtonsPropertyValueEditor : DataValueEditor { /// /// Initializes a new instance of the class. @@ -66,7 +66,7 @@ public class RadioButtonsPropertyEditor : DataEditor /// /// Validates the prevalue configuration for the radio buttons property editor. /// - internal class RadioButtonValueValidator : IValueValidator + internal sealed class RadioButtonValueValidator : IValueValidator { private readonly ILocalizedTextService _localizedTextService; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/RichTextEditorBlockValidator.cs b/src/Umbraco.Infrastructure/PropertyEditors/RichTextEditorBlockValidator.cs index a11a11e703..f48a18c698 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/RichTextEditorBlockValidator.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/RichTextEditorBlockValidator.cs @@ -8,7 +8,7 @@ using Umbraco.Extensions; namespace Umbraco.Cms.Core.PropertyEditors; -internal class RichTextEditorBlockValidator: BlockEditorValidatorBase +internal sealed class RichTextEditorBlockValidator: BlockEditorValidatorBase { private readonly BlockEditorValues _blockEditorValues; private readonly IJsonSerializer _jsonSerializer; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/RichTextPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/RichTextPropertyEditor.cs index 7c9b26f343..f9be27e551 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/RichTextPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/RichTextPropertyEditor.cs @@ -89,7 +89,7 @@ public class RichTextPropertyEditor : DataEditor /// A custom value editor to ensure that images and blocks are parsed when being persisted and formatted correctly for /// display in the editor /// - internal class RichTextPropertyValueEditor : BlockValuePropertyValueEditorBase + internal sealed class RichTextPropertyValueEditor : BlockValuePropertyValueEditorBase { private readonly IBackOfficeSecurityAccessor _backOfficeSecurityAccessor; private readonly IHtmlSanitizer _htmlSanitizer; @@ -320,7 +320,7 @@ public class RichTextPropertyEditor : DataEditor return RichTextPropertyEditorHelper.SerializeRichTextEditorValue(mergedEditorValue, _jsonSerializer); } - private string MergeMarkupValue( + private static string MergeMarkupValue( string source, string target, RichTextBlockValue? mergedBlockValue, diff --git a/src/Umbraco.Infrastructure/PropertyEditors/RichTextPropertyIndexValueFactory.cs b/src/Umbraco.Infrastructure/PropertyEditors/RichTextPropertyIndexValueFactory.cs index 6013e6c4c2..8df3466e35 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/RichTextPropertyIndexValueFactory.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/RichTextPropertyIndexValueFactory.cs @@ -9,7 +9,7 @@ using Umbraco.Extensions; namespace Umbraco.Cms.Core.PropertyEditors; -internal class RichTextPropertyIndexValueFactory : BlockValuePropertyIndexValueFactoryBase, IRichTextPropertyIndexValueFactory +internal sealed class RichTextPropertyIndexValueFactory : BlockValuePropertyIndexValueFactoryBase, IRichTextPropertyIndexValueFactory { private readonly IJsonSerializer _jsonSerializer; private readonly ILogger _logger; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/SliderPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/SliderPropertyEditor.cs index 02e96d075a..7f38484f58 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/SliderPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/SliderPropertyEditor.cs @@ -48,7 +48,7 @@ public class SliderPropertyEditor : DataEditor /// /// Defines the value editor for the slider property editor. /// - internal class SliderPropertyValueEditor : DataValueEditor + internal sealed class SliderPropertyValueEditor : DataValueEditor { private readonly IJsonSerializer _jsonSerializer; @@ -99,7 +99,7 @@ public class SliderPropertyEditor : DataEditor /// /// Represents a slider value. /// - internal class SliderRange + internal sealed class SliderRange { /// /// Gets or sets the slider range from value. @@ -156,7 +156,7 @@ public class SliderPropertyEditor : DataEditor /// /// Parses a from the provided value. /// - protected bool TryParsePropertyValue(object? value, [NotNullWhen(true)] out SliderRange? parsedValue) + protected static bool TryParsePropertyValue(object? value, [NotNullWhen(true)] out SliderRange? parsedValue) { if (value is null || value is not JsonObject valueAsJsonObject) { @@ -188,7 +188,7 @@ public class SliderPropertyEditor : DataEditor /// /// Validates the range configuration for the slider property editor. /// - internal class RangeValidator : SliderPropertyConfigurationValidatorBase, IValueValidator + internal sealed class RangeValidator : SliderPropertyConfigurationValidatorBase, IValueValidator { /// /// Initializes a new instance of the class. @@ -230,7 +230,7 @@ public class SliderPropertyEditor : DataEditor /// /// Validates the min/max configuration for the slider property editor. /// - internal class MinMaxValidator : SliderPropertyConfigurationValidatorBase, IValueValidator + internal sealed class MinMaxValidator : SliderPropertyConfigurationValidatorBase, IValueValidator { /// /// Initializes a new instance of the class. @@ -272,7 +272,7 @@ public class SliderPropertyEditor : DataEditor /// /// Validates the step configuration for the slider property editor. /// - internal class StepValidator : SliderPropertyConfigurationValidatorBase, IValueValidator + internal sealed class StepValidator : SliderPropertyConfigurationValidatorBase, IValueValidator { /// /// Initializes a new instance of the class. diff --git a/src/Umbraco.Infrastructure/PropertyEditors/TagsPropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/TagsPropertyEditor.cs index 086e698f1a..ab56bc14ee 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/TagsPropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/TagsPropertyEditor.cs @@ -46,7 +46,7 @@ public class TagsPropertyEditor : DataEditor protected override IConfigurationEditor CreateConfigurationEditor() => new TagConfigurationEditor(_ioHelper); - internal class TagPropertyValueEditor : DataValueEditor, IDataValueTags + internal sealed class TagPropertyValueEditor : DataValueEditor, IDataValueTags { private readonly IJsonSerializer _jsonSerializer; private readonly IDataTypeService _dataTypeService; @@ -183,7 +183,7 @@ public class TagsPropertyEditor : DataEditor /// the underlying data is JSON. Yes, this makes little sense. /// /// - private class RequiredJsonValueValidator : IValueRequiredValidator + private sealed class RequiredJsonValueValidator : IValueRequiredValidator { /// public IEnumerable ValidateRequired(object? value, string valueType) diff --git a/src/Umbraco.Infrastructure/PropertyEditors/TrueFalsePropertyEditor.cs b/src/Umbraco.Infrastructure/PropertyEditors/TrueFalsePropertyEditor.cs index df63ee52d2..705b51befd 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/TrueFalsePropertyEditor.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/TrueFalsePropertyEditor.cs @@ -33,7 +33,7 @@ public class TrueFalsePropertyEditor : DataEditor /// /// Defines the value editor for the true/false (toggle) property editor. /// - internal class TrueFalsePropertyValueEditor : DataValueEditor + internal sealed class TrueFalsePropertyValueEditor : DataValueEditor { /// /// Initializes a new instance of the class. @@ -61,7 +61,7 @@ public class TrueFalsePropertyEditor : DataEditor public override object? FromEditor(ContentPropertyData editorValue, object? currentValue) => ParsePropertyValue(editorValue.Value) ? 1 : 0; - private bool ParsePropertyValue(object? value) + private static bool ParsePropertyValue(object? value) => value switch { bool booleanValue => booleanValue, diff --git a/src/Umbraco.Infrastructure/PropertyEditors/Validators/BlockListValueRequiredValidator.cs b/src/Umbraco.Infrastructure/PropertyEditors/Validators/BlockListValueRequiredValidator.cs index 40d67bb0d2..8cc23a5b2d 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/Validators/BlockListValueRequiredValidator.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/Validators/BlockListValueRequiredValidator.cs @@ -9,7 +9,7 @@ namespace Umbraco.Cms.Infrastructure.PropertyEditors.Validators; /// /// Custom validator for block value required validation. /// -internal class BlockListValueRequiredValidator : RequiredValidator +internal sealed class BlockListValueRequiredValidator : RequiredValidator { private readonly IJsonSerializer _jsonSerializer; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/Validators/RichTextRegexValidator.cs b/src/Umbraco.Infrastructure/PropertyEditors/Validators/RichTextRegexValidator.cs index 4e6a5c049e..3bed75e946 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/Validators/RichTextRegexValidator.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/Validators/RichTextRegexValidator.cs @@ -4,7 +4,7 @@ using Umbraco.Cms.Core.Serialization; namespace Umbraco.Cms.Core.PropertyEditors.Validators; -internal class RichTextRegexValidator : IRichTextRegexValidator +internal sealed class RichTextRegexValidator : IRichTextRegexValidator { private readonly RegexValidator _regexValidator; private readonly IJsonSerializer _jsonSerializer; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/Validators/RichTextRequiredValidator.cs b/src/Umbraco.Infrastructure/PropertyEditors/Validators/RichTextRequiredValidator.cs index 89f27f43ff..90d80c1e25 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/Validators/RichTextRequiredValidator.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/Validators/RichTextRequiredValidator.cs @@ -1,16 +1,15 @@ using System.ComponentModel.DataAnnotations; using Microsoft.Extensions.Logging; using Umbraco.Cms.Core.Serialization; -using Umbraco.Cms.Core.Services; namespace Umbraco.Cms.Core.PropertyEditors.Validators; -internal class RichTextRequiredValidator : RequiredValidator, IRichTextRequiredValidator +internal sealed class RichTextRequiredValidator : RequiredValidator, IRichTextRequiredValidator { private readonly IJsonSerializer _jsonSerializer; private readonly ILogger _logger; - public RichTextRequiredValidator(ILocalizedTextService textService, IJsonSerializer jsonSerializer, ILogger logger) : base() + public RichTextRequiredValidator(IJsonSerializer jsonSerializer, ILogger logger) : base() { _jsonSerializer = jsonSerializer; _logger = logger; diff --git a/src/Umbraco.Infrastructure/PropertyEditors/Validators/TrueFalseValueRequiredValidator.cs b/src/Umbraco.Infrastructure/PropertyEditors/Validators/TrueFalseValueRequiredValidator.cs index 3e1cdfd117..31200384ac 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/Validators/TrueFalseValueRequiredValidator.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/Validators/TrueFalseValueRequiredValidator.cs @@ -7,7 +7,7 @@ namespace Umbraco.Cms.Infrastructure.PropertyEditors.Validators; /// /// Custom validator for true/false (toggle) required validation. /// -internal class TrueFalseValueRequiredValidator : RequiredValidator +internal sealed class TrueFalseValueRequiredValidator : RequiredValidator { /// public override IEnumerable ValidateRequired(object? value, string? valueType) diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/BlockGridPropertyValueCreator.cs b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/BlockGridPropertyValueCreator.cs index 1cfef58b23..ea00423a7c 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/BlockGridPropertyValueCreator.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/BlockGridPropertyValueCreator.cs @@ -5,7 +5,7 @@ using Umbraco.Extensions; namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters; -internal class BlockGridPropertyValueCreator : BlockPropertyValueCreatorBase +internal sealed class BlockGridPropertyValueCreator : BlockPropertyValueCreatorBase { private readonly IJsonSerializer _jsonSerializer; private readonly BlockGridPropertyValueConstructorCache _constructorCache; @@ -68,7 +68,7 @@ internal class BlockGridPropertyValueCreator : BlockPropertyValueCreatorBase CreateBlockItemActivator() => new BlockGridItemActivator(BlockEditorConverter, _constructorCache); - private class BlockGridItemActivator : BlockItemActivator + private sealed class BlockGridItemActivator : BlockItemActivator { public BlockGridItemActivator(BlockEditorConverter blockConverter, BlockGridPropertyValueConstructorCache constructorCache) : base(blockConverter, constructorCache) diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/BlockListPropertyValueCreator.cs b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/BlockListPropertyValueCreator.cs index 5714256759..8180781af1 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/BlockListPropertyValueCreator.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/BlockListPropertyValueCreator.cs @@ -4,7 +4,7 @@ using Umbraco.Cms.Core.Serialization; namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters; -internal class BlockListPropertyValueCreator : BlockPropertyValueCreatorBase +internal sealed class BlockListPropertyValueCreator : BlockPropertyValueCreatorBase { private readonly IJsonSerializer _jsonSerializer; private readonly BlockListPropertyValueConstructorCache _constructorCache; @@ -36,7 +36,7 @@ internal class BlockListPropertyValueCreator : BlockPropertyValueCreatorBase CreateBlockItemActivator() => new BlockListItemActivator(BlockEditorConverter, _constructorCache); - private class BlockListItemActivator : BlockItemActivator + private sealed class BlockListItemActivator : BlockItemActivator { public BlockListItemActivator(BlockEditorConverter blockConverter, BlockListPropertyValueConstructorCache constructorCache) : base(blockConverter, constructorCache) diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/RichTextBlockPropertyValueCreator.cs b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/RichTextBlockPropertyValueCreator.cs index 241b5825e2..eb51bd0451 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/RichTextBlockPropertyValueCreator.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/RichTextBlockPropertyValueCreator.cs @@ -7,7 +7,7 @@ using Umbraco.Cms.Core.Serialization; namespace Umbraco.Cms.Core.PropertyEditors.ValueConverters; -internal class RichTextBlockPropertyValueCreator : BlockPropertyValueCreatorBase +internal sealed class RichTextBlockPropertyValueCreator : BlockPropertyValueCreatorBase { private readonly IJsonSerializer _jsonSerializer; private readonly RichTextBlockPropertyValueConstructorCache _constructorCache; @@ -39,7 +39,7 @@ internal class RichTextBlockPropertyValueCreator : BlockPropertyValueCreatorBase protected override BlockItemActivator CreateBlockItemActivator() => new RichTextBlockItemActivator(BlockEditorConverter, _constructorCache); - private class RichTextBlockItemActivator : BlockItemActivator + private sealed class RichTextBlockItemActivator : BlockItemActivator { public RichTextBlockItemActivator(BlockEditorConverter blockConverter, RichTextBlockPropertyValueConstructorCache constructorCache) : base(blockConverter, constructorCache) diff --git a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/RteBlockRenderingValueConverter.cs b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/RteBlockRenderingValueConverter.cs index 2c3f061b80..b2c47fc3cb 100644 --- a/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/RteBlockRenderingValueConverter.cs +++ b/src/Umbraco.Infrastructure/PropertyEditors/ValueConverters/RteBlockRenderingValueConverter.cs @@ -231,7 +231,7 @@ public class RteBlockRenderingValueConverter : SimpleRichTextValueConverter, IDe }; } - private class RichTextEditorIntermediateValue : IRichTextEditorIntermediateValue + private sealed class RichTextEditorIntermediateValue : IRichTextEditorIntermediateValue { public required string Markup { get; set; } diff --git a/src/Umbraco.Infrastructure/PublishedCache/ReservedFieldNamesService.cs b/src/Umbraco.Infrastructure/PublishedCache/ReservedFieldNamesService.cs index c4d981ef10..1125c15de3 100644 --- a/src/Umbraco.Infrastructure/PublishedCache/ReservedFieldNamesService.cs +++ b/src/Umbraco.Infrastructure/PublishedCache/ReservedFieldNamesService.cs @@ -4,7 +4,7 @@ using Umbraco.Cms.Core.Services; namespace Umbraco.Cms.Infrastructure.PublishedCache; -internal class ReservedFieldNamesService : IReservedFieldNamesService +internal sealed class ReservedFieldNamesService : IReservedFieldNamesService { private readonly ContentPropertySettings _contentPropertySettings; private readonly MemberPropertySettings _memberPropertySettings; diff --git a/src/Umbraco.Infrastructure/PublishedContentQuery.cs b/src/Umbraco.Infrastructure/PublishedContentQuery.cs index 4bf0868b10..221a7545ba 100644 --- a/src/Umbraco.Infrastructure/PublishedContentQuery.cs +++ b/src/Umbraco.Infrastructure/PublishedContentQuery.cs @@ -330,7 +330,7 @@ public class PublishedContentQuery : IPublishedContentQuery /// This is used to contextualize the values in the search results when enumerating over them, so that the correct /// culture values are used. /// - private class CultureContextualSearchResults : IEnumerable + private sealed class CultureContextualSearchResults : IEnumerable { private readonly string _culture; private readonly IVariationContextAccessor _variationContextAccessor; @@ -365,7 +365,7 @@ public class PublishedContentQuery : IPublishedContentQuery /// /// Resets the variation context when this is disposed. /// - private class CultureContextualSearchResultsEnumerator : IEnumerator + private sealed class CultureContextualSearchResultsEnumerator : IEnumerator { private readonly VariationContext? _originalContext; private readonly IVariationContextAccessor _variationContextAccessor; diff --git a/src/Umbraco.Infrastructure/Routing/NotFoundHandlerHelper.cs b/src/Umbraco.Infrastructure/Routing/NotFoundHandlerHelper.cs index 818ecc50ca..39cc120a6c 100644 --- a/src/Umbraco.Infrastructure/Routing/NotFoundHandlerHelper.cs +++ b/src/Umbraco.Infrastructure/Routing/NotFoundHandlerHelper.cs @@ -9,7 +9,7 @@ namespace Umbraco.Cms.Core.Routing; /// Used to determine the node to display when content is not found based on the configured error404 elements in /// umbracoSettings.config /// -internal class NotFoundHandlerHelper +internal sealed class NotFoundHandlerHelper { internal static int? GetCurrentNotFoundPageId( ContentErrorPage[] error404Collection, diff --git a/src/Umbraco.Infrastructure/Routing/RedirectTracker.cs b/src/Umbraco.Infrastructure/Routing/RedirectTracker.cs index 9a84a6ee56..7cbf91ae8d 100644 --- a/src/Umbraco.Infrastructure/Routing/RedirectTracker.cs +++ b/src/Umbraco.Infrastructure/Routing/RedirectTracker.cs @@ -13,7 +13,7 @@ using Umbraco.Extensions; namespace Umbraco.Cms.Infrastructure.Routing { - internal class RedirectTracker : IRedirectTracker + internal sealed class RedirectTracker : IRedirectTracker { private readonly ILocalizationService _localizationService; private readonly IRedirectUrlService _redirectUrlService; diff --git a/src/Umbraco.Infrastructure/Runtime/DefaultMainDomKeyGenerator.cs b/src/Umbraco.Infrastructure/Runtime/DefaultMainDomKeyGenerator.cs index a32b77eeac..64b1a70f12 100644 --- a/src/Umbraco.Infrastructure/Runtime/DefaultMainDomKeyGenerator.cs +++ b/src/Umbraco.Infrastructure/Runtime/DefaultMainDomKeyGenerator.cs @@ -7,7 +7,7 @@ using Umbraco.Extensions; namespace Umbraco.Cms.Infrastructure.Runtime; -internal class DefaultMainDomKeyGenerator : IMainDomKeyGenerator +internal sealed class DefaultMainDomKeyGenerator : IMainDomKeyGenerator { private readonly IOptionsMonitor _globalSettings; private readonly IHostingEnvironment _hostingEnvironment; diff --git a/src/Umbraco.Infrastructure/Runtime/FileSystemMainDomLock.cs b/src/Umbraco.Infrastructure/Runtime/FileSystemMainDomLock.cs index 403bde229a..a69d936efa 100644 --- a/src/Umbraco.Infrastructure/Runtime/FileSystemMainDomLock.cs +++ b/src/Umbraco.Infrastructure/Runtime/FileSystemMainDomLock.cs @@ -7,7 +7,7 @@ using Umbraco.Cms.Core.Runtime; namespace Umbraco.Cms.Infrastructure.Runtime; -internal class FileSystemMainDomLock : IMainDomLock +internal sealed class FileSystemMainDomLock : IMainDomLock { private readonly CancellationTokenSource _cancellationTokenSource = new(); private readonly IHostingEnvironment _hostingEnvironment; @@ -109,7 +109,7 @@ internal class FileSystemMainDomLock : IMainDomLock /// Releases the resources used by this . /// true to release both managed resources. - protected virtual void Dispose(bool disposing) + private void Dispose(bool disposing) { if (disposing && !_disposed) { diff --git a/src/Umbraco.Infrastructure/Runtime/RuntimeModeValidationService.cs b/src/Umbraco.Infrastructure/Runtime/RuntimeModeValidationService.cs index c4bbeb6902..0784a51d59 100644 --- a/src/Umbraco.Infrastructure/Runtime/RuntimeModeValidationService.cs +++ b/src/Umbraco.Infrastructure/Runtime/RuntimeModeValidationService.cs @@ -6,7 +6,7 @@ using Umbraco.Cms.Core.Configuration.Models; namespace Umbraco.Cms.Infrastructure.Runtime; /// -internal class RuntimeModeValidationService : IRuntimeModeValidationService +internal sealed class RuntimeModeValidationService : IRuntimeModeValidationService { private readonly IOptionsMonitor _runtimeSettings; private readonly IServiceProvider _serviceProvider; diff --git a/src/Umbraco.Infrastructure/Scoping/AmbientScopeContextStack.cs b/src/Umbraco.Infrastructure/Scoping/AmbientScopeContextStack.cs index 1d2a947ff7..b69fe31fee 100644 --- a/src/Umbraco.Infrastructure/Scoping/AmbientScopeContextStack.cs +++ b/src/Umbraco.Infrastructure/Scoping/AmbientScopeContextStack.cs @@ -3,7 +3,7 @@ using Umbraco.Cms.Core.Scoping; namespace Umbraco.Cms.Infrastructure.Scoping; -internal class AmbientScopeContextStack : IAmbientScopeContextStack +internal sealed class AmbientScopeContextStack : IAmbientScopeContextStack { private static Lock _lock = new(); private static AsyncLocal> _stack = new(); diff --git a/src/Umbraco.Infrastructure/Scoping/AmbientScopeStack.cs b/src/Umbraco.Infrastructure/Scoping/AmbientScopeStack.cs index efb5ea27ac..4ab55f0254 100644 --- a/src/Umbraco.Infrastructure/Scoping/AmbientScopeStack.cs +++ b/src/Umbraco.Infrastructure/Scoping/AmbientScopeStack.cs @@ -2,7 +2,7 @@ using System.Collections.Concurrent; namespace Umbraco.Cms.Infrastructure.Scoping { - internal class AmbientScopeStack : IAmbientScopeStack + internal sealed class AmbientScopeStack : IAmbientScopeStack { private static Lock _lock = new(); private static AsyncLocal> _stack = new (); diff --git a/src/Umbraco.Infrastructure/Scoping/HttpScopeReference.cs b/src/Umbraco.Infrastructure/Scoping/HttpScopeReference.cs index 0ccd8c6efe..31f4b1a965 100644 --- a/src/Umbraco.Infrastructure/Scoping/HttpScopeReference.cs +++ b/src/Umbraco.Infrastructure/Scoping/HttpScopeReference.cs @@ -9,7 +9,7 @@ namespace Umbraco.Cms.Core.Scoping; /// Disposed at the end of the request to cleanup any orphaned Scopes. /// /// Registered as Scoped in DI (per request) -internal class HttpScopeReference : IHttpScopeReference +internal sealed class HttpScopeReference : IHttpScopeReference { private readonly ScopeProvider _scopeProvider; private bool _disposedValue; @@ -24,7 +24,7 @@ internal class HttpScopeReference : IHttpScopeReference public void Register() => _registered = true; - protected virtual void Dispose(bool disposing) + private void Dispose(bool disposing) { if (!_disposedValue) { diff --git a/src/Umbraco.Infrastructure/Scoping/Scope.cs b/src/Umbraco.Infrastructure/Scoping/Scope.cs index 55c45bd881..93429ad650 100644 --- a/src/Umbraco.Infrastructure/Scoping/Scope.cs +++ b/src/Umbraco.Infrastructure/Scoping/Scope.cs @@ -15,7 +15,7 @@ namespace Umbraco.Cms.Infrastructure.Scoping /// Implements . /// /// Not thread-safe obviously. - internal class Scope : CoreScope, ICoreScope, IScope, Core.Scoping.IScope + internal sealed class Scope : CoreScope, ICoreScope, IScope, Core.Scoping.IScope { private readonly bool _autoComplete; private readonly CoreDebugSettings _coreDebugSettings; diff --git a/src/Umbraco.Infrastructure/Scoping/ScopeContext.cs b/src/Umbraco.Infrastructure/Scoping/ScopeContext.cs index fbaad205a2..6159b2f743 100644 --- a/src/Umbraco.Infrastructure/Scoping/ScopeContext.cs +++ b/src/Umbraco.Infrastructure/Scoping/ScopeContext.cs @@ -104,7 +104,7 @@ _enlisted ??= new Dictionary(); return enlistedAs.Item; } - private class EnlistedObject : IEnlistedObject + private sealed class EnlistedObject : IEnlistedObject { private readonly Action? _action; diff --git a/src/Umbraco.Infrastructure/Scoping/ScopeProvider.cs b/src/Umbraco.Infrastructure/Scoping/ScopeProvider.cs index 6a30bd21ac..5940790ab6 100644 --- a/src/Umbraco.Infrastructure/Scoping/ScopeProvider.cs +++ b/src/Umbraco.Infrastructure/Scoping/ScopeProvider.cs @@ -19,7 +19,7 @@ namespace Umbraco.Cms.Infrastructure.Scoping /// /// Implements . /// - internal class ScopeProvider : + internal sealed class ScopeProvider : ICoreScopeProvider, IScopeProvider, Core.Scoping.IScopeProvider, diff --git a/src/Umbraco.Infrastructure/Security/PasswordChanger.cs b/src/Umbraco.Infrastructure/Security/PasswordChanger.cs index b3de060b42..e5c00ec143 100644 --- a/src/Umbraco.Infrastructure/Security/PasswordChanger.cs +++ b/src/Umbraco.Infrastructure/Security/PasswordChanger.cs @@ -10,7 +10,7 @@ namespace Umbraco.Cms.Core.Security; /// /// Changes the password for an identity user /// -internal class PasswordChanger : IPasswordChanger where TUser : UmbracoIdentityUser +internal sealed class PasswordChanger : IPasswordChanger where TUser : UmbracoIdentityUser { private readonly ILogger> _logger; diff --git a/src/Umbraco.Infrastructure/Telemetry/Providers/SystemTroubleshootingInformationTelemetryProvider.cs b/src/Umbraco.Infrastructure/Telemetry/Providers/SystemTroubleshootingInformationTelemetryProvider.cs index 8acf2dd7e9..a718185740 100644 --- a/src/Umbraco.Infrastructure/Telemetry/Providers/SystemTroubleshootingInformationTelemetryProvider.cs +++ b/src/Umbraco.Infrastructure/Telemetry/Providers/SystemTroubleshootingInformationTelemetryProvider.cs @@ -14,7 +14,7 @@ using Umbraco.Extensions; namespace Umbraco.Cms.Infrastructure.Telemetry.Providers; -internal class SystemTroubleshootingInformationTelemetryProvider : IDetailedTelemetryProvider, ISystemTroubleshootingInformationService +internal sealed class SystemTroubleshootingInformationTelemetryProvider : IDetailedTelemetryProvider, ISystemTroubleshootingInformationService { private readonly IHostEnvironment _hostEnvironment; private readonly HostingSettings _hostingSettings; @@ -45,21 +45,21 @@ internal class SystemTroubleshootingInformationTelemetryProvider : IDetailedTele _modelsBuilderSettings = modelsBuilderSettings.CurrentValue; } - private string CurrentWebServer => GetWebServerName(); + private static string CurrentWebServer => GetWebServerName(); - private string ServerFramework => RuntimeInformation.FrameworkDescription; + private static string ServerFramework => RuntimeInformation.FrameworkDescription; private string ModelsBuilderMode => _modelsBuilderSettings.ModelsMode.ToString(); private string RuntimeMode => _runtimeSettings.Mode.ToString(); - private string CurrentCulture => Thread.CurrentThread.CurrentCulture.ToString(); + private static string CurrentCulture => Thread.CurrentThread.CurrentCulture.ToString(); private bool IsDebug => _hostingSettings.Debug; private string AspEnvironment => _hostEnvironment.EnvironmentName; - private string ServerOs => RuntimeInformation.OSDescription; + private static string ServerOs => RuntimeInformation.OSDescription; private string DatabaseProvider => _umbracoDatabaseFactory.CreateDatabase().DatabaseType.GetProviderName(); @@ -96,7 +96,7 @@ internal class SystemTroubleshootingInformationTelemetryProvider : IDetailedTele { "Current Server Role", CurrentServerRole }, }; - private string GetWebServerName() + private static string GetWebServerName() { var processName = Path.GetFileNameWithoutExtension(Process.GetCurrentProcess().ProcessName); diff --git a/src/Umbraco.Infrastructure/Telemetry/Services/UsageInformationService.cs b/src/Umbraco.Infrastructure/Telemetry/Services/UsageInformationService.cs index c5d35ef08f..65af0856fd 100644 --- a/src/Umbraco.Infrastructure/Telemetry/Services/UsageInformationService.cs +++ b/src/Umbraco.Infrastructure/Telemetry/Services/UsageInformationService.cs @@ -3,7 +3,7 @@ using Umbraco.Cms.Infrastructure.Telemetry.Interfaces; namespace Umbraco.Cms.Core.Services; -internal class UsageInformationService : IUsageInformationService +internal sealed class UsageInformationService : IUsageInformationService { private readonly IMetricsConsentService _metricsConsentService; private readonly IEnumerable _providers; diff --git a/src/Umbraco.PublishedCache.HybridCache/DatabaseCacheRebuilder.cs b/src/Umbraco.PublishedCache.HybridCache/DatabaseCacheRebuilder.cs index 1823825a9f..40ad248728 100644 --- a/src/Umbraco.PublishedCache.HybridCache/DatabaseCacheRebuilder.cs +++ b/src/Umbraco.PublishedCache.HybridCache/DatabaseCacheRebuilder.cs @@ -14,7 +14,7 @@ namespace Umbraco.Cms.Infrastructure.HybridCache; /// /// Rebuilds the published content cache in the database. /// -internal class DatabaseCacheRebuilder : IDatabaseCacheRebuilder +internal sealed class DatabaseCacheRebuilder : IDatabaseCacheRebuilder { private const string NuCacheSerializerKey = "Umbraco.Web.PublishedCache.NuCache.Serializer"; private const string IsRebuildingDatabaseCacheRuntimeCacheKey = "temp_database_cache_rebuild_op"; diff --git a/src/Umbraco.PublishedCache.HybridCache/Factories/CacheNodeFactory.cs b/src/Umbraco.PublishedCache.HybridCache/Factories/CacheNodeFactory.cs index e2be9797a0..ba2b955afe 100644 --- a/src/Umbraco.PublishedCache.HybridCache/Factories/CacheNodeFactory.cs +++ b/src/Umbraco.PublishedCache.HybridCache/Factories/CacheNodeFactory.cs @@ -1,21 +1,18 @@ using Umbraco.Cms.Core.Models; -using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Strings; using Umbraco.Extensions; namespace Umbraco.Cms.Infrastructure.HybridCache.Factories; -internal class CacheNodeFactory : ICacheNodeFactory +internal sealed class CacheNodeFactory : ICacheNodeFactory { private readonly IShortStringHelper _shortStringHelper; private readonly UrlSegmentProviderCollection _urlSegmentProviders; - private readonly IDocumentUrlService _documentUrlService; - public CacheNodeFactory(IShortStringHelper shortStringHelper, UrlSegmentProviderCollection urlSegmentProviders, IDocumentUrlService documentUrlService) + public CacheNodeFactory(IShortStringHelper shortStringHelper, UrlSegmentProviderCollection urlSegmentProviders) { _shortStringHelper = shortStringHelper; _urlSegmentProviders = urlSegmentProviders; - _documentUrlService = documentUrlService; } public ContentCacheNode ToContentCacheNode(IContent content, bool preview) @@ -41,7 +38,7 @@ internal class CacheNodeFactory : ICacheNodeFactory }; } - private bool GetPublishedValue(IContent content, bool preview) + private static bool GetPublishedValue(IContent content, bool preview) { switch (content.PublishedState) { @@ -56,7 +53,7 @@ internal class CacheNodeFactory : ICacheNodeFactory } } - private int? GetTemplateId(IContent content, bool preview) + private static int? GetTemplateId(IContent content, bool preview) { switch (content.PublishedState) { diff --git a/src/Umbraco.PublishedCache.HybridCache/Factories/PublishedContentFactory.cs b/src/Umbraco.PublishedCache.HybridCache/Factories/PublishedContentFactory.cs index 1afc363555..57863dc986 100644 --- a/src/Umbraco.PublishedCache.HybridCache/Factories/PublishedContentFactory.cs +++ b/src/Umbraco.PublishedCache.HybridCache/Factories/PublishedContentFactory.cs @@ -4,7 +4,7 @@ using Umbraco.Cms.Core.PublishedCache; namespace Umbraco.Cms.Infrastructure.HybridCache.Factories; -internal class PublishedContentFactory : IPublishedContentFactory +internal sealed class PublishedContentFactory : IPublishedContentFactory { private readonly IElementsCache _elementsCache; private readonly IVariationContextAccessor _variationContextAccessor; @@ -88,7 +88,7 @@ internal class PublishedContentFactory : IPublishedContentFactory return new PublishedMember(member, contentNode, _elementsCache, _variationContextAccessor); } - private Dictionary GetPropertyValues(IPublishedContentType contentType, IMember member) + private static Dictionary GetPropertyValues(IPublishedContentType contentType, IMember member) { var properties = member .Properties @@ -111,7 +111,7 @@ internal class PublishedContentFactory : IPublishedContentFactory return properties; } - private void AddIf(IPublishedContentType contentType, IDictionary properties, string alias, object? value) + private static void AddIf(IPublishedContentType contentType, IDictionary properties, string alias, object? value) { IPublishedPropertyType? propertyType = contentType.GetPropertyType(alias); if (propertyType == null || propertyType.IsUserProperty) @@ -135,14 +135,14 @@ internal class PublishedContentFactory : IPublishedContentFactory } - private IPublishedContent? GetPublishedContentAsDraft(IPublishedContent? content) => + private static IPublishedContent? GetPublishedContentAsDraft(IPublishedContent? content) => content == null ? null : // an object in the cache is either an IPublishedContentOrMedia, // or a model inheriting from PublishedContentExtended - in which // case we need to unwrap to get to the original IPublishedContentOrMedia. UnwrapIPublishedContent(content); - private PublishedContent UnwrapIPublishedContent(IPublishedContent content) + private static PublishedContent UnwrapIPublishedContent(IPublishedContent content) { while (content is PublishedContentWrapped wrapped) { diff --git a/src/Umbraco.PublishedCache.HybridCache/NotificationHandlers/SeedingNotificationHandler.cs b/src/Umbraco.PublishedCache.HybridCache/NotificationHandlers/SeedingNotificationHandler.cs index 47f590125f..0581bd2654 100644 --- a/src/Umbraco.PublishedCache.HybridCache/NotificationHandlers/SeedingNotificationHandler.cs +++ b/src/Umbraco.PublishedCache.HybridCache/NotificationHandlers/SeedingNotificationHandler.cs @@ -9,7 +9,7 @@ using Umbraco.Cms.Infrastructure.HybridCache.Services; namespace Umbraco.Cms.Infrastructure.HybridCache.NotificationHandlers; -internal class SeedingNotificationHandler : INotificationAsyncHandler +internal sealed class SeedingNotificationHandler : INotificationAsyncHandler { private readonly IDocumentCacheService _documentCacheService; private readonly IMediaCacheService _mediaCacheService; diff --git a/src/Umbraco.PublishedCache.HybridCache/Persistence/ContentSourceDto.cs b/src/Umbraco.PublishedCache.HybridCache/Persistence/ContentSourceDto.cs index 4d4fcae73d..187e94fd72 100644 --- a/src/Umbraco.PublishedCache.HybridCache/Persistence/ContentSourceDto.cs +++ b/src/Umbraco.PublishedCache.HybridCache/Persistence/ContentSourceDto.cs @@ -3,7 +3,7 @@ namespace Umbraco.Cms.Infrastructure.HybridCache.Persistence { // read-only dto - internal class ContentSourceDto : IReadOnlyContentBase + internal sealed class ContentSourceDto : IReadOnlyContentBase { public int Id { get; init; } diff --git a/src/Umbraco.PublishedCache.HybridCache/PublishedMember.cs b/src/Umbraco.PublishedCache.HybridCache/PublishedMember.cs index 4253b1a4c3..8aae008782 100644 --- a/src/Umbraco.PublishedCache.HybridCache/PublishedMember.cs +++ b/src/Umbraco.PublishedCache.HybridCache/PublishedMember.cs @@ -6,7 +6,7 @@ namespace Umbraco.Cms.Infrastructure.HybridCache; // note // the whole PublishedMember thing should be refactored because as soon as a member // is wrapped on in a model, the inner IMember and all associated properties are lost -internal class PublishedMember : PublishedContent, IPublishedMember +internal sealed class PublishedMember : PublishedContent, IPublishedMember { private readonly IMember _member; diff --git a/src/Umbraco.PublishedCache.HybridCache/PublishedProperty.cs b/src/Umbraco.PublishedCache.HybridCache/PublishedProperty.cs index 187b558385..167e46c253 100644 --- a/src/Umbraco.PublishedCache.HybridCache/PublishedProperty.cs +++ b/src/Umbraco.PublishedCache.HybridCache/PublishedProperty.cs @@ -8,7 +8,7 @@ using Umbraco.Extensions; namespace Umbraco.Cms.Infrastructure.HybridCache; -internal class PublishedProperty : PublishedPropertyBase +internal sealed class PublishedProperty : PublishedPropertyBase { private readonly PublishedContent _content; private readonly bool _isPreviewing; @@ -76,7 +76,7 @@ internal class PublishedProperty : PublishedPropertyBase // used to cache the CacheValues of this property internal string ValuesCacheKey => _valuesCacheKey ??= PropertyCacheValues(_content.Key, Alias, _isPreviewing); - private string PropertyCacheValues(Guid contentUid, string typeAlias, bool previewing) + private static string PropertyCacheValues(Guid contentUid, string typeAlias, bool previewing) { if (previewing) { @@ -226,7 +226,7 @@ internal class PublishedProperty : PublishedPropertyBase return value; } - private object? GetDeliveryApiDefaultObject(CacheValue cacheValues, Func getValue) + private static object? GetDeliveryApiDefaultObject(CacheValue cacheValues, Func getValue) { if (cacheValues.DeliveryApiDefaultObjectInitialized == false) { @@ -237,7 +237,7 @@ internal class PublishedProperty : PublishedPropertyBase return cacheValues.DeliveryApiDefaultObjectValue; } - private object? GetDeliveryApiExpandedObject(CacheValue cacheValues, Func getValue) + private static object? GetDeliveryApiExpandedObject(CacheValue cacheValues, Func getValue) { if (cacheValues.DeliveryApiExpandedObjectInitialized == false) { @@ -248,7 +248,7 @@ internal class PublishedProperty : PublishedPropertyBase return cacheValues.DeliveryApiExpandedObjectValue; } - private class SourceInterValue + private sealed class SourceInterValue { private string? _culture; private string? _segment; @@ -268,7 +268,7 @@ internal class PublishedProperty : PublishedPropertyBase public object? SourceValue { get; set; } } - private class CacheValues : CacheValue + private sealed class CacheValues : CacheValue { private readonly Lock _locko = new(); private ConcurrentDictionary? _values; diff --git a/src/Umbraco.PublishedCache.HybridCache/Serialization/HybridCacheSerializer.cs b/src/Umbraco.PublishedCache.HybridCache/Serialization/HybridCacheSerializer.cs index dbe88358df..11f2a9da3a 100644 --- a/src/Umbraco.PublishedCache.HybridCache/Serialization/HybridCacheSerializer.cs +++ b/src/Umbraco.PublishedCache.HybridCache/Serialization/HybridCacheSerializer.cs @@ -6,7 +6,7 @@ using Microsoft.Extensions.Logging; namespace Umbraco.Cms.Infrastructure.HybridCache.Serialization; -internal class HybridCacheSerializer : IHybridCacheSerializer +internal sealed class HybridCacheSerializer : IHybridCacheSerializer { private readonly ILogger _logger; private readonly MessagePackSerializerOptions _options; diff --git a/src/Umbraco.PublishedCache.HybridCache/Serialization/JsonContentNestedDataSerializer.cs b/src/Umbraco.PublishedCache.HybridCache/Serialization/JsonContentNestedDataSerializer.cs index 1bb4822ced..9c730fc323 100644 --- a/src/Umbraco.PublishedCache.HybridCache/Serialization/JsonContentNestedDataSerializer.cs +++ b/src/Umbraco.PublishedCache.HybridCache/Serialization/JsonContentNestedDataSerializer.cs @@ -7,7 +7,7 @@ namespace Umbraco.Cms.Infrastructure.HybridCache.Serialization; /// /// Serializes/deserializes documents to the SQL Database as JSON. /// -internal class JsonContentNestedDataSerializer : IContentCacheDataSerializer +internal sealed class JsonContentNestedDataSerializer : IContentCacheDataSerializer { private static readonly JsonSerializerOptions _jsonSerializerOptions = new() { @@ -47,7 +47,7 @@ internal class JsonContentNestedDataSerializer : IContentCacheDataSerializer /// /// Provides a converter for handling JSON objects that can be of various types (string, number, boolean, null, or complex types). /// - internal class JsonObjectConverter : JsonConverter + internal sealed class JsonObjectConverter : JsonConverter { /// public override object? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) @@ -65,5 +65,4 @@ internal class JsonContentNestedDataSerializer : IContentCacheDataSerializer public override void Write(Utf8JsonWriter writer, object value, JsonSerializerOptions options) => JsonSerializer.Serialize(writer, value, value.GetType(), options); } - } diff --git a/src/Umbraco.PublishedCache.HybridCache/Serialization/JsonContentNestedDataSerializerFactory.cs b/src/Umbraco.PublishedCache.HybridCache/Serialization/JsonContentNestedDataSerializerFactory.cs index 7353953f4a..c3c5e395c3 100644 --- a/src/Umbraco.PublishedCache.HybridCache/Serialization/JsonContentNestedDataSerializerFactory.cs +++ b/src/Umbraco.PublishedCache.HybridCache/Serialization/JsonContentNestedDataSerializerFactory.cs @@ -1,6 +1,6 @@ namespace Umbraco.Cms.Infrastructure.HybridCache.Serialization; -internal class JsonContentNestedDataSerializerFactory : IContentCacheDataSerializerFactory +internal sealed class JsonContentNestedDataSerializerFactory : IContentCacheDataSerializerFactory { private readonly Lazy _serializer = new(); diff --git a/src/Umbraco.PublishedCache.HybridCache/Serialization/MsgPackContentNestedDataSerializerFactory.cs b/src/Umbraco.PublishedCache.HybridCache/Serialization/MsgPackContentNestedDataSerializerFactory.cs index f75f83ab73..9fa69f4d00 100644 --- a/src/Umbraco.PublishedCache.HybridCache/Serialization/MsgPackContentNestedDataSerializerFactory.cs +++ b/src/Umbraco.PublishedCache.HybridCache/Serialization/MsgPackContentNestedDataSerializerFactory.cs @@ -5,7 +5,7 @@ using Umbraco.Cms.Core.Services; namespace Umbraco.Cms.Infrastructure.HybridCache.Serialization; -internal class MsgPackContentNestedDataSerializerFactory : IContentCacheDataSerializerFactory +internal sealed class MsgPackContentNestedDataSerializerFactory : IContentCacheDataSerializerFactory { private readonly IPropertyCacheCompressionOptions _compressionOptions; private readonly IContentTypeService _contentTypeService; diff --git a/src/Umbraco.PublishedCache.HybridCache/Services/MediaCacheService.cs b/src/Umbraco.PublishedCache.HybridCache/Services/MediaCacheService.cs index 66c9fb73eb..4359f824c8 100644 --- a/src/Umbraco.PublishedCache.HybridCache/Services/MediaCacheService.cs +++ b/src/Umbraco.PublishedCache.HybridCache/Services/MediaCacheService.cs @@ -13,7 +13,7 @@ using Umbraco.Extensions; namespace Umbraco.Cms.Infrastructure.HybridCache.Services; -internal class MediaCacheService : IMediaCacheService +internal sealed class MediaCacheService : IMediaCacheService { private readonly IDatabaseCacheRepository _databaseCacheRepository; private readonly IIdKeyMap _idKeyMap; diff --git a/src/Umbraco.PublishedCache.HybridCache/Services/MemberCacheService.cs b/src/Umbraco.PublishedCache.HybridCache/Services/MemberCacheService.cs index f7bc3896fb..90eba2bd5f 100644 --- a/src/Umbraco.PublishedCache.HybridCache/Services/MemberCacheService.cs +++ b/src/Umbraco.PublishedCache.HybridCache/Services/MemberCacheService.cs @@ -5,7 +5,7 @@ using Umbraco.Cms.Infrastructure.HybridCache.Factories; namespace Umbraco.Cms.Infrastructure.HybridCache.Services; -internal class MemberCacheService : IMemberCacheService +internal sealed class MemberCacheService : IMemberCacheService { private readonly IPublishedContentFactory _publishedContentFactory; diff --git a/src/Umbraco.Web.Common/ApplicationBuilder/UmbracoEndpointBuilder.cs b/src/Umbraco.Web.Common/ApplicationBuilder/UmbracoEndpointBuilder.cs index fa75ed116d..52c30690ba 100644 --- a/src/Umbraco.Web.Common/ApplicationBuilder/UmbracoEndpointBuilder.cs +++ b/src/Umbraco.Web.Common/ApplicationBuilder/UmbracoEndpointBuilder.cs @@ -7,7 +7,7 @@ namespace Umbraco.Cms.Web.Common.ApplicationBuilder; /// /// A builder to allow encapsulating the enabled endpoints in Umbraco /// -internal class UmbracoEndpointBuilder : IUmbracoEndpointBuilderContext +internal sealed class UmbracoEndpointBuilder : IUmbracoEndpointBuilderContext { public UmbracoEndpointBuilder(IServiceProvider services, IRuntimeState runtimeState, IApplicationBuilder appBuilder, IEndpointRouteBuilder endpointRouteBuilder) { diff --git a/src/Umbraco.Web.Common/AspNetCore/ApplicationUrlRequestBeginNotificationHandler.cs b/src/Umbraco.Web.Common/AspNetCore/ApplicationUrlRequestBeginNotificationHandler.cs index 0472d31592..b6cb000c5f 100644 --- a/src/Umbraco.Web.Common/AspNetCore/ApplicationUrlRequestBeginNotificationHandler.cs +++ b/src/Umbraco.Web.Common/AspNetCore/ApplicationUrlRequestBeginNotificationHandler.cs @@ -8,7 +8,7 @@ namespace Umbraco.Cms.Web.Common.AspNetCore; /// Notification handler which will listen to the , and ensure that /// the applicationUrl is set on the first request. /// -internal class ApplicationUrlRequestBeginNotificationHandler : INotificationHandler +internal sealed class ApplicationUrlRequestBeginNotificationHandler : INotificationHandler { private readonly IRequestAccessor _requestAccessor; diff --git a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreApplicationShutdownRegistry.cs b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreApplicationShutdownRegistry.cs index 65c03ffafc..5e8e8fef75 100644 --- a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreApplicationShutdownRegistry.cs +++ b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreApplicationShutdownRegistry.cs @@ -38,7 +38,7 @@ public class AspNetCoreApplicationShutdownRegistry : IApplicationShutdownRegistr } } - private class RegisteredObjectWrapper + private sealed class RegisteredObjectWrapper { private readonly IRegisteredObject _inner; diff --git a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreSessionManager.cs b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreSessionManager.cs index ad5f480a72..2f0a6b70ca 100644 --- a/src/Umbraco.Web.Common/AspNetCore/AspNetCoreSessionManager.cs +++ b/src/Umbraco.Web.Common/AspNetCore/AspNetCoreSessionManager.cs @@ -5,7 +5,7 @@ using Umbraco.Cms.Core.Web; namespace Umbraco.Cms.Web.Common.AspNetCore; -internal class AspNetCoreSessionManager : ISessionIdResolver, ISessionManager +internal sealed class AspNetCoreSessionManager : ISessionIdResolver, ISessionManager { private readonly IHttpContextAccessor _httpContextAccessor; diff --git a/src/Umbraco.Web.Common/Cache/HttpContextRequestAppCache.cs b/src/Umbraco.Web.Common/Cache/HttpContextRequestAppCache.cs index 53c777c63e..83de3aa4ba 100644 --- a/src/Umbraco.Web.Common/Cache/HttpContextRequestAppCache.cs +++ b/src/Umbraco.Web.Common/Cache/HttpContextRequestAppCache.cs @@ -175,7 +175,7 @@ public class HttpContextRequestAppCache : FastDictionaryAppCacheBase, IRequestCa /// /// Used as Scoped instance to allow locking within a request /// - private class RequestLock + private sealed class RequestLock { public object SyncRoot { get; } = new(); } diff --git a/src/Umbraco.Web.Common/Controllers/PublishedRequestFilterAttribute.cs b/src/Umbraco.Web.Common/Controllers/PublishedRequestFilterAttribute.cs index 9cd0a975a1..b4b0c35505 100644 --- a/src/Umbraco.Web.Common/Controllers/PublishedRequestFilterAttribute.cs +++ b/src/Umbraco.Web.Common/Controllers/PublishedRequestFilterAttribute.cs @@ -9,7 +9,7 @@ namespace Umbraco.Cms.Web.Common.Controllers; /// /// Deals with custom headers for the umbraco request /// -internal class PublishedRequestFilterAttribute : ResultFilterAttribute +internal sealed class PublishedRequestFilterAttribute : ResultFilterAttribute { /// /// Deals with custom headers for the umbraco request @@ -48,7 +48,7 @@ internal class PublishedRequestFilterAttribute : ResultFilterAttribute /// /// Gets the /// - protected UmbracoRouteValues GetUmbracoRouteValues(ResultExecutingContext context) + protected static UmbracoRouteValues GetUmbracoRouteValues(ResultExecutingContext context) { UmbracoRouteValues? routeVals = context.HttpContext.Features.Get(); if (routeVals == null) @@ -60,7 +60,7 @@ internal class PublishedRequestFilterAttribute : ResultFilterAttribute return routeVals; } - private void AddCacheControlHeaders(ResultExecutingContext context, IPublishedRequest pcr) + private static void AddCacheControlHeaders(ResultExecutingContext context, IPublishedRequest pcr) { var cacheControlHeaders = new List(); diff --git a/src/Umbraco.Web.Common/DependencyInjection/ScopedServiceProvider.cs b/src/Umbraco.Web.Common/DependencyInjection/ScopedServiceProvider.cs index 31f5709bd4..7f19ede935 100644 --- a/src/Umbraco.Web.Common/DependencyInjection/ScopedServiceProvider.cs +++ b/src/Umbraco.Web.Common/DependencyInjection/ScopedServiceProvider.cs @@ -4,7 +4,7 @@ using Umbraco.Cms.Core.DependencyInjection; namespace Umbraco.Cms.Web.Common.DependencyInjection; /// -internal class ScopedServiceProvider : IScopedServiceProvider +internal sealed class ScopedServiceProvider : IScopedServiceProvider { private readonly IHttpContextAccessor _accessor; diff --git a/src/Umbraco.Web.Common/Filters/ModelBindingExceptionAttribute.cs b/src/Umbraco.Web.Common/Filters/ModelBindingExceptionAttribute.cs index 0129874deb..4b7f0a17b7 100644 --- a/src/Umbraco.Web.Common/Filters/ModelBindingExceptionAttribute.cs +++ b/src/Umbraco.Web.Common/Filters/ModelBindingExceptionAttribute.cs @@ -30,7 +30,7 @@ public sealed class ModelBindingExceptionAttribute : TypeFilterAttribute { } - private class ModelBindingExceptionFilter : IExceptionFilter + private sealed class ModelBindingExceptionFilter : IExceptionFilter { private static readonly Regex GetPublishedModelsTypesRegex = new("Umbraco.Web.PublishedModels.(\\w+)", RegexOptions.Compiled); diff --git a/src/Umbraco.Web.Common/Filters/UmbracoUserTimeoutFilterAttribute.cs b/src/Umbraco.Web.Common/Filters/UmbracoUserTimeoutFilterAttribute.cs index 13c62365c2..a615b7a277 100644 --- a/src/Umbraco.Web.Common/Filters/UmbracoUserTimeoutFilterAttribute.cs +++ b/src/Umbraco.Web.Common/Filters/UmbracoUserTimeoutFilterAttribute.cs @@ -17,7 +17,7 @@ public class UmbracoUserTimeoutFilterAttribute : TypeFilterAttribute { } - private class UmbracoUserTimeoutFilter : IActionFilter + private sealed class UmbracoUserTimeoutFilter : IActionFilter { public void OnActionExecuted(ActionExecutedContext context) { diff --git a/src/Umbraco.Web.Common/Filters/ValidateUmbracoFormRouteStringAttribute.cs b/src/Umbraco.Web.Common/Filters/ValidateUmbracoFormRouteStringAttribute.cs index cdf3d8c135..03020edccb 100644 --- a/src/Umbraco.Web.Common/Filters/ValidateUmbracoFormRouteStringAttribute.cs +++ b/src/Umbraco.Web.Common/Filters/ValidateUmbracoFormRouteStringAttribute.cs @@ -22,9 +22,9 @@ public class ValidateUmbracoFormRouteStringAttribute : TypeFilterAttribute // TODO: Lets revisit this when we get members done and the front-end working and whether it can moved to an authz policy public ValidateUmbracoFormRouteStringAttribute() : base(typeof(ValidateUmbracoFormRouteStringFilter)) => - Arguments = new object[] { }; + Arguments = []; - internal class ValidateUmbracoFormRouteStringFilter : IAuthorizationFilter + internal sealed class ValidateUmbracoFormRouteStringFilter : IAuthorizationFilter { private readonly IDataProtectionProvider _dataProtectionProvider; diff --git a/src/Umbraco.Web.Common/Hosting/UmbracoHostBuilderDecorator.cs b/src/Umbraco.Web.Common/Hosting/UmbracoHostBuilderDecorator.cs index afe4e78906..e827e5c556 100644 --- a/src/Umbraco.Web.Common/Hosting/UmbracoHostBuilderDecorator.cs +++ b/src/Umbraco.Web.Common/Hosting/UmbracoHostBuilderDecorator.cs @@ -4,7 +4,7 @@ using Microsoft.Extensions.Hosting; namespace Umbraco.Cms.Web.Common.Hosting; -internal class UmbracoHostBuilderDecorator : IHostBuilder +internal sealed class UmbracoHostBuilderDecorator : IHostBuilder { private readonly IHostBuilder _inner; private readonly Action? _onBuild; diff --git a/src/Umbraco.Web.Common/Logging/Enrichers/ApplicationIdEnricher.cs b/src/Umbraco.Web.Common/Logging/Enrichers/ApplicationIdEnricher.cs index 7886e38614..56b043732a 100644 --- a/src/Umbraco.Web.Common/Logging/Enrichers/ApplicationIdEnricher.cs +++ b/src/Umbraco.Web.Common/Logging/Enrichers/ApplicationIdEnricher.cs @@ -5,7 +5,7 @@ using Umbraco.Extensions; namespace Umbraco.Cms.Web.Common.Logging.Enrichers; -internal class ApplicationIdEnricher : ILogEventEnricher +internal sealed class ApplicationIdEnricher : ILogEventEnricher { public const string ApplicationIdProperty = "ApplicationId"; private readonly IApplicationDiscriminator _applicationDiscriminator; diff --git a/src/Umbraco.Web.Common/Logging/Enrichers/NoopEnricher.cs b/src/Umbraco.Web.Common/Logging/Enrichers/NoopEnricher.cs index d0ec659526..2318a5eefb 100644 --- a/src/Umbraco.Web.Common/Logging/Enrichers/NoopEnricher.cs +++ b/src/Umbraco.Web.Common/Logging/Enrichers/NoopEnricher.cs @@ -6,7 +6,7 @@ namespace Umbraco.Cms.Web.Common.Logging.Enrichers; /// /// NoOp but useful for tricks to avoid disposal of the global logger. /// -internal class NoopEnricher : ILogEventEnricher +internal sealed class NoopEnricher : ILogEventEnricher { public void Enrich(LogEvent logEvent, ILogEventPropertyFactory propertyFactory) { diff --git a/src/Umbraco.Web.Common/Logging/RegisteredReloadableLogger.cs b/src/Umbraco.Web.Common/Logging/RegisteredReloadableLogger.cs index 499d7aceaf..dfc4be2e09 100644 --- a/src/Umbraco.Web.Common/Logging/RegisteredReloadableLogger.cs +++ b/src/Umbraco.Web.Common/Logging/RegisteredReloadableLogger.cs @@ -9,7 +9,7 @@ namespace Umbraco.Cms.Web.Common.Logging; /// Ensures freeze is only called a single time even when resolving a logger from the snapshot container /// built for . /// -internal class RegisteredReloadableLogger +internal sealed class RegisteredReloadableLogger { private static readonly Lock _frozenLock = new(); private static bool _frozen; diff --git a/src/Umbraco.Web.Common/Media/MediaPrependBasePathFileProvider.cs b/src/Umbraco.Web.Common/Media/MediaPrependBasePathFileProvider.cs index 45d522d0de..0b78c9dcca 100644 --- a/src/Umbraco.Web.Common/Media/MediaPrependBasePathFileProvider.cs +++ b/src/Umbraco.Web.Common/Media/MediaPrependBasePathFileProvider.cs @@ -15,7 +15,7 @@ namespace Umbraco.Cms.Web.Common.Media; /// A PR has been submitted to the Dazinator project: https://github.com/dazinator/Dazinator.Extensions.FileProviders/pull/53 /// If that PR is accepted, the Dazinator dependency should be updated and this class should be removed. /// -internal class MediaPrependBasePathFileProvider : IFileProvider +internal sealed class MediaPrependBasePathFileProvider : IFileProvider { private readonly PathString _basePath; private readonly IFileProvider _underlyingFileProvider; @@ -29,7 +29,7 @@ internal class MediaPrependBasePathFileProvider : IFileProvider _underlyingFileProvider = underlyingFileProvider; } - protected virtual bool TryMapSubPath(string originalSubPath, out PathString newSubPath) + private bool TryMapSubPath(string originalSubPath, out PathString newSubPath) { if (!string.IsNullOrEmpty(originalSubPath)) { diff --git a/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs b/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs index 38d6fae93a..de6218d9af 100644 --- a/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs +++ b/src/Umbraco.Web.Common/Middleware/UmbracoRequestMiddleware.cs @@ -31,7 +31,7 @@ namespace Umbraco.Cms.Web.Common.Middleware; /// This is responsible for creating and assigning an /// /// -internal class UmbracoRequestMiddleware : IMiddleware +internal sealed class UmbracoRequestMiddleware : IMiddleware { private readonly IDefaultCultureAccessor _defaultCultureAccessor; private readonly IEventAggregator _eventAggregator; @@ -158,7 +158,7 @@ internal class UmbracoRequestMiddleware : IMiddleware _profiler?.UmbracoApplicationEndRequest(context, _runtimeState.Level); } - private Uri? GetApplicationUrlFromCurrentRequest(HttpRequest request) + private static Uri? GetApplicationUrlFromCurrentRequest(HttpRequest request) { // We only consider GET and POST. // Especially the DEBUG sent when debugging the application is annoying because it uses http, even when the https is available. @@ -173,7 +173,7 @@ internal class UmbracoRequestMiddleware : IMiddleware /// /// Dispose some request scoped objects that we are maintaining the lifecycle for. /// - private void DisposeHttpContextItems(HttpRequest request) + private static void DisposeHttpContextItems(HttpRequest request) { // do not process if client-side request if (request.IsClientSideRequest()) diff --git a/src/Umbraco.Web.Common/ModelsBuilder/InMemoryAuto/CollectibleRuntimeViewCompiler.cs b/src/Umbraco.Web.Common/ModelsBuilder/InMemoryAuto/CollectibleRuntimeViewCompiler.cs index a00193850c..46670862ed 100644 --- a/src/Umbraco.Web.Common/ModelsBuilder/InMemoryAuto/CollectibleRuntimeViewCompiler.cs +++ b/src/Umbraco.Web.Common/ModelsBuilder/InMemoryAuto/CollectibleRuntimeViewCompiler.cs @@ -18,7 +18,7 @@ using Umbraco.Extensions; namespace Umbraco.Cms.Web.Common.ModelsBuilder.InMemoryAuto; -internal class CollectibleRuntimeViewCompiler : IViewCompiler +internal sealed class CollectibleRuntimeViewCompiler : IViewCompiler { private readonly Lock _cacheLock = new(); private readonly Dictionary _precompiledViews; @@ -319,7 +319,7 @@ internal class CollectibleRuntimeViewCompiler : IViewCompiler } } - protected virtual CompiledViewDescriptor CompileAndEmit(string relativePath) + private CompiledViewDescriptor CompileAndEmit(string relativePath) { RazorProjectItem projectItem = _projectEngine.FileSystem.GetItem(relativePath, fileKind: null); RazorCodeDocument codeDocument = _projectEngine.Process(projectItem); @@ -444,7 +444,7 @@ internal class CollectibleRuntimeViewCompiler : IViewCompiler // Taken from: https://github.com/dotnet/aspnetcore/blob/a450cb69b5e4549f5515cdb057a68771f56cefd7/src/Mvc/Mvc.Razor/src/ViewPath.cs // This normalizes the relative path to the view, ensuring that it matches with what we have as keys in _precompiledViews - private string NormalizePath(string path) + private static string NormalizePath(string path) { var addLeadingSlash = path[0] != '\\' && path[0] != '/'; var transformSlashes = path.IndexOf('\\') != -1; diff --git a/src/Umbraco.Web.Common/ModelsBuilder/InMemoryAuto/InMemoryAssemblyLoadContextManager.cs b/src/Umbraco.Web.Common/ModelsBuilder/InMemoryAuto/InMemoryAssemblyLoadContextManager.cs index 15a280574d..d999333f77 100644 --- a/src/Umbraco.Web.Common/ModelsBuilder/InMemoryAuto/InMemoryAssemblyLoadContextManager.cs +++ b/src/Umbraco.Web.Common/ModelsBuilder/InMemoryAuto/InMemoryAssemblyLoadContextManager.cs @@ -4,7 +4,7 @@ using Umbraco.Cms.Infrastructure.ModelsBuilder; namespace Umbraco.Cms.Web.Common.ModelsBuilder.InMemoryAuto; -internal class InMemoryAssemblyLoadContextManager +internal sealed class InMemoryAssemblyLoadContextManager { private UmbracoAssemblyLoadContext? _currentAssemblyLoadContext; diff --git a/src/Umbraco.Web.Common/ModelsBuilder/InMemoryAuto/InMemoryModelFactory.cs b/src/Umbraco.Web.Common/ModelsBuilder/InMemoryAuto/InMemoryModelFactory.cs index b44b6345e1..cee000e7f9 100644 --- a/src/Umbraco.Web.Common/ModelsBuilder/InMemoryAuto/InMemoryModelFactory.cs +++ b/src/Umbraco.Web.Common/ModelsBuilder/InMemoryAuto/InMemoryModelFactory.cs @@ -21,7 +21,7 @@ using IHostingEnvironment = Umbraco.Cms.Core.Hosting.IHostingEnvironment; namespace Umbraco.Cms.Web.Common.ModelsBuilder.InMemoryAuto { - internal class InMemoryModelFactory : IAutoPublishedModelFactory, IRegisteredObject, IDisposable + internal sealed class InMemoryModelFactory : IAutoPublishedModelFactory, IRegisteredObject, IDisposable { private static readonly Regex s_usingRegex = new Regex("^using(.*);", RegexOptions.Compiled | RegexOptions.Multiline); private static readonly Regex s_aattrRegex = new Regex("^\\[assembly:(.*)\\]", RegexOptions.Compiled | RegexOptions.Multiline); @@ -572,7 +572,7 @@ namespace Umbraco.Cms.Web.Common.ModelsBuilder.InMemoryAuto return assembly; } - private void TryDeleteUnusedAssemblies(string dllPathFile) + private static void TryDeleteUnusedAssemblies(string dllPathFile) { if (File.Exists(dllPathFile)) { @@ -818,7 +818,7 @@ namespace Umbraco.Cms.Web.Common.ModelsBuilder.InMemoryAuto _hostingLifetime.UnregisterObject(this); } - protected virtual void Dispose(bool disposing) + private void Dispose(bool disposing) { if (!_disposedValue) { @@ -843,14 +843,14 @@ namespace Umbraco.Cms.Web.Common.ModelsBuilder.InMemoryAuto Dispose(disposing: true); } - internal class Infos + internal sealed class Infos { public Dictionary? ModelTypeMap { get; set; } public Dictionary? ModelInfos { get; set; } } - internal class ModelInfo + internal sealed class ModelInfo { public Type? ParameterType { get; set; } diff --git a/src/Umbraco.Web.Common/ModelsBuilder/InMemoryAuto/RuntimeCompilationCacheBuster.cs b/src/Umbraco.Web.Common/ModelsBuilder/InMemoryAuto/RuntimeCompilationCacheBuster.cs index 51774b92f2..f13b815f9a 100644 --- a/src/Umbraco.Web.Common/ModelsBuilder/InMemoryAuto/RuntimeCompilationCacheBuster.cs +++ b/src/Umbraco.Web.Common/ModelsBuilder/InMemoryAuto/RuntimeCompilationCacheBuster.cs @@ -4,7 +4,7 @@ using Umbraco.Cms.Core; namespace Umbraco.Cms.Web.Common.ModelsBuilder.InMemoryAuto; -internal class RuntimeCompilationCacheBuster +internal sealed class RuntimeCompilationCacheBuster { private readonly IViewCompilerProvider _viewCompilerProvider; private readonly IRazorViewEngine _razorViewEngine; diff --git a/src/Umbraco.Web.Common/ModelsBuilder/InMemoryAuto/UmbracoAssemblyLoadContext.cs b/src/Umbraco.Web.Common/ModelsBuilder/InMemoryAuto/UmbracoAssemblyLoadContext.cs index 5ca90c2df9..b21a55cb6c 100644 --- a/src/Umbraco.Web.Common/ModelsBuilder/InMemoryAuto/UmbracoAssemblyLoadContext.cs +++ b/src/Umbraco.Web.Common/ModelsBuilder/InMemoryAuto/UmbracoAssemblyLoadContext.cs @@ -3,7 +3,7 @@ using System.Runtime.Loader; namespace Umbraco.Cms.Web.Common.ModelsBuilder.InMemoryAuto; -internal class UmbracoAssemblyLoadContext : AssemblyLoadContext +internal sealed class UmbracoAssemblyLoadContext : AssemblyLoadContext { /// /// Initializes a new instance of the class. diff --git a/src/Umbraco.Web.Common/ModelsBuilder/InMemoryAuto/UmbracoCompilationException.cs b/src/Umbraco.Web.Common/ModelsBuilder/InMemoryAuto/UmbracoCompilationException.cs index cb180a6264..fb39c8fb04 100644 --- a/src/Umbraco.Web.Common/ModelsBuilder/InMemoryAuto/UmbracoCompilationException.cs +++ b/src/Umbraco.Web.Common/ModelsBuilder/InMemoryAuto/UmbracoCompilationException.cs @@ -2,7 +2,7 @@ namespace Umbraco.Cms.Web.Common.ModelsBuilder.InMemoryAuto; -internal class UmbracoCompilationException : Exception, ICompilationException +internal sealed class UmbracoCompilationException : Exception, ICompilationException { public IEnumerable? CompilationFailures { get; init; } } diff --git a/src/Umbraco.Web.Common/ModelsBuilder/InMemoryAuto/UmbracoRazorReferenceManager.cs b/src/Umbraco.Web.Common/ModelsBuilder/InMemoryAuto/UmbracoRazorReferenceManager.cs index 3a90e43be5..92891d5ed4 100644 --- a/src/Umbraco.Web.Common/ModelsBuilder/InMemoryAuto/UmbracoRazorReferenceManager.cs +++ b/src/Umbraco.Web.Common/ModelsBuilder/InMemoryAuto/UmbracoRazorReferenceManager.cs @@ -17,7 +17,7 @@ namespace Umbraco.Cms.Web.Common.ModelsBuilder.InMemoryAuto; * * This class is used by the the ViewCompiler (CollectibleRuntimeViewCompiler) to find the required references when compiling views. */ -internal class UmbracoRazorReferenceManager +internal sealed class UmbracoRazorReferenceManager { private readonly ApplicationPartManager _partManager; private readonly MvcRazorRuntimeCompilationOptions _options; @@ -33,7 +33,7 @@ internal class UmbracoRazorReferenceManager _options = options.Value; } - public virtual IReadOnlyList CompilationReferences + public IReadOnlyList CompilationReferences { get { diff --git a/src/Umbraco.Web.Common/ModelsBuilder/InMemoryAuto/UmbracoViewCompilerProvider.cs b/src/Umbraco.Web.Common/ModelsBuilder/InMemoryAuto/UmbracoViewCompilerProvider.cs index 2c4bfe0a33..600ca67a54 100644 --- a/src/Umbraco.Web.Common/ModelsBuilder/InMemoryAuto/UmbracoViewCompilerProvider.cs +++ b/src/Umbraco.Web.Common/ModelsBuilder/InMemoryAuto/UmbracoViewCompilerProvider.cs @@ -9,7 +9,7 @@ using Umbraco.Cms.Core.Exceptions; namespace Umbraco.Cms.Web.Common.ModelsBuilder.InMemoryAuto; -internal class UmbracoViewCompilerProvider : IViewCompilerProvider +internal sealed class UmbracoViewCompilerProvider : IViewCompilerProvider { private readonly RazorProjectEngine _razorProjectEngine; private readonly UmbracoRazorReferenceManager _umbracoRazorReferenceManager; diff --git a/src/Umbraco.Web.Common/ModelsBuilder/ModelsBuilderNotificationHandler.cs b/src/Umbraco.Web.Common/ModelsBuilder/ModelsBuilderNotificationHandler.cs index c25a485b55..98936a828a 100644 --- a/src/Umbraco.Web.Common/ModelsBuilder/ModelsBuilderNotificationHandler.cs +++ b/src/Umbraco.Web.Common/ModelsBuilder/ModelsBuilderNotificationHandler.cs @@ -15,7 +15,7 @@ namespace Umbraco.Cms.Web.Common.ModelsBuilder; /// Handles and /// notifications to initialize MB /// -internal class ModelsBuilderNotificationHandler : +internal sealed class ModelsBuilderNotificationHandler : INotificationHandler, INotificationHandler, INotificationHandler diff --git a/src/Umbraco.Web.Common/Repositories/WebProfilerRepository.cs b/src/Umbraco.Web.Common/Repositories/WebProfilerRepository.cs index 44dc862e96..668f1f46de 100644 --- a/src/Umbraco.Web.Common/Repositories/WebProfilerRepository.cs +++ b/src/Umbraco.Web.Common/Repositories/WebProfilerRepository.cs @@ -4,7 +4,7 @@ using Umbraco.Extensions; namespace Umbraco.Cms.Web.Common.Repositories; -internal class WebProfilerRepository : IWebProfilerRepository +internal sealed class WebProfilerRepository : IWebProfilerRepository { private const string CookieName = "UMB-DEBUG"; private const string HeaderName = "X-UMB-DEBUG"; diff --git a/src/Umbraco.Web.Common/Routing/CustomRouteContentFinderDelegate.cs b/src/Umbraco.Web.Common/Routing/CustomRouteContentFinderDelegate.cs index e42e1e63a7..16960099d2 100644 --- a/src/Umbraco.Web.Common/Routing/CustomRouteContentFinderDelegate.cs +++ b/src/Umbraco.Web.Common/Routing/CustomRouteContentFinderDelegate.cs @@ -3,7 +3,7 @@ using Umbraco.Cms.Core.Models.PublishedContent; namespace Umbraco.Cms.Web.Common.Routing; -internal class CustomRouteContentFinderDelegate +internal sealed class CustomRouteContentFinderDelegate { private readonly Func _findContent; diff --git a/src/Umbraco.Web.Common/Security/UmbracoSignInManager.cs b/src/Umbraco.Web.Common/Security/UmbracoSignInManager.cs index d49c2ae238..1d6d865f9e 100644 --- a/src/Umbraco.Web.Common/Security/UmbracoSignInManager.cs +++ b/src/Umbraco.Web.Common/Security/UmbracoSignInManager.cs @@ -517,7 +517,7 @@ public abstract class UmbracoSignInManager : SignInManager } // borrowed from https://github.com/dotnet/aspnetcore/blob/master/src/Identity/Core/src/SignInManager.cs#L891 - private class TwoFactorAuthenticationInfo + private sealed class TwoFactorAuthenticationInfo { public string? UserId { get; set; } diff --git a/src/Umbraco.Web.Common/Templates/TemplateRenderer.cs b/src/Umbraco.Web.Common/Templates/TemplateRenderer.cs index adfe936988..f60833a4b7 100644 --- a/src/Umbraco.Web.Common/Templates/TemplateRenderer.cs +++ b/src/Umbraco.Web.Common/Templates/TemplateRenderer.cs @@ -26,7 +26,7 @@ namespace Umbraco.Cms.Web.Common.Templates; /// This allows you to render an MVC template based purely off of a node id and an optional alttemplate id as string /// output. /// -internal class TemplateRenderer : ITemplateRenderer +internal sealed class TemplateRenderer : ITemplateRenderer { private readonly IFileService _fileService; private readonly IHttpContextAccessor _httpContextAccessor; diff --git a/src/Umbraco.Web.Common/Validators/BypassRenderingModelValidationMetadataProvider.cs b/src/Umbraco.Web.Common/Validators/BypassRenderingModelValidationMetadataProvider.cs index 94f0dea502..dd7117e273 100644 --- a/src/Umbraco.Web.Common/Validators/BypassRenderingModelValidationMetadataProvider.cs +++ b/src/Umbraco.Web.Common/Validators/BypassRenderingModelValidationMetadataProvider.cs @@ -6,7 +6,7 @@ namespace Umbraco.Cms.Web.Common.Validators; /// /// Ensures we bypass object graph validation for rendering models. /// -internal class BypassRenderingModelValidationMetadataProvider : IValidationMetadataProvider +internal sealed class BypassRenderingModelValidationMetadataProvider : IValidationMetadataProvider { public void CreateValidationMetadata(ValidationMetadataProviderContext context) { diff --git a/src/Umbraco.Web.Common/Validators/BypassRenderingModelValidatorProvider.cs b/src/Umbraco.Web.Common/Validators/BypassRenderingModelValidatorProvider.cs index ab52483180..a86b66974e 100644 --- a/src/Umbraco.Web.Common/Validators/BypassRenderingModelValidatorProvider.cs +++ b/src/Umbraco.Web.Common/Validators/BypassRenderingModelValidatorProvider.cs @@ -6,7 +6,7 @@ namespace Umbraco.Cms.Web.Common.Validators; /// /// Ensures we bypass property validation for rendering models. /// -internal class BypassRenderingModelValidatorProvider : IModelValidatorProvider +internal sealed class BypassRenderingModelValidatorProvider : IModelValidatorProvider { public void CreateValidators(ModelValidatorProviderContext context) { diff --git a/src/Umbraco.Web.Website/Extensions/HtmlHelperRenderExtensions.cs b/src/Umbraco.Web.Website/Extensions/HtmlHelperRenderExtensions.cs index efb48d59da..1df5c8ef1e 100644 --- a/src/Umbraco.Web.Website/Extensions/HtmlHelperRenderExtensions.cs +++ b/src/Umbraco.Web.Website/Extensions/HtmlHelperRenderExtensions.cs @@ -872,7 +872,7 @@ public static class HtmlHelperRenderExtensions /// /// Used for rendering out the Form for BeginUmbracoForm /// - internal class UmbracoForm : MvcForm + internal sealed class UmbracoForm : MvcForm { private readonly string _surfaceControllerInput; private readonly ViewContext _viewContext; diff --git a/src/Umbraco.Web.Website/Routing/EagerMatcherPolicy.cs b/src/Umbraco.Web.Website/Routing/EagerMatcherPolicy.cs index 1752fa0a72..37035ef8ab 100644 --- a/src/Umbraco.Web.Website/Routing/EagerMatcherPolicy.cs +++ b/src/Umbraco.Web.Website/Routing/EagerMatcherPolicy.cs @@ -34,7 +34,7 @@ namespace Umbraco.Cms.Web.Website.Routing; * This also handles rerouting under install/upgrade states. */ -internal class EagerMatcherPolicy : MatcherPolicy, IEndpointSelectorPolicy +internal sealed class EagerMatcherPolicy : MatcherPolicy, IEndpointSelectorPolicy { private readonly IRuntimeState _runtimeState; private readonly EndpointDataSource _endpointDataSource; diff --git a/src/Umbraco.Web.Website/Routing/NotFoundSelectorPolicy.cs b/src/Umbraco.Web.Website/Routing/NotFoundSelectorPolicy.cs index b99b432942..44b9627f31 100644 --- a/src/Umbraco.Web.Website/Routing/NotFoundSelectorPolicy.cs +++ b/src/Umbraco.Web.Website/Routing/NotFoundSelectorPolicy.cs @@ -13,7 +13,7 @@ namespace Umbraco.Cms.Web.Website.Routing; /// /// Used to handle 404 routes that haven't been handled by the end user /// -internal class NotFoundSelectorPolicy : MatcherPolicy, IEndpointSelectorPolicy +internal sealed class NotFoundSelectorPolicy : MatcherPolicy, IEndpointSelectorPolicy { private readonly EndpointDataSource _endpointDataSource; private readonly Lazy _notFound; diff --git a/src/Umbraco.Web.Website/Routing/SurfaceControllerMatcherPolicy.cs b/src/Umbraco.Web.Website/Routing/SurfaceControllerMatcherPolicy.cs index e2b0082cc2..ae8099aa3d 100644 --- a/src/Umbraco.Web.Website/Routing/SurfaceControllerMatcherPolicy.cs +++ b/src/Umbraco.Web.Website/Routing/SurfaceControllerMatcherPolicy.cs @@ -11,7 +11,7 @@ namespace Umbraco.Cms.Web.Website.Routing; /// Ensures the surface controller requests takes priority over other things like virtual routes. /// Also ensures that requests to a surface controller on a virtual route will return 405, like HttpMethodMatcherPolicy ensures for non-virtual route requests. /// -internal class SurfaceControllerMatcherPolicy : MatcherPolicy, IEndpointSelectorPolicy +internal sealed class SurfaceControllerMatcherPolicy : MatcherPolicy, IEndpointSelectorPolicy { private const string Http405EndpointDisplayName = "405 HTTP Method Not Supported"; diff --git a/src/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformer.cs b/src/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformer.cs index 0816e655e0..a990d981db 100644 --- a/src/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformer.cs +++ b/src/Umbraco.Web.Website/Routing/UmbracoRouteValueTransformer.cs @@ -272,7 +272,7 @@ public class UmbracoRouteValueTransformer : DynamicRouteValueTransformer return values; } - private class PostedDataProxyInfo + private sealed class PostedDataProxyInfo { public string? ControllerName { get; set; } diff --git a/src/Umbraco.Web.Website/Security/MemberAuthenticationBuilder.cs b/src/Umbraco.Web.Website/Security/MemberAuthenticationBuilder.cs index 50e6f80b78..36274f4705 100644 --- a/src/Umbraco.Web.Website/Security/MemberAuthenticationBuilder.cs +++ b/src/Umbraco.Web.Website/Security/MemberAuthenticationBuilder.cs @@ -59,7 +59,7 @@ public class MemberAuthenticationBuilder : AuthenticationBuilder } // Ensures that the sign in scheme is always the Umbraco member external type - private class EnsureMemberScheme : IPostConfigureOptions + private sealed class EnsureMemberScheme : IPostConfigureOptions where TOptions : RemoteAuthenticationOptions { public void PostConfigure(string? name, TOptions options) diff --git a/src/Umbraco.Web.Website/ViewEngines/PluginRazorViewEngineOptionsSetup.cs b/src/Umbraco.Web.Website/ViewEngines/PluginRazorViewEngineOptionsSetup.cs index ca7696c1e9..a12f7e6524 100644 --- a/src/Umbraco.Web.Website/ViewEngines/PluginRazorViewEngineOptionsSetup.cs +++ b/src/Umbraco.Web.Website/ViewEngines/PluginRazorViewEngineOptionsSetup.cs @@ -23,7 +23,7 @@ public class PluginRazorViewEngineOptionsSetup : IConfigureOptions /// Expands the default view locations /// - private class ViewLocationExpander : IViewLocationExpander + private sealed class ViewLocationExpander : IViewLocationExpander { public IEnumerable ExpandViewLocations( ViewLocationExpanderContext context, IEnumerable viewLocations) diff --git a/src/Umbraco.Web.Website/ViewEngines/RenderRazorViewEngineOptionsSetup.cs b/src/Umbraco.Web.Website/ViewEngines/RenderRazorViewEngineOptionsSetup.cs index 25022feafc..a1148bc071 100644 --- a/src/Umbraco.Web.Website/ViewEngines/RenderRazorViewEngineOptionsSetup.cs +++ b/src/Umbraco.Web.Website/ViewEngines/RenderRazorViewEngineOptionsSetup.cs @@ -22,7 +22,7 @@ public class RenderRazorViewEngineOptionsSetup : IConfigureOptions /// Expands the default view locations /// - private class ViewLocationExpander : IViewLocationExpander + private sealed class ViewLocationExpander : IViewLocationExpander { public IEnumerable ExpandViewLocations( ViewLocationExpanderContext context, IEnumerable viewLocations) diff --git a/tests/Umbraco.Tests.Common/Builders/ContentDataBuilder.cs b/tests/Umbraco.Tests.Common/Builders/ContentDataBuilder.cs index cd0c6f031f..e89d68951f 100644 --- a/tests/Umbraco.Tests.Common/Builders/ContentDataBuilder.cs +++ b/tests/Umbraco.Tests.Common/Builders/ContentDataBuilder.cs @@ -7,7 +7,7 @@ using Umbraco.Extensions; namespace Umbraco.Cms.Tests.Common.Builders; -internal class ContentDataBuilder : BuilderBase, IWithNameBuilder +internal sealed class ContentDataBuilder : BuilderBase, IWithNameBuilder { private Dictionary _cultureInfos; private string _name; diff --git a/tests/Umbraco.Tests.Integration/DependencyInjection/UmbracoBuilderExtensions.cs b/tests/Umbraco.Tests.Integration/DependencyInjection/UmbracoBuilderExtensions.cs index f2fdfe2128..021eaaa2ba 100644 --- a/tests/Umbraco.Tests.Integration/DependencyInjection/UmbracoBuilderExtensions.cs +++ b/tests/Umbraco.Tests.Integration/DependencyInjection/UmbracoBuilderExtensions.cs @@ -150,7 +150,7 @@ public static class UmbracoBuilderExtensions } // replace the default so there is no background index rebuilder - private class TestBackgroundIndexRebuilder : ExamineIndexRebuilder + private sealed class TestBackgroundIndexRebuilder : ExamineIndexRebuilder { public TestBackgroundIndexRebuilder( IMainDom mainDom, diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/ContentTypeRepositoryTest.cs b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/ContentTypeRepositoryTest.cs index 17cbab42ed..bba1bd864b 100644 --- a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/ContentTypeRepositoryTest.cs +++ b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/ContentTypeRepositoryTest.cs @@ -87,7 +87,6 @@ internal sealed class ContentTypeRepositoryTest : UmbracoIntegrationTest AppCaches.Disabled, LoggerFactory.CreateLogger(), FileSystems, - IOHelper, ShortStringHelper, Mock.Of(), runtimeSettingsMock.Object); diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/DocumentRepositoryTest.cs b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/DocumentRepositoryTest.cs index 22cc35b424..b794eccd86 100644 --- a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/DocumentRepositoryTest.cs +++ b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/DocumentRepositoryTest.cs @@ -117,7 +117,7 @@ internal sealed class DocumentRepositoryTest : UmbracoIntegrationTest var runtimeSettingsMock = new Mock>(); runtimeSettingsMock.Setup(x => x.CurrentValue).Returns(new RuntimeSettings()); - templateRepository = new TemplateRepository(scopeAccessor, appCaches, LoggerFactory.CreateLogger(), FileSystems, IOHelper, ShortStringHelper, Mock.Of(), runtimeSettingsMock.Object); + templateRepository = new TemplateRepository(scopeAccessor, appCaches, LoggerFactory.CreateLogger(), FileSystems, ShortStringHelper, Mock.Of(), runtimeSettingsMock.Object); var tagRepository = new TagRepository(scopeAccessor, appCaches, LoggerFactory.CreateLogger()); var commonRepository = new ContentTypeCommonRepository(scopeAccessor, templateRepository, appCaches, ShortStringHelper); diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/TemplateRepositoryTest.cs b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/TemplateRepositoryTest.cs index 2350b1d1f5..bcef116a97 100644 --- a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/TemplateRepositoryTest.cs +++ b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/TemplateRepositoryTest.cs @@ -63,7 +63,7 @@ internal sealed class TemplateRepositoryTest : UmbracoIntegrationTest private IOptionsMonitor RuntimeSettings => GetRequiredService>(); private ITemplateRepository CreateRepository(IScopeProvider provider) => - new TemplateRepository((IScopeAccessor)provider, AppCaches.Disabled, LoggerFactory.CreateLogger(), FileSystems, IOHelper, ShortStringHelper, ViewHelper, RuntimeSettings); + new TemplateRepository((IScopeAccessor)provider, AppCaches.Disabled, LoggerFactory.CreateLogger(), FileSystems, ShortStringHelper, ViewHelper, RuntimeSettings); [Test] public void Can_Instantiate_Repository() diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/UserRepositoryTest.cs b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/UserRepositoryTest.cs index 96575a67e7..b7c8f1ce3c 100644 --- a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/UserRepositoryTest.cs +++ b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/UserRepositoryTest.cs @@ -57,8 +57,7 @@ internal sealed class UserRepositoryTest : UmbracoIntegrationTest Options.Create(new UserPasswordConfigurationSettings()), new SystemTextJsonSerializer(), mockRuntimeState.Object, - PermissionMappers, - AppPolicyCache); + PermissionMappers); return repository; } @@ -165,8 +164,7 @@ internal sealed class UserRepositoryTest : UmbracoIntegrationTest Options.Create(new UserPasswordConfigurationSettings()), new SystemTextJsonSerializer(), mockRuntimeState.Object, - PermissionMappers, - AppPolicyCache); + PermissionMappers); repository2.Delete(user); diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/ImportResources.Designer.cs b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/ImportResources.Designer.cs index 45fd3a2057..3e5bc253a7 100644 --- a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/ImportResources.Designer.cs +++ b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/Importing/ImportResources.Designer.cs @@ -18,7 +18,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services.Importin [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class ImportResources { + internal sealed class ImportResources { private static global::System.Resources.ResourceManager resourceMan; diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Persistence.EFCore/DbContext/UmbracoLock.cs b/tests/Umbraco.Tests.Integration/Umbraco.Persistence.EFCore/DbContext/UmbracoLock.cs index 02a3c648cb..1dcd65a966 100644 --- a/tests/Umbraco.Tests.Integration/Umbraco.Persistence.EFCore/DbContext/UmbracoLock.cs +++ b/tests/Umbraco.Tests.Integration/Umbraco.Persistence.EFCore/DbContext/UmbracoLock.cs @@ -1,6 +1,6 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Persistence.EFCore.DbContext; -internal class UmbracoLock +internal sealed class UmbracoLock { public int Id { get; set; } diff --git a/tests/Umbraco.Tests.UnitTests/AutoFixture/Customizations/OmitRecursionCustomization.cs b/tests/Umbraco.Tests.UnitTests/AutoFixture/Customizations/OmitRecursionCustomization.cs index 1ae0af54ef..b7615d7c75 100644 --- a/tests/Umbraco.Tests.UnitTests/AutoFixture/Customizations/OmitRecursionCustomization.cs +++ b/tests/Umbraco.Tests.UnitTests/AutoFixture/Customizations/OmitRecursionCustomization.cs @@ -2,7 +2,7 @@ using AutoFixture; namespace Umbraco.Cms.Tests.UnitTests.AutoFixture.Customizations; -internal class OmitRecursionCustomization : ICustomization +internal sealed class OmitRecursionCustomization : ICustomization { public void Customize(IFixture fixture) => fixture.Behaviors.Add(new OmitOnRecursionBehavior()); diff --git a/tests/Umbraco.Tests.UnitTests/AutoFixture/Customizations/UmbracoCustomizations.cs b/tests/Umbraco.Tests.UnitTests/AutoFixture/Customizations/UmbracoCustomizations.cs index 1d1c25f8df..2593f08295 100644 --- a/tests/Umbraco.Tests.UnitTests/AutoFixture/Customizations/UmbracoCustomizations.cs +++ b/tests/Umbraco.Tests.UnitTests/AutoFixture/Customizations/UmbracoCustomizations.cs @@ -1,16 +1,13 @@ -using System.Linq; using AutoFixture; using AutoFixture.Kernel; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Identity; -using Microsoft.Extensions.Options; using Moq; using Umbraco.Cms.Api.Management.Controllers.Security; using Umbraco.Cms.Api.Management.Routing; using Umbraco.Cms.Core; using Umbraco.Cms.Core.Configuration; using Umbraco.Cms.Core.Configuration.Models; -using Umbraco.Cms.Core.Hosting; using Umbraco.Cms.Core.Routing; using Umbraco.Cms.Core.Security; using Umbraco.Cms.Core.Services; @@ -20,7 +17,7 @@ using Umbraco.Cms.Web.Common.Security; namespace Umbraco.Cms.Tests.UnitTests.AutoFixture.Customizations; -internal class UmbracoCustomizations : ICustomization +internal sealed class UmbracoCustomizations : ICustomization { public void Customize(IFixture fixture) { diff --git a/tools/Umbraco.JsonSchema/Options.cs b/tools/Umbraco.JsonSchema/Options.cs index cba5d1f16b..b1ea7ac608 100644 --- a/tools/Umbraco.JsonSchema/Options.cs +++ b/tools/Umbraco.JsonSchema/Options.cs @@ -1,6 +1,6 @@ using CommandLine; -internal class Options +internal sealed class Options { [Option("outputFile", Default = "appsettings-schema.Umbraco.Cms.json", HelpText = "Output file to save the generated JSON schema for Umbraco CMS.")] public required string OutputFile { get; set; } diff --git a/tools/Umbraco.JsonSchema/UmbracoCmsSchema.cs b/tools/Umbraco.JsonSchema/UmbracoCmsSchema.cs index 63ae6b1efa..1a874e40dc 100644 --- a/tools/Umbraco.JsonSchema/UmbracoCmsSchema.cs +++ b/tools/Umbraco.JsonSchema/UmbracoCmsSchema.cs @@ -1,8 +1,7 @@ -using Umbraco.Cms.Core.Configuration; using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.Models; -internal class UmbracoCmsSchema +internal sealed class UmbracoCmsSchema { public required UmbracoDefinition Umbraco { get; set; } diff --git a/tools/Umbraco.JsonSchema/UmbracoJsonSchemaGenerator.cs b/tools/Umbraco.JsonSchema/UmbracoJsonSchemaGenerator.cs index 099ad498c3..fee902ffac 100644 --- a/tools/Umbraco.JsonSchema/UmbracoJsonSchemaGenerator.cs +++ b/tools/Umbraco.JsonSchema/UmbracoJsonSchemaGenerator.cs @@ -5,7 +5,7 @@ using NJsonSchema; using NJsonSchema.Generation; /// -internal class UmbracoJsonSchemaGenerator : JsonSchemaGenerator +internal sealed class UmbracoJsonSchemaGenerator : JsonSchemaGenerator { /// /// Initializes a new instance of the class. @@ -26,7 +26,7 @@ internal class UmbracoJsonSchemaGenerator : JsonSchemaGenerator { } /// - private class UmbracoSystemTextJsonReflectionService : SystemTextJsonReflectionService + private sealed class UmbracoSystemTextJsonReflectionService : SystemTextJsonReflectionService { /// public override void GenerateProperties(JsonSchema schema, ContextualType contextualType, SystemTextJsonSchemaGeneratorSettings settings, JsonSchemaGenerator schemaGenerator, JsonSchemaResolver schemaResolver) From 2a83e405a708f58b21da998ba7c084c200ce248b Mon Sep 17 00:00:00 2001 From: Lucas Bach Bisgaard Date: Mon, 21 Jul 2025 09:26:30 +0200 Subject: [PATCH 11/23] add missing translation for DA (#19740) Co-authored-by: Lucas Bach Bisgaard --- .../src/assets/lang/da.ts | 172 +++++++++++++++++- 1 file changed, 170 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/assets/lang/da.ts b/src/Umbraco.Web.UI.Client/src/assets/lang/da.ts index 6722394404..f1648d91b1 100644 --- a/src/Umbraco.Web.UI.Client/src/assets/lang/da.ts +++ b/src/Umbraco.Web.UI.Client/src/assets/lang/da.ts @@ -18,6 +18,7 @@ export default { changeDocType: 'Skift Dokument Type', changeDataType: 'Skift Input Type', copy: 'Kopier', + copyTo: 'Kopier til', create: 'Opret', export: 'Eksportér', createPackage: 'Opret pakke', @@ -65,6 +66,13 @@ export default { editContent: 'Rediger indhold', chooseWhereToImport: 'Vælg hvor du vil importere', viewActionsFor: (name) => (name ? `Se handlinger for '${name}'` : 'Se handlinger'), + folderCreate: 'Opret mappe', + folderDelete: 'Slet', + folderRename: 'Omdøb', + import: 'Importer', + read: 'Læs', + readOnly: 'Skrivebeskyttet', + trash: 'Papirkurv', loadMore: 'Indlæs flere', }, actionCategories: { @@ -85,6 +93,7 @@ export default { protect: 'Tillad adgang til at indstille og ændre offentlig adgang til en node', publish: 'Tillad adgang til at udgive en node', unpublish: 'Tillad adgang til at afpublicere en node', + read: 'Tillad adgang til at læse et dokument', rights: 'Tillad adgang til at ændre rettigheder for en node', rollback: 'Tillad adgang til at returnere en node til en tidligere tilstand', sendtopublish: 'Tillad adgang til at sende en node til godkendelse før den udgives', @@ -168,7 +177,15 @@ export default { morePublishingOptions: 'Flere publiseringsmuligheder', submitChanges: 'Indsæt', }, + auditTrailsMedia: { + delete: 'Medie slettet', + move: 'Medie flyttet', + copy: 'Medie kopieret', + save: 'Medie gemt', + }, auditTrails: { + assigndomain: 'Domæne tildelt: %0%', + smallAssignDomain: 'Tildel domæne', atViewingFor: 'For', delete: 'Brugeren har slettet indholdet', unpublish: 'Brugeren har afpubliceret indholdet', @@ -330,6 +347,11 @@ export default { variantScheduleNotAllowed: 'Schedule is not allowed', variantUnpublishNotAllowed: 'Unpublish is not allowed', saveModalTitle: 'Gem', + saveAndPublishModalTitle: 'Gem og udgiv', + publishModalTitle: 'Udgiv', + selectAllVariants: 'Vælg alle varianter', + scheduledPendingChanges: 'Denne tidsplan har ændringer, der træder i kraft, når du klikker på "%0%".', + noVariantsToProcess: 'Der er ingen tilgængelige varianter', }, blueprints: { createBlueprintFrom: "Opret en ny indholdsskabelon fra '%0%'", @@ -345,7 +367,7 @@ export default { }, entityDetail: { notFoundTitle: (entityType: string) => { - const entityName = entityType ?? 'Elementet'; + const entityName = entityType ?? 'Elementet'; return `${entityName} blev ikke fundet`; }, notFoundDescription: (entityType: string) => { @@ -375,6 +397,7 @@ export default { renameFolderFailed: 'Omdøbning af mappen med id %0% fejlede', dragAndDropYourFilesIntoTheArea: 'Træk dine filer ind i dropzonen for, at uploade dem til\n mediebiblioteket.\n ', + fileSecurityValidationFailure: 'En eller flere fil-sikkerhedsvalideringer er fejlet', uploadNotAllowed: 'Upload er ikke tiladt på denne lokation', }, member: { @@ -394,6 +417,7 @@ export default { contentType: { copyFailed: 'Kopiering af indholdstypen fejlede', moveFailed: 'Flytning af indholdstypen fejlede', + contentTypes: 'Indholdstyper', }, mediaType: { copyFailed: 'Kopiering af medietypen fejlede', @@ -441,6 +465,7 @@ export default { 'Benyttes til at organisere dokumenttyper, element-typer og kompositioner i\n dokumenttype-træet.\n ', newFolder: 'Ny mappe', newDataType: 'Ny datatype', + newDataTypeDescription: 'Bruges til at definere en konfiguration for en Egenskabstype på en Indholdstype.', newJavascriptFile: 'Ny JavaScript-fil', newEmptyPartialView: 'Ny tom partial view', newPartialViewMacro: 'Ny partial view makro', @@ -605,6 +630,13 @@ export default { 'Modifying layout will result in loss of data for any existing content that is based on this configuration.', seeErrorAction: 'Se fejlen', seeErrorDialogHeadline: 'Fejl detaljer', + selectEvent: 'Vælg begivenhed', + editWebhook: 'Rediger webhook', + confirmTrash: (name: string) => `Er du sikker på, at du vil flytte ${name} til papirkurven?`, + confirmBulkTrash: (total: number) => + `Er du sikker på, at du vil flytte ${total} ${total === 1 ? 'element' : 'elementer'} til papirkurven?`, + confirmBulkDelete: (total: number) => + `Er du sikker på, at du vil slette ${total} ${total === 1 ? 'element' : 'elementer'}?`, }, dictionary: { noItems: 'Der er ingen ordbogselementer.', @@ -615,6 +647,8 @@ export default { noItemsInFile: 'There are no dictionary items in this file.', noItemsFound: 'There were no dictionary items found.', createNew: 'Create dictionary item', + pickFile: 'Vælg fil', + pickFileRequired: 'Vælg venligst en ".udt" fil', }, dictionaryItem: { description: @@ -650,6 +684,10 @@ export default { indexCannotRebuild: 'Dette index kan ikke genbygges for det ikke har nogen', iIndexPopulator: 'IIndexPopulator', contentInIndex: 'Content in index', + noResults: 'Ingen resultater blev fundet', + searchResultsFound: 'Viser %0% - %1% af %2% resultat(er) - Side %3% af %4%', + corruptStatus: 'Mulig korrupt indeks opdaget', + corruptErrorDescription: 'Fejl modtaget ved evaluering af indekset:', }, placeholders: { username: 'Indtast dit brugernavn', @@ -675,6 +713,8 @@ export default { a11yName: 'Navn', rteParagraph: 'Udfold din kreativitet...', rteHeading: 'Hvad skal overskriften være?', + enterUrl: 'Indtast en URL...', + enterdate: 'Vælg en dato...', }, editcontenttype: { createListView: 'Opret brugerdefineret listevisning', @@ -707,6 +747,7 @@ export default { 'I understand this action will delete the properties and data based on this Data\n Type\n ', canChangePropertyEditorHelp: 'Changing a property editor on a data type with stored values is disabled. To allow this you can change the Umbraco:CMS:DataTypes:CanBeChanged setting in appsettings.json.', + noConfiguration: 'Der er ingen konfiguration for denne egenskabseditor.', }, errorHandling: { errorButDataWasSaved: @@ -951,6 +992,13 @@ export default { if (new Date(date).getTime() < new Date(now).getTime()) return `for ${duration} siden`; return `om ${duration}`; }, + primary: 'Primær', + change: 'Skift', + pixels: 'pixels', + notFound: 'Ikke fundet', + manifest: 'Manifest', + toggleFor: 'Toggle for %0%', + document: 'Dokument', }, colors: { blue: 'Blå', @@ -1083,6 +1131,7 @@ export default { language: { cultureCode: 'Culture Code', displayName: 'Culture Name', + noFallbackLanguages: 'Der er ingen andre sprog at vælge imellem', }, lockout: { lockoutWillOccur: 'Du har været inaktiv, og du vil blive logget ud om', @@ -1187,6 +1236,7 @@ export default { installInstructions: 'Install instructions', packagesPromoted: 'Promoted', packageMigrationsRun: 'Run pending package migrations', + packageMigrationsConfirmText: 'Vil du køre de ventende pakke-migrationer?', packageMigrationsComplete: 'Package migrations have successfully completed.', packageMigrationsNonePending: 'All package migrations have successfully completed.', verifiedToWorkOnUmbracoCloud: 'Verified to work on Umbraco Cloud', @@ -1255,6 +1305,13 @@ export default { defineRootNode: 'Vælg udgangspunkt', pickedTrashedItem: 'Du har valgt et dokument som er slettet eller lagt i papirkurven', pickedTrashedItems: 'Du har valgt dokumenter som er slettede eller lagt i papirkurven', + specifyPickerRootTitle: 'Angiv rod', + defineXPathOrigin: 'Angiv via XPath', + unsupportedHeadline: (type?: string) => + `Ikke-understøttede ${type ?? 'indholds'} elementer
Følgende indhold understøttes ikke længere i denne editor.`, + unsupportedMessage: + 'Hvis du stadig har brug for dette indhold, bedes du kontakte din administrator. Ellers kan du fjerne det.', + unsupportedRemove: 'Fjern ikke-understøttede elementer?', }, dynamicRoot: { configurationTitle: 'Dynamisk udgangspunkts forespørgsel', @@ -1287,6 +1344,7 @@ export default { noValidStartNodeTitle: 'Intet passende indhold', noValidStartNodeDesc: 'Konfigurationen af dette felt passer ikke med noget indhold. Opret det manglende indhold eller kontakt din adminnistrator for at tilpasse Dynamisk Udgangspunkts Forespørgselen for dette felt.', + cancelAndClearQuery: 'Annuller og ryd søgning', }, mediaPicker: { deletedItem: 'Slettet medie', @@ -1504,6 +1562,13 @@ export default { dictionaryItemImported: 'The following dictionary item(s) has been imported!', preventCleanupEnableError: 'An error occurred while enabling version cleanup for %0%', preventCleanupDisableError: 'An error occurred while disabling version cleanup for %0%', + offlineHeadline: 'Offline', + offlineMessage: 'Du er i øjeblikket offline. Tjek venligst din internetforbindelse.', + onlineHeadline: 'Online', + onlineMessage: 'Du er nu online. Du kan fortsætte arbejdet.', + editContentScheduledNotSavedText: 'Planlægningen for publicering kunne ikke opdateres', + webhookSaved: 'Webhook gemt', + editContentPublishedFailedByValidation: 'Dokumentet kunne ikke publiceres, men det er gemt for dig', }, stylesheet: { addRule: 'Tilføj style', @@ -1562,6 +1627,8 @@ export default { itemsReturned: 'sider returneret, på', iWant: 'Returner', allContent: 'alt indhold', + systemFields: 'Systemfelter', + publishedItemsReturned: 'Der blev returneret %0% publicerede elementer på %1% ms', contentOfType: 'indhold af typen "%0%"', from: 'fra', websiteRoot: 'mit website', @@ -1643,6 +1710,8 @@ export default { '

Modifying a row configuration name will result in loss of data for any existing content that is based on this configuration.

Modifying only the label will not result in data loss.

', }, contentTypeEditor: { + cultureAndVariantInvariantLabel: 'Delt på tværs af sprog og segmenter', + editProperty: 'Rediger egenskab', compositions: 'Kompositioner', group: 'Gruppe', noGroups: 'Du har ikke tilføjet nogen grupper', @@ -1754,6 +1823,35 @@ export default { structure: 'Struktur', presentation: 'Præsentation', }, + webhooks: { + addWebhook: 'Opret webhook', + addWebhookHeader: 'Tilføj webhook-header', + addDocumentType: 'Tilføj dokumenttype', + addMediaType: 'Tilføj medietype', + createHeader: 'Opret header', + deliveries: 'Leveringer', + noHeaders: 'Der er ikke tilføjet nogen webhook-headers', + noEventsFound: 'Ingen hændelser blev fundet.', + enabled: 'Aktiveret', + disabled: 'Deaktiveret', + events: 'Hændelser', + event: 'Hændelse', + url: 'URL', + types: 'Indholdstyper', + webhookKey: 'Webhook-nøgle', + retryCount: 'Antal forsøg', + urlDescription: 'Den URL der kaldes, når webhooken udløses.', + eventDescription: 'De hændelser, som webhooken skal udløses for.', + contentTypeDescription: 'Udløs kun webhooken for en specifik indholdstype.', + enabledDescription: 'Er webhooken aktiveret?', + headersDescription: 'Brugertilpassede headers, der inkluderes i webhook-anmodningen.', + contentType: 'Indholdstype', + headers: 'Headers', + selectEventFirst: 'Vælg venligst en hændelse først.', + selectEvents: 'Vælg hændelser', + statusCode: 'Statuskode', + unnamedWebhook: 'Navnløs webhook', + }, languages: { addLanguage: 'Tilføj sprog', mandatoryLanguage: 'Påkrævet sprog', @@ -1884,6 +1982,8 @@ export default { settingsGroup: 'Indstillinger', templatingGroup: 'Design og layout', thirdPartyGroup: 'Tredjepart', + structureGroup: 'Struktur', + advancedGroup: 'Avanceret', webhooks: 'Webhooks', }, update: { @@ -1902,8 +2002,14 @@ export default { createUserHeadline: (kind: string) => { return kind === 'Api' ? 'Opret API bruger' : 'Opret bruger'; }, + createUserDescription: (kind: string) => { + const defaultUserText = `Opret en bruger for at give adgang til Umbraco. Når en bruger oprettes, genereres der en adgangskode, som du kan dele med brugeren.`; + const apiUserText = `Opret en API-bruger for at give eksterne tjenester mulighed for at godkende via Umbraco Management API'et.`; + return kind === 'Api' ? apiUserText : defaultUserText; + }, changePassword: 'Skift dit kodeord', changePhoto: 'Skift billede', + configureMfa: 'Konfigurer MFA', newPassword: 'Nyt kodeord', newPasswordFormatLengthTip: 'Minium %0% karakterer tilbage!', newPasswordFormatNonAlphaTip: 'Der skal som minium være %0% specielle karakterer.', @@ -1931,6 +2037,10 @@ export default { kind: 'Slags', language: 'Sprog', languageHelp: 'Indstil det sprog, du vil se i menuer og dialoger', + languageNotFound: (culture: string, baseCulture: string) => + `Den angivne kultur "${culture}" blev ikke fundet, basis-kulturen "${baseCulture}" vil blive brugt.`, + languageNotFoundFallback: (culture: string, baseCulture: string) => + `Hverken den angivne kultur "${culture}" eller basis-kulturen "${baseCulture}" blev fundet, standard fallback-kulturen "Engelsk (UK)" vil blive brugt.`, lastLockoutDate: 'Senest låst ude', lastLogin: 'Seneste login', lastPasswordChangeDate: 'Kodeord sidst ændret', @@ -1968,6 +2078,8 @@ export default { permissionsEntityGroup_document: 'Indhold', permissionsEntityGroup_media: 'Medie', permissionsEntityGroup_member: 'Medlemmer', + 'permissionsEntityGroup_document-property-value': 'Dokumentegenskabsværdi', + permissionNoVerbs: 'Ingen tilladte rettigheder', profile: 'Profil', searchAllChildren: "Søg alle 'børn'", languagesHelp: 'Tilføj sprog for at give brugerne adgang til at redigere', @@ -2107,6 +2219,10 @@ export default { duplicateUsername: "Brugernavnet '%0%' er allerede taget", legacyOption: 'Ugyldig indstilling', legacyOptionDescription: 'Denne indstilling understøttes ikke længere, vælg venligst noget andet', + numberMisconfigured: "Minimumsværdien '%0%' skal være mindre end maksimumsværdien '%1%'.", + invalidExtensions: 'En eller flere af filtypenavnene er ugyldige.', + allowedExtensions: 'Tilladte filtypenavne er:', + disallowedExtensions: 'Ikke tilladte filtypenavne er:', }, redirectUrls: { disableUrlTracker: 'Slå URL tracker fra', @@ -2228,6 +2344,8 @@ export default { searchContentTree: 'Søg i indholdstræet', maxAmount: 'Maximum antal', contextDialogDescription: 'Perform action %0% on the %1% node', + expandChildItems: 'Udvid underordnede elementer for', + openContextNode: 'Åbn kontekstnode for', }, references: { tabName: 'Referencer', @@ -2311,6 +2429,7 @@ export default { labelForCopyToClipboard: 'Kopier til udklipsholder', confirmDeleteHeadline: 'Slet fra udklipsholderen', confirmDeleteDescription: 'Er du sikker på at du vil slette {0} fra udklipsholderen?', + copySuccessHeadline: 'Kopieret til udklipsholder', }, propertyActions: { tooltipForPropertyActionsMenu: 'Åben egenskabshandlinger', @@ -2340,10 +2459,12 @@ export default { labelEditorSize: 'Rederings lagets størrelse', addCustomView: 'Tilføj speciel visning', addSettingsElementType: 'Tilføj instillinger', + confirmDeleteBlockTitle: 'Slet %0', confirmDeleteBlockMessage: 'Er du sikker på at du vil slette indholdet %0%?', confirmDeleteBlockTypeMessage: 'Er du sikker på at du vil slette konfigurationen %0%?', confirmDeleteBlockTypeNotice: 'Indholdet vil stadigt eksistere, men redigering af dette indhold vil ikke\n være muligt. Indholdet vil blive vist som ikke understøttet indhold.\n ', + confirmDeleteBlockGroupTitle: 'Slet gruppe?', confirmDeleteBlockGroupMessage: 'Er du sikker på at du vil slette gruppen %0% og blok konfigurationer?', confirmDeleteBlockGroupNotice: @@ -2356,6 +2477,7 @@ export default { tabClipboard: 'Udklipsholder', tabBlockSettings: 'Indstillinger', headlineAdvanced: 'Avanceret', + headlineCustomView: 'Brugerdefineret visning', forceHideContentEditor: 'Skjul indholdseditoren', forceHideContentEditorHelp: 'Skjul indholds redigerings knappen samt indholdseditoren i Blok Redigerings vinduet', gridInlineEditing: 'Direkte redigering', @@ -2385,6 +2507,7 @@ export default { layoutOptions: 'Layout-opsætning', structuralOptions: 'Struktur', sizeOptions: 'Størrelses opsætning', + sizeOptionsHelp: 'Definér en eller flere størrelsesmuligheder for at gøre blokken kan ændres i størrelse', allowedBlockColumns: 'Tilgængelige kolonne-størrelser', allowedBlockColumnsHelp: 'Vælg de forskellige antal kolonner denne blok må optage i layoutet. Dette forhindre ikke blokken i at optræde i et mindre område.', @@ -2432,7 +2555,6 @@ export default { configureArea: 'Konfigurer område', deleteArea: 'Slet område', addColumnSpanOption: 'Tilføj mulighed for %0% koloner', - sizeOptionsHelp: 'Define one or more size options, this enables resizing of the Block', allowBlockInAreas: 'Allow in areas', allowBlockInAreasHelp: 'Make this block available by default within the areas of other Blocks (unless explicit permissions are set for these areas).', @@ -2445,6 +2567,10 @@ export default { unsupportedBlockName: 'Ugyldigt indhold', unsupportedBlockDescription: 'Dette indhold er ikke længere understøttet. Hvis du mangler dette indhold bør du kontakte din administrator. Ellers bør du slette dette indhold.', + blockVariantConfigurationNotSupported: + 'En eller flere bloktyper i denne blokeditor bruger en elementtype, der er konfigureret til at variere efter kultur eller segment. Dette understøttes ikke på et indholdselement, som ikke varierer efter kultur eller segment.', + areaValidationEntriesNotAllowed: '%0% er ikke tilladt i dette område.', + rootValidationEntriesNotAllowed: '%0% er ikke tilladt i roden af denne egenskab.', }, contentTemplatesDashboard: { whatHeadline: 'Hvad er Indholdsskabeloner?', @@ -2578,6 +2704,8 @@ export default { trainingHeadline: 'Hours of Umbraco training videos are only a click away', trainingDescription: '\n

Want to master Umbraco? Spend a couple of minutes learning some best practices by watching one of these videos about using Umbraco. And visit umbraco.tv for even more Umbraco videos

\n ', + learningBaseDescription: + '

Vil du mestre Umbraco? Brug et par minutter på at lære nogle best practices ved at besøge Umbraco Learning Base YouTube-kanalen. Her finder du en masse videoer, der dækker mange aspekter af Umbraco.

', getStarted: 'To get you started', }, settingsDashboard: { @@ -2648,12 +2776,33 @@ export default { wordWrapConfigDescription: 'Slå ordbrydning til eller fra, så tekst automatisk brydes ved vinduets kant i stedet for at skabe en horisontal scrollbar.', }, + rte: { + config_blocks: 'Tilgængelige blokke', + config_blocks_description: 'Definér de tilgængelige blokke.', + config_ignoreUserStartNodes: 'Ignorer brugerens startnoder', + config_maxImageSize: 'Maksimal størrelse for indsatte billeder', + config_maxImageSize_description: 'Maksimal bredde eller højde – indtast 0 for at deaktivere ændring af størrelse.', + config_mediaParentId: 'Upload-mappe til billeder', + config_mediaParentId_description: 'Vælg uploadplacering for indsatte billeder.', + config_overlaySize: 'Overlay-størrelse', + config_overlaySize_description: 'Vælg bredden på overlayet (linkvælger).', + }, tiptap: { + anchor: 'Anker', + anchor_input: 'Indtast anker-ID', + config_dimensions_description: 'Sæt den maksimale bredde og højde på editoren. Dette ekskluderer værktøjslinjens højde.', + maxDimensions: 'Maksimale dimensioner', + minDimensions: 'Minimale dimensioner', + config_extensions: 'Funktioner', + config_statusbar: 'Statuslinje', + config_toolbar: 'Værktøjslinje', extGroup_formatting: 'Text formattering', extGroup_interactive: 'Inaktive elementer', extGroup_media: 'Medier', extGroup_structure: 'Indholds struktur', extGroup_unknown: 'Ukategoriseret', + statusbar_availableItems: 'Tilgængelige statusser', + statusbar_availableItemsEmpty: 'Der er ingen statuslinjeudvidelser at vise', toobar_availableItems: 'Tilgængelige handlinger', toobar_availableItemsEmpty: 'Ingen handler at vise', toolbar_designer: 'Handlings designer', @@ -2664,9 +2813,28 @@ export default { toolbar_removeGroup: 'Fjern gruppe', toolbar_removeItem: 'Fjern handling', toolbar_emptyGroup: 'Tom', + sourceCodeEdit: 'Rediger kildekode', + charmap: 'Tegntabel', + charmap_headline: 'Specialtegn', + charmap_currency: 'Valuta', + charmap_text: 'Tekst', + charmap_quotations: 'Anførselstegn', + charmap_maths: 'Matematiske', + charmap_extlatin: 'Udvidet latinsk', + charmap_symbols: 'Symboler', + charmap_arrows: 'Pile', }, collection: { noItemsTitle: 'Intet indhold', addCollectionConfiguration: 'Tilføj samling', }, + linkPicker: { + modalSource: 'Kilde', + modalManual: 'Manuel', + modalAnchorValidationMessage: + 'Indtast et anker eller en querystring, vælg et dokument eller medieelement, eller konfigurer URL’en manuelt.', + resetUrlHeadline: 'Nulstil URL?', + resetUrlMessage: 'Er du sikker på, at du vil nulstille denne URL?', + resetUrlLabel: 'Nulstil', + }, } as UmbLocalizationDictionary; From 7458143bb846df3b709e96d8e258eb84f18aa428 Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Mon, 21 Jul 2025 09:27:54 +0200 Subject: [PATCH 12/23] Restored indentation following merge of Danish translations in #19740. --- src/Umbraco.Web.UI.Client/src/assets/lang/da.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/assets/lang/da.ts b/src/Umbraco.Web.UI.Client/src/assets/lang/da.ts index f1648d91b1..ed0569656a 100644 --- a/src/Umbraco.Web.UI.Client/src/assets/lang/da.ts +++ b/src/Umbraco.Web.UI.Client/src/assets/lang/da.ts @@ -367,7 +367,7 @@ export default { }, entityDetail: { notFoundTitle: (entityType: string) => { - const entityName = entityType ?? 'Elementet'; + const entityName = entityType ?? 'Elementet'; return `${entityName} blev ikke fundet`; }, notFoundDescription: (entityType: string) => { @@ -2786,7 +2786,7 @@ export default { config_mediaParentId_description: 'Vælg uploadplacering for indsatte billeder.', config_overlaySize: 'Overlay-størrelse', config_overlaySize_description: 'Vælg bredden på overlayet (linkvælger).', - }, + }, tiptap: { anchor: 'Anker', anchor_input: 'Indtast anker-ID', From 6fe39b071fcd8a0f671309c3f96773b44a3c5557 Mon Sep 17 00:00:00 2001 From: Kevin Jump Date: Mon, 21 Jul 2025 08:52:58 +0100 Subject: [PATCH 13/23] Add a backing field for EditorUIAlias and track changes when its set. (#19733) * Add a backing field for EditorUIAlias and track changes when its set. * Add previously failing unit test to verify fix. * Aligned backing field casing with property name. --------- Co-authored-by: Andy Butland --- src/Umbraco.Core/Models/DataType.cs | 7 +++- .../Umbraco.Core/Models/DataTypeTests.cs | 35 +++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 tests/Umbraco.Tests.UnitTests/Umbraco.Core/Models/DataTypeTests.cs diff --git a/src/Umbraco.Core/Models/DataType.cs b/src/Umbraco.Core/Models/DataType.cs index e9d9258643..cac12d1bb2 100644 --- a/src/Umbraco.Core/Models/DataType.cs +++ b/src/Umbraco.Core/Models/DataType.cs @@ -17,6 +17,7 @@ public class DataType : TreeEntityBase, IDataType private IDictionary _configurationData; private ValueStorageType _databaseType; private IDataEditor? _editor; + private string? _editorUiAlias; private bool _hasConfigurationObject; /// @@ -60,7 +61,11 @@ public class DataType : TreeEntityBase, IDataType /// [DataMember] - public string? EditorUiAlias { get; set; } + public string? EditorUiAlias + { + get => _editorUiAlias; + set => SetPropertyValueAndDetectChanges(value, ref _editorUiAlias, nameof(EditorUiAlias)); + } /// [DataMember] diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Models/DataTypeTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Models/DataTypeTests.cs new file mode 100644 index 0000000000..bc27f3ea84 --- /dev/null +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Models/DataTypeTests.cs @@ -0,0 +1,35 @@ +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using NUnit.Framework; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Tests.Common.Builders; +using Umbraco.Cms.Tests.Common.Builders.Extensions; + +namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Models; + +[TestFixture] +public class DataTypeTests +{ + [Test] + public void Can_Update_And_Verify_Dirty_Properties() + { + var dataType = new DataTypeBuilder() + .WithName("Test Data Type") + .WithDatabaseType(ValueStorageType.Ntext) + .Build(); + + dataType.ResetDirtyProperties(); + + dataType.DatabaseType = ValueStorageType.Nvarchar; + dataType.EditorUiAlias = "Test.EditorUiAlias"; + + var dirtyProperties = dataType.GetDirtyProperties().OrderBy(x => x).ToList(); + + Assert.IsTrue(dataType.IsPropertyDirty(nameof(dataType.DatabaseType))); + Assert.IsTrue(dataType.IsPropertyDirty(nameof(dataType.EditorUiAlias))); + + Assert.AreEqual(2, dirtyProperties.Count); + Assert.AreEqual($"{nameof(dataType.DatabaseType)},{nameof(dataType.EditorUiAlias)}", string.Join(",", dirtyProperties)); + } +} From 5c05fd2877c641ab5931109ac699d1c4cdec05d5 Mon Sep 17 00:00:00 2001 From: NguyenThuyLan <116753400+NguyenThuyLan@users.noreply.github.com> Date: Mon, 21 Jul 2025 15:17:02 +0700 Subject: [PATCH 14/23] Template with Block List field with Inline Editing Mode causes Collection List View to shrink (#19754) Fix issue template is shrunk when enable inline editing mode in collection list view in block list field Co-authored-by: Lan Nguyen Thuy --- .../block/block/workspace/block-workspace.context.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace.context.ts index cce733ccf9..6ac00c185f 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/block/block/workspace/block-workspace.context.ts @@ -210,7 +210,12 @@ export class UmbBlockWorkspaceContext { - if (blockType?.editorSize) { + if (!blockType?.editorSize) return; + + const editorConfig = manager.getEditorConfiguration(); + const useInlineEditing = editorConfig?.find((x) => x.alias === 'useInlineEditingAsDefault')?.value; + + if (!useInlineEditing) { this.setEditorSize(blockType.editorSize); } }, From 1ec9641c9d6fc7187f5d1bdb6152ad7a169bf5fb Mon Sep 17 00:00:00 2001 From: Lee Kelleher Date: Mon, 21 Jul 2025 09:40:29 +0100 Subject: [PATCH 15/23] Updated OpenApi and TypeScript API (Siblings endpoints) (#19759) Latest OpenApi TypeScript API code generation --- src/Umbraco.Cms.Api.Management/OpenApi.json | 457 +++++++++++++++++- .../src/packages/core/backend-api/sdk.gen.ts | 93 +++- .../packages/core/backend-api/types.gen.ts | 229 ++++++++- 3 files changed, 771 insertions(+), 8 deletions(-) diff --git a/src/Umbraco.Cms.Api.Management/OpenApi.json b/src/Umbraco.Cms.Api.Management/OpenApi.json index 2370516f51..16d11c7392 100644 --- a/src/Umbraco.Cms.Api.Management/OpenApi.json +++ b/src/Umbraco.Cms.Api.Management/OpenApi.json @@ -1801,6 +1801,70 @@ ] } }, + "/umbraco/management/api/v1/tree/data-type/siblings": { + "get": { + "tags": [ + "Data Type" + ], + "operationId": "GetTreeDataTypeSiblings", + "parameters": [ + { + "name": "target", + "in": "query", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "before", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "after", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/DataTypeTreeItemResponseModel" + } + ] + } + } + } + } + }, + "401": { + "description": "The resource is protected and requires an authentication token" + }, + "403": { + "description": "The authenticated user does not have access to this resource" + } + }, + "security": [ + { + "Backoffice User": [ ] + } + ] + } + }, "/umbraco/management/api/v1/dictionary": { "get": { "tags": [ @@ -4351,6 +4415,70 @@ ] } }, + "/umbraco/management/api/v1/tree/document-blueprint/siblings": { + "get": { + "tags": [ + "Document Blueprint" + ], + "operationId": "GetTreeDocumentBlueprintSiblings", + "parameters": [ + { + "name": "target", + "in": "query", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "before", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "after", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/DocumentBlueprintTreeItemResponseModel" + } + ] + } + } + } + } + }, + "401": { + "description": "The resource is protected and requires an authentication token" + }, + "403": { + "description": "The authenticated user does not have access to this resource" + } + }, + "security": [ + { + "Backoffice User": [ ] + } + ] + } + }, "/umbraco/management/api/v1/document-type": { "post": { "tags": [ @@ -6604,6 +6732,70 @@ ] } }, + "/umbraco/management/api/v1/tree/document-type/siblings": { + "get": { + "tags": [ + "Document Type" + ], + "operationId": "GetTreeDocumentTypeSiblings", + "parameters": [ + { + "name": "target", + "in": "query", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "before", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "after", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/DocumentTypeTreeItemResponseModel" + } + ] + } + } + } + } + }, + "401": { + "description": "The resource is protected and requires an authentication token" + }, + "403": { + "description": "The authenticated user does not have access to this resource" + } + }, + "security": [ + { + "Backoffice User": [ ] + } + ] + } + }, "/umbraco/management/api/v1/document-version": { "get": { "tags": [ @@ -10986,6 +11178,70 @@ ] } }, + "/umbraco/management/api/v1/tree/document/siblings": { + "get": { + "tags": [ + "Document" + ], + "operationId": "GetTreeDocumentSiblings", + "parameters": [ + { + "name": "target", + "in": "query", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "before", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "after", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/DocumentTreeItemResponseModel" + } + ] + } + } + } + } + }, + "401": { + "description": "The resource is protected and requires an authentication token" + }, + "403": { + "description": "The authenticated user does not have access to this resource" + } + }, + "security": [ + { + "Backoffice User": [ ] + } + ] + } + }, "/umbraco/management/api/v1/dynamic-root/query": { "post": { "tags": [ @@ -15734,6 +15990,70 @@ ] } }, + "/umbraco/management/api/v1/tree/media-type/siblings": { + "get": { + "tags": [ + "Media Type" + ], + "operationId": "GetTreeMediaTypeSiblings", + "parameters": [ + { + "name": "target", + "in": "query", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "before", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "after", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/MediaTypeTreeItemResponseModel" + } + ] + } + } + } + } + }, + "401": { + "description": "The resource is protected and requires an authentication token" + }, + "403": { + "description": "The authenticated user does not have access to this resource" + } + }, + "security": [ + { + "Backoffice User": [ ] + } + ] + } + }, "/umbraco/management/api/v1/collection/media": { "get": { "tags": [ @@ -18200,6 +18520,70 @@ ] } }, + "/umbraco/management/api/v1/tree/media/siblings": { + "get": { + "tags": [ + "Media" + ], + "operationId": "GetTreeMediaSiblings", + "parameters": [ + { + "name": "target", + "in": "query", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "before", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "after", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/MediaTreeItemResponseModel" + } + ] + } + } + } + } + }, + "401": { + "description": "The resource is protected and requires an authentication token" + }, + "403": { + "description": "The authenticated user does not have access to this resource" + } + }, + "security": [ + { + "Backoffice User": [ ] + } + ] + } + }, "/umbraco/management/api/v1/item/member-group": { "get": { "tags": [ @@ -25686,9 +26070,6 @@ }, "401": { "description": "The resource is protected and requires an authentication token" - }, - "403": { - "description": "The authenticated user does not have access to this resource" } }, "security": [ @@ -28350,6 +28731,70 @@ ] } }, + "/umbraco/management/api/v1/tree/template/siblings": { + "get": { + "tags": [ + "Template" + ], + "operationId": "GetTreeTemplateSiblings", + "parameters": [ + { + "name": "target", + "in": "query", + "schema": { + "type": "string", + "format": "uuid" + } + }, + { + "name": "before", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + }, + { + "name": "after", + "in": "query", + "schema": { + "type": "integer", + "format": "int32" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/NamedEntityTreeItemResponseModel" + } + ] + } + } + } + } + }, + "401": { + "description": "The resource is protected and requires an authentication token" + }, + "403": { + "description": "The authenticated user does not have access to this resource" + } + }, + "security": [ + { + "Backoffice User": [ ] + } + ] + } + }, "/umbraco/management/api/v1/temporary-file": { "post": { "tags": [ @@ -34307,6 +34752,9 @@ }, "401": { "description": "The resource is protected and requires an authentication token" + }, + "403": { + "description": "The authenticated user does not have access to this resource" } }, "security": [ @@ -34414,6 +34862,9 @@ }, "401": { "description": "The resource is protected and requires an authentication token" + }, + "403": { + "description": "The authenticated user does not have access to this resource" } }, "security": [ diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/backend-api/sdk.gen.ts b/src/Umbraco.Web.UI.Client/src/packages/core/backend-api/sdk.gen.ts index a954f24ad2..62ef1c6b23 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/backend-api/sdk.gen.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/backend-api/sdk.gen.ts @@ -1,7 +1,7 @@ // This file is auto-generated by @hey-api/openapi-ts import { type Options as ClientOptions, type TDataShape, type Client, formDataBodySerializer } from '@hey-api/client-fetch'; -import type { GetCultureData, GetCultureResponses, GetCultureErrors, PostDataTypeData, PostDataTypeResponses, PostDataTypeErrors, DeleteDataTypeByIdData, DeleteDataTypeByIdResponses, DeleteDataTypeByIdErrors, GetDataTypeByIdData, GetDataTypeByIdResponses, GetDataTypeByIdErrors, PutDataTypeByIdData, PutDataTypeByIdResponses, PutDataTypeByIdErrors, PostDataTypeByIdCopyData, PostDataTypeByIdCopyResponses, PostDataTypeByIdCopyErrors, GetDataTypeByIdIsUsedData, GetDataTypeByIdIsUsedResponses, GetDataTypeByIdIsUsedErrors, PutDataTypeByIdMoveData, PutDataTypeByIdMoveResponses, PutDataTypeByIdMoveErrors, GetDataTypeByIdReferencedByData, GetDataTypeByIdReferencedByResponses, GetDataTypeByIdReferencedByErrors, GetDataTypeByIdReferencesData, GetDataTypeByIdReferencesResponses, GetDataTypeByIdReferencesErrors, GetDataTypeConfigurationData, GetDataTypeConfigurationResponses, GetDataTypeConfigurationErrors, PostDataTypeFolderData, PostDataTypeFolderResponses, PostDataTypeFolderErrors, DeleteDataTypeFolderByIdData, DeleteDataTypeFolderByIdResponses, DeleteDataTypeFolderByIdErrors, GetDataTypeFolderByIdData, GetDataTypeFolderByIdResponses, GetDataTypeFolderByIdErrors, PutDataTypeFolderByIdData, PutDataTypeFolderByIdResponses, PutDataTypeFolderByIdErrors, GetFilterDataTypeData, GetFilterDataTypeResponses, GetFilterDataTypeErrors, GetItemDataTypeData, GetItemDataTypeResponses, GetItemDataTypeErrors, GetItemDataTypeSearchData, GetItemDataTypeSearchResponses, GetItemDataTypeSearchErrors, GetTreeDataTypeAncestorsData, GetTreeDataTypeAncestorsResponses, GetTreeDataTypeAncestorsErrors, GetTreeDataTypeChildrenData, GetTreeDataTypeChildrenResponses, GetTreeDataTypeChildrenErrors, GetTreeDataTypeRootData, GetTreeDataTypeRootResponses, GetTreeDataTypeRootErrors, GetDictionaryData, GetDictionaryResponses, GetDictionaryErrors, PostDictionaryData, PostDictionaryResponses, PostDictionaryErrors, DeleteDictionaryByIdData, DeleteDictionaryByIdResponses, DeleteDictionaryByIdErrors, GetDictionaryByIdData, GetDictionaryByIdResponses, GetDictionaryByIdErrors, PutDictionaryByIdData, PutDictionaryByIdResponses, PutDictionaryByIdErrors, GetDictionaryByIdExportData, GetDictionaryByIdExportResponses, GetDictionaryByIdExportErrors, PutDictionaryByIdMoveData, PutDictionaryByIdMoveResponses, PutDictionaryByIdMoveErrors, PostDictionaryImportData, PostDictionaryImportResponses, PostDictionaryImportErrors, GetItemDictionaryData, GetItemDictionaryResponses, GetItemDictionaryErrors, GetTreeDictionaryAncestorsData, GetTreeDictionaryAncestorsResponses, GetTreeDictionaryAncestorsErrors, GetTreeDictionaryChildrenData, GetTreeDictionaryChildrenResponses, GetTreeDictionaryChildrenErrors, GetTreeDictionaryRootData, GetTreeDictionaryRootResponses, GetTreeDictionaryRootErrors, PostDocumentBlueprintData, PostDocumentBlueprintResponses, PostDocumentBlueprintErrors, DeleteDocumentBlueprintByIdData, DeleteDocumentBlueprintByIdResponses, DeleteDocumentBlueprintByIdErrors, GetDocumentBlueprintByIdData, GetDocumentBlueprintByIdResponses, GetDocumentBlueprintByIdErrors, PutDocumentBlueprintByIdData, PutDocumentBlueprintByIdResponses, PutDocumentBlueprintByIdErrors, PutDocumentBlueprintByIdMoveData, PutDocumentBlueprintByIdMoveResponses, PutDocumentBlueprintByIdMoveErrors, GetDocumentBlueprintByIdScaffoldData, GetDocumentBlueprintByIdScaffoldResponses, GetDocumentBlueprintByIdScaffoldErrors, PostDocumentBlueprintFolderData, PostDocumentBlueprintFolderResponses, PostDocumentBlueprintFolderErrors, DeleteDocumentBlueprintFolderByIdData, DeleteDocumentBlueprintFolderByIdResponses, DeleteDocumentBlueprintFolderByIdErrors, GetDocumentBlueprintFolderByIdData, GetDocumentBlueprintFolderByIdResponses, GetDocumentBlueprintFolderByIdErrors, PutDocumentBlueprintFolderByIdData, PutDocumentBlueprintFolderByIdResponses, PutDocumentBlueprintFolderByIdErrors, PostDocumentBlueprintFromDocumentData, PostDocumentBlueprintFromDocumentResponses, PostDocumentBlueprintFromDocumentErrors, GetItemDocumentBlueprintData, GetItemDocumentBlueprintResponses, GetItemDocumentBlueprintErrors, GetTreeDocumentBlueprintAncestorsData, GetTreeDocumentBlueprintAncestorsResponses, GetTreeDocumentBlueprintAncestorsErrors, GetTreeDocumentBlueprintChildrenData, GetTreeDocumentBlueprintChildrenResponses, GetTreeDocumentBlueprintChildrenErrors, GetTreeDocumentBlueprintRootData, GetTreeDocumentBlueprintRootResponses, GetTreeDocumentBlueprintRootErrors, PostDocumentTypeData, PostDocumentTypeResponses, PostDocumentTypeErrors, DeleteDocumentTypeByIdData, DeleteDocumentTypeByIdResponses, DeleteDocumentTypeByIdErrors, GetDocumentTypeByIdData, GetDocumentTypeByIdResponses, GetDocumentTypeByIdErrors, PutDocumentTypeByIdData, PutDocumentTypeByIdResponses, PutDocumentTypeByIdErrors, GetDocumentTypeByIdAllowedChildrenData, GetDocumentTypeByIdAllowedChildrenResponses, GetDocumentTypeByIdAllowedChildrenErrors, GetDocumentTypeByIdBlueprintData, GetDocumentTypeByIdBlueprintResponses, GetDocumentTypeByIdBlueprintErrors, GetDocumentTypeByIdCompositionReferencesData, GetDocumentTypeByIdCompositionReferencesResponses, GetDocumentTypeByIdCompositionReferencesErrors, PostDocumentTypeByIdCopyData, PostDocumentTypeByIdCopyResponses, PostDocumentTypeByIdCopyErrors, GetDocumentTypeByIdExportData, GetDocumentTypeByIdExportResponses, GetDocumentTypeByIdExportErrors, PutDocumentTypeByIdImportData, PutDocumentTypeByIdImportResponses, PutDocumentTypeByIdImportErrors, PutDocumentTypeByIdMoveData, PutDocumentTypeByIdMoveResponses, PutDocumentTypeByIdMoveErrors, GetDocumentTypeAllowedAtRootData, GetDocumentTypeAllowedAtRootResponses, GetDocumentTypeAllowedAtRootErrors, PostDocumentTypeAvailableCompositionsData, PostDocumentTypeAvailableCompositionsResponses, PostDocumentTypeAvailableCompositionsErrors, GetDocumentTypeConfigurationData, GetDocumentTypeConfigurationResponses, GetDocumentTypeConfigurationErrors, PostDocumentTypeFolderData, PostDocumentTypeFolderResponses, PostDocumentTypeFolderErrors, DeleteDocumentTypeFolderByIdData, DeleteDocumentTypeFolderByIdResponses, DeleteDocumentTypeFolderByIdErrors, GetDocumentTypeFolderByIdData, GetDocumentTypeFolderByIdResponses, GetDocumentTypeFolderByIdErrors, PutDocumentTypeFolderByIdData, PutDocumentTypeFolderByIdResponses, PutDocumentTypeFolderByIdErrors, PostDocumentTypeImportData, PostDocumentTypeImportResponses, PostDocumentTypeImportErrors, GetItemDocumentTypeData, GetItemDocumentTypeResponses, GetItemDocumentTypeErrors, GetItemDocumentTypeSearchData, GetItemDocumentTypeSearchResponses, GetItemDocumentTypeSearchErrors, GetTreeDocumentTypeAncestorsData, GetTreeDocumentTypeAncestorsResponses, GetTreeDocumentTypeAncestorsErrors, GetTreeDocumentTypeChildrenData, GetTreeDocumentTypeChildrenResponses, GetTreeDocumentTypeChildrenErrors, GetTreeDocumentTypeRootData, GetTreeDocumentTypeRootResponses, GetTreeDocumentTypeRootErrors, GetDocumentVersionData, GetDocumentVersionResponses, GetDocumentVersionErrors, GetDocumentVersionByIdData, GetDocumentVersionByIdResponses, GetDocumentVersionByIdErrors, PutDocumentVersionByIdPreventCleanupData, PutDocumentVersionByIdPreventCleanupResponses, PutDocumentVersionByIdPreventCleanupErrors, PostDocumentVersionByIdRollbackData, PostDocumentVersionByIdRollbackResponses, PostDocumentVersionByIdRollbackErrors, GetCollectionDocumentByIdData, GetCollectionDocumentByIdResponses, GetCollectionDocumentByIdErrors, PostDocumentData, PostDocumentResponses, PostDocumentErrors, DeleteDocumentByIdData, DeleteDocumentByIdResponses, DeleteDocumentByIdErrors, GetDocumentByIdData, GetDocumentByIdResponses, GetDocumentByIdErrors, PutDocumentByIdData, PutDocumentByIdResponses, PutDocumentByIdErrors, GetDocumentByIdAuditLogData, GetDocumentByIdAuditLogResponses, GetDocumentByIdAuditLogErrors, PostDocumentByIdCopyData, PostDocumentByIdCopyResponses, PostDocumentByIdCopyErrors, GetDocumentByIdDomainsData, GetDocumentByIdDomainsResponses, GetDocumentByIdDomainsErrors, PutDocumentByIdDomainsData, PutDocumentByIdDomainsResponses, PutDocumentByIdDomainsErrors, PutDocumentByIdMoveData, PutDocumentByIdMoveResponses, PutDocumentByIdMoveErrors, PutDocumentByIdMoveToRecycleBinData, PutDocumentByIdMoveToRecycleBinResponses, PutDocumentByIdMoveToRecycleBinErrors, GetDocumentByIdNotificationsData, GetDocumentByIdNotificationsResponses, GetDocumentByIdNotificationsErrors, PutDocumentByIdNotificationsData, PutDocumentByIdNotificationsResponses, PutDocumentByIdNotificationsErrors, DeleteDocumentByIdPublicAccessData, DeleteDocumentByIdPublicAccessResponses, DeleteDocumentByIdPublicAccessErrors, GetDocumentByIdPublicAccessData, GetDocumentByIdPublicAccessResponses, GetDocumentByIdPublicAccessErrors, PostDocumentByIdPublicAccessData, PostDocumentByIdPublicAccessResponses, PostDocumentByIdPublicAccessErrors, PutDocumentByIdPublicAccessData, PutDocumentByIdPublicAccessResponses, PutDocumentByIdPublicAccessErrors, PutDocumentByIdPublishData, PutDocumentByIdPublishResponses, PutDocumentByIdPublishErrors, PutDocumentByIdPublishWithDescendantsData, PutDocumentByIdPublishWithDescendantsResponses, PutDocumentByIdPublishWithDescendantsErrors, GetDocumentByIdPublishWithDescendantsResultByTaskIdData, GetDocumentByIdPublishWithDescendantsResultByTaskIdResponses, GetDocumentByIdPublishWithDescendantsResultByTaskIdErrors, GetDocumentByIdPublishedData, GetDocumentByIdPublishedResponses, GetDocumentByIdPublishedErrors, GetDocumentByIdReferencedByData, GetDocumentByIdReferencedByResponses, GetDocumentByIdReferencedByErrors, GetDocumentByIdReferencedDescendantsData, GetDocumentByIdReferencedDescendantsResponses, GetDocumentByIdReferencedDescendantsErrors, PutDocumentByIdUnpublishData, PutDocumentByIdUnpublishResponses, PutDocumentByIdUnpublishErrors, PutUmbracoManagementApiV11DocumentByIdValidate11Data, PutUmbracoManagementApiV11DocumentByIdValidate11Responses, PutUmbracoManagementApiV11DocumentByIdValidate11Errors, GetDocumentAreReferencedData, GetDocumentAreReferencedResponses, GetDocumentAreReferencedErrors, GetDocumentConfigurationData, GetDocumentConfigurationResponses, GetDocumentConfigurationErrors, PutDocumentSortData, PutDocumentSortResponses, PutDocumentSortErrors, GetDocumentUrlsData, GetDocumentUrlsResponses, GetDocumentUrlsErrors, PostDocumentValidateData, PostDocumentValidateResponses, PostDocumentValidateErrors, GetItemDocumentData, GetItemDocumentResponses, GetItemDocumentErrors, GetItemDocumentSearchData, GetItemDocumentSearchResponses, GetItemDocumentSearchErrors, DeleteRecycleBinDocumentData, DeleteRecycleBinDocumentResponses, DeleteRecycleBinDocumentErrors, DeleteRecycleBinDocumentByIdData, DeleteRecycleBinDocumentByIdResponses, DeleteRecycleBinDocumentByIdErrors, GetRecycleBinDocumentByIdOriginalParentData, GetRecycleBinDocumentByIdOriginalParentResponses, GetRecycleBinDocumentByIdOriginalParentErrors, PutRecycleBinDocumentByIdRestoreData, PutRecycleBinDocumentByIdRestoreResponses, PutRecycleBinDocumentByIdRestoreErrors, GetRecycleBinDocumentChildrenData, GetRecycleBinDocumentChildrenResponses, GetRecycleBinDocumentChildrenErrors, GetRecycleBinDocumentReferencedByData, GetRecycleBinDocumentReferencedByResponses, GetRecycleBinDocumentReferencedByErrors, GetRecycleBinDocumentRootData, GetRecycleBinDocumentRootResponses, GetRecycleBinDocumentRootErrors, GetTreeDocumentAncestorsData, GetTreeDocumentAncestorsResponses, GetTreeDocumentAncestorsErrors, GetTreeDocumentChildrenData, GetTreeDocumentChildrenResponses, GetTreeDocumentChildrenErrors, GetTreeDocumentRootData, GetTreeDocumentRootResponses, GetTreeDocumentRootErrors, PostDynamicRootQueryData, PostDynamicRootQueryResponses, PostDynamicRootQueryErrors, GetDynamicRootStepsData, GetDynamicRootStepsResponses, GetDynamicRootStepsErrors, GetHealthCheckGroupData, GetHealthCheckGroupResponses, GetHealthCheckGroupErrors, GetHealthCheckGroupByNameData, GetHealthCheckGroupByNameResponses, GetHealthCheckGroupByNameErrors, PostHealthCheckGroupByNameCheckData, PostHealthCheckGroupByNameCheckResponses, PostHealthCheckGroupByNameCheckErrors, PostHealthCheckExecuteActionData, PostHealthCheckExecuteActionResponses, PostHealthCheckExecuteActionErrors, GetHelpData, GetHelpResponses, GetHelpErrors, GetImagingResizeUrlsData, GetImagingResizeUrlsResponses, GetImagingResizeUrlsErrors, GetImportAnalyzeData, GetImportAnalyzeResponses, GetImportAnalyzeErrors, GetIndexerData, GetIndexerResponses, GetIndexerErrors, GetIndexerByIndexNameData, GetIndexerByIndexNameResponses, GetIndexerByIndexNameErrors, PostIndexerByIndexNameRebuildData, PostIndexerByIndexNameRebuildResponses, PostIndexerByIndexNameRebuildErrors, GetInstallSettingsData, GetInstallSettingsResponses, GetInstallSettingsErrors, PostInstallSetupData, PostInstallSetupResponses, PostInstallSetupErrors, PostInstallValidateDatabaseData, PostInstallValidateDatabaseResponses, PostInstallValidateDatabaseErrors, GetItemLanguageData, GetItemLanguageResponses, GetItemLanguageErrors, GetItemLanguageDefaultData, GetItemLanguageDefaultResponses, GetItemLanguageDefaultErrors, GetLanguageData, GetLanguageResponses, GetLanguageErrors, PostLanguageData, PostLanguageResponses, PostLanguageErrors, DeleteLanguageByIsoCodeData, DeleteLanguageByIsoCodeResponses, DeleteLanguageByIsoCodeErrors, GetLanguageByIsoCodeData, GetLanguageByIsoCodeResponses, GetLanguageByIsoCodeErrors, PutLanguageByIsoCodeData, PutLanguageByIsoCodeResponses, PutLanguageByIsoCodeErrors, GetLogViewerLevelData, GetLogViewerLevelResponses, GetLogViewerLevelErrors, GetLogViewerLevelCountData, GetLogViewerLevelCountResponses, GetLogViewerLevelCountErrors, GetLogViewerLogData, GetLogViewerLogResponses, GetLogViewerLogErrors, GetLogViewerMessageTemplateData, GetLogViewerMessageTemplateResponses, GetLogViewerMessageTemplateErrors, GetLogViewerSavedSearchData, GetLogViewerSavedSearchResponses, GetLogViewerSavedSearchErrors, PostLogViewerSavedSearchData, PostLogViewerSavedSearchResponses, PostLogViewerSavedSearchErrors, DeleteLogViewerSavedSearchByNameData, DeleteLogViewerSavedSearchByNameResponses, DeleteLogViewerSavedSearchByNameErrors, GetLogViewerSavedSearchByNameData, GetLogViewerSavedSearchByNameResponses, GetLogViewerSavedSearchByNameErrors, GetLogViewerValidateLogsSizeData, GetLogViewerValidateLogsSizeResponses, GetLogViewerValidateLogsSizeErrors, GetManifestManifestData, GetManifestManifestResponses, GetManifestManifestErrors, GetManifestManifestPrivateData, GetManifestManifestPrivateResponses, GetManifestManifestPrivateErrors, GetManifestManifestPublicData, GetManifestManifestPublicResponses, GetItemMediaTypeData, GetItemMediaTypeResponses, GetItemMediaTypeErrors, GetItemMediaTypeAllowedData, GetItemMediaTypeAllowedResponses, GetItemMediaTypeAllowedErrors, GetItemMediaTypeFoldersData, GetItemMediaTypeFoldersResponses, GetItemMediaTypeFoldersErrors, GetItemMediaTypeSearchData, GetItemMediaTypeSearchResponses, GetItemMediaTypeSearchErrors, PostMediaTypeData, PostMediaTypeResponses, PostMediaTypeErrors, DeleteMediaTypeByIdData, DeleteMediaTypeByIdResponses, DeleteMediaTypeByIdErrors, GetMediaTypeByIdData, GetMediaTypeByIdResponses, GetMediaTypeByIdErrors, PutMediaTypeByIdData, PutMediaTypeByIdResponses, PutMediaTypeByIdErrors, GetMediaTypeByIdAllowedChildrenData, GetMediaTypeByIdAllowedChildrenResponses, GetMediaTypeByIdAllowedChildrenErrors, GetMediaTypeByIdCompositionReferencesData, GetMediaTypeByIdCompositionReferencesResponses, GetMediaTypeByIdCompositionReferencesErrors, PostMediaTypeByIdCopyData, PostMediaTypeByIdCopyResponses, PostMediaTypeByIdCopyErrors, GetMediaTypeByIdExportData, GetMediaTypeByIdExportResponses, GetMediaTypeByIdExportErrors, PutMediaTypeByIdImportData, PutMediaTypeByIdImportResponses, PutMediaTypeByIdImportErrors, PutMediaTypeByIdMoveData, PutMediaTypeByIdMoveResponses, PutMediaTypeByIdMoveErrors, GetMediaTypeAllowedAtRootData, GetMediaTypeAllowedAtRootResponses, GetMediaTypeAllowedAtRootErrors, PostMediaTypeAvailableCompositionsData, PostMediaTypeAvailableCompositionsResponses, PostMediaTypeAvailableCompositionsErrors, GetMediaTypeConfigurationData, GetMediaTypeConfigurationResponses, GetMediaTypeConfigurationErrors, PostMediaTypeFolderData, PostMediaTypeFolderResponses, PostMediaTypeFolderErrors, DeleteMediaTypeFolderByIdData, DeleteMediaTypeFolderByIdResponses, DeleteMediaTypeFolderByIdErrors, GetMediaTypeFolderByIdData, GetMediaTypeFolderByIdResponses, GetMediaTypeFolderByIdErrors, PutMediaTypeFolderByIdData, PutMediaTypeFolderByIdResponses, PutMediaTypeFolderByIdErrors, PostMediaTypeImportData, PostMediaTypeImportResponses, PostMediaTypeImportErrors, GetTreeMediaTypeAncestorsData, GetTreeMediaTypeAncestorsResponses, GetTreeMediaTypeAncestorsErrors, GetTreeMediaTypeChildrenData, GetTreeMediaTypeChildrenResponses, GetTreeMediaTypeChildrenErrors, GetTreeMediaTypeRootData, GetTreeMediaTypeRootResponses, GetTreeMediaTypeRootErrors, GetCollectionMediaData, GetCollectionMediaResponses, GetCollectionMediaErrors, GetItemMediaData, GetItemMediaResponses, GetItemMediaErrors, GetItemMediaSearchData, GetItemMediaSearchResponses, GetItemMediaSearchErrors, PostMediaData, PostMediaResponses, PostMediaErrors, DeleteMediaByIdData, DeleteMediaByIdResponses, DeleteMediaByIdErrors, GetMediaByIdData, GetMediaByIdResponses, GetMediaByIdErrors, PutMediaByIdData, PutMediaByIdResponses, PutMediaByIdErrors, GetMediaByIdAuditLogData, GetMediaByIdAuditLogResponses, GetMediaByIdAuditLogErrors, PutMediaByIdMoveData, PutMediaByIdMoveResponses, PutMediaByIdMoveErrors, PutMediaByIdMoveToRecycleBinData, PutMediaByIdMoveToRecycleBinResponses, PutMediaByIdMoveToRecycleBinErrors, GetMediaByIdReferencedByData, GetMediaByIdReferencedByResponses, GetMediaByIdReferencedByErrors, GetMediaByIdReferencedDescendantsData, GetMediaByIdReferencedDescendantsResponses, GetMediaByIdReferencedDescendantsErrors, PutMediaByIdValidateData, PutMediaByIdValidateResponses, PutMediaByIdValidateErrors, GetMediaAreReferencedData, GetMediaAreReferencedResponses, GetMediaAreReferencedErrors, GetMediaConfigurationData, GetMediaConfigurationResponses, GetMediaConfigurationErrors, PutMediaSortData, PutMediaSortResponses, PutMediaSortErrors, GetMediaUrlsData, GetMediaUrlsResponses, GetMediaUrlsErrors, PostMediaValidateData, PostMediaValidateResponses, PostMediaValidateErrors, DeleteRecycleBinMediaData, DeleteRecycleBinMediaResponses, DeleteRecycleBinMediaErrors, DeleteRecycleBinMediaByIdData, DeleteRecycleBinMediaByIdResponses, DeleteRecycleBinMediaByIdErrors, GetRecycleBinMediaByIdOriginalParentData, GetRecycleBinMediaByIdOriginalParentResponses, GetRecycleBinMediaByIdOriginalParentErrors, PutRecycleBinMediaByIdRestoreData, PutRecycleBinMediaByIdRestoreResponses, PutRecycleBinMediaByIdRestoreErrors, GetRecycleBinMediaChildrenData, GetRecycleBinMediaChildrenResponses, GetRecycleBinMediaChildrenErrors, GetRecycleBinMediaReferencedByData, GetRecycleBinMediaReferencedByResponses, GetRecycleBinMediaReferencedByErrors, GetRecycleBinMediaRootData, GetRecycleBinMediaRootResponses, GetRecycleBinMediaRootErrors, GetTreeMediaAncestorsData, GetTreeMediaAncestorsResponses, GetTreeMediaAncestorsErrors, GetTreeMediaChildrenData, GetTreeMediaChildrenResponses, GetTreeMediaChildrenErrors, GetTreeMediaRootData, GetTreeMediaRootResponses, GetTreeMediaRootErrors, GetItemMemberGroupData, GetItemMemberGroupResponses, GetItemMemberGroupErrors, GetMemberGroupData, GetMemberGroupResponses, GetMemberGroupErrors, PostMemberGroupData, PostMemberGroupResponses, PostMemberGroupErrors, DeleteMemberGroupByIdData, DeleteMemberGroupByIdResponses, DeleteMemberGroupByIdErrors, GetMemberGroupByIdData, GetMemberGroupByIdResponses, GetMemberGroupByIdErrors, PutMemberGroupByIdData, PutMemberGroupByIdResponses, PutMemberGroupByIdErrors, GetTreeMemberGroupRootData, GetTreeMemberGroupRootResponses, GetTreeMemberGroupRootErrors, GetItemMemberTypeData, GetItemMemberTypeResponses, GetItemMemberTypeErrors, GetItemMemberTypeSearchData, GetItemMemberTypeSearchResponses, GetItemMemberTypeSearchErrors, PostMemberTypeData, PostMemberTypeResponses, PostMemberTypeErrors, DeleteMemberTypeByIdData, DeleteMemberTypeByIdResponses, DeleteMemberTypeByIdErrors, GetMemberTypeByIdData, GetMemberTypeByIdResponses, GetMemberTypeByIdErrors, PutMemberTypeByIdData, PutMemberTypeByIdResponses, PutMemberTypeByIdErrors, GetMemberTypeByIdCompositionReferencesData, GetMemberTypeByIdCompositionReferencesResponses, GetMemberTypeByIdCompositionReferencesErrors, PostMemberTypeByIdCopyData, PostMemberTypeByIdCopyResponses, PostMemberTypeByIdCopyErrors, PostMemberTypeAvailableCompositionsData, PostMemberTypeAvailableCompositionsResponses, PostMemberTypeAvailableCompositionsErrors, GetMemberTypeConfigurationData, GetMemberTypeConfigurationResponses, GetMemberTypeConfigurationErrors, GetTreeMemberTypeRootData, GetTreeMemberTypeRootResponses, GetTreeMemberTypeRootErrors, GetFilterMemberData, GetFilterMemberResponses, GetFilterMemberErrors, GetItemMemberData, GetItemMemberResponses, GetItemMemberErrors, GetItemMemberSearchData, GetItemMemberSearchResponses, GetItemMemberSearchErrors, PostMemberData, PostMemberResponses, PostMemberErrors, DeleteMemberByIdData, DeleteMemberByIdResponses, DeleteMemberByIdErrors, GetMemberByIdData, GetMemberByIdResponses, GetMemberByIdErrors, PutMemberByIdData, PutMemberByIdResponses, PutMemberByIdErrors, GetMemberByIdReferencedByData, GetMemberByIdReferencedByResponses, GetMemberByIdReferencedByErrors, GetMemberByIdReferencedDescendantsData, GetMemberByIdReferencedDescendantsResponses, GetMemberByIdReferencedDescendantsErrors, PutMemberByIdValidateData, PutMemberByIdValidateResponses, PutMemberByIdValidateErrors, GetMemberAreReferencedData, GetMemberAreReferencedResponses, GetMemberAreReferencedErrors, GetMemberConfigurationData, GetMemberConfigurationResponses, GetMemberConfigurationErrors, PostMemberValidateData, PostMemberValidateResponses, PostMemberValidateErrors, PostModelsBuilderBuildData, PostModelsBuilderBuildResponses, PostModelsBuilderBuildErrors, GetModelsBuilderDashboardData, GetModelsBuilderDashboardResponses, GetModelsBuilderDashboardErrors, GetModelsBuilderStatusData, GetModelsBuilderStatusResponses, GetModelsBuilderStatusErrors, GetObjectTypesData, GetObjectTypesResponses, GetObjectTypesErrors, GetOembedQueryData, GetOembedQueryResponses, GetOembedQueryErrors, PostPackageByNameRunMigrationData, PostPackageByNameRunMigrationResponses, PostPackageByNameRunMigrationErrors, GetPackageConfigurationData, GetPackageConfigurationResponses, GetPackageConfigurationErrors, GetPackageCreatedData, GetPackageCreatedResponses, GetPackageCreatedErrors, PostPackageCreatedData, PostPackageCreatedResponses, PostPackageCreatedErrors, DeletePackageCreatedByIdData, DeletePackageCreatedByIdResponses, DeletePackageCreatedByIdErrors, GetPackageCreatedByIdData, GetPackageCreatedByIdResponses, GetPackageCreatedByIdErrors, PutPackageCreatedByIdData, PutPackageCreatedByIdResponses, PutPackageCreatedByIdErrors, GetPackageCreatedByIdDownloadData, GetPackageCreatedByIdDownloadResponses, GetPackageCreatedByIdDownloadErrors, GetPackageMigrationStatusData, GetPackageMigrationStatusResponses, GetPackageMigrationStatusErrors, GetItemPartialViewData, GetItemPartialViewResponses, GetItemPartialViewErrors, PostPartialViewData, PostPartialViewResponses, PostPartialViewErrors, DeletePartialViewByPathData, DeletePartialViewByPathResponses, DeletePartialViewByPathErrors, GetPartialViewByPathData, GetPartialViewByPathResponses, GetPartialViewByPathErrors, PutPartialViewByPathData, PutPartialViewByPathResponses, PutPartialViewByPathErrors, PutPartialViewByPathRenameData, PutPartialViewByPathRenameResponses, PutPartialViewByPathRenameErrors, PostPartialViewFolderData, PostPartialViewFolderResponses, PostPartialViewFolderErrors, DeletePartialViewFolderByPathData, DeletePartialViewFolderByPathResponses, DeletePartialViewFolderByPathErrors, GetPartialViewFolderByPathData, GetPartialViewFolderByPathResponses, GetPartialViewFolderByPathErrors, GetPartialViewSnippetData, GetPartialViewSnippetResponses, GetPartialViewSnippetErrors, GetPartialViewSnippetByIdData, GetPartialViewSnippetByIdResponses, GetPartialViewSnippetByIdErrors, GetTreePartialViewAncestorsData, GetTreePartialViewAncestorsResponses, GetTreePartialViewAncestorsErrors, GetTreePartialViewChildrenData, GetTreePartialViewChildrenResponses, GetTreePartialViewChildrenErrors, GetTreePartialViewRootData, GetTreePartialViewRootResponses, GetTreePartialViewRootErrors, DeletePreviewData, DeletePreviewResponses, PostPreviewData, PostPreviewResponses, PostPreviewErrors, GetProfilingStatusData, GetProfilingStatusResponses, GetProfilingStatusErrors, PutProfilingStatusData, PutProfilingStatusResponses, PutProfilingStatusErrors, GetPropertyTypeIsUsedData, GetPropertyTypeIsUsedResponses, GetPropertyTypeIsUsedErrors, PostPublishedCacheRebuildData, PostPublishedCacheRebuildResponses, PostPublishedCacheRebuildErrors, GetPublishedCacheRebuildStatusData, GetPublishedCacheRebuildStatusResponses, GetPublishedCacheRebuildStatusErrors, PostPublishedCacheReloadData, PostPublishedCacheReloadResponses, PostPublishedCacheReloadErrors, GetRedirectManagementData, GetRedirectManagementResponses, GetRedirectManagementErrors, DeleteRedirectManagementByIdData, DeleteRedirectManagementByIdResponses, DeleteRedirectManagementByIdErrors, GetRedirectManagementByIdData, GetRedirectManagementByIdResponses, GetRedirectManagementByIdErrors, GetRedirectManagementStatusData, GetRedirectManagementStatusResponses, GetRedirectManagementStatusErrors, PostRedirectManagementStatusData, PostRedirectManagementStatusResponses, PostRedirectManagementStatusErrors, GetItemRelationTypeData, GetItemRelationTypeResponses, GetItemRelationTypeErrors, GetRelationTypeData, GetRelationTypeResponses, GetRelationTypeErrors, GetRelationTypeByIdData, GetRelationTypeByIdResponses, GetRelationTypeByIdErrors, GetRelationByRelationTypeIdData, GetRelationByRelationTypeIdResponses, GetRelationByRelationTypeIdErrors, GetItemScriptData, GetItemScriptResponses, GetItemScriptErrors, PostScriptData, PostScriptResponses, PostScriptErrors, DeleteScriptByPathData, DeleteScriptByPathResponses, DeleteScriptByPathErrors, GetScriptByPathData, GetScriptByPathResponses, GetScriptByPathErrors, PutScriptByPathData, PutScriptByPathResponses, PutScriptByPathErrors, PutScriptByPathRenameData, PutScriptByPathRenameResponses, PutScriptByPathRenameErrors, PostScriptFolderData, PostScriptFolderResponses, PostScriptFolderErrors, DeleteScriptFolderByPathData, DeleteScriptFolderByPathResponses, DeleteScriptFolderByPathErrors, GetScriptFolderByPathData, GetScriptFolderByPathResponses, GetScriptFolderByPathErrors, GetTreeScriptAncestorsData, GetTreeScriptAncestorsResponses, GetTreeScriptAncestorsErrors, GetTreeScriptChildrenData, GetTreeScriptChildrenResponses, GetTreeScriptChildrenErrors, GetTreeScriptRootData, GetTreeScriptRootResponses, GetTreeScriptRootErrors, GetSearcherData, GetSearcherResponses, GetSearcherErrors, GetSearcherBySearcherNameQueryData, GetSearcherBySearcherNameQueryResponses, GetSearcherBySearcherNameQueryErrors, GetSecurityConfigurationData, GetSecurityConfigurationResponses, GetSecurityConfigurationErrors, PostSecurityForgotPasswordData, PostSecurityForgotPasswordResponses, PostSecurityForgotPasswordErrors, PostSecurityForgotPasswordResetData, PostSecurityForgotPasswordResetResponses, PostSecurityForgotPasswordResetErrors, PostSecurityForgotPasswordVerifyData, PostSecurityForgotPasswordVerifyResponses, PostSecurityForgotPasswordVerifyErrors, GetSegmentData, GetSegmentResponses, GetSegmentErrors, GetServerConfigurationData, GetServerConfigurationResponses, GetServerInformationData, GetServerInformationResponses, GetServerInformationErrors, GetServerStatusData, GetServerStatusResponses, GetServerStatusErrors, GetServerTroubleshootingData, GetServerTroubleshootingResponses, GetServerTroubleshootingErrors, GetServerUpgradeCheckData, GetServerUpgradeCheckResponses, GetServerUpgradeCheckErrors, GetItemStaticFileData, GetItemStaticFileResponses, GetItemStaticFileErrors, GetTreeStaticFileAncestorsData, GetTreeStaticFileAncestorsResponses, GetTreeStaticFileAncestorsErrors, GetTreeStaticFileChildrenData, GetTreeStaticFileChildrenResponses, GetTreeStaticFileChildrenErrors, GetTreeStaticFileRootData, GetTreeStaticFileRootResponses, GetTreeStaticFileRootErrors, GetItemStylesheetData, GetItemStylesheetResponses, GetItemStylesheetErrors, PostStylesheetData, PostStylesheetResponses, PostStylesheetErrors, DeleteStylesheetByPathData, DeleteStylesheetByPathResponses, DeleteStylesheetByPathErrors, GetStylesheetByPathData, GetStylesheetByPathResponses, GetStylesheetByPathErrors, PutStylesheetByPathData, PutStylesheetByPathResponses, PutStylesheetByPathErrors, PutStylesheetByPathRenameData, PutStylesheetByPathRenameResponses, PutStylesheetByPathRenameErrors, PostStylesheetFolderData, PostStylesheetFolderResponses, PostStylesheetFolderErrors, DeleteStylesheetFolderByPathData, DeleteStylesheetFolderByPathResponses, DeleteStylesheetFolderByPathErrors, GetStylesheetFolderByPathData, GetStylesheetFolderByPathResponses, GetStylesheetFolderByPathErrors, GetTreeStylesheetAncestorsData, GetTreeStylesheetAncestorsResponses, GetTreeStylesheetAncestorsErrors, GetTreeStylesheetChildrenData, GetTreeStylesheetChildrenResponses, GetTreeStylesheetChildrenErrors, GetTreeStylesheetRootData, GetTreeStylesheetRootResponses, GetTreeStylesheetRootErrors, GetTagData, GetTagResponses, GetTagErrors, GetTelemetryData, GetTelemetryResponses, GetTelemetryErrors, GetTelemetryLevelData, GetTelemetryLevelResponses, GetTelemetryLevelErrors, PostTelemetryLevelData, PostTelemetryLevelResponses, PostTelemetryLevelErrors, GetItemTemplateData, GetItemTemplateResponses, GetItemTemplateErrors, GetItemTemplateSearchData, GetItemTemplateSearchResponses, GetItemTemplateSearchErrors, PostTemplateData, PostTemplateResponses, PostTemplateErrors, DeleteTemplateByIdData, DeleteTemplateByIdResponses, DeleteTemplateByIdErrors, GetTemplateByIdData, GetTemplateByIdResponses, GetTemplateByIdErrors, PutTemplateByIdData, PutTemplateByIdResponses, PutTemplateByIdErrors, GetTemplateConfigurationData, GetTemplateConfigurationResponses, GetTemplateConfigurationErrors, PostTemplateQueryExecuteData, PostTemplateQueryExecuteResponses, PostTemplateQueryExecuteErrors, GetTemplateQuerySettingsData, GetTemplateQuerySettingsResponses, GetTemplateQuerySettingsErrors, GetTreeTemplateAncestorsData, GetTreeTemplateAncestorsResponses, GetTreeTemplateAncestorsErrors, GetTreeTemplateChildrenData, GetTreeTemplateChildrenResponses, GetTreeTemplateChildrenErrors, GetTreeTemplateRootData, GetTreeTemplateRootResponses, GetTreeTemplateRootErrors, PostTemporaryFileData, PostTemporaryFileResponses, PostTemporaryFileErrors, DeleteTemporaryFileByIdData, DeleteTemporaryFileByIdResponses, DeleteTemporaryFileByIdErrors, GetTemporaryFileByIdData, GetTemporaryFileByIdResponses, GetTemporaryFileByIdErrors, GetTemporaryFileConfigurationData, GetTemporaryFileConfigurationResponses, GetTemporaryFileConfigurationErrors, PostUpgradeAuthorizeData, PostUpgradeAuthorizeResponses, PostUpgradeAuthorizeErrors, GetUpgradeSettingsData, GetUpgradeSettingsResponses, GetUpgradeSettingsErrors, GetUserDataData, GetUserDataResponses, GetUserDataErrors, PostUserDataData, PostUserDataResponses, PostUserDataErrors, PutUserDataData, PutUserDataResponses, PutUserDataErrors, GetUserDataByIdData, GetUserDataByIdResponses, GetUserDataByIdErrors, GetFilterUserGroupData, GetFilterUserGroupResponses, GetFilterUserGroupErrors, GetItemUserGroupData, GetItemUserGroupResponses, GetItemUserGroupErrors, DeleteUserGroupData, DeleteUserGroupResponses, DeleteUserGroupErrors, GetUserGroupData, GetUserGroupResponses, GetUserGroupErrors, PostUserGroupData, PostUserGroupResponses, PostUserGroupErrors, DeleteUserGroupByIdData, DeleteUserGroupByIdResponses, DeleteUserGroupByIdErrors, GetUserGroupByIdData, GetUserGroupByIdResponses, GetUserGroupByIdErrors, PutUserGroupByIdData, PutUserGroupByIdResponses, PutUserGroupByIdErrors, DeleteUserGroupByIdUsersData, DeleteUserGroupByIdUsersResponses, DeleteUserGroupByIdUsersErrors, PostUserGroupByIdUsersData, PostUserGroupByIdUsersResponses, PostUserGroupByIdUsersErrors, GetFilterUserData, GetFilterUserResponses, GetFilterUserErrors, GetItemUserData, GetItemUserResponses, GetItemUserErrors, DeleteUserData, DeleteUserResponses, DeleteUserErrors, GetUserData, GetUserResponses, GetUserErrors, PostUserData, PostUserResponses, PostUserErrors, DeleteUserByIdData, DeleteUserByIdResponses, DeleteUserByIdErrors, GetUserByIdData, GetUserByIdResponses, GetUserByIdErrors, PutUserByIdData, PutUserByIdResponses, PutUserByIdErrors, GetUserById2FaData, GetUserById2FaResponses, GetUserById2FaErrors, DeleteUserById2FaByProviderNameData, DeleteUserById2FaByProviderNameResponses, DeleteUserById2FaByProviderNameErrors, GetUserByIdCalculateStartNodesData, GetUserByIdCalculateStartNodesResponses, GetUserByIdCalculateStartNodesErrors, PostUserByIdChangePasswordData, PostUserByIdChangePasswordResponses, PostUserByIdChangePasswordErrors, GetUserByIdClientCredentialsData, GetUserByIdClientCredentialsResponses, GetUserByIdClientCredentialsErrors, PostUserByIdClientCredentialsData, PostUserByIdClientCredentialsResponses, PostUserByIdClientCredentialsErrors, DeleteUserByIdClientCredentialsByClientIdData, DeleteUserByIdClientCredentialsByClientIdResponses, DeleteUserByIdClientCredentialsByClientIdErrors, PostUserByIdResetPasswordData, PostUserByIdResetPasswordResponses, PostUserByIdResetPasswordErrors, DeleteUserAvatarByIdData, DeleteUserAvatarByIdResponses, DeleteUserAvatarByIdErrors, PostUserAvatarByIdData, PostUserAvatarByIdResponses, PostUserAvatarByIdErrors, GetUserConfigurationData, GetUserConfigurationResponses, GetUserConfigurationErrors, GetUserCurrentData, GetUserCurrentResponses, GetUserCurrentErrors, GetUserCurrent2FaData, GetUserCurrent2FaResponses, GetUserCurrent2FaErrors, DeleteUserCurrent2FaByProviderNameData, DeleteUserCurrent2FaByProviderNameResponses, DeleteUserCurrent2FaByProviderNameErrors, GetUserCurrent2FaByProviderNameData, GetUserCurrent2FaByProviderNameResponses, GetUserCurrent2FaByProviderNameErrors, PostUserCurrent2FaByProviderNameData, PostUserCurrent2FaByProviderNameResponses, PostUserCurrent2FaByProviderNameErrors, PostUserCurrentAvatarData, PostUserCurrentAvatarResponses, PostUserCurrentAvatarErrors, PostUserCurrentChangePasswordData, PostUserCurrentChangePasswordResponses, PostUserCurrentChangePasswordErrors, GetUserCurrentConfigurationData, GetUserCurrentConfigurationResponses, GetUserCurrentConfigurationErrors, GetUserCurrentLoginProvidersData, GetUserCurrentLoginProvidersResponses, GetUserCurrentLoginProvidersErrors, GetUserCurrentPermissionsData, GetUserCurrentPermissionsResponses, GetUserCurrentPermissionsErrors, GetUserCurrentPermissionsDocumentData, GetUserCurrentPermissionsDocumentResponses, GetUserCurrentPermissionsDocumentErrors, GetUserCurrentPermissionsMediaData, GetUserCurrentPermissionsMediaResponses, GetUserCurrentPermissionsMediaErrors, PostUserDisableData, PostUserDisableResponses, PostUserDisableErrors, PostUserEnableData, PostUserEnableResponses, PostUserEnableErrors, PostUserInviteData, PostUserInviteResponses, PostUserInviteErrors, PostUserInviteCreatePasswordData, PostUserInviteCreatePasswordResponses, PostUserInviteCreatePasswordErrors, PostUserInviteResendData, PostUserInviteResendResponses, PostUserInviteResendErrors, PostUserInviteVerifyData, PostUserInviteVerifyResponses, PostUserInviteVerifyErrors, PostUserSetUserGroupsData, PostUserSetUserGroupsResponses, PostUserSetUserGroupsErrors, PostUserUnlockData, PostUserUnlockResponses, PostUserUnlockErrors, GetItemWebhookData, GetItemWebhookResponses, GetItemWebhookErrors, GetWebhookData, GetWebhookResponses, GetWebhookErrors, PostWebhookData, PostWebhookResponses, PostWebhookErrors, DeleteWebhookByIdData, DeleteWebhookByIdResponses, DeleteWebhookByIdErrors, GetWebhookByIdData, GetWebhookByIdResponses, GetWebhookByIdErrors, PutWebhookByIdData, PutWebhookByIdResponses, PutWebhookByIdErrors, GetWebhookByIdLogsData, GetWebhookByIdLogsResponses, GetWebhookByIdLogsErrors, GetWebhookEventsData, GetWebhookEventsResponses, GetWebhookEventsErrors, GetWebhookLogsData, GetWebhookLogsResponses, GetWebhookLogsErrors } from './types.gen'; +import type { GetCultureData, GetCultureResponses, GetCultureErrors, PostDataTypeData, PostDataTypeResponses, PostDataTypeErrors, DeleteDataTypeByIdData, DeleteDataTypeByIdResponses, DeleteDataTypeByIdErrors, GetDataTypeByIdData, GetDataTypeByIdResponses, GetDataTypeByIdErrors, PutDataTypeByIdData, PutDataTypeByIdResponses, PutDataTypeByIdErrors, PostDataTypeByIdCopyData, PostDataTypeByIdCopyResponses, PostDataTypeByIdCopyErrors, GetDataTypeByIdIsUsedData, GetDataTypeByIdIsUsedResponses, GetDataTypeByIdIsUsedErrors, PutDataTypeByIdMoveData, PutDataTypeByIdMoveResponses, PutDataTypeByIdMoveErrors, GetDataTypeByIdReferencedByData, GetDataTypeByIdReferencedByResponses, GetDataTypeByIdReferencedByErrors, GetDataTypeByIdReferencesData, GetDataTypeByIdReferencesResponses, GetDataTypeByIdReferencesErrors, GetDataTypeConfigurationData, GetDataTypeConfigurationResponses, GetDataTypeConfigurationErrors, PostDataTypeFolderData, PostDataTypeFolderResponses, PostDataTypeFolderErrors, DeleteDataTypeFolderByIdData, DeleteDataTypeFolderByIdResponses, DeleteDataTypeFolderByIdErrors, GetDataTypeFolderByIdData, GetDataTypeFolderByIdResponses, GetDataTypeFolderByIdErrors, PutDataTypeFolderByIdData, PutDataTypeFolderByIdResponses, PutDataTypeFolderByIdErrors, GetFilterDataTypeData, GetFilterDataTypeResponses, GetFilterDataTypeErrors, GetItemDataTypeData, GetItemDataTypeResponses, GetItemDataTypeErrors, GetItemDataTypeSearchData, GetItemDataTypeSearchResponses, GetItemDataTypeSearchErrors, GetTreeDataTypeAncestorsData, GetTreeDataTypeAncestorsResponses, GetTreeDataTypeAncestorsErrors, GetTreeDataTypeChildrenData, GetTreeDataTypeChildrenResponses, GetTreeDataTypeChildrenErrors, GetTreeDataTypeRootData, GetTreeDataTypeRootResponses, GetTreeDataTypeRootErrors, GetTreeDataTypeSiblingsData, GetTreeDataTypeSiblingsResponses, GetTreeDataTypeSiblingsErrors, GetDictionaryData, GetDictionaryResponses, GetDictionaryErrors, PostDictionaryData, PostDictionaryResponses, PostDictionaryErrors, DeleteDictionaryByIdData, DeleteDictionaryByIdResponses, DeleteDictionaryByIdErrors, GetDictionaryByIdData, GetDictionaryByIdResponses, GetDictionaryByIdErrors, PutDictionaryByIdData, PutDictionaryByIdResponses, PutDictionaryByIdErrors, GetDictionaryByIdExportData, GetDictionaryByIdExportResponses, GetDictionaryByIdExportErrors, PutDictionaryByIdMoveData, PutDictionaryByIdMoveResponses, PutDictionaryByIdMoveErrors, PostDictionaryImportData, PostDictionaryImportResponses, PostDictionaryImportErrors, GetItemDictionaryData, GetItemDictionaryResponses, GetItemDictionaryErrors, GetTreeDictionaryAncestorsData, GetTreeDictionaryAncestorsResponses, GetTreeDictionaryAncestorsErrors, GetTreeDictionaryChildrenData, GetTreeDictionaryChildrenResponses, GetTreeDictionaryChildrenErrors, GetTreeDictionaryRootData, GetTreeDictionaryRootResponses, GetTreeDictionaryRootErrors, PostDocumentBlueprintData, PostDocumentBlueprintResponses, PostDocumentBlueprintErrors, DeleteDocumentBlueprintByIdData, DeleteDocumentBlueprintByIdResponses, DeleteDocumentBlueprintByIdErrors, GetDocumentBlueprintByIdData, GetDocumentBlueprintByIdResponses, GetDocumentBlueprintByIdErrors, PutDocumentBlueprintByIdData, PutDocumentBlueprintByIdResponses, PutDocumentBlueprintByIdErrors, PutDocumentBlueprintByIdMoveData, PutDocumentBlueprintByIdMoveResponses, PutDocumentBlueprintByIdMoveErrors, GetDocumentBlueprintByIdScaffoldData, GetDocumentBlueprintByIdScaffoldResponses, GetDocumentBlueprintByIdScaffoldErrors, PostDocumentBlueprintFolderData, PostDocumentBlueprintFolderResponses, PostDocumentBlueprintFolderErrors, DeleteDocumentBlueprintFolderByIdData, DeleteDocumentBlueprintFolderByIdResponses, DeleteDocumentBlueprintFolderByIdErrors, GetDocumentBlueprintFolderByIdData, GetDocumentBlueprintFolderByIdResponses, GetDocumentBlueprintFolderByIdErrors, PutDocumentBlueprintFolderByIdData, PutDocumentBlueprintFolderByIdResponses, PutDocumentBlueprintFolderByIdErrors, PostDocumentBlueprintFromDocumentData, PostDocumentBlueprintFromDocumentResponses, PostDocumentBlueprintFromDocumentErrors, GetItemDocumentBlueprintData, GetItemDocumentBlueprintResponses, GetItemDocumentBlueprintErrors, GetTreeDocumentBlueprintAncestorsData, GetTreeDocumentBlueprintAncestorsResponses, GetTreeDocumentBlueprintAncestorsErrors, GetTreeDocumentBlueprintChildrenData, GetTreeDocumentBlueprintChildrenResponses, GetTreeDocumentBlueprintChildrenErrors, GetTreeDocumentBlueprintRootData, GetTreeDocumentBlueprintRootResponses, GetTreeDocumentBlueprintRootErrors, GetTreeDocumentBlueprintSiblingsData, GetTreeDocumentBlueprintSiblingsResponses, GetTreeDocumentBlueprintSiblingsErrors, PostDocumentTypeData, PostDocumentTypeResponses, PostDocumentTypeErrors, DeleteDocumentTypeByIdData, DeleteDocumentTypeByIdResponses, DeleteDocumentTypeByIdErrors, GetDocumentTypeByIdData, GetDocumentTypeByIdResponses, GetDocumentTypeByIdErrors, PutDocumentTypeByIdData, PutDocumentTypeByIdResponses, PutDocumentTypeByIdErrors, GetDocumentTypeByIdAllowedChildrenData, GetDocumentTypeByIdAllowedChildrenResponses, GetDocumentTypeByIdAllowedChildrenErrors, GetDocumentTypeByIdBlueprintData, GetDocumentTypeByIdBlueprintResponses, GetDocumentTypeByIdBlueprintErrors, GetDocumentTypeByIdCompositionReferencesData, GetDocumentTypeByIdCompositionReferencesResponses, GetDocumentTypeByIdCompositionReferencesErrors, PostDocumentTypeByIdCopyData, PostDocumentTypeByIdCopyResponses, PostDocumentTypeByIdCopyErrors, GetDocumentTypeByIdExportData, GetDocumentTypeByIdExportResponses, GetDocumentTypeByIdExportErrors, PutDocumentTypeByIdImportData, PutDocumentTypeByIdImportResponses, PutDocumentTypeByIdImportErrors, PutDocumentTypeByIdMoveData, PutDocumentTypeByIdMoveResponses, PutDocumentTypeByIdMoveErrors, GetDocumentTypeAllowedAtRootData, GetDocumentTypeAllowedAtRootResponses, GetDocumentTypeAllowedAtRootErrors, PostDocumentTypeAvailableCompositionsData, PostDocumentTypeAvailableCompositionsResponses, PostDocumentTypeAvailableCompositionsErrors, GetDocumentTypeConfigurationData, GetDocumentTypeConfigurationResponses, GetDocumentTypeConfigurationErrors, PostDocumentTypeFolderData, PostDocumentTypeFolderResponses, PostDocumentTypeFolderErrors, DeleteDocumentTypeFolderByIdData, DeleteDocumentTypeFolderByIdResponses, DeleteDocumentTypeFolderByIdErrors, GetDocumentTypeFolderByIdData, GetDocumentTypeFolderByIdResponses, GetDocumentTypeFolderByIdErrors, PutDocumentTypeFolderByIdData, PutDocumentTypeFolderByIdResponses, PutDocumentTypeFolderByIdErrors, PostDocumentTypeImportData, PostDocumentTypeImportResponses, PostDocumentTypeImportErrors, GetItemDocumentTypeData, GetItemDocumentTypeResponses, GetItemDocumentTypeErrors, GetItemDocumentTypeSearchData, GetItemDocumentTypeSearchResponses, GetItemDocumentTypeSearchErrors, GetTreeDocumentTypeAncestorsData, GetTreeDocumentTypeAncestorsResponses, GetTreeDocumentTypeAncestorsErrors, GetTreeDocumentTypeChildrenData, GetTreeDocumentTypeChildrenResponses, GetTreeDocumentTypeChildrenErrors, GetTreeDocumentTypeRootData, GetTreeDocumentTypeRootResponses, GetTreeDocumentTypeRootErrors, GetTreeDocumentTypeSiblingsData, GetTreeDocumentTypeSiblingsResponses, GetTreeDocumentTypeSiblingsErrors, GetDocumentVersionData, GetDocumentVersionResponses, GetDocumentVersionErrors, GetDocumentVersionByIdData, GetDocumentVersionByIdResponses, GetDocumentVersionByIdErrors, PutDocumentVersionByIdPreventCleanupData, PutDocumentVersionByIdPreventCleanupResponses, PutDocumentVersionByIdPreventCleanupErrors, PostDocumentVersionByIdRollbackData, PostDocumentVersionByIdRollbackResponses, PostDocumentVersionByIdRollbackErrors, GetCollectionDocumentByIdData, GetCollectionDocumentByIdResponses, GetCollectionDocumentByIdErrors, PostDocumentData, PostDocumentResponses, PostDocumentErrors, DeleteDocumentByIdData, DeleteDocumentByIdResponses, DeleteDocumentByIdErrors, GetDocumentByIdData, GetDocumentByIdResponses, GetDocumentByIdErrors, PutDocumentByIdData, PutDocumentByIdResponses, PutDocumentByIdErrors, GetDocumentByIdAuditLogData, GetDocumentByIdAuditLogResponses, GetDocumentByIdAuditLogErrors, PostDocumentByIdCopyData, PostDocumentByIdCopyResponses, PostDocumentByIdCopyErrors, GetDocumentByIdDomainsData, GetDocumentByIdDomainsResponses, GetDocumentByIdDomainsErrors, PutDocumentByIdDomainsData, PutDocumentByIdDomainsResponses, PutDocumentByIdDomainsErrors, PutDocumentByIdMoveData, PutDocumentByIdMoveResponses, PutDocumentByIdMoveErrors, PutDocumentByIdMoveToRecycleBinData, PutDocumentByIdMoveToRecycleBinResponses, PutDocumentByIdMoveToRecycleBinErrors, GetDocumentByIdNotificationsData, GetDocumentByIdNotificationsResponses, GetDocumentByIdNotificationsErrors, PutDocumentByIdNotificationsData, PutDocumentByIdNotificationsResponses, PutDocumentByIdNotificationsErrors, DeleteDocumentByIdPublicAccessData, DeleteDocumentByIdPublicAccessResponses, DeleteDocumentByIdPublicAccessErrors, GetDocumentByIdPublicAccessData, GetDocumentByIdPublicAccessResponses, GetDocumentByIdPublicAccessErrors, PostDocumentByIdPublicAccessData, PostDocumentByIdPublicAccessResponses, PostDocumentByIdPublicAccessErrors, PutDocumentByIdPublicAccessData, PutDocumentByIdPublicAccessResponses, PutDocumentByIdPublicAccessErrors, PutDocumentByIdPublishData, PutDocumentByIdPublishResponses, PutDocumentByIdPublishErrors, PutDocumentByIdPublishWithDescendantsData, PutDocumentByIdPublishWithDescendantsResponses, PutDocumentByIdPublishWithDescendantsErrors, GetDocumentByIdPublishWithDescendantsResultByTaskIdData, GetDocumentByIdPublishWithDescendantsResultByTaskIdResponses, GetDocumentByIdPublishWithDescendantsResultByTaskIdErrors, GetDocumentByIdPublishedData, GetDocumentByIdPublishedResponses, GetDocumentByIdPublishedErrors, GetDocumentByIdReferencedByData, GetDocumentByIdReferencedByResponses, GetDocumentByIdReferencedByErrors, GetDocumentByIdReferencedDescendantsData, GetDocumentByIdReferencedDescendantsResponses, GetDocumentByIdReferencedDescendantsErrors, PutDocumentByIdUnpublishData, PutDocumentByIdUnpublishResponses, PutDocumentByIdUnpublishErrors, PutUmbracoManagementApiV11DocumentByIdValidate11Data, PutUmbracoManagementApiV11DocumentByIdValidate11Responses, PutUmbracoManagementApiV11DocumentByIdValidate11Errors, GetDocumentAreReferencedData, GetDocumentAreReferencedResponses, GetDocumentAreReferencedErrors, GetDocumentConfigurationData, GetDocumentConfigurationResponses, GetDocumentConfigurationErrors, PutDocumentSortData, PutDocumentSortResponses, PutDocumentSortErrors, GetDocumentUrlsData, GetDocumentUrlsResponses, GetDocumentUrlsErrors, PostDocumentValidateData, PostDocumentValidateResponses, PostDocumentValidateErrors, GetItemDocumentData, GetItemDocumentResponses, GetItemDocumentErrors, GetItemDocumentSearchData, GetItemDocumentSearchResponses, GetItemDocumentSearchErrors, DeleteRecycleBinDocumentData, DeleteRecycleBinDocumentResponses, DeleteRecycleBinDocumentErrors, DeleteRecycleBinDocumentByIdData, DeleteRecycleBinDocumentByIdResponses, DeleteRecycleBinDocumentByIdErrors, GetRecycleBinDocumentByIdOriginalParentData, GetRecycleBinDocumentByIdOriginalParentResponses, GetRecycleBinDocumentByIdOriginalParentErrors, PutRecycleBinDocumentByIdRestoreData, PutRecycleBinDocumentByIdRestoreResponses, PutRecycleBinDocumentByIdRestoreErrors, GetRecycleBinDocumentChildrenData, GetRecycleBinDocumentChildrenResponses, GetRecycleBinDocumentChildrenErrors, GetRecycleBinDocumentReferencedByData, GetRecycleBinDocumentReferencedByResponses, GetRecycleBinDocumentReferencedByErrors, GetRecycleBinDocumentRootData, GetRecycleBinDocumentRootResponses, GetRecycleBinDocumentRootErrors, GetTreeDocumentAncestorsData, GetTreeDocumentAncestorsResponses, GetTreeDocumentAncestorsErrors, GetTreeDocumentChildrenData, GetTreeDocumentChildrenResponses, GetTreeDocumentChildrenErrors, GetTreeDocumentRootData, GetTreeDocumentRootResponses, GetTreeDocumentRootErrors, GetTreeDocumentSiblingsData, GetTreeDocumentSiblingsResponses, GetTreeDocumentSiblingsErrors, PostDynamicRootQueryData, PostDynamicRootQueryResponses, PostDynamicRootQueryErrors, GetDynamicRootStepsData, GetDynamicRootStepsResponses, GetDynamicRootStepsErrors, GetHealthCheckGroupData, GetHealthCheckGroupResponses, GetHealthCheckGroupErrors, GetHealthCheckGroupByNameData, GetHealthCheckGroupByNameResponses, GetHealthCheckGroupByNameErrors, PostHealthCheckGroupByNameCheckData, PostHealthCheckGroupByNameCheckResponses, PostHealthCheckGroupByNameCheckErrors, PostHealthCheckExecuteActionData, PostHealthCheckExecuteActionResponses, PostHealthCheckExecuteActionErrors, GetHelpData, GetHelpResponses, GetHelpErrors, GetImagingResizeUrlsData, GetImagingResizeUrlsResponses, GetImagingResizeUrlsErrors, GetImportAnalyzeData, GetImportAnalyzeResponses, GetImportAnalyzeErrors, GetIndexerData, GetIndexerResponses, GetIndexerErrors, GetIndexerByIndexNameData, GetIndexerByIndexNameResponses, GetIndexerByIndexNameErrors, PostIndexerByIndexNameRebuildData, PostIndexerByIndexNameRebuildResponses, PostIndexerByIndexNameRebuildErrors, GetInstallSettingsData, GetInstallSettingsResponses, GetInstallSettingsErrors, PostInstallSetupData, PostInstallSetupResponses, PostInstallSetupErrors, PostInstallValidateDatabaseData, PostInstallValidateDatabaseResponses, PostInstallValidateDatabaseErrors, GetItemLanguageData, GetItemLanguageResponses, GetItemLanguageErrors, GetItemLanguageDefaultData, GetItemLanguageDefaultResponses, GetItemLanguageDefaultErrors, GetLanguageData, GetLanguageResponses, GetLanguageErrors, PostLanguageData, PostLanguageResponses, PostLanguageErrors, DeleteLanguageByIsoCodeData, DeleteLanguageByIsoCodeResponses, DeleteLanguageByIsoCodeErrors, GetLanguageByIsoCodeData, GetLanguageByIsoCodeResponses, GetLanguageByIsoCodeErrors, PutLanguageByIsoCodeData, PutLanguageByIsoCodeResponses, PutLanguageByIsoCodeErrors, GetLogViewerLevelData, GetLogViewerLevelResponses, GetLogViewerLevelErrors, GetLogViewerLevelCountData, GetLogViewerLevelCountResponses, GetLogViewerLevelCountErrors, GetLogViewerLogData, GetLogViewerLogResponses, GetLogViewerLogErrors, GetLogViewerMessageTemplateData, GetLogViewerMessageTemplateResponses, GetLogViewerMessageTemplateErrors, GetLogViewerSavedSearchData, GetLogViewerSavedSearchResponses, GetLogViewerSavedSearchErrors, PostLogViewerSavedSearchData, PostLogViewerSavedSearchResponses, PostLogViewerSavedSearchErrors, DeleteLogViewerSavedSearchByNameData, DeleteLogViewerSavedSearchByNameResponses, DeleteLogViewerSavedSearchByNameErrors, GetLogViewerSavedSearchByNameData, GetLogViewerSavedSearchByNameResponses, GetLogViewerSavedSearchByNameErrors, GetLogViewerValidateLogsSizeData, GetLogViewerValidateLogsSizeResponses, GetLogViewerValidateLogsSizeErrors, GetManifestManifestData, GetManifestManifestResponses, GetManifestManifestErrors, GetManifestManifestPrivateData, GetManifestManifestPrivateResponses, GetManifestManifestPrivateErrors, GetManifestManifestPublicData, GetManifestManifestPublicResponses, GetItemMediaTypeData, GetItemMediaTypeResponses, GetItemMediaTypeErrors, GetItemMediaTypeAllowedData, GetItemMediaTypeAllowedResponses, GetItemMediaTypeAllowedErrors, GetItemMediaTypeFoldersData, GetItemMediaTypeFoldersResponses, GetItemMediaTypeFoldersErrors, GetItemMediaTypeSearchData, GetItemMediaTypeSearchResponses, GetItemMediaTypeSearchErrors, PostMediaTypeData, PostMediaTypeResponses, PostMediaTypeErrors, DeleteMediaTypeByIdData, DeleteMediaTypeByIdResponses, DeleteMediaTypeByIdErrors, GetMediaTypeByIdData, GetMediaTypeByIdResponses, GetMediaTypeByIdErrors, PutMediaTypeByIdData, PutMediaTypeByIdResponses, PutMediaTypeByIdErrors, GetMediaTypeByIdAllowedChildrenData, GetMediaTypeByIdAllowedChildrenResponses, GetMediaTypeByIdAllowedChildrenErrors, GetMediaTypeByIdCompositionReferencesData, GetMediaTypeByIdCompositionReferencesResponses, GetMediaTypeByIdCompositionReferencesErrors, PostMediaTypeByIdCopyData, PostMediaTypeByIdCopyResponses, PostMediaTypeByIdCopyErrors, GetMediaTypeByIdExportData, GetMediaTypeByIdExportResponses, GetMediaTypeByIdExportErrors, PutMediaTypeByIdImportData, PutMediaTypeByIdImportResponses, PutMediaTypeByIdImportErrors, PutMediaTypeByIdMoveData, PutMediaTypeByIdMoveResponses, PutMediaTypeByIdMoveErrors, GetMediaTypeAllowedAtRootData, GetMediaTypeAllowedAtRootResponses, GetMediaTypeAllowedAtRootErrors, PostMediaTypeAvailableCompositionsData, PostMediaTypeAvailableCompositionsResponses, PostMediaTypeAvailableCompositionsErrors, GetMediaTypeConfigurationData, GetMediaTypeConfigurationResponses, GetMediaTypeConfigurationErrors, PostMediaTypeFolderData, PostMediaTypeFolderResponses, PostMediaTypeFolderErrors, DeleteMediaTypeFolderByIdData, DeleteMediaTypeFolderByIdResponses, DeleteMediaTypeFolderByIdErrors, GetMediaTypeFolderByIdData, GetMediaTypeFolderByIdResponses, GetMediaTypeFolderByIdErrors, PutMediaTypeFolderByIdData, PutMediaTypeFolderByIdResponses, PutMediaTypeFolderByIdErrors, PostMediaTypeImportData, PostMediaTypeImportResponses, PostMediaTypeImportErrors, GetTreeMediaTypeAncestorsData, GetTreeMediaTypeAncestorsResponses, GetTreeMediaTypeAncestorsErrors, GetTreeMediaTypeChildrenData, GetTreeMediaTypeChildrenResponses, GetTreeMediaTypeChildrenErrors, GetTreeMediaTypeRootData, GetTreeMediaTypeRootResponses, GetTreeMediaTypeRootErrors, GetTreeMediaTypeSiblingsData, GetTreeMediaTypeSiblingsResponses, GetTreeMediaTypeSiblingsErrors, GetCollectionMediaData, GetCollectionMediaResponses, GetCollectionMediaErrors, GetItemMediaData, GetItemMediaResponses, GetItemMediaErrors, GetItemMediaSearchData, GetItemMediaSearchResponses, GetItemMediaSearchErrors, PostMediaData, PostMediaResponses, PostMediaErrors, DeleteMediaByIdData, DeleteMediaByIdResponses, DeleteMediaByIdErrors, GetMediaByIdData, GetMediaByIdResponses, GetMediaByIdErrors, PutMediaByIdData, PutMediaByIdResponses, PutMediaByIdErrors, GetMediaByIdAuditLogData, GetMediaByIdAuditLogResponses, GetMediaByIdAuditLogErrors, PutMediaByIdMoveData, PutMediaByIdMoveResponses, PutMediaByIdMoveErrors, PutMediaByIdMoveToRecycleBinData, PutMediaByIdMoveToRecycleBinResponses, PutMediaByIdMoveToRecycleBinErrors, GetMediaByIdReferencedByData, GetMediaByIdReferencedByResponses, GetMediaByIdReferencedByErrors, GetMediaByIdReferencedDescendantsData, GetMediaByIdReferencedDescendantsResponses, GetMediaByIdReferencedDescendantsErrors, PutMediaByIdValidateData, PutMediaByIdValidateResponses, PutMediaByIdValidateErrors, GetMediaAreReferencedData, GetMediaAreReferencedResponses, GetMediaAreReferencedErrors, GetMediaConfigurationData, GetMediaConfigurationResponses, GetMediaConfigurationErrors, PutMediaSortData, PutMediaSortResponses, PutMediaSortErrors, GetMediaUrlsData, GetMediaUrlsResponses, GetMediaUrlsErrors, PostMediaValidateData, PostMediaValidateResponses, PostMediaValidateErrors, DeleteRecycleBinMediaData, DeleteRecycleBinMediaResponses, DeleteRecycleBinMediaErrors, DeleteRecycleBinMediaByIdData, DeleteRecycleBinMediaByIdResponses, DeleteRecycleBinMediaByIdErrors, GetRecycleBinMediaByIdOriginalParentData, GetRecycleBinMediaByIdOriginalParentResponses, GetRecycleBinMediaByIdOriginalParentErrors, PutRecycleBinMediaByIdRestoreData, PutRecycleBinMediaByIdRestoreResponses, PutRecycleBinMediaByIdRestoreErrors, GetRecycleBinMediaChildrenData, GetRecycleBinMediaChildrenResponses, GetRecycleBinMediaChildrenErrors, GetRecycleBinMediaReferencedByData, GetRecycleBinMediaReferencedByResponses, GetRecycleBinMediaReferencedByErrors, GetRecycleBinMediaRootData, GetRecycleBinMediaRootResponses, GetRecycleBinMediaRootErrors, GetTreeMediaAncestorsData, GetTreeMediaAncestorsResponses, GetTreeMediaAncestorsErrors, GetTreeMediaChildrenData, GetTreeMediaChildrenResponses, GetTreeMediaChildrenErrors, GetTreeMediaRootData, GetTreeMediaRootResponses, GetTreeMediaRootErrors, GetTreeMediaSiblingsData, GetTreeMediaSiblingsResponses, GetTreeMediaSiblingsErrors, GetItemMemberGroupData, GetItemMemberGroupResponses, GetItemMemberGroupErrors, GetMemberGroupData, GetMemberGroupResponses, GetMemberGroupErrors, PostMemberGroupData, PostMemberGroupResponses, PostMemberGroupErrors, DeleteMemberGroupByIdData, DeleteMemberGroupByIdResponses, DeleteMemberGroupByIdErrors, GetMemberGroupByIdData, GetMemberGroupByIdResponses, GetMemberGroupByIdErrors, PutMemberGroupByIdData, PutMemberGroupByIdResponses, PutMemberGroupByIdErrors, GetTreeMemberGroupRootData, GetTreeMemberGroupRootResponses, GetTreeMemberGroupRootErrors, GetItemMemberTypeData, GetItemMemberTypeResponses, GetItemMemberTypeErrors, GetItemMemberTypeSearchData, GetItemMemberTypeSearchResponses, GetItemMemberTypeSearchErrors, PostMemberTypeData, PostMemberTypeResponses, PostMemberTypeErrors, DeleteMemberTypeByIdData, DeleteMemberTypeByIdResponses, DeleteMemberTypeByIdErrors, GetMemberTypeByIdData, GetMemberTypeByIdResponses, GetMemberTypeByIdErrors, PutMemberTypeByIdData, PutMemberTypeByIdResponses, PutMemberTypeByIdErrors, GetMemberTypeByIdCompositionReferencesData, GetMemberTypeByIdCompositionReferencesResponses, GetMemberTypeByIdCompositionReferencesErrors, PostMemberTypeByIdCopyData, PostMemberTypeByIdCopyResponses, PostMemberTypeByIdCopyErrors, PostMemberTypeAvailableCompositionsData, PostMemberTypeAvailableCompositionsResponses, PostMemberTypeAvailableCompositionsErrors, GetMemberTypeConfigurationData, GetMemberTypeConfigurationResponses, GetMemberTypeConfigurationErrors, GetTreeMemberTypeRootData, GetTreeMemberTypeRootResponses, GetTreeMemberTypeRootErrors, GetFilterMemberData, GetFilterMemberResponses, GetFilterMemberErrors, GetItemMemberData, GetItemMemberResponses, GetItemMemberErrors, GetItemMemberSearchData, GetItemMemberSearchResponses, GetItemMemberSearchErrors, PostMemberData, PostMemberResponses, PostMemberErrors, DeleteMemberByIdData, DeleteMemberByIdResponses, DeleteMemberByIdErrors, GetMemberByIdData, GetMemberByIdResponses, GetMemberByIdErrors, PutMemberByIdData, PutMemberByIdResponses, PutMemberByIdErrors, GetMemberByIdReferencedByData, GetMemberByIdReferencedByResponses, GetMemberByIdReferencedByErrors, GetMemberByIdReferencedDescendantsData, GetMemberByIdReferencedDescendantsResponses, GetMemberByIdReferencedDescendantsErrors, PutMemberByIdValidateData, PutMemberByIdValidateResponses, PutMemberByIdValidateErrors, GetMemberAreReferencedData, GetMemberAreReferencedResponses, GetMemberAreReferencedErrors, GetMemberConfigurationData, GetMemberConfigurationResponses, GetMemberConfigurationErrors, PostMemberValidateData, PostMemberValidateResponses, PostMemberValidateErrors, PostModelsBuilderBuildData, PostModelsBuilderBuildResponses, PostModelsBuilderBuildErrors, GetModelsBuilderDashboardData, GetModelsBuilderDashboardResponses, GetModelsBuilderDashboardErrors, GetModelsBuilderStatusData, GetModelsBuilderStatusResponses, GetModelsBuilderStatusErrors, GetObjectTypesData, GetObjectTypesResponses, GetObjectTypesErrors, GetOembedQueryData, GetOembedQueryResponses, GetOembedQueryErrors, PostPackageByNameRunMigrationData, PostPackageByNameRunMigrationResponses, PostPackageByNameRunMigrationErrors, GetPackageConfigurationData, GetPackageConfigurationResponses, GetPackageConfigurationErrors, GetPackageCreatedData, GetPackageCreatedResponses, GetPackageCreatedErrors, PostPackageCreatedData, PostPackageCreatedResponses, PostPackageCreatedErrors, DeletePackageCreatedByIdData, DeletePackageCreatedByIdResponses, DeletePackageCreatedByIdErrors, GetPackageCreatedByIdData, GetPackageCreatedByIdResponses, GetPackageCreatedByIdErrors, PutPackageCreatedByIdData, PutPackageCreatedByIdResponses, PutPackageCreatedByIdErrors, GetPackageCreatedByIdDownloadData, GetPackageCreatedByIdDownloadResponses, GetPackageCreatedByIdDownloadErrors, GetPackageMigrationStatusData, GetPackageMigrationStatusResponses, GetPackageMigrationStatusErrors, GetItemPartialViewData, GetItemPartialViewResponses, GetItemPartialViewErrors, PostPartialViewData, PostPartialViewResponses, PostPartialViewErrors, DeletePartialViewByPathData, DeletePartialViewByPathResponses, DeletePartialViewByPathErrors, GetPartialViewByPathData, GetPartialViewByPathResponses, GetPartialViewByPathErrors, PutPartialViewByPathData, PutPartialViewByPathResponses, PutPartialViewByPathErrors, PutPartialViewByPathRenameData, PutPartialViewByPathRenameResponses, PutPartialViewByPathRenameErrors, PostPartialViewFolderData, PostPartialViewFolderResponses, PostPartialViewFolderErrors, DeletePartialViewFolderByPathData, DeletePartialViewFolderByPathResponses, DeletePartialViewFolderByPathErrors, GetPartialViewFolderByPathData, GetPartialViewFolderByPathResponses, GetPartialViewFolderByPathErrors, GetPartialViewSnippetData, GetPartialViewSnippetResponses, GetPartialViewSnippetErrors, GetPartialViewSnippetByIdData, GetPartialViewSnippetByIdResponses, GetPartialViewSnippetByIdErrors, GetTreePartialViewAncestorsData, GetTreePartialViewAncestorsResponses, GetTreePartialViewAncestorsErrors, GetTreePartialViewChildrenData, GetTreePartialViewChildrenResponses, GetTreePartialViewChildrenErrors, GetTreePartialViewRootData, GetTreePartialViewRootResponses, GetTreePartialViewRootErrors, DeletePreviewData, DeletePreviewResponses, PostPreviewData, PostPreviewResponses, PostPreviewErrors, GetProfilingStatusData, GetProfilingStatusResponses, GetProfilingStatusErrors, PutProfilingStatusData, PutProfilingStatusResponses, PutProfilingStatusErrors, GetPropertyTypeIsUsedData, GetPropertyTypeIsUsedResponses, GetPropertyTypeIsUsedErrors, PostPublishedCacheRebuildData, PostPublishedCacheRebuildResponses, PostPublishedCacheRebuildErrors, GetPublishedCacheRebuildStatusData, GetPublishedCacheRebuildStatusResponses, GetPublishedCacheRebuildStatusErrors, PostPublishedCacheReloadData, PostPublishedCacheReloadResponses, PostPublishedCacheReloadErrors, GetRedirectManagementData, GetRedirectManagementResponses, GetRedirectManagementErrors, DeleteRedirectManagementByIdData, DeleteRedirectManagementByIdResponses, DeleteRedirectManagementByIdErrors, GetRedirectManagementByIdData, GetRedirectManagementByIdResponses, GetRedirectManagementByIdErrors, GetRedirectManagementStatusData, GetRedirectManagementStatusResponses, GetRedirectManagementStatusErrors, PostRedirectManagementStatusData, PostRedirectManagementStatusResponses, PostRedirectManagementStatusErrors, GetItemRelationTypeData, GetItemRelationTypeResponses, GetItemRelationTypeErrors, GetRelationTypeData, GetRelationTypeResponses, GetRelationTypeErrors, GetRelationTypeByIdData, GetRelationTypeByIdResponses, GetRelationTypeByIdErrors, GetRelationByRelationTypeIdData, GetRelationByRelationTypeIdResponses, GetRelationByRelationTypeIdErrors, GetItemScriptData, GetItemScriptResponses, GetItemScriptErrors, PostScriptData, PostScriptResponses, PostScriptErrors, DeleteScriptByPathData, DeleteScriptByPathResponses, DeleteScriptByPathErrors, GetScriptByPathData, GetScriptByPathResponses, GetScriptByPathErrors, PutScriptByPathData, PutScriptByPathResponses, PutScriptByPathErrors, PutScriptByPathRenameData, PutScriptByPathRenameResponses, PutScriptByPathRenameErrors, PostScriptFolderData, PostScriptFolderResponses, PostScriptFolderErrors, DeleteScriptFolderByPathData, DeleteScriptFolderByPathResponses, DeleteScriptFolderByPathErrors, GetScriptFolderByPathData, GetScriptFolderByPathResponses, GetScriptFolderByPathErrors, GetTreeScriptAncestorsData, GetTreeScriptAncestorsResponses, GetTreeScriptAncestorsErrors, GetTreeScriptChildrenData, GetTreeScriptChildrenResponses, GetTreeScriptChildrenErrors, GetTreeScriptRootData, GetTreeScriptRootResponses, GetTreeScriptRootErrors, GetSearcherData, GetSearcherResponses, GetSearcherErrors, GetSearcherBySearcherNameQueryData, GetSearcherBySearcherNameQueryResponses, GetSearcherBySearcherNameQueryErrors, GetSecurityConfigurationData, GetSecurityConfigurationResponses, GetSecurityConfigurationErrors, PostSecurityForgotPasswordData, PostSecurityForgotPasswordResponses, PostSecurityForgotPasswordErrors, PostSecurityForgotPasswordResetData, PostSecurityForgotPasswordResetResponses, PostSecurityForgotPasswordResetErrors, PostSecurityForgotPasswordVerifyData, PostSecurityForgotPasswordVerifyResponses, PostSecurityForgotPasswordVerifyErrors, GetSegmentData, GetSegmentResponses, GetSegmentErrors, GetServerConfigurationData, GetServerConfigurationResponses, GetServerInformationData, GetServerInformationResponses, GetServerInformationErrors, GetServerStatusData, GetServerStatusResponses, GetServerStatusErrors, GetServerTroubleshootingData, GetServerTroubleshootingResponses, GetServerTroubleshootingErrors, GetServerUpgradeCheckData, GetServerUpgradeCheckResponses, GetServerUpgradeCheckErrors, GetItemStaticFileData, GetItemStaticFileResponses, GetItemStaticFileErrors, GetTreeStaticFileAncestorsData, GetTreeStaticFileAncestorsResponses, GetTreeStaticFileAncestorsErrors, GetTreeStaticFileChildrenData, GetTreeStaticFileChildrenResponses, GetTreeStaticFileChildrenErrors, GetTreeStaticFileRootData, GetTreeStaticFileRootResponses, GetTreeStaticFileRootErrors, GetItemStylesheetData, GetItemStylesheetResponses, GetItemStylesheetErrors, PostStylesheetData, PostStylesheetResponses, PostStylesheetErrors, DeleteStylesheetByPathData, DeleteStylesheetByPathResponses, DeleteStylesheetByPathErrors, GetStylesheetByPathData, GetStylesheetByPathResponses, GetStylesheetByPathErrors, PutStylesheetByPathData, PutStylesheetByPathResponses, PutStylesheetByPathErrors, PutStylesheetByPathRenameData, PutStylesheetByPathRenameResponses, PutStylesheetByPathRenameErrors, PostStylesheetFolderData, PostStylesheetFolderResponses, PostStylesheetFolderErrors, DeleteStylesheetFolderByPathData, DeleteStylesheetFolderByPathResponses, DeleteStylesheetFolderByPathErrors, GetStylesheetFolderByPathData, GetStylesheetFolderByPathResponses, GetStylesheetFolderByPathErrors, GetTreeStylesheetAncestorsData, GetTreeStylesheetAncestorsResponses, GetTreeStylesheetAncestorsErrors, GetTreeStylesheetChildrenData, GetTreeStylesheetChildrenResponses, GetTreeStylesheetChildrenErrors, GetTreeStylesheetRootData, GetTreeStylesheetRootResponses, GetTreeStylesheetRootErrors, GetTagData, GetTagResponses, GetTagErrors, GetTelemetryData, GetTelemetryResponses, GetTelemetryErrors, GetTelemetryLevelData, GetTelemetryLevelResponses, GetTelemetryLevelErrors, PostTelemetryLevelData, PostTelemetryLevelResponses, PostTelemetryLevelErrors, GetItemTemplateData, GetItemTemplateResponses, GetItemTemplateErrors, GetItemTemplateSearchData, GetItemTemplateSearchResponses, GetItemTemplateSearchErrors, PostTemplateData, PostTemplateResponses, PostTemplateErrors, DeleteTemplateByIdData, DeleteTemplateByIdResponses, DeleteTemplateByIdErrors, GetTemplateByIdData, GetTemplateByIdResponses, GetTemplateByIdErrors, PutTemplateByIdData, PutTemplateByIdResponses, PutTemplateByIdErrors, GetTemplateConfigurationData, GetTemplateConfigurationResponses, GetTemplateConfigurationErrors, PostTemplateQueryExecuteData, PostTemplateQueryExecuteResponses, PostTemplateQueryExecuteErrors, GetTemplateQuerySettingsData, GetTemplateQuerySettingsResponses, GetTemplateQuerySettingsErrors, GetTreeTemplateAncestorsData, GetTreeTemplateAncestorsResponses, GetTreeTemplateAncestorsErrors, GetTreeTemplateChildrenData, GetTreeTemplateChildrenResponses, GetTreeTemplateChildrenErrors, GetTreeTemplateRootData, GetTreeTemplateRootResponses, GetTreeTemplateRootErrors, GetTreeTemplateSiblingsData, GetTreeTemplateSiblingsResponses, GetTreeTemplateSiblingsErrors, PostTemporaryFileData, PostTemporaryFileResponses, PostTemporaryFileErrors, DeleteTemporaryFileByIdData, DeleteTemporaryFileByIdResponses, DeleteTemporaryFileByIdErrors, GetTemporaryFileByIdData, GetTemporaryFileByIdResponses, GetTemporaryFileByIdErrors, GetTemporaryFileConfigurationData, GetTemporaryFileConfigurationResponses, GetTemporaryFileConfigurationErrors, PostUpgradeAuthorizeData, PostUpgradeAuthorizeResponses, PostUpgradeAuthorizeErrors, GetUpgradeSettingsData, GetUpgradeSettingsResponses, GetUpgradeSettingsErrors, GetUserDataData, GetUserDataResponses, GetUserDataErrors, PostUserDataData, PostUserDataResponses, PostUserDataErrors, PutUserDataData, PutUserDataResponses, PutUserDataErrors, GetUserDataByIdData, GetUserDataByIdResponses, GetUserDataByIdErrors, GetFilterUserGroupData, GetFilterUserGroupResponses, GetFilterUserGroupErrors, GetItemUserGroupData, GetItemUserGroupResponses, GetItemUserGroupErrors, DeleteUserGroupData, DeleteUserGroupResponses, DeleteUserGroupErrors, GetUserGroupData, GetUserGroupResponses, GetUserGroupErrors, PostUserGroupData, PostUserGroupResponses, PostUserGroupErrors, DeleteUserGroupByIdData, DeleteUserGroupByIdResponses, DeleteUserGroupByIdErrors, GetUserGroupByIdData, GetUserGroupByIdResponses, GetUserGroupByIdErrors, PutUserGroupByIdData, PutUserGroupByIdResponses, PutUserGroupByIdErrors, DeleteUserGroupByIdUsersData, DeleteUserGroupByIdUsersResponses, DeleteUserGroupByIdUsersErrors, PostUserGroupByIdUsersData, PostUserGroupByIdUsersResponses, PostUserGroupByIdUsersErrors, GetFilterUserData, GetFilterUserResponses, GetFilterUserErrors, GetItemUserData, GetItemUserResponses, GetItemUserErrors, DeleteUserData, DeleteUserResponses, DeleteUserErrors, GetUserData, GetUserResponses, GetUserErrors, PostUserData, PostUserResponses, PostUserErrors, DeleteUserByIdData, DeleteUserByIdResponses, DeleteUserByIdErrors, GetUserByIdData, GetUserByIdResponses, GetUserByIdErrors, PutUserByIdData, PutUserByIdResponses, PutUserByIdErrors, GetUserById2FaData, GetUserById2FaResponses, GetUserById2FaErrors, DeleteUserById2FaByProviderNameData, DeleteUserById2FaByProviderNameResponses, DeleteUserById2FaByProviderNameErrors, GetUserByIdCalculateStartNodesData, GetUserByIdCalculateStartNodesResponses, GetUserByIdCalculateStartNodesErrors, PostUserByIdChangePasswordData, PostUserByIdChangePasswordResponses, PostUserByIdChangePasswordErrors, GetUserByIdClientCredentialsData, GetUserByIdClientCredentialsResponses, GetUserByIdClientCredentialsErrors, PostUserByIdClientCredentialsData, PostUserByIdClientCredentialsResponses, PostUserByIdClientCredentialsErrors, DeleteUserByIdClientCredentialsByClientIdData, DeleteUserByIdClientCredentialsByClientIdResponses, DeleteUserByIdClientCredentialsByClientIdErrors, PostUserByIdResetPasswordData, PostUserByIdResetPasswordResponses, PostUserByIdResetPasswordErrors, DeleteUserAvatarByIdData, DeleteUserAvatarByIdResponses, DeleteUserAvatarByIdErrors, PostUserAvatarByIdData, PostUserAvatarByIdResponses, PostUserAvatarByIdErrors, GetUserConfigurationData, GetUserConfigurationResponses, GetUserConfigurationErrors, GetUserCurrentData, GetUserCurrentResponses, GetUserCurrentErrors, GetUserCurrent2FaData, GetUserCurrent2FaResponses, GetUserCurrent2FaErrors, DeleteUserCurrent2FaByProviderNameData, DeleteUserCurrent2FaByProviderNameResponses, DeleteUserCurrent2FaByProviderNameErrors, GetUserCurrent2FaByProviderNameData, GetUserCurrent2FaByProviderNameResponses, GetUserCurrent2FaByProviderNameErrors, PostUserCurrent2FaByProviderNameData, PostUserCurrent2FaByProviderNameResponses, PostUserCurrent2FaByProviderNameErrors, PostUserCurrentAvatarData, PostUserCurrentAvatarResponses, PostUserCurrentAvatarErrors, PostUserCurrentChangePasswordData, PostUserCurrentChangePasswordResponses, PostUserCurrentChangePasswordErrors, GetUserCurrentConfigurationData, GetUserCurrentConfigurationResponses, GetUserCurrentConfigurationErrors, GetUserCurrentLoginProvidersData, GetUserCurrentLoginProvidersResponses, GetUserCurrentLoginProvidersErrors, GetUserCurrentPermissionsData, GetUserCurrentPermissionsResponses, GetUserCurrentPermissionsErrors, GetUserCurrentPermissionsDocumentData, GetUserCurrentPermissionsDocumentResponses, GetUserCurrentPermissionsDocumentErrors, GetUserCurrentPermissionsMediaData, GetUserCurrentPermissionsMediaResponses, GetUserCurrentPermissionsMediaErrors, PostUserDisableData, PostUserDisableResponses, PostUserDisableErrors, PostUserEnableData, PostUserEnableResponses, PostUserEnableErrors, PostUserInviteData, PostUserInviteResponses, PostUserInviteErrors, PostUserInviteCreatePasswordData, PostUserInviteCreatePasswordResponses, PostUserInviteCreatePasswordErrors, PostUserInviteResendData, PostUserInviteResendResponses, PostUserInviteResendErrors, PostUserInviteVerifyData, PostUserInviteVerifyResponses, PostUserInviteVerifyErrors, PostUserSetUserGroupsData, PostUserSetUserGroupsResponses, PostUserSetUserGroupsErrors, PostUserUnlockData, PostUserUnlockResponses, PostUserUnlockErrors, GetItemWebhookData, GetItemWebhookResponses, GetItemWebhookErrors, GetWebhookData, GetWebhookResponses, GetWebhookErrors, PostWebhookData, PostWebhookResponses, PostWebhookErrors, DeleteWebhookByIdData, DeleteWebhookByIdResponses, DeleteWebhookByIdErrors, GetWebhookByIdData, GetWebhookByIdResponses, GetWebhookByIdErrors, PutWebhookByIdData, PutWebhookByIdResponses, PutWebhookByIdErrors, GetWebhookByIdLogsData, GetWebhookByIdLogsResponses, GetWebhookByIdLogsErrors, GetWebhookEventsData, GetWebhookEventsResponses, GetWebhookEventsErrors, GetWebhookLogsData, GetWebhookLogsResponses, GetWebhookLogsErrors } from './types.gen'; import { client as _heyApiClient } from './client.gen'; export type Options = ClientOptions & { @@ -320,6 +320,19 @@ export class DataTypeService { ...options }); } + + public static getTreeDataTypeSiblings(options?: Options) { + return (options?.client ?? _heyApiClient).get({ + security: [ + { + scheme: 'bearer', + type: 'http' + } + ], + url: '/umbraco/management/api/v1/tree/data-type/siblings', + ...options + }); + } } export class DictionaryService { @@ -715,6 +728,19 @@ export class DocumentBlueprintService { ...options }); } + + public static getTreeDocumentBlueprintSiblings(options?: Options) { + return (options?.client ?? _heyApiClient).get({ + security: [ + { + scheme: 'bearer', + type: 'http' + } + ], + url: '/umbraco/management/api/v1/tree/document-blueprint/siblings', + ...options + }); + } } export class DocumentTypeService { @@ -1065,6 +1091,19 @@ export class DocumentTypeService { ...options }); } + + public static getTreeDocumentTypeSiblings(options?: Options) { + return (options?.client ?? _heyApiClient).get({ + security: [ + { + scheme: 'bearer', + type: 'http' + } + ], + url: '/umbraco/management/api/v1/tree/document-type/siblings', + ...options + }); + } } export class DocumentVersionService { @@ -1727,6 +1766,19 @@ export class DocumentService { ...options }); } + + public static getTreeDocumentSiblings(options?: Options) { + return (options?.client ?? _heyApiClient).get({ + security: [ + { + scheme: 'bearer', + type: 'http' + } + ], + url: '/umbraco/management/api/v1/tree/document/siblings', + ...options + }); + } } export class DynamicRootService { @@ -2556,6 +2608,19 @@ export class MediaTypeService { ...options }); } + + public static getTreeMediaTypeSiblings(options?: Options) { + return (options?.client ?? _heyApiClient).get({ + security: [ + { + scheme: 'bearer', + type: 'http' + } + ], + url: '/umbraco/management/api/v1/tree/media-type/siblings', + ...options + }); + } } export class MediaService { @@ -2953,6 +3018,19 @@ export class MediaService { ...options }); } + + public static getTreeMediaSiblings(options?: Options) { + return (options?.client ?? _heyApiClient).get({ + security: [ + { + scheme: 'bearer', + type: 'http' + } + ], + url: '/umbraco/management/api/v1/tree/media/siblings', + ...options + }); + } } export class MemberGroupService { @@ -4819,6 +4897,19 @@ export class TemplateService { ...options }); } + + public static getTreeTemplateSiblings(options?: Options) { + return (options?.client ?? _heyApiClient).get({ + security: [ + { + scheme: 'bearer', + type: 'http' + } + ], + url: '/umbraco/management/api/v1/tree/template/siblings', + ...options + }); + } } export class TemporaryFileService { diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/backend-api/types.gen.ts b/src/Umbraco.Web.UI.Client/src/packages/core/backend-api/types.gen.ts index cf958d9ab7..8cc5b2ace8 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/backend-api/types.gen.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/backend-api/types.gen.ts @@ -3745,6 +3745,37 @@ export type GetTreeDataTypeRootResponses = { export type GetTreeDataTypeRootResponse = GetTreeDataTypeRootResponses[keyof GetTreeDataTypeRootResponses]; +export type GetTreeDataTypeSiblingsData = { + body?: never; + path?: never; + query?: { + target?: string; + before?: number; + after?: number; + }; + url: '/umbraco/management/api/v1/tree/data-type/siblings'; +}; + +export type GetTreeDataTypeSiblingsErrors = { + /** + * The resource is protected and requires an authentication token + */ + 401: unknown; + /** + * The authenticated user does not have access to this resource + */ + 403: unknown; +}; + +export type GetTreeDataTypeSiblingsResponses = { + /** + * OK + */ + 200: Array; +}; + +export type GetTreeDataTypeSiblingsResponse = GetTreeDataTypeSiblingsResponses[keyof GetTreeDataTypeSiblingsResponses]; + export type GetDictionaryData = { body?: never; path?: never; @@ -4652,6 +4683,37 @@ export type GetTreeDocumentBlueprintRootResponses = { export type GetTreeDocumentBlueprintRootResponse = GetTreeDocumentBlueprintRootResponses[keyof GetTreeDocumentBlueprintRootResponses]; +export type GetTreeDocumentBlueprintSiblingsData = { + body?: never; + path?: never; + query?: { + target?: string; + before?: number; + after?: number; + }; + url: '/umbraco/management/api/v1/tree/document-blueprint/siblings'; +}; + +export type GetTreeDocumentBlueprintSiblingsErrors = { + /** + * The resource is protected and requires an authentication token + */ + 401: unknown; + /** + * The authenticated user does not have access to this resource + */ + 403: unknown; +}; + +export type GetTreeDocumentBlueprintSiblingsResponses = { + /** + * OK + */ + 200: Array; +}; + +export type GetTreeDocumentBlueprintSiblingsResponse = GetTreeDocumentBlueprintSiblingsResponses[keyof GetTreeDocumentBlueprintSiblingsResponses]; + export type PostDocumentTypeData = { body?: CreateDocumentTypeRequestModel; path?: never; @@ -5462,6 +5524,37 @@ export type GetTreeDocumentTypeRootResponses = { export type GetTreeDocumentTypeRootResponse = GetTreeDocumentTypeRootResponses[keyof GetTreeDocumentTypeRootResponses]; +export type GetTreeDocumentTypeSiblingsData = { + body?: never; + path?: never; + query?: { + target?: string; + before?: number; + after?: number; + }; + url: '/umbraco/management/api/v1/tree/document-type/siblings'; +}; + +export type GetTreeDocumentTypeSiblingsErrors = { + /** + * The resource is protected and requires an authentication token + */ + 401: unknown; + /** + * The authenticated user does not have access to this resource + */ + 403: unknown; +}; + +export type GetTreeDocumentTypeSiblingsResponses = { + /** + * OK + */ + 200: Array; +}; + +export type GetTreeDocumentTypeSiblingsResponse = GetTreeDocumentTypeSiblingsResponses[keyof GetTreeDocumentTypeSiblingsResponses]; + export type GetDocumentVersionData = { body?: never; path?: never; @@ -7056,6 +7149,37 @@ export type GetTreeDocumentRootResponses = { export type GetTreeDocumentRootResponse = GetTreeDocumentRootResponses[keyof GetTreeDocumentRootResponses]; +export type GetTreeDocumentSiblingsData = { + body?: never; + path?: never; + query?: { + target?: string; + before?: number; + after?: number; + }; + url: '/umbraco/management/api/v1/tree/document/siblings'; +}; + +export type GetTreeDocumentSiblingsErrors = { + /** + * The resource is protected and requires an authentication token + */ + 401: unknown; + /** + * The authenticated user does not have access to this resource + */ + 403: unknown; +}; + +export type GetTreeDocumentSiblingsResponses = { + /** + * OK + */ + 200: Array; +}; + +export type GetTreeDocumentSiblingsResponse = GetTreeDocumentSiblingsResponses[keyof GetTreeDocumentSiblingsResponses]; + export type PostDynamicRootQueryData = { body?: DynamicRootRequestModel; path?: never; @@ -8920,6 +9044,37 @@ export type GetTreeMediaTypeRootResponses = { export type GetTreeMediaTypeRootResponse = GetTreeMediaTypeRootResponses[keyof GetTreeMediaTypeRootResponses]; +export type GetTreeMediaTypeSiblingsData = { + body?: never; + path?: never; + query?: { + target?: string; + before?: number; + after?: number; + }; + url: '/umbraco/management/api/v1/tree/media-type/siblings'; +}; + +export type GetTreeMediaTypeSiblingsErrors = { + /** + * The resource is protected and requires an authentication token + */ + 401: unknown; + /** + * The authenticated user does not have access to this resource + */ + 403: unknown; +}; + +export type GetTreeMediaTypeSiblingsResponses = { + /** + * OK + */ + 200: Array; +}; + +export type GetTreeMediaTypeSiblingsResponse = GetTreeMediaTypeSiblingsResponses[keyof GetTreeMediaTypeSiblingsResponses]; + export type GetCollectionMediaData = { body?: never; path?: never; @@ -9854,6 +10009,37 @@ export type GetTreeMediaRootResponses = { export type GetTreeMediaRootResponse = GetTreeMediaRootResponses[keyof GetTreeMediaRootResponses]; +export type GetTreeMediaSiblingsData = { + body?: never; + path?: never; + query?: { + target?: string; + before?: number; + after?: number; + }; + url: '/umbraco/management/api/v1/tree/media/siblings'; +}; + +export type GetTreeMediaSiblingsErrors = { + /** + * The resource is protected and requires an authentication token + */ + 401: unknown; + /** + * The authenticated user does not have access to this resource + */ + 403: unknown; +}; + +export type GetTreeMediaSiblingsResponses = { + /** + * OK + */ + 200: Array; +}; + +export type GetTreeMediaSiblingsResponse = GetTreeMediaSiblingsResponses[keyof GetTreeMediaSiblingsResponses]; + export type GetItemMemberGroupData = { body?: never; path?: never; @@ -12841,10 +13027,6 @@ export type GetSegmentErrors = { * The resource is protected and requires an authentication token */ 401: unknown; - /** - * The authenticated user does not have access to this resource - */ - 403: unknown; }; export type GetSegmentError = GetSegmentErrors[keyof GetSegmentErrors]; @@ -13962,6 +14144,37 @@ export type GetTreeTemplateRootResponses = { export type GetTreeTemplateRootResponse = GetTreeTemplateRootResponses[keyof GetTreeTemplateRootResponses]; +export type GetTreeTemplateSiblingsData = { + body?: never; + path?: never; + query?: { + target?: string; + before?: number; + after?: number; + }; + url: '/umbraco/management/api/v1/tree/template/siblings'; +}; + +export type GetTreeTemplateSiblingsErrors = { + /** + * The resource is protected and requires an authentication token + */ + 401: unknown; + /** + * The authenticated user does not have access to this resource + */ + 403: unknown; +}; + +export type GetTreeTemplateSiblingsResponses = { + /** + * OK + */ + 200: Array; +}; + +export type GetTreeTemplateSiblingsResponse = GetTreeTemplateSiblingsResponses[keyof GetTreeTemplateSiblingsResponses]; + export type PostTemporaryFileData = { body?: { Id: string; @@ -16081,6 +16294,10 @@ export type GetWebhookByIdLogsErrors = { * The resource is protected and requires an authentication token */ 401: unknown; + /** + * The authenticated user does not have access to this resource + */ + 403: unknown; }; export type GetWebhookByIdLogsResponses = { @@ -16137,6 +16354,10 @@ export type GetWebhookLogsErrors = { * The resource is protected and requires an authentication token */ 401: unknown; + /** + * The authenticated user does not have access to this resource + */ + 403: unknown; }; export type GetWebhookLogsResponses = { From 55cc415c3094c636491b2078d7f8c7b2dea0a655 Mon Sep 17 00:00:00 2001 From: Kenn Jacobsen Date: Mon, 21 Jul 2025 12:51:44 +0200 Subject: [PATCH 16/23] Make the OpenAPI security scheme name for the Management API valid (#19762) --- .../ManagementApiConfiguration.cs | 2 +- src/Umbraco.Cms.Api.Management/OpenApi.json | 806 +++++++++--------- 2 files changed, 404 insertions(+), 404 deletions(-) diff --git a/src/Umbraco.Cms.Api.Management/DependencyInjection/ManagementApiConfiguration.cs b/src/Umbraco.Cms.Api.Management/DependencyInjection/ManagementApiConfiguration.cs index 613185a285..8d428d553e 100644 --- a/src/Umbraco.Cms.Api.Management/DependencyInjection/ManagementApiConfiguration.cs +++ b/src/Umbraco.Cms.Api.Management/DependencyInjection/ManagementApiConfiguration.cs @@ -4,7 +4,7 @@ namespace Umbraco.Cms.Api.Management.DependencyInjection; internal static class ManagementApiConfiguration { - internal const string ApiSecurityName = "Backoffice User"; + internal const string ApiSecurityName = "Backoffice-User"; internal const string ApiTitle = "Umbraco Management API"; internal const string ApiName = "management"; diff --git a/src/Umbraco.Cms.Api.Management/OpenApi.json b/src/Umbraco.Cms.Api.Management/OpenApi.json index 16d11c7392..1cd05c0cd8 100644 --- a/src/Umbraco.Cms.Api.Management/OpenApi.json +++ b/src/Umbraco.Cms.Api.Management/OpenApi.json @@ -53,7 +53,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -199,7 +199,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -259,7 +259,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -368,7 +368,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -508,7 +508,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -639,7 +639,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -695,7 +695,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -811,7 +811,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -875,7 +875,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -939,7 +939,7 @@ "deprecated": true, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -974,7 +974,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -1120,7 +1120,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -1180,7 +1180,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -1289,7 +1289,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -1429,7 +1429,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -1506,7 +1506,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -1555,7 +1555,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -1614,7 +1614,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -1662,7 +1662,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -1733,7 +1733,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -1796,7 +1796,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -1860,7 +1860,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -1922,7 +1922,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -2092,7 +2092,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -2152,7 +2152,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -2261,7 +2261,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -2401,7 +2401,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -2470,7 +2470,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -2612,7 +2612,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -2758,7 +2758,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -2807,7 +2807,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -2855,7 +2855,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -2918,7 +2918,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -2973,7 +2973,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -3119,7 +3119,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -3179,7 +3179,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -3288,7 +3288,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -3428,7 +3428,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -3544,7 +3544,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -3604,7 +3604,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -3750,7 +3750,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -3810,7 +3810,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -3919,7 +3919,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -4059,7 +4059,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -4179,7 +4179,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -4228,7 +4228,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -4276,7 +4276,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -4347,7 +4347,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -4410,7 +4410,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -4474,7 +4474,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -4620,7 +4620,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -4680,7 +4680,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -4763,7 +4763,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -4903,7 +4903,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -4989,7 +4989,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -5067,7 +5067,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -5144,7 +5144,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -5301,7 +5301,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -5362,7 +5362,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -5504,7 +5504,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -5646,7 +5646,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -5701,7 +5701,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -5794,7 +5794,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -5829,7 +5829,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -5975,7 +5975,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -6035,7 +6035,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -6144,7 +6144,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -6284,7 +6284,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -6430,7 +6430,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -6479,7 +6479,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -6545,7 +6545,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -6593,7 +6593,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -6664,7 +6664,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -6727,7 +6727,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -6791,7 +6791,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -6890,7 +6890,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -6964,7 +6964,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -7082,7 +7082,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -7200,7 +7200,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -7329,7 +7329,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -7475,7 +7475,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -7535,7 +7535,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -7644,7 +7644,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -7784,7 +7784,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -7863,7 +7863,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -7994,7 +7994,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -8054,7 +8054,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -8220,7 +8220,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -8336,7 +8336,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -8447,7 +8447,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -8510,7 +8510,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -8624,7 +8624,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -8755,7 +8755,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -8838,7 +8838,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -8896,7 +8896,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -9010,7 +9010,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -9152,7 +9152,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -9305,7 +9305,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -9388,7 +9388,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -9448,7 +9448,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -9512,7 +9512,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -9576,7 +9576,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -9718,7 +9718,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -9860,7 +9860,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -9927,7 +9927,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -9962,7 +9962,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -10093,7 +10093,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -10145,7 +10145,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -10276,7 +10276,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -10325,7 +10325,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -10417,7 +10417,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -10491,7 +10491,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -10602,7 +10602,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -10676,7 +10676,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -10818,7 +10818,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -10881,7 +10881,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -10936,7 +10936,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -10991,7 +10991,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -11039,7 +11039,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -11110,7 +11110,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -11173,7 +11173,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -11237,7 +11237,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -11327,7 +11327,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -11361,7 +11361,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -11416,7 +11416,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -11475,7 +11475,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -11570,7 +11570,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -11686,7 +11686,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -11774,7 +11774,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -11851,7 +11851,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -11921,7 +11921,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -11973,7 +11973,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -12029,7 +12029,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -12150,7 +12150,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -12400,7 +12400,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -12432,7 +12432,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -12484,7 +12484,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -12628,7 +12628,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -12684,7 +12684,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -12792,7 +12792,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -12931,7 +12931,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -12986,7 +12986,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -13053,7 +13053,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -13148,7 +13148,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -13233,7 +13233,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -13288,7 +13288,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -13406,7 +13406,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -13465,7 +13465,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -13547,7 +13547,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -13603,7 +13603,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -13641,7 +13641,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -13679,7 +13679,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -13755,7 +13755,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -13814,7 +13814,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -13866,7 +13866,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -13925,7 +13925,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -14071,7 +14071,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -14131,7 +14131,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -14214,7 +14214,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -14354,7 +14354,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -14440,7 +14440,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -14517,7 +14517,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -14674,7 +14674,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -14735,7 +14735,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -14877,7 +14877,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -15019,7 +15019,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -15074,7 +15074,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -15167,7 +15167,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -15202,7 +15202,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -15348,7 +15348,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -15408,7 +15408,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -15517,7 +15517,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -15657,7 +15657,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -15803,7 +15803,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -15851,7 +15851,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -15922,7 +15922,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -15985,7 +15985,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -16049,7 +16049,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -16170,7 +16170,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -16219,7 +16219,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -16311,7 +16311,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -16457,7 +16457,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -16517,7 +16517,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -16626,7 +16626,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -16766,7 +16766,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -16845,7 +16845,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -16961,7 +16961,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -17072,7 +17072,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -17136,7 +17136,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -17200,7 +17200,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -17342,7 +17342,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -17409,7 +17409,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -17445,7 +17445,7 @@ "deprecated": true, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -17576,7 +17576,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -17628,7 +17628,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -17759,7 +17759,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -17833,7 +17833,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -17944,7 +17944,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -18018,7 +18018,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -18160,7 +18160,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -18223,7 +18223,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -18278,7 +18278,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -18333,7 +18333,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -18381,7 +18381,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -18452,7 +18452,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -18515,7 +18515,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -18579,7 +18579,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -18628,7 +18628,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -18683,7 +18683,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -18801,7 +18801,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -18850,7 +18850,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -18959,7 +18959,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -19099,7 +19099,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -19154,7 +19154,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -19203,7 +19203,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -19262,7 +19262,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -19408,7 +19408,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -19468,7 +19468,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -19551,7 +19551,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -19691,7 +19691,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -19768,7 +19768,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -19894,7 +19894,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -19987,7 +19987,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -20022,7 +20022,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -20077,7 +20077,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -20197,7 +20197,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -20246,7 +20246,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -20316,7 +20316,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -20462,7 +20462,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -20522,7 +20522,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -20631,7 +20631,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -20771,7 +20771,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -20835,7 +20835,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -20899,7 +20899,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -21041,7 +21041,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -21108,7 +21108,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -21143,7 +21143,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -21274,7 +21274,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -21348,7 +21348,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -21383,7 +21383,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -21418,7 +21418,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -21470,7 +21470,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -21531,7 +21531,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -21641,7 +21641,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -21676,7 +21676,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -21731,7 +21731,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -21875,7 +21875,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -21935,7 +21935,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -22018,7 +22018,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -22132,7 +22132,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -22193,7 +22193,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -22248,7 +22248,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -22296,7 +22296,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -22442,7 +22442,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -22501,7 +22501,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -22609,7 +22609,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -22748,7 +22748,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -22904,7 +22904,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -23050,7 +23050,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -23109,7 +23109,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -23217,7 +23217,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -23272,7 +23272,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -23331,7 +23331,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -23378,7 +23378,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -23440,7 +23440,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -23495,7 +23495,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -23551,7 +23551,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -23586,7 +23586,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -23663,7 +23663,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -23725,7 +23725,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -23758,7 +23758,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -23790,7 +23790,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -23823,7 +23823,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -23899,7 +23899,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -23963,7 +23963,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -24020,7 +24020,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -24055,7 +24055,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -24110,7 +24110,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -24159,7 +24159,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -24214,7 +24214,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -24274,7 +24274,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -24352,7 +24352,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -24400,7 +24400,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -24546,7 +24546,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -24605,7 +24605,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -24713,7 +24713,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -24852,7 +24852,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -25008,7 +25008,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -25154,7 +25154,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -25213,7 +25213,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -25321,7 +25321,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -25368,7 +25368,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -25430,7 +25430,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -25485,7 +25485,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -25537,7 +25537,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -25618,7 +25618,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -25653,7 +25653,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -25758,7 +25758,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -25889,7 +25889,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -26074,7 +26074,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -26130,7 +26130,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -26200,7 +26200,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -26235,7 +26235,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -26283,7 +26283,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -26327,7 +26327,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -26386,7 +26386,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -26438,7 +26438,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -26486,7 +26486,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -26632,7 +26632,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -26691,7 +26691,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -26799,7 +26799,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -26938,7 +26938,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -27094,7 +27094,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -27240,7 +27240,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -27299,7 +27299,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -27407,7 +27407,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -27454,7 +27454,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -27516,7 +27516,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -27571,7 +27571,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -27644,7 +27644,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -27699,7 +27699,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -27734,7 +27734,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -27837,7 +27837,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -27886,7 +27886,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -27945,7 +27945,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -28091,7 +28091,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -28151,7 +28151,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -28260,7 +28260,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -28400,7 +28400,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -28435,7 +28435,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -28525,7 +28525,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -28560,7 +28560,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -28608,7 +28608,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -28671,7 +28671,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -28726,7 +28726,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -28790,7 +28790,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -28895,7 +28895,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -28966,7 +28966,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -29060,7 +29060,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -29092,7 +29092,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -29192,7 +29192,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -29241,7 +29241,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -29364,7 +29364,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -29434,7 +29434,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -29540,7 +29540,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -29586,7 +29586,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -29677,7 +29677,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -29726,7 +29726,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -29831,7 +29831,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -29949,7 +29949,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -30002,7 +30002,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -30062,7 +30062,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -30145,7 +30145,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -30259,7 +30259,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -30384,7 +30384,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -30507,7 +30507,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -30635,7 +30635,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -30684,7 +30684,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -30830,7 +30830,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -30933,7 +30933,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -31000,7 +31000,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -31060,7 +31060,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -31169,7 +31169,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -31309,7 +31309,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -31372,7 +31372,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -31491,7 +31491,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -31551,7 +31551,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -31693,7 +31693,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -31809,7 +31809,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -31852,7 +31852,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -31945,7 +31945,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -32067,7 +32067,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -32178,7 +32178,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -32318,7 +32318,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -32353,7 +32353,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -32385,7 +32385,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -32420,7 +32420,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -32522,7 +32522,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -32657,7 +32657,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -32725,7 +32725,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -32815,7 +32815,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -32905,7 +32905,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -32940,7 +32940,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -32975,7 +32975,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -33035,7 +33035,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -33098,7 +33098,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -33158,7 +33158,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -33289,7 +33289,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -33420,7 +33420,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -33566,7 +33566,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -33820,7 +33820,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -34033,7 +34033,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -34138,7 +34138,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -34187,7 +34187,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -34242,7 +34242,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -34386,7 +34386,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -34446,7 +34446,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -34555,7 +34555,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] }, @@ -34695,7 +34695,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -34759,7 +34759,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -34814,7 +34814,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -34869,7 +34869,7 @@ }, "security": [ { - "Backoffice User": [ ] + "Backoffice-User": [ ] } ] } @@ -47582,7 +47582,7 @@ } }, "securitySchemes": { - "Backoffice User": { + "Backoffice-User": { "type": "oauth2", "description": "Umbraco Authentication", "flows": { From 93d61d03164e911568fc70aa3c441e274af2b827 Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Mon, 21 Jul 2025 13:05:40 +0200 Subject: [PATCH 17/23] Return 404 on delivery API requests for segments that are invalid or not created (#19718) * Return 404 on delivery API requests for segments that are invalid or not created. * Handled case with no segmented properties. * Let the property decide if it has a value or not --------- Co-authored-by: kjac --- .../DeliveryApi/ApiContentBuilder.cs | 9 ++- .../DeliveryApi/ApiContentBuilderBase.cs | 50 +++++++++++-- .../DeliveryApi/ApiContentResponseBuilder.cs | 13 ++-- .../DeliveryApi/ContentBuilderTests.cs | 72 +++++++++++++++++++ .../DeliveryApi/DeliveryApiTests.cs | 9 ++- 5 files changed, 132 insertions(+), 21 deletions(-) diff --git a/src/Umbraco.Core/DeliveryApi/ApiContentBuilder.cs b/src/Umbraco.Core/DeliveryApi/ApiContentBuilder.cs index 64c1029b02..f362344390 100644 --- a/src/Umbraco.Core/DeliveryApi/ApiContentBuilder.cs +++ b/src/Umbraco.Core/DeliveryApi/ApiContentBuilder.cs @@ -7,8 +7,6 @@ namespace Umbraco.Cms.Core.DeliveryApi; public sealed class ApiContentBuilder : ApiContentBuilderBase, IApiContentBuilder { - private readonly IVariationContextAccessor _variationContextAccessor; - [Obsolete("Please use the constructor that takes an IVariationContextAccessor instead. Scheduled for removal in V17.")] public ApiContentBuilder( IApiContentNameProvider apiContentNameProvider, @@ -27,9 +25,10 @@ public sealed class ApiContentBuilder : ApiContentBuilderBase, IApi IApiContentRouteBuilder apiContentRouteBuilder, IOutputExpansionStrategyAccessor outputExpansionStrategyAccessor, IVariationContextAccessor variationContextAccessor) - : base(apiContentNameProvider, apiContentRouteBuilder, outputExpansionStrategyAccessor) - => _variationContextAccessor = variationContextAccessor; + : base(apiContentNameProvider, apiContentRouteBuilder, outputExpansionStrategyAccessor, variationContextAccessor) + { + } protected override IApiContent Create(IPublishedContent content, string name, IApiContentRoute route, IDictionary properties) - => new ApiContent(content.Key, name, content.ContentType.Alias, content.CreateDate, content.CultureDate(_variationContextAccessor), route, properties); + => new ApiContent(content.Key, name, content.ContentType.Alias, content.CreateDate, content.CultureDate(VariationContextAccessor), route, properties); } diff --git a/src/Umbraco.Core/DeliveryApi/ApiContentBuilderBase.cs b/src/Umbraco.Core/DeliveryApi/ApiContentBuilderBase.cs index 8ffcd6d849..209ce4e33e 100644 --- a/src/Umbraco.Core/DeliveryApi/ApiContentBuilderBase.cs +++ b/src/Umbraco.Core/DeliveryApi/ApiContentBuilderBase.cs @@ -1,5 +1,8 @@ -using Umbraco.Cms.Core.Models.DeliveryApi; +using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.DependencyInjection; +using Umbraco.Cms.Core.Models.DeliveryApi; using Umbraco.Cms.Core.Models.PublishedContent; +using Umbraco.Extensions; namespace Umbraco.Cms.Core.DeliveryApi; @@ -7,26 +10,63 @@ public abstract class ApiContentBuilderBase where T : IApiContent { private readonly IApiContentNameProvider _apiContentNameProvider; - private readonly IApiContentRouteBuilder _apiContentRouteBuilder; private readonly IOutputExpansionStrategyAccessor _outputExpansionStrategyAccessor; - protected ApiContentBuilderBase(IApiContentNameProvider apiContentNameProvider, IApiContentRouteBuilder apiContentRouteBuilder, IOutputExpansionStrategyAccessor outputExpansionStrategyAccessor) + [Obsolete("Please use the constructor that takes all parameters. Scheduled for removal in Umbraco 17.")] + protected ApiContentBuilderBase( + IApiContentNameProvider apiContentNameProvider, + IApiContentRouteBuilder apiContentRouteBuilder, + IOutputExpansionStrategyAccessor outputExpansionStrategyAccessor) + : this( + apiContentNameProvider, + apiContentRouteBuilder, + outputExpansionStrategyAccessor, + StaticServiceProvider.Instance.GetRequiredService()) + { + } + + protected ApiContentBuilderBase( + IApiContentNameProvider apiContentNameProvider, + IApiContentRouteBuilder apiContentRouteBuilder, + IOutputExpansionStrategyAccessor outputExpansionStrategyAccessor, + IVariationContextAccessor variationContextAccessor) { _apiContentNameProvider = apiContentNameProvider; - _apiContentRouteBuilder = apiContentRouteBuilder; + ApiContentRouteBuilder = apiContentRouteBuilder; _outputExpansionStrategyAccessor = outputExpansionStrategyAccessor; + VariationContextAccessor = variationContextAccessor; } + protected IApiContentRouteBuilder ApiContentRouteBuilder { get; } + + protected IVariationContextAccessor VariationContextAccessor { get; } + protected abstract T Create(IPublishedContent content, string name, IApiContentRoute route, IDictionary properties); public virtual T? Build(IPublishedContent content) { - IApiContentRoute? route = _apiContentRouteBuilder.Build(content); + IApiContentRoute? route = ApiContentRouteBuilder.Build(content); if (route is null) { return default; } + // If a segment is requested and no segmented properties have any values, we consider the segment as not created or non-existing and return null. + // This aligns the behaviour of the API when it comes to "Accept-Segment" and "Accept-Language" requests, so 404 is returned for both when + // the segment or language is not created or does not exist. + // It also aligns with what we show in the backoffice for whether a segment is "Published" or "Not created". + // Requested languages that aren't created or don't exist will already have exited early in the route builder. + var segment = VariationContextAccessor.VariationContext?.Segment; + if (segment.IsNullOrWhiteSpace() is false + && content.ContentType.VariesBySegment() + && content + .Properties + .Where(p => p.PropertyType.VariesBySegment()) + .All(p => p.HasValue(VariationContextAccessor.VariationContext?.Culture, segment) is false)) + { + return default; + } + IDictionary properties = _outputExpansionStrategyAccessor.TryGetValue(out IOutputExpansionStrategy? outputExpansionStrategy) ? outputExpansionStrategy.MapContentProperties(content) diff --git a/src/Umbraco.Core/DeliveryApi/ApiContentResponseBuilder.cs b/src/Umbraco.Core/DeliveryApi/ApiContentResponseBuilder.cs index 833d7f2016..17d6271cb5 100644 --- a/src/Umbraco.Core/DeliveryApi/ApiContentResponseBuilder.cs +++ b/src/Umbraco.Core/DeliveryApi/ApiContentResponseBuilder.cs @@ -1,4 +1,4 @@ -using Umbraco.Cms.Core.DependencyInjection; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Models.DeliveryApi; using Umbraco.Cms.Core.Models.PublishedContent; using Umbraco.Extensions; @@ -7,9 +7,6 @@ namespace Umbraco.Cms.Core.DeliveryApi; public class ApiContentResponseBuilder : ApiContentBuilderBase, IApiContentResponseBuilder { - private readonly IApiContentRouteBuilder _apiContentRouteBuilder; - private readonly IVariationContextAccessor _variationContextAccessor; - [Obsolete("Please use the constructor that takes an IVariationContextAccessor instead. Scheduled for removal in V17.")] public ApiContentResponseBuilder( IApiContentNameProvider apiContentNameProvider, @@ -28,16 +25,14 @@ public class ApiContentResponseBuilder : ApiContentBuilderBase properties) { IDictionary cultures = GetCultures(content); - return new ApiContentResponse(content.Key, name, content.ContentType.Alias, content.CreateDate, content.CultureDate(_variationContextAccessor), route, properties, cultures); + return new ApiContentResponse(content.Key, name, content.ContentType.Alias, content.CreateDate, content.CultureDate(VariationContextAccessor), route, properties, cultures); } protected virtual IDictionary GetCultures(IPublishedContent content) @@ -52,7 +47,7 @@ public class ApiContentResponseBuilder : ApiContentBuilderBase(); + + var sharedPropertyValueConverter = new Mock(); + sharedPropertyValueConverter.Setup(p => p.IsValue(It.IsAny(), It.IsAny())).Returns(sharedValue is not null); + sharedPropertyValueConverter.Setup(p => p.ConvertIntermediateToDeliveryApiObject( + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny())).Returns(sharedValue); + sharedPropertyValueConverter.Setup(p => p.IsConverter(It.IsAny())).Returns(true); + sharedPropertyValueConverter.Setup(p => p.GetPropertyCacheLevel(It.IsAny())).Returns(PropertyCacheLevel.None); + sharedPropertyValueConverter.Setup(p => p.GetDeliveryApiPropertyCacheLevel(It.IsAny())).Returns(PropertyCacheLevel.None); + + var sharedPropertyType = SetupPublishedPropertyType(sharedPropertyValueConverter.Object, "sharedMessage", "Umbraco.Textstring"); + var sharedProperty = new PublishedElementPropertyBase(sharedPropertyType, content.Object, false, PropertyCacheLevel.None, new VariationContext(), Mock.Of()); + + var segmentedPropertyValueConverter = new Mock(); + segmentedPropertyValueConverter.Setup(p => p.IsValue(It.IsAny(), It.IsAny())).Returns(segmentedValue is not null); + segmentedPropertyValueConverter.Setup(p => p.ConvertIntermediateToDeliveryApiObject( + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny())).Returns(segmentedValue); + segmentedPropertyValueConverter.Setup(p => p.IsConverter(It.IsAny())).Returns(true); + segmentedPropertyValueConverter.Setup(p => p.GetPropertyCacheLevel(It.IsAny())).Returns(PropertyCacheLevel.None); + segmentedPropertyValueConverter.Setup(p => p.GetDeliveryApiPropertyCacheLevel(It.IsAny())).Returns(PropertyCacheLevel.None); + + var segmentedPropertyType = SetupPublishedPropertyType(segmentedPropertyValueConverter.Object, "segmentedMessage", "Umbraco.Textstring", contentVariation: ContentVariation.Segment); + var segmentedProperty = new PublishedElementPropertyBase(segmentedPropertyType, content.Object, false, PropertyCacheLevel.None, new VariationContext(), Mock.Of()); + + var contentType = new Mock(); + contentType.SetupGet(c => c.Alias).Returns("thePageType"); + contentType.SetupGet(c => c.ItemType).Returns(PublishedItemType.Content); + contentType.SetupGet(c => c.Variations).Returns(ContentVariation.Segment); + + var key = Guid.NewGuid(); + var urlSegment = "url-segment"; + var name = "The page"; + ConfigurePublishedContentMock(content, key, name, urlSegment, contentType.Object, [sharedProperty, segmentedProperty]); + + var routeBuilderMock = new Mock(); + routeBuilderMock + .Setup(r => r.Build(content.Object, It.IsAny())) + .Returns(new ApiContentRoute(content.Object.UrlSegment!, new ApiContentStartItem(Guid.NewGuid(), "/"))); + + var variationContextAccessorMock = new Mock(); + variationContextAccessorMock.Setup(v => v.VariationContext).Returns(new VariationContext(segment: "missingSegment")); + + var builder = new ApiContentBuilder(new ApiContentNameProvider(), routeBuilderMock.Object, CreateOutputExpansionStrategyAccessor(), variationContextAccessorMock.Object); + var result = builder.Build(content.Object); + + if (expectNull) + { + Assert.IsNull(result); + } + else + { + Assert.IsNotNull(result); + } + } } diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/DeliveryApiTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/DeliveryApiTests.cs index 3c5b6d8ca0..c165666cc3 100644 --- a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/DeliveryApiTests.cs +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/DeliveryApi/DeliveryApiTests.cs @@ -73,7 +73,12 @@ public class DeliveryApiTests PublishStatusQueryService = publishStatusQueryService.Object; } - protected IPublishedPropertyType SetupPublishedPropertyType(IPropertyValueConverter valueConverter, string propertyTypeAlias, string editorAlias, object? dataTypeConfiguration = null) + protected IPublishedPropertyType SetupPublishedPropertyType( + IPropertyValueConverter valueConverter, + string propertyTypeAlias, + string editorAlias, + object? dataTypeConfiguration = null, + ContentVariation contentVariation = ContentVariation.Nothing) { var mockPublishedContentTypeFactory = new Mock(); mockPublishedContentTypeFactory.Setup(x => x.GetDataType(It.IsAny())) @@ -83,7 +88,7 @@ public class DeliveryApiTests propertyTypeAlias, 123, true, - ContentVariation.Nothing, + contentVariation, new PropertyValueConverterCollection(() => new[] { valueConverter }), Mock.Of(), mockPublishedContentTypeFactory.Object); From a0406b1406377addf18b67adcf2d8df778bef9da Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Mon, 21 Jul 2025 13:19:42 +0200 Subject: [PATCH 18/23] Add defensive coding to the member application initializer (16) (#19764) * Add defensive coding to the member application initializer (#19760) * Moved _isInitialized to after the initialization --------- Co-authored-by: kjac --- ...izeMemberApplicationNotificationHandler.cs | 42 +++++++++++++++---- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/src/Umbraco.Cms.Api.Delivery/Handlers/InitializeMemberApplicationNotificationHandler.cs b/src/Umbraco.Cms.Api.Delivery/Handlers/InitializeMemberApplicationNotificationHandler.cs index fdd98e1702..cf2ff26337 100644 --- a/src/Umbraco.Cms.Api.Delivery/Handlers/InitializeMemberApplicationNotificationHandler.cs +++ b/src/Umbraco.Cms.Api.Delivery/Handlers/InitializeMemberApplicationNotificationHandler.cs @@ -7,6 +7,7 @@ using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.Notifications; using Umbraco.Cms.Core.Security; using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Sync; using Umbraco.Cms.Infrastructure.Security; namespace Umbraco.Cms.Api.Delivery.Handlers; @@ -18,18 +19,24 @@ internal sealed class InitializeMemberApplicationNotificationHandler : INotifica private readonly DeliveryApiSettings _deliveryApiSettings; private readonly IServiceScopeFactory _serviceScopeFactory; private readonly IMemberClientCredentialsManager _memberClientCredentialsManager; + private readonly IServerRoleAccessor _serverRoleAccessor; + + private static readonly SemaphoreSlim _locker = new(1); + private static bool _isInitialized = false; public InitializeMemberApplicationNotificationHandler( IRuntimeState runtimeState, IOptions deliveryApiSettings, ILogger logger, IServiceScopeFactory serviceScopeFactory, - IMemberClientCredentialsManager memberClientCredentialsManager) + IMemberClientCredentialsManager memberClientCredentialsManager, + IServerRoleAccessor serverRoleAccessor) { _runtimeState = runtimeState; _logger = logger; _serviceScopeFactory = serviceScopeFactory; _memberClientCredentialsManager = memberClientCredentialsManager; + _serverRoleAccessor = serverRoleAccessor; _deliveryApiSettings = deliveryApiSettings.Value; } @@ -40,13 +47,34 @@ internal sealed class InitializeMemberApplicationNotificationHandler : INotifica return; } - // we cannot inject the IMemberApplicationManager because it ultimately takes a dependency on the DbContext ... and during - // install that is not allowed (no connection string means no DbContext) - using IServiceScope scope = _serviceScopeFactory.CreateScope(); - IMemberApplicationManager memberApplicationManager = scope.ServiceProvider.GetRequiredService(); + if (_serverRoleAccessor.CurrentServerRole is ServerRole.Subscriber) + { + // subscriber instances should not alter the member application + return; + } - await HandleMemberApplication(memberApplicationManager, cancellationToken); - await HandleMemberClientCredentialsApplication(memberApplicationManager, cancellationToken); + try + { + await _locker.WaitAsync(cancellationToken); + if (_isInitialized) + { + return; + } + + // we cannot inject the IMemberApplicationManager because it ultimately takes a dependency on the DbContext ... and during + // install that is not allowed (no connection string means no DbContext) + using IServiceScope scope = _serviceScopeFactory.CreateScope(); + IMemberApplicationManager memberApplicationManager = scope.ServiceProvider.GetRequiredService(); + + await HandleMemberApplication(memberApplicationManager, cancellationToken); + await HandleMemberClientCredentialsApplication(memberApplicationManager, cancellationToken); + + _isInitialized = true; + } + finally + { + _locker.Release(); + } } private async Task HandleMemberApplication(IMemberApplicationManager memberApplicationManager, CancellationToken cancellationToken) From 8cc6508b225eb571951f82f094938b12623c818f Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Tue, 22 Jul 2025 09:50:05 +0200 Subject: [PATCH 19/23] Retrieve only user external logins when invalidate following removal of backoffice external user login (#19766) * Retrieve only user external logins when invalidate following removal of backoffice external user login. * Improved variable name. --- .../Repositories/Implement/UserRepository.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/UserRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/UserRepository.cs index c56c40e02e..88f9540a4f 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/UserRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/UserRepository.cs @@ -1264,13 +1264,14 @@ SELECT 4 AS [Key], COUNT(id) AS [Value] FROM umbracoUser WHERE userDisabled = 0 /// public void InvalidateSessionsForRemovedProviders(IEnumerable currentLoginProviders) { - // Get all the user or member keys associated with the removed providers. + // Get all the user keys associated with the removed providers. Sql idsQuery = SqlContext.Sql() .Select(x => x.UserOrMemberKey) .From() + .Where(x => !x.LoginProvider.StartsWith(Constants.Security.MemberExternalAuthenticationTypePrefix)) // Only invalidate sessions relating to backoffice users, not members. .WhereNotIn(x => x.LoginProvider, currentLoginProviders); - List userAndMemberKeysAssociatedWithRemovedProviders = Database.Fetch(idsQuery); - if (userAndMemberKeysAssociatedWithRemovedProviders.Count == 0) + List userKeysAssociatedWithRemovedProviders = Database.Fetch(idsQuery); + if (userKeysAssociatedWithRemovedProviders.Count == 0) { return; } @@ -1278,12 +1279,12 @@ SELECT 4 AS [Key], COUNT(id) AS [Value] FROM umbracoUser WHERE userDisabled = 0 // Invalidate the security stamps on the users associated with the removed providers. Sql updateSecurityStampsQuery = Sql() .Update(u => u.Set(x => x.SecurityStampToken, "0".PadLeft(32, '0'))) - .WhereIn(x => x.Key, userAndMemberKeysAssociatedWithRemovedProviders); + .WhereIn(x => x.Key, userKeysAssociatedWithRemovedProviders); Database.Execute(updateSecurityStampsQuery); // Delete the OpenIddict tokens for the users associated with the removed providers. // The following is safe from SQL injection as we are dealing with GUIDs, not strings. - var userKeysForInClause = string.Join("','", userAndMemberKeysAssociatedWithRemovedProviders.Select(x => x.ToString())); + var userKeysForInClause = string.Join("','", userKeysAssociatedWithRemovedProviders.Select(x => x.ToString())); Database.Execute("DELETE FROM umbracoOpenIddictTokens WHERE Subject IN ('" + userKeysForInClause + "')"); } From df9b387175b6c2ffae12a7fb869b7313eec3bcf5 Mon Sep 17 00:00:00 2001 From: Lee Kelleher Date: Tue, 22 Jul 2025 09:16:38 +0100 Subject: [PATCH 20/23] Repository Details Manager: Prevent making requests for empty arrays (#19731) * fix: Prevent Repository Details Manager making requests for empty arrays Fixes #19604 * Reworked to pass the `uniques` through to the `#requestNewDetails()` method The unique values are included as a closure, persisting after the `#init` promise is resolved. Rather than call `getUniques()` to get an async'd value. * Updated with Copilot suggestions https://github.com/umbraco/Umbraco-CMS/pull/19731#discussion_r2221512463 --- .../core/repository/repository-details.manager.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/core/repository/repository-details.manager.ts b/src/Umbraco.Web.UI.Client/src/packages/core/repository/repository-details.manager.ts index 7d31d0ad83..b2d170c902 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/core/repository/repository-details.manager.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/core/repository/repository-details.manager.ts @@ -88,7 +88,7 @@ export class UmbRepositoryDetailsManager this.removeUmbControllerByAlias('observeEntry_' + entry); }); - this.#requestNewDetails(); + this.#requestNewDetails(uniques); }, null, ); @@ -181,13 +181,13 @@ export class UmbRepositoryDetailsManager return this.#entries.asObservablePart((items) => items.find((item) => item.unique === unique)); } - async #requestNewDetails(): Promise { + async #requestNewDetails(uniques?: Array): Promise { + if (!uniques?.length) return; + await this.#init; if (!this.repository) throw new Error('Repository is not initialized'); - const requestedUniques = this.getUniques(); - - const newRequestedUniques = requestedUniques.filter((unique) => { + const newRequestedUniques = uniques.filter((unique) => { const item = this.#statuses.getValue().find((status) => status.unique === unique); return !item; }); From d7a32a31a1baa3a56d5414546ba627e379d5a091 Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Tue, 22 Jul 2025 12:46:04 +0200 Subject: [PATCH 21/23] Reloads the template tree when creating a document type with a template (#19769) * Reloads the template tree when creating a document type with a template. * Housekeeping: separating/sorting import types --------- Co-authored-by: leekelleher --- .../document-type-workspace.context.ts | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/document-type/document-type-workspace.context.ts b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/document-type/document-type-workspace.context.ts index f91f2c55c9..8c9a66f575 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/document-type/document-type-workspace.context.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/documents/document-types/workspace/document-type/document-type-workspace.context.ts @@ -3,25 +3,27 @@ import { UMB_CREATE_DOCUMENT_TYPE_WORKSPACE_PRESET_ELEMENT, UMB_CREATE_DOCUMENT_TYPE_WORKSPACE_PRESET_TEMPLATE, UMB_EDIT_DOCUMENT_TYPE_WORKSPACE_PATH_PATTERN, - type UmbCreateDocumentTypeWorkspacePresetType, } from '../../paths.js'; +import type { UmbCreateDocumentTypeWorkspacePresetType } from '../../paths.js'; import type { UmbDocumentTypeDetailModel } from '../../types.js'; import { UMB_DOCUMENT_TYPE_ENTITY_TYPE, UMB_DOCUMENT_TYPE_DETAIL_REPOSITORY_ALIAS } from '../../constants.js'; -import { UmbDocumentTypeWorkspaceEditorElement } from './document-type-workspace-editor.element.js'; import { UMB_DOCUMENT_TYPE_WORKSPACE_ALIAS } from './constants.js'; +import { UmbDocumentTypeWorkspaceEditorElement } from './document-type-workspace-editor.element.js'; +import { CompositionTypeModel } from '@umbraco-cms/backoffice/external/backend-api'; import { UmbContentTypeWorkspaceContextBase } from '@umbraco-cms/backoffice/content-type'; +import { UmbRequestReloadChildrenOfEntityEvent } from '@umbraco-cms/backoffice/entity-action'; import { UmbWorkspaceIsNewRedirectController, UmbWorkspaceIsNewRedirectControllerAlias, } from '@umbraco-cms/backoffice/workspace'; +import { UMB_ACTION_EVENT_CONTEXT } from '@umbraco-cms/backoffice/action'; +import { UMB_TEMPLATE_ROOT_ENTITY_TYPE, UmbTemplateDetailRepository } from '@umbraco-cms/backoffice/template'; import type { UmbContentTypeSortModel, UmbContentTypeWorkspaceContext } from '@umbraco-cms/backoffice/content-type'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; +import type { UmbEntityModel } from '@umbraco-cms/backoffice/entity'; +import type { UmbPathPatternTypeAsEncodedParamsType } from '@umbraco-cms/backoffice/router'; import type { UmbReferenceByUnique } from '@umbraco-cms/backoffice/models'; import type { UmbRoutableWorkspaceContext } from '@umbraco-cms/backoffice/workspace'; -import type { UmbPathPatternTypeAsEncodedParamsType } from '@umbraco-cms/backoffice/router'; -import type { UmbEntityModel } from '@umbraco-cms/backoffice/entity'; -import { UmbTemplateDetailRepository } from '@umbraco-cms/backoffice/template'; -import { CompositionTypeModel } from '@umbraco-cms/backoffice/external/backend-api'; type DetailModelType = UmbDocumentTypeDetailModel; export class UmbDocumentTypeWorkspaceContext @@ -189,6 +191,16 @@ export class UmbDocumentTypeWorkspaceContext const { data: template } = await this.#templateRepository.create(templateScaffold, null); if (!template) throw new Error('Could not create template'); + const eventContext = await this.getContext(UMB_ACTION_EVENT_CONTEXT); + if (!eventContext) { + throw new Error('Could not get the action event context'); + } + const event = new UmbRequestReloadChildrenOfEntityEvent({ + entityType: UMB_TEMPLATE_ROOT_ENTITY_TYPE, + unique: null, + }); + eventContext.dispatchEvent(event); + const templateEntity = { id: template.unique }; const allowedTemplates = this.getAllowedTemplateIds() ?? []; this.setAllowedTemplateIds([templateEntity, ...allowedTemplates]); From ca1476f7c78fedc630ef45dbc11bbb877650a666 Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Tue, 22 Jul 2025 14:22:11 +0200 Subject: [PATCH 22/23] Fires the updated event when content types are updated (#19768) * Fires the updated event when content types are updated. * Housekeeping: separating/sorting import types --------- Co-authored-by: leekelleher --- .../content-type-workspace-context-base.ts | 51 ++++++++++++------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/packages/content/content-type/workspace/content-type-workspace-context-base.ts b/src/Umbraco.Web.UI.Client/src/packages/content/content-type/workspace/content-type-workspace-context-base.ts index 068eaed33c..bbc93cf00f 100644 --- a/src/Umbraco.Web.UI.Client/src/packages/content/content-type/workspace/content-type-workspace-context-base.ts +++ b/src/Umbraco.Web.UI.Client/src/packages/content/content-type/workspace/content-type-workspace-context-base.ts @@ -1,26 +1,27 @@ -import type { UmbContentTypeCompositionModel, UmbContentTypeDetailModel, UmbContentTypeSortModel } from '../types.js'; import { UmbContentTypeStructureManager } from '../structure/index.js'; +import type { UmbContentTypeCompositionModel, UmbContentTypeDetailModel, UmbContentTypeSortModel } from '../types.js'; import type { UmbContentTypeWorkspaceContext } from './content-type-workspace-context.interface.js'; +import { UmbEntityDetailWorkspaceContextBase } from '@umbraco-cms/backoffice/workspace'; +import { + UmbEntityUpdatedEvent, + UmbRequestReloadChildrenOfEntityEvent, + UmbRequestReloadStructureForEntityEvent, +} from '@umbraco-cms/backoffice/entity-action'; +import { UMB_ACTION_EVENT_CONTEXT } from '@umbraco-cms/backoffice/action'; +import type { Observable } from '@umbraco-cms/backoffice/observable-api'; import type { UmbControllerHost } from '@umbraco-cms/backoffice/controller-api'; +import type { UmbEntityModel } from '@umbraco-cms/backoffice/entity'; import type { UmbDetailRepository, UmbRepositoryResponse, UmbRepositoryResponseWithAsObservable, } from '@umbraco-cms/backoffice/repository'; -import { - UmbEntityDetailWorkspaceContextBase, - type UmbEntityDetailWorkspaceContextArgs, - type UmbEntityDetailWorkspaceContextCreateArgs, - type UmbRoutableWorkspaceContext, +import type { + UmbEntityDetailWorkspaceContextArgs, + UmbEntityDetailWorkspaceContextCreateArgs, + UmbRoutableWorkspaceContext, } from '@umbraco-cms/backoffice/workspace'; import type { UmbReferenceByUnique } from '@umbraco-cms/backoffice/models'; -import type { Observable } from '@umbraco-cms/backoffice/observable-api'; -import { UMB_ACTION_EVENT_CONTEXT } from '@umbraco-cms/backoffice/action'; -import { - UmbRequestReloadChildrenOfEntityEvent, - UmbRequestReloadStructureForEntityEvent, -} from '@umbraco-cms/backoffice/entity-action'; -import type { UmbEntityModel } from '@umbraco-cms/backoffice/entity'; // eslint-disable-next-line @typescript-eslint/no-empty-object-type export interface UmbContentTypeWorkspaceContextArgs extends UmbEntityDetailWorkspaceContextArgs {} @@ -183,16 +184,28 @@ export abstract class UmbContentTypeWorkspaceContextBase< this._data.setPersisted(this.structure.getOwnerContentType()); - const actionEventContext = await this.getContext(UMB_ACTION_EVENT_CONTEXT); - if (!actionEventContext) { + const eventContext = await this.getContext(UMB_ACTION_EVENT_CONTEXT); + if (!eventContext) { throw new Error('Could not get the action event context'); } - const event = new UmbRequestReloadStructureForEntityEvent({ - unique: this.getUnique()!, - entityType: this.getEntityType(), + + const unique = this.getUnique()!; + const entityType = this.getEntityType(); + + const reloadStructureEvent = new UmbRequestReloadStructureForEntityEvent({ + unique, + entityType, }); - actionEventContext.dispatchEvent(event); + eventContext.dispatchEvent(reloadStructureEvent); + + const updatedEvent = new UmbEntityUpdatedEvent({ + unique, + entityType, + eventUnique: this._workspaceEventUnique, + }); + + eventContext.dispatchEvent(updatedEvent); } catch (error) { console.error(error); } From b722c0d72ddd92c0912aa059d960dab8947bae2c Mon Sep 17 00:00:00 2001 From: Laura Neto <12862535+lauraneto@users.noreply.github.com> Date: Tue, 22 Jul 2025 15:26:04 +0200 Subject: [PATCH 23/23] Abstract submit and poll operations (#19688) * Started implementing new LongRunningOperationService and adjusting tasks to use this service This service will manage operations that require status to be synced between servers (load balanced setup). * Missing migration to add new lock. Other simplifications. * Add job to cleanup the LongRunningOperations entries * Add new DatabaseCacheRebuilder.RebuildAsync method This is both async and returns an attempt, which will fail if a rebuild operation is already running. * Missing LongRunningOperation database table creation on clean install * Store expire date in the long running operation. Better handling of non-background operations. Storing an expiration date allows setting different expiration times depending on the type of operation, and whether it is running in the background or not. * Added integration tests for LongRunningOperationRepository * Added unit tests for LongRunningOperationService * Add type as a parameter to more repository calls. Distinguish between expiration and deletion in `LongRunningOperationRepository.CleanOperations`. * Fix failing unit test * Fixed `PerformPublishBranchAsync` result not being deserialized correctly * Remove unnecessary DatabaseCacheRebuildResult value * Add status to `LongRunningOperationService.GetResult` attempt to inform on why a result could not be retrieved * General improvements * Missing rename * Improve the handling of long running operations that are not in background and stale operations * Fix failing unit tests * Fixed small mismatch between interface and implementation * Use a fire and forget task instead of the background queue * Apply suggestions from code review Co-authored-by: Andy Butland * Make sure exceptions are caught when running in the background * Alignment with other repositories (async + pagination) * Additional fixes * Add Async suffix to service methods * Missing adjustment * Moved hardcoded settings to IOptions * Fix issue in SQL Server where 0 is not accepted as requested number of rows * Fix issue in SQL Server where query provided to count cannot contain orderby * Additional SQL Server fixes --------- Co-authored-by: Andy Butland --- ...ublishDocumentWithDescendantsController.cs | 11 +- ...DocumentWithDescendantsResultController.cs | 24 +- .../RebuildPublishedCacheController.cs | 13 +- .../RebuildPublishedCacheStatusController.cs | 13 +- src/Umbraco.Core/AttemptOfTResultTStatus.cs | 3 + .../LongRunningOperationsCleanupSettings.cs | 27 ++ .../Models/LongRunningOperationsSettings.cs | 33 ++ src/Umbraco.Core/Constants-Configuration.cs | 1 + .../UmbracoBuilder.Configuration.cs | 1 + .../DependencyInjection/UmbracoBuilder.cs | 2 + .../ContentPublishingBranchInternalResult.cs | 14 + .../Models/DatabaseCacheRebuildResult.cs | 17 + .../Models/LongRunningOperation.cs | 22 + .../Models/LongRunningOperationOfTResult.cs | 13 + .../Models/LongRunningOperationStatus.cs | 32 ++ .../Persistence/Constants-DatabaseSchema.cs | 2 + .../Persistence/Constants-Locks.cs | 5 + .../ILongRunningOperationRepository.cs | 74 ++++ .../PublishedCache/IDatabaseCacheRebuilder.cs | 33 +- .../Services/ContentPublishingService.cs | 217 ++++----- .../Services/ILongRunningOperationService.cs | 72 +++ .../Services/LongRunningOperationService.cs | 250 +++++++++++ .../LongRunningOperationEnqueueStatus.cs | 17 + .../LongRunningOperationResultStatus.cs | 27 ++ .../Jobs/LongRunningOperationsCleanupJob.cs | 58 +++ .../UmbracoBuilder.Repositories.cs | 1 + .../HostedServices/QueuedHostedService.cs | 14 +- .../Migrations/Install/DatabaseDataCreator.cs | 1 + .../Install/DatabaseSchemaCreator.cs | 1 + .../Migrations/MigrationPlanExecutor.cs | 6 +- .../Migrations/Upgrade/UmbracoPlan.cs | 3 + .../V_16_2_0/AddLongRunningOperations.cs | 35 ++ .../Dtos/LongRunningOperationDto.cs | 45 ++ .../Querying/ExpressionVisitorBase.cs | 5 + .../LongRunningOperationRepository.cs | 186 ++++++++ .../Persistence/UmbracoDatabaseExtensions.cs | 45 ++ .../DatabaseCacheRebuilder.cs | 120 ++--- .../HybridCacheStartupNotificationHandler.cs | 8 +- .../Persistence/DatabaseCacheRepository.cs | 1 - .../UmbracoBuilderExtensions.cs | 2 +- .../LongRunningOperationRepositoryTests.cs | 228 ++++++++++ .../LongRunningOperationServiceTests.cs | 417 ++++++++++++++++++ 42 files changed, 1899 insertions(+), 200 deletions(-) create mode 100644 src/Umbraco.Core/Configuration/Models/LongRunningOperationsCleanupSettings.cs create mode 100644 src/Umbraco.Core/Configuration/Models/LongRunningOperationsSettings.cs create mode 100644 src/Umbraco.Core/Models/ContentPublishing/ContentPublishingBranchInternalResult.cs create mode 100644 src/Umbraco.Core/Models/DatabaseCacheRebuildResult.cs create mode 100644 src/Umbraco.Core/Models/LongRunningOperation.cs create mode 100644 src/Umbraco.Core/Models/LongRunningOperationOfTResult.cs create mode 100644 src/Umbraco.Core/Models/LongRunningOperationStatus.cs create mode 100644 src/Umbraco.Core/Persistence/Repositories/ILongRunningOperationRepository.cs create mode 100644 src/Umbraco.Core/Services/ILongRunningOperationService.cs create mode 100644 src/Umbraco.Core/Services/LongRunningOperationService.cs create mode 100644 src/Umbraco.Core/Services/OperationStatus/LongRunningOperationEnqueueStatus.cs create mode 100644 src/Umbraco.Core/Services/OperationStatus/LongRunningOperationResultStatus.cs create mode 100644 src/Umbraco.Infrastructure/BackgroundJobs/Jobs/LongRunningOperationsCleanupJob.cs create mode 100644 src/Umbraco.Infrastructure/Migrations/Upgrade/V_16_2_0/AddLongRunningOperations.cs create mode 100644 src/Umbraco.Infrastructure/Persistence/Dtos/LongRunningOperationDto.cs create mode 100644 src/Umbraco.Infrastructure/Persistence/Repositories/Implement/LongRunningOperationRepository.cs create mode 100644 tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/LongRunningOperationRepositoryTests.cs create mode 100644 tests/Umbraco.Tests.UnitTests/Umbraco.Core/Services/LongRunningOperationServiceTests.cs diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Document/PublishDocumentWithDescendantsController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Document/PublishDocumentWithDescendantsController.cs index f9d9681f07..e39bebd680 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Document/PublishDocumentWithDescendantsController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Document/PublishDocumentWithDescendantsController.cs @@ -58,11 +58,12 @@ public class PublishDocumentWithDescendantsController : DocumentControllerBase true); return attempt.Success && attempt.Result.AcceptedTaskId.HasValue - ? Ok(new PublishWithDescendantsResultModel - { - TaskId = attempt.Result.AcceptedTaskId.Value, - IsComplete = false - }) + ? Ok( + new PublishWithDescendantsResultModel + { + TaskId = attempt.Result.AcceptedTaskId.Value, + IsComplete = false, + }) : DocumentPublishingOperationStatusResult(attempt.Status, failedBranchItems: attempt.Result.FailedItems); } diff --git a/src/Umbraco.Cms.Api.Management/Controllers/Document/PublishDocumentWithDescendantsResultController.cs b/src/Umbraco.Cms.Api.Management/Controllers/Document/PublishDocumentWithDescendantsResultController.cs index 9a499ede1e..7325fc1b4b 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/Document/PublishDocumentWithDescendantsResultController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/Document/PublishDocumentWithDescendantsResultController.cs @@ -49,21 +49,23 @@ public class PublishDocumentWithDescendantsResultController : DocumentController var isPublishing = await _contentPublishingService.IsPublishingBranchAsync(taskId); if (isPublishing) { - return Ok(new PublishWithDescendantsResultModel - { - TaskId = taskId, - IsComplete = false - }); - }; + return Ok( + new PublishWithDescendantsResultModel + { + TaskId = taskId, + IsComplete = false, + }); + } // If completed, get the result and return the status. Attempt attempt = await _contentPublishingService.GetPublishBranchResultAsync(taskId); return attempt.Success - ? Ok(new PublishWithDescendantsResultModel - { - TaskId = taskId, - IsComplete = true - }) + ? Ok( + new PublishWithDescendantsResultModel + { + TaskId = taskId, + IsComplete = true, + }) : DocumentPublishingOperationStatusResult(attempt.Status, failedBranchItems: attempt.Result.FailedItems); } } diff --git a/src/Umbraco.Cms.Api.Management/Controllers/PublishedCache/RebuildPublishedCacheController.cs b/src/Umbraco.Cms.Api.Management/Controllers/PublishedCache/RebuildPublishedCacheController.cs index 8f9cd490eb..f716058fc4 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/PublishedCache/RebuildPublishedCacheController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/PublishedCache/RebuildPublishedCacheController.cs @@ -1,6 +1,8 @@ using Asp.Versioning; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.PublishedCache; namespace Umbraco.Cms.Api.Management.Controllers.PublishedCache; @@ -15,9 +17,10 @@ public class RebuildPublishedCacheController : PublishedCacheControllerBase [HttpPost("rebuild")] [MapToApiVersion("1.0")] [ProducesResponseType(StatusCodes.Status200OK)] - public Task Rebuild(CancellationToken cancellationToken) + public async Task Rebuild(CancellationToken cancellationToken) { - if (_databaseCacheRebuilder.IsRebuilding()) + Attempt attempt = await _databaseCacheRebuilder.RebuildAsync(true); + if (attempt is { Success: false, Result: DatabaseCacheRebuildResult.AlreadyRunning }) { var problemDetails = new ProblemDetails { @@ -26,11 +29,9 @@ public class RebuildPublishedCacheController : PublishedCacheControllerBase Status = StatusCodes.Status400BadRequest, Type = "Error", }; - - return Task.FromResult(Conflict(problemDetails)); + return Conflict(problemDetails); } - _databaseCacheRebuilder.Rebuild(true); - return Task.FromResult(Ok()); + return Ok(); } } diff --git a/src/Umbraco.Cms.Api.Management/Controllers/PublishedCache/RebuildPublishedCacheStatusController.cs b/src/Umbraco.Cms.Api.Management/Controllers/PublishedCache/RebuildPublishedCacheStatusController.cs index 5ecceecd3d..e924116751 100644 --- a/src/Umbraco.Cms.Api.Management/Controllers/PublishedCache/RebuildPublishedCacheStatusController.cs +++ b/src/Umbraco.Cms.Api.Management/Controllers/PublishedCache/RebuildPublishedCacheStatusController.cs @@ -16,12 +16,13 @@ public class RebuildPublishedCacheStatusController : PublishedCacheControllerBas [HttpGet("rebuild/status")] [MapToApiVersion("1.0")] [ProducesResponseType(typeof(RebuildStatusModel), StatusCodes.Status200OK)] - public Task Status(CancellationToken cancellationToken) + public async Task Status(CancellationToken cancellationToken) { - var isRebuilding = _databaseCacheRebuilder.IsRebuilding(); - return Task.FromResult((IActionResult)Ok(new RebuildStatusModel - { - IsRebuilding = isRebuilding - })); + var isRebuilding = await _databaseCacheRebuilder.IsRebuildingAsync(); + return Ok( + new RebuildStatusModel + { + IsRebuilding = isRebuilding, + }); } } diff --git a/src/Umbraco.Core/AttemptOfTResultTStatus.cs b/src/Umbraco.Core/AttemptOfTResultTStatus.cs index e88465b3ad..ed3fc98225 100644 --- a/src/Umbraco.Core/AttemptOfTResultTStatus.cs +++ b/src/Umbraco.Core/AttemptOfTResultTStatus.cs @@ -1,3 +1,5 @@ +using System.Text.Json.Serialization; + namespace Umbraco.Cms.Core; /// @@ -9,6 +11,7 @@ namespace Umbraco.Cms.Core; public struct Attempt { // private - use Succeed() or Fail() methods to create attempts + [JsonConstructor] private Attempt(bool success, TResult result, TStatus status, Exception? exception) { Success = success; diff --git a/src/Umbraco.Core/Configuration/Models/LongRunningOperationsCleanupSettings.cs b/src/Umbraco.Core/Configuration/Models/LongRunningOperationsCleanupSettings.cs new file mode 100644 index 0000000000..d4b25c1c6f --- /dev/null +++ b/src/Umbraco.Core/Configuration/Models/LongRunningOperationsCleanupSettings.cs @@ -0,0 +1,27 @@ +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System.ComponentModel; + +namespace Umbraco.Cms.Core.Configuration.Models; + +/// +/// Typed configuration options for long-running operations cleanup settings. +/// +public class LongRunningOperationsCleanupSettings +{ + private const string StaticPeriod = "00:02:00"; + private const string StaticMaxAge = "01:00:00"; + + /// + /// Gets or sets a value for the period in which long-running operations are cleaned up. + /// + [DefaultValue(StaticPeriod)] + public TimeSpan Period { get; set; } = TimeSpan.Parse(StaticPeriod); + + /// + /// Gets or sets the maximum time a long-running operation entry can exist, without being updated, before it is considered for cleanup. + /// + [DefaultValue(StaticMaxAge)] + public TimeSpan MaxEntryAge { get; set; } = TimeSpan.Parse(StaticMaxAge); +} diff --git a/src/Umbraco.Core/Configuration/Models/LongRunningOperationsSettings.cs b/src/Umbraco.Core/Configuration/Models/LongRunningOperationsSettings.cs new file mode 100644 index 0000000000..32db2f73da --- /dev/null +++ b/src/Umbraco.Core/Configuration/Models/LongRunningOperationsSettings.cs @@ -0,0 +1,33 @@ +// Copyright (c) Umbraco. +// See LICENSE for more details. + +using System.ComponentModel; + +namespace Umbraco.Cms.Core.Configuration.Models; + +/// +/// Typed configuration options for long-running operations settings. +/// +[UmbracoOptions(Constants.Configuration.ConfigLongRunningOperations)] +public class LongRunningOperationsSettings +{ + private const string StaticExpirationTime = "00:05:00"; + private const string StaticTimeBetweenStatusChecks = "00:00:10"; + + /// + /// Gets or sets the cleanup settings for long-running operations. + /// + public LongRunningOperationsCleanupSettings Cleanup { get; set; } = new(); + + /// + /// Gets or sets the time after which a long-running operation is considered expired/stale, if not updated. + /// + [DefaultValue(StaticExpirationTime)] + public TimeSpan ExpirationTime { get; set; } = TimeSpan.Parse(StaticExpirationTime); + + /// + /// Gets or sets the time between status checks for long-running operations. + /// + [DefaultValue(StaticTimeBetweenStatusChecks)] + public TimeSpan TimeBetweenStatusChecks { get; set; } = TimeSpan.Parse(StaticTimeBetweenStatusChecks); +} diff --git a/src/Umbraco.Core/Constants-Configuration.cs b/src/Umbraco.Core/Constants-Configuration.cs index 78b43009b0..8504210504 100644 --- a/src/Umbraco.Core/Constants-Configuration.cs +++ b/src/Umbraco.Core/Constants-Configuration.cs @@ -40,6 +40,7 @@ public static partial class Constants public const string ConfigExamine = ConfigPrefix + "Examine"; public const string ConfigIndexing = ConfigPrefix + "Indexing"; public const string ConfigLogging = ConfigPrefix + "Logging"; + public const string ConfigLongRunningOperations = ConfigPrefix + "LongRunningOperations"; public const string ConfigMemberPassword = ConfigPrefix + "Security:MemberPassword"; public const string ConfigModelsBuilder = ConfigPrefix + "ModelsBuilder"; public const string ConfigModelsMode = ConfigModelsBuilder + ":ModelsMode"; diff --git a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Configuration.cs b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Configuration.cs index 1e9a93abf2..cc9b03e65b 100644 --- a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Configuration.cs +++ b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.Configuration.cs @@ -69,6 +69,7 @@ public static partial class UmbracoBuilderExtensions .AddUmbracoOptions() .AddUmbracoOptions() .AddUmbracoOptions() + .AddUmbracoOptions() .AddUmbracoOptions() .AddUmbracoOptions() .AddUmbracoOptions() diff --git a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs index c6802ed29e..cb5020f5b9 100644 --- a/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs +++ b/src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs @@ -34,6 +34,7 @@ using Umbraco.Cms.Core.Scoping; using Umbraco.Cms.Core.Security; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Services.ContentTypeEditing; +using Umbraco.Cms.Core.HostedServices; using Umbraco.Cms.Core.Preview; using Umbraco.Cms.Core.PublishedCache; using Umbraco.Cms.Core.PublishedCache.Internal; @@ -341,6 +342,7 @@ namespace Umbraco.Cms.Core.DependencyInjection Services.AddUnique(factory => new LocalizedTextService( factory.GetRequiredService>(), factory.GetRequiredService>())); + Services.AddUnique(); Services.AddUnique(); diff --git a/src/Umbraco.Core/Models/ContentPublishing/ContentPublishingBranchInternalResult.cs b/src/Umbraco.Core/Models/ContentPublishing/ContentPublishingBranchInternalResult.cs new file mode 100644 index 0000000000..fbc598180b --- /dev/null +++ b/src/Umbraco.Core/Models/ContentPublishing/ContentPublishingBranchInternalResult.cs @@ -0,0 +1,14 @@ +namespace Umbraco.Cms.Core.Models.ContentPublishing; + +internal sealed class ContentPublishingBranchInternalResult +{ + public Guid? ContentKey { get; init; } + + public IContent? Content { get; init; } + + public IEnumerable SucceededItems { get; set; } = []; + + public IEnumerable FailedItems { get; set; } = []; + + public Guid? AcceptedTaskId { get; init; } +} diff --git a/src/Umbraco.Core/Models/DatabaseCacheRebuildResult.cs b/src/Umbraco.Core/Models/DatabaseCacheRebuildResult.cs new file mode 100644 index 0000000000..970ac77f3c --- /dev/null +++ b/src/Umbraco.Core/Models/DatabaseCacheRebuildResult.cs @@ -0,0 +1,17 @@ +namespace Umbraco.Cms.Core.Models; + +/// +/// Represents the result of a database cache rebuild operation. +/// +public enum DatabaseCacheRebuildResult +{ + /// + /// The cache rebuild operation was either successful or enqueued successfully. + /// + Success, + + /// + /// A cache rebuild operation is already in progress. + /// + AlreadyRunning, +} diff --git a/src/Umbraco.Core/Models/LongRunningOperation.cs b/src/Umbraco.Core/Models/LongRunningOperation.cs new file mode 100644 index 0000000000..9b60792f9a --- /dev/null +++ b/src/Umbraco.Core/Models/LongRunningOperation.cs @@ -0,0 +1,22 @@ +namespace Umbraco.Cms.Core.Models; + +/// +/// Represents a long-running operation. +/// +public class LongRunningOperation +{ + /// + /// Gets the unique identifier for the long-running operation. + /// + public required Guid Id { get; init; } + + /// + /// Gets or sets the type of the long-running operation. + /// + public required string Type { get; set; } + + /// + /// Gets or sets the status of the long-running operation. + /// + public required LongRunningOperationStatus Status { get; set; } +} diff --git a/src/Umbraco.Core/Models/LongRunningOperationOfTResult.cs b/src/Umbraco.Core/Models/LongRunningOperationOfTResult.cs new file mode 100644 index 0000000000..805a36f8be --- /dev/null +++ b/src/Umbraco.Core/Models/LongRunningOperationOfTResult.cs @@ -0,0 +1,13 @@ +namespace Umbraco.Cms.Core.Models; + +/// +/// Represents a long-running operation. +/// +/// The type of the result of the long-running operation. +public class LongRunningOperation : LongRunningOperation +{ + /// + /// Gets or sets the result of the long-running operation. + /// + public TResult? Result { get; set; } +} diff --git a/src/Umbraco.Core/Models/LongRunningOperationStatus.cs b/src/Umbraco.Core/Models/LongRunningOperationStatus.cs new file mode 100644 index 0000000000..b370d4c392 --- /dev/null +++ b/src/Umbraco.Core/Models/LongRunningOperationStatus.cs @@ -0,0 +1,32 @@ +namespace Umbraco.Cms.Core.Models; + +/// +/// Represents the status of a long-running operation. +/// +public enum LongRunningOperationStatus +{ + /// + /// The operation has finished successfully. + /// + Success, + + /// + /// The operation has failed. + /// + Failed, + + /// + /// The operation has been queued. + /// + Enqueued, + + /// + /// The operation is currently running. + /// + Running, + + /// + /// The operation wasn't updated within the expected time frame and is considered stale. + /// + Stale, +} diff --git a/src/Umbraco.Core/Persistence/Constants-DatabaseSchema.cs b/src/Umbraco.Core/Persistence/Constants-DatabaseSchema.cs index c275fdd108..9dc3148b7d 100644 --- a/src/Umbraco.Core/Persistence/Constants-DatabaseSchema.cs +++ b/src/Umbraco.Core/Persistence/Constants-DatabaseSchema.cs @@ -98,6 +98,8 @@ public static partial class Constants public const string Webhook2Headers = Webhook + "2Headers"; public const string WebhookLog = Webhook + "Log"; public const string WebhookRequest = Webhook + "Request"; + + public const string LongRunningOperation = TableNamePrefix + "LongRunningOperation"; } } } diff --git a/src/Umbraco.Core/Persistence/Constants-Locks.cs b/src/Umbraco.Core/Persistence/Constants-Locks.cs index 874c0ffe2f..f8b7ce61cf 100644 --- a/src/Umbraco.Core/Persistence/Constants-Locks.cs +++ b/src/Umbraco.Core/Persistence/Constants-Locks.cs @@ -80,5 +80,10 @@ public static partial class Constants /// All webhook logs. /// public const int WebhookLogs = -343; + + /// + /// Long-running operations. + /// + public const int LongRunningOperations = -344; } } diff --git a/src/Umbraco.Core/Persistence/Repositories/ILongRunningOperationRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ILongRunningOperationRepository.cs new file mode 100644 index 0000000000..5821f1b144 --- /dev/null +++ b/src/Umbraco.Core/Persistence/Repositories/ILongRunningOperationRepository.cs @@ -0,0 +1,74 @@ +using Umbraco.Cms.Core.Models; + +namespace Umbraco.Cms.Core.Persistence.Repositories; + +/// +/// Represents a repository for managing long-running operations. +/// +public interface ILongRunningOperationRepository +{ + /// + /// Creates a new long-running operation. + /// + /// The operation to create. + /// The date and time when the operation should be considered stale. + /// A representing the asynchronous operation. + Task CreateAsync(LongRunningOperation operation, DateTimeOffset expirationDate); + + /// + /// Retrieves a long-running operation by its ID. + /// + /// The unique identifier of the long-running operation. + /// The long-running operation if found; otherwise, null. + Task GetAsync(Guid id); + + /// + /// Retrieves a long-running operation by its ID. + /// + /// The type of the result of the long-running operation. + /// The unique identifier of the long-running operation. + /// The long-running operation if found; otherwise, null. + Task?> GetAsync(Guid id); + + /// + /// Gets all long-running operations of a specific type, optionally filtered by their statuses. + /// + /// Type of the long-running operation. + /// Array of statuses to filter the operations by. + /// Number of entries to skip. + /// Number of entries to take. + /// A paged model of objects. + Task> GetByTypeAsync(string type, LongRunningOperationStatus[] statuses, int skip, int take); + + /// + /// Gets the status of a long-running operation by its unique identifier. + /// + /// The unique identifier for the operation. + /// The long-running operation if found; otherwise, null. + Task GetStatusAsync(Guid id); + + /// + /// Updates the status of a long-running operation identified by its ID. + /// + /// The unique identifier of the long-running operation. + /// The new status to set for the operation. + /// The date and time when the operation should be considered stale. + /// A representing the asynchronous operation. + public Task UpdateStatusAsync(Guid id, LongRunningOperationStatus status, DateTimeOffset expirationDate); + + /// + /// Sets the result of a long-running operation identified by its ID. + /// + /// The unique identifier of the long-running operation. + /// The result of the operation. + /// The type of the result. + /// A representing the asynchronous operation. + public Task SetResultAsync(Guid id, T result); + + /// + /// Cleans up long-running operations that haven't been updated for a certain period of time. + /// + /// The cutoff date and time for operations to be considered for deletion. + /// A representing the asynchronous operation. + Task CleanOperationsAsync(DateTimeOffset olderThan); +} diff --git a/src/Umbraco.Core/PublishedCache/IDatabaseCacheRebuilder.cs b/src/Umbraco.Core/PublishedCache/IDatabaseCacheRebuilder.cs index c4b7e2883a..ce46f1152c 100644 --- a/src/Umbraco.Core/PublishedCache/IDatabaseCacheRebuilder.cs +++ b/src/Umbraco.Core/PublishedCache/IDatabaseCacheRebuilder.cs @@ -1,3 +1,5 @@ +using Umbraco.Cms.Core.Models; + namespace Umbraco.Cms.Core.PublishedCache; /// @@ -11,6 +13,12 @@ public interface IDatabaseCacheRebuilder /// bool IsRebuilding() => false; + /// + /// Indicates if the database cache is in the process of being rebuilt. + /// + /// + Task IsRebuildingAsync() => Task.FromResult(IsRebuilding()); + /// /// Rebuilds the database cache. /// @@ -21,13 +29,36 @@ public interface IDatabaseCacheRebuilder /// Rebuilds the database cache, optionally using a background thread. /// /// Flag indicating whether to use a background thread for the operation and immediately return to the caller. + [Obsolete("Use RebuildAsync instead. Scheduled for removal in Umbraco 18.")] void Rebuild(bool useBackgroundThread) #pragma warning disable CS0618 // Type or member is obsolete => Rebuild(); #pragma warning restore CS0618 // Type or member is obsolete /// - /// Rebuids the database cache if the configured serializer has changed. + /// Rebuilds the database cache, optionally using a background thread. /// + /// Flag indicating whether to use a background thread for the operation and immediately return to the caller. + /// An attempt indicating the result of the rebuild operation. + Task> RebuildAsync(bool useBackgroundThread) + { + Rebuild(useBackgroundThread); + return Task.FromResult(Attempt.Succeed(DatabaseCacheRebuildResult.Success)); + } + + /// + /// Rebuilds the database cache if the configured serializer has changed. + /// + [Obsolete("Use the async version. Scheduled for removal in Umbraco 18.")] void RebuildDatabaseCacheIfSerializerChanged(); + + /// + /// Rebuilds the database cache if the configured serializer has changed. + /// + /// A representing the asynchronous operation. + Task RebuildDatabaseCacheIfSerializerChangedAsync() + { + RebuildDatabaseCacheIfSerializerChanged(); + return Task.CompletedTask; + } } diff --git a/src/Umbraco.Core/Services/ContentPublishingService.cs b/src/Umbraco.Core/Services/ContentPublishingService.cs index 98505483a1..ddabe19448 100644 --- a/src/Umbraco.Core/Services/ContentPublishingService.cs +++ b/src/Umbraco.Core/Services/ContentPublishingService.cs @@ -1,9 +1,7 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -using Umbraco.Cms.Core.Cache; using Umbraco.Cms.Core.Configuration.Models; using Umbraco.Cms.Core.Events; -using Umbraco.Cms.Core.HostedServices; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Models.ContentEditing; using Umbraco.Cms.Core.Models.ContentPublishing; @@ -15,8 +13,7 @@ namespace Umbraco.Cms.Core.Services; internal sealed class ContentPublishingService : IContentPublishingService { - private const string IsPublishingBranchRuntimeCacheKeyPrefix = "temp_indexing_op_"; - private const string PublishingBranchResultCacheKeyPrefix = "temp_indexing_result_"; + private const string PublishBranchOperationType = "ContentPublishBranch"; private readonly ICoreScopeProvider _coreScopeProvider; private readonly IContentService _contentService; @@ -27,8 +24,7 @@ internal sealed class ContentPublishingService : IContentPublishingService private ContentSettings _contentSettings; private readonly IRelationService _relationService; private readonly ILogger _logger; - private readonly IBackgroundTaskQueue _backgroundTaskQueue; - private readonly IAppPolicyCache _runtimeCache; + private readonly ILongRunningOperationService _longRunningOperationService; public ContentPublishingService( ICoreScopeProvider coreScopeProvider, @@ -40,8 +36,7 @@ internal sealed class ContentPublishingService : IContentPublishingService IOptionsMonitor optionsMonitor, IRelationService relationService, ILogger logger, - IBackgroundTaskQueue backgroundTaskQueue, - IAppPolicyCache runtimeCache) + ILongRunningOperationService longRunningOperationService) { _coreScopeProvider = coreScopeProvider; _contentService = contentService; @@ -51,8 +46,7 @@ internal sealed class ContentPublishingService : IContentPublishingService _languageService = languageService; _relationService = relationService; _logger = logger; - _backgroundTaskQueue = backgroundTaskQueue; - _runtimeCache = runtimeCache; + _longRunningOperationService = longRunningOperationService; _contentSettings = optionsMonitor.CurrentValue; optionsMonitor.OnChange((contentSettings) => { @@ -281,123 +275,125 @@ internal sealed class ContentPublishingService : IContentPublishingService => await PublishBranchAsync(key, cultures, publishBranchFilter, userKey, false); /// - public async Task> PublishBranchAsync(Guid key, IEnumerable cultures, PublishBranchFilter publishBranchFilter, Guid userKey, bool useBackgroundThread) + public async Task> PublishBranchAsync( + Guid key, + IEnumerable cultures, + PublishBranchFilter publishBranchFilter, + Guid userKey, + bool useBackgroundThread) { - if (useBackgroundThread) + if (useBackgroundThread is false) { - _logger.LogInformation("Starting async background thread for publishing branch."); + Attempt minimalAttempt + = await PerformPublishBranchAsync(key, cultures, publishBranchFilter, userKey, returnContent: true); + return MapInternalPublishingAttempt(minimalAttempt); + } - var taskId = Guid.NewGuid(); - _backgroundTaskQueue.QueueBackgroundWorkItem( - cancellationToken => - { - using (ExecutionContext.SuppressFlow()) + _logger.LogInformation("Starting async background thread for publishing branch."); + Attempt enqueueAttempt = await _longRunningOperationService.RunAsync( + PublishBranchOperationType, + async _ => await PerformPublishBranchAsync(key, cultures, publishBranchFilter, userKey, returnContent: false), + allowConcurrentExecution: true); + if (enqueueAttempt.Success) + { + return Attempt.SucceedWithStatus( + ContentPublishingOperationStatus.Accepted, + new ContentPublishingBranchResult { AcceptedTaskId = enqueueAttempt.Result }); + } + + return Attempt.FailWithStatus( + ContentPublishingOperationStatus.Unknown, + new ContentPublishingBranchResult + { + FailedItems = + [ + new ContentPublishingBranchItemResult { - Task.Run(async () => await PerformPublishBranchAsync(key, cultures, publishBranchFilter, userKey, taskId) ); - return Task.CompletedTask; + Key = key, + OperationStatus = ContentPublishingOperationStatus.Unknown, } - }); - - return Attempt.SucceedWithStatus(ContentPublishingOperationStatus.Accepted, new ContentPublishingBranchResult { AcceptedTaskId = taskId}); - } - else - { - return await PerformPublishBranchAsync(key, cultures, publishBranchFilter, userKey); - } + ], + }); } - private async Task> PerformPublishBranchAsync(Guid key, IEnumerable cultures, PublishBranchFilter publishBranchFilter, Guid userKey, Guid? taskId = null) + private async Task> PerformPublishBranchAsync( + Guid key, + IEnumerable cultures, + PublishBranchFilter publishBranchFilter, + Guid userKey, + bool returnContent) { - try + using ICoreScope scope = _coreScopeProvider.CreateCoreScope(); + IContent? content = _contentService.GetById(key); + if (content is null) { - if (taskId.HasValue) - { - SetIsPublishingBranch(taskId.Value); - } - - using ICoreScope scope = _coreScopeProvider.CreateCoreScope(); - IContent? content = _contentService.GetById(key); - if (content is null) - { - return Attempt.FailWithStatus( - ContentPublishingOperationStatus.ContentNotFound, - new ContentPublishingBranchResult - { - FailedItems = new[] + return Attempt.FailWithStatus( + ContentPublishingOperationStatus.ContentNotFound, + new ContentPublishingBranchInternalResult + { + FailedItems = + [ + new ContentPublishingBranchItemResult { - new ContentPublishingBranchItemResult - { - Key = key, - OperationStatus = ContentPublishingOperationStatus.ContentNotFound, - } + Key = key, + OperationStatus = ContentPublishingOperationStatus.ContentNotFound, } - }); - } - - var userId = await _userIdKeyResolver.GetAsync(userKey); - IEnumerable result = _contentService.PublishBranch(content, publishBranchFilter, cultures.ToArray(), userId); - scope.Complete(); - - var itemResults = result.ToDictionary(r => r.Content.Key, ToContentPublishingOperationStatus); - var branchResult = new ContentPublishingBranchResult - { - Content = content, - SucceededItems = itemResults - .Where(i => i.Value is ContentPublishingOperationStatus.Success) - .Select(i => new ContentPublishingBranchItemResult { Key = i.Key, OperationStatus = i.Value }) - .ToArray(), - FailedItems = itemResults - .Where(i => i.Value is not ContentPublishingOperationStatus.Success) - .Select(i => new ContentPublishingBranchItemResult { Key = i.Key, OperationStatus = i.Value }) - .ToArray() - }; - - Attempt attempt = branchResult.FailedItems.Any() is false - ? Attempt.SucceedWithStatus(ContentPublishingOperationStatus.Success, branchResult) - : Attempt.FailWithStatus(ContentPublishingOperationStatus.FailedBranch, branchResult); - if (taskId.HasValue) - { - SetPublishingBranchResult(taskId.Value, attempt); - } - - return attempt; + ], + }); } - finally + + var userId = await _userIdKeyResolver.GetAsync(userKey); + IEnumerable result = _contentService.PublishBranch(content, publishBranchFilter, cultures.ToArray(), userId); + scope.Complete(); + + var itemResults = result.ToDictionary(r => r.Content.Key, ToContentPublishingOperationStatus); + var branchResult = new ContentPublishingBranchInternalResult { - if (taskId.HasValue) - { - ClearIsPublishingBranch(taskId.Value); - } - } + ContentKey = content.Key, + Content = returnContent ? content : null, + SucceededItems = itemResults + .Where(i => i.Value is ContentPublishingOperationStatus.Success) + .Select(i => new ContentPublishingBranchItemResult { Key = i.Key, OperationStatus = i.Value }) + .ToArray(), + FailedItems = itemResults + .Where(i => i.Value is not ContentPublishingOperationStatus.Success) + .Select(i => new ContentPublishingBranchItemResult { Key = i.Key, OperationStatus = i.Value }) + .ToArray(), + }; + + Attempt attempt = branchResult.FailedItems.Any() is false + ? Attempt.SucceedWithStatus(ContentPublishingOperationStatus.Success, branchResult) + : Attempt.FailWithStatus(ContentPublishingOperationStatus.FailedBranch, branchResult); + + return attempt; } /// - public Task IsPublishingBranchAsync(Guid taskId) => Task.FromResult(_runtimeCache.Get(GetIsPublishingBranchCacheKey(taskId)) is not null); + public async Task IsPublishingBranchAsync(Guid taskId) + => await _longRunningOperationService.GetStatusAsync(taskId) is LongRunningOperationStatus.Enqueued or LongRunningOperationStatus.Running; /// - public Task> GetPublishBranchResultAsync(Guid taskId) + public async Task> GetPublishBranchResultAsync(Guid taskId) { - var taskResult = _runtimeCache.Get(GetPublishingBranchResultCacheKey(taskId)) as Attempt?; - if (taskResult is null) + Attempt, LongRunningOperationResultStatus> result = + await _longRunningOperationService + .GetResultAsync>(taskId); + + if (result.Success is false) { - return Task.FromResult(Attempt.FailWithStatus(ContentPublishingOperationStatus.TaskResultNotFound, new ContentPublishingBranchResult())); + return Attempt.FailWithStatus( + result.Status switch + { + LongRunningOperationResultStatus.OperationNotFound => ContentPublishingOperationStatus.TaskResultNotFound, + LongRunningOperationResultStatus.OperationFailed => ContentPublishingOperationStatus.Failed, + _ => ContentPublishingOperationStatus.Unknown, + }, + new ContentPublishingBranchResult()); } - // We won't clear the cache here just in case we remove references to the returned object. It expires after 60 seconds anyway. - return Task.FromResult(taskResult.Value); + return MapInternalPublishingAttempt(result.Result); } - private void SetIsPublishingBranch(Guid taskId) => _runtimeCache.Insert(GetIsPublishingBranchCacheKey(taskId), () => "tempValue", TimeSpan.FromMinutes(10)); - - private void ClearIsPublishingBranch(Guid taskId) => _runtimeCache.Clear(GetIsPublishingBranchCacheKey(taskId)); - - private static string GetIsPublishingBranchCacheKey(Guid taskId) => IsPublishingBranchRuntimeCacheKeyPrefix + taskId; - - private void SetPublishingBranchResult(Guid taskId, Attempt result) - => _runtimeCache.Insert(GetPublishingBranchResultCacheKey(taskId), () => result, TimeSpan.FromMinutes(1)); - - private static string GetPublishingBranchResultCacheKey(Guid taskId) => PublishingBranchResultCacheKeyPrefix + taskId; - /// public async Task> UnpublishAsync(Guid key, ISet? cultures, Guid userKey) { @@ -564,4 +560,19 @@ internal sealed class ContentPublishingService : IContentPublishingService PublishResultType.FailedUnpublishCancelledByEvent => ContentPublishingOperationStatus.CancelledByEvent, _ => throw new ArgumentOutOfRangeException() }; + + private Attempt MapInternalPublishingAttempt( + Attempt minimalAttempt) => + minimalAttempt.Success + ? Attempt.SucceedWithStatus(minimalAttempt.Status, MapMinimalPublishingBranchResult(minimalAttempt.Result)) + : Attempt.FailWithStatus(minimalAttempt.Status, MapMinimalPublishingBranchResult(minimalAttempt.Result)); + + private ContentPublishingBranchResult MapMinimalPublishingBranchResult(ContentPublishingBranchInternalResult internalResult) => + new() + { + Content = internalResult.Content + ?? (internalResult.ContentKey is null ? null : _contentService.GetById(internalResult.ContentKey.Value)), + SucceededItems = internalResult.SucceededItems, + FailedItems = internalResult.FailedItems, + }; } diff --git a/src/Umbraco.Core/Services/ILongRunningOperationService.cs b/src/Umbraco.Core/Services/ILongRunningOperationService.cs new file mode 100644 index 0000000000..6258d2b36a --- /dev/null +++ b/src/Umbraco.Core/Services/ILongRunningOperationService.cs @@ -0,0 +1,72 @@ +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Services.OperationStatus; + +namespace Umbraco.Cms.Core.Services; + +/// +/// A service for managing long-running operations that can be executed in the background. +/// +public interface ILongRunningOperationService +{ + /// + /// Enqueues a long-running operation to be executed in the background. + /// + /// The type of the long-running operation, used for categorization. + /// The operation to execute, which should accept a . + /// Whether to allow multiple instances of the same operation type to run concurrently. + /// Whether to run the operation in the background. + /// An indicating the status of the enqueue operation. + /// Thrown if attempting to run an operation in the foreground within a scope. + Task> RunAsync( + string type, + Func operation, + bool allowConcurrentExecution = false, + bool runInBackground = true); + + /// + /// Enqueues a long-running operation to be executed in the background. + /// + /// The type of the long-running operation, used for categorization. + /// The operation to execute, which should accept a . + /// Whether to allow multiple instances of the same operation type to run concurrently. + /// Whether to run the operation in the background. + /// An indicating the status of the enqueue operation. + /// The type of the result expected from the operation. + /// Thrown if attempting to run an operation in the foreground within a scope. + Task> RunAsync( + string type, + Func> operation, + bool allowConcurrentExecution = false, + bool runInBackground = true); + + /// + /// Gets the status of a long-running operation by its unique identifier. + /// + /// The unique identifier for the operation. + /// True if the operation is running or enqueued; otherwise, false. + Task GetStatusAsync(Guid operationId); + + /// + /// Gets the active long-running operations of a specific type. + /// + /// The type of the long-running operation. + /// Number of operations to skip. + /// Number of operations to take. + /// Optional array of statuses to filter the operations by. If null, only enqueued and running + /// operations are returned. + /// True if the operation is running or enqueued; otherwise, false. + Task> GetByTypeAsync( + string type, + int skip, + int take, + LongRunningOperationStatus[]? statuses = null); + + /// + /// Gets the result of a long-running operation. + /// + /// The unique identifier of the long-running operation. + /// The type of the result expected from the operation. + /// An containing the result of the operation + /// and its status. If the operation is not found or has not completed, the result will be null. + Task> GetResultAsync(Guid operationId); +} diff --git a/src/Umbraco.Core/Services/LongRunningOperationService.cs b/src/Umbraco.Core/Services/LongRunningOperationService.cs new file mode 100644 index 0000000000..7c867c178c --- /dev/null +++ b/src/Umbraco.Core/Services/LongRunningOperationService.cs @@ -0,0 +1,250 @@ +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Persistence.Repositories; +using Umbraco.Cms.Core.Scoping; +using Umbraco.Cms.Core.Services.OperationStatus; + +namespace Umbraco.Cms.Core.Services; + +/// +internal class LongRunningOperationService : ILongRunningOperationService +{ + private readonly IOptions _options; + private readonly ILongRunningOperationRepository _repository; + private readonly ICoreScopeProvider _scopeProvider; + private readonly TimeProvider _timeProvider; + private readonly ILogger _logger; + + /// + /// Initializes a new instance of the class. + /// + /// The repository for tracking long-running operations. + /// The scope provider for managing database transactions. + /// The time provider for getting the current UTC time. + /// The logger for logging information and errors related to long-running operations. + public LongRunningOperationService( + IOptions options, + ILongRunningOperationRepository repository, + ICoreScopeProvider scopeProvider, + TimeProvider timeProvider, + ILogger logger) + { + _options = options; + _repository = repository; + _scopeProvider = scopeProvider; + _timeProvider = timeProvider; + _logger = logger; + } + + /// + public Task> RunAsync( + string type, + Func operation, + bool allowConcurrentExecution = false, + bool runInBackground = true) + => RunInner( + type, + async cancellationToken => + { + await operation(cancellationToken); + return null; + }, + allowConcurrentExecution, + runInBackground); + + /// + public Task> RunAsync( + string type, + Func> operation, + bool allowConcurrentExecution = false, + bool runInBackground = true) + => RunInner( + type, + operation, + allowConcurrentExecution, + runInBackground); + + /// + public async Task GetStatusAsync(Guid operationId) + { + using ICoreScope scope = _scopeProvider.CreateCoreScope(autoComplete: true); + return await _repository.GetStatusAsync(operationId); + } + + /// + public async Task> GetByTypeAsync( + string type, + int skip, + int take, + LongRunningOperationStatus[]? statuses = null) + { + using ICoreScope scope = _scopeProvider.CreateCoreScope(autoComplete: true); + return await _repository.GetByTypeAsync( + type, + statuses ?? [LongRunningOperationStatus.Enqueued, LongRunningOperationStatus.Running], + skip, + take); + } + + /// + public async Task> GetResultAsync(Guid operationId) + { + using ICoreScope scope = _scopeProvider.CreateCoreScope(autoComplete: true); + LongRunningOperation? operation = await _repository.GetAsync(operationId); + if (operation?.Status is not LongRunningOperationStatus.Success) + { + return Attempt.FailWithStatus( + operation?.Status switch + { + LongRunningOperationStatus.Enqueued or LongRunningOperationStatus.Running => LongRunningOperationResultStatus.OperationPending, + LongRunningOperationStatus.Failed => LongRunningOperationResultStatus.OperationFailed, + null => LongRunningOperationResultStatus.OperationNotFound, + _ => throw new ArgumentOutOfRangeException(nameof(operation.Status), operation.Status, "Unhandled operation status."), + }, + default); + } + + return Attempt.SucceedWithStatus(LongRunningOperationResultStatus.Success, operation.Result); + } + + private async Task> RunInner( + string type, + Func> operation, + bool allowConcurrentExecution = true, + bool runInBackground = true, + CancellationToken cancellationToken = default) + { + if (!runInBackground && _scopeProvider.Context is not null) + { + throw new InvalidOperationException("Long running operations cannot be executed in the foreground within an existing scope."); + } + + Guid operationId; + using (ICoreScope scope = _scopeProvider.CreateCoreScope()) + { + if (allowConcurrentExecution is false) + { + // Acquire a write lock to ensure that no other operations of the same type can be enqueued while this one is being processed. + // This is only needed if we do not allow multiple runs of the same type. + scope.WriteLock(Constants.Locks.LongRunningOperations); + if (await IsAlreadyRunning(type)) + { + scope.Complete(); + return Attempt.FailWithStatus(LongRunningOperationEnqueueStatus.AlreadyRunning, Guid.Empty); + } + } + + operationId = Guid.CreateVersion7(); + await _repository.CreateAsync( + new LongRunningOperation + { + Id = operationId, + Type = type, + Status = LongRunningOperationStatus.Enqueued, + }, + _timeProvider.GetUtcNow() + _options.Value.ExpirationTime); + scope.Complete(); + } + + if (runInBackground) + { + using (ExecutionContext.SuppressFlow()) + { + _ = Task.Run( + async () => + { + try + { + await RunOperation(operationId, type, operation, cancellationToken); + } + catch (Exception ex) + { + _logger.LogError(ex, "An error occurred while running long-running background operation {Type} with id {OperationId}.", type, operationId); + } + }, + cancellationToken); + } + } + else + { + await RunOperation(operationId, type, operation, cancellationToken); + } + + return Attempt.SucceedWithStatus(LongRunningOperationEnqueueStatus.Success, operationId); + } + + private async Task RunOperation( + Guid operationId, + string type, + Func> operation, + CancellationToken cancellationToken = default) + { + _logger.LogDebug("Running long-running operation {Type} with id {OperationId}.", type, operationId); + + Task operationTask = operation(cancellationToken); + + Task task; + using (ExecutionContext.SuppressFlow()) + { + task = Task.Run( + () => TrackOperationStatus(operationId, type, operationTask), + CancellationToken.None); + } + + await task.ConfigureAwait(false); + } + + private async Task TrackOperationStatus( + Guid operationId, + string type, + Task operationTask) + { + _logger.LogDebug("Started tracking long-running operation {Type} with id {OperationId}.", type, operationId); + + try + { + while (operationTask.IsCompleted is false) + { + // Update the status in the database and increase the expiration time. + // That way, even if the status has not changed, we know that the operation is still being processed. + using (ICoreScope scope = _scopeProvider.CreateCoreScope()) + { + await _repository.UpdateStatusAsync(operationId, LongRunningOperationStatus.Running, _timeProvider.GetUtcNow() + _options.Value.ExpirationTime); + scope.Complete(); + } + + await Task.WhenAny(operationTask, Task.Delay(_options.Value.TimeBetweenStatusChecks)).ConfigureAwait(false); + } + } + catch (Exception) + { + // If an exception occurs, we update the status to Failed and rethrow the exception. + _logger.LogDebug("Finished long-running operation {Type} with id {OperationId} and status {Status}.", type, operationId, LongRunningOperationStatus.Failed); + using (ICoreScope scope = _scopeProvider.CreateCoreScope()) + { + await _repository.UpdateStatusAsync(operationId, LongRunningOperationStatus.Failed, _timeProvider.GetUtcNow() + _options.Value.ExpirationTime); + scope.Complete(); + } + + throw; + } + + _logger.LogDebug("Finished long-running operation {Type} with id {OperationId} and status {Status}.", type, operationId, LongRunningOperationStatus.Success); + + using (ICoreScope scope = _scopeProvider.CreateCoreScope()) + { + await _repository.UpdateStatusAsync(operationId, LongRunningOperationStatus.Success, _timeProvider.GetUtcNow() + _options.Value.ExpirationTime); + if (operationTask.Result != null) + { + await _repository.SetResultAsync(operationId, operationTask.Result); + } + + scope.Complete(); + } + } + + private async Task IsAlreadyRunning(string type) + => (await _repository.GetByTypeAsync(type, [LongRunningOperationStatus.Enqueued, LongRunningOperationStatus.Running], 0, 0)).Total != 0; +} diff --git a/src/Umbraco.Core/Services/OperationStatus/LongRunningOperationEnqueueStatus.cs b/src/Umbraco.Core/Services/OperationStatus/LongRunningOperationEnqueueStatus.cs new file mode 100644 index 0000000000..2c964cb8c0 --- /dev/null +++ b/src/Umbraco.Core/Services/OperationStatus/LongRunningOperationEnqueueStatus.cs @@ -0,0 +1,17 @@ +namespace Umbraco.Cms.Core.Services.OperationStatus; + +/// +/// Represents the result of attempting to enqueue a long-running operation. +/// +public enum LongRunningOperationEnqueueStatus +{ + /// + /// The operation was successfully enqueued and will be executed in the background. + /// + Success, + + /// + /// The operation is already running. + /// + AlreadyRunning, +} diff --git a/src/Umbraco.Core/Services/OperationStatus/LongRunningOperationResultStatus.cs b/src/Umbraco.Core/Services/OperationStatus/LongRunningOperationResultStatus.cs new file mode 100644 index 0000000000..a178aff19e --- /dev/null +++ b/src/Umbraco.Core/Services/OperationStatus/LongRunningOperationResultStatus.cs @@ -0,0 +1,27 @@ +namespace Umbraco.Cms.Core.Services.OperationStatus; + +/// +/// Represents the status of the result of a long-running operation. +/// +public enum LongRunningOperationResultStatus +{ + /// + /// The operation result was successfully retrieved. + /// + Success, + + /// + /// The operation was not found, possibly due to unknown type or ID or it was already deleted. + /// + OperationNotFound, + + /// + /// The operation is still running and the result is not yet available. + /// + OperationPending, + + /// + /// The operation has failed, and the result is not available. + /// + OperationFailed, +} diff --git a/src/Umbraco.Infrastructure/BackgroundJobs/Jobs/LongRunningOperationsCleanupJob.cs b/src/Umbraco.Infrastructure/BackgroundJobs/Jobs/LongRunningOperationsCleanupJob.cs new file mode 100644 index 0000000000..46d139b08b --- /dev/null +++ b/src/Umbraco.Infrastructure/BackgroundJobs/Jobs/LongRunningOperationsCleanupJob.cs @@ -0,0 +1,58 @@ +using Microsoft.Extensions.Options; +using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.Persistence.Repositories; +using Umbraco.Cms.Core.Scoping; + +namespace Umbraco.Cms.Infrastructure.BackgroundJobs.Jobs; + +/// +/// Cleans up long-running operations that have exceeded a specified age. +/// +public class LongRunningOperationsCleanupJob : IRecurringBackgroundJob +{ + private readonly ICoreScopeProvider _scopeProvider; + private readonly ILongRunningOperationRepository _longRunningOperationRepository; + private readonly TimeProvider _timeProvider; + private readonly TimeSpan _maxEntryAge; + + /// + /// Initializes a new instance of the class. + /// + /// The long-running operations settings. + /// The scope provider for managing database transactions. + /// The repository for managing long-running operations. + /// The time provider for getting the current time. + public LongRunningOperationsCleanupJob( + IOptions options, + ICoreScopeProvider scopeProvider, + ILongRunningOperationRepository longRunningOperationRepository, + TimeProvider timeProvider) + { + _scopeProvider = scopeProvider; + _longRunningOperationRepository = longRunningOperationRepository; + _timeProvider = timeProvider; + _maxEntryAge = options.Value.Cleanup.MaxEntryAge; + Period = options.Value.Cleanup.Period; + } + + /// + public event EventHandler? PeriodChanged + { + add { } + remove { } + } + + /// + public TimeSpan Period { get; } + + /// + public TimeSpan Delay { get; } = TimeSpan.FromSeconds(10); + + /// + public async Task RunJobAsync() + { + using ICoreScope scope = _scopeProvider.CreateCoreScope(); + await _longRunningOperationRepository.CleanOperationsAsync(_timeProvider.GetUtcNow() - _maxEntryAge); + scope.Complete(); + } +} diff --git a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Repositories.cs b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Repositories.cs index 73ee0d263a..1b624aa5f6 100644 --- a/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Repositories.cs +++ b/src/Umbraco.Infrastructure/DependencyInjection/UmbracoBuilder.Repositories.cs @@ -82,6 +82,7 @@ public static partial class UmbracoBuilderExtensions builder.Services.AddUnique(); builder.Services.AddUnique(); builder.Services.AddUnique(); + builder.Services.AddUnique(); return builder; } diff --git a/src/Umbraco.Infrastructure/HostedServices/QueuedHostedService.cs b/src/Umbraco.Infrastructure/HostedServices/QueuedHostedService.cs index 79d93a928f..038691cc99 100644 --- a/src/Umbraco.Infrastructure/HostedServices/QueuedHostedService.cs +++ b/src/Umbraco.Infrastructure/HostedServices/QueuedHostedService.cs @@ -39,18 +39,26 @@ public class QueuedHostedService : BackgroundService { Func? workItem = await TaskQueue.DequeueAsync(stoppingToken); + if (workItem is null) + { + continue; + } + try { - if (workItem is not null) + Task task; + using (ExecutionContext.SuppressFlow()) { - await workItem(stoppingToken); + task = Task.Run(async () => await workItem(stoppingToken), stoppingToken); } + + await task; } catch (Exception ex) { _logger.LogError( ex, - "Error occurred executing {WorkItem}.", nameof(workItem)); + "Error occurred executing workItem."); } } } diff --git a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseDataCreator.cs b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseDataCreator.cs index b30423be99..5255b79518 100644 --- a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseDataCreator.cs +++ b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseDataCreator.cs @@ -1050,6 +1050,7 @@ internal sealed class DatabaseDataCreator _database.Insert(Constants.DatabaseSchema.Tables.Lock, "id", false, new LockDto { Id = Constants.Locks.MainDom, Name = "MainDom" }); _database.Insert(Constants.DatabaseSchema.Tables.Lock, "id", false, new LockDto { Id = Constants.Locks.WebhookRequest, Name = "WebhookRequest" }); _database.Insert(Constants.DatabaseSchema.Tables.Lock, "id", false, new LockDto { Id = Constants.Locks.WebhookLogs, Name = "WebhookLogs" }); + _database.Insert(Constants.DatabaseSchema.Tables.Lock, "id", false, new LockDto { Id = Constants.Locks.LongRunningOperations, Name = "LongRunningOperations" }); } private void CreateContentTypeData() diff --git a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseSchemaCreator.cs b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseSchemaCreator.cs index cd7fcd44d0..d454d97847 100644 --- a/src/Umbraco.Infrastructure/Migrations/Install/DatabaseSchemaCreator.cs +++ b/src/Umbraco.Infrastructure/Migrations/Install/DatabaseSchemaCreator.cs @@ -90,6 +90,7 @@ public class DatabaseSchemaCreator typeof(WebhookLogDto), typeof(WebhookRequestDto), typeof(UserDataDto), + typeof(LongRunningOperationDto), }; private readonly IUmbracoDatabase _database; diff --git a/src/Umbraco.Infrastructure/Migrations/MigrationPlanExecutor.cs b/src/Umbraco.Infrastructure/Migrations/MigrationPlanExecutor.cs index 48c8899c81..878d0e4d3b 100644 --- a/src/Umbraco.Infrastructure/Migrations/MigrationPlanExecutor.cs +++ b/src/Umbraco.Infrastructure/Migrations/MigrationPlanExecutor.cs @@ -122,7 +122,7 @@ public class MigrationPlanExecutor : IMigrationPlanExecutor if (_rebuildCache) { _logger.LogInformation("Starts rebuilding the cache. This can be a long running operation"); - RebuildCache(); + await RebuildCache(); } // If any completed migration requires us to sign out the user we'll do that. @@ -295,11 +295,11 @@ public class MigrationPlanExecutor : IMigrationPlanExecutor } } - private void RebuildCache() + private async Task RebuildCache() { _appCaches.RuntimeCache.Clear(); _appCaches.IsolatedCaches.ClearAllCaches(); - _databaseCacheRebuilder.Rebuild(false); + await _databaseCacheRebuilder.RebuildAsync(false); _distributedCache.RefreshAllPublishedSnapshot(); } diff --git a/src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs b/src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs index 21cfe558a6..c5a6abd4b7 100644 --- a/src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs +++ b/src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs @@ -119,5 +119,8 @@ public class UmbracoPlan : MigrationPlan // To 16.0.0 To("{C6681435-584F-4BC8-BB8D-BC853966AF0B}"); To("{D1568C33-A697-455F-8D16-48060CB954A1}"); + + // To 16.2.0 + To("{741C22CF-5FB8-4343-BF79-B97A58C2CCBA}"); } } diff --git a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_16_2_0/AddLongRunningOperations.cs b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_16_2_0/AddLongRunningOperations.cs new file mode 100644 index 0000000000..b9f9afcdfb --- /dev/null +++ b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_16_2_0/AddLongRunningOperations.cs @@ -0,0 +1,35 @@ +using NPoco; +using Umbraco.Cms.Core; +using Umbraco.Cms.Infrastructure.Persistence; +using Umbraco.Cms.Infrastructure.Persistence.Dtos; +using Umbraco.Extensions; + +namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_16_2_0; + +[Obsolete("Remove in Umbraco 18.")] +public class AddLongRunningOperations : MigrationBase +{ + public AddLongRunningOperations(IMigrationContext context) + : base(context) + { + } + + protected override void Migrate() + { + if (!TableExists(Constants.DatabaseSchema.Tables.LongRunningOperation)) + { + Create.Table().Do(); + } + + Sql sql = Database.SqlContext.Sql() + .Select() + .From() + .Where(x => x.Id == Constants.Locks.LongRunningOperations); + + LockDto? longRunningOperationsLock = Database.FirstOrDefault(sql); + if (longRunningOperationsLock is null) + { + Database.Insert(Constants.DatabaseSchema.Tables.Lock, "id", false, new LockDto { Id = Constants.Locks.LongRunningOperations, Name = "LongRunningOperations" }); + } + } +} diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/LongRunningOperationDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/LongRunningOperationDto.cs new file mode 100644 index 0000000000..8b223b5c06 --- /dev/null +++ b/src/Umbraco.Infrastructure/Persistence/Dtos/LongRunningOperationDto.cs @@ -0,0 +1,45 @@ +using NPoco; +using Umbraco.Cms.Core; +using Umbraco.Cms.Infrastructure.Persistence.DatabaseAnnotations; +using Umbraco.Cms.Infrastructure.Persistence.DatabaseModelDefinitions; + +namespace Umbraco.Cms.Infrastructure.Persistence.Dtos; + +[TableName(Constants.DatabaseSchema.Tables.LongRunningOperation)] +[PrimaryKey("id", AutoIncrement = false)] +[ExplicitColumns] +internal class LongRunningOperationDto +{ + [Column("id")] + [PrimaryKeyColumn(Name = "PK_umbracoLongRunningOperation", AutoIncrement = false)] + public Guid Id { get; set; } + + [Column("type")] + [Length(50)] + [NullSetting(NullSetting = NullSettings.NotNull)] + public string Type { get; set; } = null!; + + [Column("status")] + [Length(50)] + [NullSetting(NullSetting = NullSettings.NotNull)] + public string Status { get; set; } = null!; + + [Column("result")] + [SpecialDbType(SpecialDbTypes.NVARCHARMAX)] + [NullSetting(NullSetting = NullSettings.Null)] + public string? Result { get; set; } = null; + + [Column("createDate", ForceToUtc = false)] + [NullSetting(NullSetting = NullSettings.NotNull)] + [Constraint(Default = SystemMethods.CurrentDateTime)] + public DateTime CreateDate { get; set; } = DateTime.UtcNow; + + [Column("updateDate", ForceToUtc = false)] + [NullSetting(NullSetting = NullSettings.NotNull)] + [Constraint(Default = SystemMethods.CurrentDateTime)] + public DateTime UpdateDate { get; set; } = DateTime.UtcNow; + + [Column("expirationDate", ForceToUtc = false)] + [NullSetting(NullSetting = NullSettings.NotNull)] + public DateTime ExpirationDate { get; set; } +} diff --git a/src/Umbraco.Infrastructure/Persistence/Querying/ExpressionVisitorBase.cs b/src/Umbraco.Infrastructure/Persistence/Querying/ExpressionVisitorBase.cs index 897628f806..a585151929 100644 --- a/src/Umbraco.Infrastructure/Persistence/Querying/ExpressionVisitorBase.cs +++ b/src/Umbraco.Infrastructure/Persistence/Querying/ExpressionVisitorBase.cs @@ -681,6 +681,11 @@ internal abstract class ExpressionVisitorBase inBuilder.Append(SqlParameters.Count - 1); } + if (inFirst) + { + inBuilder.Append("NULL"); + } + inBuilder.Append(")"); return inBuilder.ToString(); diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/LongRunningOperationRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/LongRunningOperationRepository.cs new file mode 100644 index 0000000000..0f53cb1dd3 --- /dev/null +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/LongRunningOperationRepository.cs @@ -0,0 +1,186 @@ +using System.Linq.Expressions; +using NPoco; +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Cache; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Persistence.Repositories; +using Umbraco.Cms.Core.Serialization; +using Umbraco.Cms.Infrastructure.Persistence.Dtos; +using Umbraco.Cms.Infrastructure.Scoping; +using Umbraco.Extensions; + +namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement; + +/// +/// Repository for managing long-running operations. +/// +internal class LongRunningOperationRepository : RepositoryBase, ILongRunningOperationRepository +{ + private readonly IJsonSerializer _jsonSerializer; + private readonly TimeProvider _timeProvider; + + /// + /// Initializes a new instance of the class. + /// + public LongRunningOperationRepository( + IJsonSerializer jsonSerializer, + IScopeAccessor scopeAccessor, + AppCaches appCaches, + TimeProvider timeProvider) + : base(scopeAccessor, appCaches) + { + _jsonSerializer = jsonSerializer; + _timeProvider = timeProvider; + } + + /// + public async Task CreateAsync(LongRunningOperation operation, DateTimeOffset expirationDate) + { + LongRunningOperationDto dto = MapEntityToDto(operation, expirationDate); + await Database.InsertAsync(dto); + } + + /// + public async Task GetAsync(Guid id) + { + Sql sql = Sql() + .Select() + .From() + .Where(x => x.Id == id); + + LongRunningOperationDto dto = await Database.FirstOrDefaultAsync(sql); + return dto == null ? null : MapDtoToEntity(dto); + } + + /// + public async Task?> GetAsync(Guid id) + { + Sql sql = Sql() + .Select() + .From() + .Where(x => x.Id == id); + + LongRunningOperationDto dto = await Database.FirstOrDefaultAsync(sql); + return dto == null ? null : MapDtoToEntity(dto); + } + + /// + public async Task> GetByTypeAsync( + string type, + LongRunningOperationStatus[] statuses, + int skip, + int take) + { + Sql sql = Sql() + .Select() + .From() + .Where(x => x.Type == type); + + if (statuses.Length > 0) + { + var includeStale = statuses.Contains(LongRunningOperationStatus.Stale); + string[] possibleStaleStatuses = + [nameof(LongRunningOperationStatus.Enqueued), nameof(LongRunningOperationStatus.Running)]; + IEnumerable statusList = statuses.Except([LongRunningOperationStatus.Stale]).Select(s => s.ToString()); + + DateTime now = _timeProvider.GetUtcNow().UtcDateTime; + sql = sql.Where(x => + (statusList.Contains(x.Status) && (!possibleStaleStatuses.Contains(x.Status) || x.ExpirationDate >= now)) + || (includeStale && possibleStaleStatuses.Contains(x.Status) && x.ExpirationDate < now)); + } + + return await Database.PagedAsync( + sql, + skip, + take, + sortingAction: sql2 => sql2.OrderBy(x => x.CreateDate), + mapper: MapDtoToEntity); + } + + /// + public async Task GetStatusAsync(Guid id) + { + Sql sql = Sql() + .Select(x => x.Status) + .From() + .Where(x => x.Id == id); + + return (await Database.ExecuteScalarAsync(sql))?.EnumParse(false); + } + + /// + public async Task UpdateStatusAsync(Guid id, LongRunningOperationStatus status, DateTimeOffset expirationTime) + { + Sql sql = Sql() + .Update(x => x + .Set(y => y.Status, status.ToString()) + .Set(y => y.UpdateDate, DateTime.UtcNow) + .Set(y => y.ExpirationDate, expirationTime.DateTime)) + .Where(x => x.Id == id); + + await Database.ExecuteAsync(sql); + } + + /// + public async Task SetResultAsync(Guid id, T result) + { + Sql sql = Sql() + .Update(x => x + .Set(y => y.Result, _jsonSerializer.Serialize(result)) + .Set(y => y.UpdateDate, DateTime.UtcNow)) + .Where(x => x.Id == id); + + await Database.ExecuteAsync(sql); + } + + /// + public async Task CleanOperationsAsync(DateTimeOffset olderThan) + { + Sql sql = Sql() + .Delete() + .Where(x => x.UpdateDate < olderThan); + + await Database.ExecuteAsync(sql); + } + + private LongRunningOperation MapDtoToEntity(LongRunningOperationDto dto) => + new() + { + Id = dto.Id, + Type = dto.Type, + Status = DetermineStatus(dto), + }; + + private LongRunningOperation MapDtoToEntity(LongRunningOperationDto dto) => + new() + { + Id = dto.Id, + Type = dto.Type, + Status = DetermineStatus(dto), + Result = dto.Result == null ? default : _jsonSerializer.Deserialize(dto.Result), + }; + + private static LongRunningOperationDto MapEntityToDto(LongRunningOperation entity, DateTimeOffset expirationTime) => + new() + { + Id = entity.Id, + Type = entity.Type, + Status = entity.Status.ToString(), + CreateDate = DateTime.UtcNow, + UpdateDate = DateTime.UtcNow, + ExpirationDate = expirationTime.UtcDateTime, + }; + + private LongRunningOperationStatus DetermineStatus(LongRunningOperationDto dto) + { + LongRunningOperationStatus status = dto.Status.EnumParse(false); + DateTimeOffset now = _timeProvider.GetUtcNow(); + if (status is LongRunningOperationStatus.Enqueued or LongRunningOperationStatus.Running + && now.UtcDateTime >= dto.ExpirationDate) + { + status = LongRunningOperationStatus.Stale; + } + + return status; + } +} diff --git a/src/Umbraco.Infrastructure/Persistence/UmbracoDatabaseExtensions.cs b/src/Umbraco.Infrastructure/Persistence/UmbracoDatabaseExtensions.cs index 767655e4b3..7fd3f614f5 100644 --- a/src/Umbraco.Infrastructure/Persistence/UmbracoDatabaseExtensions.cs +++ b/src/Umbraco.Infrastructure/Persistence/UmbracoDatabaseExtensions.cs @@ -1,4 +1,6 @@ +using System.Linq.Expressions; using NPoco; +using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Persistence; using Umbraco.Cms.Infrastructure.Persistence.Dtos; using Umbraco.Cms.Infrastructure.Persistence.SqlSyntax; @@ -82,4 +84,47 @@ internal static class UmbracoDatabaseExtensions return database.ExecuteScalar(query); } + + public static async Task CountAsync(this IUmbracoDatabase database, Sql sql) + { + // We need to copy the sql into a new object, to avoid this method from changing the sql. + Sql query = new Sql().Select("COUNT(*)").From().Append("(").Append(new Sql(sql.SQL, sql.Arguments)).Append(") as count_query"); + + return await database.ExecuteScalarAsync(query); + } + + public static async Task> PagedAsync( + this IUmbracoDatabase database, + Sql sql, + int skip, + int take, + Action> sortingAction, + Func mapper) + { + ArgumentOutOfRangeException.ThrowIfLessThan(skip, 0, nameof(skip)); + ArgumentOutOfRangeException.ThrowIfLessThan(take, 0, nameof(take)); + + var count = await database.CountAsync(sql); + if (take == 0 || skip >= count) + { + return new PagedModel + { + Total = count, + Items = [], + }; + } + + sortingAction(sql); + + List results = await database.SkipTakeAsync( + skip, + take, + sql); + + return new PagedModel + { + Total = count, + Items = results.Select(mapper), + }; + } } diff --git a/src/Umbraco.PublishedCache.HybridCache/DatabaseCacheRebuilder.cs b/src/Umbraco.PublishedCache.HybridCache/DatabaseCacheRebuilder.cs index 40ad248728..b61daf7f7c 100644 --- a/src/Umbraco.PublishedCache.HybridCache/DatabaseCacheRebuilder.cs +++ b/src/Umbraco.PublishedCache.HybridCache/DatabaseCacheRebuilder.cs @@ -1,12 +1,13 @@ using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; -using Umbraco.Cms.Core.Cache; +using Umbraco.Cms.Core; using Umbraco.Cms.Core.Configuration.Models; -using Umbraco.Cms.Core.HostedServices; using Umbraco.Cms.Core.Logging; +using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.PublishedCache; using Umbraco.Cms.Core.Scoping; using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Services.OperationStatus; using Umbraco.Cms.Infrastructure.HybridCache.Persistence; namespace Umbraco.Cms.Infrastructure.HybridCache; @@ -17,7 +18,7 @@ namespace Umbraco.Cms.Infrastructure.HybridCache; internal sealed class DatabaseCacheRebuilder : IDatabaseCacheRebuilder { private const string NuCacheSerializerKey = "Umbraco.Web.PublishedCache.NuCache.Serializer"; - private const string IsRebuildingDatabaseCacheRuntimeCacheKey = "temp_database_cache_rebuild_op"; + private const string RebuildOperationName = "DatabaseCacheRebuild"; private readonly IDatabaseCacheRepository _databaseCacheRepository; private readonly ICoreScopeProvider _coreScopeProvider; @@ -25,8 +26,7 @@ internal sealed class DatabaseCacheRebuilder : IDatabaseCacheRebuilder private readonly IKeyValueService _keyValueService; private readonly ILogger _logger; private readonly IProfilingLogger _profilingLogger; - private readonly IBackgroundTaskQueue _backgroundTaskQueue; - private readonly IAppPolicyCache _runtimeCache; + private readonly ILongRunningOperationService _longRunningOperationService; /// /// Initializes a new instance of the class. @@ -38,8 +38,7 @@ internal sealed class DatabaseCacheRebuilder : IDatabaseCacheRebuilder IKeyValueService keyValueService, ILogger logger, IProfilingLogger profilingLogger, - IBackgroundTaskQueue backgroundTaskQueue, - IAppPolicyCache runtimeCache) + ILongRunningOperationService longRunningOperationService) { _databaseCacheRepository = databaseCacheRepository; _coreScopeProvider = coreScopeProvider; @@ -47,65 +46,60 @@ internal sealed class DatabaseCacheRebuilder : IDatabaseCacheRebuilder _keyValueService = keyValueService; _logger = logger; _profilingLogger = profilingLogger; - _backgroundTaskQueue = backgroundTaskQueue; - _runtimeCache = runtimeCache; + _longRunningOperationService = longRunningOperationService; } /// - public bool IsRebuilding() => _runtimeCache.Get(IsRebuildingDatabaseCacheRuntimeCacheKey) is not null; + public bool IsRebuilding() => IsRebuildingAsync().GetAwaiter().GetResult(); /// + public async Task IsRebuildingAsync() + => (await _longRunningOperationService.GetByTypeAsync(RebuildOperationName, 0, 0)).Total != 0; + + /// + [Obsolete("Use the overload with the useBackgroundThread parameter. Scheduled for removal in Umbraco 17.")] public void Rebuild() => Rebuild(false); /// - public void Rebuild(bool useBackgroundThread) - { - if (useBackgroundThread) - { - _logger.LogInformation("Starting async background thread for rebuilding database cache."); - - _backgroundTaskQueue.QueueBackgroundWorkItem( - cancellationToken => - { - using (ExecutionContext.SuppressFlow()) - { - Task.Run(() => PerformRebuild()); - return Task.CompletedTask; - } - }); - } - else - { - PerformRebuild(); - } - } - - private void PerformRebuild() - { - try - { - SetIsRebuilding(); - - using ICoreScope scope = _coreScopeProvider.CreateCoreScope(); - _databaseCacheRepository.Rebuild(); - scope.Complete(); - } - finally - { - ClearIsRebuilding(); - } - } - - private void SetIsRebuilding() => _runtimeCache.Insert(IsRebuildingDatabaseCacheRuntimeCacheKey, () => "tempValue", TimeSpan.FromMinutes(10)); - - private void ClearIsRebuilding() => _runtimeCache.Clear(IsRebuildingDatabaseCacheRuntimeCacheKey); + [Obsolete("Use RebuildAsync instead. Scheduled for removal in Umbraco 18.")] + public void Rebuild(bool useBackgroundThread) => + RebuildAsync(useBackgroundThread).GetAwaiter().GetResult(); /// - public void RebuildDatabaseCacheIfSerializerChanged() + public async Task> RebuildAsync(bool useBackgroundThread) + { + Attempt attempt = await _longRunningOperationService.RunAsync( + RebuildOperationName, + _ => PerformRebuild(), + allowConcurrentExecution: false, + runInBackground: useBackgroundThread); + + if (attempt.Success) + { + return Attempt.Succeed(DatabaseCacheRebuildResult.Success); + } + + return attempt.Status switch + { + LongRunningOperationEnqueueStatus.AlreadyRunning => Attempt.Fail(DatabaseCacheRebuildResult.AlreadyRunning), + _ => throw new InvalidOperationException( + $"Unexpected status {attempt.Status} when trying to enqueue the database cache rebuild operation."), + }; + } + + /// + public void RebuildDatabaseCacheIfSerializerChanged() => + RebuildDatabaseCacheIfSerializerChangedAsync().GetAwaiter().GetResult(); + + /// + public async Task RebuildDatabaseCacheIfSerializerChangedAsync() { - using ICoreScope scope = _coreScopeProvider.CreateCoreScope(); NuCacheSerializerType serializer = _nucacheSettings.Value.NuCacheSerializerType; - var currentSerializerValue = _keyValueService.GetValue(NuCacheSerializerKey); + string? currentSerializerValue; + using (ICoreScope scope = _coreScopeProvider.CreateCoreScope(autoComplete: true)) + { + currentSerializerValue = _keyValueService.GetValue(NuCacheSerializerKey); + } if (Enum.TryParse(currentSerializerValue, out NuCacheSerializerType currentSerializer) && serializer == currentSerializer) { @@ -119,10 +113,24 @@ internal sealed class DatabaseCacheRebuilder : IDatabaseCacheRebuilder using (_profilingLogger.TraceDuration($"Rebuilding database cache with {serializer} serializer")) { - Rebuild(false); - _keyValueService.SetValue(NuCacheSerializerKey, serializer.ToString()); + await RebuildAsync(false); + } + } + + private Task PerformRebuild() + { + using ICoreScope scope = _coreScopeProvider.CreateCoreScope(); + _databaseCacheRepository.Rebuild(); + + // If the serializer type has changed, we also need to update it in the key value store. + var currentSerializerValue = _keyValueService.GetValue(NuCacheSerializerKey); + if (!Enum.TryParse(currentSerializerValue, out NuCacheSerializerType currentSerializer) || + _nucacheSettings.Value.NuCacheSerializerType != currentSerializer) + { + _keyValueService.SetValue(NuCacheSerializerKey, _nucacheSettings.Value.NuCacheSerializerType.ToString()); } scope.Complete(); + return Task.CompletedTask; } } diff --git a/src/Umbraco.PublishedCache.HybridCache/NotificationHandlers/HybridCacheStartupNotificationHandler.cs b/src/Umbraco.PublishedCache.HybridCache/NotificationHandlers/HybridCacheStartupNotificationHandler.cs index 19d524f791..43b19ab17f 100644 --- a/src/Umbraco.PublishedCache.HybridCache/NotificationHandlers/HybridCacheStartupNotificationHandler.cs +++ b/src/Umbraco.PublishedCache.HybridCache/NotificationHandlers/HybridCacheStartupNotificationHandler.cs @@ -20,13 +20,13 @@ public class HybridCacheStartupNotificationHandler : INotificationAsyncHandler RuntimeLevel.Install) + if (_runtimeState.Level <= RuntimeLevel.Install) { - _databaseCacheRebuilder.RebuildDatabaseCacheIfSerializerChanged(); + return; } - return Task.CompletedTask; + await _databaseCacheRebuilder.RebuildDatabaseCacheIfSerializerChangedAsync(); } } diff --git a/src/Umbraco.PublishedCache.HybridCache/Persistence/DatabaseCacheRepository.cs b/src/Umbraco.PublishedCache.HybridCache/Persistence/DatabaseCacheRepository.cs index 5ae2260cb8..91f8ad8e92 100644 --- a/src/Umbraco.PublishedCache.HybridCache/Persistence/DatabaseCacheRepository.cs +++ b/src/Umbraco.PublishedCache.HybridCache/Persistence/DatabaseCacheRepository.cs @@ -120,7 +120,6 @@ internal sealed class DatabaseCacheRepository : RepositoryBase, IDatabaseCacheRe RebuildContentDbCache(serializer, _nucacheSettings.Value.SqlPageSize, contentTypeIds); RebuildMediaDbCache(serializer, _nucacheSettings.Value.SqlPageSize, mediaTypeIds); RebuildMemberDbCache(serializer, _nucacheSettings.Value.SqlPageSize, memberTypeIds); - } public async Task GetContentSourceAsync(Guid key, bool preview = false) diff --git a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs index 2fd5348f4a..d0eec0039e 100644 --- a/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs +++ b/src/Umbraco.Web.Common/DependencyInjection/UmbracoBuilderExtensions.cs @@ -190,7 +190,7 @@ public static partial class UmbracoBuilderExtensions builder.Services.AddRecurringBackgroundJob(); builder.Services.AddRecurringBackgroundJob(); builder.Services.AddRecurringBackgroundJob(); - + builder.Services.AddRecurringBackgroundJob(); builder.Services.AddSingleton(RecurringBackgroundJobHostedService.CreateHostedServiceFactory); builder.Services.AddHostedService(); diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/LongRunningOperationRepositoryTests.cs b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/LongRunningOperationRepositoryTests.cs new file mode 100644 index 0000000000..2ad6d33f26 --- /dev/null +++ b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/LongRunningOperationRepositoryTests.cs @@ -0,0 +1,228 @@ +using System.Data.Common; +using NUnit.Framework; +using Umbraco.Cms.Core.Cache; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Serialization; +using Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement; +using Umbraco.Cms.Infrastructure.Scoping; +using Umbraco.Cms.Tests.Common.Testing; +using Umbraco.Cms.Tests.Integration.Testing; + +namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Persistence.Repositories; + +[TestFixture] +[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] +public class LongRunningOperationRepositoryTests : UmbracoIntegrationTest +{ + [Test] + public async Task Get_ReturnsNull_WhenOperationDoesNotExist() + { + var provider = ScopeProvider; + using var scope = provider.CreateScope(); + var repository = CreateRepository(provider); + await CreateTestData(repository); + + var result = await repository.GetAsync(Guid.NewGuid()); + Assert.IsNull(result); + } + + [Test] + public async Task Get_ReturnsExpectedOperation_WhenOperationExists() + { + var provider = ScopeProvider; + using var scope = provider.CreateScope(); + var repository = CreateRepository(provider); + await CreateTestData(repository); + + var testOperation = _operations[1]; + var result = await repository.GetAsync(testOperation.Operation.Id); + + Assert.IsNotNull(result); + Assert.AreEqual(testOperation.Operation.Id, result.Id); + Assert.AreEqual(testOperation.Operation.Type, result.Type); + Assert.AreEqual(testOperation.Operation.Status, result.Status); + } + + [TestCase("Test", new LongRunningOperationStatus[] { }, 0, 100, 5, 5)] + [TestCase("Test", new[] { LongRunningOperationStatus.Enqueued }, 0, 100, 1, 1)] + [TestCase("Test", new[] { LongRunningOperationStatus.Running }, 0, 100, 1, 1)] + [TestCase("Test", new[] { LongRunningOperationStatus.Enqueued, LongRunningOperationStatus.Running }, 0, 100, 2, 2)] + [TestCase("Test", new[] { LongRunningOperationStatus.Stale }, 0, 100, 1, 1)] + [TestCase("Test", new[] { LongRunningOperationStatus.Running, LongRunningOperationStatus.Stale }, 0, 100, 2, 2)] + [TestCase("Test", new[] { LongRunningOperationStatus.Success, LongRunningOperationStatus.Stale }, 0, 100, 2, 2)] + [TestCase("AnotherTest", new LongRunningOperationStatus[] { }, 0, 100, 1, 1)] + [TestCase("Test", new LongRunningOperationStatus[] { }, 0, 0, 0, 5)] + [TestCase("Test", new LongRunningOperationStatus[] { }, 0, 1, 1, 5)] + [TestCase("Test", new LongRunningOperationStatus[] { }, 2, 2, 2, 5)] + [TestCase("Test", new LongRunningOperationStatus[] { }, 5, 1, 0, 5)] + public async Task GetByType_ReturnsExpectedOperations(string type, LongRunningOperationStatus[] statuses, int skip, int take, int expectedCount, int expectedTotal) + { + var provider = ScopeProvider; + using var scope = provider.CreateScope(); + var repository = CreateRepository(provider); + await CreateTestData(repository); + + var result = await repository.GetByTypeAsync(type, statuses, skip, take); + + Assert.IsNotNull(result); + Assert.AreEqual(expectedCount, result.Items.Count(), "Count of returned items should match the expected count"); + Assert.AreEqual(expectedTotal, result.Total, "Total count should match the expected total count"); + } + + [Test] + public async Task GetStatus_ReturnsNull_WhenOperationDoesNotExist() + { + var provider = ScopeProvider; + using var scope = provider.CreateScope(); + var repository = CreateRepository(provider); + await CreateTestData(repository); + + var result = await repository.GetStatusAsync(Guid.NewGuid()); + Assert.IsNull(result); + } + + [Test] + public async Task GetStatus_ReturnsExpectedStatus_WhenOperationExists() + { + var provider = ScopeProvider; + using var scope = provider.CreateScope(); + var repository = CreateRepository(provider); + await CreateTestData(repository); + + var result = await repository.GetStatusAsync(_operations[0].Operation.Id); + Assert.AreEqual(_operations[0].Operation.Status, result); + } + + [Test] + public async Task Create_InsertsOperationIntoDatabase() + { + var provider = ScopeProvider; + using var scope = provider.CreateScope(); + var repository = CreateRepository(provider); + await CreateTestData(repository); + + var newOperation = new LongRunningOperation + { + Id = Guid.NewGuid(), + Type = "NewTest", + Status = LongRunningOperationStatus.Enqueued, + }; + await repository.CreateAsync(newOperation, DateTimeOffset.UtcNow.AddMinutes(5)); + + var result = await repository.GetAsync(newOperation.Id); + Assert.IsNotNull(result); + Assert.AreEqual(newOperation.Id, result.Id); + Assert.AreEqual(newOperation.Type, result.Type); + Assert.AreEqual(newOperation.Status, result.Status); + } + + [Test] + public async Task Create_ThrowsException_WhenOperationWithTheSameIdExists() + { + var provider = ScopeProvider; + using var scope = provider.CreateScope(); + var repository = CreateRepository(provider); + await CreateTestData(repository); + + var newOperation = new LongRunningOperation + { + Id = _operations[0].Operation.Id, + Type = "NewTest", + Status = LongRunningOperationStatus.Enqueued, + }; + Assert.ThrowsAsync(Is.InstanceOf(), () => repository.CreateAsync(newOperation, DateTimeOffset.UtcNow.AddMinutes(5))); + } + + [Test] + public async Task UpdateStatus_UpdatesOperationStatusInDatabase() + { + var provider = ScopeProvider; + using var scope = provider.CreateScope(); + var repository = CreateRepository(provider); + await CreateTestData(repository); + + var testOperation = _operations[1]; + repository.UpdateStatusAsync(testOperation.Operation.Id, LongRunningOperationStatus.Failed, DateTimeOffset.UtcNow); + + var result = await repository.GetAsync(testOperation.Operation.Id); + Assert.IsNotNull(result); + Assert.AreEqual(LongRunningOperationStatus.Failed, result.Status); + } + + [Test] + public async Task SetResult_UpdatesOperationResultInDatabase() + { + var provider = ScopeProvider; + using var scope = provider.CreateScope(); + var repository = CreateRepository(provider); + await CreateTestData(repository); + + var testOperation = _operations[1]; + var opResult = new LongRunningOperationResult { Result = true }; + await repository.SetResultAsync(testOperation.Operation.Id, opResult); + + var result = await repository.GetAsync(testOperation.Operation.Id); + Assert.IsNotNull(result); + Assert.IsNotNull(result.Result); + Assert.AreEqual(opResult.Result, result.Result.Result); + } + + [Test] + public async Task CleanOperations_RemovesOldOperationsFromTheDatabase() + { + var provider = ScopeProvider; + using var scope = provider.CreateScope(); + var repository = CreateRepository(provider); + await CreateTestData(repository); + + var oldOperation = _operations[0]; + + // Check that the operation is present before cleaning + var result = await repository.GetAsync(oldOperation.Operation.Id); + Assert.IsNotNull(result); + + await repository.CleanOperationsAsync(DateTimeOffset.UtcNow.AddMinutes(1)); + + // Check that the operation is removed after cleaning + result = await repository.GetAsync(oldOperation.Operation.Id); + Assert.IsNull(result); + } + + private LongRunningOperationRepository CreateRepository(IScopeProvider provider) + => new(GetRequiredService(), (IScopeAccessor)provider, AppCaches.Disabled, TimeProvider.System); + + private async Task CreateTestData(LongRunningOperationRepository repository) + { + foreach (var op in _operations) + { + await repository.CreateAsync(op.Operation, op.ExpiresIn); + } + } + + private readonly List<(LongRunningOperation Operation, DateTimeOffset ExpiresIn)> _operations = + [ + ( + Operation: new LongRunningOperation { Id = Guid.NewGuid(), Type = "Test", Status = LongRunningOperationStatus.Success }, + ExpiresIn: DateTimeOffset.UtcNow.AddMinutes(5)), + ( + Operation: new LongRunningOperation { Id = Guid.NewGuid(), Type = "Test", Status = LongRunningOperationStatus.Enqueued }, + ExpiresIn: DateTimeOffset.UtcNow.AddMinutes(5)), + ( + Operation: new LongRunningOperation { Id = Guid.NewGuid(), Type = "Test", Status = LongRunningOperationStatus.Running }, + ExpiresIn: DateTimeOffset.UtcNow.AddMinutes(5)), + ( + Operation: new LongRunningOperation { Id = Guid.NewGuid(), Type = "Test", Status = LongRunningOperationStatus.Running }, + ExpiresIn: DateTimeOffset.UtcNow.AddMinutes(-1)), + ( + Operation: new LongRunningOperation { Id = Guid.NewGuid(), Type = "Test", Status = LongRunningOperationStatus.Failed }, + ExpiresIn: DateTimeOffset.UtcNow.AddMinutes(-1)), + ( + Operation: new LongRunningOperation { Id = Guid.NewGuid(), Type = "AnotherTest", Status = LongRunningOperationStatus.Success, }, + ExpiresIn: DateTimeOffset.UtcNow.AddMinutes(5)), + ]; + + private class LongRunningOperationResult + { + public bool Result { get; init; } + } +} diff --git a/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Services/LongRunningOperationServiceTests.cs b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Services/LongRunningOperationServiceTests.cs new file mode 100644 index 0000000000..4174f1235e --- /dev/null +++ b/tests/Umbraco.Tests.UnitTests/Umbraco.Core/Services/LongRunningOperationServiceTests.cs @@ -0,0 +1,417 @@ +using System.Data; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Moq; +using NUnit.Framework; +using Umbraco.Cms.Core.Configuration.Models; +using Umbraco.Cms.Core.Events; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Persistence.Repositories; +using Umbraco.Cms.Core.Scoping; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Services.OperationStatus; + +namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Services; + +[TestFixture] +public class LongRunningOperationServiceTests +{ + private ILongRunningOperationService _longRunningOperationService; + private Mock _scopeProviderMock; + private Mock _longRunningOperationRepositoryMock; + private Mock _timeProviderMock; + private Mock _scopeMock; + + [SetUp] + public void Setup() + { + _scopeProviderMock = new Mock(MockBehavior.Strict); + _longRunningOperationRepositoryMock = new Mock(MockBehavior.Strict); + _timeProviderMock = new Mock(MockBehavior.Strict); + _scopeMock = new Mock(); + + _longRunningOperationService = new LongRunningOperationService( + Options.Create(new LongRunningOperationsSettings()), + _longRunningOperationRepositoryMock.Object, + _scopeProviderMock.Object, + _timeProviderMock.Object, + Mock.Of>()); + } + + [Test] + public async Task Run_ReturnsFailedAttempt_WhenOperationIsAlreadyRunning() + { + SetupScopeProviderMock(); + _longRunningOperationRepositoryMock + .Setup(repo => repo.GetByTypeAsync("Test", It.IsAny(), 0, 0)) + .Callback((_, statuses, _, _) => + { + Assert.AreEqual(2, statuses.Length); + Assert.Contains(LongRunningOperationStatus.Enqueued, statuses); + Assert.Contains(LongRunningOperationStatus.Running, statuses); + }) + .ReturnsAsync( + new PagedModel + { + Total = 1, + Items = new List { new() { Id = Guid.NewGuid(), Type = "Test", Status = LongRunningOperationStatus.Running } }, + }) + .Verifiable(Times.Once); + + var result = await _longRunningOperationService.RunAsync( + "Test", + _ => Task.CompletedTask, + allowConcurrentExecution: false, + runInBackground: true); + + _longRunningOperationRepositoryMock.VerifyAll(); + + Assert.IsFalse(result.Success); + Assert.AreEqual(LongRunningOperationEnqueueStatus.AlreadyRunning, result.Status); + } + + [Test] + public async Task Run_CreatesAndRunsOperation_WhenNotInBackground() + { + SetupScopeProviderMock(); + + _timeProviderMock.Setup(repo => repo.GetUtcNow()) + .Returns(() => DateTime.UtcNow) + .Verifiable(Times.Exactly(2)); + + _longRunningOperationRepositoryMock + .Setup(repo => repo.CreateAsync(It.IsAny(), It.IsAny())) + .Callback((op, exp) => + { + Assert.AreEqual("Test", op.Type); + Assert.IsNotNull(op.Id); + Assert.AreEqual(LongRunningOperationStatus.Enqueued, op.Status); + }) + .Returns(Task.CompletedTask) + .Verifiable(Times.Once); + + _scopeProviderMock.Setup(scopeProvider => scopeProvider.Context) + .Returns(default(IScopeContext?)) + .Verifiable(Times.Exactly(1)); + + var expectedStatuses = new List + { + LongRunningOperationStatus.Enqueued, + LongRunningOperationStatus.Running, + LongRunningOperationStatus.Success, + }; + + _longRunningOperationRepositoryMock.Setup(repo => repo.UpdateStatusAsync(It.IsAny(), It.IsAny(), It.IsAny())) + .Callback((id, status, exp) => + { + Assert.Contains(status, expectedStatuses); + }) + .Returns(Task.CompletedTask); + + var opCalls = 0; + var result = await _longRunningOperationService.RunAsync( + "Test", + _ => + { + opCalls++; + return Task.CompletedTask; + }, + allowConcurrentExecution: true, + runInBackground: false); + + _longRunningOperationRepositoryMock.VerifyAll(); + + Assert.IsTrue(result.Success); + Assert.AreEqual(LongRunningOperationEnqueueStatus.Success, result.Status); + Assert.AreEqual(1, opCalls, "Operation should have run and increased the call count, since it's not configured to run in the background."); + } + + [Test] + public void Run_ThrowsException_WhenAttemptingToRunOperationNotInBackgroundInsideAScope() + { + SetupScopeProviderMock(); + + _scopeProviderMock.Setup(scopeProvider => scopeProvider.Context) + .Returns(new ScopeContext()) + .Verifiable(Times.Exactly(1)); + + var opCalls = 0; + Assert.ThrowsAsync(async () => await _longRunningOperationService.RunAsync( + "Test", + _ => + { + opCalls++; + return Task.CompletedTask; + }, + allowConcurrentExecution: true, + runInBackground: false)); + Assert.AreEqual(0, opCalls, "The operation should not have been called."); + } + + [Test] + public async Task Run_CreatesAndQueuesOperation_WhenInBackground() + { + SetupScopeProviderMock(); + + _timeProviderMock.Setup(repo => repo.GetUtcNow()) + .Returns(() => DateTime.UtcNow) + .Verifiable(Times.Exactly(2)); + + _longRunningOperationRepositoryMock + .Setup(repo => repo.CreateAsync(It.IsAny(), It.IsAny())) + .Callback((op, exp) => + { + Assert.AreEqual("Test", op.Type); + Assert.IsNotNull(op.Id); + Assert.AreEqual(LongRunningOperationStatus.Enqueued, op.Status); + }) + .Returns(Task.CompletedTask) + .Verifiable(Times.Once); + + var result = await _longRunningOperationService.RunAsync( + "Test", + _ => Task.CompletedTask, + allowConcurrentExecution: true, + runInBackground: true); + + _longRunningOperationRepositoryMock.VerifyAll(); + + Assert.IsTrue(result.Success); + Assert.AreEqual(LongRunningOperationEnqueueStatus.Success, result.Status); + } + + [Test] + public async Task GetStatus_ReturnsExpectedStatus_WhenOperationExists() + { + SetupScopeProviderMock(); + var operationId = Guid.NewGuid(); + _longRunningOperationRepositoryMock + .Setup(repo => repo.GetStatusAsync(operationId)) + .ReturnsAsync(LongRunningOperationStatus.Running) + .Verifiable(Times.Once); + + var status = await _longRunningOperationService.GetStatusAsync(operationId); + + _longRunningOperationRepositoryMock.VerifyAll(); + Assert.IsTrue(status.HasValue); + Assert.AreEqual(LongRunningOperationStatus.Running, status.Value); + } + + [Test] + public async Task GetStatus_ReturnsNull_WhenOperationDoesNotExist() + { + SetupScopeProviderMock(); + var operationId = Guid.NewGuid(); + _longRunningOperationRepositoryMock + .Setup(repo => repo.GetStatusAsync(operationId)) + .ReturnsAsync((LongRunningOperationStatus?)null) + .Verifiable(Times.Once); + + var status = await _longRunningOperationService.GetStatusAsync(operationId); + + _longRunningOperationRepositoryMock.VerifyAll(); + Assert.IsFalse(status.HasValue); + } + + [Test] + public async Task GetByType_ReturnsExpectedOperations_WhenOperationsExist() + { + SetupScopeProviderMock(); + const string operationType = "Test"; + var operations = new List + { + new() { Id = Guid.NewGuid(), Type = operationType, Status = LongRunningOperationStatus.Running }, + new() { Id = Guid.NewGuid(), Type = operationType, Status = LongRunningOperationStatus.Enqueued }, + }; + _longRunningOperationRepositoryMock + .Setup(repo => repo.GetByTypeAsync(operationType, It.IsAny(), 0, 100)) + .Callback((_, statuses, _, _) => + { + Assert.AreEqual(2, statuses.Length); + Assert.Contains(LongRunningOperationStatus.Enqueued, statuses); + Assert.Contains(LongRunningOperationStatus.Running, statuses); + }) + .ReturnsAsync( + new PagedModel + { + Total = 2, + Items = operations, + }) + .Verifiable(Times.Once); + + var result = await _longRunningOperationService.GetByTypeAsync(operationType, 0, 100); + + _longRunningOperationRepositoryMock.VerifyAll(); + Assert.IsNotNull(result); + Assert.AreEqual(2, result.Items.Count()); + Assert.AreEqual(2, result.Total); + Assert.IsTrue(result.Items.All(op => op.Type == operationType)); + } + + [Test] + public async Task GetByType_ReturnsExpectedOperations_WhenOperationsExistWithProvidedStatuses() + { + SetupScopeProviderMock(); + const string operationType = "Test"; + var operations = new List + { + new() { Id = Guid.NewGuid(), Type = operationType, Status = LongRunningOperationStatus.Failed }, + }; + _longRunningOperationRepositoryMock + .Setup(repo => repo.GetByTypeAsync(operationType, It.IsAny(), 0, 30)) + .Callback((type, statuses, _, _) => + { + Assert.AreEqual(1, statuses.Length); + Assert.Contains(LongRunningOperationStatus.Failed, statuses); + }) + .ReturnsAsync( + new PagedModel + { + Total = 1, + Items = operations, + }) + .Verifiable(Times.Once); + + var result = await _longRunningOperationService.GetByTypeAsync(operationType, 0, 30, [LongRunningOperationStatus.Failed]); + + _longRunningOperationRepositoryMock.VerifyAll(); + Assert.IsNotNull(result); + Assert.AreEqual(1, result.Total); + Assert.AreEqual(1, result.Items.Count()); + Assert.IsTrue(result.Items.All(op => op.Type == operationType)); + } + + [Test] + public async Task GetResult_ReturnsExpectedResult_WhenOperationExists() + { + SetupScopeProviderMock(); + const string operationType = "Test"; + var operationId = Guid.NewGuid(); + const string expectedResult = "TestResult"; + _longRunningOperationRepositoryMock + .Setup(repo => repo.GetAsync(operationId)) + .ReturnsAsync( + new LongRunningOperation + { + Id = operationId, + Type = operationType, + Status = LongRunningOperationStatus.Success, + Result = expectedResult, + }) + .Verifiable(Times.Once); + + var result = await _longRunningOperationService.GetResultAsync(operationId); + + _longRunningOperationRepositoryMock.VerifyAll(); + Assert.IsTrue(result.Success); + Assert.AreEqual(LongRunningOperationResultStatus.Success, result.Status); + Assert.AreEqual(expectedResult, result.Result); + } + + [Test] + public async Task GetResult_ReturnsFailedAttempt_WhenOperationDoesNotExist() + { + SetupScopeProviderMock(); + var operationId = Guid.NewGuid(); + _longRunningOperationRepositoryMock + .Setup(repo => repo.GetAsync(operationId)) + .ReturnsAsync(default(LongRunningOperation)) + .Verifiable(Times.Once); + + var result = await _longRunningOperationService.GetResultAsync(operationId); + + _longRunningOperationRepositoryMock.VerifyAll(); + Assert.IsFalse(result.Success); + Assert.AreEqual(result.Status, LongRunningOperationResultStatus.OperationNotFound); + Assert.IsNull(result.Result); + } + + [Test] + public async Task GetResult_ReturnsFailedAttempt_WhenOperationFailed() + { + SetupScopeProviderMock(); + const string operationType = "Test"; + var operationId = Guid.NewGuid(); + _longRunningOperationRepositoryMock + .Setup(repo => repo.GetAsync(operationId)) + .ReturnsAsync( + new LongRunningOperation + { + Id = operationId, + Type = operationType, + Status = LongRunningOperationStatus.Failed, + }) + .Verifiable(Times.Once); + + var result = await _longRunningOperationService.GetResultAsync(operationId); + + _longRunningOperationRepositoryMock.VerifyAll(); + Assert.IsFalse(result.Success); + Assert.AreEqual(result.Status, LongRunningOperationResultStatus.OperationFailed); + Assert.IsNull(result.Result); + } + + [Test] + public async Task GetResult_ReturnsFailedAttempt_WhenOperationIsRunning() + { + SetupScopeProviderMock(); + const string operationType = "Test"; + var operationId = Guid.NewGuid(); + _longRunningOperationRepositoryMock + .Setup(repo => repo.GetAsync(operationId)) + .ReturnsAsync( + new LongRunningOperation + { + Id = operationId, + Type = operationType, + Status = LongRunningOperationStatus.Running, + }) + .Verifiable(Times.Once); + + var result = await _longRunningOperationService.GetResultAsync(operationId); + + _longRunningOperationRepositoryMock.VerifyAll(); + Assert.IsFalse(result.Success); + Assert.AreEqual(result.Status, LongRunningOperationResultStatus.OperationPending); + Assert.IsNull(result.Result); + } + + [Test] + public async Task GetResult_ReturnsFailedAttempt_WhenOperationIsEnqueued() + { + SetupScopeProviderMock(); + const string operationType = "Test"; + var operationId = Guid.NewGuid(); + _longRunningOperationRepositoryMock + .Setup(repo => repo.GetAsync(operationId)) + .ReturnsAsync( + new LongRunningOperation + { + Id = operationId, + Type = operationType, + Status = LongRunningOperationStatus.Enqueued, + }) + .Verifiable(Times.Once); + + var result = await _longRunningOperationService.GetResultAsync(operationId); + + _longRunningOperationRepositoryMock.VerifyAll(); + Assert.IsFalse(result.Success); + Assert.AreEqual(result.Status, LongRunningOperationResultStatus.OperationPending); + Assert.IsNull(result.Result); + } + + private void SetupScopeProviderMock() => + _scopeProviderMock + .Setup(x => x.CreateCoreScope( + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny(), + It.IsAny())) + .Returns(_scopeMock.Object); +} + +