V14: Test new content and media list view service (#16193)

* Fix operation status msg

* Cleanup

* Removing unused status

* Adding WithConfigurationEditor on DataEditorBuilder to be able to create new list views with custom configuration

* Adding list view service tests for content and media

* Adding list view service tests base

* Consistency

* Clean up

* More cleanup

---------

Co-authored-by: Bjarke Berg <mail@bergmania.dk>
This commit is contained in:
Elitsa Marinovska
2024-05-01 10:54:26 +02:00
committed by GitHub
parent 94b0f4d1a2
commit c8180d508b
9 changed files with 1320 additions and 9 deletions

View File

@@ -68,10 +68,6 @@ public abstract class ContentCollectionControllerBase<TContent, TCollectionRespo
.WithTitle("Data type id does not belong to a collection")
.WithDetail("The specified data type does not represent a collection")
.Build()),
ContentCollectionOperationStatus.DataTypeNotContentCollection => new BadRequestObjectResult(problemDetailsBuilder
.WithTitle("Data type id does not represent the configured collection")
.WithDetail($"The specified data type is not the configured collection for the given {type} item")
.Build()),
ContentCollectionOperationStatus.DataTypeNotContentProperty => new BadRequestObjectResult(problemDetailsBuilder
.WithTitle($"Data type id is not a {type} property")
.WithDetail($"The specified data type is not part of the {type} properties")

View File

@@ -17,7 +17,7 @@ public abstract class ContentControllerBase : ManagementApiControllerBase
.WithDetail("A notification handler prevented the content operation.")
.Build()),
ContentEditingOperationStatus.ContentTypeNotFound => NotFound(problemDetailsBuilder
.WithTitle("The requested content could not be found")
.WithTitle("The requested content type could not be found")
.Build()),
ContentEditingOperationStatus.ContentTypeCultureVarianceMismatch => BadRequest(problemDetailsBuilder
.WithTitle("Content type culture variance mismatch")

View File

@@ -8,7 +8,6 @@ public enum ContentCollectionOperationStatus
ContentNotFound,
ContentTypeNotFound,
DataTypeNotCollection,
DataTypeNotContentCollection,
DataTypeNotContentProperty,
DataTypeNotFound,
DataTypeWithoutContentType,

View File

@@ -5,7 +5,6 @@ using Umbraco.Cms.Core.Models.Membership;
using Umbraco.Cms.Core.Persistence.Querying;
using Umbraco.Cms.Core.Security.Authorization;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Services.AuthorizationStatus;
using Umbraco.Cms.Core.Services.OperationStatus;
using Umbraco.Cms.Infrastructure.Persistence;

View File

@@ -4,7 +4,6 @@ using Umbraco.Cms.Core.Models.Membership;
using Umbraco.Cms.Core.Persistence.Querying;
using Umbraco.Cms.Core.Security.Authorization;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Services.AuthorizationStatus;
using Umbraco.Cms.Core.Services.OperationStatus;
using Umbraco.Cms.Infrastructure.Persistence;

View File

@@ -20,6 +20,7 @@ public class DataEditorBuilder<TParent>
private string _alias;
private IDictionary<string, object> _defaultConfiguration;
private string _name;
private ConfigurationEditor? _configurationEditor;
public DataEditorBuilder(TParent parentBuilder)
: base(parentBuilder)
@@ -46,6 +47,12 @@ public class DataEditorBuilder<TParent>
return this;
}
public DataEditorBuilder<TParent> WithConfigurationEditor(ConfigurationEditor configurationEditor)
{
_configurationEditor = configurationEditor;
return this;
}
public ConfigurationEditorBuilder<DataEditorBuilder<TParent>> AddExplicitConfigurationEditorBuilder() =>
_explicitConfigurationEditorBuilder;
@@ -58,7 +65,7 @@ public class DataEditorBuilder<TParent>
var alias = _alias ?? name.ToCamelCase();
var defaultConfiguration = _defaultConfiguration ?? new Dictionary<string, object>();
var explicitConfigurationEditor = _explicitConfigurationEditorBuilder.Build();
var explicitConfigurationEditor = _configurationEditor ?? _explicitConfigurationEditorBuilder.Build();
var explicitValueEditor = _explicitValueEditorBuilder.Build();
return new DataEditor(

View File

@@ -0,0 +1,53 @@
using NUnit.Framework;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.Membership;
using Umbraco.Cms.Core.PropertyEditors;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Tests.Common.Testing;
using Umbraco.Cms.Tests.Integration.Testing;
namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services;
[TestFixture]
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)]
public abstract class ContentListViewServiceTestsBase : UmbracoIntegrationTest
{
protected IDataTypeService DataTypeService => GetRequiredService<IDataTypeService>();
protected IUserGroupService UserGroupService => GetRequiredService<IUserGroupService>();
protected IUserService UserService => GetRequiredService<IUserService>();
protected async Task<IUser> GetSuperUser()
=> await UserService.GetAsync(Constants.Security.SuperUserKey);
protected async Task AssertListViewConfiguration(ListViewConfiguration actualConfiguration, Guid expectedListViewDataTypeKey)
{
var actualCollectionPropertyAliases = actualConfiguration
.IncludeProperties
.Select(p => p.Alias)
.WhereNotNull()
.ToArray();
// The configured list view
var expectedContentListViewConfig = await GetListViewConfigurationFromListViewDataType(expectedListViewDataTypeKey);
var expectedCollectionPropertyAliases = expectedContentListViewConfig
.IncludeProperties
.Select(p => p.Alias)
.WhereNotNull()
.ToArray();
Assert.AreEqual(expectedCollectionPropertyAliases.Length, actualCollectionPropertyAliases.Length);
Assert.IsTrue(expectedCollectionPropertyAliases.SequenceEqual(actualCollectionPropertyAliases));
}
private async Task<ListViewConfiguration> GetListViewConfigurationFromListViewDataType(Guid dataTypeKey)
{
IDataType? dataType = await DataTypeService.GetAsync(dataTypeKey);
var listViewConfiguration = dataType.ConfigurationObject;
Assert.IsTrue(listViewConfiguration is ListViewConfiguration);
return listViewConfiguration as ListViewConfiguration;
}
}

View File

@@ -0,0 +1,244 @@
using NUnit.Framework;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.ContentEditing;
using Umbraco.Cms.Core.Models.Membership;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Services.OperationStatus;
using Umbraco.Cms.Tests.Common.Builders;
using Umbraco.Cms.Tests.Common.Builders.Extensions;
namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services;
/// <summary>
/// Tests for the media list view service. Please notice that a lot of functional test is covered by the content list
/// view service tests, since these services share the same base implementation.
/// </summary>
public class MediaListViewServiceTests : ContentListViewServiceTestsBase
{
private IMediaListViewService MediaListViewService => GetRequiredService<IMediaListViewService>();
private IMediaTypeService MediaTypeService => GetRequiredService<IMediaTypeService>();
private IMediaService MediaService => GetRequiredService<IMediaService>();
private IMediaEditingService MediaEditingService => GetRequiredService<IMediaEditingService>();
private IUser SuperUser { get; set; }
[SetUp]
public async Task Setup()
=> SuperUser = await GetSuperUser();
[Test]
public async Task Can_Get_List_View_Items_At_Root()
{
// Arrange
CreateTenMediaItemsFromTwoMediaTypesAtRoot();
var descendants = MediaService.GetPagedDescendants(Constants.System.Root, 0, int.MaxValue, out _);
// Act
var result = await MediaListViewService.GetListViewItemsByKeyAsync(
SuperUser,
null,
null,
"updateDate",
Direction.Ascending,
null,
0,
10);
// Assert
Assert.Multiple(() =>
{
Assert.IsTrue(result.Success);
Assert.AreEqual(ContentCollectionOperationStatus.Success, result.Status);
Assert.IsNotNull(result.Result);
PagedModel<IMedia> collectionItemsResult = result.Result.Items;
Assert.AreEqual(10, collectionItemsResult.Total);
CollectionAssert.AreEquivalent(descendants, collectionItemsResult.Items);
});
}
[Test]
public async Task Can_Get_Items_With_Default_List_View_Configuration()
{
// Arrange
CreateTenMediaItemsFromTwoMediaTypesAtRoot();
// Act
var result = await MediaListViewService.GetListViewItemsByKeyAsync(
SuperUser,
null,
null,
"updateDate",
Direction.Ascending,
null,
0,
10);
// Assert
Assert.Multiple(async () =>
{
Assert.IsTrue(result.Success);
Assert.AreEqual(ContentCollectionOperationStatus.Success, result.Status);
Assert.IsNotNull(result.Result);
await AssertListViewConfiguration(result.Result.ListViewConfiguration, Constants.DataTypes.Guids.ListViewMediaGuid);
});
}
[Test]
public async Task Can_Get_List_View_Items_By_Key()
{
// Arrange
var root = await CreateRootMediaWithFiveChildrenAsListViewItems();
var descendants = MediaService.GetPagedDescendants(root.Id, 0, int.MaxValue, out _);
// Act
var result = await MediaListViewService.GetListViewItemsByKeyAsync(
SuperUser,
root.Key,
null,
"updateDate",
Direction.Ascending,
null,
0,
10);
// Assert
Assert.Multiple(() =>
{
// Assert the content type is configured as list view
Assert.IsNotNull(root.ContentType.ListView);
Assert.IsTrue(result.Success);
Assert.AreEqual(ContentCollectionOperationStatus.Success, result.Status);
Assert.IsNotNull(result.Result);
PagedModel<IMedia> collectionItemsResult = result.Result.Items;
Assert.AreEqual(5, collectionItemsResult.Total);
CollectionAssert.AreEquivalent(descendants, collectionItemsResult.Items);
});
}
[Test]
public async Task Can_Only_Get_List_View_Items_That_The_User_Has_Access_To()
{
// Arrange
// Media item that the user doesn't have access to
var imageMediaType = MediaTypeService.Get(Constants.Conventions.MediaTypes.Image);
var image = MediaBuilder.CreateMediaImage(imageMediaType, -1);
MediaService.Save(image);
// Media item that serves as a start node
var album = await CreateRootMediaWithFiveChildrenAsListViewItems();
MediaService.GetPagedChildren(Constants.System.Root, 0, int.MaxValue, out var totalChildren);
// New user and user group
var userGroup = new UserGroupBuilder()
.WithAlias("test")
.WithName("Test")
.WithAllowedSections(new[] { "packages" })
.WithStartMediaId(album.Id)
.Build();
var userGroupCreateResult = await UserGroupService.CreateAsync(userGroup, Constants.Security.SuperUserKey);
var userCreateModel = new UserCreateModel
{
UserName = "testUser@mail.com",
Email = "testUser@mail.com",
Name = "Test user",
UserGroupKeys = new HashSet<Guid> { userGroupCreateResult.Result.Key },
};
var userCreateResult =
await UserService.CreateAsync(Constants.Security.SuperUserKey, userCreateModel, true);
// Act
var result = await MediaListViewService.GetListViewItemsByKeyAsync(
userCreateResult.Result.CreatedUser,
null,
null,
"updateDate",
Direction.Ascending,
null,
0,
10);
// Assert
Assert.Multiple(() =>
{
Assert.IsTrue(result.Success);
Assert.AreEqual(ContentCollectionOperationStatus.Success, result.Status);
Assert.IsNotNull(result.Result);
Assert.AreEqual(2, totalChildren);
Assert.AreEqual(1, result.Result.Items.Items.Count());
});
}
private void CreateTenMediaItemsFromTwoMediaTypesAtRoot()
{
var mediaType1 = MediaTypeBuilder.CreateImageMediaType("Image2");
MediaTypeService.Save(mediaType1);
var mediaType2 = MediaTypeBuilder.CreateImageMediaType("Image3");
MediaTypeService.Save(mediaType2);
for (var i = 0; i < 5; i++)
{
var m1 = MediaBuilder.CreateMediaImage(mediaType1, -1);
MediaService.Save(m1);
var m2 = MediaBuilder.CreateMediaImage(mediaType2, -1);
MediaService.Save(m2);
}
}
private async Task<IMedia> CreateRootMediaWithFiveChildrenAsListViewItems(Guid? listViewDataTypeKey = null)
{
var childImageMediaType = MediaTypeService.Get(Constants.Conventions.MediaTypes.Image);
var mediaTypeWithListView = new MediaTypeBuilder()
.WithAlias("album")
.WithName("Album")
.WithIsContainer(listViewDataTypeKey ?? Constants.DataTypes.Guids.ListViewMediaGuid)
.Build();
mediaTypeWithListView.AllowedAsRoot = true;
mediaTypeWithListView.AllowedContentTypes = new[]
{
new ContentTypeSort(childImageMediaType.Key, 1, childImageMediaType.Alias),
};
MediaTypeService.Save(mediaTypeWithListView);
var rootContentCreateModel = new MediaCreateModel
{
ContentTypeKey = mediaTypeWithListView.Key,
ParentKey = Constants.System.RootKey,
InvariantName = "Album",
};
var result = await MediaEditingService.CreateAsync(rootContentCreateModel, Constants.Security.SuperUserKey);
var root = result.Result.Content;
for (var i = 1; i < 6; i++)
{
var createModel = new MediaCreateModel
{
ContentTypeKey = childImageMediaType.Key,
ParentKey = root.Key,
InvariantName = $"Image {i}",
Key = i.ToGuid(),
};
await MediaEditingService.CreateAsync(createModel, Constants.Security.SuperUserKey);
}
return root;
}
}