From f26e5d12a025b9d0101644afd695d9307bac2585 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Thu, 13 Apr 2023 14:58:16 +0200 Subject: [PATCH] Management API: Data type or property is used endpoints (#14078) * Added is-used endpoints * Updated CompatibilitySuppressions.xml * Minor cleanup * Fix issue where only document types was supported. Now also media and member types is supported * CompatibilitySuppressions.xml --------- Co-authored-by: Nikolaj --- .../DataType/IsUsedDataTypeController.cs | 33 +++++++++++ .../IsUsedPropertyTypeController.cs | 31 ++++++++++ .../PropertyTypeControllerBase.cs | 20 +++++++ .../CompatibilitySuppressions.xml | 36 ++++++++++++ .../Repositories/IDataTypeUsageRepository.cs | 2 + .../IPropertyTypeUsageRepository.cs | 3 + .../Services/DataTypeUsageService.cs | 34 +++++++++++ .../Services/IDataTypeUsageService.cs | 12 +++- .../Services/IPropertyTypeUsageService.cs | 11 ++++ .../PropertyTypeOperationStatus.cs | 7 +++ .../Services/PropertyTypeUsageService.cs | 34 +++++++++++ .../CompatibilitySuppressions.xml | 1 + .../Implement/DataTypeUsageRepository.cs | 25 ++++++++ .../Implement/PropertyTypeUsageRepository.cs | 57 ++++++++++++++++++- .../CompatibilitySuppressions.xml | 1 + .../CompatibilitySuppressions.xml | 1 + 16 files changed, 304 insertions(+), 4 deletions(-) create mode 100644 src/Umbraco.Cms.Api.Management/Controllers/DataType/IsUsedDataTypeController.cs create mode 100644 src/Umbraco.Cms.Api.Management/Controllers/PropertyType/IsUsedPropertyTypeController.cs create mode 100644 src/Umbraco.Cms.Api.Management/Controllers/PropertyType/PropertyTypeControllerBase.cs create mode 100644 src/Umbraco.Core/Services/OperationStatus/PropertyTypeOperationStatus.cs diff --git a/src/Umbraco.Cms.Api.Management/Controllers/DataType/IsUsedDataTypeController.cs b/src/Umbraco.Cms.Api.Management/Controllers/DataType/IsUsedDataTypeController.cs new file mode 100644 index 0000000000..c1fbb4f34d --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/Controllers/DataType/IsUsedDataTypeController.cs @@ -0,0 +1,33 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Umbraco.Cms.Api.Management.ViewModels.DataType; +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Mapping; +using Umbraco.Cms.Core.Models; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Services.OperationStatus; + +namespace Umbraco.Cms.Api.Management.Controllers.DataType; + +public class IsUsedDataTypeController : DataTypeControllerBase +{ + private readonly IDataTypeUsageService _dataTypeUsageService; + + public IsUsedDataTypeController(IDataTypeUsageService dataTypeUsageService) + { + _dataTypeUsageService = dataTypeUsageService; + } + + [HttpGet("{id:guid}/is-used")] + [MapToApiVersion("1.0")] + [ProducesResponseType(typeof(bool), StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status404NotFound)] + public async Task IsUsed(Guid id) + { + Attempt result = await _dataTypeUsageService.HasSavedValuesAsync(id); + + return result.Success + ? Ok(result.Result) + : DataTypeOperationStatusResult(result.Status); + } +} diff --git a/src/Umbraco.Cms.Api.Management/Controllers/PropertyType/IsUsedPropertyTypeController.cs b/src/Umbraco.Cms.Api.Management/Controllers/PropertyType/IsUsedPropertyTypeController.cs new file mode 100644 index 0000000000..e09d3ebf93 --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/Controllers/PropertyType/IsUsedPropertyTypeController.cs @@ -0,0 +1,31 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Umbraco.Cms.Api.Common.ViewModels.Pagination; +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Services.OperationStatus; + +namespace Umbraco.Cms.Api.Management.Controllers.PropertyType; + +public class IsUsedPropertyTypeController : PropertyTypeControllerBase +{ + private readonly IPropertyTypeUsageService _propertyTypeUsageService; + + public IsUsedPropertyTypeController(IPropertyTypeUsageService propertyTypeUsageService) + { + _propertyTypeUsageService = propertyTypeUsageService; + } + + [HttpGet("is-used")] + [MapToApiVersion("1.0")] + [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)] + [ProducesResponseType(typeof(PagedViewModel), StatusCodes.Status200OK)] + public async Task Get(Guid contentTypeId, string propertyAlias) + { + Attempt result = await _propertyTypeUsageService.HasSavedPropertyValuesAsync(contentTypeId, propertyAlias); + + return result.Success + ? Ok(result.Result) + : PropertyTypeOperationStatusResult(result.Status); + } +} diff --git a/src/Umbraco.Cms.Api.Management/Controllers/PropertyType/PropertyTypeControllerBase.cs b/src/Umbraco.Cms.Api.Management/Controllers/PropertyType/PropertyTypeControllerBase.cs new file mode 100644 index 0000000000..e003b039b9 --- /dev/null +++ b/src/Umbraco.Cms.Api.Management/Controllers/PropertyType/PropertyTypeControllerBase.cs @@ -0,0 +1,20 @@ +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Umbraco.Cms.Api.Management.Routing; +using Umbraco.Cms.Core.Services.OperationStatus; + +namespace Umbraco.Cms.Api.Management.Controllers.PropertyType; + +[ApiController] +[VersionedApiBackOfficeRoute("property-type")] +[ApiExplorerSettings(GroupName = "Property Type")] +[ApiVersion("1.0")] +public abstract class PropertyTypeControllerBase : ManagementApiControllerBase +{ + protected IActionResult PropertyTypeOperationStatusResult(PropertyTypeOperationStatus status) => + status switch + { + PropertyTypeOperationStatus.ContentTypeNotFound => NotFound("The content type was not found."), + _ => StatusCode(StatusCodes.Status500InternalServerError, "Unknown data type operation status") + }; +} diff --git a/src/Umbraco.Core/CompatibilitySuppressions.xml b/src/Umbraco.Core/CompatibilitySuppressions.xml index b11593e5d0..a554c1d785 100644 --- a/src/Umbraco.Core/CompatibilitySuppressions.xml +++ b/src/Umbraco.Core/CompatibilitySuppressions.xml @@ -1,4 +1,5 @@  + CP0001 @@ -868,6 +869,27 @@ lib/net7.0/Umbraco.Core.dll true + + CP0006 + M:Umbraco.Cms.Core.Persistence.Repositories.IDataTypeUsageRepository.HasSavedValuesAsync(System.Guid) + lib/net7.0/Umbraco.Core.dll + lib/net7.0/Umbraco.Core.dll + true + + + CP0006 + M:Umbraco.Cms.Core.Persistence.Repositories.IPropertyTypeUsageRepository.ContentTypeExistAsync(System.Guid) + lib/net7.0/Umbraco.Core.dll + lib/net7.0/Umbraco.Core.dll + true + + + CP0006 + M:Umbraco.Cms.Core.Persistence.Repositories.IPropertyTypeUsageRepository.HasSavedPropertyValuesAsync(System.Guid,System.String) + lib/net7.0/Umbraco.Core.dll + lib/net7.0/Umbraco.Core.dll + true + CP0006 M:Umbraco.Cms.Core.Persistence.Repositories.ITrackedReferencesRepository.GetPagedDescendantsInReferences(System.Guid,System.Int64,System.Int64,System.Boolean,System.Int64@) @@ -1036,6 +1058,13 @@ lib/net7.0/Umbraco.Core.dll true + + CP0006 + M:Umbraco.Cms.Core.Services.IDataTypeUsageService.HasSavedValuesAsync(System.Guid) + lib/net7.0/Umbraco.Core.dll + lib/net7.0/Umbraco.Core.dll + true + CP0006 M:Umbraco.Cms.Core.Services.IDomainService.GetAllAsync(System.Boolean) @@ -1169,6 +1198,13 @@ lib/net7.0/Umbraco.Core.dll true + + CP0006 + M:Umbraco.Cms.Core.Services.IPropertyTypeUsageService.HasSavedPropertyValuesAsync(System.Guid,System.String) + lib/net7.0/Umbraco.Core.dll + lib/net7.0/Umbraco.Core.dll + true + CP0006 M:Umbraco.Cms.Core.Services.IRelationService.CreateAsync(Umbraco.Cms.Core.Models.IRelationType,System.Guid) diff --git a/src/Umbraco.Core/Persistence/Repositories/IDataTypeUsageRepository.cs b/src/Umbraco.Core/Persistence/Repositories/IDataTypeUsageRepository.cs index ed52e4fb3f..3c3b00e479 100644 --- a/src/Umbraco.Core/Persistence/Repositories/IDataTypeUsageRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/IDataTypeUsageRepository.cs @@ -2,5 +2,7 @@ namespace Umbraco.Cms.Core.Persistence.Repositories; public interface IDataTypeUsageRepository { + [Obsolete("Please use HasSavedValuesAsync. Scheduled for removable in Umbraco 15.")] bool HasSavedValues(int dataTypeId); + Task HasSavedValuesAsync(Guid dataTypeKey); } diff --git a/src/Umbraco.Core/Persistence/Repositories/IPropertyTypeUsageRepository.cs b/src/Umbraco.Core/Persistence/Repositories/IPropertyTypeUsageRepository.cs index d6f1053122..fd34c3e7e8 100644 --- a/src/Umbraco.Core/Persistence/Repositories/IPropertyTypeUsageRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/IPropertyTypeUsageRepository.cs @@ -2,5 +2,8 @@ namespace Umbraco.Cms.Core.Persistence.Repositories; public interface IPropertyTypeUsageRepository { + [Obsolete("Please use HasSavedPropertyValuesAsync. Scheduled for removable in Umbraco 15.")] bool HasSavedPropertyValues(string propertyTypeAlias); + Task HasSavedPropertyValuesAsync(Guid contentTypeKey, string propertyAlias); + Task ContentTypeExistAsync(Guid contentTypeKey); } diff --git a/src/Umbraco.Core/Services/DataTypeUsageService.cs b/src/Umbraco.Core/Services/DataTypeUsageService.cs index 1a6182037e..9773ec2a32 100644 --- a/src/Umbraco.Core/Services/DataTypeUsageService.cs +++ b/src/Umbraco.Core/Services/DataTypeUsageService.cs @@ -1,25 +1,59 @@ +using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.DependencyInjection; +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; public class DataTypeUsageService : IDataTypeUsageService { private readonly IDataTypeUsageRepository _dataTypeUsageRepository; + private readonly IDataTypeService _dataTypeService; private readonly ICoreScopeProvider _scopeProvider; + + [Obsolete("Use non-obsolete constructor. This will be removed in Umbraco 15.")] public DataTypeUsageService( IDataTypeUsageRepository dataTypeUsageRepository, ICoreScopeProvider scopeProvider) + : this(dataTypeUsageRepository, StaticServiceProvider.Instance.GetRequiredService(), scopeProvider) + { + } + + public DataTypeUsageService( + IDataTypeUsageRepository dataTypeUsageRepository, + IDataTypeService dataTypeService, + ICoreScopeProvider scopeProvider) { _dataTypeUsageRepository = dataTypeUsageRepository; + _dataTypeService = dataTypeService; _scopeProvider = scopeProvider; } /// + [Obsolete("Please use HasSavedValuesAsync. Scheduled for removable in Umbraco 15.")] public bool HasSavedValues(int dataTypeId) { using ICoreScope scope = _scopeProvider.CreateCoreScope(autoComplete: true); + return _dataTypeUsageRepository.HasSavedValues(dataTypeId); } + + /// + public async Task> HasSavedValuesAsync(Guid dataTypeKey) + { + using ICoreScope scope = _scopeProvider.CreateCoreScope(autoComplete: true); + + IDataType? dataType = await _dataTypeService.GetAsync(dataTypeKey); + if (dataType is null) + { + return Attempt.FailWithStatus(DataTypeOperationStatus.NotFound, false); + } + + var hasSavedValues = await _dataTypeUsageRepository.HasSavedValuesAsync(dataTypeKey); + + return Attempt.SucceedWithStatus(DataTypeOperationStatus.Success, hasSavedValues); + } } diff --git a/src/Umbraco.Core/Services/IDataTypeUsageService.cs b/src/Umbraco.Core/Services/IDataTypeUsageService.cs index 2514c9bef9..c7bb2e7636 100644 --- a/src/Umbraco.Core/Services/IDataTypeUsageService.cs +++ b/src/Umbraco.Core/Services/IDataTypeUsageService.cs @@ -1,11 +1,17 @@ +using Umbraco.Cms.Core.Services.OperationStatus; + namespace Umbraco.Cms.Core.Services; public interface IDataTypeUsageService { + + [Obsolete("Please use HasSavedValuesAsync. Scheduled for removable in Umbraco 15.")] + bool HasSavedValues(int dataTypeId); + /// /// Checks if there are any saved property values using a given data type. /// - /// The ID of the data type to check. - /// True if there are any property values using the data type, otherwise false. - bool HasSavedValues(int dataTypeId); + /// The key of the data type to check. + /// An attempt with status and result if there are any property values using the data type, otherwise false. + Task> HasSavedValuesAsync(Guid dataTypeKey); } diff --git a/src/Umbraco.Core/Services/IPropertyTypeUsageService.cs b/src/Umbraco.Core/Services/IPropertyTypeUsageService.cs index 231e535cc4..088d3b037b 100644 --- a/src/Umbraco.Core/Services/IPropertyTypeUsageService.cs +++ b/src/Umbraco.Core/Services/IPropertyTypeUsageService.cs @@ -1,3 +1,5 @@ +using Umbraco.Cms.Core.Services.OperationStatus; + namespace Umbraco.Cms.Core.Services; public interface IPropertyTypeUsageService @@ -7,5 +9,14 @@ public interface IPropertyTypeUsageService /// /// The alias of the property type to check. /// True if the property type has any property values, otherwise false. + [Obsolete("Please use HasSavedPropertyValuesAsync. Scheduled for removable in Umbraco 15.")] bool HasSavedPropertyValues(string propertyTypeAlias); + + /// + /// Checks if a property type has any saved property values associated with it. + /// + /// The key of the content type to check. + /// The alias of the property to check. + /// An attempt with status and result if the property type has any property values, otherwise false. + Task> HasSavedPropertyValuesAsync(Guid contentTypeKey, string propertyAlias); } diff --git a/src/Umbraco.Core/Services/OperationStatus/PropertyTypeOperationStatus.cs b/src/Umbraco.Core/Services/OperationStatus/PropertyTypeOperationStatus.cs new file mode 100644 index 0000000000..fe36f61b79 --- /dev/null +++ b/src/Umbraco.Core/Services/OperationStatus/PropertyTypeOperationStatus.cs @@ -0,0 +1,7 @@ +namespace Umbraco.Cms.Core.Services.OperationStatus; + +public enum PropertyTypeOperationStatus +{ + Success, + ContentTypeNotFound, +} diff --git a/src/Umbraco.Core/Services/PropertyTypeUsageService.cs b/src/Umbraco.Core/Services/PropertyTypeUsageService.cs index 4e6c273a91..3b9bba53ef 100644 --- a/src/Umbraco.Core/Services/PropertyTypeUsageService.cs +++ b/src/Umbraco.Core/Services/PropertyTypeUsageService.cs @@ -1,25 +1,59 @@ +using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.DependencyInjection; using Umbraco.Cms.Core.Persistence.Repositories; using Umbraco.Cms.Core.Scoping; +using Umbraco.Cms.Core.Services.OperationStatus; namespace Umbraco.Cms.Core.Services; public class PropertyTypeUsageService : IPropertyTypeUsageService { private readonly IPropertyTypeUsageRepository _propertyTypeUsageRepository; + private readonly IContentTypeService _contentTypeService; private readonly ICoreScopeProvider _scopeProvider; + [Obsolete("Use non-obsolete constructor. This will be removed in Umbraco 15.")] + public PropertyTypeUsageService( + IPropertyTypeUsageRepository propertyTypeUsageRepository, + ICoreScopeProvider scopeProvider): this(propertyTypeUsageRepository, StaticServiceProvider.Instance.GetRequiredService(), scopeProvider) + { + + } + public PropertyTypeUsageService( IPropertyTypeUsageRepository propertyTypeUsageRepository, + IContentTypeService contentTypeService, ICoreScopeProvider scopeProvider) { _propertyTypeUsageRepository = propertyTypeUsageRepository; + _contentTypeService = contentTypeService; _scopeProvider = scopeProvider; } /// + [Obsolete("Please use HasSavedPropertyValuesAsync. Scheduled for removable in Umbraco 15.")] public bool HasSavedPropertyValues(string propertyTypeAlias) { using ICoreScope scope = _scopeProvider.CreateCoreScope(autoComplete: true); + return _propertyTypeUsageRepository.HasSavedPropertyValues(propertyTypeAlias); } + + /// + public async Task> HasSavedPropertyValuesAsync(Guid contentTypeKey, string propertyAlias) + { + using ICoreScope scope = _scopeProvider.CreateCoreScope(autoComplete: true); + + var contentTypeExists = await _propertyTypeUsageRepository.ContentTypeExistAsync(contentTypeKey); + + if (contentTypeExists is false) + { + return Attempt.FailWithStatus(PropertyTypeOperationStatus.ContentTypeNotFound, false); + } + + + var hasSavedPropertyValues = await _propertyTypeUsageRepository.HasSavedPropertyValuesAsync(contentTypeKey, propertyAlias); + + return Attempt.SucceedWithStatus(PropertyTypeOperationStatus.Success, hasSavedPropertyValues); + } } diff --git a/src/Umbraco.Infrastructure/CompatibilitySuppressions.xml b/src/Umbraco.Infrastructure/CompatibilitySuppressions.xml index f2bbac9348..b580cdcb84 100644 --- a/src/Umbraco.Infrastructure/CompatibilitySuppressions.xml +++ b/src/Umbraco.Infrastructure/CompatibilitySuppressions.xml @@ -1,4 +1,5 @@  + CP0001 diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DataTypeUsageRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DataTypeUsageRepository.cs index 4f7614416f..32ea15718b 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DataTypeUsageRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DataTypeUsageRepository.cs @@ -15,6 +15,7 @@ public class DataTypeUsageRepository : IDataTypeUsageRepository _scopeAccessor = scopeAccessor; } + [Obsolete("Please use HasSavedValuesAsync. Scheduled for removable in Umbraco 15.")] public bool HasSavedValues(int dataTypeId) { IUmbracoDatabase? database = _scopeAccessor.AmbientScope?.Database; @@ -36,4 +37,28 @@ public class DataTypeUsageRepository : IDataTypeUsageRepository return database.ExecuteScalar(hasValueQuery); } + + public async Task HasSavedValuesAsync(Guid dataTypeKey) + { + IUmbracoDatabase? database = _scopeAccessor.AmbientScope?.Database; + + if (database is null) + { + throw new InvalidOperationException("A scope is required to query the database"); + } + + Sql selectQuery = database.SqlContext.Sql() + .SelectAll() + .From("pt") + .InnerJoin("pd") + .On((left, right) => left.PropertyTypeId == right.Id, "pd", "pt") + .InnerJoin("n") + .On((pt, n) => pt.DataTypeId == n.NodeId, "pt", "n") + .Where(n => n.UniqueId == dataTypeKey, "n"); + + Sql hasValueQuery = database.SqlContext.Sql() + .SelectAnyIfExists(selectQuery); + + return await Task.FromResult(database.ExecuteScalar(hasValueQuery)); + } } diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PropertyTypeUsageRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PropertyTypeUsageRepository.cs index dd599aa6d5..bca7cecd7a 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PropertyTypeUsageRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/PropertyTypeUsageRepository.cs @@ -1,5 +1,6 @@ -using System; + using NPoco; +using Umbraco.Cms.Core; using Umbraco.Cms.Core.Persistence.Repositories; using Umbraco.Cms.Infrastructure.Persistence.Dtos; using Umbraco.Cms.Infrastructure.Scoping; @@ -9,6 +10,11 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement; internal class PropertyTypeUsageRepository : IPropertyTypeUsageRepository { + private static readonly Guid?[] NodeObjectTypes = new Guid?[] + { + Constants.ObjectTypes.DocumentType, Constants.ObjectTypes.MediaType, Constants.ObjectTypes.MemberType, + }; + private readonly IScopeAccessor _scopeAccessor; public PropertyTypeUsageRepository(IScopeAccessor scopeAccessor) @@ -16,6 +22,7 @@ internal class PropertyTypeUsageRepository : IPropertyTypeUsageRepository _scopeAccessor = scopeAccessor; } + [Obsolete("Please use HasSavedPropertyValuesAsync. Scheduled for removable in Umbraco 15.")] public bool HasSavedPropertyValues(string propertyTypeAlias) { IUmbracoDatabase? database = _scopeAccessor.AmbientScope?.Database; @@ -37,4 +44,52 @@ internal class PropertyTypeUsageRepository : IPropertyTypeUsageRepository return database.ExecuteScalar(hasValuesQuery); } + + public async Task HasSavedPropertyValuesAsync(Guid contentTypeKey, string propertyAlias) + { + IUmbracoDatabase? database = _scopeAccessor.AmbientScope?.Database; + + if (database is null) + { + throw new InvalidOperationException("A scope is required to query the database"); + } + + Sql selectQuery = database.SqlContext.Sql() + .SelectAll() + .From("pt") + .InnerJoin("pd") + .On((pd, pt) => pd.PropertyTypeId == pt.Id, "pd", "pt") + .InnerJoin("n") + .On((pt, n) => pt.ContentTypeId == n.NodeId, "pt", "n") + .Where(pt => pt.Alias == propertyAlias, "pt") + .Where(n => n.UniqueId == contentTypeKey, "n"); + + Sql hasValuesQuery = database.SqlContext.Sql() + .SelectAnyIfExists(selectQuery); + + return database.ExecuteScalar(hasValuesQuery); + } + + public async Task ContentTypeExistAsync(Guid contentTypeKey) + { + IUmbracoDatabase? database = _scopeAccessor.AmbientScope?.Database; + + if (database is null) + { + throw new InvalidOperationException("A scope is required to query the database"); + } + + Sql selectQuery = database.SqlContext.Sql() + .SelectAll() + .From("n") + .Where(n => n.UniqueId == contentTypeKey, "n") + .Where(n => NodeObjectTypes.Contains(n.NodeObjectType), "n"); + + Sql hasValuesQuery = database.SqlContext.Sql() + .SelectAnyIfExists(selectQuery); + + return database.ExecuteScalar(hasValuesQuery); + } + + } diff --git a/src/Umbraco.Web.BackOffice/CompatibilitySuppressions.xml b/src/Umbraco.Web.BackOffice/CompatibilitySuppressions.xml index 2811562e53..e60e5c2b68 100644 --- a/src/Umbraco.Web.BackOffice/CompatibilitySuppressions.xml +++ b/src/Umbraco.Web.BackOffice/CompatibilitySuppressions.xml @@ -1,4 +1,5 @@  + CP0002 diff --git a/src/Umbraco.Web.Common/CompatibilitySuppressions.xml b/src/Umbraco.Web.Common/CompatibilitySuppressions.xml index af97dca9af..95a26a3f01 100644 --- a/src/Umbraco.Web.Common/CompatibilitySuppressions.xml +++ b/src/Umbraco.Web.Common/CompatibilitySuppressions.xml @@ -1,4 +1,5 @@  + CP0002