? GetByXPath(string query, int nodeContextId, int? parentId, UmbracoEntityTypes type)
{
- // TODO: Rename this!!! It's misleading, it should be GetByXPath
-
-
if (type != UmbracoEntityTypes.Document)
{
throw new ArgumentException("Get by query is only compatible with entities of type Document");
}
-
- var q = ParseXPathQuery(query, nodeContextId);
+ var q = ParseXPathQuery(query, nodeContextId, parentId);
IPublishedContent? node = _publishedContentQuery.ContentSingleAtXPath(q);
if (node == null)
@@ -546,10 +552,11 @@ public class EntityController : UmbracoAuthorizedJsonController
}
// PP: Work in progress on the query parser
- private string ParseXPathQuery(string query, int id) =>
+ private string ParseXPathQuery(string query, int id, int? parentId) =>
UmbracoXPathPathSyntaxParser.ParseXPathQuery(
query,
id,
+ parentId,
nodeid =>
{
IEntitySlim? ent = _entityService.Get(nodeid);
diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/entity.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/entity.resource.js
index a3c96cf805..6f46268b5b 100644
--- a/src/Umbraco.Web.UI.Client/src/common/resources/entity.resource.js
+++ b/src/Umbraco.Web.UI.Client/src/common/resources/entity.resource.js
@@ -318,9 +318,22 @@ function entityResource($q, $http, umbRequestHelper) {
'Failed to retrieve entity data for ids ' + ids);
},
+ /**
+ * @deprecated use getByXPath instead.
+ */
+ getByQuery: function (query, nodeContextId, type) {
+ return umbRequestHelper.resourcePromise(
+ $http.get(
+ umbRequestHelper.getApiUrl(
+ "entityApiBaseUrl",
+ "GetByQuery",
+ [{ query: query }, { nodeContextId: nodeContextId }, { type: type }])),
+ 'Failed to retrieve entity data for query ' + query);
+ },
+
/**
* @ngdoc method
- * @name umbraco.resources.entityResource#getByQuery
+ * @name umbraco.resources.entityResource#getByXPath
* @methodOf umbraco.resources.entityResource
*
* @description
@@ -329,7 +342,7 @@ function entityResource($q, $http, umbRequestHelper) {
* ##usage
*
* //get content by xpath
- * entityResource.getByQuery("$current", -1, "Document")
+ * entityResource.getByXPath("$current", -1, -1, "Document")
* .then(function(ent) {
* var myDoc = ent;
* alert('its here!');
@@ -338,17 +351,18 @@ function entityResource($q, $http, umbRequestHelper) {
*
* @param {string} query xpath to use in query
* @param {Int} nodeContextId id id to start from
+ * @param {Int} parentId id id of the parent to the starting point
* @param {string} type Object type name
* @returns {Promise} resourcePromise object containing the entity.
*
*/
- getByQuery: function (query, nodeContextId, type) {
+ getByXPath: function (query, nodeContextId, parentId, type) {
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"entityApiBaseUrl",
- "GetByQuery",
- [{ query: query }, { nodeContextId: nodeContextId }, { type: type }])),
+ "GetByXPath",
+ [{ query: query }, { nodeContextId: nodeContextId }, { parentId: parentId }, { type: type }])),
'Failed to retrieve entity data for query ' + query);
},
diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js
index 09b9d2c98b..52f147bce0 100644
--- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js
@@ -245,9 +245,12 @@ function contentPickerController($scope, $q, $routeParams, $location, entityReso
dialogOptions.startNodeId = -1;
}
else if ($scope.model.config.startNode.query) {
- //if we have a query for the startnode, we will use that.
- var rootId = editorState.current.id;
- entityResource.getByQuery($scope.model.config.startNode.query, rootId, "Document").then(function (ent) {
+ entityResource.getByXPath(
+ $scope.model.config.startNode.query,
+ editorState.current.id,
+ editorState.current.parentId,
+ "Document"
+ ).then(function (ent) {
dialogOptions.startNodeId = ($scope.model.config.idType === "udi" ? ent.udi : ent.id).toString();
});
}
From 9f028e0bd50c99dd70c72eb119882ebb1c58a90f Mon Sep 17 00:00:00 2001
From: Lucas Bach Bisgaard
Date: Mon, 15 May 2023 15:51:14 +0200
Subject: [PATCH 07/32] Add posibillty to use composition on memberstype
(#14060)
---
src/Umbraco.Core/ConventionsHelper.cs | 14 +--
.../Controllers/MemberTypeController.cs | 17 +++
.../components/umbgroupsbuilder.directive.js | 45 +++++---
.../common/resources/membertype.resource.js | 19 ++-
.../memberTypes/views/design/design.html | 1 -
.../Repositories/MemberRepositoryTest.cs | 23 ++--
.../Repositories/MemberTypeRepositoryTest.cs | 109 +++---------------
.../Services/MemberServiceTests.cs | 33 +-----
8 files changed, 99 insertions(+), 162 deletions(-)
diff --git a/src/Umbraco.Core/ConventionsHelper.cs b/src/Umbraco.Core/ConventionsHelper.cs
index 7d79338142..697b3904f5 100644
--- a/src/Umbraco.Core/ConventionsHelper.cs
+++ b/src/Umbraco.Core/ConventionsHelper.cs
@@ -6,17 +6,5 @@ namespace Umbraco.Cms.Core;
public static class ConventionsHelper
{
public static Dictionary GetStandardPropertyTypeStubs(IShortStringHelper shortStringHelper) =>
- new()
- {
- {
- Constants.Conventions.Member.Comments,
- new PropertyType(
- shortStringHelper,
- Constants.PropertyEditors.Aliases.TextArea,
- ValueStorageType.Ntext,
- true,
- Constants.Conventions.Member.Comments)
- { Name = Constants.Conventions.Member.CommentsLabel }
- },
- };
+ new();
}
diff --git a/src/Umbraco.Web.BackOffice/Controllers/MemberTypeController.cs b/src/Umbraco.Web.BackOffice/Controllers/MemberTypeController.cs
index 4184cc5798..1c11c0fd59 100644
--- a/src/Umbraco.Web.BackOffice/Controllers/MemberTypeController.cs
+++ b/src/Umbraco.Web.BackOffice/Controllers/MemberTypeController.cs
@@ -57,6 +57,8 @@ public class MemberTypeController : ContentTypeControllerBase
localizedTextService ?? throw new ArgumentNullException(nameof(localizedTextService));
}
+ public int GetCount() => _memberTypeService.Count();
+
///
/// Gets the member type a given id
///
@@ -172,6 +174,21 @@ public class MemberTypeController : ContentTypeControllerBase
return Ok(result);
}
+ ///
+ /// Returns where a particular composition has been used
+ /// This has been wrapped in a dto instead of simple parameters to support having multiple parameters in post request
+ /// body
+ ///
+ ///
+ ///
+ public IActionResult GetWhereCompositionIsUsedInMemberTypes(int contentTypeId)
+ {
+ var result =
+ PerformGetWhereCompositionIsUsedInContentTypes(contentTypeId, UmbracoObjectTypes.MemberType).Value?
+ .Select(x => new { contentType = x });
+ return Ok(result);
+ }
+
public MemberTypeDisplay? GetEmpty()
{
var ct = new MemberType(_shortStringHelper, -1)
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgroupsbuilder.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgroupsbuilder.directive.js
index 41d40a4615..6ba0aec2ee 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgroupsbuilder.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbgroupsbuilder.directive.js
@@ -1,7 +1,7 @@
(function () {
'use strict';
- function GroupsBuilderDirective(contentTypeHelper, contentTypeResource, mediaTypeResource,
+ function GroupsBuilderDirective(contentTypeHelper, contentTypeResource, mediaTypeResource, memberTypeResource,
$filter, iconHelper, $q, $timeout, notificationsService,
localizationService, editorService, eventsService, overlayService) {
@@ -215,7 +215,7 @@
scope.sortableRequestedTabTimeout = $timeout(() => {
scope.openTabAlias = scope.sortableRequestedTabAlias;
scope.sortableRequestedTabTimeout = null;
- /* hack to update sortable positions when switching from one tab to another.
+ /* hack to update sortable positions when switching from one tab to another.
without this sorting direct properties doesn't work correctly */
scope.$apply();
$('.umb-group-builder__ungrouped-properties .umb-group-builder__properties').sortable('refresh');
@@ -238,7 +238,7 @@
if (items && items.length <= 1) {
return;
}
-
+
// update the moved item sort order to fit into where it is dragged
const movedItem = items[movedIndex];
@@ -250,8 +250,8 @@
movedItem.sortOrder = prevItem.sortOrder + 1;
}
- /* After the above two items next to each other might have the same sort order
- to prevent this we run through the rest of the
+ /* After the above two items next to each other might have the same sort order
+ to prevent this we run through the rest of the
items and update the sort order if they are next to each other.
This will make it possible to make gaps without the number being updated */
for (let i = movedIndex; i < items.length; i++) {
@@ -289,7 +289,12 @@
});
//use a different resource lookup depending on the content type type
- var resourceLookup = scope.contentType === "documentType" ? contentTypeResource.getAvailableCompositeContentTypes : mediaTypeResource.getAvailableCompositeContentTypes;
+ var resourceLookup = mediaTypeResource.getAvailableCompositeContentTypes;
+ if (scope.contentType === "documentType") {
+ resourceLookup = contentTypeResource.getAvailableCompositeContentTypes;
+ } else if (scope.contentType === "memberType") {
+ resourceLookup = memberTypeResource.getAvailableCompositeContentTypes;
+ }
return resourceLookup(scope.model.id, selectedContentTypeAliases, propAliasesExisting).then(filteredAvailableCompositeTypes => {
scope.compositionsDialogModel.availableCompositeContentTypes.forEach(current => {
@@ -406,7 +411,12 @@
//merge composition with content type
//use a different resource lookup depending on the content type type
- var resourceLookup = scope.contentType === "documentType" ? contentTypeResource.getById : mediaTypeResource.getById;
+ var resourceLookup = mediaTypeResource.getById;
+ if (scope.contentType === "documentType") {
+ resourceLookup = contentTypeResource.getById;
+ } else if (scope.contentType === "memberType") {
+ resourceLookup = memberTypeResource.getById;
+ }
resourceLookup(selectedContentType.id).then(composition => {
//based on the above filtering we shouldn't be able to select an invalid one, but let's be safe and
@@ -449,10 +459,19 @@
}
};
- //select which resource methods to use, eg document Type or Media Type versions
- var availableContentTypeResource = scope.contentType === "documentType" ? contentTypeResource.getAvailableCompositeContentTypes : mediaTypeResource.getAvailableCompositeContentTypes;
- var whereUsedContentTypeResource = scope.contentType === "documentType" ? contentTypeResource.getWhereCompositionIsUsedInContentTypes : mediaTypeResource.getWhereCompositionIsUsedInContentTypes;
- var countContentTypeResource = scope.contentType === "documentType" ? contentTypeResource.getCount : mediaTypeResource.getCount;
+ var availableContentTypeResource = mediaTypeResource.getAvailableCompositeContentTypes;
+ var whereUsedContentTypeResource = mediaTypeResource.getWhereCompositionIsUsedInContentTypes;
+ var countContentTypeResource = mediaTypeResource.getCount;
+
+ if (scope.contentType === "documentType") {
+ availableContentTypeResource = contentTypeResource.getAvailableCompositeContentTypes;
+ whereUsedContentTypeResource = contentTypeResource.getWhereCompositionIsUsedInContentTypes;
+ countContentTypeResource = contentTypeResource.getCount;
+ } else if (scope.contentType === "memberType") {
+ availableContentTypeResource = memberTypeResource.getAvailableCompositeContentTypes;
+ whereUsedContentTypeResource = memberTypeResource.getWhereCompositionIsUsedInContentTypes;
+ countContentTypeResource = memberTypeResource.getCount;
+ }
//get the currently assigned property type aliases - ensure we pass these to the server side filer
var propAliasesExisting = _.filter(_.flatten(_.map(scope.model.groups, g => {
@@ -548,7 +567,7 @@
const localizeMany = localizationService.localizeMany(['general_delete', 'contentTypeEditor_confirmDeleteTabNotice']);
const localize = localizationService.localize('contentTypeEditor_confirmDeleteTabMessage', [tabName]);
-
+
$q.all([localizeMany, localize]).then(values => {
const translations = values[0];
const message = values[1];
@@ -752,7 +771,7 @@
const localizeMany = localizationService.localizeMany(['general_delete', 'contentTypeEditor_confirmDeleteGroupNotice']);
const localize = localizationService.localize('contentTypeEditor_confirmDeleteGroupMessage', [groupName]);
-
+
$q.all([localizeMany, localize]).then(values => {
const translations = values[0];
const message = values[1];
diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/membertype.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/membertype.resource.js
index e1d0fbe8ac..f96ba02ecb 100644
--- a/src/Umbraco.Web.UI.Client/src/common/resources/membertype.resource.js
+++ b/src/Umbraco.Web.UI.Client/src/common/resources/membertype.resource.js
@@ -6,7 +6,14 @@
function memberTypeResource($q, $http, umbRequestHelper, umbDataFormatter, localizationService) {
return {
-
+ getCount: function () {
+ return umbRequestHelper.resourcePromise(
+ $http.get(
+ umbRequestHelper.getApiUrl(
+ "memberTypeApiBaseUrl",
+ "GetCount")),
+ 'Failed to retrieve count');
+ },
getAvailableCompositeContentTypes: function (contentTypeId, filterContentTypes, filterPropertyTypes) {
if (!filterContentTypes) {
filterContentTypes = [];
@@ -39,7 +46,17 @@ function memberTypeResource($q, $http, umbRequestHelper, umbDataFormatter, local
query)),
'Failed to retrieve data for content type id ' + contentTypeId);
},
+ getWhereCompositionIsUsedInContentTypes: function (contentTypeId) {
+ var query = "contentTypeId=" + contentTypeId;
+ return umbRequestHelper.resourcePromise(
+ $http.get(
+ umbRequestHelper.getApiUrl(
+ "memberTypeApiBaseUrl",
+ "GetWhereCompositionIsUsedInMemberTypes",
+ query)),
+ "Failed to retrieve data for content type id " + contentTypeId);
+ },
//return all member types
getTypes: function () {
diff --git a/src/Umbraco.Web.UI.Client/src/views/memberTypes/views/design/design.html b/src/Umbraco.Web.UI.Client/src/views/memberTypes/views/design/design.html
index 7cd40dd25e..f9350023dd 100644
--- a/src/Umbraco.Web.UI.Client/src/views/memberTypes/views/design/design.html
+++ b/src/Umbraco.Web.UI.Client/src/views/memberTypes/views/design/design.html
@@ -1,5 +1,4 @@
diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/MemberRepositoryTest.cs b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/MemberRepositoryTest.cs
index 034e076ae5..58dc4bb4b0 100644
--- a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/MemberRepositoryTest.cs
+++ b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/MemberRepositoryTest.cs
@@ -195,18 +195,25 @@ public class MemberRepositoryTest : UmbracoIntegrationTest
repository.Save(member);
var sut = repository.Get(member.Id);
+ var standardPropertiesCount = ConventionsHelper.GetStandardPropertyTypeStubs(ShortStringHelper).Count;
- Assert.That(memberType.CompositionPropertyGroups.Count(), Is.EqualTo(2));
- Assert.That(memberType.CompositionPropertyTypes.Count(), Is.EqualTo(3 + ConventionsHelper.GetStandardPropertyTypeStubs(ShortStringHelper).Count));
- Assert.That(sut.Properties.Count(), Is.EqualTo(3 + ConventionsHelper.GetStandardPropertyTypeStubs(ShortStringHelper).Count));
+ // if there are any standard properties, they all get added to a single group
+ var expectedGroupCount = standardPropertiesCount > 0 ? 2 : 1;
+ Assert.That(memberType.CompositionPropertyGroups.Count(), Is.EqualTo(expectedGroupCount));
+ Assert.That(memberType.CompositionPropertyTypes.Count(), Is.EqualTo(3 + standardPropertiesCount));
+ Assert.That(sut.Properties.Count(), Is.EqualTo(3 + standardPropertiesCount));
var grp = memberType.CompositionPropertyGroups.FirstOrDefault(x =>
x.Name == Constants.Conventions.Member.StandardPropertiesGroupName);
- Assert.IsNotNull(grp);
- var aliases = ConventionsHelper.GetStandardPropertyTypeStubs(ShortStringHelper).Select(x => x.Key)
- .ToArray();
- foreach (var p in memberType.CompositionPropertyTypes.Where(x => aliases.Contains(x.Alias)))
+ if (grp != null)
{
- Assert.AreEqual(grp.Id, p.PropertyGroupId.Value);
+ var aliases = ConventionsHelper.GetStandardPropertyTypeStubs(ShortStringHelper).Select(x => x.Key)
+ .ToArray();
+
+ foreach (var p in memberType.CompositionPropertyTypes.Where(x => aliases.Contains(x.Alias)))
+ {
+ Assert.AreEqual(grp.Id, p.PropertyGroupId.Value);
+ }
+
}
}
}
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 5ab4ef3e8b..27d0cce985 100644
--- a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/MemberTypeRepositoryTest.cs
+++ b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Persistence/Repositories/MemberTypeRepositoryTest.cs
@@ -44,8 +44,11 @@ public class MemberTypeRepositoryTest : UmbracoIntegrationTest
var standardProps = ConventionsHelper.GetStandardPropertyTypeStubs(ShortStringHelper);
+ // if there are any standard properties, they all get added to a single group
+ var expectedGroupCount = standardProps.Count > 0 ? 2 : 1;
+
Assert.That(sut, Is.Not.Null);
- Assert.That(sut.PropertyGroups.Count, Is.EqualTo(2));
+ Assert.That(sut.PropertyGroups.Count, Is.EqualTo(expectedGroupCount));
Assert.That(sut.PropertyTypes.Count(), Is.EqualTo(3 + standardProps.Count));
Assert.That(sut.PropertyGroups.Any(x => x.HasIdentity == false || x.Id == 0), Is.False);
@@ -227,111 +230,25 @@ public class MemberTypeRepositoryTest : UmbracoIntegrationTest
[Test]
public void Bug_Changing_Built_In_Member_Type_Property_Type_Aliases_Results_In_Exception()
{
- var stubs = ConventionsHelper.GetStandardPropertyTypeStubs(ShortStringHelper);
-
- var provider = ScopeProvider;
- using (provider.CreateScope())
- {
- var repository = CreateRepository(provider);
-
- IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType("mtype");
-
- // created without the stub properties
- Assert.AreEqual(1, memberType.PropertyGroups.Count);
- Assert.AreEqual(3, memberType.PropertyTypes.Count());
-
- // saving *new* member type adds the stub properties
- repository.Save(memberType);
-
- // saving has added (and saved) the stub properties
- Assert.AreEqual(2, memberType.PropertyGroups.Count);
- Assert.AreEqual(3 + stubs.Count, memberType.PropertyTypes.Count());
-
- foreach (var stub in stubs)
- {
- var prop = memberType.PropertyTypes.First(x => x.Alias == stub.Key);
- prop.Alias += "__0000";
- }
-
- // saving *existing* member type does *not* ensure stub properties
- repository.Save(memberType);
-
- // therefore, nothing has changed
- Assert.AreEqual(2, memberType.PropertyGroups.Count);
- Assert.AreEqual(3 + stubs.Count, memberType.PropertyTypes.Count());
-
- // fetching ensures that the stub properties are there
- memberType = repository.Get("mtype");
- Assert.IsNotNull(memberType);
-
- Assert.AreEqual(2, memberType.PropertyGroups.Count);
- Assert.AreEqual(3 + (stubs.Count * 2), memberType.PropertyTypes.Count());
- }
+ // This test was initially deleted but that broke the build as it was marked as a breaking change
+ // https://github.com/umbraco/Umbraco-CMS/pull/14060
+ // Easiest fix for now is to leave the test and just don't do anything
}
[Test]
public void Built_In_Member_Type_Properties_Are_Automatically_Added_When_Creating()
{
- var stubs = ConventionsHelper.GetStandardPropertyTypeStubs(ShortStringHelper);
-
- var provider = ScopeProvider;
- using (provider.CreateScope())
- {
- var repository = CreateRepository(provider);
-
- IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType();
-
- // created without the stub properties
- Assert.AreEqual(1, memberType.PropertyGroups.Count);
- Assert.AreEqual(3, memberType.PropertyTypes.Count());
-
- // saving *new* member type adds the stub properties
- repository.Save(memberType);
-
- // saving has added (and saved) the stub properties
- Assert.AreEqual(2, memberType.PropertyGroups.Count);
- Assert.AreEqual(3 + stubs.Count, memberType.PropertyTypes.Count());
-
- // getting with stub properties
- memberType = repository.Get(memberType.Id);
-
- Assert.AreEqual(2, memberType.PropertyGroups.Count);
- Assert.AreEqual(3 + stubs.Count, memberType.PropertyTypes.Count());
- }
+ // This test was initially deleted but that broke the build as it was marked as a breaking change
+ // https://github.com/umbraco/Umbraco-CMS/pull/14060
+ // Easiest fix for now is to leave the test and just don't do anything
}
[Test]
public void Built_In_Member_Type_Properties_Missing_Are_Automatically_Added_When_Creating()
{
- var stubs = ConventionsHelper.GetStandardPropertyTypeStubs(ShortStringHelper);
-
- var provider = ScopeProvider;
- using (provider.CreateScope())
- {
- var repository = CreateRepository(provider);
-
- IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType();
-
- // created without the stub properties
- Assert.AreEqual(1, memberType.PropertyGroups.Count);
- Assert.AreEqual(3, memberType.PropertyTypes.Count());
-
- // add one stub property, others are still missing
- memberType.AddPropertyType(stubs.First().Value, Constants.Conventions.Member.StandardPropertiesGroupAlias, Constants.Conventions.Member.StandardPropertiesGroupName);
-
- // saving *new* member type adds the (missing) stub properties
- repository.Save(memberType);
-
- // saving has added (and saved) the (missing) stub properties
- Assert.AreEqual(2, memberType.PropertyGroups.Count);
- Assert.AreEqual(3 + stubs.Count, memberType.PropertyTypes.Count());
-
- // getting with stub properties
- memberType = repository.Get(memberType.Id);
-
- Assert.AreEqual(2, memberType.PropertyGroups.Count);
- Assert.AreEqual(3 + stubs.Count, memberType.PropertyTypes.Count());
- }
+ // This test was initially deleted but that broke the build as it was marked as a breaking change
+ // https://github.com/umbraco/Umbraco-CMS/pull/14060
+ // Easiest fix for now is to leave the test and just don't do anything
}
// This is to show that new properties are created for each member type - there was a bug before
diff --git a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/MemberServiceTests.cs b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/MemberServiceTests.cs
index 5375d87686..64e741752d 100644
--- a/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/MemberServiceTests.cs
+++ b/tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/MemberServiceTests.cs
@@ -685,36 +685,9 @@ public class MemberServiceTests : UmbracoIntegrationTest
[Test]
public void Tracks_Dirty_Changes()
{
- IMemberType memberType = MemberTypeBuilder.CreateSimpleMemberType();
- MemberTypeService.Save(memberType);
- IMember member = MemberBuilder.CreateSimpleMember(memberType, "test", "test@test.com", "pass", "test");
- MemberService.Save(member);
-
- var resolved = MemberService.GetByEmail(member.Email);
-
- // NOTE: This will not trigger a property isDirty because this is not based on a 'Property', it is
- // just a c# property of the Member object
- resolved.Email = "changed@test.com";
-
- // NOTE: This will not trigger a property isDirty for the same reason above, but this is a new change, so leave this to make sure.
- resolved.FailedPasswordAttempts = 1234;
-
- // NOTE: this WILL trigger a property isDirty because setting this c# property actually sets a value of
- // the underlying 'Property'
- resolved.Comments = "This will make it dirty";
-
- var dirtyMember = (ICanBeDirty)resolved;
- var dirtyProperties = resolved.Properties.Where(x => x.IsDirty()).ToList();
- Assert.IsTrue(dirtyMember.IsDirty());
- Assert.AreEqual(1, dirtyProperties.Count);
-
- // Assert that email and failed password attempts is still set as dirty on the member it self
- Assert.IsTrue(dirtyMember.IsPropertyDirty(nameof(resolved.Email)));
- Assert.IsTrue(dirtyMember.IsPropertyDirty(nameof(resolved.FailedPasswordAttempts)));
-
- // Comment will also be marked as dirty on the member object because content base merges dirty properties.
- Assert.IsTrue(dirtyMember.IsPropertyDirty(Constants.Conventions.Member.Comments));
- Assert.AreEqual(3, dirtyMember.GetDirtyProperties().Count());
+ // This test was initially deleted but that broke the build as it was marked as a breaking change
+ // https://github.com/umbraco/Umbraco-CMS/pull/14060
+ // Easiest fix for now is to leave the test and just don't do anything
}
[Test]
From 8c42f19d0def239ce38b80d04d65732e73593ab6 Mon Sep 17 00:00:00 2001
From: Warren Buckley
Date: Thu, 11 May 2023 14:12:33 +0100
Subject: [PATCH 08/32] Fix the args used in log endMessages in the
profillingLogger
---
src/Umbraco.Core/Logging/DisposableTimer.cs | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/src/Umbraco.Core/Logging/DisposableTimer.cs b/src/Umbraco.Core/Logging/DisposableTimer.cs
index b153e096c4..6246724143 100644
--- a/src/Umbraco.Core/Logging/DisposableTimer.cs
+++ b/src/Umbraco.Core/Logging/DisposableTimer.cs
@@ -59,7 +59,7 @@ public class DisposableTimer : DisposableObjectSlim
{
var args = new object[startMessageArgs.Length + 1];
startMessageArgs.CopyTo(args, 0);
- args[startMessageArgs.Length] = _timingId;
+ args[^1] = _timingId;
logger.LogDebug(startMessage + " [Timing {TimingId}]", args);
}
@@ -73,7 +73,7 @@ public class DisposableTimer : DisposableObjectSlim
{
var args = new object[startMessageArgs.Length + 1];
startMessageArgs.CopyTo(args, 0);
- args[startMessageArgs.Length] = _timingId;
+ args[^1] = _timingId;
logger.LogInformation(startMessage + " [Timing {TimingId}]", args);
}
@@ -127,8 +127,8 @@ public class DisposableTimer : DisposableObjectSlim
{
var args = new object[_failMessageArgs.Length + 2];
_failMessageArgs.CopyTo(args, 0);
- args[_failMessageArgs.Length - 1] = Stopwatch.ElapsedMilliseconds;
- args[_failMessageArgs.Length] = _timingId;
+ args[^2] = Stopwatch.ElapsedMilliseconds;
+ args[^1] = _timingId;
_logger.LogError(_failException, _failMessage + " ({Duration}ms) [Timing {TimingId}]", args);
}
}
@@ -149,8 +149,8 @@ public class DisposableTimer : DisposableObjectSlim
{
var args = new object[_endMessageArgs.Length + 2];
_endMessageArgs.CopyTo(args, 0);
- args[^1] = Stopwatch.ElapsedMilliseconds;
- args[args.Length] = _timingId;
+ args[^2] = Stopwatch.ElapsedMilliseconds;
+ args[^1] = _timingId;
_logger.LogDebug(_endMessage + " ({Duration}ms) [Timing {TimingId}]", args);
}
@@ -168,8 +168,8 @@ public class DisposableTimer : DisposableObjectSlim
{
var args = new object[_endMessageArgs.Length + 2];
_endMessageArgs.CopyTo(args, 0);
- args[_endMessageArgs.Length - 1] = Stopwatch.ElapsedMilliseconds;
- args[_endMessageArgs.Length] = _timingId;
+ args[^2] = Stopwatch.ElapsedMilliseconds;
+ args[^1] = _timingId;
_logger.LogInformation(_endMessage + " ({Duration}ms) [Timing {TimingId}]", args);
}
From 53e3c99af6a7184c075ec864f3211e908678e113 Mon Sep 17 00:00:00 2001
From: Bjarne Fyrstenborg
Date: Tue, 16 May 2023 16:32:32 +0200
Subject: [PATCH 09/32] Fix transparent background after upgrade of spectrum
color picker (#14251)
---
.../src/less/components/umb-color-picker.less | 10 +++-------
1 file changed, 3 insertions(+), 7 deletions(-)
diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-color-picker.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-color-picker.less
index a84ca17ebc..4634f33dbd 100644
--- a/src/Umbraco.Web.UI.Client/src/less/components/umb-color-picker.less
+++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-color-picker.less
@@ -1,19 +1,15 @@
-.umb-color-picker {
+.umb-color-picker {
.sp-replacer {
display: inline-flex;
margin-right: 12px;
height: 32px;
+ padding: 5px;
&.sp-light {
background-color: @white;
}
- .sp-preview {
- margin: 5px;
- height: auto;
- }
-
.sp-dd {
line-height: 2rem;
}
@@ -24,4 +20,4 @@
.sp-replacer {
cursor: not-allowed;
}
-}
\ No newline at end of file
+}
From 6fcdb1a6e4f48be65dde3f69991d299070132704 Mon Sep 17 00:00:00 2001
From: Vitor Rodrigues
Date: Mon, 20 Mar 2023 20:26:58 +0100
Subject: [PATCH 10/32] Fix build required before initial publish for packages
---
templates/UmbracoPackage/buildTransitive/UmbracoPackage.targets | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/templates/UmbracoPackage/buildTransitive/UmbracoPackage.targets b/templates/UmbracoPackage/buildTransitive/UmbracoPackage.targets
index 2bd0156cca..4c376ac97b 100644
--- a/templates/UmbracoPackage/buildTransitive/UmbracoPackage.targets
+++ b/templates/UmbracoPackage/buildTransitive/UmbracoPackage.targets
@@ -3,7 +3,7 @@
$(MSBuildThisFileDirectory)..\App_Plugins\UmbracoPackage\**\*.*
-
+
From 9640616b56b7076b6d7ac7d317388ad738b7a66b Mon Sep 17 00:00:00 2001
From: Marc Goodson
Date: Wed, 17 May 2023 09:19:18 +0100
Subject: [PATCH 11/32] Update ContentValueSetValidator to allow
include/exclude of fields (#14177)
---
.../Examine/ContentValueSetValidator.cs | 26 ++++++++++++++++---
1 file changed, 23 insertions(+), 3 deletions(-)
diff --git a/src/Umbraco.Infrastructure/Examine/ContentValueSetValidator.cs b/src/Umbraco.Infrastructure/Examine/ContentValueSetValidator.cs
index 7f4f3cd50e..ec4dff77f4 100644
--- a/src/Umbraco.Infrastructure/Examine/ContentValueSetValidator.cs
+++ b/src/Umbraco.Infrastructure/Examine/ContentValueSetValidator.cs
@@ -19,10 +19,28 @@ public class ContentValueSetValidator : ValueSetValidator, IContentValueSetValid
// used for tests
public ContentValueSetValidator(bool publishedValuesOnly, int? parentId = null, IEnumerable? includeItemTypes = null, IEnumerable? excludeItemTypes = null)
- : this(publishedValuesOnly, true, null, null, parentId, includeItemTypes, excludeItemTypes)
+ : this(publishedValuesOnly, true, null, null, parentId, includeItemTypes, excludeItemTypes, null, null)
{
}
+ [Obsolete("Use the overload accepting includeFields and excludeFields instead. This overload will be removed in Umbraco 14.")]
+ public ContentValueSetValidator(
+ bool publishedValuesOnly,
+ bool supportProtectedContent,
+ IPublicAccessService? publicAccessService,
+ IScopeProvider? scopeProvider,
+ int? parentId,
+ IEnumerable? includeItemTypes,
+ IEnumerable? excludeItemTypes)
+ : base(includeItemTypes, excludeItemTypes, null, null)
+ {
+ PublishedValuesOnly = publishedValuesOnly;
+ SupportProtectedContent = supportProtectedContent;
+ ParentId = parentId;
+ _publicAccessService = publicAccessService;
+ _scopeProvider = scopeProvider;
+ }
+
public ContentValueSetValidator(
bool publishedValuesOnly,
bool supportProtectedContent,
@@ -30,8 +48,10 @@ public class ContentValueSetValidator : ValueSetValidator, IContentValueSetValid
IScopeProvider? scopeProvider,
int? parentId = null,
IEnumerable? includeItemTypes = null,
- IEnumerable? excludeItemTypes = null)
- : base(includeItemTypes, excludeItemTypes, null, null)
+ IEnumerable? excludeItemTypes = null,
+ IEnumerable? includeFields = null,
+ IEnumerable? excludeFields = null)
+ : base(includeItemTypes, excludeItemTypes, includeFields, excludeFields)
{
PublishedValuesOnly = publishedValuesOnly;
SupportProtectedContent = supportProtectedContent;
From 4b62cb59b746ce39f36c33fb13415ce0500dec95 Mon Sep 17 00:00:00 2001
From: Mykyta Zakharov
Date: Thu, 18 May 2023 14:28:00 +0300
Subject: [PATCH 12/32] Issue-12704: added new necessary indexes.
---
.../Migrations/MigrationBase_Extra.cs | 20 ++++++
.../Migrations/Upgrade/UmbracoPlan.cs | 3 +
.../V_12_1_0/TablesIndexesImprovement.cs | 65 +++++++++++++++++++
.../DatabaseAnnotations/IndexAttribute.cs | 2 +-
.../DefinitionFactory.cs | 10 ++-
.../Persistence/Dtos/ContentNuDto.cs | 3 +
.../Dtos/ContentVersionCultureVariationDto.cs | 2 +-
.../Persistence/Dtos/ContentVersionDto.cs | 2 +-
.../Persistence/Dtos/DocumentVersionDto.cs | 4 +-
.../Persistence/Dtos/LogDto.cs | 4 +-
.../Persistence/Dtos/NodeDto.cs | 3 +-
.../Persistence/Dtos/RedirectUrlDto.cs | 3 +
.../Persistence/Dtos/TagDto.cs | 1 +
.../Persistence/Dtos/TagRelationshipDto.cs | 1 +
14 files changed, 114 insertions(+), 9 deletions(-)
create mode 100644 src/Umbraco.Infrastructure/Migrations/Upgrade/V_12_1_0/TablesIndexesImprovement.cs
diff --git a/src/Umbraco.Infrastructure/Migrations/MigrationBase_Extra.cs b/src/Umbraco.Infrastructure/Migrations/MigrationBase_Extra.cs
index b548112d8f..23de94e824 100644
--- a/src/Umbraco.Infrastructure/Migrations/MigrationBase_Extra.cs
+++ b/src/Umbraco.Infrastructure/Migrations/MigrationBase_Extra.cs
@@ -2,6 +2,7 @@ using System.Collections.Generic;
using System.Linq;
using Umbraco.Cms.Infrastructure.Persistence;
using Umbraco.Cms.Infrastructure.Persistence.DatabaseModelDefinitions;
+using Umbraco.Cms.Infrastructure.Migrations.Expressions.Execute.Expressions;
using Umbraco.Cms.Infrastructure.Persistence.SqlSyntax;
using Umbraco.Extensions;
@@ -110,6 +111,25 @@ namespace Umbraco.Cms.Infrastructure.Migrations
return indexes.Any(x => x.Item2.InvariantEquals(indexName));
}
+ protected void CreateIndex(string toCreate)
+ {
+ TableDefinition tableDef = DefinitionFactory.GetTableDefinition(typeof(T), Context.SqlContext.SqlSyntax);
+ IndexDefinition index = tableDef.Indexes.First(x => x.Name == toCreate);
+ new ExecuteSqlStatementExpression(Context) { SqlStatement = Context.SqlContext.SqlSyntax.Format(index) }
+ .Execute();
+ }
+
+ protected void DeleteIndex(string toDelete)
+ {
+ if (!IndexExists(toDelete))
+ {
+ return;
+ }
+
+ TableDefinition tableDef = DefinitionFactory.GetTableDefinition(typeof(T), Context.SqlContext.SqlSyntax);
+ Delete.Index(toDelete).OnTable(tableDef.Name).Do();
+ }
+
protected bool PrimaryKeyExists(string tableName, string primaryKeyName)
{
return SqlSyntax.DoesPrimaryKeyExist(Context.Database, tableName, primaryKeyName);
diff --git a/src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs b/src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs
index 092da29913..ba9437a34d 100644
--- a/src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs
+++ b/src/Umbraco.Infrastructure/Migrations/Upgrade/UmbracoPlan.cs
@@ -77,5 +77,8 @@ public class UmbracoPlan : MigrationPlan
// To 12.0.0
To("{888A0D5D-51E4-4C7E-AA0A-01306523C7FB}");
To("{539F2F83-FBA7-4C48-81A3-75081A56BB9D}");
+
+ // To 12.1.0
+ To("{1187192D-EDB5-4619-955D-91D48D738871}");
}
}
diff --git a/src/Umbraco.Infrastructure/Migrations/Upgrade/V_12_1_0/TablesIndexesImprovement.cs b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_12_1_0/TablesIndexesImprovement.cs
new file mode 100644
index 0000000000..5483f25593
--- /dev/null
+++ b/src/Umbraco.Infrastructure/Migrations/Upgrade/V_12_1_0/TablesIndexesImprovement.cs
@@ -0,0 +1,65 @@
+using Umbraco.Cms.Infrastructure.Persistence.Dtos;
+
+namespace Umbraco.Cms.Infrastructure.Migrations.Upgrade.V_12_1_0;
+
+public class TablesIndexesImprovement : MigrationBase
+{
+ public TablesIndexesImprovement(IMigrationContext context) : base(context)
+ {
+ }
+
+ protected override void Migrate()
+ {
+ var nodeDtoTrashedIndex = $"IX_{NodeDto.TableName}_ObjectType_trashed_sorted";
+ DeleteIndex(nodeDtoTrashedIndex);
+ CreateIndex(nodeDtoTrashedIndex);
+
+ var redirectUrlCreateDateUtcIndex = $"IX_{RedirectUrlDto.TableName}_culture_hash";
+ DeleteIndex(redirectUrlCreateDateUtcIndex);
+ CreateIndex(redirectUrlCreateDateUtcIndex);
+
+ var contentVersionCultureVariationVersionIdIndex = $"IX_{ContentVersionCultureVariationDto.TableName}_VersionId";
+ DeleteIndex(contentVersionCultureVariationVersionIdIndex);
+ CreateIndex(contentVersionCultureVariationVersionIdIndex);
+
+ var contentVersionDtoNodeIdV2Index = $"IX_{ContentVersionDto.TableName}_NodeId";
+ DeleteIndex(contentVersionDtoNodeIdV2Index);
+ CreateIndex(contentVersionDtoNodeIdV2Index);
+
+ var tagRelationshipDtoTagNodeIndex = $"IX_{TagRelationshipDto.TableName}_tagId_nodeId";
+ DeleteIndex(tagRelationshipDtoTagNodeIndex);
+ CreateIndex(tagRelationshipDtoTagNodeIndex);
+
+ var tagDtoLanguageGroupIndex = $"IX_{TagDto.TableName}_languageId_group";
+ DeleteIndex(tagDtoLanguageGroupIndex);
+ CreateIndex(tagDtoLanguageGroupIndex);
+
+ var documentVersionDtoIdPublishedIndex = $"IX_{DocumentVersionDto.TableName}_id_published";
+ DeleteIndex(documentVersionDtoIdPublishedIndex);
+ CreateIndex(documentVersionDtoIdPublishedIndex);
+
+ var documentVersionDtoPublishedIndex = $"IX_{DocumentVersionDto.TableName}_published";
+ DeleteIndex(documentVersionDtoPublishedIndex);
+ CreateIndex(documentVersionDtoPublishedIndex);
+
+ var logDtoDatestampIndex = $"IX_{LogDto.TableName}_datestamp";
+ DeleteIndex(logDtoDatestampIndex);
+ CreateIndex(logDtoDatestampIndex);
+
+ var logDtoDatestampHeaderIndex = $"IX_{LogDto.TableName}_datestamp_logheader";
+ DeleteIndex(logDtoDatestampHeaderIndex);
+ CreateIndex(logDtoDatestampHeaderIndex);
+
+ var propertyDataDtoVersionIdIndex = $"IX_{PropertyDataDto.TableName}_VersionId";
+ DeleteIndex(propertyDataDtoVersionIdIndex);
+ CreateIndex(propertyDataDtoVersionIdIndex);
+
+ var contentNuDtoPublishedIdIndex = $"IX_{ContentNuDto.TableName}_published";
+ DeleteIndex(contentNuDtoPublishedIdIndex);
+ CreateIndex(contentNuDtoPublishedIdIndex);
+
+ var nodeDtoParentIdNodeObjectTypeIndex = $"IX_{NodeDto.TableName}_parentId_nodeObjectType";
+ DeleteIndex(nodeDtoParentIdNodeObjectTypeIndex);
+ CreateIndex(nodeDtoParentIdNodeObjectTypeIndex);
+ }
+}
diff --git a/src/Umbraco.Infrastructure/Persistence/DatabaseAnnotations/IndexAttribute.cs b/src/Umbraco.Infrastructure/Persistence/DatabaseAnnotations/IndexAttribute.cs
index 826e56ad89..0628da82aa 100644
--- a/src/Umbraco.Infrastructure/Persistence/DatabaseAnnotations/IndexAttribute.cs
+++ b/src/Umbraco.Infrastructure/Persistence/DatabaseAnnotations/IndexAttribute.cs
@@ -3,7 +3,7 @@ namespace Umbraco.Cms.Infrastructure.Persistence.DatabaseAnnotations;
///
/// Attribute that represents an Index
///
-[AttributeUsage(AttributeTargets.Property)]
+[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
public class IndexAttribute : Attribute
{
public IndexAttribute(IndexTypes indexType) => IndexType = indexType;
diff --git a/src/Umbraco.Infrastructure/Persistence/DatabaseModelDefinitions/DefinitionFactory.cs b/src/Umbraco.Infrastructure/Persistence/DatabaseModelDefinitions/DefinitionFactory.cs
index 32bdd213e6..ad043c08c4 100644
--- a/src/Umbraco.Infrastructure/Persistence/DatabaseModelDefinitions/DefinitionFactory.cs
+++ b/src/Umbraco.Infrastructure/Persistence/DatabaseModelDefinitions/DefinitionFactory.cs
@@ -55,8 +55,14 @@ public static class DefinitionFactory
}
// Creates an index definition and adds it to the collection on the table definition
- IndexAttribute? indexAttribute = propertyInfo.FirstAttribute();
- if (indexAttribute != null)
+ IEnumerable? indexAttributes = propertyInfo.MultipleAttribute();
+
+ if (indexAttributes == null)
+ {
+ continue;
+ }
+
+ foreach (IndexAttribute indexAttribute in indexAttributes)
{
IndexDefinition indexDefinition =
GetIndexDefinition(modelType, propertyInfo, indexAttribute, columnName, tableName);
diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/ContentNuDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/ContentNuDto.cs
index 6fa45d9cce..a3a978f2e4 100644
--- a/src/Umbraco.Infrastructure/Persistence/Dtos/ContentNuDto.cs
+++ b/src/Umbraco.Infrastructure/Persistence/Dtos/ContentNuDto.cs
@@ -10,12 +10,15 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos;
[ExplicitColumns]
public class ContentNuDto
{
+ public const string TableName = Constants.DatabaseSchema.Tables.NodeData;
+
[Column("nodeId")]
[PrimaryKeyColumn(AutoIncrement = false, Name = "PK_cmsContentNu", OnColumns = "nodeId, published")]
[ForeignKey(typeof(ContentDto), Column = "nodeId", OnDelete = Rule.Cascade)]
public int NodeId { get; set; }
[Column("published")]
+ [Index(IndexTypes.NonClustered, Name = "IX_" + TableName + "_published", ForColumns = "published,nodeId,rv", IncludeColumns = "dataRaw")]
public bool Published { get; set; }
///
diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/ContentVersionCultureVariationDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/ContentVersionCultureVariationDto.cs
index 48c6ee97ef..b7d675f9a8 100644
--- a/src/Umbraco.Infrastructure/Persistence/Dtos/ContentVersionCultureVariationDto.cs
+++ b/src/Umbraco.Infrastructure/Persistence/Dtos/ContentVersionCultureVariationDto.cs
@@ -18,7 +18,7 @@ internal class ContentVersionCultureVariationDto
[Column("versionId")]
[ForeignKey(typeof(ContentVersionDto))]
- [Index(IndexTypes.UniqueNonClustered, Name = "IX_" + TableName + "_VersionId", ForColumns = "versionId,languageId")]
+ [Index(IndexTypes.UniqueNonClustered, Name = "IX_" + TableName + "_VersionId", ForColumns = "versionId,languageId", IncludeColumns = "id,name,date,availableUserId")]
public int VersionId { get; set; }
[Column("languageId")]
diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/ContentVersionDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/ContentVersionDto.cs
index 3a6aae2aff..07fe6d9a84 100644
--- a/src/Umbraco.Infrastructure/Persistence/Dtos/ContentVersionDto.cs
+++ b/src/Umbraco.Infrastructure/Persistence/Dtos/ContentVersionDto.cs
@@ -19,7 +19,7 @@ public class ContentVersionDto
[Column("nodeId")]
[ForeignKey(typeof(ContentDto))]
- [Index(IndexTypes.NonClustered, Name = "IX_" + TableName + "_NodeId", ForColumns = "nodeId,current", IncludeColumns = "id,versionDate,text,userId")]
+ [Index(IndexTypes.NonClustered, Name = "IX_" + TableName + "_NodeId", ForColumns = "nodeId,current", IncludeColumns = "id,versionDate,text,userId,preventCleanup")]
public int NodeId { get; set; }
[Column("versionDate")] // TODO: db rename to 'updateDate'
diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/DocumentVersionDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/DocumentVersionDto.cs
index 75dea080a2..f99a6676be 100644
--- a/src/Umbraco.Infrastructure/Persistence/Dtos/DocumentVersionDto.cs
+++ b/src/Umbraco.Infrastructure/Persistence/Dtos/DocumentVersionDto.cs
@@ -9,11 +9,12 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos;
[ExplicitColumns]
public class DocumentVersionDto
{
- private const string TableName = Constants.DatabaseSchema.Tables.DocumentVersion;
+ public const string TableName = Constants.DatabaseSchema.Tables.DocumentVersion;
[Column("id")]
[PrimaryKeyColumn(AutoIncrement = false)]
[ForeignKey(typeof(ContentVersionDto))]
+ [Index(IndexTypes.NonClustered, Name = "IX_" + TableName + "_id_published", ForColumns = "id,published", IncludeColumns = "templateId")]
public int Id { get; set; }
[Column("templateId")]
@@ -22,6 +23,7 @@ public class DocumentVersionDto
public int? TemplateId { get; set; }
[Column("published")]
+ [Index(IndexTypes.NonClustered, Name = "IX_" + TableName + "_published", ForColumns = "published", IncludeColumns = "id,templateId")]
public bool Published { get; set; }
[ResultColumn]
diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/LogDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/LogDto.cs
index b464d6628d..89bfeb8612 100644
--- a/src/Umbraco.Infrastructure/Persistence/Dtos/LogDto.cs
+++ b/src/Umbraco.Infrastructure/Persistence/Dtos/LogDto.cs
@@ -35,14 +35,14 @@ internal class LogDto
[NullSetting(NullSetting = NullSettings.Null)]
public string? EntityType { get; set; }
- // TODO: Should we have an index on this since we allow searching on it?
[Column("Datestamp")]
[Constraint(Default = SystemMethods.CurrentDateTime)]
+ [Index(IndexTypes.NonClustered, Name = "IX_" + TableName + "_datestamp", ForColumns = "Datestamp,userId,NodeId")]
public DateTime Datestamp { get; set; }
- // TODO: Should we have an index on this since we allow searching on it?
[Column("logHeader")]
[Length(50)]
+ [Index(IndexTypes.NonClustered, Name = "IX_" + TableName + "_datestamp_logheader", ForColumns = "Datestamp,logHeader")]
public string Header { get; set; } = null!;
[Column("logComment")]
diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/NodeDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/NodeDto.cs
index d11ebc96ce..5bf3a26207 100644
--- a/src/Umbraco.Infrastructure/Persistence/Dtos/NodeDto.cs
+++ b/src/Umbraco.Infrastructure/Persistence/Dtos/NodeDto.cs
@@ -26,7 +26,7 @@ public class NodeDto
[Column("parentId")]
[ForeignKey(typeof(NodeDto))]
- [Index(IndexTypes.NonClustered, Name = "IX_" + TableName + "_ParentId")]
+ [Index(IndexTypes.NonClustered, Name = "IX_" + TableName + "_parentId_nodeObjectType", ForColumns = "parentID,nodeObjectType", IncludeColumns = "trashed,nodeUser,level,path,sortOrder,uniqueID,text,createDate")]
public int ParentId { get; set; }
// NOTE: This index is primarily for the nucache data lookup, see https://github.com/umbraco/Umbraco-CMS/pull/8365#issuecomment-673404177
@@ -40,6 +40,7 @@ public class NodeDto
public string Path { get; set; } = null!;
[Column("sortOrder")]
+ [Index(IndexTypes.NonClustered, Name = "IX_" + TableName + "_ObjectType_trashed_sorted", ForColumns = "nodeObjectType,trashed,sortOrder,id", IncludeColumns = "uniqueID,parentID,level,path,nodeUser,text,createDate")]
public int SortOrder { get; set; }
[Column("trashed")]
diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/RedirectUrlDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/RedirectUrlDto.cs
index b377b49177..453ab1e308 100644
--- a/src/Umbraco.Infrastructure/Persistence/Dtos/RedirectUrlDto.cs
+++ b/src/Umbraco.Infrastructure/Persistence/Dtos/RedirectUrlDto.cs
@@ -9,6 +9,8 @@ namespace Umbraco.Cms.Infrastructure.Persistence.Dtos;
[ExplicitColumns]
internal class RedirectUrlDto
{
+ public const string TableName = Constants.DatabaseSchema.Tables.RedirectUrl;
+
public RedirectUrlDto() => CreateDateUtc = DateTime.UtcNow;
// notes
@@ -31,6 +33,7 @@ internal class RedirectUrlDto
[Column("createDateUtc")]
[NullSetting(NullSetting = NullSettings.NotNull)]
+ [Index(IndexTypes.NonClustered, Name = "IX_" + TableName + "_culture_hash", ForColumns = "createDateUtc", IncludeColumns = "culture,url,urlHash,contentKey")]
public DateTime CreateDateUtc { get; set; }
[Column("url")]
diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/TagDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/TagDto.cs
index cc8b80c777..d2a68cf971 100644
--- a/src/Umbraco.Infrastructure/Persistence/Dtos/TagDto.cs
+++ b/src/Umbraco.Infrastructure/Persistence/Dtos/TagDto.cs
@@ -17,6 +17,7 @@ internal class TagDto
[Column("group")]
[Length(100)]
+ [Index(IndexTypes.NonClustered, Name = "IX_" + TableName + "_languageId_group", ForColumns = "languageId,group", IncludeColumns = "id,tag")]
public string Group { get; set; } = null!;
[Column("languageId")]
diff --git a/src/Umbraco.Infrastructure/Persistence/Dtos/TagRelationshipDto.cs b/src/Umbraco.Infrastructure/Persistence/Dtos/TagRelationshipDto.cs
index 3799679e4d..f5f9fd0b38 100644
--- a/src/Umbraco.Infrastructure/Persistence/Dtos/TagRelationshipDto.cs
+++ b/src/Umbraco.Infrastructure/Persistence/Dtos/TagRelationshipDto.cs
@@ -14,6 +14,7 @@ internal class TagRelationshipDto
[Column("nodeId")]
[PrimaryKeyColumn(AutoIncrement = false, Name = "PK_cmsTagRelationship", OnColumns = "nodeId, propertyTypeId, tagId")]
[ForeignKey(typeof(ContentDto), Name = "FK_cmsTagRelationship_cmsContent", Column = "nodeId")]
+ [Index(IndexTypes.NonClustered, Name = "IX_" + TableName + "_tagId_nodeId", ForColumns = "tagId,nodeId", IncludeColumns = "propertyTypeId")]
public int NodeId { get; set; }
[Column("tagId")]
From 58695b6e9fdafc0539a757e6d842e44f618d833d Mon Sep 17 00:00:00 2001
From: Dhanesh Kumar Mj <58820887+dKumarmj@users.noreply.github.com>
Date: Fri, 19 May 2023 14:51:40 +0530
Subject: [PATCH 13/32] [Fix] Block editor labels showing Angular JS on first
load. (#14143)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-authored-by: Dhanesh Kumar <“dhanesh.kumar@phases.io”>
---
.../src/common/services/blockeditormodelobject.service.js | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/src/Umbraco.Web.UI.Client/src/common/services/blockeditormodelobject.service.js b/src/Umbraco.Web.UI.Client/src/common/services/blockeditormodelobject.service.js
index abb81c38dc..20661d5d1c 100644
--- a/src/Umbraco.Web.UI.Client/src/common/services/blockeditormodelobject.service.js
+++ b/src/Umbraco.Web.UI.Client/src/common/services/blockeditormodelobject.service.js
@@ -639,10 +639,9 @@
mapToPropertyModel(this.settings, this.settingsData);
}
};
-
// first time instant update of label.
- blockObject.label = (blockObject.config.label || blockObject.content?.contentTypeName) ?? "" ;
- blockObject.index = 0;
+ blockObject.label = blockObject.content?.contentTypeName || "";
+ blockObject.index = 0;
if (blockObject.config.label && blockObject.config.label !== "" && blockObject.config.unsupported !== true) {
var labelElement = $('', { text: blockObject.config.label});
From afddb3d7814760bf2a7ebca1cab2378413cbd6fd Mon Sep 17 00:00:00 2001
From: Matt Brailsford
Date: Tue, 23 May 2023 16:30:21 +0100
Subject: [PATCH 14/32] Enforce passing tree alias to tree api requests
(#12678)
* Enforce passing tree alias to tree api proxy
* Update ApplicationTreeController.cs
---
.../Trees/ApplicationTreeController.cs | 30 ++++++++++++-------
1 file changed, 19 insertions(+), 11 deletions(-)
diff --git a/src/Umbraco.Web.BackOffice/Trees/ApplicationTreeController.cs b/src/Umbraco.Web.BackOffice/Trees/ApplicationTreeController.cs
index 7e709b5904..461d1fc82f 100644
--- a/src/Umbraco.Web.BackOffice/Trees/ApplicationTreeController.cs
+++ b/src/Umbraco.Web.BackOffice/Trees/ApplicationTreeController.cs
@@ -26,14 +26,13 @@ namespace Umbraco.Cms.Web.BackOffice.Trees;
[PluginController(Constants.Web.Mvc.BackOfficeTreeArea)]
public class ApplicationTreeController : UmbracoAuthorizedApiController
{
- private readonly IActionDescriptorCollectionProvider _actionDescriptorCollectionProvider;
- private readonly IControllerFactory _controllerFactory;
- private readonly ILocalizedTextService _localizedTextService;
- private readonly ISectionService _sectionService;
private readonly ITreeService _treeService;
+ private readonly ISectionService _sectionService;
+ private readonly ILocalizedTextService _localizedTextService;
+ private readonly IControllerFactory _controllerFactory;
+ private readonly IActionDescriptorCollectionProvider _actionDescriptorCollectionProvider;
- ///
- /// Initializes a new instance of the class.
+ /// Initializes a new instance of the class.
///
public ApplicationTreeController(
ITreeService treeService,
@@ -209,14 +208,19 @@ public class ApplicationTreeController : UmbracoAuthorizedApiController
throw new ArgumentNullException(nameof(tree));
}
- ActionResult? childrenResult = await GetChildren(tree, id, querystring);
+ // Force tree querystring param
+ Dictionary? td = querystring?.ToDictionary(x => x.Key, x => x.Value) ?? new Dictionary();
+ td["tree"] = tree.TreeAlias;
+ var qs = new FormCollection(td);
+
+ ActionResult? childrenResult = await GetChildren(tree, id, qs);
if (!(childrenResult?.Result is null))
{
return new ActionResult(childrenResult.Result);
}
TreeNodeCollection? children = childrenResult?.Value;
- ActionResult? rootNodeResult = await GetRootNode(tree, querystring);
+ ActionResult? rootNodeResult = await GetRootNode(tree, qs);
if (!(rootNodeResult?.Result is null))
{
return rootNodeResult.Result;
@@ -224,7 +228,6 @@ public class ApplicationTreeController : UmbracoAuthorizedApiController
TreeNode? rootNode = rootNodeResult?.Value;
-
var sectionRoot = TreeRootNode.CreateSingleTreeRoot(
Constants.System.RootString,
rootNode!.ChildNodesUrl,
@@ -256,7 +259,12 @@ public class ApplicationTreeController : UmbracoAuthorizedApiController
throw new ArgumentNullException(nameof(tree));
}
- ActionResult
public void ClearAll()
{
- _logger.LogDebug("Clear all.");
+ if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug))
+ {
+ _logger.LogDebug("Clear all.");
+ }
try
{
@@ -84,7 +87,10 @@ public class PublishedContentTypeCache : IDisposable
/// An identifier.
public void ClearContentType(int id)
{
- _logger.LogDebug("Clear content type w/id {ContentTypeId}", id);
+ if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug))
+ {
+ _logger.LogDebug("Clear content type w/id {ContentTypeId}", id);
+ }
try
{
@@ -125,7 +131,10 @@ public class PublishedContentTypeCache : IDisposable
/// A data type identifier.
public void ClearDataType(int id)
{
- _logger.LogDebug("Clear data type w/id {DataTypeId}.", id);
+ if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug))
+ {
+ _logger.LogDebug("Clear data type w/id {DataTypeId}.", id);
+ }
// there is no recursion to handle here because a PublishedContentType contains *all* its
// properties ie both its own properties and those that were inherited (it's based upon an
diff --git a/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs b/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs
index 5bc005fc6d..19c947481d 100644
--- a/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs
+++ b/src/Umbraco.Infrastructure/Runtime/CoreRuntime.cs
@@ -236,7 +236,7 @@ public class CoreRuntime : IRuntime
private void AcquireMainDom()
{
- using DisposableTimer? timer = _profilingLogger.DebugDuration("Acquiring MainDom.", "Acquired.");
+ using DisposableTimer? timer = !_profilingLogger.IsEnabled(Core.Logging.LogLevel.Debug) ? null : _profilingLogger.DebugDuration("Acquiring MainDom.", "Acquired.");
try
{
@@ -257,18 +257,23 @@ public class CoreRuntime : IRuntime
return;
}
- using DisposableTimer? timer =
+ using DisposableTimer? timer = !_profilingLogger.IsEnabled(Core.Logging.LogLevel.Debug) ? null :
_profilingLogger.DebugDuration("Determining runtime level.", "Determined.");
try
{
State.DetermineRuntimeLevel();
-
- _logger.LogDebug("Runtime level: {RuntimeLevel} - {RuntimeLevelReason}", State.Level, State.Reason);
+ if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug))
+ {
+ _logger.LogDebug("Runtime level: {RuntimeLevel} - {RuntimeLevelReason}", State.Level, State.Reason);
+ }
if (State.Level == RuntimeLevel.Upgrade)
{
- _logger.LogDebug("Configure database factory for upgrades.");
+ if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug))
+ {
+ _logger.LogDebug("Configure database factory for upgrades.");
+ }
_databaseFactory.ConfigureForUpgrade();
}
}
diff --git a/src/Umbraco.Infrastructure/Runtime/FileSystemMainDomLock.cs b/src/Umbraco.Infrastructure/Runtime/FileSystemMainDomLock.cs
index 26b8d55f96..6dcd3ef9b0 100644
--- a/src/Umbraco.Infrastructure/Runtime/FileSystemMainDomLock.cs
+++ b/src/Umbraco.Infrastructure/Runtime/FileSystemMainDomLock.cs
@@ -44,16 +44,22 @@ internal class FileSystemMainDomLock : IMainDomLock
try
{
Directory.CreateDirectory(_hostingEnvironment.LocalTempPath);
- _logger.LogDebug("Attempting to obtain MainDom lock file handle {lockFilePath}", _lockFilePath);
+ if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug))
+ {
+ _logger.LogDebug("Attempting to obtain MainDom lock file handle {lockFilePath}", _lockFilePath);
+ }
_lockFileStream = File.Open(_lockFilePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
DeleteLockReleaseSignalFile();
return Task.FromResult(true);
}
catch (IOException)
{
- _logger.LogDebug(
+ if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug))
+ {
+ _logger.LogDebug(
"Couldn't obtain MainDom lock file handle, signalling for release of {lockFilePath}",
_lockFilePath);
+ }
CreateLockReleaseSignalFile();
}
catch (Exception ex)
@@ -107,13 +113,19 @@ internal class FileSystemMainDomLock : IMainDomLock
{
if (_cancellationTokenSource.IsCancellationRequested)
{
- _logger.LogDebug("ListenAsync Task canceled, exiting loop");
+ if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug))
+ {
+ _logger.LogDebug("ListenAsync Task canceled, exiting loop");
+ }
return;
}
if (File.Exists(_releaseSignalFilePath))
{
- _logger.LogDebug("Found lock release signal file, releasing lock on {lockFilePath}", _lockFilePath);
+ if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug))
+ {
+ _logger.LogDebug("Found lock release signal file, releasing lock on {lockFilePath}", _lockFilePath);
+ }
_lockFileStream?.Close();
_lockFileStream = null;
break;
diff --git a/src/Umbraco.Infrastructure/Runtime/RuntimeState.cs b/src/Umbraco.Infrastructure/Runtime/RuntimeState.cs
index 6597fadf61..37c99c64f2 100644
--- a/src/Umbraco.Infrastructure/Runtime/RuntimeState.cs
+++ b/src/Umbraco.Infrastructure/Runtime/RuntimeState.cs
@@ -168,7 +168,10 @@ public class RuntimeState : IRuntimeState
{
// local version *does* match code version, but the database is not configured
// install - may happen with Deploy/Cloud/etc
- _logger.LogDebug("Database is not configured, need to install Umbraco.");
+ if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug))
+ {
+ _logger.LogDebug("Database is not configured, need to install Umbraco.");
+ }
Level = RuntimeLevel.Install;
Reason = RuntimeLevelReason.InstallNoDatabase;
@@ -206,8 +209,11 @@ public class RuntimeState : IRuntimeState
{
case UmbracoDatabaseState.CannotConnect:
{
- // cannot connect to configured database, this is bad, fail
- _logger.LogDebug("Could not connect to database.");
+ // cannot connect to configured database, this is bad, fail
+ if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug))
+ {
+ _logger.LogDebug("Could not connect to database.");
+ }
if (_globalSettings.Value.InstallMissingDatabase || _databaseProviderMetadata.CanForceCreateDatabase(_databaseFactory))
{
@@ -231,12 +237,15 @@ public class RuntimeState : IRuntimeState
}
case UmbracoDatabaseState.NeedsUpgrade:
{
- // the db version does not match... but we do have a migration table
- // so, at least one valid table, so we quite probably are installed & need to upgrade
+ // the db version does not match... but we do have a migration table
+ // so, at least one valid table, so we quite probably are installed & need to upgrade
- // although the files version matches the code version, the database version does not
- // which means the local files have been upgraded but not the database - need to upgrade
- _logger.LogDebug("Has not reached the final upgrade step, need to upgrade Umbraco.");
+ // although the files version matches the code version, the database version does not
+ // which means the local files have been upgraded but not the database - need to upgrade
+ if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug))
+ {
+ _logger.LogDebug("Has not reached the final upgrade step, need to upgrade Umbraco.");
+ }
Level = _unattendedSettings.Value.UpgradeUnattended ? RuntimeLevel.Run : RuntimeLevel.Upgrade;
Reason = RuntimeLevelReason.UpgradeMigrations;
}
@@ -249,7 +258,10 @@ public class RuntimeState : IRuntimeState
if (_unattendedSettings.Value.PackageMigrationsUnattended)
{
- _logger.LogDebug("Package migrations need to execute.");
+ if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug))
+ {
+ _logger.LogDebug("Package migrations need to execute.");
+ }
Reason = RuntimeLevelReason.UpgradePackageMigrations;
}
else
@@ -354,9 +366,10 @@ public class RuntimeState : IRuntimeState
}
FinalMigrationState = upgrader.Plan.FinalState;
-
- _logger.LogDebug("Final upgrade state is {FinalMigrationState}, database contains {DatabaseState}", FinalMigrationState, CurrentMigrationState ?? "");
-
+ if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug))
+ {
+ _logger.LogDebug("Final upgrade state is {FinalMigrationState}, database contains {DatabaseState}", FinalMigrationState, CurrentMigrationState ?? "");
+ }
return CurrentMigrationState != FinalMigrationState;
}
@@ -373,8 +386,10 @@ public class RuntimeState : IRuntimeState
{
break;
}
-
- _logger.LogDebug("Could not immediately connect to database, trying again.");
+ if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug))
+ {
+ _logger.LogDebug("Could not immediately connect to database, trying again.");
+ }
Thread.Sleep(1000);
}
diff --git a/src/Umbraco.Infrastructure/Scoping/Scope.cs b/src/Umbraco.Infrastructure/Scoping/Scope.cs
index 0ff1fa5d30..295c92a6d6 100644
--- a/src/Umbraco.Infrastructure/Scoping/Scope.cs
+++ b/src/Umbraco.Infrastructure/Scoping/Scope.cs
@@ -75,7 +75,10 @@ namespace Umbraco.Cms.Infrastructure.Scoping
#if DEBUG_SCOPES
_scopeProvider.RegisterScope(this);
#endif
- logger.LogTrace("Create {InstanceId} on thread {ThreadId}", InstanceId.ToString("N").Substring(0, 8), Thread.CurrentThread.ManagedThreadId);
+ if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Trace))
+ {
+ logger.LogTrace("Create {InstanceId} on thread {ThreadId}", InstanceId.ToString("N").Substring(0, 8), Thread.CurrentThread.ManagedThreadId);
+ }
if (detachable)
{
diff --git a/src/Umbraco.Infrastructure/Security/MemberPasswordHasher.cs b/src/Umbraco.Infrastructure/Security/MemberPasswordHasher.cs
index 034014663d..3c7e4eabee 100644
--- a/src/Umbraco.Infrastructure/Security/MemberPasswordHasher.cs
+++ b/src/Umbraco.Infrastructure/Security/MemberPasswordHasher.cs
@@ -107,8 +107,11 @@ public class MemberPasswordHasher : UmbracoPasswordHasher
}
else
{
- _logger.LogDebug(
+ if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug))
+ {
+ _logger.LogDebug(
"Unable to determine member password hashing algorithm, but this can happen when member enters a wrong password, before it has be rehashed");
+ }
}
return PasswordVerificationResult.Failed;
diff --git a/src/Umbraco.Infrastructure/Services/CacheInstructionService.cs b/src/Umbraco.Infrastructure/Services/CacheInstructionService.cs
index 53be47e155..f47210fa49 100644
--- a/src/Umbraco.Infrastructure/Services/CacheInstructionService.cs
+++ b/src/Umbraco.Infrastructure/Services/CacheInstructionService.cs
@@ -154,7 +154,7 @@ namespace Umbraco.Cms
DateTime lastPruned,
int lastId)
{
- using (_profilingLogger.DebugDuration("Syncing from database..."))
+ using (!_profilingLogger.IsEnabled(Core.Logging.LogLevel.Debug) ? null : _profilingLogger.DebugDuration("Syncing from database..."))
using (ICoreScope scope = ScopeProvider.CreateCoreScope())
{
var numberOfInstructionsProcessed = ProcessDatabaseInstructions(cacheRefreshers, cancellationToken, localIdentity, ref lastId);
diff --git a/src/Umbraco.Infrastructure/Sync/ServerMessengerBase.cs b/src/Umbraco.Infrastructure/Sync/ServerMessengerBase.cs
index 20d251696b..1f158fcdf8 100644
--- a/src/Umbraco.Infrastructure/Sync/ServerMessengerBase.cs
+++ b/src/Umbraco.Infrastructure/Sync/ServerMessengerBase.cs
@@ -228,10 +228,12 @@ public abstract class ServerMessengerBase : IServerMessenger
{
throw new ArgumentNullException(nameof(refresher));
}
-
- StaticApplicationLogging.Logger.LogDebug(
+ if (StaticApplicationLogging.Logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug))
+ {
+ StaticApplicationLogging.Logger.LogDebug(
"Invoking refresher {RefresherType} on local server for message type RefreshByPayload",
refresher.GetType());
+ }
var payloadRefresher = refresher as IPayloadCacheRefresher;
if (payloadRefresher == null)
@@ -260,9 +262,11 @@ public abstract class ServerMessengerBase : IServerMessenger
{
throw new ArgumentNullException(nameof(refresher));
}
-
- StaticApplicationLogging.Logger.LogDebug(
+ if (StaticApplicationLogging.Logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug))
+ {
+ StaticApplicationLogging.Logger.LogDebug(
"Invoking refresher {RefresherType} on local server for message type {MessageType}", refresher.GetType(), messageType);
+ }
switch (messageType)
{
@@ -350,9 +354,11 @@ public abstract class ServerMessengerBase : IServerMessenger
{
throw new ArgumentNullException(nameof(refresher));
}
-
- StaticApplicationLogging.Logger.LogDebug(
+ if (StaticApplicationLogging.Logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug))
+ {
+ StaticApplicationLogging.Logger.LogDebug(
"Invoking refresher {RefresherType} on local server for message type {MessageType}", refresher.GetType(), messageType);
+ }
var typedRefresher = refresher as ICacheRefresher;
diff --git a/src/Umbraco.PublishedCache.NuCache/PublishedSnapshotService.cs b/src/Umbraco.PublishedCache.NuCache/PublishedSnapshotService.cs
index fe3c2836c5..68b50cfd91 100644
--- a/src/Umbraco.PublishedCache.NuCache/PublishedSnapshotService.cs
+++ b/src/Umbraco.PublishedCache.NuCache/PublishedSnapshotService.cs
@@ -181,7 +181,10 @@ internal class PublishedSnapshotService : IPublishedSnapshotService
foreach (ContentTypeCacheRefresher.JsonPayload payload in payloads)
{
- _logger.LogDebug("Notified {ChangeTypes} for {ItemType} {ItemId}", payload.ChangeTypes, payload.ItemType, payload.Id);
+ if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug))
+ {
+ _logger.LogDebug("Notified {ChangeTypes} for {ItemType} {ItemId}", payload.ChangeTypes, payload.ItemType, payload.Id);
+ }
}
Notify(_contentStore, payloads, RefreshContentTypesLocked);
@@ -230,10 +233,13 @@ internal class PublishedSnapshotService : IPublishedSnapshotService
foreach (DataTypeCacheRefresher.JsonPayload payload in payloads)
{
- _logger.LogDebug(
+ if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug))
+ {
+ _logger.LogDebug(
"Notified {RemovedStatus} for data type {DataTypeId}",
payload.Removed ? "Removed" : "Refreshed",
payload.Id);
+ }
}
using (_contentStore.GetScopedWriteLock(_scopeProvider))
@@ -622,15 +628,23 @@ internal class PublishedSnapshotService : IPublishedSnapshotService
///
private void MainDomRelease()
{
- _logger.LogDebug("Releasing from MainDom...");
+ if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug))
+ {
+ _logger.LogDebug("Releasing from MainDom...");
+ }
lock (_storesLock)
{
- _logger.LogDebug("Releasing content store...");
+ if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug))
+ {
+ _logger.LogDebug("Releasing content store...");
+ }
_contentStore?.ReleaseLocalDb(); // null check because we could shut down before being assigned
_localContentDb = null;
-
- _logger.LogDebug("Releasing media store...");
+ if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug))
+ {
+ _logger.LogDebug("Releasing media store...");
+ }
_mediaStore?.ReleaseLocalDb(); // null check because we could shut down before being assigned
_localMediaDb = null;
@@ -742,8 +756,10 @@ internal class PublishedSnapshotService : IPublishedSnapshotService
// beware! at that point the cache is inconsistent,
// assuming we are going to SetAll content items!
_localMediaDb?.Clear();
-
- _logger.LogDebug("Loading media from database...");
+ if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug))
+ {
+ _logger.LogDebug("Loading media from database...");
+ }
// IMPORTANT GetAllMediaSources sorts kits by level + parentId + sortOrder
try
@@ -852,7 +868,10 @@ internal class PublishedSnapshotService : IPublishedSnapshotService
// contentStore is write-locked during changes - see note above, calls to this method are wrapped in contentStore.GetScopedWriteLock
foreach (ContentCacheRefresher.JsonPayload payload in payloads)
{
- _logger.LogDebug("Notified {ChangeTypes} for content {ContentId}", payload.ChangeTypes, payload.Id);
+ if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug))
+ {
+ _logger.LogDebug("Notified {ChangeTypes} for content {ContentId}", payload.ChangeTypes, payload.Id);
+ }
if (payload.ChangeTypes.HasType(TreeChangeTypes.RefreshAll))
{
@@ -926,7 +945,10 @@ internal class PublishedSnapshotService : IPublishedSnapshotService
// see notes for content cache refresher
foreach (MediaCacheRefresher.JsonPayload payload in payloads)
{
- _logger.LogDebug("Notified {ChangeTypes} for media {MediaId}", payload.ChangeTypes, payload.Id);
+ if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug))
+ {
+ _logger.LogDebug("Notified {ChangeTypes} for media {MediaId}", payload.ChangeTypes, payload.Id);
+ }
if (payload.ChangeTypes.HasType(TreeChangeTypes.RefreshAll))
{
diff --git a/src/Umbraco.Web.BackOffice/Controllers/ExamineManagementController.cs b/src/Umbraco.Web.BackOffice/Controllers/ExamineManagementController.cs
index 0fac0e482e..e59d3166bb 100644
--- a/src/Umbraco.Web.BackOffice/Controllers/ExamineManagementController.cs
+++ b/src/Umbraco.Web.BackOffice/Controllers/ExamineManagementController.cs
@@ -266,8 +266,10 @@ public class ExamineManagementController : UmbracoAuthorizedJsonController
private void Indexer_IndexOperationComplete(object? sender, EventArgs e)
{
var indexer = (IIndex?)sender;
-
- _logger.LogDebug("Logging operation completed for index {IndexName}", indexer?.Name);
+ if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug))
+ {
+ _logger.LogDebug("Logging operation completed for index {IndexName}", indexer?.Name);
+ }
if (indexer is not null)
{
diff --git a/src/Umbraco.Web.BackOffice/Controllers/RedirectUrlManagementController.cs b/src/Umbraco.Web.BackOffice/Controllers/RedirectUrlManagementController.cs
index c4d7d47d87..d87398d574 100644
--- a/src/Umbraco.Web.BackOffice/Controllers/RedirectUrlManagementController.cs
+++ b/src/Umbraco.Web.BackOffice/Controllers/RedirectUrlManagementController.cs
@@ -116,7 +116,10 @@ public class RedirectUrlManagementController : UmbracoAuthorizedApiController
{
var errorMessage =
"User is not a member of the administrators group and so is not allowed to toggle the URL tracker";
- _logger.LogDebug(errorMessage);
+ if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug))
+ {
+ _logger.LogDebug(errorMessage);
+ }
throw new SecurityException(errorMessage);
}
diff --git a/src/Umbraco.Web.BackOffice/Filters/FileUploadCleanupFilterAttribute.cs b/src/Umbraco.Web.BackOffice/Filters/FileUploadCleanupFilterAttribute.cs
index 474b1ef581..60f70c021a 100644
--- a/src/Umbraco.Web.BackOffice/Filters/FileUploadCleanupFilterAttribute.cs
+++ b/src/Umbraco.Web.BackOffice/Filters/FileUploadCleanupFilterAttribute.cs
@@ -104,8 +104,10 @@ public sealed class FileUploadCleanupFilterAttribute : TypeFilterAttribute
{
tempFolders.Add(dir);
}
-
- _logger.LogDebug("Removing temp file {FileName}", f.TempFilePath);
+ if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug))
+ {
+ _logger.LogDebug("Removing temp file {FileName}", f.TempFilePath);
+ }
try
{
diff --git a/src/Umbraco.Web.BackOffice/HealthChecks/HealthCheckController.cs b/src/Umbraco.Web.BackOffice/HealthChecks/HealthCheckController.cs
index 34adf15a94..9744ed8c5f 100644
--- a/src/Umbraco.Web.BackOffice/HealthChecks/HealthCheckController.cs
+++ b/src/Umbraco.Web.BackOffice/HealthChecks/HealthCheckController.cs
@@ -76,7 +76,10 @@ public class HealthCheckController : UmbracoAuthorizedJsonController
try
{
- _logger.LogDebug("Running health check: " + check.Name);
+ if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug))
+ {
+ _logger.LogDebug("Running health check: " + check.Name);
+ }
return await check.GetStatus();
}
catch (Exception ex)
diff --git a/src/Umbraco.Web.BackOffice/Install/InstallApiController.cs b/src/Umbraco.Web.BackOffice/Install/InstallApiController.cs
index 52068c6f8d..5708b3c4fd 100644
--- a/src/Umbraco.Web.BackOffice/Install/InstallApiController.cs
+++ b/src/Umbraco.Web.BackOffice/Install/InstallApiController.cs
@@ -278,7 +278,7 @@ public class InstallApiController : ControllerBase
// executes the step
internal async Task ExecuteStepAsync(InstallSetupStep step, object? instruction)
{
- using (_proflog.TraceDuration($"Executing installation step: '{step.Name}'.", "Step completed"))
+ using (!_proflog.IsEnabled(Core.Logging.LogLevel.Verbose) ? null : _proflog.TraceDuration($"Executing installation step: '{step.Name}'.", "Step completed"))
{
Attempt modelAttempt = instruction.TryConvertTo(step.StepType);
if (!modelAttempt.Success)
diff --git a/src/Umbraco.Web.Common/Controllers/RenderController.cs b/src/Umbraco.Web.Common/Controllers/RenderController.cs
index dad8d8a84b..4b9ab5d98d 100644
--- a/src/Umbraco.Web.Common/Controllers/RenderController.cs
+++ b/src/Umbraco.Web.Common/Controllers/RenderController.cs
@@ -55,12 +55,14 @@ public class RenderController : UmbracoPageController, IRenderController
public override async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
IPublishedRequest pcr = UmbracoRouteValues.PublishedRequest;
-
- _logger.LogDebug(
+ if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug))
+ {
+ _logger.LogDebug(
"Response status: Content={Content}, StatusCode={ResponseStatusCode}, Culture={Culture}",
pcr.PublishedContent?.Id ?? -1,
pcr.ResponseStatusCode,
pcr.Culture);
+ }
UmbracoRouteResult routeStatus = pcr.GetRouteResult();
switch (routeStatus)
diff --git a/src/Umbraco.Web.Common/Macros/MacroRenderer.cs b/src/Umbraco.Web.Common/Macros/MacroRenderer.cs
index 9ff69bcb7a..1bc46f0db0 100644
--- a/src/Umbraco.Web.Common/Macros/MacroRenderer.cs
+++ b/src/Umbraco.Web.Common/Macros/MacroRenderer.cs
@@ -249,9 +249,10 @@ public class MacroRenderer : IMacroRenderer
{
return null;
}
-
- _logger.LogDebug("Macro content loaded from cache '{MacroCacheId}'", model.CacheIdentifier);
-
+ if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug))
+ {
+ _logger.LogDebug("Macro content loaded from cache '{MacroCacheId}'", model.CacheIdentifier);
+ }
// ensure that the source has not changed
// note: does not handle dependencies, and never has
FileInfo? macroSource = GetMacroFile(model); // null if macro is not file-based
@@ -259,13 +260,19 @@ public class MacroRenderer : IMacroRenderer
{
if (macroSource.Exists == false)
{
- _logger.LogDebug("Macro source does not exist anymore, ignore cache.");
+ if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug))
+ {
+ _logger.LogDebug("Macro source does not exist anymore, ignore cache.");
+ }
return null;
}
if (macroContent.Date < macroSource.LastWriteTime)
{
- _logger.LogDebug("Macro source has changed, ignore cache.");
+ if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug))
+ {
+ _logger.LogDebug("Macro source has changed, ignore cache.");
+ }
return null;
}
}
@@ -304,8 +311,10 @@ public class MacroRenderer : IMacroRenderer
CacheKeys.MacroContentCacheKey + model.CacheIdentifier,
() => macroContent,
new TimeSpan(0, 0, model.CacheDuration));
-
- _logger.LogDebug("Macro content saved to cache '{MacroCacheId}'", model.CacheIdentifier);
+ if (_logger.IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug))
+ {
+ _logger.LogDebug("Macro content saved to cache '{MacroCacheId}'", model.CacheIdentifier);
+ }
}
// gets the macro source file name
@@ -372,7 +381,7 @@ public class MacroRenderer : IMacroRenderer
}
var macroInfo = $"Render Macro: {macro.Name}, cache: {macro.CacheDuration}";
- using (_profilingLogger.DebugDuration(macroInfo, "Rendered Macro."))
+ using (!_profilingLogger.IsEnabled(Core.Logging.LogLevel.Debug) ? null : _profilingLogger.DebugDuration(macroInfo, "Rendered Macro."))
{
// parse macro parameters ie replace the special [#key], [$key], etc. syntaxes
foreach (MacroPropertyModel prop in macro.Properties)
@@ -424,7 +433,7 @@ public class MacroRenderer : IMacroRenderer
///