From 5d0486fddc3801de3680a66dce777f59768393fa Mon Sep 17 00:00:00 2001 From: Mehmet <36473707+ustadstar@users.noreply.github.com> Date: Tue, 6 Feb 2024 15:50:16 +0100 Subject: [PATCH] Add missing list view usages to data type references (#14485) (#14617) * Add missing list view usages to data type references (#14485) * Added default implementation #14617 --- .../ContentEditing/DataTypeReferences.cs | 11 +++ .../Repositories/IDataTypeRepository.cs | 9 +++ src/Umbraco.Core/Services/DataTypeService.cs | 6 ++ src/Umbraco.Core/Services/IDataTypeService.cs | 1 + .../Implement/DataTypeRepository.cs | 81 +++++++++++++++++++ .../Controllers/DataTypeController.cs | 34 +++++++- .../views/dataTypes/views/datatype.info.html | 8 +- 7 files changed, 145 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Core/Models/ContentEditing/DataTypeReferences.cs b/src/Umbraco.Core/Models/ContentEditing/DataTypeReferences.cs index 47711fc0a3..3d6f0fabce 100644 --- a/src/Umbraco.Core/Models/ContentEditing/DataTypeReferences.cs +++ b/src/Umbraco.Core/Models/ContentEditing/DataTypeReferences.cs @@ -1,4 +1,5 @@ using System.Runtime.Serialization; +using System.Xml.Linq; namespace Umbraco.Cms.Core.Models.ContentEditing; @@ -20,6 +21,9 @@ public class DataTypeReferences [DataMember(Name = "properties")] public object? Properties { get; set; } + [DataMember(Name = "listViews")] + public object? ListViews { get; set; } + [DataContract(Name = "property", Namespace = "")] public class PropertyTypeReferences { @@ -29,5 +33,12 @@ public class DataTypeReferences [DataMember(Name = "alias")] public string? Alias { get; set; } } + + [DataContract(Name = "listView", Namespace = "")] + public class ListViewReferences + { + [DataMember(Name = "name")] + public string? Name { get; set; } + } } } diff --git a/src/Umbraco.Core/Persistence/Repositories/IDataTypeRepository.cs b/src/Umbraco.Core/Persistence/Repositories/IDataTypeRepository.cs index 060d2f2e1d..4da8fa2a3a 100644 --- a/src/Umbraco.Core/Persistence/Repositories/IDataTypeRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/IDataTypeRepository.cs @@ -14,4 +14,13 @@ public interface IDataTypeRepository : IReadWriteQueryRepository /// /// IReadOnlyDictionary> FindUsages(int id); + + /// + /// Returns a dictionary of content type s and the data type (List view) aliases that use a + /// + /// + /// + /// + + IReadOnlyDictionary> FindListViewUsages(int id) => throw new NotImplementedException(); } diff --git a/src/Umbraco.Core/Services/DataTypeService.cs b/src/Umbraco.Core/Services/DataTypeService.cs index 857ecdc347..32ba152e28 100644 --- a/src/Umbraco.Core/Services/DataTypeService.cs +++ b/src/Umbraco.Core/Services/DataTypeService.cs @@ -612,6 +612,12 @@ namespace Umbraco.Cms.Core.Services.Implement return _dataTypeRepository.FindUsages(id); } + public IReadOnlyDictionary> GetListViewReferences(int id) + { + using ICoreScope scope = ScopeProvider.CreateCoreScope(autoComplete: true); + return _dataTypeRepository.FindListViewUsages(id); + } + private void Audit(AuditType type, int userId, int objectId) { _auditRepository.Save(new AuditItem(objectId, type, userId, ObjectTypes.GetName(UmbracoObjectTypes.DataType))); diff --git a/src/Umbraco.Core/Services/IDataTypeService.cs b/src/Umbraco.Core/Services/IDataTypeService.cs index 035c7e8a7b..20e065b7e0 100644 --- a/src/Umbraco.Core/Services/IDataTypeService.cs +++ b/src/Umbraco.Core/Services/IDataTypeService.cs @@ -14,6 +14,7 @@ public interface IDataTypeService : IService /// /// IReadOnlyDictionary> GetReferences(int id); + IReadOnlyDictionary> GetListViewReferences(int id) => throw new NotImplementedException(); Attempt?> CreateContainer(int parentId, Guid key, string name, int userId = Constants.Security.SuperUserId); diff --git a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DataTypeRepository.cs b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DataTypeRepository.cs index 9f9d685552..f71d8cce43 100644 --- a/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DataTypeRepository.cs +++ b/src/Umbraco.Infrastructure/Persistence/Repositories/Implement/DataTypeRepository.cs @@ -1,5 +1,6 @@ using System.Data; using System.Globalization; +using System.Xml.Linq; using Microsoft.Extensions.Logging; using NPoco; using Umbraco.Cms.Core; @@ -10,6 +11,7 @@ using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.Persistence.Querying; using Umbraco.Cms.Core.Persistence.Repositories; using Umbraco.Cms.Core.PropertyEditors; +using Umbraco.Cms.Core.Scoping; using Umbraco.Cms.Core.Serialization; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Infrastructure.Persistence.Dtos; @@ -17,6 +19,7 @@ using Umbraco.Cms.Infrastructure.Persistence.Factories; using Umbraco.Cms.Infrastructure.Persistence.Querying; using Umbraco.Cms.Infrastructure.Scoping; using Umbraco.Extensions; +using static Umbraco.Cms.Core.Constants.SqlTemplates; using static Umbraco.Cms.Core.Persistence.SqlExtensionsStatics; namespace Umbraco.Cms.Infrastructure.Persistence.Repositories.Implement; @@ -124,6 +127,84 @@ internal class DataTypeRepository : EntityRepositoryBase, IDataT x => (IEnumerable)x.PropertyTypes.Select(p => p.Alias).ToList()); } + public IReadOnlyDictionary> FindListViewUsages(int id) + { + var usages = new Dictionary>(); + + if (id == default) + { + return usages; + } + + IDataType? dataType = Get(id); + + if (dataType != null && dataType.EditorAlias.Equals(Constants.PropertyEditors.Aliases.ListView)) + { + // Get All contentTypes where isContainer (list view enabled) is set to true + Sql sql = Sql() + .Select(ct => ct.Select(node => node.NodeDto)) + .From() + .InnerJoin().On(n => n.NodeId, ct => ct.NodeId) + .Where(ct => ct.IsContainer == true); + + List ctds = Database.Fetch(sql); + + // If there are not any ContentTypes with a ListView return. + if (!ctds.Any()) + { + return usages; + } + + // First check if it is a custom list view + ContentTypeDto? customListView = ctds.Where(x => (Constants.Conventions.DataTypes.ListViewPrefix + x.Alias).Equals(dataType.Name)).FirstOrDefault(); + + if (customListView != null) + { + // Add usages as customListView + usages.Add( + new GuidUdi(ObjectTypes.GetUdiType(customListView.NodeDto.NodeObjectType!.Value), customListView.NodeDto.UniqueId), + new List { dataType.Name! }); + } + else + { + // It is not a custom ListView, so check the default ones. + foreach (ContentTypeDto contentWithListView in ctds) + { + var customListViewName = Constants.Conventions.DataTypes.ListViewPrefix + contentWithListView.Alias; + IDataType? clv = Get(Query().Where(x => x.Name == customListViewName))?.FirstOrDefault(); + + // Check if the content type has a custom listview (extra check to prevent duplicates) + if (clv == null) + { + // ContentType has no custom listview so it uses the default one + var udi = new GuidUdi(ObjectTypes.GetUdiType(contentWithListView.NodeDto.NodeObjectType!.Value), contentWithListView.NodeDto.UniqueId); + var listViewType = new List(); + + if (dataType.Id.Equals(Constants.DataTypes.DefaultContentListView) && udi.EntityType == ObjectTypes.GetUdiType(UmbracoObjectTypes.DocumentType)) + listViewType.Add(Constants.Conventions.DataTypes.ListViewPrefix + "Content"); + else if (dataType.Id.Equals(Constants.DataTypes.DefaultMediaListView) && udi.EntityType == ObjectTypes.GetUdiType(UmbracoObjectTypes.MediaType)) + listViewType.Add(Constants.Conventions.DataTypes.ListViewPrefix + "Media"); + else if (dataType.Id.Equals(Constants.DataTypes.DefaultMembersListView) && udi.EntityType == ObjectTypes.GetUdiType(UmbracoObjectTypes.MemberType)) + listViewType.Add(Constants.Conventions.DataTypes.ListViewPrefix + "Members"); + + if (listViewType.Any()) + { + var added = usages.TryAdd(udi, listViewType); + if (!added) + { + usages[udi] = usages[udi].Append(dataType.Name!); + } + } + } + } + + } + } + + return usages; + } + + #region Overrides of RepositoryBase protected override IDataType? PerformGet(int id) => GetMany(id).FirstOrDefault(); diff --git a/src/Umbraco.Web.BackOffice/Controllers/DataTypeController.cs b/src/Umbraco.Web.BackOffice/Controllers/DataTypeController.cs index 6e559a7c68..0b12e92d66 100644 --- a/src/Umbraco.Web.BackOffice/Controllers/DataTypeController.cs +++ b/src/Umbraco.Web.BackOffice/Controllers/DataTypeController.cs @@ -430,7 +430,8 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers var result = new DataTypeReferences(); var usages = _dataTypeService.GetReferences(id); - foreach(var groupOfEntityType in usages.GroupBy(x => x.Key.EntityType)) + // properties + foreach (var groupOfEntityType in usages.GroupBy(x => x.Key.EntityType)) { //get all the GUIDs for the content types to find var guidsAndPropertyAliases = groupOfEntityType.ToDictionary(i => ((GuidUdi)i.Key).Guid, i => i.Value); @@ -443,6 +444,21 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers result.MemberTypes = GetContentTypeUsages(_memberTypeService.GetAll(guidsAndPropertyAliases.Keys), guidsAndPropertyAliases); } + // ListView + var listViewUsages = _dataTypeService.GetListViewReferences(id); + foreach (var groupOfEntityType in listViewUsages.GroupBy(x => x.Key.EntityType)) + { + //get all the GUIDs for the content types to find + var guidsAndPropertyAliases = groupOfEntityType.ToDictionary(i => ((GuidUdi)i.Key).Guid, i => i.Value); + + if (groupOfEntityType.Key == ObjectTypes.GetUdiType(UmbracoObjectTypes.DocumentType)) + result.DocumentTypes = result.DocumentTypes.Concat(GetListViewContentTypeUsages(_contentTypeService.GetAll(guidsAndPropertyAliases.Keys), guidsAndPropertyAliases)); + else if (groupOfEntityType.Key == ObjectTypes.GetUdiType(UmbracoObjectTypes.MediaType)) + result.MediaTypes = result.MediaTypes.Concat(GetListViewContentTypeUsages(_mediaTypeService.GetAll(guidsAndPropertyAliases.Keys), guidsAndPropertyAliases)); + else if (groupOfEntityType.Key == ObjectTypes.GetUdiType(UmbracoObjectTypes.MemberType)) + result.MemberTypes = result.MemberTypes.Concat(GetListViewContentTypeUsages(_memberTypeService.GetAll(guidsAndPropertyAliases.Keys), guidsAndPropertyAliases)); + } + return result; } @@ -481,6 +497,22 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers }); } + private IEnumerable GetListViewContentTypeUsages( + IEnumerable cts, + IReadOnlyDictionary> usages) => cts.Select(x => new DataTypeReferences.ContentTypeReferences + { + Id = x.Id, + Key = x.Key, + Alias = x.Alias, + Icon = x.Icon, + Name = x.Name, + Udi = new GuidUdi(ObjectTypes.GetUdiType(UmbracoObjectTypes.DocumentType), x.Key), + ListViews = usages.GetValueOrDefault(x.Key)?.Select(lv => new DataTypeReferences.ContentTypeReferences.ListViewReferences + { + Name = lv + }) + }); + #region ReadOnly actions to return basic data - allow access for: content ,media, members, settings, developer /// /// Gets the content json for all data types diff --git a/src/Umbraco.Web.UI.Client/src/views/dataTypes/views/datatype.info.html b/src/Umbraco.Web.UI.Client/src/views/dataTypes/views/datatype.info.html index b5dd3c9271..ac414fbbc4 100644 --- a/src/Umbraco.Web.UI.Client/src/views/dataTypes/views/datatype.info.html +++ b/src/Umbraco.Web.UI.Client/src/views/dataTypes/views/datatype.info.html @@ -42,7 +42,7 @@
{{::reference.name}}
{{::reference.alias}}
-
{{::reference.properties | umbCmsJoinArray:', ':'name'}}
+
{{::reference.properties | umbCmsJoinArray:', ':'name'}} {{::reference.listViews | umbCmsJoinArray:', ':'name'}}
@@ -52,7 +52,7 @@
- +
Used in Media Types
@@ -72,7 +72,7 @@
{{::reference.name}}
{{::reference.alias}}
-
{{::reference.properties | umbCmsJoinArray:', ':'name'}}
+
{{::reference.properties | umbCmsJoinArray:', ':'name'}} {{::reference.listViews | umbCmsJoinArray:', ':'name'}}
@@ -103,7 +103,7 @@
{{::reference.name}}
{{::reference.alias}}
-
{{::reference.properties | umbCmsJoinArray:', ':'name'}}
+
{{::reference.properties | umbCmsJoinArray:', ':'name'}} {{::reference.listViews | umbCmsJoinArray:', ':'name'}}