From d0eb01b348babf28d912041263dc50bc26cc2000 Mon Sep 17 00:00:00 2001 From: Bjarke Berg Date: Mon, 12 Oct 2020 15:22:11 +0200 Subject: [PATCH] Added fix for RelateOnTrashComponent.MediaService_Trashed so relations are looked up before creating duplicates Signed-off-by: Bjarke Berg --- src/Umbraco.Core/Services/IRelationService.cs | 10 +++ .../Compose/RelateOnTrashComponent.cs | 84 +++++++++++-------- .../Services/Implement/RelationService.cs | 12 +++ 3 files changed, 72 insertions(+), 34 deletions(-) diff --git a/src/Umbraco.Core/Services/IRelationService.cs b/src/Umbraco.Core/Services/IRelationService.cs index bf8bcd5b2a..9cb07d27e8 100644 --- a/src/Umbraco.Core/Services/IRelationService.cs +++ b/src/Umbraco.Core/Services/IRelationService.cs @@ -341,5 +341,15 @@ namespace Umbraco.Core.Services /// /// to Delete Relations for void DeleteRelationsOfType(IRelationType relationType); + + /// + /// Gets a relation by the unique combination of parentId, childId and relationType. + /// + /// The id of the parent item. + /// The id of the child item. + /// The RelationType. + /// The relation or null + IRelation GetByParentChildAndType(int parentId, int childId, IRelationType relationType); + } } diff --git a/src/Umbraco.Infrastructure/Compose/RelateOnTrashComponent.cs b/src/Umbraco.Infrastructure/Compose/RelateOnTrashComponent.cs index aa92972e9c..9bae2847f0 100644 --- a/src/Umbraco.Infrastructure/Compose/RelateOnTrashComponent.cs +++ b/src/Umbraco.Infrastructure/Compose/RelateOnTrashComponent.cs @@ -2,6 +2,7 @@ using Umbraco.Core.Composing; using Umbraco.Core.Events; using Umbraco.Core.Models; +using Umbraco.Core.Scoping; using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; @@ -13,13 +14,20 @@ namespace Umbraco.Core.Compose private readonly IEntityService _entityService; private readonly ILocalizedTextService _textService; private readonly IAuditService _auditService; + private readonly IScopeProvider _scopeProvider; - public RelateOnTrashComponent(IRelationService relationService, IEntityService entityService, ILocalizedTextService textService, IAuditService auditService) + public RelateOnTrashComponent( + IRelationService relationService, + IEntityService entityService, + ILocalizedTextService textService, + IAuditService auditService, + IScopeProvider scopeProvider) { _relationService = relationService; _entityService = entityService; _textService = textService; _auditService = auditService; + _scopeProvider = scopeProvider; } public void Initialize() @@ -68,47 +76,55 @@ namespace Umbraco.Core.Compose private void ContentService_Trashed(IContentService sender, MoveEventArgs e) { - const string relationTypeAlias = Constants.Conventions.RelationTypes.RelateParentDocumentOnDeleteAlias; - var relationType = _relationService.GetRelationTypeByAlias(relationTypeAlias); - - // check that the relation-type exists, if not, then recreate it - if (relationType == null) + using (var scope = _scopeProvider.CreateScope()) { - var documentObjectType = Constants.ObjectTypes.Document; - const string relationTypeName = Constants.Conventions.RelationTypes.RelateParentDocumentOnDeleteName; + const string relationTypeAlias = Constants.Conventions.RelationTypes.RelateParentDocumentOnDeleteAlias; + var relationType = _relationService.GetRelationTypeByAlias(relationTypeAlias); - relationType = new RelationType(relationTypeName, relationTypeAlias, false, documentObjectType, documentObjectType); - _relationService.Save(relationType); - } - - foreach (var item in e.MoveInfoCollection) - { - var originalPath = item.OriginalPath.ToDelimitedList(); - var originalParentId = originalPath.Count > 2 - ? int.Parse(originalPath[originalPath.Count - 2]) - : Constants.System.Root; - - //before we can create this relation, we need to ensure that the original parent still exists which - //may not be the case if the encompassing transaction also deleted it when this item was moved to the bin - - if (_entityService.Exists(originalParentId)) + // check that the relation-type exists, if not, then recreate it + if (relationType == null) { - // Add a relation for the item being deleted, so that we can know the original parent for if we need to restore later - var relation = new Relation(originalParentId, item.Entity.Id, relationType); - _relationService.Save(relation); + var documentObjectType = Constants.ObjectTypes.Document; + const string relationTypeName = + Constants.Conventions.RelationTypes.RelateParentDocumentOnDeleteName; - _auditService.Add(AuditType.Delete, - item.Entity.WriterId, - item.Entity.Id, - ObjectTypes.GetName(UmbracoObjectTypes.Document), - string.Format(_textService.Localize( - "recycleBin/contentTrashed"), - item.Entity.Id, originalParentId)); + relationType = new RelationType(relationTypeName, relationTypeAlias, false, documentObjectType, + documentObjectType); + _relationService.Save(relationType); } + + foreach (var item in e.MoveInfoCollection) + { + var originalPath = item.OriginalPath.ToDelimitedList(); + var originalParentId = originalPath.Count > 2 + ? int.Parse(originalPath[originalPath.Count - 2]) + : Constants.System.Root; + + //before we can create this relation, we need to ensure that the original parent still exists which + //may not be the case if the encompassing transaction also deleted it when this item was moved to the bin + + if (_entityService.Exists(originalParentId)) + { + // Add a relation for the item being deleted, so that we can know the original parent for if we need to restore later + var relation = _relationService.GetByParentChildAndType(originalParentId, item.Entity.Id, relationType) ?? + new Relation(originalParentId, item.Entity.Id, relationType); + _relationService.Save(relation); + + _auditService.Add(AuditType.Delete, + item.Entity.WriterId, + item.Entity.Id, + ObjectTypes.GetName(UmbracoObjectTypes.Document), + string.Format(_textService.Localize( + "recycleBin/contentTrashed"), + item.Entity.Id, originalParentId)); + } + } + + scope.Complete(); } } - private void MediaService_Trashed(IMediaService sender, MoveEventArgs e) + public void MediaService_Trashed(IMediaService sender, MoveEventArgs e) { const string relationTypeAlias = Constants.Conventions.RelationTypes.RelateParentMediaFolderOnDeleteAlias; var relationType = _relationService.GetRelationTypeByAlias(relationTypeAlias); diff --git a/src/Umbraco.Infrastructure/Services/Implement/RelationService.cs b/src/Umbraco.Infrastructure/Services/Implement/RelationService.cs index ddec99e692..fce98f3378 100644 --- a/src/Umbraco.Infrastructure/Services/Implement/RelationService.cs +++ b/src/Umbraco.Infrastructure/Services/Implement/RelationService.cs @@ -543,6 +543,18 @@ namespace Umbraco.Core.Services.Implement } } + /// + public IRelation GetByParentChildAndType(int parentId, int childId, IRelationType relationType) + { + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) + { + var query = Query().Where(x => x.ParentId == parentId && + x.ChildId == childId && + x.RelationTypeId == relationType.Id); + return _relationRepository.Get(query).FirstOrDefault(); + } + } + #region Private Methods private IRelationType GetRelationType(string relationTypeAlias)