Merge branch 'main' into v17/dev

# Conflicts:
#	src/Umbraco.Cms.Api.Management/Controllers/Content/ContentCollectionControllerBase.cs
#	src/Umbraco.Core/Services/IMemberService.cs
#	src/Umbraco.Core/Services/MemberService.cs
This commit is contained in:
Andy Butland
2025-09-17 15:42:23 +02:00
150 changed files with 1642 additions and 1107 deletions

View File

@@ -0,0 +1,196 @@
using NUnit.Framework;
using Umbraco.Cms.Api.Management.Services.Flags;
using Umbraco.Cms.Api.Management.ViewModels;
using Umbraco.Cms.Api.Management.ViewModels.Document.Collection;
using Umbraco.Cms.Api.Management.ViewModels.Document.Item;
using Umbraco.Cms.Api.Management.ViewModels.DocumentType;
using Umbraco.Cms.Api.Management.ViewModels.Media.Collection;
using Umbraco.Cms.Api.Management.ViewModels.Media.Item;
using Umbraco.Cms.Api.Management.ViewModels.MediaType;
using Umbraco.Cms.Api.Management.ViewModels.Tree;
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Cms.Api.Management.Services.Flags;
[TestFixture]
internal class HasCollectionFlagProviderTests
{
[Test]
public void HasCollectionFlagProvider_Can_Provide_Document_Tree_Flags()
{
var sut = new HasCollectionFlagProvider();
Assert.IsTrue(sut.CanProvideFlags<DocumentTreeItemResponseModel>());
}
[Test]
public void HasCollectionFlagProvider_Can_Provide_Document_Collection_Flags()
{
var sut = new HasCollectionFlagProvider();
Assert.IsTrue(sut.CanProvideFlags<DocumentCollectionResponseModel>());
}
[Test]
public void HasCollectionFlagProvider_Can_Provide_Document_Item_Flags()
{
var sut = new HasCollectionFlagProvider();
Assert.IsTrue(sut.CanProvideFlags<DocumentItemResponseModel>());
}
[Test]
public void HasCollectionFlagProvider_Can_Provide_Media_Tree_Flags()
{
var sut = new HasCollectionFlagProvider();
Assert.IsTrue(sut.CanProvideFlags<MediaTreeItemResponseModel>());
}
[Test]
public void HasCollectionFlagProvider_Can_Provide_Media_Collection_Flags()
{
var sut = new HasCollectionFlagProvider();
Assert.IsTrue(sut.CanProvideFlags<MediaCollectionResponseModel>());
}
[Test]
public void HasCollectionFlagProvider_Can_Provide_Media_Item_Flags()
{
var sut = new HasCollectionFlagProvider();
Assert.IsTrue(sut.CanProvideFlags<MediaItemResponseModel>());
}
[Test]
public async Task HasCollectionFlagProvider_Should_Populate_Document_Tree_Flags()
{
var sut = new HasCollectionFlagProvider();
var viewModels = new List<DocumentTreeItemResponseModel>
{
new()
{
Id = Guid.NewGuid(), DocumentType = new DocumentTypeReferenceResponseModel() { Collection = new ReferenceByIdModel(Guid.NewGuid()) },
},
new() { Id = Guid.NewGuid() },
};
await sut.PopulateFlagsAsync(viewModels);
Assert.AreEqual(viewModels[0].Flags.Count(), 1);
Assert.AreEqual(viewModels[1].Flags.Count(), 0);
var flagModel = viewModels[0].Flags.First();
Assert.AreEqual("Umb.HasCollection", flagModel.Alias);
}
[Test]
public async Task HasCollectionFlagProvider_Should_Populate_Document_Collection_Flags()
{
var sut = new HasCollectionFlagProvider();
var viewModels = new List<DocumentCollectionResponseModel>
{
new()
{
Id = Guid.NewGuid(), DocumentType = new DocumentTypeCollectionReferenceResponseModel() { Collection = new ReferenceByIdModel(Guid.NewGuid()) },
},
new() { Id = Guid.NewGuid() },
};
await sut.PopulateFlagsAsync(viewModels);
Assert.AreEqual(viewModels[0].Flags.Count(), 1);
Assert.AreEqual(viewModels[1].Flags.Count(), 0);
var flagModel = viewModels[0].Flags.First();
Assert.AreEqual("Umb.HasCollection", flagModel.Alias);
}
[Test]
public async Task HasCollectionFlagProvider_Should_Populate_Document_Item_Flags()
{
var sut = new HasCollectionFlagProvider();
var viewModels = new List<DocumentItemResponseModel>
{
new()
{
Id = Guid.NewGuid(), DocumentType = new DocumentTypeReferenceResponseModel() { Collection = new ReferenceByIdModel(Guid.NewGuid()) },
},
new() { Id = Guid.NewGuid() },
};
await sut.PopulateFlagsAsync(viewModels);
Assert.AreEqual(viewModels[0].Flags.Count(), 1);
Assert.AreEqual(viewModels[1].Flags.Count(), 0);
var flagModel = viewModels[0].Flags.First();
Assert.AreEqual("Umb.HasCollection", flagModel.Alias);
}
[Test]
public async Task HasCollectionFlagProvider_Should_Populate_Media_Tree_Flags()
{
var sut = new HasCollectionFlagProvider();
var viewModels = new List<MediaTreeItemResponseModel>
{
new()
{
Id = Guid.NewGuid(), MediaType = new MediaTypeReferenceResponseModel() { Collection = new ReferenceByIdModel(Guid.NewGuid()) },
},
new() { Id = Guid.NewGuid() },
};
await sut.PopulateFlagsAsync(viewModels);
Assert.AreEqual(viewModels[0].Flags.Count(), 1);
Assert.AreEqual(viewModels[1].Flags.Count(), 0);
var flagModel = viewModels[0].Flags.First();
Assert.AreEqual("Umb.HasCollection", flagModel.Alias);
}
[Test]
public async Task HasCollectionFlagProvider_Should_Populate_Media_Collection_Flags()
{
var sut = new HasCollectionFlagProvider();
var viewModels = new List<MediaCollectionResponseModel>
{
new()
{
Id = Guid.NewGuid(), MediaType = new MediaTypeCollectionReferenceResponseModel() { Collection = new ReferenceByIdModel(Guid.NewGuid()) },
},
new() { Id = Guid.NewGuid() },
};
await sut.PopulateFlagsAsync(viewModels);
Assert.AreEqual(viewModels[0].Flags.Count(), 1);
Assert.AreEqual(viewModels[1].Flags.Count(), 0);
var flagModel = viewModels[0].Flags.First();
Assert.AreEqual("Umb.HasCollection", flagModel.Alias);
}
[Test]
public async Task HasCollectionFlagProvider_Should_Populate_Media_Item_Flags()
{
var sut = new HasCollectionFlagProvider();
var viewModels = new List<MediaItemResponseModel>
{
new()
{
Id = Guid.NewGuid(), MediaType = new MediaTypeReferenceResponseModel() { Collection = new ReferenceByIdModel(Guid.NewGuid()) },
},
new() { Id = Guid.NewGuid() },
};
await sut.PopulateFlagsAsync(viewModels);
Assert.AreEqual(viewModels[0].Flags.Count(), 1);
Assert.AreEqual(viewModels[1].Flags.Count(), 0);
var flagModel = viewModels[0].Flags.First();
Assert.AreEqual("Umb.HasCollection", flagModel.Alias);
}
}

View File

@@ -0,0 +1,83 @@
using NUnit.Framework;
using Umbraco.Cms.Api.Management.Services.Flags;
using Umbraco.Cms.Api.Management.ViewModels.Document;
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Cms.Api.Management.Services.Flags;
[TestFixture]
internal class HasPendingChangesFlagProviderTests
{
[Test]
public void HasPendingChangesFlagProvider_Can_Provide_Variant_Item_Flags()
{
var sut = new HasPendingChangesFlagProvider();
Assert.IsTrue(sut.CanProvideFlags<DocumentVariantItemResponseModel>());
}
[Test]
public void HasPendingChangesFlagProvider_Can_Provide_Variant_Flags()
{
var sut = new HasPendingChangesFlagProvider();
Assert.IsTrue(sut.CanProvideFlags<DocumentVariantResponseModel>());
}
[Test]
public async Task HasPendingChangesFlagProvider_Should_Populate_Variant_Item_Flags()
{
var sut = new HasPendingChangesFlagProvider();
var variants = new List<DocumentVariantItemResponseModel>
{
new()
{
State = DocumentVariantState.PublishedPendingChanges,
Culture = null,
Name = "Test",
},
new()
{
State = DocumentVariantState.Published,
Culture = null,
Name = "Test2",
},
};
await sut.PopulateFlagsAsync(variants);
Assert.AreEqual(variants[0].Flags.Count(), 1);
Assert.AreEqual(variants[1].Flags.Count(), 0);
var flagModel = variants[0].Flags.First();
Assert.AreEqual("Umb.PendingChanges", flagModel.Alias);
}
[Test]
public async Task HasPendingChangesFlagProvider_Should_Populate_Variant_Flags()
{
var sut = new HasPendingChangesFlagProvider();
var variants = new List<DocumentVariantResponseModel>
{
new()
{
State = DocumentVariantState.PublishedPendingChanges,
Culture = null,
Name = "Test",
},
new()
{
State = DocumentVariantState.Published,
Culture = null,
Name = "Test2",
},
};
await sut.PopulateFlagsAsync(variants);
Assert.AreEqual(variants[0].Flags.Count(), 1);
Assert.AreEqual(variants[1].Flags.Count(), 0);
var flagModel = variants[0].Flags.First();
Assert.AreEqual("Umb.PendingChanges", flagModel.Alias);
}
}

View File

@@ -1,6 +1,6 @@
using Moq;
using NUnit.Framework;
using Umbraco.Cms.Api.Management.Services.Signs;
using Umbraco.Cms.Api.Management.Services.Flags;
using Umbraco.Cms.Api.Management.ViewModels.Content;
using Umbraco.Cms.Api.Management.ViewModels.Document;
using Umbraco.Cms.Api.Management.ViewModels.Document.Collection;
@@ -11,43 +11,43 @@ using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.Entities;
using Umbraco.Cms.Core.Services;
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Cms.Api.Management.Services.Signs;
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Cms.Api.Management.Services.Flags;
[TestFixture]
internal class HasScheduleSignProviderTests
internal class HasScheduleFlagProviderTests
{
[Test]
public void HasScheduleSignProvider_Can_Provide_Document_Tree_Signs()
public void HasScheduleFlagProvider_Can_Provide_Document_Tree_Flags()
{
var contentServiceMock = new Mock<IContentService>();
var idKeyMapMock = new Mock<IIdKeyMap>();
var sut = new HasScheduleSignProvider(contentServiceMock.Object, idKeyMapMock.Object);
Assert.IsTrue(sut.CanProvideSigns<DocumentTreeItemResponseModel>());
var sut = new HasScheduleFlagProvider(contentServiceMock.Object, idKeyMapMock.Object);
Assert.IsTrue(sut.CanProvideFlags<DocumentTreeItemResponseModel>());
}
[Test]
public void HasScheduleSignProvider_Can_Provide_Document_Collection_Signs()
public void HasScheduleFlagProvider_Can_Provide_Document_Collection_Flags()
{
var contentServiceMock = new Mock<IContentService>();
var idKeyMapMock = new Mock<IIdKeyMap>();
var sut = new HasScheduleSignProvider(contentServiceMock.Object, idKeyMapMock.Object);
Assert.IsTrue(sut.CanProvideSigns<DocumentCollectionResponseModel>());
var sut = new HasScheduleFlagProvider(contentServiceMock.Object, idKeyMapMock.Object);
Assert.IsTrue(sut.CanProvideFlags<DocumentCollectionResponseModel>());
}
[Test]
public void HasScheduleSignProvider_Can_Provide_Document_Item_Signs()
public void HasScheduleFlagProvider_Can_Provide_Document_Item_Flags()
{
var contentServiceMock = new Mock<IContentService>();
var idKeyMapMock = new Mock<IIdKeyMap>();
var sut = new HasScheduleSignProvider(contentServiceMock.Object, idKeyMapMock.Object);
Assert.IsTrue(sut.CanProvideSigns<DocumentItemResponseModel>());
var sut = new HasScheduleFlagProvider(contentServiceMock.Object, idKeyMapMock.Object);
Assert.IsTrue(sut.CanProvideFlags<DocumentItemResponseModel>());
}
[Test]
public async Task HasScheduleSignProvider_Should_Populate_Document_Tree_Signs()
public async Task HasScheduleFlagProvider_Should_Populate_Document_Tree_Flags()
{
var entities = new List<EntitySlim>
{
@@ -67,7 +67,7 @@ internal class HasScheduleSignProviderTests
.Returns(CreateContentSchedules());
var sut = new HasScheduleSignProvider(contentServiceMock.Object, idKeyMapMock.Object);
var sut = new HasScheduleFlagProvider(contentServiceMock.Object, idKeyMapMock.Object);
var variant1 = new DocumentVariantItemResponseModel() { State = DocumentVariantState.Published, Name = "Test1", Culture = "en-EN" };
var variant2 = new DocumentVariantItemResponseModel() { State = DocumentVariantState.Published, Name = "Test1", Culture = "da-DA" };
@@ -78,18 +78,18 @@ internal class HasScheduleSignProviderTests
new() { Id = entities[0].Key, Variants = [variant1, variant2] }, new() { Id = entities[1].Key, Variants = [variant3] },
};
await sut.PopulateSignsAsync(viewModels);
await sut.PopulateFlagsAsync(viewModels);
Assert.AreEqual(viewModels[0].Variants.FirstOrDefault(x => x.Culture == "da-DA").Signs.Count(), 0);
Assert.AreEqual(viewModels[0].Variants.FirstOrDefault(x => x.Culture == "en-EN").Signs.Count(), 1);
Assert.AreEqual(viewModels[1].Variants.First().Signs.Count(), 1);
Assert.AreEqual(viewModels[0].Variants.FirstOrDefault(x => x.Culture == "da-DA").Flags.Count(), 0);
Assert.AreEqual(viewModels[0].Variants.FirstOrDefault(x => x.Culture == "en-EN").Flags.Count(), 1);
Assert.AreEqual(viewModels[1].Variants.First().Flags.Count(), 1);
var signModel = viewModels[0].Variants.First().Signs.First();
Assert.AreEqual("Umb.ScheduledForPublish", signModel.Alias);
var flagModel = viewModels[0].Variants.First().Flags.First();
Assert.AreEqual("Umb.ScheduledForPublish", flagModel.Alias);
}
[Test]
public async Task HasScheduleSignProvider_Should_Populate_Document_Collection_Signs()
public async Task HasScheduleFlagProvider_Should_Populate_Document_Collection_Flags()
{
var entities = new List<EntitySlim>
{
@@ -108,7 +108,7 @@ internal class HasScheduleSignProviderTests
.Setup(x => x.GetContentSchedulesByIds(keys))
.Returns(CreateContentSchedules());
var sut = new HasScheduleSignProvider(contentServiceMock.Object, idKeyMapMock.Object);
var sut = new HasScheduleFlagProvider(contentServiceMock.Object, idKeyMapMock.Object);
var variant1 = new DocumentVariantResponseModel() { State = DocumentVariantState.Published, Name = "Test1", Culture = "en-EN" };
var variant2 = new DocumentVariantResponseModel() { State = DocumentVariantState.Published, Name = "Test1", Culture = "da-DA" };
@@ -119,18 +119,18 @@ internal class HasScheduleSignProviderTests
new() { Id = entities[0].Key, Variants = [variant1, variant2] }, new() { Id = entities[1].Key, Variants = [variant3] },
};
await sut.PopulateSignsAsync(viewModels);
await sut.PopulateFlagsAsync(viewModels);
Assert.AreEqual(viewModels[0].Variants.FirstOrDefault(x => x.Culture == "da-DA").Signs.Count(), 0);
Assert.AreEqual(viewModels[0].Variants.FirstOrDefault(x => x.Culture == "en-EN").Signs.Count(), 1);
Assert.AreEqual(viewModels[1].Variants.First().Signs.Count(), 1);
Assert.AreEqual(viewModels[0].Variants.FirstOrDefault(x => x.Culture == "da-DA").Flags.Count(), 0);
Assert.AreEqual(viewModels[0].Variants.FirstOrDefault(x => x.Culture == "en-EN").Flags.Count(), 1);
Assert.AreEqual(viewModels[1].Variants.First().Flags.Count(), 1);
var signModel = viewModels[0].Variants.First().Signs.First();
Assert.AreEqual("Umb.ScheduledForPublish", signModel.Alias);
var flagModel = viewModels[0].Variants.First().Flags.First();
Assert.AreEqual("Umb.ScheduledForPublish", flagModel.Alias);
}
[Test]
public async Task HasScheduleSignProvider_Should_Populate_Document_Item_Signs()
public async Task HasScheduleFlagProvider_Should_Populate_Document_Item_Flags()
{
var entities = new List<EntitySlim>
{
@@ -149,7 +149,7 @@ internal class HasScheduleSignProviderTests
.Setup(x => x.GetContentSchedulesByIds(keys))
.Returns(CreateContentSchedules());
var sut = new HasScheduleSignProvider(contentServiceMock.Object, idKeyMapMock.Object);
var sut = new HasScheduleFlagProvider(contentServiceMock.Object, idKeyMapMock.Object);
var variant1 = new DocumentVariantItemResponseModel() { State = DocumentVariantState.Published, Name = "Test1", Culture = "en-EN" };
var variant2 = new DocumentVariantItemResponseModel() { State = DocumentVariantState.Published, Name = "Test1", Culture = "da-DA" };
@@ -160,14 +160,14 @@ internal class HasScheduleSignProviderTests
new() { Id = entities[0].Key, Variants = [variant1, variant2] }, new() { Id = entities[1].Key, Variants = [variant3] },
};
await sut.PopulateSignsAsync(viewModels);
await sut.PopulateFlagsAsync(viewModels);
Assert.AreEqual(viewModels[0].Variants.FirstOrDefault(x => x.Culture == "da-DA").Signs.Count(), 0);
Assert.AreEqual(viewModels[0].Variants.FirstOrDefault(x => x.Culture == "en-EN").Signs.Count(), 1);
Assert.AreEqual(viewModels[1].Variants.First().Signs.Count(), 1);
Assert.AreEqual(viewModels[0].Variants.FirstOrDefault(x => x.Culture == "da-DA").Flags.Count(), 0);
Assert.AreEqual(viewModels[0].Variants.FirstOrDefault(x => x.Culture == "en-EN").Flags.Count(), 1);
Assert.AreEqual(viewModels[1].Variants.First().Flags.Count(), 1);
var signModel = viewModels[0].Variants.First().Signs.First();
Assert.AreEqual("Umb.ScheduledForPublish", signModel.Alias);
var flagModel = viewModels[0].Variants.First().Flags.First();
Assert.AreEqual("Umb.ScheduledForPublish", flagModel.Alias);
}
private Dictionary<int, IEnumerable<ContentSchedule>> CreateContentSchedules()

View File

@@ -0,0 +1,92 @@
using NUnit.Framework;
using Umbraco.Cms.Api.Management.Services.Flags;
using Umbraco.Cms.Api.Management.ViewModels.Document.Collection;
using Umbraco.Cms.Api.Management.ViewModels.Document.Item;
using Umbraco.Cms.Api.Management.ViewModels.Tree;
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Cms.Api.Management.Services.Flags;
[TestFixture]
internal class IsProtectedFlagProviderTests
{
[Test]
public void IsProtectedFlagProvider_Can_Provide_Tree_Flags()
{
var sut = new IsProtectedFlagProvider();
Assert.IsTrue(sut.CanProvideFlags<DocumentTreeItemResponseModel>());
}
[Test]
public void IsProtectedFlagProvider_Can_Provide_Collection_Flags()
{
var sut = new IsProtectedFlagProvider();
Assert.IsTrue(sut.CanProvideFlags<DocumentCollectionResponseModel>());
}
[Test]
public void IsProtectedFlagProvider_Can_Provide_Plain_Flags()
{
var sut = new IsProtectedFlagProvider();
Assert.IsTrue(sut.CanProvideFlags<DocumentItemResponseModel>());
}
[Test]
public async Task IsProtectedFlagProvider_Should_Populate_Tree_Flags()
{
var sut = new IsProtectedFlagProvider();
var viewModels = new List<DocumentTreeItemResponseModel>
{
new(),
new() { IsProtected = true },
};
await sut.PopulateFlagsAsync(viewModels);
Assert.AreEqual(viewModels[0].Flags.Count(), 0);
Assert.AreEqual(viewModels[1].Flags.Count(), 1);
var flagModel = viewModels[1].Flags.First();
Assert.AreEqual("Umb.IsProtected", flagModel.Alias);
}
[Test]
public async Task IsProtectedFlagProvider_Should_Populate_Collection_Flags()
{
var sut = new IsProtectedFlagProvider();
var viewModels = new List<DocumentCollectionResponseModel>
{
new(),
new() { IsProtected = true },
};
await sut.PopulateFlagsAsync(viewModels);
Assert.AreEqual(viewModels[0].Flags.Count(), 0);
Assert.AreEqual(viewModels[1].Flags.Count(), 1);
var flagModel = viewModels[1].Flags.First();
Assert.AreEqual("Umb.IsProtected", flagModel.Alias);
}
[Test]
public async Task IsProtectedFlagProvider_Should_Populate_Plain_Flags()
{
var sut = new IsProtectedFlagProvider();
var viewModels = new List<DocumentItemResponseModel>
{
new(),
new() { IsProtected = true },
};
await sut.PopulateFlagsAsync(viewModels);
Assert.AreEqual(viewModels[0].Flags.Count(), 0);
Assert.AreEqual(viewModels[1].Flags.Count(), 1);
var flagModel = viewModels[1].Flags.First();
Assert.AreEqual("Umb.IsProtected", flagModel.Alias);
}
}

View File

@@ -1,196 +0,0 @@
using NUnit.Framework;
using Umbraco.Cms.Api.Management.Services.Signs;
using Umbraco.Cms.Api.Management.ViewModels;
using Umbraco.Cms.Api.Management.ViewModels.Document.Collection;
using Umbraco.Cms.Api.Management.ViewModels.Document.Item;
using Umbraco.Cms.Api.Management.ViewModels.DocumentType;
using Umbraco.Cms.Api.Management.ViewModels.Media.Collection;
using Umbraco.Cms.Api.Management.ViewModels.Media.Item;
using Umbraco.Cms.Api.Management.ViewModels.MediaType;
using Umbraco.Cms.Api.Management.ViewModels.Tree;
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Cms.Api.Management.Services.Signs;
[TestFixture]
internal class HasCollectionSignProviderTests
{
[Test]
public void HasCollectionSignProvider_Can_Provide_Document_Tree_Signs()
{
var sut = new HasCollectionSignProvider();
Assert.IsTrue(sut.CanProvideSigns<DocumentTreeItemResponseModel>());
}
[Test]
public void HasCollectionSignProvider_Can_Provide_Document_Collection_Signs()
{
var sut = new HasCollectionSignProvider();
Assert.IsTrue(sut.CanProvideSigns<DocumentCollectionResponseModel>());
}
[Test]
public void HasCollectionSignProvider_Can_Provide_Document_Item_Signs()
{
var sut = new HasCollectionSignProvider();
Assert.IsTrue(sut.CanProvideSigns<DocumentItemResponseModel>());
}
[Test]
public void HasCollectionSignProvider_Can_Provide_Media_Tree_Signs()
{
var sut = new HasCollectionSignProvider();
Assert.IsTrue(sut.CanProvideSigns<MediaTreeItemResponseModel>());
}
[Test]
public void HasCollectionSignProvider_Can_Provide_Media_Collection_Signs()
{
var sut = new HasCollectionSignProvider();
Assert.IsTrue(sut.CanProvideSigns<MediaCollectionResponseModel>());
}
[Test]
public void HasCollectionSignProvider_Can_Provide_Media_Item_Signs()
{
var sut = new HasCollectionSignProvider();
Assert.IsTrue(sut.CanProvideSigns<MediaItemResponseModel>());
}
[Test]
public async Task HasCollectionSignProvider_Should_Populate_Document_Tree_Signs()
{
var sut = new HasCollectionSignProvider();
var viewModels = new List<DocumentTreeItemResponseModel>
{
new()
{
Id = Guid.NewGuid(), DocumentType = new DocumentTypeReferenceResponseModel() { Collection = new ReferenceByIdModel(Guid.NewGuid()) },
},
new() { Id = Guid.NewGuid() },
};
await sut.PopulateSignsAsync(viewModels);
Assert.AreEqual(viewModels[0].Signs.Count(), 1);
Assert.AreEqual(viewModels[1].Signs.Count(), 0);
var signModel = viewModels[0].Signs.First();
Assert.AreEqual("Umb.HasCollection", signModel.Alias);
}
[Test]
public async Task HasCollectionSignProvider_Should_Populate_Document_Collection_Signs()
{
var sut = new HasCollectionSignProvider();
var viewModels = new List<DocumentCollectionResponseModel>
{
new()
{
Id = Guid.NewGuid(), DocumentType = new DocumentTypeCollectionReferenceResponseModel() { Collection = new ReferenceByIdModel(Guid.NewGuid()) },
},
new() { Id = Guid.NewGuid() },
};
await sut.PopulateSignsAsync(viewModels);
Assert.AreEqual(viewModels[0].Signs.Count(), 1);
Assert.AreEqual(viewModels[1].Signs.Count(), 0);
var signModel = viewModels[0].Signs.First();
Assert.AreEqual("Umb.HasCollection", signModel.Alias);
}
[Test]
public async Task HasCollectionSignProvider_Should_Populate_Document_Item_Signs()
{
var sut = new HasCollectionSignProvider();
var viewModels = new List<DocumentItemResponseModel>
{
new()
{
Id = Guid.NewGuid(), DocumentType = new DocumentTypeReferenceResponseModel() { Collection = new ReferenceByIdModel(Guid.NewGuid()) },
},
new() { Id = Guid.NewGuid() },
};
await sut.PopulateSignsAsync(viewModels);
Assert.AreEqual(viewModels[0].Signs.Count(), 1);
Assert.AreEqual(viewModels[1].Signs.Count(), 0);
var signModel = viewModels[0].Signs.First();
Assert.AreEqual("Umb.HasCollection", signModel.Alias);
}
[Test]
public async Task HasCollectionSignProvider_Should_Populate_Media_Tree_Signs()
{
var sut = new HasCollectionSignProvider();
var viewModels = new List<MediaTreeItemResponseModel>
{
new()
{
Id = Guid.NewGuid(), MediaType = new MediaTypeReferenceResponseModel() { Collection = new ReferenceByIdModel(Guid.NewGuid()) },
},
new() { Id = Guid.NewGuid() },
};
await sut.PopulateSignsAsync(viewModels);
Assert.AreEqual(viewModels[0].Signs.Count(), 1);
Assert.AreEqual(viewModels[1].Signs.Count(), 0);
var signModel = viewModels[0].Signs.First();
Assert.AreEqual("Umb.HasCollection", signModel.Alias);
}
[Test]
public async Task HasCollectionSignProvider_Should_Populate_Media_Collection_Signs()
{
var sut = new HasCollectionSignProvider();
var viewModels = new List<MediaCollectionResponseModel>
{
new()
{
Id = Guid.NewGuid(), MediaType = new MediaTypeCollectionReferenceResponseModel() { Collection = new ReferenceByIdModel(Guid.NewGuid()) },
},
new() { Id = Guid.NewGuid() },
};
await sut.PopulateSignsAsync(viewModels);
Assert.AreEqual(viewModels[0].Signs.Count(), 1);
Assert.AreEqual(viewModels[1].Signs.Count(), 0);
var signModel = viewModels[0].Signs.First();
Assert.AreEqual("Umb.HasCollection", signModel.Alias);
}
[Test]
public async Task HasCollectionSignProvider_Should_Populate_Media_Item_Signs()
{
var sut = new HasCollectionSignProvider();
var viewModels = new List<MediaItemResponseModel>
{
new()
{
Id = Guid.NewGuid(), MediaType = new MediaTypeReferenceResponseModel() { Collection = new ReferenceByIdModel(Guid.NewGuid()) },
},
new() { Id = Guid.NewGuid() },
};
await sut.PopulateSignsAsync(viewModels);
Assert.AreEqual(viewModels[0].Signs.Count(), 1);
Assert.AreEqual(viewModels[1].Signs.Count(), 0);
var signModel = viewModels[0].Signs.First();
Assert.AreEqual("Umb.HasCollection", signModel.Alias);
}
}

View File

@@ -1,86 +0,0 @@
using NUnit.Framework;
using Umbraco.Cms.Api.Management.Services.Signs;
using Umbraco.Cms.Api.Management.ViewModels.Document;
using Umbraco.Cms.Api.Management.ViewModels.Document.Collection;
using Umbraco.Cms.Api.Management.ViewModels.Document.Item;
using Umbraco.Cms.Api.Management.ViewModels.Tree;
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Cms.Api.Management.Services.Signs;
[TestFixture]
internal class HasPendingChangesSignProviderTests
{
[Test]
public void HasPendingChangesSignProvider_Can_Provide_Variant_Item_Signs()
{
var sut = new HasPendingChangesSignProvider();
Assert.IsTrue(sut.CanProvideSigns<DocumentVariantItemResponseModel>());
}
[Test]
public void HasPendingChangesSignProvider_Can_Provide_Variant_Signs()
{
var sut = new HasPendingChangesSignProvider();
Assert.IsTrue(sut.CanProvideSigns<DocumentVariantResponseModel>());
}
[Test]
public async Task HasPendingChangesSignProvider_Should_Populate_Variant_Item_Signs()
{
var sut = new HasPendingChangesSignProvider();
var variants = new List<DocumentVariantItemResponseModel>
{
new()
{
State = DocumentVariantState.PublishedPendingChanges,
Culture = null,
Name = "Test",
},
new()
{
State = DocumentVariantState.Published,
Culture = null,
Name = "Test2",
},
};
await sut.PopulateSignsAsync(variants);
Assert.AreEqual(variants[0].Signs.Count(), 1);
Assert.AreEqual(variants[1].Signs.Count(), 0);
var signModel = variants[0].Signs.First();
Assert.AreEqual("Umb.PendingChanges", signModel.Alias);
}
[Test]
public async Task HasPendingChangesSignProvider_Should_Populate_Variant_Signs()
{
var sut = new HasPendingChangesSignProvider();
var variants = new List<DocumentVariantResponseModel>
{
new()
{
State = DocumentVariantState.PublishedPendingChanges,
Culture = null,
Name = "Test",
},
new()
{
State = DocumentVariantState.Published,
Culture = null,
Name = "Test2",
},
};
await sut.PopulateSignsAsync(variants);
Assert.AreEqual(variants[0].Signs.Count(), 1);
Assert.AreEqual(variants[1].Signs.Count(), 0);
var signModel = variants[0].Signs.First();
Assert.AreEqual("Umb.PendingChanges", signModel.Alias);
}
}

View File

@@ -1,92 +0,0 @@
using NUnit.Framework;
using Umbraco.Cms.Api.Management.Services.Signs;
using Umbraco.Cms.Api.Management.ViewModels.Document.Collection;
using Umbraco.Cms.Api.Management.ViewModels.Document.Item;
using Umbraco.Cms.Api.Management.ViewModels.Tree;
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Cms.Api.Management.Services.Signs;
[TestFixture]
internal class IsProtectedSignProviderTests
{
[Test]
public void IsProtectedSignProvider_Can_Provide_Tree_Signs()
{
var sut = new IsProtectedSignProvider();
Assert.IsTrue(sut.CanProvideSigns<DocumentTreeItemResponseModel>());
}
[Test]
public void IsProtectedSignProvider_Can_Provide_Collection_Signs()
{
var sut = new IsProtectedSignProvider();
Assert.IsTrue(sut.CanProvideSigns<DocumentCollectionResponseModel>());
}
[Test]
public void IsProtectedSignProvider_Can_Provide_Plain_Signs()
{
var sut = new IsProtectedSignProvider();
Assert.IsTrue(sut.CanProvideSigns<DocumentItemResponseModel>());
}
[Test]
public async Task IsProtectedSignProvider_Should_Populate_Tree_Signs()
{
var sut = new IsProtectedSignProvider();
var viewModels = new List<DocumentTreeItemResponseModel>
{
new(),
new() { IsProtected = true },
};
await sut.PopulateSignsAsync(viewModels);
Assert.AreEqual(viewModels[0].Signs.Count(), 0);
Assert.AreEqual(viewModels[1].Signs.Count(), 1);
var signModel = viewModels[1].Signs.First();
Assert.AreEqual("Umb.IsProtected", signModel.Alias);
}
[Test]
public async Task IsProtectedSignProvider_Should_Populate_Collection_Signs()
{
var sut = new IsProtectedSignProvider();
var viewModels = new List<DocumentCollectionResponseModel>
{
new(),
new() { IsProtected = true },
};
await sut.PopulateSignsAsync(viewModels);
Assert.AreEqual(viewModels[0].Signs.Count(), 0);
Assert.AreEqual(viewModels[1].Signs.Count(), 1);
var signModel = viewModels[1].Signs.First();
Assert.AreEqual("Umb.IsProtected", signModel.Alias);
}
[Test]
public async Task IsProtectedSignProvider_Should_Populate_Plain_Signs()
{
var sut = new IsProtectedSignProvider();
var viewModels = new List<DocumentItemResponseModel>
{
new(),
new() { IsProtected = true },
};
await sut.PopulateSignsAsync(viewModels);
Assert.AreEqual(viewModels[0].Signs.Count(), 0);
Assert.AreEqual(viewModels[1].Signs.Count(), 1);
var signModel = viewModels[1].Signs.First();
Assert.AreEqual("Umb.IsProtected", signModel.Alias);
}
}

View File

@@ -10,6 +10,7 @@ using Umbraco.Cms.Core.PropertyEditors;
using Umbraco.Cms.Core.PropertyEditors.ValueConverters;
using Umbraco.Cms.Core.PublishedCache;
using Umbraco.Cms.Infrastructure.DeliveryApi;
using Umbraco.Extensions;
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.DeliveryApi;
@@ -127,12 +128,15 @@ public class RichTextParserTests : PropertyValueConverterTests
Assert.AreEqual("the original something", span.Attributes.First().Value);
}
[Test]
public void ParseElement_CanParseContentLink()
[TestCase(null)]
[TestCase("")]
[TestCase("#some-anchor")]
[TestCase("?something=true")]
public void ParseElement_CanParseContentLink(string? postfix)
{
var parser = CreateRichTextElementParser();
var element = parser.Parse($"<p><a href=\"/{{localLink:umb://document/{_contentKey:N}}}\"></a></p>", RichTextBlockModel.Empty) as RichTextRootElement;
var element = parser.Parse($"<p><a href=\"/{{localLink:umb://document/{_contentKey:N}}}{postfix}\"></a></p>", RichTextBlockModel.Empty) as RichTextRootElement;
Assert.IsNotNull(element);
var link = element.Elements.OfType<RichTextGenericElement>().Single().Elements.Single() as RichTextGenericElement;
Assert.IsNotNull(link);
@@ -142,6 +146,7 @@ public class RichTextParserTests : PropertyValueConverterTests
var route = link.Attributes.First().Value as IApiContentRoute;
Assert.IsNotNull(route);
Assert.AreEqual("/some-content-path", route.Path);
Assert.AreEqual(postfix.NullOrWhiteSpaceAsNull(), route.QueryString);
Assert.AreEqual(_contentRootKey, route.StartItem.Id);
Assert.AreEqual("the-root-path", route.StartItem.Path);
}
@@ -176,6 +181,22 @@ public class RichTextParserTests : PropertyValueConverterTests
Assert.AreEqual("https://some.where/else/", link.Attributes.First().Value);
}
[TestCase("#some-anchor")]
[TestCase("?something=true")]
public void ParseElement_CanHandleNonLocalLink_WithPostfix(string postfix)
{
var parser = CreateRichTextElementParser();
var element = parser.Parse($"<p><a href=\"https://some.where/else/{postfix}\"></a></p>", RichTextBlockModel.Empty) as RichTextRootElement;
Assert.IsNotNull(element);
var link = element.Elements.OfType<RichTextGenericElement>().Single().Elements.Single() as RichTextGenericElement;
Assert.IsNotNull(link);
Assert.AreEqual("a", link.Tag);
Assert.AreEqual(1, link.Attributes.Count);
Assert.AreEqual("href", link.Attributes.First().Key);
Assert.AreEqual($"https://some.where/else/{postfix}", link.Attributes.First().Value);
}
[Test]
public void ParseElement_LinkTextIsWrappedInTextElement()
{
@@ -459,12 +480,51 @@ public class RichTextParserTests : PropertyValueConverterTests
{
var parser = CreateRichTextMarkupParser();
var result = parser.Parse($"<p><a href=\"/{{localLink:{_contentKey:N}}}\" type=\"document\"></a></p>");
Assert.IsTrue(result.Contains("href=\"/some-content-path\""));
Assert.IsTrue(result.Contains("data-start-item-path=\"the-root-path\""));
Assert.IsTrue(result.Contains($"data-start-item-id=\"{_contentRootKey:D}\""));
}
[Test]
public void ParseMarkup_CanParseLegacyContentLink()
{
var parser = CreateRichTextMarkupParser();
var result = parser.Parse($"<p><a href=\"/{{localLink:umb://document/{_contentKey:N}}}\"></a></p>");
Assert.IsTrue(result.Contains("href=\"/some-content-path\""));
Assert.IsTrue(result.Contains("data-start-item-path=\"the-root-path\""));
Assert.IsTrue(result.Contains($"data-start-item-id=\"{_contentRootKey:D}\""));
}
[TestCase("#some-anchor")]
[TestCase("?something=true")]
[TestCase("#!some-hashbang")]
[TestCase("?something=true#some-anchor")]
public void ParseMarkup_CanParseContentLink_WithPostfix(string postfix)
{
var parser = CreateRichTextMarkupParser();
var result = parser.Parse($"<p><a href=\"/{{localLink:{_contentKey:N}}}{postfix}\" type=\"document\"></a></p>");
Assert.IsTrue(result.Contains($"href=\"/some-content-path{postfix}\""));
Assert.IsTrue(result.Contains("data-start-item-path=\"the-root-path\""));
Assert.IsTrue(result.Contains($"data-start-item-id=\"{_contentRootKey:D}\""));
}
[TestCase("#some-anchor")]
[TestCase("?something=true")]
[TestCase("#!some-hashbang")]
[TestCase("?something=true#some-anchor")]
public void ParseMarkup_CanParseLegacyContentLink_WithPostfix(string postfix)
{
var parser = CreateRichTextMarkupParser();
var result = parser.Parse($"<p><a href=\"/{{localLink:umb://document/{_contentKey:N}}}{postfix}\"></a></p>");
Assert.IsTrue(result.Contains($"href=\"/some-content-path{postfix}\""));
Assert.IsTrue(result.Contains("data-start-item-path=\"the-root-path\""));
Assert.IsTrue(result.Contains($"data-start-item-id=\"{_contentRootKey:D}\""));
}
[Test]
public void ParseMarkup_CanParseMediaLink()
{
@@ -485,6 +545,8 @@ public class RichTextParserTests : PropertyValueConverterTests
}
[TestCase("<p><a href=\"https://some.where/else/\"></a></p>")]
[TestCase("<p><a href=\"https://some.where/else/#some-anchor\"></a></p>")]
[TestCase("<p><a href=\"https://some.where/else/?something=true\"></a></p>")]
[TestCase("<p><img src=\"https://some.where/something.png?rmode=max&amp;width=500\"></p>")]
public void ParseMarkup_CanHandleNonLocalReferences(string html)
{

View File

@@ -79,6 +79,45 @@ public class ApiRichTextMarkupParserTests
Assert.AreEqual(expectedOutput, parsedHtml);
}
[TestCase("#some-anchor")]
[TestCase("?something=true")]
[TestCase("#!some-hashbang")]
[TestCase("?something=true#some-anchor")]
public void Can_Parse_LocalLinks_With_Postfix(string postfix)
{
var key1 = Guid.Parse("eed5fc6b-96fd-45a5-a0f1-b1adfb483c2f");
var data1 = new MockData()
.WithKey(key1)
.WithRoutePath($"/self/{postfix}")
.WithRouteStartPath("self");
var key2 = Guid.Parse("cc143afe-4cbf-46e5-b399-c9f451384373");
var data2 = new MockData()
.WithKey(key2)
.WithRoutePath($"/other/{postfix}")
.WithRouteStartPath("other");
var mockData = new Dictionary<Guid, MockData>
{
{ key1, data1 },
{ key2, data2 },
};
var parser = BuildDefaultSut(mockData);
var html =
$@"<p>Rich text outside of the blocks with a link to <a type=""document"" href=""/{{localLink:eed5fc6b-96fd-45a5-a0f1-b1adfb483c2f}}{postfix}"" title=""itself"">itself</a><br><br></p>
<p>and to the <a type=""document"" href=""/{{localLink:cc143afe-4cbf-46e5-b399-c9f451384373}}{postfix}"" title=""other page"">other page</a></p>";
var expectedOutput =
$@"<p>Rich text outside of the blocks with a link to <a href=""/self/{postfix}"" title=""itself"" data-start-item-path=""self"" data-start-item-id=""eed5fc6b-96fd-45a5-a0f1-b1adfb483c2f"">itself</a><br><br></p>
<p>and to the <a href=""/other/{postfix}"" title=""other page"" data-start-item-path=""other"" data-start-item-id=""cc143afe-4cbf-46e5-b399-c9f451384373"">other page</a></p>";
var parsedHtml = parser.Parse(html);
Assert.AreEqual(expectedOutput, parsedHtml);
}
[Test]
public void Can_Parse_Inline_LocalImages()
{