* Adding TrackedReferencesController * Adding/changing views * Adding/Editing js files * RelationService changes * RelationRepository changes * Adding missing translations * Adding/Modifying tests * Beginning of #9125 migration * Introducing a new component + refactoring based on that * Abstracting + refactoring * Work on content unpublishing * Work on media.delete * Various small changes * Beginning of #9119 migration * Changes on content.delete * Various fixes * Adding new keys used in the listview bulk actions * Adding methods to get the items used in relations from array of ids * Adding the checkLinkedItems function to the trackedReferencesResource * Passing the selected items from a listview to unpublish and delete * Adding umb-tracked-references-listview * Adding umb-tracked-references-listview-table with language column * Fixes for tracked references * Changes in listview unpublish dialog * Changes in listview delete dialog * Removing Variants logic as it is not currently supported * Visual fixes * Closing dialogs on click * Fix wording * Fix breaking changes * Change to a single title "Items in use" instead of 2 different for Content and Media * No need for obsoleting because we can change new controllers * Return ActionResult from actions * V9: Prevent delete or unpublish of items that have references (#12047) * Introducing config settings that prevent delete or unpublish of items referenced by other items * Disable deletion of content items and show a new warning * Disable deletion of media items and show a new warning * Disable deletion of list view items * Disable unpublish and bulk unpublish * Add a new warning * V9: Displaying descendants in use as part of item tracking (#12039) * Replace HasReferencesInDescendants with GetPagedDescendantsInReferences * Display descendants in use on parent's info tab * Add getPagedDescendantsInReferences to trackedReferencesResource * Add lang keys for Descendants in use * Refactoring controller actions * Don't call check descendants usage when it is a new item * rename busfy to busy * always show references * rearrange for scrollbar to appear at the edge of the dialog * use the word referenced instead of used * change fallback texts * Added "IsDependency" to relation types * refactor of umb-tracked-references * rename checkLinkedItems to getPagedReferencedItems * rename check to load, to be consistent with the rest. * Refactored backend . Needs frontend fixes * Cleanup * Use filters * Front-end refactor to match refactored end-points * Fixed bug + warning * Fixed query (more then 2100 descensdants) and optimized it (using nested select instead of inner join). * remove comment * hideNoneDependencies including varying text for the configuration * Hack for SqlCE :( * some final adjustments for item tracking ui * Unbreak change Co-authored-by: Niels Lyngsø <niels.lyngso@gmail.com> Co-authored-by: Bjarke Berg <mail@bergmania.dk>
269 lines
9.8 KiB
C#
269 lines
9.8 KiB
C#
// Copyright (c) Umbraco.
|
|
// See LICENSE for more details.
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
using NUnit.Framework;
|
|
using Umbraco.Cms.Core.Models;
|
|
using Umbraco.Cms.Core.Services;
|
|
using Umbraco.Cms.Tests.Common.Builders;
|
|
using Umbraco.Cms.Tests.Common.Testing;
|
|
using Umbraco.Cms.Tests.Integration.Testing;
|
|
using Umbraco.Extensions;
|
|
using Constants = Umbraco.Cms.Core.Constants;
|
|
|
|
namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services
|
|
{
|
|
[TestFixture]
|
|
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)]
|
|
public class RelationServiceTests : UmbracoIntegrationTest
|
|
{
|
|
private IContentTypeService ContentTypeService => GetRequiredService<IContentTypeService>();
|
|
|
|
private IContentService ContentService => GetRequiredService<IContentService>();
|
|
|
|
private IMediaTypeService MediaTypeService => GetRequiredService<IMediaTypeService>();
|
|
|
|
private IMediaService MediaService => GetRequiredService<IMediaService>();
|
|
|
|
private IRelationService RelationService => GetRequiredService<IRelationService>();
|
|
|
|
[Test]
|
|
public void Get_Paged_Relations_By_Relation_Type()
|
|
{
|
|
// Create content
|
|
var createdContent = new List<IContent>();
|
|
ContentType contentType = ContentTypeBuilder.CreateBasicContentType("blah");
|
|
ContentTypeService.Save(contentType);
|
|
for (int i = 0; i < 3; i++)
|
|
{
|
|
Content c1 = ContentBuilder.CreateBasicContent(contentType);
|
|
ContentService.Save(c1);
|
|
createdContent.Add(c1);
|
|
}
|
|
|
|
// Create media
|
|
var createdMedia = new List<IMedia>();
|
|
MediaType imageType = MediaTypeBuilder.CreateImageMediaType("myImage");
|
|
MediaTypeService.Save(imageType);
|
|
for (int i = 0; i < 3; i++)
|
|
{
|
|
Media c1 = MediaBuilder.CreateMediaImage(imageType, -1);
|
|
MediaService.Save(c1);
|
|
createdMedia.Add(c1);
|
|
}
|
|
|
|
IRelationType relType = RelationService.GetRelationTypeByAlias(Constants.Conventions.RelationTypes.RelatedMediaAlias);
|
|
|
|
// Relate content to media
|
|
foreach (IContent content in createdContent)
|
|
{
|
|
foreach (IMedia media in createdMedia)
|
|
{
|
|
RelationService.Relate(content.Id, media.Id, relType);
|
|
}
|
|
}
|
|
|
|
var paged = RelationService.GetPagedByRelationTypeId(relType.Id, 0, 4, out long totalRecs).ToList();
|
|
|
|
Assert.AreEqual(9, totalRecs);
|
|
Assert.AreEqual(4, paged.Count);
|
|
|
|
// next page
|
|
paged.AddRange(RelationService.GetPagedByRelationTypeId(relType.Id, 1, 4, out totalRecs));
|
|
|
|
Assert.AreEqual(9, totalRecs);
|
|
Assert.AreEqual(8, paged.Count);
|
|
|
|
Assert.IsTrue(createdContent.Select(x => x.Id).ContainsAll(paged.Select(x => x.ParentId)));
|
|
Assert.IsTrue(createdMedia.Select(x => x.Id).ContainsAll(paged.Select(x => x.ChildId)));
|
|
}
|
|
|
|
[Test]
|
|
public void Return_List_Of_Content_Items_Where_Media_Item_Referenced()
|
|
{
|
|
MediaType mt = MediaTypeBuilder.CreateSimpleMediaType("testMediaType", "Test Media Type");
|
|
MediaTypeService.Save(mt);
|
|
Media m1 = MediaBuilder.CreateSimpleMedia(mt, "hello 1", -1);
|
|
MediaService.Save(m1);
|
|
|
|
ContentType ct = ContentTypeBuilder.CreateTextPageContentType("richTextTest");
|
|
ct.AllowedTemplates = Enumerable.Empty<ITemplate>();
|
|
ContentTypeService.Save(ct);
|
|
|
|
void CreateContentWithMediaRefs()
|
|
{
|
|
Content content = ContentBuilder.CreateTextpageContent(ct, "my content 2", -1);
|
|
|
|
// 'bodyText' is a property with a RTE property editor which we knows automatically tracks relations
|
|
content.Properties["bodyText"].SetValue(@"<p>
|
|
<img src='/media/12312.jpg' data-udi='umb://media/" + m1.Key.ToString("N") + @"' />
|
|
</p>");
|
|
ContentService.Save(content);
|
|
}
|
|
|
|
for (int i = 0; i < 6; i++)
|
|
{
|
|
CreateContentWithMediaRefs(); // create 6 content items referencing the same media
|
|
}
|
|
|
|
var relations = RelationService.GetByChildId(m1.Id, Constants.Conventions.RelationTypes.RelatedMediaAlias).ToList();
|
|
Assert.AreEqual(6, relations.Count);
|
|
|
|
var entities = RelationService.GetParentEntitiesFromRelations(relations).ToList();
|
|
Assert.AreEqual(6, entities.Count);
|
|
}
|
|
|
|
[Test]
|
|
public void Can_Create_RelationType_Without_Name()
|
|
{
|
|
IRelationService rs = RelationService;
|
|
IRelationType rt = new RelationType("Test", "repeatedEventOccurence", false, Constants.ObjectTypes.Document, Constants.ObjectTypes.Media);
|
|
|
|
Assert.DoesNotThrow(() => rs.Save(rt));
|
|
|
|
// re-get
|
|
rt = RelationService.GetRelationTypeById(rt.Id);
|
|
|
|
Assert.AreEqual("Test", rt.Name);
|
|
Assert.AreEqual("repeatedEventOccurence", rt.Alias);
|
|
Assert.AreEqual(false, rt.IsBidirectional);
|
|
Assert.AreEqual(Constants.ObjectTypes.Document, rt.ParentObjectType.Value);
|
|
Assert.AreEqual(Constants.ObjectTypes.Media, rt.ChildObjectType.Value);
|
|
}
|
|
|
|
[Test]
|
|
public void Create_Relation_Type_Without_Object_Types()
|
|
{
|
|
IRelationService rs = RelationService;
|
|
IRelationType rt = new RelationType("repeatedEventOccurence", "repeatedEventOccurence", false, null, null);
|
|
|
|
Assert.DoesNotThrow(() => rs.Save(rt));
|
|
|
|
// re-get
|
|
rt = RelationService.GetRelationTypeById(rt.Id);
|
|
|
|
Assert.IsNull(rt.ChildObjectType);
|
|
Assert.IsNull(rt.ParentObjectType);
|
|
}
|
|
|
|
[Test]
|
|
public void Relation_Returns_Parent_Child_Object_Types_When_Creating()
|
|
{
|
|
IRelation r = CreateAndSaveRelation("Test", "test");
|
|
|
|
Assert.AreEqual(Constants.ObjectTypes.Document, r.ParentObjectType);
|
|
Assert.AreEqual(Constants.ObjectTypes.Media, r.ChildObjectType);
|
|
}
|
|
|
|
[Test]
|
|
public void Relation_Returns_Parent_Child_Object_Types_When_Getting()
|
|
{
|
|
IRelation r = CreateAndSaveRelation("Test", "test");
|
|
|
|
// re-get
|
|
r = RelationService.GetById(r.Id);
|
|
|
|
Assert.AreEqual(Constants.ObjectTypes.Document, r.ParentObjectType);
|
|
Assert.AreEqual(Constants.ObjectTypes.Media, r.ChildObjectType);
|
|
}
|
|
|
|
[Test]
|
|
public void Insert_Bulk_Relations()
|
|
{
|
|
IRelationService rs = RelationService;
|
|
|
|
IEnumerable<IRelation> newRelations = CreateRelations(10);
|
|
|
|
Assert.IsTrue(newRelations.All(x => !x.HasIdentity));
|
|
|
|
RelationService.Save(newRelations);
|
|
|
|
Assert.IsTrue(newRelations.All(x => x.HasIdentity));
|
|
}
|
|
|
|
[Test]
|
|
public void Update_Bulk_Relations()
|
|
{
|
|
IRelationService rs = RelationService;
|
|
|
|
DateTime date = DateTime.Now.AddDays(-10);
|
|
IEnumerable<IRelation> newRelations = CreateRelations(10);
|
|
foreach (IRelation r in newRelations)
|
|
{
|
|
r.CreateDate = date;
|
|
r.UpdateDate = date;
|
|
}
|
|
|
|
// insert
|
|
RelationService.Save(newRelations);
|
|
Assert.IsTrue(newRelations.All(x => x.UpdateDate == date));
|
|
|
|
DateTime newDate = DateTime.Now.AddDays(-5);
|
|
foreach (IRelation r in newRelations)
|
|
{
|
|
r.UpdateDate = newDate;
|
|
}
|
|
|
|
// update
|
|
RelationService.Save(newRelations);
|
|
Assert.IsTrue(newRelations.All(x => x.UpdateDate == newDate));
|
|
}
|
|
|
|
private IRelation CreateAndSaveRelation(string name, string alias)
|
|
{
|
|
IRelationService rs = RelationService;
|
|
var rt = new RelationType(name, alias, false, null, null);
|
|
rs.Save(rt);
|
|
|
|
ContentType ct = ContentTypeBuilder.CreateBasicContentType();
|
|
ContentTypeService.Save(ct);
|
|
|
|
MediaType mt = MediaTypeBuilder.CreateImageMediaType("img");
|
|
MediaTypeService.Save(mt);
|
|
|
|
Content c1 = ContentBuilder.CreateBasicContent(ct);
|
|
Media c2 = MediaBuilder.CreateMediaImage(mt, -1);
|
|
ContentService.Save(c1);
|
|
MediaService.Save(c2);
|
|
|
|
var r = new Relation(c1.Id, c2.Id, rt);
|
|
RelationService.Save(r);
|
|
|
|
return r;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a bunch of content/media items return relation objects for them (unsaved)
|
|
/// </summary>
|
|
/// <param name="count"></param>
|
|
/// <returns></returns>
|
|
private IEnumerable<IRelation> CreateRelations(int count)
|
|
{
|
|
IRelationService rs = RelationService;
|
|
string rtName = Guid.NewGuid().ToString();
|
|
var rt = new RelationType(rtName, rtName, false, null, null);
|
|
rs.Save(rt);
|
|
|
|
ContentType ct = ContentTypeBuilder.CreateBasicContentType();
|
|
ContentTypeService.Save(ct);
|
|
|
|
MediaType mt = MediaTypeBuilder.CreateImageMediaType("img");
|
|
MediaTypeService.Save(mt);
|
|
|
|
return Enumerable.Range(1, count).Select(index =>
|
|
{
|
|
Content c1 = ContentBuilder.CreateBasicContent(ct);
|
|
Media c2 = MediaBuilder.CreateMediaImage(mt, -1);
|
|
ContentService.Save(c1);
|
|
MediaService.Save(c2);
|
|
|
|
return new Relation(c1.Id, c2.Id, rt);
|
|
}).ToList();
|
|
}
|
|
|
|
// TODO: Create a relation for entities of the wrong Entity Type (GUID) based on the Relation Type's defined parent/child object types
|
|
}
|
|
} |