Merge branch 'v16/dev' into v15/feature/select-segment
This commit is contained in:
@@ -78,6 +78,20 @@
|
||||
<Right>lib/net9.0/Umbraco.Tests.Integration.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Umbraco.Cms.Tests.Integration.Umbraco.Core.Services.DocumentNavigationServiceTests.Bin_Structure_Can_Rebuild</Target>
|
||||
<Left>lib/net9.0/Umbraco.Tests.Integration.dll</Left>
|
||||
<Right>lib/net9.0/Umbraco.Tests.Integration.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Umbraco.Cms.Tests.Integration.Umbraco.Core.Services.DocumentNavigationServiceTests.Structure_Can_Rebuild</Target>
|
||||
<Left>lib/net9.0/Umbraco.Tests.Integration.dll</Left>
|
||||
<Right>lib/net9.0/Umbraco.Tests.Integration.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Umbraco.Cms.Tests.Integration.Umbraco.Core.Services.UserServiceCrudTests.Cannot_Request_Disabled_If_Hidden(Umbraco.Cms.Core.Models.Membership.UserState)</Target>
|
||||
@@ -92,6 +106,13 @@
|
||||
<Right>lib/net9.0/Umbraco.Tests.Integration.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services.EntityServiceTests.CreateTestData</Target>
|
||||
<Left>lib/net9.0/Umbraco.Tests.Integration.dll</Left>
|
||||
<Right>lib/net9.0/Umbraco.Tests.Integration.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services.MemberEditingServiceTests.Cannot_Change_IsApproved_Without_Access</Target>
|
||||
@@ -113,4 +134,11 @@
|
||||
<Right>lib/net9.0/Umbraco.Tests.Integration.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
<Suppression>
|
||||
<DiagnosticId>CP0002</DiagnosticId>
|
||||
<Target>M:Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services.TrackedReferencesServiceTests.Does_not_return_references_if_item_is_not_referenced</Target>
|
||||
<Left>lib/net9.0/Umbraco.Tests.Integration.dll</Left>
|
||||
<Right>lib/net9.0/Umbraco.Tests.Integration.dll</Right>
|
||||
<IsBaselineSuppression>true</IsBaselineSuppression>
|
||||
</Suppression>
|
||||
</Suppressions>
|
||||
@@ -108,7 +108,6 @@ public static class UmbracoBuilderExtensions
|
||||
/// </summary>
|
||||
private static ILocalizedTextService GetLocalizedTextService(IServiceProvider factory)
|
||||
{
|
||||
var globalSettings = factory.GetRequiredService<IOptions<GlobalSettings>>();
|
||||
var loggerFactory = factory.GetRequiredService<ILoggerFactory>();
|
||||
var appCaches = factory.GetRequiredService<AppCaches>();
|
||||
|
||||
@@ -133,7 +132,7 @@ public static class UmbracoBuilderExtensions
|
||||
uiProject.Create();
|
||||
}
|
||||
|
||||
var mainLangFolder = new DirectoryInfo(Path.Combine(uiProject.FullName, Constants.System.DefaultUmbracoPath.TrimStart("~/"), "config", "lang"));
|
||||
var mainLangFolder = new DirectoryInfo(Path.Combine(uiProject.FullName, Constants.System.DefaultUmbracoPath.TrimStart(Constants.CharArrays.TildeForwardSlash), "config", "lang"));
|
||||
|
||||
return new LocalizedTextServiceFileSources(
|
||||
loggerFactory.CreateLogger<LocalizedTextServiceFileSources>(),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Api.Management.Factories;
|
||||
using Umbraco.Cms.Api.Management.Mapping.Permissions;
|
||||
@@ -7,6 +7,7 @@ using Umbraco.Cms.Api.Management.ViewModels.UserGroup;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.UserGroup.Permissions;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.Membership.Permissions;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Services.ContentTypeEditing;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
@@ -20,11 +21,14 @@ namespace Umbraco.Cms.Tests.Integration.ManagementApi.Factories;
|
||||
|
||||
[TestFixture]
|
||||
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)]
|
||||
public class UserGroupPresentationFactoryTests : UmbracoIntegrationTest
|
||||
internal sealed class UserGroupPresentationFactoryTests : UmbracoIntegrationTest
|
||||
{
|
||||
public IUserGroupPresentationFactory UserGroupPresentationFactory => GetRequiredService<IUserGroupPresentationFactory>();
|
||||
|
||||
public IUserGroupService UserGroupService => GetRequiredService<IUserGroupService>();
|
||||
|
||||
public ITemplateService TemplateService => GetRequiredService<ITemplateService>();
|
||||
|
||||
public IContentTypeEditingService ContentTypeEditingService => GetRequiredService<IContentTypeEditingService>();
|
||||
|
||||
public IContentEditingService ContentEditingService => GetRequiredService<IContentEditingService>();
|
||||
@@ -33,27 +37,27 @@ public class UserGroupPresentationFactoryTests : UmbracoIntegrationTest
|
||||
{
|
||||
services.AddTransient<IUserGroupPresentationFactory, UserGroupPresentationFactory>();
|
||||
services.AddSingleton<IPermissionPresentationFactory, PermissionPresentationFactory>();
|
||||
services.AddSingleton<DocumentPermissionMapper>();
|
||||
services.AddSingleton<IPermissionMapper>(x=>x.GetRequiredService<DocumentPermissionMapper>());
|
||||
services.AddSingleton<IPermissionPresentationMapper>(x=>x.GetRequiredService<DocumentPermissionMapper>());
|
||||
services.AddSingleton<IPermissionMapper, DocumentPermissionMapper>();
|
||||
services.AddSingleton<IPermissionPresentationMapper, DocumentPermissionMapper>();
|
||||
services.AddSingleton<IPermissionMapper, DocumentPropertyValuePermissionMapper>();
|
||||
services.AddSingleton<IPermissionPresentationMapper, DocumentPropertyValuePermissionMapper>();
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public async Task Can_Map_Create_Model_And_Create()
|
||||
{
|
||||
var updateModel = new CreateUserGroupRequestModel()
|
||||
var createModel = new CreateUserGroupRequestModel()
|
||||
{
|
||||
Alias = "testAlias",
|
||||
FallbackPermissions = new HashSet<string>(),
|
||||
HasAccessToAllLanguages = true,
|
||||
Languages = new List<string>(),
|
||||
Name = "Test Name",
|
||||
Sections = new [] {"Umb.Section.Content"},
|
||||
Sections = new[] { "Umb.Section.Content" },
|
||||
Permissions = new HashSet<IPermissionPresentationModel>()
|
||||
};
|
||||
|
||||
var attempt = await UserGroupPresentationFactory.CreateAsync(updateModel);
|
||||
var attempt = await UserGroupPresentationFactory.CreateAsync(createModel);
|
||||
Assert.IsTrue(attempt.Success);
|
||||
|
||||
var userGroupCreateAttempt = await UserGroupService.CreateAsync(attempt.Result, Constants.Security.SuperUserKey);
|
||||
@@ -70,6 +74,39 @@ public class UserGroupPresentationFactoryTests : UmbracoIntegrationTest
|
||||
|
||||
[Test]
|
||||
public async Task Cannot_Create_UserGroup_With_Unexisting_Document_Reference()
|
||||
{
|
||||
var createModel = new CreateUserGroupRequestModel()
|
||||
{
|
||||
Alias = "testAlias",
|
||||
FallbackPermissions = new HashSet<string>(),
|
||||
HasAccessToAllLanguages = true,
|
||||
Languages = new List<string>(),
|
||||
Name = "Test Name",
|
||||
Sections = new[] { "Umb.Section.Content" },
|
||||
Permissions = new HashSet<IPermissionPresentationModel>()
|
||||
{
|
||||
new DocumentPermissionPresentationModel()
|
||||
{
|
||||
Document = new ReferenceByIdModel(Guid.NewGuid()),
|
||||
Verbs = new HashSet<string>()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var attempt = await UserGroupPresentationFactory.CreateAsync(createModel);
|
||||
Assert.IsTrue(attempt.Success);
|
||||
|
||||
var userGroupCreateAttempt = await UserGroupService.CreateAsync(attempt.Result, Constants.Security.SuperUserKey);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.IsFalse(userGroupCreateAttempt.Success);
|
||||
Assert.AreEqual(UserGroupOperationStatus.DocumentPermissionKeyNotFound, userGroupCreateAttempt.Status);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Cannot_Create_UserGroup_With_Unexisting_DocumentType_Reference()
|
||||
{
|
||||
var updateModel = new CreateUserGroupRequestModel()
|
||||
{
|
||||
@@ -78,12 +115,13 @@ public class UserGroupPresentationFactoryTests : UmbracoIntegrationTest
|
||||
HasAccessToAllLanguages = true,
|
||||
Languages = new List<string>(),
|
||||
Name = "Test Name",
|
||||
Sections = new [] {"Umb.Section.Content"},
|
||||
Sections = new[] { "Umb.Section.Content" },
|
||||
Permissions = new HashSet<IPermissionPresentationModel>()
|
||||
{
|
||||
new DocumentPermissionPresentationModel()
|
||||
new DocumentPropertyValuePermissionPresentationModel()
|
||||
{
|
||||
Document = new ReferenceByIdModel(Guid.NewGuid()),
|
||||
DocumentType = new ReferenceByIdModel(Guid.NewGuid()),
|
||||
PropertyType = new ReferenceByIdModel(Guid.NewGuid()),
|
||||
Verbs = new HashSet<string>()
|
||||
}
|
||||
}
|
||||
@@ -97,23 +135,23 @@ public class UserGroupPresentationFactoryTests : UmbracoIntegrationTest
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.IsFalse(userGroupCreateAttempt.Success);
|
||||
Assert.AreEqual(UserGroupOperationStatus.DocumentPermissionKeyNotFound, userGroupCreateAttempt.Status);
|
||||
Assert.AreEqual(UserGroupOperationStatus.DocumentTypePermissionKeyNotFound, userGroupCreateAttempt.Status);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Can_Create_Usergroup_With_Empty_Granluar_Permissions_For_Document()
|
||||
public async Task Can_Create_Usergroup_With_Empty_Granular_Permissions_For_Document()
|
||||
{
|
||||
var contentKey = await CreateContent();
|
||||
|
||||
var updateModel = new CreateUserGroupRequestModel()
|
||||
var createModel = new CreateUserGroupRequestModel()
|
||||
{
|
||||
Alias = "testAlias",
|
||||
FallbackPermissions = new HashSet<string>(),
|
||||
HasAccessToAllLanguages = true,
|
||||
Languages = new List<string>(),
|
||||
Name = "Test Name",
|
||||
Sections = new [] {"Umb.Section.Content"},
|
||||
Sections = new[] { "Umb.Section.Content" },
|
||||
Permissions = new HashSet<IPermissionPresentationModel>
|
||||
{
|
||||
new DocumentPermissionPresentationModel()
|
||||
@@ -124,7 +162,7 @@ public class UserGroupPresentationFactoryTests : UmbracoIntegrationTest
|
||||
}
|
||||
};
|
||||
|
||||
var attempt = await UserGroupPresentationFactory.CreateAsync(updateModel);
|
||||
var attempt = await UserGroupPresentationFactory.CreateAsync(createModel);
|
||||
Assert.IsTrue(attempt.Success);
|
||||
|
||||
var userGroupCreateAttempt = await UserGroupService.CreateAsync(attempt.Result, Constants.Security.SuperUserKey);
|
||||
@@ -140,6 +178,170 @@ public class UserGroupPresentationFactoryTests : UmbracoIntegrationTest
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Can_Create_Usergroup_With_Granular_Permissions_For_Document_PropertyValue()
|
||||
{
|
||||
var template = TemplateBuilder.CreateTextPageTemplate("defaultTemplate");
|
||||
await TemplateService.CreateAsync(template, Constants.Security.SuperUserKey);
|
||||
|
||||
var contentType = (await ContentTypeEditingService.CreateAsync(
|
||||
ContentTypeEditingBuilder.CreateSimpleContentType(defaultTemplateKey: template.Key),
|
||||
Constants.Security.SuperUserKey)).Result!;
|
||||
|
||||
var propertyType = contentType.PropertyTypes.First();
|
||||
|
||||
var updateModel = new CreateUserGroupRequestModel()
|
||||
{
|
||||
Alias = "testAlias",
|
||||
FallbackPermissions = new HashSet<string>(),
|
||||
HasAccessToAllLanguages = true,
|
||||
Languages = new List<string>(),
|
||||
Name = "Test Name",
|
||||
Sections = new[] { "Umb.Section.Content" },
|
||||
Permissions = new HashSet<IPermissionPresentationModel>
|
||||
{
|
||||
new DocumentPropertyValuePermissionPresentationModel
|
||||
{
|
||||
DocumentType = new ReferenceByIdModel(contentType.Key),
|
||||
PropertyType = new ReferenceByIdModel(propertyType.Key),
|
||||
Verbs = new HashSet<string>(["Some", "Another"])
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var attempt = await UserGroupPresentationFactory.CreateAsync(updateModel);
|
||||
Assert.IsTrue(attempt.Success);
|
||||
|
||||
var userGroupCreateAttempt = await UserGroupService.CreateAsync(attempt.Result, Constants.Security.SuperUserKey);
|
||||
var userGroup = userGroupCreateAttempt.Result;
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.IsTrue(userGroupCreateAttempt.Success);
|
||||
Assert.IsNotNull(userGroup);
|
||||
});
|
||||
|
||||
Assert.AreEqual(2, userGroup.GranularPermissions.Count);
|
||||
var documentTypeGranularPermissions = userGroup.GranularPermissions.OfType<DocumentPropertyValueGranularPermission>().ToArray();
|
||||
Assert.AreEqual(2, documentTypeGranularPermissions.Length);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.IsTrue(documentTypeGranularPermissions.All(x => x.Key == contentType.Key));
|
||||
Assert.AreEqual($"{propertyType.Key}|Some", documentTypeGranularPermissions.First().Permission);
|
||||
Assert.AreEqual($"{propertyType.Key}|Another", documentTypeGranularPermissions.Last().Permission);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Can_Create_Usergroup_With_Granular_Permissions_For_Document_PropertyValue_Without_Verbs()
|
||||
{
|
||||
var template = TemplateBuilder.CreateTextPageTemplate("defaultTemplate");
|
||||
await TemplateService.CreateAsync(template, Constants.Security.SuperUserKey);
|
||||
|
||||
var contentType = (await ContentTypeEditingService.CreateAsync(
|
||||
ContentTypeEditingBuilder.CreateSimpleContentType(defaultTemplateKey: template.Key),
|
||||
Constants.Security.SuperUserKey)).Result!;
|
||||
|
||||
var propertyType = contentType.PropertyTypes.First();
|
||||
|
||||
var updateModel = new CreateUserGroupRequestModel()
|
||||
{
|
||||
Alias = "testAlias",
|
||||
FallbackPermissions = new HashSet<string>(),
|
||||
HasAccessToAllLanguages = true,
|
||||
Languages = new List<string>(),
|
||||
Name = "Test Name",
|
||||
Sections = new[] { "Umb.Section.Content" },
|
||||
Permissions = new HashSet<IPermissionPresentationModel>
|
||||
{
|
||||
new DocumentPropertyValuePermissionPresentationModel
|
||||
{
|
||||
DocumentType = new ReferenceByIdModel(contentType.Key),
|
||||
PropertyType = new ReferenceByIdModel(propertyType.Key),
|
||||
Verbs = new HashSet<string>()
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var attempt = await UserGroupPresentationFactory.CreateAsync(updateModel);
|
||||
Assert.IsTrue(attempt.Success);
|
||||
|
||||
var userGroupCreateAttempt = await UserGroupService.CreateAsync(attempt.Result, Constants.Security.SuperUserKey);
|
||||
var userGroup = userGroupCreateAttempt.Result;
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.IsTrue(userGroupCreateAttempt.Success);
|
||||
Assert.IsNotNull(userGroup);
|
||||
});
|
||||
|
||||
Assert.AreEqual(1, userGroup.GranularPermissions.Count);
|
||||
var documentTypeGranularPermissions = userGroup.GranularPermissions.OfType<DocumentPropertyValueGranularPermission>().ToArray();
|
||||
Assert.AreEqual(1, documentTypeGranularPermissions.Length);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.IsTrue(documentTypeGranularPermissions.All(x => x.Key == contentType.Key));
|
||||
Assert.AreEqual($"{propertyType.Key}|", documentTypeGranularPermissions.First().Permission);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Usergroup_Granular_Permissions_For_Document_PropertyValue_Are_Cleaned_Up_When_DocumentType_Is_Deleted()
|
||||
{
|
||||
var template = TemplateBuilder.CreateTextPageTemplate("defaultTemplate");
|
||||
await TemplateService.CreateAsync(template, Constants.Security.SuperUserKey);
|
||||
|
||||
var contentType1 = (await ContentTypeEditingService.CreateAsync(
|
||||
ContentTypeEditingBuilder.CreateSimpleContentType(defaultTemplateKey: template.Key),
|
||||
Constants.Security.SuperUserKey)).Result!;
|
||||
|
||||
var contentType2 = (await ContentTypeEditingService.CreateAsync(
|
||||
ContentTypeEditingBuilder.CreateSimpleContentType(alias: "anotherAlias", defaultTemplateKey: template.Key),
|
||||
Constants.Security.SuperUserKey)).Result!;
|
||||
|
||||
var propertyType1 = contentType1.PropertyTypes.First();
|
||||
var propertyType2 = contentType2.PropertyTypes.First();
|
||||
|
||||
var updateModel = new CreateUserGroupRequestModel()
|
||||
{
|
||||
Alias = "testAlias",
|
||||
FallbackPermissions = new HashSet<string>(),
|
||||
HasAccessToAllLanguages = true,
|
||||
Languages = new List<string>(),
|
||||
Name = "Test Name",
|
||||
Sections = new[] { "Umb.Section.Content" },
|
||||
Permissions = new HashSet<IPermissionPresentationModel>
|
||||
{
|
||||
new DocumentPropertyValuePermissionPresentationModel
|
||||
{
|
||||
DocumentType = new ReferenceByIdModel(contentType1.Key),
|
||||
PropertyType = new ReferenceByIdModel(propertyType1.Key),
|
||||
Verbs = new HashSet<string>(["Some", "Another"])
|
||||
},
|
||||
new DocumentPropertyValuePermissionPresentationModel
|
||||
{
|
||||
DocumentType = new ReferenceByIdModel(contentType2.Key),
|
||||
PropertyType = new ReferenceByIdModel(propertyType2.Key),
|
||||
Verbs = new HashSet<string>(["Even", "More"])
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var attempt = await UserGroupPresentationFactory.CreateAsync(updateModel);
|
||||
|
||||
var userGroupCreateAttempt = await UserGroupService.CreateAsync(attempt.Result, Constants.Security.SuperUserKey);
|
||||
Assert.IsTrue(userGroupCreateAttempt.Success);
|
||||
Assert.AreEqual(4, userGroupCreateAttempt.Result!.GranularPermissions.Count);
|
||||
|
||||
var deleteResult = await GetRequiredService<IContentTypeService>().DeleteAsync(contentType1.Key, Constants.Security.SuperUserKey);
|
||||
Assert.AreEqual(ContentTypeOperationStatus.Success, deleteResult);
|
||||
|
||||
var userGroup = await UserGroupService.GetAsync(userGroupCreateAttempt.Result!.Key);
|
||||
Assert.IsNotNull(userGroup);
|
||||
|
||||
Assert.AreEqual(2, userGroup.GranularPermissions.Count);
|
||||
}
|
||||
|
||||
private async Task<Guid> CreateContent()
|
||||
{
|
||||
// NOTE Maybe not the best way to create/save test data as we are using the services, which are being tested.
|
||||
@@ -151,7 +353,8 @@ public class UserGroupPresentationFactoryTests : UmbracoIntegrationTest
|
||||
Assert.IsTrue(contentTypeAttempt.Success);
|
||||
|
||||
var contentTypeResult = contentTypeAttempt.Result;
|
||||
var contentTypeUpdateModel = ContentTypeUpdateHelper.CreateContentTypeUpdateModel(contentTypeResult); contentTypeUpdateModel.AllowedContentTypes = new[]
|
||||
var contentTypeUpdateModel = ContentTypeUpdateHelper.CreateContentTypeUpdateModel(contentTypeResult);
|
||||
contentTypeUpdateModel.AllowedContentTypes = new[]
|
||||
{
|
||||
new ContentTypeSort(contentTypeResult.Key, 0, contentTypeCreateModel.Alias),
|
||||
};
|
||||
|
||||
@@ -0,0 +1,291 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Api.Management.Factories;
|
||||
using Umbraco.Cms.Api.Management.Mapping.Permissions;
|
||||
using Umbraco.Cms.Api.Management.Routing;
|
||||
using Umbraco.Cms.Api.Management.ViewModels.UserGroup.Permissions;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.Membership;
|
||||
using Umbraco.Cms.Core.Models.Membership.Permissions;
|
||||
using Umbraco.Cms.Core.Routing;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Infrastructure.Persistence.Mappers;
|
||||
using Umbraco.Cms.Tests.Common.Builders;
|
||||
using Umbraco.Cms.Tests.Common.Builders.Extensions;
|
||||
using Umbraco.Cms.Tests.Common.Testing;
|
||||
using Umbraco.Cms.Tests.Integration.Testing;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.ManagementApi.Factories;
|
||||
|
||||
[TestFixture]
|
||||
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)]
|
||||
public class UserPresentationFactoryTests : UmbracoIntegrationTestWithContent
|
||||
{
|
||||
public IUserPresentationFactory UserPresentationFactory => GetRequiredService<IUserPresentationFactory>();
|
||||
|
||||
public IUserGroupService UserGroupService => GetRequiredService<IUserGroupService>();
|
||||
|
||||
public IUserService UserService => GetRequiredService<IUserService>();
|
||||
|
||||
public ILanguageService LanguageService => GetRequiredService<ILanguageService>();
|
||||
|
||||
public IMediaService MediaService => GetRequiredService<IMediaService>();
|
||||
|
||||
protected override void ConfigureTestServices(IServiceCollection services)
|
||||
{
|
||||
services.AddTransient<IUserPresentationFactory, UserPresentationFactory>();
|
||||
services.AddTransient<IUserGroupPresentationFactory, UserGroupPresentationFactory>();
|
||||
services.AddSingleton<IAbsoluteUrlBuilder, DefaultAbsoluteUrlBuilder>();
|
||||
services.AddSingleton<IUrlAssembler, DefaultUrlAssembler>();
|
||||
services.AddSingleton<IPasswordConfigurationPresentationFactory, PasswordConfigurationPresentationFactory>();
|
||||
services.AddSingleton<IPermissionPresentationFactory, PermissionPresentationFactory>();
|
||||
|
||||
services.AddSingleton<IPermissionMapper, DocumentPermissionMapper>();
|
||||
services.AddSingleton<IPermissionPresentationMapper, DocumentPermissionMapper>();
|
||||
|
||||
services.AddSingleton<IPermissionMapper, DocumentPropertyValuePermissionMapper>();
|
||||
services.AddSingleton<IPermissionPresentationMapper, DocumentPropertyValuePermissionMapper>();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Can_Create_Current_User_Response_Model()
|
||||
{
|
||||
var daLanguage = new LanguageBuilder()
|
||||
.WithCultureInfo("da-DK")
|
||||
.Build();
|
||||
await LanguageService.CreateAsync(daLanguage, Constants.Security.SuperUserKey);
|
||||
var enUsLanguage = await LanguageService.GetAsync("en-US");
|
||||
var daDkLanguage = await LanguageService.GetAsync("da-DK");
|
||||
|
||||
var rootMediaFolder = MediaService.CreateMedia("Pictures Folder", Constants.System.Root, "Folder");
|
||||
MediaService.Save(rootMediaFolder);
|
||||
|
||||
var groupOne = await CreateUserGroup(
|
||||
"Group One",
|
||||
"groupOne",
|
||||
[enUsLanguage.Id],
|
||||
[],
|
||||
[],
|
||||
rootMediaFolder.Id);
|
||||
var groupTwo = await CreateUserGroup(
|
||||
"Group Two",
|
||||
"groupTwo",
|
||||
[daDkLanguage.Id],
|
||||
[],
|
||||
[],
|
||||
rootMediaFolder.Id);
|
||||
|
||||
var user = await CreateUser([groupOne.Key, groupTwo.Key]);
|
||||
|
||||
var model = await UserPresentationFactory.CreateCurrentUserResponseModelAsync(user);
|
||||
|
||||
Assert.AreEqual(user.Key, model.Id);
|
||||
Assert.AreEqual("test@test.com", model.Email);
|
||||
Assert.AreEqual("Test User", model.Name);
|
||||
Assert.AreEqual("test@test.com", model.UserName);
|
||||
Assert.AreEqual(2, model.UserGroupIds.Count);
|
||||
Assert.IsTrue(model.UserGroupIds.Select(x => x.Id).ContainsAll([groupOne.Key, groupTwo.Key]));
|
||||
Assert.IsFalse(model.HasAccessToAllLanguages);
|
||||
Assert.AreEqual(2, model.Languages.Count());
|
||||
Assert.IsTrue(model.Languages.ContainsAll(["en-US", "da-DK"]));
|
||||
Assert.IsTrue(model.HasDocumentRootAccess);
|
||||
Assert.AreEqual(0, model.DocumentStartNodeIds.Count);
|
||||
Assert.IsFalse(model.HasMediaRootAccess);
|
||||
Assert.AreEqual(1, model.MediaStartNodeIds.Count);
|
||||
Assert.AreEqual(rootMediaFolder.Key, model.MediaStartNodeIds.First().Id);
|
||||
Assert.IsFalse(model.HasAccessToSensitiveData);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Can_Create_Current_User_Response_Model_With_Aggregated_Document_Permissions()
|
||||
{
|
||||
var rootContentKey = Guid.Parse(TextpageKey);
|
||||
var subPageContentKey = Guid.Parse(SubPageKey);
|
||||
var subPage2ContentKey = Guid.Parse(SubPage2Key);
|
||||
|
||||
var rootMediaFolder = MediaService.CreateMedia("Pictures Folder", Constants.System.Root, "Folder");
|
||||
MediaService.Save(rootMediaFolder);
|
||||
|
||||
var groupOne = await CreateUserGroup(
|
||||
"Group One",
|
||||
"groupOne",
|
||||
[],
|
||||
["A", "B", "C"],
|
||||
[
|
||||
new DocumentGranularPermission
|
||||
{
|
||||
Key = rootContentKey,
|
||||
Permission = "A",
|
||||
},
|
||||
new DocumentGranularPermission
|
||||
{
|
||||
Key = rootContentKey,
|
||||
Permission = "E",
|
||||
},
|
||||
new DocumentGranularPermission
|
||||
{
|
||||
Key = subPageContentKey,
|
||||
Permission = "F",
|
||||
},
|
||||
new DocumentGranularPermission
|
||||
{
|
||||
Key = subPage2ContentKey,
|
||||
Permission = "F",
|
||||
}
|
||||
],
|
||||
rootMediaFolder.Id);
|
||||
var groupTwo = await CreateUserGroup(
|
||||
"Group Two",
|
||||
"groupTwo",
|
||||
[],
|
||||
["A", "B", "D"],
|
||||
[
|
||||
new DocumentGranularPermission
|
||||
{
|
||||
Key = subPage2ContentKey,
|
||||
Permission = "G",
|
||||
},
|
||||
new DocumentGranularPermission
|
||||
{
|
||||
Key = subPage2ContentKey,
|
||||
Permission = "H",
|
||||
}
|
||||
],
|
||||
rootMediaFolder.Id);
|
||||
|
||||
var user = await CreateUser([groupOne.Key, groupTwo.Key]);
|
||||
|
||||
var model = await UserPresentationFactory.CreateCurrentUserResponseModelAsync(user);
|
||||
|
||||
Assert.AreEqual(4, model.FallbackPermissions.Count);
|
||||
Assert.IsTrue(model.FallbackPermissions.ContainsAll(["A", "B", "C", "D"]));
|
||||
|
||||
// When aggregated, we expect one permission per document (we have several granular permissions assigned, for three unique documents).
|
||||
Assert.AreEqual(3, model.Permissions.Count);
|
||||
|
||||
// User has two user groups, one of which provides granular permissions for the root content item.
|
||||
// As such we expect the aggregated permissions to be the union of the specific permissions coming from the user group with them assigned to the document,
|
||||
// and the fallback permissions from the other.
|
||||
var rootContentPermissions = model.Permissions.Cast<DocumentPermissionPresentationModel>().Single(x => x.Document.Id == rootContentKey);
|
||||
Assert.AreEqual(4, rootContentPermissions.Verbs.Count);
|
||||
Assert.IsTrue(rootContentPermissions.Verbs.ContainsAll(["A", "B", "D", "E"]));
|
||||
|
||||
// The sub-page and it's parent have specific granular permissions from one user group.
|
||||
// So we expect the aggregated permissions to include those from the sub-page and the other user's groups fallback permissions.
|
||||
var subPageContentPermissions = model.Permissions.Cast<DocumentPermissionPresentationModel>().Single(x => x.Document.Id == subPageContentKey);
|
||||
Assert.AreEqual(4, subPageContentPermissions.Verbs.Count);
|
||||
Assert.IsTrue(subPageContentPermissions.Verbs.ContainsAll(["A", "B", "D", "F"]));
|
||||
|
||||
// Both user groups provide granular permissions for the second sub-page content item.
|
||||
// Here we expect the aggregated permissions to be the union of the granular permissions on the document from both user groups.
|
||||
var subPage2ContentPermissions = model.Permissions.Cast<DocumentPermissionPresentationModel>().Single(x => x.Document.Id == subPage2ContentKey);
|
||||
Assert.AreEqual(3, subPage2ContentPermissions.Verbs.Count);
|
||||
Assert.IsTrue(subPage2ContentPermissions.Verbs.ContainsAll(["F", "G", "H"]));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Can_Create_Current_User_Response_Model_With_Aggregated_Document_Property_Value_Permissions()
|
||||
{
|
||||
var propertyTypeKey = Guid.NewGuid();
|
||||
var propertyTypeKey2 = Guid.NewGuid();
|
||||
var groupOne = await CreateUserGroup(
|
||||
"Group One",
|
||||
"groupOne",
|
||||
[],
|
||||
[],
|
||||
[
|
||||
new DocumentGranularPermission
|
||||
{
|
||||
Key = Guid.Parse(TextpageKey),
|
||||
Permission = "A",
|
||||
},
|
||||
new DocumentPropertyValueGranularPermission
|
||||
{
|
||||
Key = ContentType.Key,
|
||||
Permission = $"{propertyTypeKey}|C",
|
||||
},
|
||||
new DocumentPropertyValueGranularPermission
|
||||
{
|
||||
Key = ContentType.Key,
|
||||
Permission = $"{propertyTypeKey2}|D",
|
||||
},
|
||||
],
|
||||
Constants.System.Root);
|
||||
var groupTwo = await CreateUserGroup(
|
||||
"Group Two",
|
||||
"groupTwo",
|
||||
[],
|
||||
[],
|
||||
[
|
||||
new DocumentPropertyValueGranularPermission
|
||||
{
|
||||
Key = ContentType.Key,
|
||||
Permission = $"{propertyTypeKey}|B",
|
||||
},
|
||||
],
|
||||
Constants.System.Root);
|
||||
var user = await CreateUser([groupOne.Key, groupTwo.Key]);
|
||||
|
||||
var model = await UserPresentationFactory.CreateCurrentUserResponseModelAsync(user);
|
||||
Assert.AreEqual(3, model.Permissions.Count);
|
||||
|
||||
var documentPermissions = model.Permissions
|
||||
.Where(x => x is DocumentPermissionPresentationModel)
|
||||
.Cast<DocumentPermissionPresentationModel>()
|
||||
.Single(x => x.Document.Id == Guid.Parse(TextpageKey));
|
||||
Assert.AreEqual(1, documentPermissions.Verbs.Count);
|
||||
Assert.IsTrue(documentPermissions.Verbs.ContainsAll(["A"]));
|
||||
|
||||
var documentPropertyValuePermissions = model.Permissions
|
||||
.Where(x => x is DocumentPropertyValuePermissionPresentationModel)
|
||||
.Cast<DocumentPropertyValuePermissionPresentationModel>()
|
||||
.Where(x => x.DocumentType.Id == ContentType.Key);
|
||||
Assert.AreEqual(2, documentPropertyValuePermissions.Count());
|
||||
|
||||
var propertyTypePermission1 = documentPropertyValuePermissions
|
||||
.Single(x => x.PropertyType.Id == propertyTypeKey);
|
||||
Assert.AreEqual(2, propertyTypePermission1.Verbs.Count);
|
||||
Assert.IsTrue(propertyTypePermission1.Verbs.ContainsAll(["B", "C"]));
|
||||
|
||||
var propertyTypePermission2 = documentPropertyValuePermissions
|
||||
.Single(x => x.PropertyType.Id == propertyTypeKey2);
|
||||
Assert.AreEqual(1, propertyTypePermission2.Verbs.Count);
|
||||
Assert.IsTrue(propertyTypePermission2.Verbs.ContainsAll(["D"]));
|
||||
}
|
||||
|
||||
private async Task<IUserGroup> CreateUserGroup(
|
||||
string name,
|
||||
string alias,
|
||||
int[] allowedLanguages,
|
||||
string[] permissions,
|
||||
INodeGranularPermission[] granularPermissions,
|
||||
int startMediaId)
|
||||
{
|
||||
var userGroup = new UserGroupBuilder()
|
||||
.WithName(name)
|
||||
.WithAlias(alias)
|
||||
.WithAllowedLanguages(allowedLanguages)
|
||||
.WithStartMediaId(startMediaId)
|
||||
.WithPermissions(permissions.ToHashSet())
|
||||
.WithGranularPermissions(granularPermissions)
|
||||
.Build();
|
||||
var createUserGroupResult = await UserGroupService.CreateAsync(userGroup, Constants.Security.SuperUserKey);
|
||||
Assert.IsTrue(createUserGroupResult.Success);
|
||||
return userGroup;
|
||||
}
|
||||
|
||||
private async Task<IUser> CreateUser(Guid[] userGroupKeys)
|
||||
{
|
||||
var createUserAttempt = await UserService.CreateAsync(Constants.Security.SuperUserKey, new UserCreateModel
|
||||
{
|
||||
Email = "test@test.com",
|
||||
Name = "Test User",
|
||||
UserName = "test@test.com",
|
||||
UserGroupKeys = userGroupKeys.ToHashSet(),
|
||||
});
|
||||
Assert.IsTrue(createUserAttempt.Success);
|
||||
|
||||
return await UserService.GetAsync(createUserAttempt.Result.CreatedUser.Key);
|
||||
}
|
||||
}
|
||||
@@ -31,11 +31,12 @@ public abstract class ManagementApiTest<T> : UmbracoTestServerTestBase
|
||||
where T : ManagementApiControllerBase
|
||||
{
|
||||
[SetUp]
|
||||
public async Task Setup()
|
||||
public Task Setup()
|
||||
{
|
||||
Client.DefaultRequestHeaders
|
||||
.Accept
|
||||
.Add(new MediaTypeWithQualityHeaderValue(MediaTypeNames.Application.Json));
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
protected override void CustomTestAuthSetup(IServiceCollection services)
|
||||
|
||||
@@ -9,13 +9,13 @@ namespace Umbraco.Cms.Tests.Integration.ManagementApi.Policies;
|
||||
///
|
||||
/// </summary>
|
||||
[TestFixture]
|
||||
public class AllCultureControllerTests : ManagementApiTest<AllCultureController>
|
||||
internal sealed class AllCultureControllerTests : ManagementApiTest<AllCultureController>
|
||||
{
|
||||
protected override Expression<Func<AllCultureController, object>> MethodSelector =>
|
||||
x => x.GetAll(CancellationToken.None, 0, 100);
|
||||
|
||||
[Test]
|
||||
public virtual async Task As_Admin_I_Have_Access()
|
||||
public async Task As_Admin_I_Have_Access()
|
||||
{
|
||||
await AuthenticateClientAsync(Client, "admin@umbraco.com", "1234567890", true);
|
||||
|
||||
@@ -25,7 +25,7 @@ public class AllCultureControllerTests : ManagementApiTest<AllCultureController>
|
||||
}
|
||||
|
||||
[Test]
|
||||
public virtual async Task As_Editor_I_Have_Access()
|
||||
public async Task As_Editor_I_Have_Access()
|
||||
{
|
||||
await AuthenticateClientAsync(Client, "editor@umbraco.com", "1234567890", false);
|
||||
|
||||
@@ -35,7 +35,7 @@ public class AllCultureControllerTests : ManagementApiTest<AllCultureController>
|
||||
}
|
||||
|
||||
[Test]
|
||||
public virtual async Task Unauthourized_when_no_token_is_provided()
|
||||
public async Task Unauthourized_when_no_token_is_provided()
|
||||
{
|
||||
var response = await Client.GetAsync(Url);
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ using Umbraco.Cms.Tests.Common.TestHelpers;
|
||||
namespace Umbraco.Cms.Tests.Integration.ManagementApi.Policies;
|
||||
|
||||
[TestFixture]
|
||||
public class CreateDocumentTests : ManagementApiTest<CreateDocumentController>
|
||||
internal sealed class CreateDocumentTests : ManagementApiTest<CreateDocumentController>
|
||||
{
|
||||
private IUserGroupService UserGroupService => GetRequiredService<IUserGroupService>();
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Actions;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.ContentEditing;
|
||||
using Umbraco.Cms.Core.Models.ContentPublishing;
|
||||
using Umbraco.Cms.Core.Models.Membership;
|
||||
using Umbraco.Cms.Core.Serialization;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
@@ -19,7 +18,7 @@ using Umbraco.Cms.Tests.Common.TestHelpers;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.ManagementApi.Policies;
|
||||
|
||||
public class UpdateDocumentTests : ManagementApiTest<UpdateDocumentController>
|
||||
internal sealed class UpdateDocumentTests : ManagementApiTest<UpdateDocumentController>
|
||||
{
|
||||
private IUserGroupService UserGroupService => GetRequiredService<IUserGroupService>();
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Linq.Expressions;
|
||||
using System.Linq.Expressions;
|
||||
using System.Net;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Api.Management.Controllers.Preview;
|
||||
@@ -6,14 +6,14 @@ using Umbraco.Cms.Core;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.ManagementApi.Preview;
|
||||
|
||||
public class EndPreviewTests : ManagementApiTest<EndPreviewController>
|
||||
internal sealed class EndPreviewTests : ManagementApiTest<EndPreviewController>
|
||||
{
|
||||
protected override Expression<Func<EndPreviewController, object>> MethodSelector =>
|
||||
x => x.End(CancellationToken.None);
|
||||
|
||||
|
||||
[Test]
|
||||
public virtual async Task As_Anonymous_I_Can_End_Preview_Mode()
|
||||
public async Task As_Anonymous_I_Can_End_Preview_Mode()
|
||||
{
|
||||
var response = await Client.DeleteAsync(Url);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Linq.Expressions;
|
||||
using System.Linq.Expressions;
|
||||
using System.Net;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Api.Management.Controllers.Preview;
|
||||
@@ -6,14 +6,14 @@ using Umbraco.Cms.Core;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.ManagementApi.Preview;
|
||||
|
||||
public class EnterPreviewTests : ManagementApiTest<EnterPreviewController>
|
||||
internal sealed class EnterPreviewTests : ManagementApiTest<EnterPreviewController>
|
||||
{
|
||||
protected override Expression<Func<EnterPreviewController, object>> MethodSelector =>
|
||||
x => x.Enter(CancellationToken.None);
|
||||
|
||||
|
||||
[Test]
|
||||
public virtual async Task As_Editor_I_Can_Enter_Preview_Mode()
|
||||
public async Task As_Editor_I_Can_Enter_Preview_Mode()
|
||||
{
|
||||
await AuthenticateClientAsync(Client, "admin@umbraco.com", "1234567890", false);
|
||||
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.ManagementApi.Services;
|
||||
|
||||
public partial class UserStartNodeEntitiesServiceMediaTests
|
||||
{
|
||||
[Test]
|
||||
public async Task RootUserAccessEntities_FirstAndLastRoot_YieldsBoth_AsAllowed()
|
||||
{
|
||||
var contentStartNodeIds = await CreateUserAndGetStartNodeIds(_mediaByName["1"].Id, _mediaByName["5"].Id);
|
||||
|
||||
var roots = UserStartNodeEntitiesService
|
||||
.RootUserAccessEntities(
|
||||
UmbracoObjectTypes.Media,
|
||||
contentStartNodeIds)
|
||||
.ToArray();
|
||||
|
||||
// expected total is 2, because only two items at root ("1" amd "10") are allowed
|
||||
Assert.AreEqual(2, roots.Length);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
// first and last content items are the ones allowed
|
||||
Assert.AreEqual(_mediaByName["1"].Key, roots[0].Entity.Key);
|
||||
Assert.AreEqual(_mediaByName["5"].Key, roots[1].Entity.Key);
|
||||
|
||||
// explicitly verify the entity sort order, both so we know sorting works,
|
||||
// and so we know it's actually the first and last item at root
|
||||
Assert.AreEqual(0, roots[0].Entity.SortOrder);
|
||||
Assert.AreEqual(4, roots[1].Entity.SortOrder);
|
||||
|
||||
// both are allowed (they are the actual start nodes)
|
||||
Assert.IsTrue(roots[0].HasAccess);
|
||||
Assert.IsTrue(roots[1].HasAccess);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task RootUserAccessEntities_ChildrenAsStartNode_YieldsChildRoots_AsNotAllowed()
|
||||
{
|
||||
var contentStartNodeIds = await CreateUserAndGetStartNodeIds(_mediaByName["1-3"].Id, _mediaByName["3-3"].Id, _mediaByName["5-3"].Id);
|
||||
|
||||
var roots = UserStartNodeEntitiesService
|
||||
.RootUserAccessEntities(
|
||||
UmbracoObjectTypes.Media,
|
||||
contentStartNodeIds)
|
||||
.ToArray();
|
||||
|
||||
Assert.AreEqual(3, roots.Length);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
// the three start nodes are the children of the "1", "3" and "5" roots, respectively, so these are expected as roots
|
||||
Assert.AreEqual(_mediaByName["1"].Key, roots[0].Entity.Key);
|
||||
Assert.AreEqual(_mediaByName["3"].Key, roots[1].Entity.Key);
|
||||
Assert.AreEqual(_mediaByName["5"].Key, roots[2].Entity.Key);
|
||||
|
||||
// all are disallowed - only the children (the actual start nodes) are allowed
|
||||
Assert.IsTrue(roots.All(r => r.HasAccess is false));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task RootUserAccessEntities_GrandchildrenAsStartNode_YieldsGrandchildRoots_AsNotAllowed()
|
||||
{
|
||||
var contentStartNodeIds = await CreateUserAndGetStartNodeIds(_mediaByName["1-2-3"].Id, _mediaByName["2-3-4"].Id, _mediaByName["3-4-5"].Id);
|
||||
|
||||
var roots = UserStartNodeEntitiesService
|
||||
.RootUserAccessEntities(
|
||||
UmbracoObjectTypes.Media,
|
||||
contentStartNodeIds)
|
||||
.ToArray();
|
||||
|
||||
Assert.AreEqual(3, roots.Length);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
// the three start nodes are the grandchildren of the "1", "2" and "3" roots, respectively, so these are expected as roots
|
||||
Assert.AreEqual(_mediaByName["1"].Key, roots[0].Entity.Key);
|
||||
Assert.AreEqual(_mediaByName["2"].Key, roots[1].Entity.Key);
|
||||
Assert.AreEqual(_mediaByName["3"].Key, roots[2].Entity.Key);
|
||||
|
||||
// all are disallowed - only the grandchildren (the actual start nodes) are allowed
|
||||
Assert.IsTrue(roots.All(r => r.HasAccess is false));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,336 @@
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.ManagementApi.Services;
|
||||
|
||||
public partial class UserStartNodeEntitiesServiceMediaTests
|
||||
{
|
||||
[Test]
|
||||
public async Task ChildUserAccessEntities_FirstAndLastChildOfRoot_YieldsBothInFirstPage_AsAllowed()
|
||||
{
|
||||
var mediaStartNodePaths = await CreateUserAndGetStartNodePaths(_mediaByName["1-1"].Id, _mediaByName["1-10"].Id);
|
||||
|
||||
var children = UserStartNodeEntitiesService
|
||||
.ChildUserAccessEntities(
|
||||
UmbracoObjectTypes.Media,
|
||||
mediaStartNodePaths,
|
||||
_mediaByName["1"].Key,
|
||||
0,
|
||||
3,
|
||||
BySortOrder,
|
||||
out var totalItems)
|
||||
.ToArray();
|
||||
|
||||
// expected total is 2, because only two items under "1" are allowed (note the page size is 3 for good measure)
|
||||
Assert.AreEqual(2, totalItems);
|
||||
Assert.AreEqual(2, children.Length);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
// first and last media items are the ones allowed
|
||||
Assert.AreEqual(_mediaByName["1-1"].Key, children[0].Entity.Key);
|
||||
Assert.AreEqual(_mediaByName["1-10"].Key, children[1].Entity.Key);
|
||||
|
||||
// explicitly verify the entity sort order, both so we know sorting works,
|
||||
// and so we know it's actually the first and last item below "1"
|
||||
Assert.AreEqual(0, children[0].Entity.SortOrder);
|
||||
Assert.AreEqual(9, children[1].Entity.SortOrder);
|
||||
|
||||
// both are allowed (they are the actual start nodes)
|
||||
Assert.IsTrue(children[0].HasAccess);
|
||||
Assert.IsTrue(children[1].HasAccess);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ChildUserAccessEntities_InAndOutOfScope_YieldsOnlyChildrenInScope()
|
||||
{
|
||||
var mediaStartNodePaths = await CreateUserAndGetStartNodePaths(_mediaByName["1-5"].Id, _mediaByName["2-10"].Id);
|
||||
Assert.AreEqual(2, mediaStartNodePaths.Length);
|
||||
|
||||
var children = UserStartNodeEntitiesService
|
||||
.ChildUserAccessEntities(
|
||||
UmbracoObjectTypes.Media,
|
||||
mediaStartNodePaths,
|
||||
_mediaByName["2"].Key,
|
||||
0,
|
||||
10,
|
||||
BySortOrder,
|
||||
out var totalItems)
|
||||
.ToArray();
|
||||
|
||||
Assert.AreEqual(1, totalItems);
|
||||
Assert.AreEqual(1, children.Length);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
// only the "2-10" media item is returned, as "1-5" is out of scope
|
||||
Assert.AreEqual(_mediaByName["2-10"].Key, children[0].Entity.Key);
|
||||
Assert.IsTrue(children[0].HasAccess);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ChildUserAccessEntities_OutOfScope_YieldsNothing()
|
||||
{
|
||||
var mediaStartNodePaths = await CreateUserAndGetStartNodePaths(_mediaByName["1-5"].Id, _mediaByName["2-10"].Id);
|
||||
Assert.AreEqual(2, mediaStartNodePaths.Length);
|
||||
|
||||
var children = UserStartNodeEntitiesService
|
||||
.ChildUserAccessEntities(
|
||||
UmbracoObjectTypes.Media,
|
||||
mediaStartNodePaths,
|
||||
_mediaByName["3"].Key,
|
||||
0,
|
||||
10,
|
||||
BySortOrder,
|
||||
out var totalItems)
|
||||
.ToArray();
|
||||
|
||||
Assert.AreEqual(0, totalItems);
|
||||
Assert.AreEqual(0, children.Length);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ChildUserAccessEntities_SpanningMultipleResultPages_CanPaginate()
|
||||
{
|
||||
var mediaStartNodePaths = await CreateUserAndGetStartNodePaths(
|
||||
_mediaByName["1-1"].Id,
|
||||
_mediaByName["1-3"].Id,
|
||||
_mediaByName["1-5"].Id,
|
||||
_mediaByName["1-7"].Id,
|
||||
_mediaByName["1-9"].Id);
|
||||
|
||||
var children = UserStartNodeEntitiesService
|
||||
.ChildUserAccessEntities(
|
||||
UmbracoObjectTypes.Media,
|
||||
mediaStartNodePaths,
|
||||
_mediaByName["1"].Key,
|
||||
0,
|
||||
2,
|
||||
BySortOrder,
|
||||
out var totalItems)
|
||||
.ToArray();
|
||||
|
||||
Assert.AreEqual(5, totalItems);
|
||||
// page size is 2
|
||||
Assert.AreEqual(2, children.Length);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual(_mediaByName["1-1"].Key, children[0].Entity.Key);
|
||||
Assert.AreEqual(_mediaByName["1-3"].Key, children[1].Entity.Key);
|
||||
Assert.IsTrue(children[0].HasAccess);
|
||||
Assert.IsTrue(children[1].HasAccess);
|
||||
});
|
||||
|
||||
// next result page
|
||||
children = UserStartNodeEntitiesService
|
||||
.ChildUserAccessEntities(
|
||||
UmbracoObjectTypes.Media,
|
||||
mediaStartNodePaths,
|
||||
_mediaByName["1"].Key,
|
||||
2,
|
||||
2,
|
||||
BySortOrder,
|
||||
out totalItems)
|
||||
.ToArray();
|
||||
|
||||
Assert.AreEqual(5, totalItems);
|
||||
// page size is still 2
|
||||
Assert.AreEqual(2, children.Length);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual(_mediaByName["1-5"].Key, children[0].Entity.Key);
|
||||
Assert.AreEqual(_mediaByName["1-7"].Key, children[1].Entity.Key);
|
||||
Assert.IsTrue(children[0].HasAccess);
|
||||
Assert.IsTrue(children[1].HasAccess);
|
||||
});
|
||||
|
||||
// next result page
|
||||
children = UserStartNodeEntitiesService
|
||||
.ChildUserAccessEntities(
|
||||
UmbracoObjectTypes.Media,
|
||||
mediaStartNodePaths,
|
||||
_mediaByName["1"].Key,
|
||||
4,
|
||||
2,
|
||||
BySortOrder,
|
||||
out totalItems)
|
||||
.ToArray();
|
||||
|
||||
Assert.AreEqual(5, totalItems);
|
||||
// page size is still 2, but this is the last result page
|
||||
Assert.AreEqual(1, children.Length);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual(_mediaByName["1-9"].Key, children[0].Entity.Key);
|
||||
Assert.IsTrue(children[0].HasAccess);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ChildUserAccessEntities_ChildrenAsStartNode_YieldsAllGrandchildren_AsAllowed()
|
||||
{
|
||||
var mediaStartNodePaths = await CreateUserAndGetStartNodePaths(_mediaByName["3-3"].Id);
|
||||
|
||||
var children = UserStartNodeEntitiesService
|
||||
.ChildUserAccessEntities(
|
||||
UmbracoObjectTypes.Media,
|
||||
mediaStartNodePaths,
|
||||
_mediaByName["3-3"].Key,
|
||||
0,
|
||||
100,
|
||||
BySortOrder,
|
||||
out var totalItems)
|
||||
.ToArray();
|
||||
|
||||
Assert.AreEqual(5, totalItems);
|
||||
Assert.AreEqual(5, children.Length);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
// all children of "3-3" should be allowed because "3-3" is a start node
|
||||
foreach (var childNumber in Enumerable.Range(1, 5))
|
||||
{
|
||||
var child = children[childNumber - 1];
|
||||
Assert.AreEqual(_mediaByName[$"3-3-{childNumber}"].Key, child.Entity.Key);
|
||||
Assert.IsTrue(child.HasAccess);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ChildUserAccessEntities_GrandchildrenAsStartNode_YieldsGrandchildren_AsAllowed()
|
||||
{
|
||||
var mediaStartNodePaths = await CreateUserAndGetStartNodePaths(_mediaByName["3-3-3"].Id, _mediaByName["3-3-4"].Id);
|
||||
|
||||
var children = UserStartNodeEntitiesService
|
||||
.ChildUserAccessEntities(
|
||||
UmbracoObjectTypes.Media,
|
||||
mediaStartNodePaths,
|
||||
_mediaByName["3-3"].Key,
|
||||
0,
|
||||
3,
|
||||
BySortOrder,
|
||||
out var totalItems)
|
||||
.ToArray();
|
||||
|
||||
Assert.AreEqual(2, totalItems);
|
||||
Assert.AreEqual(2, children.Length);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
// the two items are the children of "3-3" - that is, the actual start nodes
|
||||
Assert.AreEqual(_mediaByName["3-3-3"].Key, children[0].Entity.Key);
|
||||
Assert.AreEqual(_mediaByName["3-3-4"].Key, children[1].Entity.Key);
|
||||
|
||||
// both are allowed (they are the actual start nodes)
|
||||
Assert.IsTrue(children[0].HasAccess);
|
||||
Assert.IsTrue(children[1].HasAccess);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ChildUserAccessEntities_GrandchildrenAsStartNode_YieldsChildren_AsNotAllowed()
|
||||
{
|
||||
var mediaStartNodePaths = await CreateUserAndGetStartNodePaths(_mediaByName["3-3-3"].Id, _mediaByName["3-5-3"].Id);
|
||||
|
||||
var children = UserStartNodeEntitiesService
|
||||
.ChildUserAccessEntities(
|
||||
UmbracoObjectTypes.Media,
|
||||
mediaStartNodePaths,
|
||||
_mediaByName["3"].Key,
|
||||
0,
|
||||
3,
|
||||
BySortOrder,
|
||||
out var totalItems)
|
||||
.ToArray();
|
||||
|
||||
Assert.AreEqual(2, totalItems);
|
||||
Assert.AreEqual(2, children.Length);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
// the two items are the children of "3" - that is, the parents of the actual start nodes
|
||||
Assert.AreEqual(_mediaByName["3-3"].Key, children[0].Entity.Key);
|
||||
Assert.AreEqual(_mediaByName["3-5"].Key, children[1].Entity.Key);
|
||||
|
||||
// both are disallowed - only the two children (the actual start nodes) are allowed
|
||||
Assert.IsFalse(children[0].HasAccess);
|
||||
Assert.IsFalse(children[1].HasAccess);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ChildUserAccessEntities_ChildAndGrandchildAsStartNode_AllowsOnlyGrandchild()
|
||||
{
|
||||
// NOTE: this test proves that start node paths are *not* additive when structural inheritance is in play.
|
||||
// if one has a start node that is a descendant to another start node, the descendant start node "wins"
|
||||
// and the ancestor start node is ignored. this differs somewhat from the norm; we normally consider
|
||||
// permissions additive (which in this case would mean ignoring the descendant rather than the ancestor).
|
||||
|
||||
var mediaStartNodePaths = await CreateUserAndGetStartNodePaths(_mediaByName["3-3"].Id, _mediaByName["3-3-1"].Id, _mediaByName["3-3-5"].Id);
|
||||
Assert.AreEqual(2, mediaStartNodePaths.Length);
|
||||
|
||||
var children = UserStartNodeEntitiesService
|
||||
.ChildUserAccessEntities(
|
||||
UmbracoObjectTypes.Media,
|
||||
mediaStartNodePaths,
|
||||
_mediaByName["3"].Key,
|
||||
0,
|
||||
10,
|
||||
BySortOrder,
|
||||
out var totalItems)
|
||||
.ToArray();
|
||||
Assert.AreEqual(1, totalItems);
|
||||
Assert.AreEqual(1, children.Length);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual(_mediaByName["3-3"].Key, children[0].Entity.Key);
|
||||
Assert.IsFalse(children[0].HasAccess);
|
||||
});
|
||||
|
||||
children = UserStartNodeEntitiesService
|
||||
.ChildUserAccessEntities(
|
||||
UmbracoObjectTypes.Media,
|
||||
mediaStartNodePaths,
|
||||
_mediaByName["3-3"].Key,
|
||||
0,
|
||||
10,
|
||||
BySortOrder,
|
||||
out totalItems)
|
||||
.ToArray();
|
||||
|
||||
Assert.AreEqual(2, totalItems);
|
||||
Assert.AreEqual(2, children.Length);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
// the two items are the children of "3-3" - that is, the actual start nodes
|
||||
Assert.AreEqual(_mediaByName["3-3-1"].Key, children[0].Entity.Key);
|
||||
Assert.AreEqual(_mediaByName["3-3-5"].Key, children[1].Entity.Key);
|
||||
|
||||
Assert.IsTrue(children[0].HasAccess);
|
||||
Assert.IsTrue(children[1].HasAccess);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ChildUserAccessEntities_ReverseStartNodeOrder_DoesNotAffectResultOrder()
|
||||
{
|
||||
var mediaStartNodePaths = await CreateUserAndGetStartNodePaths(_mediaByName["3-3"].Id, _mediaByName["3-2"].Id, _mediaByName["3-1"].Id);
|
||||
|
||||
var children = UserStartNodeEntitiesService
|
||||
.ChildUserAccessEntities(
|
||||
UmbracoObjectTypes.Media,
|
||||
mediaStartNodePaths,
|
||||
_mediaByName["3"].Key,
|
||||
0,
|
||||
10,
|
||||
BySortOrder,
|
||||
out var totalItems)
|
||||
.ToArray();
|
||||
Assert.AreEqual(3, totalItems);
|
||||
Assert.AreEqual(3, children.Length);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual(_mediaByName["3-1"].Key, children[0].Entity.Key);
|
||||
Assert.AreEqual(_mediaByName["3-2"].Key, children[1].Entity.Key);
|
||||
Assert.AreEqual(_mediaByName["3-3"].Key, children[2].Entity.Key);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Api.Management.Services.Entities;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Cache;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.Membership;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Tests.Common.Builders;
|
||||
using Umbraco.Cms.Tests.Common.Builders.Extensions;
|
||||
using Umbraco.Cms.Tests.Common.Testing;
|
||||
using Umbraco.Cms.Tests.Integration.Testing;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.ManagementApi.Services;
|
||||
|
||||
[TestFixture]
|
||||
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerFixture)]
|
||||
public partial class UserStartNodeEntitiesServiceMediaTests : UmbracoIntegrationTest
|
||||
{
|
||||
private Dictionary<string, IMedia> _mediaByName = new ();
|
||||
private IUserGroup _userGroup;
|
||||
|
||||
private IMediaService MediaService => GetRequiredService<IMediaService>();
|
||||
|
||||
private IMediaTypeService MediaTypeService => GetRequiredService<IMediaTypeService>();
|
||||
|
||||
private IUserGroupService UserGroupService => GetRequiredService<IUserGroupService>();
|
||||
|
||||
private IUserService UserService => GetRequiredService<IUserService>();
|
||||
|
||||
private IEntityService EntityService => GetRequiredService<IEntityService>();
|
||||
|
||||
private IUserStartNodeEntitiesService UserStartNodeEntitiesService => GetRequiredService<IUserStartNodeEntitiesService>();
|
||||
|
||||
protected readonly Ordering BySortOrder = Ordering.By("sortOrder");
|
||||
|
||||
protected override void ConfigureTestServices(IServiceCollection services)
|
||||
{
|
||||
base.ConfigureTestServices(services);
|
||||
services.AddTransient<IUserStartNodeEntitiesService, UserStartNodeEntitiesService>();
|
||||
}
|
||||
|
||||
[SetUp]
|
||||
public async Task SetUpTestAsync()
|
||||
{
|
||||
if (_mediaByName.Any())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var mediaType = new MediaTypeBuilder()
|
||||
.WithAlias("theMediaType")
|
||||
.Build();
|
||||
mediaType.AllowedAsRoot = true;
|
||||
await MediaTypeService.CreateAsync(mediaType, Constants.Security.SuperUserKey);
|
||||
mediaType.AllowedContentTypes = [new() { Alias = mediaType.Alias, Key = mediaType.Key }];
|
||||
await MediaTypeService.UpdateAsync(mediaType, Constants.Security.SuperUserKey);
|
||||
|
||||
foreach (var rootNumber in Enumerable.Range(1, 5))
|
||||
{
|
||||
var root = new MediaBuilder()
|
||||
.WithMediaType(mediaType)
|
||||
.WithName($"{rootNumber}")
|
||||
.Build();
|
||||
MediaService.Save(root);
|
||||
_mediaByName[root.Name!] = root;
|
||||
|
||||
foreach (var childNumber in Enumerable.Range(1, 10))
|
||||
{
|
||||
var child = new MediaBuilder()
|
||||
.WithMediaType(mediaType)
|
||||
.WithName($"{rootNumber}-{childNumber}")
|
||||
.Build();
|
||||
child.SetParent(root);
|
||||
MediaService.Save(child);
|
||||
_mediaByName[child.Name!] = child;
|
||||
|
||||
foreach (var grandChildNumber in Enumerable.Range(1, 5))
|
||||
{
|
||||
var grandchild = new MediaBuilder()
|
||||
.WithMediaType(mediaType)
|
||||
.WithName($"{rootNumber}-{childNumber}-{grandChildNumber}")
|
||||
.Build();
|
||||
grandchild.SetParent(child);
|
||||
MediaService.Save(grandchild);
|
||||
_mediaByName[grandchild.Name!] = grandchild;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_userGroup = new UserGroupBuilder()
|
||||
.WithAlias("theGroup")
|
||||
.WithAllowedSections(["media"])
|
||||
.Build();
|
||||
_userGroup.StartMediaId = null;
|
||||
await UserGroupService.CreateAsync(_userGroup, Constants.Security.SuperUserKey);
|
||||
}
|
||||
|
||||
private async Task<string[]> CreateUserAndGetStartNodePaths(params int[] startNodeIds)
|
||||
{
|
||||
var user = await CreateUser(startNodeIds);
|
||||
|
||||
var mediaStartNodePaths = user.GetMediaStartNodePaths(EntityService, AppCaches.NoCache);
|
||||
Assert.IsNotNull(mediaStartNodePaths);
|
||||
|
||||
return mediaStartNodePaths;
|
||||
}
|
||||
|
||||
private async Task<int[]> CreateUserAndGetStartNodeIds(params int[] startNodeIds)
|
||||
{
|
||||
var user = await CreateUser(startNodeIds);
|
||||
|
||||
var mediaStartNodeIds = user.CalculateMediaStartNodeIds(EntityService, AppCaches.NoCache);
|
||||
Assert.IsNotNull(mediaStartNodeIds);
|
||||
|
||||
return mediaStartNodeIds;
|
||||
}
|
||||
|
||||
private async Task<User> CreateUser(int[] startNodeIds)
|
||||
{
|
||||
var user = new UserBuilder()
|
||||
.WithName(Guid.NewGuid().ToString("N"))
|
||||
.WithStartMediaIds(startNodeIds)
|
||||
.Build();
|
||||
UserService.Save(user);
|
||||
|
||||
var attempt = await UserGroupService.AddUsersToUserGroupAsync(
|
||||
new UsersToUserGroupManipulationModel(_userGroup.Key, [user.Key]),
|
||||
Constants.Security.SuperUserKey);
|
||||
|
||||
Assert.IsTrue(attempt.Success);
|
||||
return user;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,336 @@
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.ManagementApi.Services;
|
||||
|
||||
public partial class UserStartNodeEntitiesServiceTests
|
||||
{
|
||||
[Test]
|
||||
public async Task ChildUserAccessEntities_FirstAndLastChildOfRoot_YieldsBothInFirstPage_AsAllowed()
|
||||
{
|
||||
var contentStartNodePaths = await CreateUserAndGetStartNodePaths(_contentByName["1-1"].Id, _contentByName["1-10"].Id);
|
||||
|
||||
var children = UserStartNodeEntitiesService
|
||||
.ChildUserAccessEntities(
|
||||
UmbracoObjectTypes.Document,
|
||||
contentStartNodePaths,
|
||||
_contentByName["1"].Key,
|
||||
0,
|
||||
3,
|
||||
BySortOrder,
|
||||
out var totalItems)
|
||||
.ToArray();
|
||||
|
||||
// expected total is 2, because only two items under "1" are allowed (note the page size is 3 for good measure)
|
||||
Assert.AreEqual(2, totalItems);
|
||||
Assert.AreEqual(2, children.Length);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
// first and last content items are the ones allowed
|
||||
Assert.AreEqual(_contentByName["1-1"].Key, children[0].Entity.Key);
|
||||
Assert.AreEqual(_contentByName["1-10"].Key, children[1].Entity.Key);
|
||||
|
||||
// explicitly verify the entity sort order, both so we know sorting works,
|
||||
// and so we know it's actually the first and last item below "1"
|
||||
Assert.AreEqual(0, children[0].Entity.SortOrder);
|
||||
Assert.AreEqual(9, children[1].Entity.SortOrder);
|
||||
|
||||
// both are allowed (they are the actual start nodes)
|
||||
Assert.IsTrue(children[0].HasAccess);
|
||||
Assert.IsTrue(children[1].HasAccess);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ChildUserAccessEntities_InAndOutOfScope_YieldsOnlyChildrenInScope()
|
||||
{
|
||||
var contentStartNodePaths = await CreateUserAndGetStartNodePaths(_contentByName["1-5"].Id, _contentByName["2-10"].Id);
|
||||
Assert.AreEqual(2, contentStartNodePaths.Length);
|
||||
|
||||
var children = UserStartNodeEntitiesService
|
||||
.ChildUserAccessEntities(
|
||||
UmbracoObjectTypes.Document,
|
||||
contentStartNodePaths,
|
||||
_contentByName["2"].Key,
|
||||
0,
|
||||
10,
|
||||
BySortOrder,
|
||||
out var totalItems)
|
||||
.ToArray();
|
||||
|
||||
Assert.AreEqual(1, totalItems);
|
||||
Assert.AreEqual(1, children.Length);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
// only the "2-10" content item is returned, as "1-5" is out of scope
|
||||
Assert.AreEqual(_contentByName["2-10"].Key, children[0].Entity.Key);
|
||||
Assert.IsTrue(children[0].HasAccess);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ChildUserAccessEntities_OutOfScope_YieldsNothing()
|
||||
{
|
||||
var contentStartNodePaths = await CreateUserAndGetStartNodePaths(_contentByName["1-5"].Id, _contentByName["2-10"].Id);
|
||||
Assert.AreEqual(2, contentStartNodePaths.Length);
|
||||
|
||||
var children = UserStartNodeEntitiesService
|
||||
.ChildUserAccessEntities(
|
||||
UmbracoObjectTypes.Document,
|
||||
contentStartNodePaths,
|
||||
_contentByName["3"].Key,
|
||||
0,
|
||||
10,
|
||||
BySortOrder,
|
||||
out var totalItems)
|
||||
.ToArray();
|
||||
|
||||
Assert.AreEqual(0, totalItems);
|
||||
Assert.AreEqual(0, children.Length);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ChildUserAccessEntities_SpanningMultipleResultPages_CanPaginate()
|
||||
{
|
||||
var contentStartNodePaths = await CreateUserAndGetStartNodePaths(
|
||||
_contentByName["1-1"].Id,
|
||||
_contentByName["1-3"].Id,
|
||||
_contentByName["1-5"].Id,
|
||||
_contentByName["1-7"].Id,
|
||||
_contentByName["1-9"].Id);
|
||||
|
||||
var children = UserStartNodeEntitiesService
|
||||
.ChildUserAccessEntities(
|
||||
UmbracoObjectTypes.Document,
|
||||
contentStartNodePaths,
|
||||
_contentByName["1"].Key,
|
||||
0,
|
||||
2,
|
||||
BySortOrder,
|
||||
out var totalItems)
|
||||
.ToArray();
|
||||
|
||||
Assert.AreEqual(5, totalItems);
|
||||
// page size is 2
|
||||
Assert.AreEqual(2, children.Length);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual(_contentByName["1-1"].Key, children[0].Entity.Key);
|
||||
Assert.AreEqual(_contentByName["1-3"].Key, children[1].Entity.Key);
|
||||
Assert.IsTrue(children[0].HasAccess);
|
||||
Assert.IsTrue(children[1].HasAccess);
|
||||
});
|
||||
|
||||
// next result page
|
||||
children = UserStartNodeEntitiesService
|
||||
.ChildUserAccessEntities(
|
||||
UmbracoObjectTypes.Document,
|
||||
contentStartNodePaths,
|
||||
_contentByName["1"].Key,
|
||||
2,
|
||||
2,
|
||||
BySortOrder,
|
||||
out totalItems)
|
||||
.ToArray();
|
||||
|
||||
Assert.AreEqual(5, totalItems);
|
||||
// page size is still 2
|
||||
Assert.AreEqual(2, children.Length);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual(_contentByName["1-5"].Key, children[0].Entity.Key);
|
||||
Assert.AreEqual(_contentByName["1-7"].Key, children[1].Entity.Key);
|
||||
Assert.IsTrue(children[0].HasAccess);
|
||||
Assert.IsTrue(children[1].HasAccess);
|
||||
});
|
||||
|
||||
// next result page
|
||||
children = UserStartNodeEntitiesService
|
||||
.ChildUserAccessEntities(
|
||||
UmbracoObjectTypes.Document,
|
||||
contentStartNodePaths,
|
||||
_contentByName["1"].Key,
|
||||
4,
|
||||
2,
|
||||
BySortOrder,
|
||||
out totalItems)
|
||||
.ToArray();
|
||||
|
||||
Assert.AreEqual(5, totalItems);
|
||||
// page size is still 2, but this is the last result page
|
||||
Assert.AreEqual(1, children.Length);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual(_contentByName["1-9"].Key, children[0].Entity.Key);
|
||||
Assert.IsTrue(children[0].HasAccess);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ChildUserAccessEntities_ChildrenAsStartNode_YieldsAllGrandchildren_AsAllowed()
|
||||
{
|
||||
var contentStartNodePaths = await CreateUserAndGetStartNodePaths(_contentByName["3-3"].Id);
|
||||
|
||||
var children = UserStartNodeEntitiesService
|
||||
.ChildUserAccessEntities(
|
||||
UmbracoObjectTypes.Document,
|
||||
contentStartNodePaths,
|
||||
_contentByName["3-3"].Key,
|
||||
0,
|
||||
100,
|
||||
BySortOrder,
|
||||
out var totalItems)
|
||||
.ToArray();
|
||||
|
||||
Assert.AreEqual(5, totalItems);
|
||||
Assert.AreEqual(5, children.Length);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
// all children of "3-3" should be allowed because "3-3" is a start node
|
||||
foreach (var childNumber in Enumerable.Range(1, 5))
|
||||
{
|
||||
var child = children[childNumber - 1];
|
||||
Assert.AreEqual(_contentByName[$"3-3-{childNumber}"].Key, child.Entity.Key);
|
||||
Assert.IsTrue(child.HasAccess);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ChildUserAccessEntities_GrandchildrenAsStartNode_YieldsGrandchildren_AsAllowed()
|
||||
{
|
||||
var contentStartNodePaths = await CreateUserAndGetStartNodePaths(_contentByName["3-3-3"].Id, _contentByName["3-3-4"].Id);
|
||||
|
||||
var children = UserStartNodeEntitiesService
|
||||
.ChildUserAccessEntities(
|
||||
UmbracoObjectTypes.Document,
|
||||
contentStartNodePaths,
|
||||
_contentByName["3-3"].Key,
|
||||
0,
|
||||
3,
|
||||
BySortOrder,
|
||||
out var totalItems)
|
||||
.ToArray();
|
||||
|
||||
Assert.AreEqual(2, totalItems);
|
||||
Assert.AreEqual(2, children.Length);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
// the two items are the children of "3-3" - that is, the actual start nodes
|
||||
Assert.AreEqual(_contentByName["3-3-3"].Key, children[0].Entity.Key);
|
||||
Assert.AreEqual(_contentByName["3-3-4"].Key, children[1].Entity.Key);
|
||||
|
||||
// both are allowed (they are the actual start nodes)
|
||||
Assert.IsTrue(children[0].HasAccess);
|
||||
Assert.IsTrue(children[1].HasAccess);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ChildUserAccessEntities_GrandchildrenAsStartNode_YieldsChildren_AsNotAllowed()
|
||||
{
|
||||
var contentStartNodePaths = await CreateUserAndGetStartNodePaths(_contentByName["3-3-3"].Id, _contentByName["3-5-3"].Id);
|
||||
|
||||
var children = UserStartNodeEntitiesService
|
||||
.ChildUserAccessEntities(
|
||||
UmbracoObjectTypes.Document,
|
||||
contentStartNodePaths,
|
||||
_contentByName["3"].Key,
|
||||
0,
|
||||
3,
|
||||
BySortOrder,
|
||||
out var totalItems)
|
||||
.ToArray();
|
||||
|
||||
Assert.AreEqual(2, totalItems);
|
||||
Assert.AreEqual(2, children.Length);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
// the two items are the children of "3" - that is, the parents of the actual start nodes
|
||||
Assert.AreEqual(_contentByName["3-3"].Key, children[0].Entity.Key);
|
||||
Assert.AreEqual(_contentByName["3-5"].Key, children[1].Entity.Key);
|
||||
|
||||
// both are disallowed - only the two children (the actual start nodes) are allowed
|
||||
Assert.IsFalse(children[0].HasAccess);
|
||||
Assert.IsFalse(children[1].HasAccess);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ChildUserAccessEntities_ChildAndGrandchildAsStartNode_AllowsOnlyGrandchild()
|
||||
{
|
||||
// NOTE: this test proves that start node paths are *not* additive when structural inheritance is in play.
|
||||
// if one has a start node that is a descendant to another start node, the descendant start node "wins"
|
||||
// and the ancestor start node is ignored. this differs somewhat from the norm; we normally consider
|
||||
// permissions additive (which in this case would mean ignoring the descendant rather than the ancestor).
|
||||
|
||||
var contentStartNodePaths = await CreateUserAndGetStartNodePaths(_contentByName["3-3"].Id, _contentByName["3-3-1"].Id, _contentByName["3-3-5"].Id);
|
||||
Assert.AreEqual(2, contentStartNodePaths.Length);
|
||||
|
||||
var children = UserStartNodeEntitiesService
|
||||
.ChildUserAccessEntities(
|
||||
UmbracoObjectTypes.Document,
|
||||
contentStartNodePaths,
|
||||
_contentByName["3"].Key,
|
||||
0,
|
||||
10,
|
||||
BySortOrder,
|
||||
out var totalItems)
|
||||
.ToArray();
|
||||
Assert.AreEqual(1, totalItems);
|
||||
Assert.AreEqual(1, children.Length);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual(_contentByName["3-3"].Key, children[0].Entity.Key);
|
||||
Assert.IsFalse(children[0].HasAccess);
|
||||
});
|
||||
|
||||
children = UserStartNodeEntitiesService
|
||||
.ChildUserAccessEntities(
|
||||
UmbracoObjectTypes.Document,
|
||||
contentStartNodePaths,
|
||||
_contentByName["3-3"].Key,
|
||||
0,
|
||||
10,
|
||||
BySortOrder,
|
||||
out totalItems)
|
||||
.ToArray();
|
||||
|
||||
Assert.AreEqual(2, totalItems);
|
||||
Assert.AreEqual(2, children.Length);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
// the two items are the children of "3-3" - that is, the actual start nodes
|
||||
Assert.AreEqual(_contentByName["3-3-1"].Key, children[0].Entity.Key);
|
||||
Assert.AreEqual(_contentByName["3-3-5"].Key, children[1].Entity.Key);
|
||||
|
||||
Assert.IsTrue(children[0].HasAccess);
|
||||
Assert.IsTrue(children[1].HasAccess);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task ChildUserAccessEntities_ReverseStartNodeOrder_DoesNotAffectResultOrder()
|
||||
{
|
||||
var contentStartNodePaths = await CreateUserAndGetStartNodePaths(_contentByName["3-3"].Id, _contentByName["3-2"].Id, _contentByName["3-1"].Id);
|
||||
|
||||
var children = UserStartNodeEntitiesService
|
||||
.ChildUserAccessEntities(
|
||||
UmbracoObjectTypes.Document,
|
||||
contentStartNodePaths,
|
||||
_contentByName["3"].Key,
|
||||
0,
|
||||
10,
|
||||
BySortOrder,
|
||||
out var totalItems)
|
||||
.ToArray();
|
||||
Assert.AreEqual(3, totalItems);
|
||||
Assert.AreEqual(3, children.Length);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual(_contentByName["3-1"].Key, children[0].Entity.Key);
|
||||
Assert.AreEqual(_contentByName["3-2"].Key, children[1].Entity.Key);
|
||||
Assert.AreEqual(_contentByName["3-3"].Key, children[2].Entity.Key);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.ManagementApi.Services;
|
||||
|
||||
public partial class UserStartNodeEntitiesServiceTests
|
||||
{
|
||||
[Test]
|
||||
public async Task RootUserAccessEntities_FirstAndLastRoot_YieldsBoth_AsAllowed()
|
||||
{
|
||||
var contentStartNodeIds = await CreateUserAndGetStartNodeIds(_contentByName["1"].Id, _contentByName["5"].Id);
|
||||
|
||||
var roots = UserStartNodeEntitiesService
|
||||
.RootUserAccessEntities(
|
||||
UmbracoObjectTypes.Document,
|
||||
contentStartNodeIds)
|
||||
.ToArray();
|
||||
|
||||
// expected total is 2, because only two items at root ("1" amd "10") are allowed
|
||||
Assert.AreEqual(2, roots.Length);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
// first and last content items are the ones allowed
|
||||
Assert.AreEqual(_contentByName["1"].Key, roots[0].Entity.Key);
|
||||
Assert.AreEqual(_contentByName["5"].Key, roots[1].Entity.Key);
|
||||
|
||||
// explicitly verify the entity sort order, both so we know sorting works,
|
||||
// and so we know it's actually the first and last item at root
|
||||
Assert.AreEqual(0, roots[0].Entity.SortOrder);
|
||||
Assert.AreEqual(4, roots[1].Entity.SortOrder);
|
||||
|
||||
// both are allowed (they are the actual start nodes)
|
||||
Assert.IsTrue(roots[0].HasAccess);
|
||||
Assert.IsTrue(roots[1].HasAccess);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task RootUserAccessEntities_ChildrenAsStartNode_YieldsChildRoots_AsNotAllowed()
|
||||
{
|
||||
var contentStartNodeIds = await CreateUserAndGetStartNodeIds(_contentByName["1-3"].Id, _contentByName["3-3"].Id, _contentByName["5-3"].Id);
|
||||
|
||||
var roots = UserStartNodeEntitiesService
|
||||
.RootUserAccessEntities(
|
||||
UmbracoObjectTypes.Document,
|
||||
contentStartNodeIds)
|
||||
.ToArray();
|
||||
|
||||
Assert.AreEqual(3, roots.Length);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
// the three start nodes are the children of the "1", "3" and "5" roots, respectively, so these are expected as roots
|
||||
Assert.AreEqual(_contentByName["1"].Key, roots[0].Entity.Key);
|
||||
Assert.AreEqual(_contentByName["3"].Key, roots[1].Entity.Key);
|
||||
Assert.AreEqual(_contentByName["5"].Key, roots[2].Entity.Key);
|
||||
|
||||
// all are disallowed - only the children (the actual start nodes) are allowed
|
||||
Assert.IsTrue(roots.All(r => r.HasAccess is false));
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task RootUserAccessEntities_GrandchildrenAsStartNode_YieldsGrandchildRoots_AsNotAllowed()
|
||||
{
|
||||
var contentStartNodeIds = await CreateUserAndGetStartNodeIds(_contentByName["1-2-3"].Id, _contentByName["2-3-4"].Id, _contentByName["3-4-5"].Id);
|
||||
|
||||
var roots = UserStartNodeEntitiesService
|
||||
.RootUserAccessEntities(
|
||||
UmbracoObjectTypes.Document,
|
||||
contentStartNodeIds)
|
||||
.ToArray();
|
||||
|
||||
Assert.AreEqual(3, roots.Length);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
// the three start nodes are the grandchildren of the "1", "2" and "3" roots, respectively, so these are expected as roots
|
||||
Assert.AreEqual(_contentByName["1"].Key, roots[0].Entity.Key);
|
||||
Assert.AreEqual(_contentByName["2"].Key, roots[1].Entity.Key);
|
||||
Assert.AreEqual(_contentByName["3"].Key, roots[2].Entity.Key);
|
||||
|
||||
// all are disallowed - only the grandchildren (the actual start nodes) are allowed
|
||||
Assert.IsTrue(roots.All(r => r.HasAccess is false));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Api.Management.Services.Entities;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Cache;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.Membership;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Tests.Common.Builders;
|
||||
using Umbraco.Cms.Tests.Common.Builders.Extensions;
|
||||
using Umbraco.Cms.Tests.Common.Testing;
|
||||
using Umbraco.Cms.Tests.Integration.Testing;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.ManagementApi.Services;
|
||||
|
||||
[TestFixture]
|
||||
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerFixture)]
|
||||
public partial class UserStartNodeEntitiesServiceTests : UmbracoIntegrationTest
|
||||
{
|
||||
private Dictionary<string, IContent> _contentByName = new ();
|
||||
private IUserGroup _userGroup;
|
||||
|
||||
private IContentService ContentService => GetRequiredService<IContentService>();
|
||||
|
||||
private IContentTypeService ContentTypeService => GetRequiredService<IContentTypeService>();
|
||||
|
||||
private IUserGroupService UserGroupService => GetRequiredService<IUserGroupService>();
|
||||
|
||||
private IUserService UserService => GetRequiredService<IUserService>();
|
||||
|
||||
private IEntityService EntityService => GetRequiredService<IEntityService>();
|
||||
|
||||
private IUserStartNodeEntitiesService UserStartNodeEntitiesService => GetRequiredService<IUserStartNodeEntitiesService>();
|
||||
|
||||
protected readonly Ordering BySortOrder = Ordering.By("sortOrder");
|
||||
|
||||
protected override void ConfigureTestServices(IServiceCollection services)
|
||||
{
|
||||
base.ConfigureTestServices(services);
|
||||
services.AddTransient<IUserStartNodeEntitiesService, UserStartNodeEntitiesService>();
|
||||
}
|
||||
|
||||
[SetUp]
|
||||
public async Task SetUpTestAsync()
|
||||
{
|
||||
if (_contentByName.Any())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var contentType = new ContentTypeBuilder()
|
||||
.WithAlias("theContentType")
|
||||
.Build();
|
||||
contentType.AllowedAsRoot = true;
|
||||
await ContentTypeService.CreateAsync(contentType, Constants.Security.SuperUserKey);
|
||||
contentType.AllowedContentTypes = [new() { Alias = contentType.Alias, Key = contentType.Key }];
|
||||
await ContentTypeService.UpdateAsync(contentType, Constants.Security.SuperUserKey);
|
||||
|
||||
foreach (var rootNumber in Enumerable.Range(1, 5))
|
||||
{
|
||||
var root = new ContentBuilder()
|
||||
.WithContentType(contentType)
|
||||
.WithName($"{rootNumber}")
|
||||
.Build();
|
||||
ContentService.Save(root);
|
||||
_contentByName[root.Name!] = root;
|
||||
|
||||
foreach (var childNumber in Enumerable.Range(1, 10))
|
||||
{
|
||||
var child = new ContentBuilder()
|
||||
.WithContentType(contentType)
|
||||
.WithParent(root)
|
||||
.WithName($"{rootNumber}-{childNumber}")
|
||||
.Build();
|
||||
ContentService.Save(child);
|
||||
_contentByName[child.Name!] = child;
|
||||
|
||||
foreach (var grandChildNumber in Enumerable.Range(1, 5))
|
||||
{
|
||||
var grandchild = new ContentBuilder()
|
||||
.WithContentType(contentType)
|
||||
.WithParent(child)
|
||||
.WithName($"{rootNumber}-{childNumber}-{grandChildNumber}")
|
||||
.Build();
|
||||
ContentService.Save(grandchild);
|
||||
_contentByName[grandchild.Name!] = grandchild;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_userGroup = new UserGroupBuilder()
|
||||
.WithAlias("theGroup")
|
||||
.WithAllowedSections(["content"])
|
||||
.Build();
|
||||
_userGroup.StartContentId = null;
|
||||
await UserGroupService.CreateAsync(_userGroup, Constants.Security.SuperUserKey);
|
||||
}
|
||||
|
||||
private async Task<string[]> CreateUserAndGetStartNodePaths(params int[] startNodeIds)
|
||||
{
|
||||
var user = await CreateUser(startNodeIds);
|
||||
|
||||
var contentStartNodePaths = user.GetContentStartNodePaths(EntityService, AppCaches.NoCache);
|
||||
Assert.IsNotNull(contentStartNodePaths);
|
||||
|
||||
return contentStartNodePaths;
|
||||
}
|
||||
|
||||
private async Task<int[]> CreateUserAndGetStartNodeIds(params int[] startNodeIds)
|
||||
{
|
||||
var user = await CreateUser(startNodeIds);
|
||||
|
||||
var contentStartNodeIds = user.CalculateContentStartNodeIds(EntityService, AppCaches.NoCache);
|
||||
Assert.IsNotNull(contentStartNodeIds);
|
||||
|
||||
return contentStartNodeIds;
|
||||
}
|
||||
|
||||
private async Task<User> CreateUser(int[] startNodeIds)
|
||||
{
|
||||
var user = new UserBuilder()
|
||||
.WithName(Guid.NewGuid().ToString("N"))
|
||||
.WithStartContentIds(startNodeIds)
|
||||
.Build();
|
||||
UserService.Save(user);
|
||||
|
||||
var attempt = await UserGroupService.AddUsersToUserGroupAsync(
|
||||
new UsersToUserGroupManipulationModel(_userGroup.Key, [user.Key]),
|
||||
Constants.Security.SuperUserKey);
|
||||
|
||||
Assert.IsTrue(attempt.Success);
|
||||
return user;
|
||||
}
|
||||
}
|
||||
@@ -40,10 +40,10 @@ internal sealed class OpenAPIContractTest : UmbracoTestServerTestBase
|
||||
public async Task Validate_OpenApi_Contract_is_implemented()
|
||||
{
|
||||
string[] keysToIgnore = { "servers", "x-generator" };
|
||||
var officePath = GlobalSettings.GetBackOfficePath(HostingEnvironment);
|
||||
var backOfficePath = HostingEnvironment.GetBackOfficePath();
|
||||
|
||||
var urlToContract = $"{officePath}/management/api/openapi.json";
|
||||
var swaggerPath = $"{officePath}/swagger/management/swagger.json";
|
||||
var urlToContract = $"{backOfficePath}/management/api/openapi.json";
|
||||
var swaggerPath = $"{backOfficePath}/swagger/management/swagger.json";
|
||||
var apiContract = JsonNode.Parse(await Client.GetStringAsync(urlToContract)).AsObject();
|
||||
|
||||
var generatedJsonString = await Client.GetStringAsync(swaggerPath);
|
||||
|
||||
@@ -13,7 +13,6 @@ using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Api.Common.Attributes;
|
||||
using Umbraco.Cms.Api.Delivery.Controllers.Content;
|
||||
using Umbraco.Cms.Api.Management.Controllers;
|
||||
using Umbraco.Cms.Api.Management.Controllers.ModelsBuilder;
|
||||
@@ -31,6 +30,7 @@ using Umbraco.Cms.Tests.Integration.DependencyInjection;
|
||||
using Umbraco.Cms.Tests.Integration.Testing;
|
||||
using Umbraco.Cms.Web.Common.Controllers;
|
||||
using Umbraco.Cms.Web.Website.Controllers;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.TestServerTest
|
||||
{
|
||||
@@ -237,11 +237,8 @@ namespace Umbraco.Cms.Tests.Integration.TestServerTest
|
||||
{
|
||||
services.AddTransient<TestUmbracoDatabaseFactoryProvider>();
|
||||
|
||||
Core.Hosting.IHostingEnvironment hostingEnvironment = TestHelper.GetHostingEnvironment();
|
||||
|
||||
TypeLoader typeLoader = services.AddTypeLoader(
|
||||
GetType().Assembly,
|
||||
hostingEnvironment,
|
||||
TestHelper.ConsoleLoggerFactory,
|
||||
AppCaches.NoCache,
|
||||
Configuration,
|
||||
@@ -249,7 +246,7 @@ namespace Umbraco.Cms.Tests.Integration.TestServerTest
|
||||
|
||||
services.AddLogger(TestHelper.GetWebHostEnvironment(), Configuration);
|
||||
|
||||
var builder = new UmbracoBuilder(services, Configuration, typeLoader, TestHelper.ConsoleLoggerFactory, TestHelper.Profiler, AppCaches.NoCache, hostingEnvironment);
|
||||
var builder = new UmbracoBuilder(services, Configuration, typeLoader, TestHelper.ConsoleLoggerFactory, TestHelper.Profiler, AppCaches.NoCache);
|
||||
builder.Services.AddTransient<IHostedService>(sp => new TestDatabaseHostedLifecycleService(() => UseTestDatabase(sp)));
|
||||
|
||||
builder
|
||||
@@ -281,7 +278,6 @@ namespace Umbraco.Cms.Tests.Integration.TestServerTest
|
||||
|
||||
CustomMvcSetup(mvcBuilder);
|
||||
})
|
||||
.AddWebServer()
|
||||
.AddWebsite()
|
||||
.AddUmbracoSqlServerSupport()
|
||||
.AddUmbracoSqliteSupport()
|
||||
|
||||
@@ -151,12 +151,11 @@ public abstract class UmbracoIntegrationTest : UmbracoIntegrationTestBase
|
||||
var hostingEnvironment = TestHelper.GetHostingEnvironment();
|
||||
var typeLoader = services.AddTypeLoader(
|
||||
GetType().Assembly,
|
||||
hostingEnvironment,
|
||||
TestHelper.ConsoleLoggerFactory,
|
||||
AppCaches.NoCache,
|
||||
Configuration,
|
||||
TestHelper.Profiler);
|
||||
var builder = new UmbracoBuilder(services, Configuration, typeLoader, TestHelper.ConsoleLoggerFactory, TestHelper.Profiler, AppCaches.NoCache, hostingEnvironment);
|
||||
var builder = new UmbracoBuilder(services, Configuration, typeLoader, TestHelper.ConsoleLoggerFactory, TestHelper.Profiler, AppCaches.NoCache);
|
||||
|
||||
builder.AddConfiguration()
|
||||
.AddUmbracoCore()
|
||||
|
||||
@@ -57,7 +57,7 @@ public abstract class UmbracoIntegrationTestWithContent : UmbracoIntegrationTest
|
||||
// Create and Save Content "Text Page 1" based on "umbTextpage" -> 1054
|
||||
Subpage = ContentBuilder.CreateSimpleContent(ContentType, "Text Page 1", Textpage.Id);
|
||||
Subpage.Key = new Guid(SubPageKey);
|
||||
var contentSchedule = ContentScheduleCollection.CreateWithEntry(DateTime.Now.AddMinutes(-5), null);
|
||||
var contentSchedule = ContentScheduleCollection.CreateWithEntry(DateTime.UtcNow.AddMinutes(-5), null);
|
||||
ContentService.Save(Subpage, -1, contentSchedule);
|
||||
|
||||
// Create and Save Content "Text Page 1" based on "umbTextpage" -> 1055
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using NUnit.Framework;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models.ContentTypeEditing;
|
||||
using Umbraco.Cms.Core.Models.PublishedContent;
|
||||
@@ -12,7 +12,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Cache;
|
||||
|
||||
[TestFixture]
|
||||
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)]
|
||||
public class PublishedContentTypeCacheTests : UmbracoIntegrationTestWithContentEditing
|
||||
internal sealed class PublishedContentTypeCacheTests : UmbracoIntegrationTestWithContentEditing
|
||||
{
|
||||
protected override void CustomTestSetup(IUmbracoBuilder builder) => builder.AddUmbracoHybridCache();
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,258 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Cache;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Services.Changes;
|
||||
using Umbraco.Cms.Tests.Common.Builders;
|
||||
using Umbraco.Cms.Tests.Common.Builders.Extensions;
|
||||
using Umbraco.Cms.Tests.Integration.Attributes;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.DeliveryApi.Request;
|
||||
|
||||
public class ApiContentPathResolverInvariantTests : ApiContentPathResolverTestBase
|
||||
{
|
||||
private Dictionary<string, IContent> _contentByName = new ();
|
||||
|
||||
public static void ConfigureIncludeTopLevelNodeInPath(IUmbracoBuilder builder)
|
||||
=> builder.Services.Configure<GlobalSettings>(config => config.HideTopLevelNodeFromPath = false);
|
||||
|
||||
[SetUp]
|
||||
public async Task SetUpTest()
|
||||
{
|
||||
UmbracoContextFactory.EnsureUmbracoContext();
|
||||
SetRequestHost("localhost");
|
||||
|
||||
if (_contentByName.Any())
|
||||
{
|
||||
// these tests all run on the same DB to make them run faster, so we need to get the cache in a
|
||||
// predictable state with each test run.
|
||||
RefreshContentCache();
|
||||
return;
|
||||
}
|
||||
|
||||
await DocumentUrlService.InitAsync(true, CancellationToken.None);
|
||||
|
||||
var contentType = new ContentTypeBuilder()
|
||||
.WithAlias("theContentType")
|
||||
.Build();
|
||||
contentType.AllowedAsRoot = true;
|
||||
await ContentTypeService.CreateAsync(contentType, Constants.Security.SuperUserKey);
|
||||
contentType.AllowedContentTypes = [new() { Alias = contentType.Alias, Key = contentType.Key }];
|
||||
await ContentTypeService.UpdateAsync(contentType, Constants.Security.SuperUserKey);
|
||||
foreach (var rootNumber in Enumerable.Range(1, 3))
|
||||
{
|
||||
var root = new ContentBuilder()
|
||||
.WithContentType(contentType)
|
||||
.WithName($"Root {rootNumber}")
|
||||
.Build();
|
||||
ContentService.Save(root);
|
||||
ContentService.Publish(root, ["*"]);
|
||||
_contentByName[root.Name!] = root;
|
||||
|
||||
foreach (var childNumber in Enumerable.Range(1, 3))
|
||||
{
|
||||
var child = new ContentBuilder()
|
||||
.WithContentType(contentType)
|
||||
.WithParent(root)
|
||||
.WithName($"Child {childNumber}")
|
||||
.Build();
|
||||
ContentService.Save(child);
|
||||
ContentService.Publish(child, ["*"]);
|
||||
_contentByName[$"{root.Name!}/{child.Name!}"] = child;
|
||||
|
||||
foreach (var grandchildNumber in Enumerable.Range(1, 3))
|
||||
{
|
||||
var grandchild = new ContentBuilder()
|
||||
.WithContentType(contentType)
|
||||
.WithParent(child)
|
||||
.WithName($"Grandchild {grandchildNumber}")
|
||||
.Build();
|
||||
ContentService.Save(grandchild);
|
||||
ContentService.Publish(grandchild, ["*"]);
|
||||
_contentByName[$"{root.Name!}/{child.Name!}/{grandchild.Name!}"] = grandchild;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void First_Root_Without_StartItem()
|
||||
{
|
||||
Assert.IsEmpty(GetRequiredService<IHttpContextAccessor>().HttpContext!.Request.Headers["Start-Item"].ToString());
|
||||
|
||||
var content = ApiContentPathResolver.ResolveContentPath("/");
|
||||
Assert.IsNotNull(content);
|
||||
Assert.AreEqual(_contentByName["Root 1"].Key, content.Key);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ConfigureBuilder(ActionName = nameof(ConfigureIncludeTopLevelNodeInPath))]
|
||||
public void First_Root_Without_StartItem_With_Top_Level_Node_Included()
|
||||
{
|
||||
Assert.IsEmpty(GetRequiredService<IHttpContextAccessor>().HttpContext!.Request.Headers["Start-Item"].ToString());
|
||||
|
||||
var content = ApiContentPathResolver.ResolveContentPath("/");
|
||||
Assert.IsNotNull(content);
|
||||
Assert.AreEqual(_contentByName["Root 1"].Key, content.Key);
|
||||
}
|
||||
|
||||
[TestCase(1)]
|
||||
[TestCase(2)]
|
||||
[TestCase(3)]
|
||||
public void First_Root_Child_Without_StartItem(int child)
|
||||
{
|
||||
Assert.IsEmpty(GetRequiredService<IHttpContextAccessor>().HttpContext!.Request.Headers["Start-Item"].ToString());
|
||||
|
||||
var content = ApiContentPathResolver.ResolveContentPath($"/child-{child}");
|
||||
Assert.IsNotNull(content);
|
||||
Assert.AreEqual(_contentByName[$"Root 1/Child {child}"].Key, content.Key);
|
||||
}
|
||||
|
||||
[TestCase(1, 1)]
|
||||
[TestCase(2, 2)]
|
||||
[TestCase(3, 3)]
|
||||
[TestCase(1, 2)]
|
||||
[TestCase(2, 3)]
|
||||
[TestCase(3, 1)]
|
||||
public void First_Root_Grandchild_Without_StartItem(int child, int grandchild)
|
||||
{
|
||||
Assert.IsEmpty(GetRequiredService<IHttpContextAccessor>().HttpContext!.Request.Headers["Start-Item"].ToString());
|
||||
|
||||
var content = ApiContentPathResolver.ResolveContentPath($"/child-{child}/grandchild-{grandchild}");
|
||||
Assert.IsNotNull(content);
|
||||
Assert.AreEqual(_contentByName[$"Root 1/Child {child}/Grandchild {grandchild}"].Key, content.Key);
|
||||
}
|
||||
|
||||
[TestCase(1)]
|
||||
[TestCase(2)]
|
||||
[TestCase(3)]
|
||||
public void Root_With_StartItem(int root)
|
||||
{
|
||||
SetRequestStartItem($"root-{root}");
|
||||
|
||||
var content = ApiContentPathResolver.ResolveContentPath("/");
|
||||
Assert.IsNotNull(content);
|
||||
Assert.AreEqual(_contentByName[$"Root {root}"].Key, content.Key);
|
||||
}
|
||||
|
||||
[TestCase(1)]
|
||||
[TestCase(2)]
|
||||
[TestCase(3)]
|
||||
[ConfigureBuilder(ActionName = nameof(ConfigureIncludeTopLevelNodeInPath))]
|
||||
public void Root_With_StartItem_With_Top_Level_Node_Included(int root)
|
||||
{
|
||||
SetRequestStartItem($"root-{root}");
|
||||
|
||||
var content = ApiContentPathResolver.ResolveContentPath("/");
|
||||
Assert.IsNotNull(content);
|
||||
Assert.AreEqual(_contentByName[$"Root {root}"].Key, content.Key);
|
||||
}
|
||||
|
||||
[TestCase(1, 1)]
|
||||
[TestCase(2, 2)]
|
||||
[TestCase(3, 3)]
|
||||
[TestCase(1, 2)]
|
||||
[TestCase(2, 3)]
|
||||
[TestCase(3, 1)]
|
||||
public void Child_With_StartItem(int root, int child)
|
||||
{
|
||||
SetRequestStartItem($"root-{root}");
|
||||
|
||||
var content = ApiContentPathResolver.ResolveContentPath($"/child-{child}");
|
||||
Assert.IsNotNull(content);
|
||||
Assert.AreEqual(_contentByName[$"Root {root}/Child {child}"].Key, content.Key);
|
||||
}
|
||||
|
||||
[TestCase(1, 1)]
|
||||
[TestCase(2, 2)]
|
||||
[TestCase(3, 3)]
|
||||
[TestCase(1, 2)]
|
||||
[TestCase(2, 3)]
|
||||
[TestCase(3, 1)]
|
||||
[ConfigureBuilder(ActionName = nameof(ConfigureIncludeTopLevelNodeInPath))]
|
||||
public void Child_With_StartItem_With_Top_Level_Node_Included(int root, int child)
|
||||
{
|
||||
SetRequestStartItem($"root-{root}");
|
||||
|
||||
var content = ApiContentPathResolver.ResolveContentPath($"/child-{child}");
|
||||
Assert.IsNotNull(content);
|
||||
Assert.AreEqual(_contentByName[$"Root {root}/Child {child}"].Key, content.Key);
|
||||
}
|
||||
|
||||
[TestCase(1, 1, 1)]
|
||||
[TestCase(2, 2, 2)]
|
||||
[TestCase(3, 3, 3)]
|
||||
[TestCase(1, 2, 3)]
|
||||
[TestCase(2, 3, 1)]
|
||||
[TestCase(3, 1, 2)]
|
||||
public void Grandchild_With_StartItem(int root, int child, int grandchild)
|
||||
{
|
||||
SetRequestStartItem($"root-{root}");
|
||||
|
||||
var content = ApiContentPathResolver.ResolveContentPath($"/child-{child}/grandchild-{grandchild}");
|
||||
Assert.IsNotNull(content);
|
||||
Assert.AreEqual(_contentByName[$"Root {root}/Child {child}/Grandchild {grandchild}"].Key, content.Key);
|
||||
}
|
||||
|
||||
[TestCase("/", 1)]
|
||||
[TestCase("/root-2", 2)]
|
||||
[TestCase("/root-3", 3)]
|
||||
public void Root_By_Path_With_StartItem(string path, int root)
|
||||
{
|
||||
SetRequestStartItem($"root-{root}");
|
||||
|
||||
var content = ApiContentPathResolver.ResolveContentPath(path);
|
||||
Assert.IsNotNull(content);
|
||||
Assert.AreEqual(_contentByName[$"Root {root}"].Key, content.Key);
|
||||
}
|
||||
|
||||
[TestCase("/", 1)]
|
||||
[TestCase("/root-2", 2)]
|
||||
[TestCase("/root-3", 3)]
|
||||
public void Root_By_Path_Without_StartItem(string path, int root)
|
||||
{
|
||||
var content = ApiContentPathResolver.ResolveContentPath(path);
|
||||
Assert.IsNotNull(content);
|
||||
Assert.AreEqual(_contentByName[$"Root {root}"].Key, content.Key);
|
||||
}
|
||||
|
||||
[TestCase(1)]
|
||||
[TestCase(2)]
|
||||
[TestCase(3)]
|
||||
public async Task Root_With_Domain_Bindings(int root)
|
||||
{
|
||||
await SetContentHost(_contentByName[$"Root {root}"], "some.host", "en-US");
|
||||
SetRequestHost("some.host");
|
||||
|
||||
var content = ApiContentPathResolver.ResolveContentPath("/");
|
||||
Assert.IsNotNull(content);
|
||||
Assert.AreEqual(_contentByName[$"Root {root}"].Key, content.Key);
|
||||
}
|
||||
|
||||
[TestCase("/a", 1)]
|
||||
[TestCase("/123", 2)]
|
||||
[TestCase("/no-such-child", 3)]
|
||||
[TestCase("/a/b", 1)]
|
||||
[TestCase("/123/456", 2)]
|
||||
[TestCase("/no-such-child/no-such-grandchild", 3)]
|
||||
public void Non_Existant_Descendant_By_Path_With_StartItem(string path, int root)
|
||||
{
|
||||
SetRequestStartItem($"root-{root}");
|
||||
|
||||
var content = ApiContentPathResolver.ResolveContentPath(path);
|
||||
Assert.IsNull(content);
|
||||
}
|
||||
|
||||
[TestCase("/a")]
|
||||
[TestCase("/123")]
|
||||
[TestCase("/a/b")]
|
||||
[TestCase("/123/456")]
|
||||
public void Non_Existant_Descendant_By_Path_Without_StartItem(string path)
|
||||
{
|
||||
var content = ApiContentPathResolver.ResolveContentPath(path);
|
||||
Assert.IsNull(content);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core.DeliveryApi;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Tests.Common.Testing;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.DeliveryApi.Request;
|
||||
|
||||
[TestFixture]
|
||||
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerFixture)]
|
||||
public abstract class ApiContentPathResolverTestBase : ApiContentRequestTestBase
|
||||
{
|
||||
protected IApiContentPathResolver ApiContentPathResolver => GetRequiredService<IApiContentPathResolver>();
|
||||
|
||||
protected IDocumentUrlService DocumentUrlService => GetRequiredService<IDocumentUrlService>();
|
||||
}
|
||||
@@ -0,0 +1,326 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Tests.Common.Builders;
|
||||
using Umbraco.Cms.Tests.Common.Builders.Extensions;
|
||||
using Umbraco.Cms.Tests.Integration.Attributes;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.DeliveryApi.Request;
|
||||
|
||||
public class ApiContentPathResolverVariantTests : ApiContentPathResolverTestBase
|
||||
{
|
||||
private readonly Dictionary<string, IContent> _contentByName = new ();
|
||||
|
||||
public static void ConfigureIncludeTopLevelNodeInPath(IUmbracoBuilder builder)
|
||||
=> builder.Services.Configure<GlobalSettings>(config => config.HideTopLevelNodeFromPath = false);
|
||||
|
||||
[SetUp]
|
||||
public async Task SetUpTest()
|
||||
{
|
||||
UmbracoContextFactory.EnsureUmbracoContext();
|
||||
SetRequestHost("localhost");
|
||||
|
||||
if (_contentByName.Any())
|
||||
{
|
||||
// these tests all run on the same DB to make them run faster, so we need to get the cache in a
|
||||
// predictable state with each test run.
|
||||
RefreshContentCache();
|
||||
return;
|
||||
}
|
||||
|
||||
await DocumentUrlService.InitAsync(true, CancellationToken.None);
|
||||
|
||||
await GetRequiredService<ILanguageService>().CreateAsync(new Language("da-DK", "Danish"), Constants.Security.SuperUserKey);
|
||||
|
||||
var contentType = new ContentTypeBuilder()
|
||||
.WithAlias("theContentType")
|
||||
.WithContentVariation(ContentVariation.Culture)
|
||||
.Build();
|
||||
contentType.AllowedAsRoot = true;
|
||||
await ContentTypeService.CreateAsync(contentType, Constants.Security.SuperUserKey);
|
||||
contentType.AllowedContentTypes = [new() { Alias = contentType.Alias, Key = contentType.Key }];
|
||||
await ContentTypeService.UpdateAsync(contentType, Constants.Security.SuperUserKey);
|
||||
foreach (var rootNumber in Enumerable.Range(1, 3))
|
||||
{
|
||||
var root = new ContentBuilder()
|
||||
.WithContentType(contentType)
|
||||
.WithCultureName("en-US", $"Root {rootNumber} en-US")
|
||||
.WithCultureName("da-DK", $"Root {rootNumber} da-DK")
|
||||
.Build();
|
||||
ContentService.Save(root);
|
||||
ContentService.Publish(root, ["*"]);
|
||||
_contentByName[$"Root {rootNumber}"] = root;
|
||||
|
||||
foreach (var childNumber in Enumerable.Range(1, 3))
|
||||
{
|
||||
var child = new ContentBuilder()
|
||||
.WithContentType(contentType)
|
||||
.WithParent(root)
|
||||
.WithCultureName("en-US", $"Child {childNumber} en-US")
|
||||
.WithCultureName("da-DK", $"Child {childNumber} da-DK")
|
||||
.Build();
|
||||
ContentService.Save(child);
|
||||
ContentService.Publish(child, ["*"]);
|
||||
_contentByName[$"Root {rootNumber}/Child {childNumber}"] = child;
|
||||
|
||||
foreach (var grandchildNumber in Enumerable.Range(1, 3))
|
||||
{
|
||||
var grandchild = new ContentBuilder()
|
||||
.WithContentType(contentType)
|
||||
.WithParent(child)
|
||||
.WithCultureName("en-US", $"Grandchild {grandchildNumber} en-US")
|
||||
.WithCultureName("da-DK", $"Grandchild {grandchildNumber} da-DK")
|
||||
.Build();
|
||||
ContentService.Save(grandchild);
|
||||
ContentService.Publish(grandchild, ["*"]);
|
||||
_contentByName[$"Root {rootNumber}/Child {childNumber}/Grandchild {grandchildNumber}"] = grandchild;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[TestCase("en-US")]
|
||||
[TestCase("da-DK")]
|
||||
public void First_Root_Without_StartItem(string culture)
|
||||
{
|
||||
Assert.IsEmpty(GetRequiredService<IHttpContextAccessor>().HttpContext!.Request.Headers["Start-Item"].ToString());
|
||||
SetVariationContext(culture);
|
||||
|
||||
var content = ApiContentPathResolver.ResolveContentPath("/");
|
||||
Assert.IsNotNull(content);
|
||||
Assert.AreEqual(_contentByName["Root 1"].Key, content.Key);
|
||||
}
|
||||
|
||||
[TestCase("en-US")]
|
||||
[TestCase("da-DK")]
|
||||
[ConfigureBuilder(ActionName = nameof(ConfigureIncludeTopLevelNodeInPath))]
|
||||
public void First_Root_Without_StartItem_With_Top_Level_Node_Included(string culture)
|
||||
{
|
||||
Assert.IsEmpty(GetRequiredService<IHttpContextAccessor>().HttpContext!.Request.Headers["Start-Item"].ToString());
|
||||
SetVariationContext(culture);
|
||||
|
||||
var content = ApiContentPathResolver.ResolveContentPath("/");
|
||||
Assert.IsNotNull(content);
|
||||
Assert.AreEqual(_contentByName["Root 1"].Key, content.Key);
|
||||
}
|
||||
|
||||
[TestCase(1, "en-US")]
|
||||
[TestCase(2, "en-US")]
|
||||
[TestCase(3, "en-US")]
|
||||
[TestCase(1, "da-DK")]
|
||||
[TestCase(2, "da-DK")]
|
||||
[TestCase(3, "da-DK")]
|
||||
public void First_Root_Child_Without_StartItem(int child, string culture)
|
||||
{
|
||||
Assert.IsEmpty(GetRequiredService<IHttpContextAccessor>().HttpContext!.Request.Headers["Start-Item"].ToString());
|
||||
SetVariationContext(culture);
|
||||
|
||||
var content = ApiContentPathResolver.ResolveContentPath($"/child-{child}-{culture.ToLowerInvariant()}");
|
||||
Assert.IsNotNull(content);
|
||||
Assert.AreEqual(_contentByName[$"Root 1/Child {child}"].Key, content.Key);
|
||||
}
|
||||
|
||||
[TestCase(1, 1, "en-US")]
|
||||
[TestCase(2, 2, "en-US")]
|
||||
[TestCase(3, 3, "en-US")]
|
||||
[TestCase(1, 2, "en-US")]
|
||||
[TestCase(2, 3, "en-US")]
|
||||
[TestCase(3, 1, "en-US")]
|
||||
[TestCase(1, 1, "da-DK")]
|
||||
[TestCase(2, 2, "da-DK")]
|
||||
[TestCase(3, 3, "da-DK")]
|
||||
[TestCase(1, 2, "da-DK")]
|
||||
[TestCase(2, 3, "da-DK")]
|
||||
[TestCase(3, 1, "da-DK")]
|
||||
public void First_Root_Grandchild_Without_StartItem(int child, int grandchild, string culture)
|
||||
{
|
||||
Assert.IsEmpty(GetRequiredService<IHttpContextAccessor>().HttpContext!.Request.Headers["Start-Item"].ToString());
|
||||
SetVariationContext(culture);
|
||||
|
||||
var content = ApiContentPathResolver.ResolveContentPath($"/child-{child}-{culture.ToLowerInvariant()}/grandchild-{grandchild}-{culture.ToLowerInvariant()}");
|
||||
Assert.IsNotNull(content);
|
||||
Assert.AreEqual(_contentByName[$"Root 1/Child {child}/Grandchild {grandchild}"].Key, content.Key);
|
||||
}
|
||||
|
||||
[TestCase(1, "en-US")]
|
||||
[TestCase(2, "en-US")]
|
||||
[TestCase(3, "en-US")]
|
||||
[TestCase(1, "da-DK")]
|
||||
[TestCase(2, "da-DK")]
|
||||
[TestCase(3, "da-DK")]
|
||||
public void Root_With_StartItem(int root, string culture)
|
||||
{
|
||||
SetRequestStartItem($"root-{root}-{culture.ToLowerInvariant()}");
|
||||
SetVariationContext(culture);
|
||||
|
||||
var content = ApiContentPathResolver.ResolveContentPath("/");
|
||||
Assert.IsNotNull(content);
|
||||
Assert.AreEqual(_contentByName[$"Root {root}"].Key, content.Key);
|
||||
}
|
||||
|
||||
[TestCase(1, "en-US")]
|
||||
[TestCase(2, "en-US")]
|
||||
[TestCase(3, "en-US")]
|
||||
[TestCase(1, "da-DK")]
|
||||
[TestCase(2, "da-DK")]
|
||||
[TestCase(3, "da-DK")]
|
||||
[ConfigureBuilder(ActionName = nameof(ConfigureIncludeTopLevelNodeInPath))]
|
||||
public void Root_With_StartItem_With_Top_Level_Node_Included(int root, string culture)
|
||||
{
|
||||
SetRequestStartItem($"root-{root}-{culture.ToLowerInvariant()}");
|
||||
SetVariationContext(culture);
|
||||
|
||||
var content = ApiContentPathResolver.ResolveContentPath("/");
|
||||
Assert.IsNotNull(content);
|
||||
Assert.AreEqual(_contentByName[$"Root {root}"].Key, content.Key);
|
||||
}
|
||||
|
||||
[TestCase(1, 1, "en-US")]
|
||||
[TestCase(2, 2, "en-US")]
|
||||
[TestCase(3, 3, "en-US")]
|
||||
[TestCase(1, 2, "en-US")]
|
||||
[TestCase(2, 3, "en-US")]
|
||||
[TestCase(3, 1, "en-US")]
|
||||
[TestCase(1, 1, "da-DK")]
|
||||
[TestCase(2, 2, "da-DK")]
|
||||
[TestCase(3, 3, "da-DK")]
|
||||
[TestCase(1, 2, "da-DK")]
|
||||
[TestCase(2, 3, "da-DK")]
|
||||
[TestCase(3, 1, "da-DK")]
|
||||
public void Child_With_StartItem(int root, int child, string culture)
|
||||
{
|
||||
SetRequestStartItem($"root-{root}-{culture.ToLowerInvariant()}");
|
||||
SetVariationContext(culture);
|
||||
|
||||
var content = ApiContentPathResolver.ResolveContentPath($"/child-{child}-{culture.ToLowerInvariant()}");
|
||||
Assert.IsNotNull(content);
|
||||
Assert.AreEqual(_contentByName[$"Root {root}/Child {child}"].Key, content.Key);
|
||||
}
|
||||
|
||||
[TestCase(1, 1, "en-US")]
|
||||
[TestCase(2, 2, "en-US")]
|
||||
[TestCase(3, 3, "en-US")]
|
||||
[TestCase(1, 2, "en-US")]
|
||||
[TestCase(2, 3, "en-US")]
|
||||
[TestCase(3, 1, "en-US")]
|
||||
[TestCase(1, 1, "da-DK")]
|
||||
[TestCase(2, 2, "da-DK")]
|
||||
[TestCase(3, 3, "da-DK")]
|
||||
[TestCase(1, 2, "da-DK")]
|
||||
[TestCase(2, 3, "da-DK")]
|
||||
[TestCase(3, 1, "da-DK")]
|
||||
[ConfigureBuilder(ActionName = nameof(ConfigureIncludeTopLevelNodeInPath))]
|
||||
public void Child_With_StartItem_With_Top_Level_Node_Included(int root, int child, string culture)
|
||||
{
|
||||
SetRequestStartItem($"root-{root}-{culture.ToLowerInvariant()}");
|
||||
SetVariationContext(culture);
|
||||
|
||||
var content = ApiContentPathResolver.ResolveContentPath($"/child-{child}-{culture.ToLowerInvariant()}");
|
||||
Assert.IsNotNull(content);
|
||||
Assert.AreEqual(_contentByName[$"Root {root}/Child {child}"].Key, content.Key);
|
||||
}
|
||||
|
||||
[TestCase(1, 1, 1, "en-US")]
|
||||
[TestCase(2, 2, 2, "en-US")]
|
||||
[TestCase(3, 3, 3, "en-US")]
|
||||
[TestCase(1, 2, 3, "en-US")]
|
||||
[TestCase(2, 3, 1, "en-US")]
|
||||
[TestCase(3, 1, 2, "en-US")]
|
||||
[TestCase(1, 1, 1, "da-DK")]
|
||||
[TestCase(2, 2, 2, "da-DK")]
|
||||
[TestCase(3, 3, 3, "da-DK")]
|
||||
[TestCase(1, 2, 3, "da-DK")]
|
||||
[TestCase(2, 3, 1, "da-DK")]
|
||||
[TestCase(3, 1, 2, "da-DK")]
|
||||
public void Grandchild_With_StartItem(int root, int child, int grandchild, string culture)
|
||||
{
|
||||
SetRequestStartItem($"root-{root}-{culture.ToLowerInvariant()}");
|
||||
SetVariationContext(culture);
|
||||
|
||||
var content = ApiContentPathResolver.ResolveContentPath($"/child-{child}-{culture.ToLowerInvariant()}/grandchild-{grandchild}-{culture.ToLowerInvariant()}");
|
||||
Assert.IsNotNull(content);
|
||||
Assert.AreEqual(_contentByName[$"Root {root}/Child {child}/Grandchild {grandchild}"].Key, content.Key);
|
||||
}
|
||||
|
||||
[TestCase("/", 1, "en-US")]
|
||||
[TestCase("/root-2-en-us", 2, "en-US")]
|
||||
[TestCase("/root-3-en-us", 3, "en-US")]
|
||||
[TestCase("/", 1, "da-DK")]
|
||||
[TestCase("/root-2-da-dk", 2, "da-DK")]
|
||||
[TestCase("/root-3-da-dk", 3, "da-DK")]
|
||||
public void Root_By_Path_With_StartItem(string path, int root, string culture)
|
||||
{
|
||||
SetRequestStartItem($"root-{root}-{culture.ToLowerInvariant()}");
|
||||
SetVariationContext(culture);
|
||||
|
||||
var content = ApiContentPathResolver.ResolveContentPath(path);
|
||||
Assert.IsNotNull(content);
|
||||
Assert.AreEqual(_contentByName[$"Root {root}"].Key, content.Key);
|
||||
}
|
||||
|
||||
[TestCase("/", 1, "en-US")]
|
||||
[TestCase("/root-2-en-us", 2, "en-US")]
|
||||
[TestCase("/root-3-en-us", 3, "en-US")]
|
||||
[TestCase("/", 1, "da-DK")]
|
||||
[TestCase("/root-2-da-dk", 2, "da-DK")]
|
||||
[TestCase("/root-3-da-dk", 3, "da-DK")]
|
||||
public void Root_By_Path_Without_StartItem(string path, int root, string culture)
|
||||
{
|
||||
SetVariationContext(culture);
|
||||
|
||||
var content = ApiContentPathResolver.ResolveContentPath(path);
|
||||
Assert.IsNotNull(content);
|
||||
Assert.AreEqual(_contentByName[$"Root {root}"].Key, content.Key);
|
||||
}
|
||||
|
||||
[TestCase(1, "en-US")]
|
||||
[TestCase(2, "en-US")]
|
||||
[TestCase(3, "en-US")]
|
||||
[TestCase(1, "da-DK")]
|
||||
[TestCase(2, "da-DK")]
|
||||
[TestCase(3, "da-DK")]
|
||||
public async Task Root_With_Domain_Bindings(int root, string culture)
|
||||
{
|
||||
await SetContentHost(_contentByName[$"Root {root}"], "some.host", "en-US");
|
||||
SetRequestHost("some.host");
|
||||
SetVariationContext(culture);
|
||||
|
||||
var content = ApiContentPathResolver.ResolveContentPath("/");
|
||||
Assert.IsNotNull(content);
|
||||
Assert.AreEqual(_contentByName[$"Root {root}"].Key, content.Key);
|
||||
}
|
||||
|
||||
[TestCase("/a", 1, "en-US")]
|
||||
[TestCase("/b", 1, "da-DK")]
|
||||
[TestCase("/123", 2, "en-US")]
|
||||
[TestCase("/456", 2, "da-DK")]
|
||||
[TestCase("/no-such-child", 3, "en-US")]
|
||||
[TestCase("/not-at-all", 3, "da-DK")]
|
||||
[TestCase("/a/b", 1, "en-US")]
|
||||
[TestCase("/c/d", 1, "da-DK")]
|
||||
[TestCase("/123/456", 2, "en-US")]
|
||||
[TestCase("/789/012", 2, "da-DK")]
|
||||
[TestCase("/no-such-child/no-such-grandchild", 3, "en-US")]
|
||||
[TestCase("/not-at-all/aint-no-way", 3, "da-DK")]
|
||||
public void Non_Existant_Descendant_By_Path_With_StartItem(string path, int root, string culture)
|
||||
{
|
||||
SetRequestStartItem($"root-{root}-{culture.ToLowerInvariant()}");
|
||||
|
||||
var content = ApiContentPathResolver.ResolveContentPath(path);
|
||||
Assert.IsNull(content);
|
||||
}
|
||||
|
||||
[TestCase("/a")]
|
||||
[TestCase("/123")]
|
||||
[TestCase("/a/b")]
|
||||
[TestCase("/123/456")]
|
||||
public void Non_Existant_Descendant_By_Path_Without_StartItem(string path)
|
||||
{
|
||||
var content = ApiContentPathResolver.ResolveContentPath(path);
|
||||
Assert.IsNull(content);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core.Cache;
|
||||
using Umbraco.Cms.Core.DeliveryApi;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.ContentEditing;
|
||||
using Umbraco.Cms.Core.Models.PublishedContent;
|
||||
using Umbraco.Cms.Core.Notifications;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Services.Changes;
|
||||
using Umbraco.Cms.Core.Sync;
|
||||
using Umbraco.Cms.Core.Web;
|
||||
using Umbraco.Cms.Tests.Integration.Testing;
|
||||
using Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.DeliveryApi.Request;
|
||||
|
||||
public abstract class ApiContentRequestTestBase : UmbracoIntegrationTest
|
||||
{
|
||||
protected IContentService ContentService => GetRequiredService<IContentService>();
|
||||
|
||||
protected IContentTypeService ContentTypeService => GetRequiredService<IContentTypeService>();
|
||||
|
||||
protected IApiContentRouteBuilder ApiContentRouteBuilder => GetRequiredService<IApiContentRouteBuilder>();
|
||||
|
||||
protected IVariationContextAccessor VariationContextAccessor => GetRequiredService<IVariationContextAccessor>();
|
||||
|
||||
protected IUmbracoContextAccessor UmbracoContextAccessor => GetRequiredService<IUmbracoContextAccessor>();
|
||||
|
||||
protected IUmbracoContextFactory UmbracoContextFactory => GetRequiredService<IUmbracoContextFactory>();
|
||||
|
||||
protected override void CustomTestSetup(IUmbracoBuilder builder)
|
||||
{
|
||||
builder.AddUmbracoHybridCache();
|
||||
builder.AddNotificationHandler<ContentTreeChangeNotification, ContentTreeChangeDistributedCacheNotificationHandler>();
|
||||
builder.Services.AddUnique<IServerMessenger, ContentEventsTests.LocalServerMessenger>();
|
||||
|
||||
builder.AddDeliveryApi();
|
||||
}
|
||||
|
||||
[TearDown]
|
||||
public async Task CleanUpAfterTest()
|
||||
{
|
||||
var domainService = GetRequiredService<IDomainService>();
|
||||
foreach (var content in ContentService.GetRootContent())
|
||||
{
|
||||
await domainService.UpdateDomainsAsync(content.Key, new DomainsUpdateModel { Domains = [] });
|
||||
}
|
||||
|
||||
var httpContextAccessor = GetRequiredService<IHttpContextAccessor>();
|
||||
httpContextAccessor.HttpContext?.Request.Headers.Clear();
|
||||
}
|
||||
|
||||
protected void SetVariationContext(string? culture)
|
||||
=> VariationContextAccessor.VariationContext = new VariationContext(culture: culture);
|
||||
|
||||
protected async Task SetContentHost(IContent content, string host, string culture)
|
||||
=> await GetRequiredService<IDomainService>().UpdateDomainsAsync(
|
||||
content.Key,
|
||||
new DomainsUpdateModel { Domains = [new DomainModel { DomainName = host, IsoCode = culture }] });
|
||||
|
||||
protected void SetRequestHost(string host)
|
||||
{
|
||||
var httpContextAccessor = GetRequiredService<IHttpContextAccessor>();
|
||||
|
||||
httpContextAccessor.HttpContext = new DefaultHttpContext
|
||||
{
|
||||
Request =
|
||||
{
|
||||
Scheme = "https",
|
||||
Host = new HostString(host),
|
||||
Path = "/",
|
||||
QueryString = new QueryString(string.Empty)
|
||||
},
|
||||
RequestServices = Services
|
||||
};
|
||||
}
|
||||
|
||||
protected void SetRequestStartItem(string startItem)
|
||||
{
|
||||
var httpContextAccessor = GetRequiredService<IHttpContextAccessor>();
|
||||
if (httpContextAccessor.HttpContext is null)
|
||||
{
|
||||
throw new InvalidOperationException("HTTP context is null");
|
||||
}
|
||||
|
||||
httpContextAccessor.HttpContext.Request.Headers["Start-Item"] = startItem;
|
||||
}
|
||||
|
||||
protected void RefreshContentCache()
|
||||
=> Services.GetRequiredService<ContentCacheRefresher>().Refresh([new ContentCacheRefresher.JsonPayload { ChangeTypes = TreeChangeTypes.RefreshAll }]);
|
||||
}
|
||||
@@ -0,0 +1,242 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Tests.Common.Builders;
|
||||
using Umbraco.Cms.Tests.Common.Builders.Extensions;
|
||||
using Umbraco.Cms.Tests.Integration.Attributes;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.DeliveryApi.Request;
|
||||
|
||||
public class ApiContentRouteBuilderInvariantTests : ApiContentRouteBuilderTestBase
|
||||
{
|
||||
private readonly Dictionary<string, IContent> _contentByName = new ();
|
||||
|
||||
public static void ConfigureIncludeTopLevelNodeInPath(IUmbracoBuilder builder)
|
||||
=> builder.Services.Configure<GlobalSettings>(config => config.HideTopLevelNodeFromPath = false);
|
||||
|
||||
public static void ConfigureOmitTrailingSlash(IUmbracoBuilder builder)
|
||||
=> builder.Services.Configure<RequestHandlerSettings>(config => config.AddTrailingSlash = false);
|
||||
|
||||
[SetUp]
|
||||
public async Task SetUpTest()
|
||||
{
|
||||
SetRequestHost("localhost");
|
||||
|
||||
if (_contentByName.Any())
|
||||
{
|
||||
// these tests all run on the same DB to make them run faster, so we need to get the cache in a
|
||||
// predictable state with each test run.
|
||||
RefreshContentCache();
|
||||
return;
|
||||
}
|
||||
|
||||
var contentType = new ContentTypeBuilder()
|
||||
.WithAlias("theContentType")
|
||||
.Build();
|
||||
contentType.AllowedAsRoot = true;
|
||||
await ContentTypeService.CreateAsync(contentType, Constants.Security.SuperUserKey);
|
||||
contentType.AllowedContentTypes = [new() { Alias = contentType.Alias, Key = contentType.Key }];
|
||||
await ContentTypeService.UpdateAsync(contentType, Constants.Security.SuperUserKey);
|
||||
foreach (var rootNumber in Enumerable.Range(1, 3))
|
||||
{
|
||||
var root = new ContentBuilder()
|
||||
.WithContentType(contentType)
|
||||
.WithName($"Root {rootNumber}")
|
||||
.Build();
|
||||
ContentService.Save(root);
|
||||
ContentService.Publish(root, ["*"]);
|
||||
_contentByName[root.Name!] = root;
|
||||
|
||||
foreach (var childNumber in Enumerable.Range(1, 3))
|
||||
{
|
||||
var child = new ContentBuilder()
|
||||
.WithContentType(contentType)
|
||||
.WithParent(root)
|
||||
.WithName($"Child {childNumber}")
|
||||
.Build();
|
||||
ContentService.Save(child);
|
||||
ContentService.Publish(child, ["*"]);
|
||||
_contentByName[$"{root.Name!}/{child.Name!}"] = child;
|
||||
|
||||
foreach (var grandchildNumber in Enumerable.Range(1, 3))
|
||||
{
|
||||
var grandchild = new ContentBuilder()
|
||||
.WithContentType(contentType)
|
||||
.WithParent(child)
|
||||
.WithName($"Grandchild {grandchildNumber}")
|
||||
.Build();
|
||||
ContentService.Save(grandchild);
|
||||
ContentService.Publish(grandchild, ["*"]);
|
||||
_contentByName[$"{root.Name!}/{child.Name!}/{grandchild.Name!}"] = grandchild;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void First_Root()
|
||||
{
|
||||
var publishedContent = GetPublishedContent(_contentByName["Root 1"].Key);
|
||||
var route = ApiContentRouteBuilder.Build(publishedContent);
|
||||
Assert.IsNotNull(route);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual("/", route.Path);
|
||||
Assert.AreEqual("root-1", route.StartItem.Path);
|
||||
Assert.AreEqual(_contentByName["Root 1"].Key, route.StartItem.Id);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Last_Root()
|
||||
{
|
||||
var publishedContent = GetPublishedContent(_contentByName["Root 3"].Key);
|
||||
var route = ApiContentRouteBuilder.Build(publishedContent);
|
||||
Assert.IsNotNull(route);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual("/root-3/", route.Path);
|
||||
Assert.AreEqual("root-3", route.StartItem.Path);
|
||||
Assert.AreEqual(_contentByName["Root 3"].Key, route.StartItem.Id);
|
||||
});
|
||||
}
|
||||
|
||||
[TestCase(1)]
|
||||
[TestCase(2)]
|
||||
[TestCase(3)]
|
||||
public void First_Child(int root)
|
||||
{
|
||||
var publishedContent = GetPublishedContent(_contentByName[$"Root {root}/Child 1"].Key);
|
||||
var route = ApiContentRouteBuilder.Build(publishedContent);
|
||||
Assert.IsNotNull(route);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual("/child-1/", route.Path);
|
||||
Assert.AreEqual($"root-{root}", route.StartItem.Path);
|
||||
Assert.AreEqual(_contentByName[$"Root {root}"].Key, route.StartItem.Id);
|
||||
});
|
||||
}
|
||||
|
||||
[TestCase(1)]
|
||||
[TestCase(2)]
|
||||
[TestCase(3)]
|
||||
public void Last_Child(int root)
|
||||
{
|
||||
var publishedContent = GetPublishedContent(_contentByName[$"Root {root}/Child 3"].Key);
|
||||
var route = ApiContentRouteBuilder.Build(publishedContent);
|
||||
Assert.IsNotNull(route);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual("/child-3/", route.Path);
|
||||
Assert.AreEqual($"root-{root}", route.StartItem.Path);
|
||||
Assert.AreEqual(_contentByName[$"Root {root}"].Key, route.StartItem.Id);
|
||||
});
|
||||
}
|
||||
|
||||
[TestCase(1)]
|
||||
[TestCase(2)]
|
||||
[TestCase(3)]
|
||||
public void First_Grandchild(int root)
|
||||
{
|
||||
var publishedContent = GetPublishedContent(_contentByName[$"Root {root}/Child 1/Grandchild 1"].Key);
|
||||
var route = ApiContentRouteBuilder.Build(publishedContent);
|
||||
Assert.IsNotNull(route);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual("/child-1/grandchild-1/", route.Path);
|
||||
Assert.AreEqual($"root-{root}", route.StartItem.Path);
|
||||
Assert.AreEqual(_contentByName[$"Root {root}"].Key, route.StartItem.Id);
|
||||
});
|
||||
}
|
||||
|
||||
[TestCase(1)]
|
||||
[TestCase(2)]
|
||||
[TestCase(3)]
|
||||
public void Last_Grandchild(int root)
|
||||
{
|
||||
var publishedContent = GetPublishedContent(_contentByName[$"Root {root}/Child 3/Grandchild 3"].Key);
|
||||
var route = ApiContentRouteBuilder.Build(publishedContent);
|
||||
Assert.IsNotNull(route);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual("/child-3/grandchild-3/", route.Path);
|
||||
Assert.AreEqual($"root-{root}", route.StartItem.Path);
|
||||
Assert.AreEqual(_contentByName[$"Root {root}"].Key, route.StartItem.Id);
|
||||
});
|
||||
}
|
||||
|
||||
[TestCase(1)]
|
||||
[TestCase(2)]
|
||||
[TestCase(3)]
|
||||
[ConfigureBuilder(ActionName = nameof(ConfigureIncludeTopLevelNodeInPath))]
|
||||
public void Root_With_Top_Level_Node_Included(int root)
|
||||
{
|
||||
var publishedContent = GetPublishedContent(_contentByName[$"Root {root}"].Key);
|
||||
var route = ApiContentRouteBuilder.Build(publishedContent);
|
||||
Assert.IsNotNull(route);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual("/", route.Path);
|
||||
Assert.AreEqual($"root-{root}", route.StartItem.Path);
|
||||
Assert.AreEqual(_contentByName[$"Root {root}"].Key, route.StartItem.Id);
|
||||
});
|
||||
}
|
||||
|
||||
[TestCase(1)]
|
||||
[TestCase(2)]
|
||||
[TestCase(3)]
|
||||
public async Task Root_With_Domain_Bindings(int root)
|
||||
{
|
||||
await SetContentHost(_contentByName[$"Root {root}"], "some.host", "en-US");
|
||||
SetRequestHost("some.host");
|
||||
|
||||
var publishedContent = GetPublishedContent(_contentByName[$"Root {root}"].Key);
|
||||
var route = ApiContentRouteBuilder.Build(publishedContent);
|
||||
Assert.IsNotNull(route);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual("/", route.Path);
|
||||
Assert.AreEqual($"root-{root}", route.StartItem.Path);
|
||||
Assert.AreEqual(_contentByName[$"Root {root}"].Key, route.StartItem.Id);
|
||||
});
|
||||
}
|
||||
|
||||
[TestCase(1, "/")]
|
||||
[TestCase(2, "/root-2")]
|
||||
[TestCase(3, "/root-3")]
|
||||
[ConfigureBuilder(ActionName = nameof(ConfigureOmitTrailingSlash))]
|
||||
public void Root_Without_Trailing_Slash(int root, string expectedPath)
|
||||
{
|
||||
var publishedContent = GetPublishedContent(_contentByName[$"Root {root}"].Key);
|
||||
var route = ApiContentRouteBuilder.Build(publishedContent);
|
||||
Assert.IsNotNull(route);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual(expectedPath, route.Path);
|
||||
Assert.AreEqual($"root-{root}", route.StartItem.Path);
|
||||
Assert.AreEqual(_contentByName[$"Root {root}"].Key, route.StartItem.Id);
|
||||
});
|
||||
}
|
||||
|
||||
[TestCase(1, 1)]
|
||||
[TestCase(2, 2)]
|
||||
[TestCase(3, 3)]
|
||||
[TestCase(1, 2)]
|
||||
[TestCase(2, 3)]
|
||||
[TestCase(3, 1)]
|
||||
[ConfigureBuilder(ActionName = nameof(ConfigureOmitTrailingSlash))]
|
||||
public void Child_Without_Trailing_Slash(int root, int child)
|
||||
{
|
||||
var publishedContent = GetPublishedContent(_contentByName[$"Root {root}/Child {child}"].Key);
|
||||
var route = ApiContentRouteBuilder.Build(publishedContent);
|
||||
Assert.IsNotNull(route);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual($"/child-{child}", route.Path);
|
||||
Assert.AreEqual($"root-{root}", route.StartItem.Path);
|
||||
Assert.AreEqual(_contentByName[$"Root {root}"].Key, route.StartItem.Id);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core.Models.PublishedContent;
|
||||
using Umbraco.Cms.Tests.Common.Testing;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.DeliveryApi.Request;
|
||||
|
||||
[TestFixture]
|
||||
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerFixture)]
|
||||
public abstract class ApiContentRouteBuilderTestBase : ApiContentRequestTestBase
|
||||
{
|
||||
protected IPublishedContent GetPublishedContent(Guid key)
|
||||
{
|
||||
UmbracoContextAccessor.Clear();
|
||||
var umbracoContext = UmbracoContextFactory.EnsureUmbracoContext().UmbracoContext;
|
||||
var publishedContent = umbracoContext.Content?.GetById(key);
|
||||
Assert.IsNotNull(publishedContent);
|
||||
|
||||
return publishedContent;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,287 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Tests.Common.Builders;
|
||||
using Umbraco.Cms.Tests.Common.Builders.Extensions;
|
||||
using Umbraco.Cms.Tests.Integration.Attributes;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.DeliveryApi.Request;
|
||||
|
||||
public class ApiContentRouteBuilderVariantTests : ApiContentRouteBuilderTestBase
|
||||
{
|
||||
private readonly Dictionary<string, IContent> _contentByName = new ();
|
||||
|
||||
public static void ConfigureIncludeTopLevelNodeInPath(IUmbracoBuilder builder)
|
||||
=> builder.Services.Configure<GlobalSettings>(config => config.HideTopLevelNodeFromPath = false);
|
||||
|
||||
public static void ConfigureOmitTrailingSlash(IUmbracoBuilder builder)
|
||||
=> builder.Services.Configure<RequestHandlerSettings>(config => config.AddTrailingSlash = false);
|
||||
|
||||
[SetUp]
|
||||
public async Task SetUpTest()
|
||||
{
|
||||
SetRequestHost("localhost");
|
||||
|
||||
if (_contentByName.Any())
|
||||
{
|
||||
// these tests all run on the same DB to make them run faster, so we need to get the cache in a
|
||||
// predictable state with each test run.
|
||||
RefreshContentCache();
|
||||
return;
|
||||
}
|
||||
|
||||
await GetRequiredService<ILanguageService>().CreateAsync(new Language("da-DK", "Danish"), Constants.Security.SuperUserKey);
|
||||
|
||||
var contentType = new ContentTypeBuilder()
|
||||
.WithAlias("theContentType")
|
||||
.WithContentVariation(ContentVariation.Culture)
|
||||
.Build();
|
||||
contentType.AllowedAsRoot = true;
|
||||
await ContentTypeService.CreateAsync(contentType, Constants.Security.SuperUserKey);
|
||||
contentType.AllowedContentTypes = [new() { Alias = contentType.Alias, Key = contentType.Key }];
|
||||
await ContentTypeService.UpdateAsync(contentType, Constants.Security.SuperUserKey);
|
||||
foreach (var rootNumber in Enumerable.Range(1, 3))
|
||||
{
|
||||
var root = new ContentBuilder()
|
||||
.WithContentType(contentType)
|
||||
.WithCultureName("en-US", $"Root {rootNumber} en-US")
|
||||
.WithCultureName("da-DK", $"Root {rootNumber} da-DK")
|
||||
.Build();
|
||||
ContentService.Save(root);
|
||||
ContentService.Publish(root, ["*"]);
|
||||
_contentByName[$"Root {rootNumber}"] = root;
|
||||
|
||||
foreach (var childNumber in Enumerable.Range(1, 3))
|
||||
{
|
||||
var child = new ContentBuilder()
|
||||
.WithContentType(contentType)
|
||||
.WithParent(root)
|
||||
.WithCultureName("en-US", $"Child {childNumber} en-US")
|
||||
.WithCultureName("da-DK", $"Child {childNumber} da-DK")
|
||||
.Build();
|
||||
ContentService.Save(child);
|
||||
ContentService.Publish(child, ["*"]);
|
||||
_contentByName[$"Root {rootNumber}/Child {childNumber}"] = child;
|
||||
|
||||
foreach (var grandchildNumber in Enumerable.Range(1, 3))
|
||||
{
|
||||
var grandchild = new ContentBuilder()
|
||||
.WithContentType(contentType)
|
||||
.WithParent(child)
|
||||
.WithCultureName("en-US", $"Grandchild {grandchildNumber} en-US")
|
||||
.WithCultureName("da-DK", $"Grandchild {grandchildNumber} da-DK")
|
||||
.Build();
|
||||
ContentService.Save(grandchild);
|
||||
ContentService.Publish(grandchild, ["*"]);
|
||||
_contentByName[$"Root {rootNumber}/Child {childNumber}/Grandchild {grandchildNumber}"] = grandchild;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[TestCase("da-DK")]
|
||||
[TestCase("en-US")]
|
||||
public void First_Root(string culture)
|
||||
{
|
||||
SetVariationContext(culture);
|
||||
var publishedContent = GetPublishedContent(_contentByName[$"Root 1"].Key);
|
||||
var route = ApiContentRouteBuilder.Build(publishedContent);
|
||||
Assert.IsNotNull(route);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual("/", route.Path);
|
||||
Assert.AreEqual($"root-1-{culture.ToLowerInvariant()}", route.StartItem.Path);
|
||||
Assert.AreEqual(_contentByName[$"Root 1"].Key, route.StartItem.Id);
|
||||
});
|
||||
}
|
||||
|
||||
[TestCase("da-DK")]
|
||||
[TestCase("en-US")]
|
||||
public void Last_Root(string culture)
|
||||
{
|
||||
SetVariationContext(culture);
|
||||
var publishedContent = GetPublishedContent(_contentByName["Root 3"].Key);
|
||||
var route = ApiContentRouteBuilder.Build(publishedContent);
|
||||
Assert.IsNotNull(route);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual($"/root-3-{culture.ToLowerInvariant()}/", route.Path);
|
||||
Assert.AreEqual($"root-3-{culture.ToLowerInvariant()}", route.StartItem.Path);
|
||||
Assert.AreEqual(_contentByName["Root 3"].Key, route.StartItem.Id);
|
||||
});
|
||||
}
|
||||
|
||||
[TestCase(1, "en-US")]
|
||||
[TestCase(1, "da-DK")]
|
||||
[TestCase(2, "en-US")]
|
||||
[TestCase(2, "da-DK")]
|
||||
[TestCase(3, "en-US")]
|
||||
[TestCase(3, "da-DK")]
|
||||
public void First_Child(int root, string culture)
|
||||
{
|
||||
SetVariationContext(culture);
|
||||
var publishedContent = GetPublishedContent(_contentByName[$"Root {root}/Child 1"].Key);
|
||||
var route = ApiContentRouteBuilder.Build(publishedContent);
|
||||
Assert.IsNotNull(route);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual($"/child-1-{culture.ToLowerInvariant()}/", route.Path);
|
||||
Assert.AreEqual($"root-{root}-{culture.ToLowerInvariant()}", route.StartItem.Path);
|
||||
Assert.AreEqual(_contentByName[$"Root {root}"].Key, route.StartItem.Id);
|
||||
});
|
||||
}
|
||||
|
||||
[TestCase(1, "en-US")]
|
||||
[TestCase(1, "da-DK")]
|
||||
[TestCase(2, "en-US")]
|
||||
[TestCase(2, "da-DK")]
|
||||
[TestCase(3, "en-US")]
|
||||
[TestCase(3, "da-DK")]
|
||||
public void Last_Child(int root, string culture)
|
||||
{
|
||||
SetVariationContext(culture);
|
||||
var publishedContent = GetPublishedContent(_contentByName[$"Root {root}/Child 3"].Key);
|
||||
var route = ApiContentRouteBuilder.Build(publishedContent);
|
||||
Assert.IsNotNull(route);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual($"/child-3-{culture.ToLowerInvariant()}/", route.Path);
|
||||
Assert.AreEqual($"root-{root}-{culture.ToLowerInvariant()}", route.StartItem.Path);
|
||||
Assert.AreEqual(_contentByName[$"Root {root}"].Key, route.StartItem.Id);
|
||||
});
|
||||
}
|
||||
|
||||
[TestCase(1, "en-US")]
|
||||
[TestCase(1, "da-DK")]
|
||||
[TestCase(2, "en-US")]
|
||||
[TestCase(2, "da-DK")]
|
||||
[TestCase(3, "en-US")]
|
||||
[TestCase(3, "da-DK")]
|
||||
public void First_Grandchild(int root, string culture)
|
||||
{
|
||||
SetVariationContext(culture);
|
||||
var publishedContent = GetPublishedContent(_contentByName[$"Root {root}/Child 1/Grandchild 1"].Key);
|
||||
var route = ApiContentRouteBuilder.Build(publishedContent);
|
||||
Assert.IsNotNull(route);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual($"/child-1-{culture.ToLowerInvariant()}/grandchild-1-{culture.ToLowerInvariant()}/", route.Path);
|
||||
Assert.AreEqual($"root-{root}-{culture.ToLowerInvariant()}", route.StartItem.Path);
|
||||
Assert.AreEqual(_contentByName[$"Root {root}"].Key, route.StartItem.Id);
|
||||
});
|
||||
}
|
||||
|
||||
[TestCase(1, "en-US")]
|
||||
[TestCase(1, "da-DK")]
|
||||
[TestCase(2, "en-US")]
|
||||
[TestCase(2, "da-DK")]
|
||||
[TestCase(3, "en-US")]
|
||||
[TestCase(3, "da-DK")]
|
||||
public void Last_Grandchild(int root, string culture)
|
||||
{
|
||||
SetVariationContext(culture);
|
||||
var publishedContent = GetPublishedContent(_contentByName[$"Root {root}/Child 3/Grandchild 3"].Key);
|
||||
var route = ApiContentRouteBuilder.Build(publishedContent);
|
||||
Assert.IsNotNull(route);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual($"/child-3-{culture.ToLowerInvariant()}/grandchild-3-{culture.ToLowerInvariant()}/", route.Path);
|
||||
Assert.AreEqual($"root-{root}-{culture.ToLowerInvariant()}", route.StartItem.Path);
|
||||
Assert.AreEqual(_contentByName[$"Root {root}"].Key, route.StartItem.Id);
|
||||
});
|
||||
}
|
||||
|
||||
[TestCase(1, "en-US")]
|
||||
[TestCase(1, "da-DK")]
|
||||
[TestCase(2, "en-US")]
|
||||
[TestCase(2, "da-DK")]
|
||||
[TestCase(3, "en-US")]
|
||||
[TestCase(3, "da-DK")]
|
||||
[ConfigureBuilder(ActionName = nameof(ConfigureIncludeTopLevelNodeInPath))]
|
||||
public void Root_With_Top_Level_Node_Included(int root, string culture)
|
||||
{
|
||||
SetVariationContext(culture);
|
||||
var publishedContent = GetPublishedContent(_contentByName[$"Root {root}"].Key);
|
||||
var route = ApiContentRouteBuilder.Build(publishedContent);
|
||||
Assert.IsNotNull(route);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual("/", route.Path);
|
||||
Assert.AreEqual($"root-{root}-{culture.ToLowerInvariant()}", route.StartItem.Path);
|
||||
Assert.AreEqual(_contentByName[$"Root {root}"].Key, route.StartItem.Id);
|
||||
});
|
||||
}
|
||||
|
||||
[TestCase(1, "en-US")]
|
||||
[TestCase(1, "da-DK")]
|
||||
[TestCase(2, "en-US")]
|
||||
[TestCase(2, "da-DK")]
|
||||
[TestCase(3, "en-US")]
|
||||
[TestCase(3, "da-DK")]
|
||||
public async Task Root_With_Domain_Bindings(int root, string culture)
|
||||
{
|
||||
await SetContentHost(_contentByName[$"Root {root}"], "some.host", culture);
|
||||
SetRequestHost("some.host");
|
||||
SetVariationContext(culture);
|
||||
var publishedContent = GetPublishedContent(_contentByName[$"Root {root}"].Key);
|
||||
var route = ApiContentRouteBuilder.Build(publishedContent);
|
||||
Assert.IsNotNull(route);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual("/", route.Path);
|
||||
Assert.AreEqual($"root-{root}-{culture.ToLowerInvariant()}", route.StartItem.Path);
|
||||
Assert.AreEqual(_contentByName[$"Root {root}"].Key, route.StartItem.Id);
|
||||
});
|
||||
}
|
||||
|
||||
[TestCase(1, "en-US", "/")]
|
||||
[TestCase(1, "da-DK", "/")]
|
||||
[TestCase(2, "en-US", "/root-2-en-us")]
|
||||
[TestCase(2, "da-DK", "/root-2-da-dk")]
|
||||
[TestCase(3, "en-US", "/root-3-en-us")]
|
||||
[TestCase(3, "da-DK", "/root-3-da-dk")]
|
||||
[ConfigureBuilder(ActionName = nameof(ConfigureOmitTrailingSlash))]
|
||||
public void Root_Without_Trailing_Slash(int root, string culture, string expectedPath)
|
||||
{
|
||||
SetVariationContext(culture);
|
||||
var publishedContent = GetPublishedContent(_contentByName[$"Root {root}"].Key);
|
||||
var route = ApiContentRouteBuilder.Build(publishedContent);
|
||||
Assert.IsNotNull(route);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual(expectedPath, route.Path);
|
||||
Assert.AreEqual($"root-{root}-{culture.ToLowerInvariant()}", route.StartItem.Path);
|
||||
Assert.AreEqual(_contentByName[$"Root {root}"].Key, route.StartItem.Id);
|
||||
});
|
||||
}
|
||||
|
||||
[TestCase(1, 1, "en-US")]
|
||||
[TestCase(1, 1, "da-DK")]
|
||||
[TestCase(2, 2, "en-US")]
|
||||
[TestCase(2, 2, "da-DK")]
|
||||
[TestCase(3, 3, "en-US")]
|
||||
[TestCase(3, 3, "da-DK")]
|
||||
[TestCase(1, 2, "en-US")]
|
||||
[TestCase(1, 2, "da-DK")]
|
||||
[TestCase(2, 3, "en-US")]
|
||||
[TestCase(2, 3, "da-DK")]
|
||||
[TestCase(3, 1, "en-US")]
|
||||
[TestCase(3, 1, "da-DK")]
|
||||
[ConfigureBuilder(ActionName = nameof(ConfigureOmitTrailingSlash))]
|
||||
public void Child_Without_Trailing_Slash(int root, int child, string culture)
|
||||
{
|
||||
SetVariationContext(culture);
|
||||
var publishedContent = GetPublishedContent(_contentByName[$"Root {root}/Child {child}"].Key);
|
||||
var route = ApiContentRouteBuilder.Build(publishedContent);
|
||||
Assert.IsNotNull(route);
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual($"/child-{child}-{culture.ToLowerInvariant()}", route.Path);
|
||||
Assert.AreEqual($"root-{root}-{culture.ToLowerInvariant()}", route.StartItem.Path);
|
||||
Assert.AreEqual(_contentByName[$"Root {root}"].Key, route.StartItem.Id);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ using Umbraco.Cms.Tests.Integration.TestServerTest;
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Events;
|
||||
|
||||
[TestFixture]
|
||||
public class EventAggregatorTests : UmbracoTestServerTestBase
|
||||
internal sealed class EventAggregatorTests : UmbracoTestServerTestBase
|
||||
{
|
||||
protected override void ConfigureTestServices(IServiceCollection services)
|
||||
{
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.IO;
|
||||
|
||||
[TestFixture]
|
||||
[UmbracoTest]
|
||||
public class FileSystemsTests : UmbracoIntegrationTest
|
||||
internal sealed class FileSystemsTests : UmbracoIntegrationTest
|
||||
{
|
||||
[Test]
|
||||
public void Can_Get_MediaFileManager()
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.IO;
|
||||
|
||||
[TestFixture]
|
||||
[UmbracoTest]
|
||||
public class ShadowFileSystemTests : UmbracoIntegrationTest
|
||||
internal sealed class ShadowFileSystemTests : UmbracoIntegrationTest
|
||||
{
|
||||
[SetUp]
|
||||
public void SetUp() => ClearFiles(HostingEnvironment);
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Packaging;
|
||||
|
||||
[TestFixture]
|
||||
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerFixture)]
|
||||
public class CreatedPackagesRepositoryTests : UmbracoIntegrationTest
|
||||
internal sealed class CreatedPackagesRepositoryTests : UmbracoIntegrationTest
|
||||
{
|
||||
[SetUp]
|
||||
public void SetupTestData() => _testBaseFolder = Guid.NewGuid();
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.PublishedContent;
|
||||
|
||||
[TestFixture]
|
||||
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)]
|
||||
public class PublishContentTypeFactoryTest : UmbracoIntegrationTest
|
||||
internal sealed class PublishContentTypeFactoryTest : UmbracoIntegrationTest
|
||||
{
|
||||
protected override void CustomTestSetup(IUmbracoBuilder builder)
|
||||
{
|
||||
|
||||
@@ -9,7 +9,7 @@ using Umbraco.Cms.Tests.Integration.TestServerTest;
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core;
|
||||
|
||||
[TestFixture]
|
||||
public class PublishedContentQueryAccessorTests : UmbracoTestServerTestBase
|
||||
internal sealed class PublishedContentQueryAccessorTests : UmbracoTestServerTestBase
|
||||
{
|
||||
[Test]
|
||||
[LongRunning]
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Core;
|
||||
|
||||
[TestFixture]
|
||||
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)]
|
||||
public class RuntimeStateTests : UmbracoIntegrationTest
|
||||
internal sealed class RuntimeStateTests : UmbracoIntegrationTest
|
||||
{
|
||||
private IRuntimeState RuntimeState => Services.GetRequiredService<IRuntimeState>();
|
||||
|
||||
@@ -79,7 +79,7 @@ public class RuntimeStateTests : UmbracoIntegrationTest
|
||||
protected override void DefinePlan() => To<TestMigration>(TestMigrationFinalState);
|
||||
}
|
||||
|
||||
private class TestMigration : PackageMigrationBase
|
||||
private sealed class TestMigration : AsyncPackageMigrationBase
|
||||
{
|
||||
public TestMigration(
|
||||
IPackagingService packagingService,
|
||||
@@ -91,9 +91,13 @@ public class RuntimeStateTests : UmbracoIntegrationTest
|
||||
IMigrationContext context,
|
||||
IOptions<PackageMigrationSettings> options)
|
||||
: base(packagingService, mediaService, mediaFileManager, mediaUrlGenerators, shortStringHelper, contentTypeBaseServiceProvider, context, options)
|
||||
{
|
||||
}
|
||||
{ }
|
||||
|
||||
protected override void Migrate() => ImportPackage.FromEmbeddedResource<TestMigration>().Do();
|
||||
protected override Task MigrateAsync()
|
||||
{
|
||||
ImportPackage.FromEmbeddedResource<TestMigration>().Do();
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
Database = UmbracoTestOptions.Database.NewSchemaPerTest,
|
||||
PublishedRepositoryEvents = true,
|
||||
WithApplication = true)]
|
||||
public class ContentEditingServiceTests : UmbracoIntegrationTestWithContent
|
||||
internal sealed class ContentEditingServiceTests : UmbracoIntegrationTestWithContent
|
||||
{
|
||||
[SetUp]
|
||||
public void Setup() => ContentRepositoryBase.ThrowOnWarning = true;
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.ContentPublishing;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Tests.Integration.Testing;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
public partial class ContentPublishingServiceTests : UmbracoIntegrationTestWithContent
|
||||
{
|
||||
[Test]
|
||||
public async Task Can_Clear_Schedule_Invariant()
|
||||
{
|
||||
var doctype = await SetupInvariantDoctypeAsync();
|
||||
var content = await CreateInvariantContentAsync(doctype);
|
||||
|
||||
var scheduleSetupAttempt =
|
||||
await SchedulePublishAndUnPublishInvariantAsync(content);
|
||||
|
||||
if (scheduleSetupAttempt.Success is false)
|
||||
{
|
||||
throw new Exception("Setup failed");
|
||||
}
|
||||
|
||||
var clearScheduleAttempt = await ContentPublishingService.PublishAsync(
|
||||
content.Key,
|
||||
[
|
||||
new()
|
||||
{
|
||||
Culture = Constants.System.InvariantCulture,
|
||||
Schedule = new ContentScheduleModel(),
|
||||
},
|
||||
],
|
||||
Constants.Security.SuperUserKey);
|
||||
|
||||
Assert.IsTrue(clearScheduleAttempt.Success);
|
||||
|
||||
var schedules = ContentService.GetContentScheduleByContentId(content.Id);
|
||||
content = ContentService.GetById(content.Key);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual(0, content!.PublishedCultures.Count());
|
||||
Assert.IsNull(content!.PublishDate);
|
||||
Assert.AreEqual(0, schedules.FullSchedule.Count);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Can_Clear_Schedule_Single_Culture()
|
||||
{
|
||||
var setupInfo = await SetupVariantDoctypeAsync();
|
||||
var content = await CreateVariantContentAsync(
|
||||
setupInfo.LangEn,
|
||||
setupInfo.LangDa,
|
||||
setupInfo.LangBe,
|
||||
setupInfo.contentType);
|
||||
|
||||
var scheduleSetupAttempt =
|
||||
await SchedulePublishAndUnPublishForAllCulturesAsync(content, setupInfo);
|
||||
|
||||
if (scheduleSetupAttempt.Success is false)
|
||||
{
|
||||
throw new Exception("Setup failed");
|
||||
}
|
||||
|
||||
var scheduleAttempt = await ContentPublishingService.PublishAsync(
|
||||
content.Key,
|
||||
[
|
||||
new()
|
||||
{
|
||||
Culture = setupInfo.LangEn.IsoCode,
|
||||
Schedule = new ContentScheduleModel(),
|
||||
},
|
||||
],
|
||||
Constants.Security.SuperUserKey);
|
||||
|
||||
Assert.IsTrue(scheduleAttempt.Success);
|
||||
|
||||
var schedules = ContentService.GetContentScheduleByContentId(content.Id);
|
||||
content = ContentService.GetById(content.Key);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual(0, content!.PublishedCultures.Count());
|
||||
Assert.IsFalse(schedules.GetSchedule(setupInfo.LangEn.IsoCode, ContentScheduleAction.Release).Any());
|
||||
Assert.IsFalse(schedules.GetSchedule(setupInfo.LangEn.IsoCode, ContentScheduleAction.Expire).Any());
|
||||
Assert.AreEqual(4, schedules.FullSchedule.Count);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Can_Clear_Schedule_Some_Cultures()
|
||||
{
|
||||
var setupInfo = await SetupVariantDoctypeAsync();
|
||||
var content = await CreateVariantContentAsync(
|
||||
setupInfo.LangEn,
|
||||
setupInfo.LangDa,
|
||||
setupInfo.LangBe,
|
||||
setupInfo.contentType);
|
||||
|
||||
var scheduleSetupAttempt =
|
||||
await SchedulePublishAndUnPublishForAllCulturesAsync(content, setupInfo);
|
||||
|
||||
if (scheduleSetupAttempt.Success is false)
|
||||
{
|
||||
throw new Exception("Setup failed");
|
||||
}
|
||||
|
||||
var scheduleAttempt = await ContentPublishingService.PublishAsync(
|
||||
content.Key,
|
||||
[
|
||||
new()
|
||||
{
|
||||
Culture = setupInfo.LangEn.IsoCode,
|
||||
Schedule = new ContentScheduleModel(),
|
||||
},
|
||||
new()
|
||||
{
|
||||
Culture = setupInfo.LangDa.IsoCode,
|
||||
Schedule = new ContentScheduleModel(),
|
||||
},
|
||||
],
|
||||
Constants.Security.SuperUserKey);
|
||||
|
||||
Assert.IsTrue(scheduleAttempt.Success);
|
||||
|
||||
var schedules = ContentService.GetContentScheduleByContentId(content.Id);
|
||||
content = ContentService.GetById(content.Key);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual(0, content!.PublishedCultures.Count());
|
||||
Assert.IsFalse(schedules.GetSchedule(setupInfo.LangEn.IsoCode, ContentScheduleAction.Release).Any());
|
||||
Assert.IsFalse(schedules.GetSchedule(setupInfo.LangEn.IsoCode, ContentScheduleAction.Expire).Any());
|
||||
Assert.IsFalse(schedules.GetSchedule(setupInfo.LangDa.IsoCode, ContentScheduleAction.Release).Any());
|
||||
Assert.IsFalse(schedules.GetSchedule(setupInfo.LangDa.IsoCode, ContentScheduleAction.Expire).Any());
|
||||
Assert.AreEqual(2, schedules.FullSchedule.Count);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Can_Clear_Schedule_All_Cultures()
|
||||
{
|
||||
var setupInfo = await SetupVariantDoctypeAsync();
|
||||
var content = await CreateVariantContentAsync(
|
||||
setupInfo.LangEn,
|
||||
setupInfo.LangDa,
|
||||
setupInfo.LangBe,
|
||||
setupInfo.contentType);
|
||||
|
||||
var scheduleSetupAttempt =
|
||||
await SchedulePublishAndUnPublishForAllCulturesAsync(content, setupInfo);
|
||||
|
||||
if (scheduleSetupAttempt.Success is false)
|
||||
{
|
||||
throw new Exception("Setup failed");
|
||||
}
|
||||
|
||||
var scheduleAttempt = await ContentPublishingService.PublishAsync(
|
||||
content.Key,
|
||||
[
|
||||
new()
|
||||
{
|
||||
Culture = setupInfo.LangEn.IsoCode,
|
||||
Schedule = new ContentScheduleModel(),
|
||||
},
|
||||
new()
|
||||
{
|
||||
Culture = setupInfo.LangDa.IsoCode,
|
||||
Schedule = new ContentScheduleModel(),
|
||||
},
|
||||
new()
|
||||
{
|
||||
Culture = setupInfo.LangBe.IsoCode,
|
||||
Schedule = new ContentScheduleModel(),
|
||||
},
|
||||
],
|
||||
Constants.Security.SuperUserKey);
|
||||
|
||||
Assert.IsTrue(scheduleAttempt.Success);
|
||||
|
||||
var schedules = ContentService.GetContentScheduleByContentId(content.Id);
|
||||
content = ContentService.GetById(content.Key);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual(0, content!.PublishedCultures.Count());
|
||||
Assert.AreEqual(0, schedules.FullSchedule.Count);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,280 @@
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models.ContentPublishing;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
using Umbraco.Cms.Tests.Integration.Testing;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
public partial class ContentPublishingServiceTests : UmbracoIntegrationTestWithContent
|
||||
{
|
||||
[Test]
|
||||
public async Task Can_Publish_Single_Culture()
|
||||
{
|
||||
var (langEn, langDa, langBe, contentType) = await SetupVariantDoctypeAsync();
|
||||
var setupData = await CreateVariantContentAsync(langEn, langDa, langBe, contentType);
|
||||
|
||||
var publishAttempt = await ContentPublishingService.PublishAsync(
|
||||
setupData.Key,
|
||||
[new() { Culture = langEn.IsoCode }],
|
||||
Constants.Security.SuperUserKey);
|
||||
|
||||
Assert.IsTrue(publishAttempt.Success);
|
||||
var content = ContentService.GetById(setupData.Key);
|
||||
Assert.AreEqual(1, content!.PublishedCultures.Count());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Can_Publish_Some_Cultures()
|
||||
{
|
||||
var (langEn, langDa, langBe, contentType) = await SetupVariantDoctypeAsync();
|
||||
var content = await CreateVariantContentAsync(langEn, langDa, langBe, contentType);
|
||||
|
||||
var publishAttempt = await ContentPublishingService.PublishAsync(
|
||||
content.Key,
|
||||
[
|
||||
new() { Culture = langEn.IsoCode }, new() { Culture = langDa.IsoCode },
|
||||
],
|
||||
Constants.Security.SuperUserKey);
|
||||
|
||||
Assert.IsTrue(publishAttempt.Success);
|
||||
content = ContentService.GetById(content.Key);
|
||||
Assert.AreEqual(2, content!.PublishedCultures.Count());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Can_Publish_All_Cultures()
|
||||
{
|
||||
var (langEn, langDa, langBe, contentType) = await SetupVariantDoctypeAsync();
|
||||
var content = await CreateVariantContentAsync(langEn, langDa, langBe, contentType);
|
||||
|
||||
var publishAttempt = await ContentPublishingService.PublishAsync(
|
||||
content.Key,
|
||||
[
|
||||
new() { Culture = langEn.IsoCode },
|
||||
new() { Culture = langDa.IsoCode },
|
||||
new() { Culture = langBe.IsoCode },
|
||||
],
|
||||
Constants.Security.SuperUserKey);
|
||||
|
||||
Assert.IsTrue(publishAttempt.Success);
|
||||
content = ContentService.GetById(content.Key);
|
||||
Assert.AreEqual(3, content!.PublishedCultures.Count());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Cannot_Publish_Invariant_In_Variant_Setup()
|
||||
{
|
||||
var (langEn, langDa, langBe, contentType) = await SetupVariantDoctypeAsync();
|
||||
var content = await CreateVariantContentAsync(
|
||||
langEn,
|
||||
langDa,
|
||||
langBe,
|
||||
contentType);
|
||||
|
||||
var publishAttempt = await ContentPublishingService.PublishAsync(
|
||||
content.Key,
|
||||
[new() { Culture = Constants.System.InvariantCulture }],
|
||||
Constants.Security.SuperUserKey);
|
||||
|
||||
Assert.IsFalse(publishAttempt.Success);
|
||||
Assert.AreEqual(ContentPublishingOperationStatus.CannotPublishInvariantWhenVariant, publishAttempt.Status);
|
||||
|
||||
content = ContentService.GetById(content.Key);
|
||||
Assert.AreEqual(0, content!.PublishedCultures.Count());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Can_Publish_Invariant_In_Invariant_Setup()
|
||||
{
|
||||
var doctype = await SetupInvariantDoctypeAsync();
|
||||
var content = await CreateInvariantContentAsync(doctype);
|
||||
|
||||
var publishAttempt = await ContentPublishingService.PublishAsync(
|
||||
content.Key,
|
||||
[new() { Culture = Constants.System.InvariantCulture }],
|
||||
Constants.Security.SuperUserKey);
|
||||
|
||||
Assert.IsTrue(publishAttempt.Success);
|
||||
|
||||
content = ContentService.GetById(content.Key);
|
||||
Assert.NotNull(content!.PublishDate);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Cannot_Publish_Unknown_Culture()
|
||||
{
|
||||
var (langEn, langDa, langBe, contentType) = await SetupVariantDoctypeAsync();
|
||||
var content = await CreateVariantContentAsync(
|
||||
langEn,
|
||||
langDa,
|
||||
langBe,
|
||||
contentType);
|
||||
|
||||
var publishAttempt = await ContentPublishingService.PublishAsync(
|
||||
content.Key,
|
||||
[
|
||||
new() { Culture = langEn.IsoCode },
|
||||
new() { Culture = langDa.IsoCode },
|
||||
new() { Culture = UnknownCulture },
|
||||
],
|
||||
Constants.Security.SuperUserKey);
|
||||
|
||||
Assert.IsFalse(publishAttempt.Success);
|
||||
Assert.AreEqual(ContentPublishingOperationStatus.InvalidCulture, publishAttempt.Status);
|
||||
|
||||
content = ContentService.GetById(content.Key);
|
||||
Assert.AreEqual(0, content!.PublishedCultures.Count());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Cannot_Publish_Scheduled_Culture()
|
||||
{
|
||||
var (langEn, langDa, langBe, contentType) = await SetupVariantDoctypeAsync();
|
||||
var content = await CreateVariantContentAsync(
|
||||
langEn,
|
||||
langDa,
|
||||
langBe,
|
||||
contentType);
|
||||
|
||||
var scheduleAttempt = await ContentPublishingService.PublishAsync(
|
||||
content.Key,
|
||||
[
|
||||
new()
|
||||
{
|
||||
Culture = langEn.IsoCode,
|
||||
Schedule = new ContentScheduleModel { PublishDate = _schedulePublishDate },
|
||||
}
|
||||
],
|
||||
Constants.Security.SuperUserKey);
|
||||
|
||||
if (scheduleAttempt.Success is false)
|
||||
{
|
||||
throw new Exception("Setup failed");
|
||||
}
|
||||
|
||||
var publishAttempt = await ContentPublishingService.PublishAsync(
|
||||
content.Key,
|
||||
[new() { Culture = langEn.IsoCode }],
|
||||
Constants.Security.SuperUserKey);
|
||||
|
||||
Assert.IsFalse(publishAttempt.Success);
|
||||
Assert.AreEqual(ContentPublishingOperationStatus.CultureAwaitingRelease, publishAttempt.Status);
|
||||
|
||||
content = ContentService.GetById(content.Key);
|
||||
Assert.AreEqual(0, content!.PublishedCultures.Count());
|
||||
}
|
||||
|
||||
// TODO: The following three tests verify existing functionality that could be reconsidered.
|
||||
// The existing behaviour, verified on Umbraco 13 and 15 is as follows:
|
||||
// - For invariant content, if a parent is unpublished and I try to publish the child, I get a ContentPublishingOperationStatus.PathNotPublished error.
|
||||
// - For variant content, if I publish the parent in English but not Danish, I can publish the child in Danish.
|
||||
// This is inconsistent so we should consider if this is the desired behaviour.
|
||||
// For now though, the following tests verify the existing behaviour.
|
||||
|
||||
[Test]
|
||||
public async Task Cannot_Publish_With_Unpublished_Parent()
|
||||
{
|
||||
var doctype = await SetupInvariantDoctypeAsync();
|
||||
var parentContent = await CreateInvariantContentAsync(doctype);
|
||||
var childContent = await CreateInvariantContentAsync(doctype, parentContent.Key);
|
||||
|
||||
var publishAttempt = await ContentPublishingService.PublishAsync(
|
||||
childContent.Key,
|
||||
[new() { Culture = Constants.System.InvariantCulture }],
|
||||
Constants.Security.SuperUserKey);
|
||||
|
||||
Assert.IsFalse(publishAttempt.Success);
|
||||
Assert.AreEqual(ContentPublishingOperationStatus.PathNotPublished, publishAttempt.Status);
|
||||
|
||||
// Now publish the parent and re-try publishing the child.
|
||||
publishAttempt = await ContentPublishingService.PublishAsync(
|
||||
parentContent.Key,
|
||||
[new() { Culture = Constants.System.InvariantCulture }],
|
||||
Constants.Security.SuperUserKey);
|
||||
Assert.IsTrue(publishAttempt.Success);
|
||||
|
||||
publishAttempt = await ContentPublishingService.PublishAsync(
|
||||
childContent.Key,
|
||||
[new() { Culture = Constants.System.InvariantCulture }],
|
||||
Constants.Security.SuperUserKey);
|
||||
Assert.IsTrue(publishAttempt.Success);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Cannot_Publish_Culture_With_Unpublished_Parent()
|
||||
{
|
||||
var (langEn, langDa, langBe, contentType) = await SetupVariantDoctypeAsync();
|
||||
var parentContent = await CreateVariantContentAsync(
|
||||
langEn,
|
||||
langDa,
|
||||
langBe,
|
||||
contentType);
|
||||
var childContent = await CreateVariantContentAsync(
|
||||
langEn,
|
||||
langDa,
|
||||
langBe,
|
||||
contentType,
|
||||
parentContent.Key);
|
||||
|
||||
// Publish child in English, should not succeed.
|
||||
var publishAttempt = await ContentPublishingService.PublishAsync(
|
||||
childContent.Key,
|
||||
[new() { Culture = langEn.IsoCode }],
|
||||
Constants.Security.SuperUserKey);
|
||||
Assert.IsFalse(publishAttempt.Success);
|
||||
Assert.AreEqual(ContentPublishingOperationStatus.PathNotPublished, publishAttempt.Status);
|
||||
|
||||
// Now publish the parent and re-try publishing the child.
|
||||
publishAttempt = await ContentPublishingService.PublishAsync(
|
||||
parentContent.Key,
|
||||
[new() { Culture = langEn.IsoCode }],
|
||||
Constants.Security.SuperUserKey);
|
||||
Assert.IsTrue(publishAttempt.Success);
|
||||
|
||||
publishAttempt = await ContentPublishingService.PublishAsync(
|
||||
childContent.Key,
|
||||
[new() { Culture = langEn.IsoCode }],
|
||||
Constants.Security.SuperUserKey);
|
||||
Assert.IsTrue(publishAttempt.Success);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Can_Publish_Culture_With_Unpublished_Parent_Culture()
|
||||
{
|
||||
var (langEn, langDa, langBe, contentType) = await SetupVariantDoctypeAsync();
|
||||
var parentContent = await CreateVariantContentAsync(
|
||||
langEn,
|
||||
langDa,
|
||||
langBe,
|
||||
contentType);
|
||||
var childContent = await CreateVariantContentAsync(
|
||||
langEn,
|
||||
langDa,
|
||||
langBe,
|
||||
contentType,
|
||||
parentContent.Key);
|
||||
|
||||
// Publish parent in English.
|
||||
var publishAttempt = await ContentPublishingService.PublishAsync(
|
||||
parentContent.Key,
|
||||
[new() { Culture = langEn.IsoCode }],
|
||||
Constants.Security.SuperUserKey);
|
||||
Assert.IsTrue(publishAttempt.Success);
|
||||
|
||||
// Publish child in English, should succeed.
|
||||
publishAttempt = await ContentPublishingService.PublishAsync(
|
||||
childContent.Key,
|
||||
[new() { Culture = langEn.IsoCode }],
|
||||
Constants.Security.SuperUserKey);
|
||||
Assert.IsTrue(publishAttempt.Success);
|
||||
|
||||
// Publish child in Danish, should also succeed.
|
||||
publishAttempt = await ContentPublishingService.PublishAsync(
|
||||
childContent.Key,
|
||||
[new() { Culture = langDa.IsoCode }],
|
||||
Constants.Security.SuperUserKey);
|
||||
Assert.IsTrue(publishAttempt.Success);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,258 @@
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.ContentPublishing;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
using Umbraco.Cms.Tests.Integration.Testing;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
public partial class ContentPublishingServiceTests : UmbracoIntegrationTestWithContent
|
||||
{
|
||||
[Test]
|
||||
public async Task Can_Schedule_Publish_Invariant()
|
||||
{
|
||||
var doctype = await SetupInvariantDoctypeAsync();
|
||||
var content = await CreateInvariantContentAsync(doctype);
|
||||
|
||||
var scheduleAttempt = await ContentPublishingService.PublishAsync(
|
||||
content.Key,
|
||||
[
|
||||
new()
|
||||
{
|
||||
Culture = Constants.System.InvariantCulture,
|
||||
Schedule = new ContentScheduleModel { PublishDate = _schedulePublishDate },
|
||||
},
|
||||
],
|
||||
Constants.Security.SuperUserKey);
|
||||
|
||||
Assert.IsTrue(scheduleAttempt.Success);
|
||||
|
||||
var schedules = ContentService.GetContentScheduleByContentId(content.Id);
|
||||
content = ContentService.GetById(content.Key);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual(0, content!.PublishedCultures.Count());
|
||||
Assert.IsNull(content!.PublishDate);
|
||||
Assert.AreEqual(
|
||||
_schedulePublishDate,
|
||||
schedules.GetSchedule(Constants.System.InvariantCulture, ContentScheduleAction.Release).Single().Date);
|
||||
Assert.AreEqual(1, schedules.FullSchedule.Count);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Can_Schedule_Publish_Single_Culture()
|
||||
{
|
||||
var (langEn, langDa, langBe, contentType) = await SetupVariantDoctypeAsync();
|
||||
var content = await CreateVariantContentAsync(
|
||||
langEn,
|
||||
langDa,
|
||||
langBe,
|
||||
contentType);
|
||||
|
||||
var scheduleAttempt = await ContentPublishingService.PublishAsync(
|
||||
content.Key,
|
||||
[
|
||||
new()
|
||||
{
|
||||
Culture = langEn.IsoCode,
|
||||
Schedule = new ContentScheduleModel { PublishDate = _schedulePublishDate },
|
||||
},
|
||||
],
|
||||
Constants.Security.SuperUserKey);
|
||||
|
||||
Assert.IsTrue(scheduleAttempt.Success);
|
||||
|
||||
var schedules = ContentService.GetContentScheduleByContentId(content.Id);
|
||||
content = ContentService.GetById(content.Key);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual(0, content!.PublishedCultures.Count());
|
||||
Assert.AreEqual(
|
||||
_schedulePublishDate,
|
||||
schedules.GetSchedule(langEn.IsoCode, ContentScheduleAction.Release).Single().Date);
|
||||
Assert.AreEqual(1, schedules.FullSchedule.Count);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Can_Schedule_Publish_Some_Cultures()
|
||||
{
|
||||
var (langEn, langDa, langBe, contentType) = await SetupVariantDoctypeAsync();
|
||||
var content = await CreateVariantContentAsync(
|
||||
langEn,
|
||||
langDa,
|
||||
langBe,
|
||||
contentType);
|
||||
|
||||
var scheduleAttempt = await ContentPublishingService.PublishAsync(
|
||||
content.Key,
|
||||
[
|
||||
new()
|
||||
{
|
||||
Culture = langEn.IsoCode,
|
||||
Schedule = new ContentScheduleModel { PublishDate = _schedulePublishDate },
|
||||
},
|
||||
new()
|
||||
{
|
||||
Culture = langDa.IsoCode,
|
||||
Schedule = new ContentScheduleModel { PublishDate = _schedulePublishDate },
|
||||
},
|
||||
],
|
||||
Constants.Security.SuperUserKey);
|
||||
|
||||
Assert.IsTrue(scheduleAttempt.Success);
|
||||
|
||||
var schedules = ContentService.GetContentScheduleByContentId(content.Id);
|
||||
content = ContentService.GetById(content.Key);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual(0, content!.PublishedCultures.Count());
|
||||
Assert.AreEqual(
|
||||
_schedulePublishDate,
|
||||
schedules.GetSchedule(langEn.IsoCode, ContentScheduleAction.Release).Single().Date);
|
||||
Assert.AreEqual(
|
||||
_schedulePublishDate,
|
||||
schedules.GetSchedule(langDa.IsoCode, ContentScheduleAction.Release).Single().Date);
|
||||
Assert.AreEqual(2, schedules.FullSchedule.Count);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Can_Schedule_Publish_All_Cultures()
|
||||
{
|
||||
var (langEn, langDa, langBe, contentType) = await SetupVariantDoctypeAsync();
|
||||
var content = await CreateVariantContentAsync(
|
||||
langEn,
|
||||
langDa,
|
||||
langBe,
|
||||
contentType);
|
||||
|
||||
var scheduleAttempt = await ContentPublishingService.PublishAsync(
|
||||
content.Key,
|
||||
[
|
||||
new()
|
||||
{
|
||||
Culture = langEn.IsoCode,
|
||||
Schedule = new ContentScheduleModel { PublishDate = _schedulePublishDate },
|
||||
},
|
||||
new()
|
||||
{
|
||||
Culture = langDa.IsoCode,
|
||||
Schedule = new ContentScheduleModel { PublishDate = _schedulePublishDate },
|
||||
},
|
||||
new()
|
||||
{
|
||||
Culture = langBe.IsoCode,
|
||||
Schedule = new ContentScheduleModel { PublishDate = _schedulePublishDate },
|
||||
},
|
||||
],
|
||||
Constants.Security.SuperUserKey);
|
||||
|
||||
Assert.IsTrue(scheduleAttempt.Success);
|
||||
|
||||
var schedules = ContentService.GetContentScheduleByContentId(content.Id);
|
||||
content = ContentService.GetById(content.Key);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual(0, content!.PublishedCultures.Count());
|
||||
Assert.AreEqual(
|
||||
_schedulePublishDate,
|
||||
schedules.GetSchedule(langEn.IsoCode, ContentScheduleAction.Release).Single().Date);
|
||||
Assert.AreEqual(
|
||||
_schedulePublishDate,
|
||||
schedules.GetSchedule(langDa.IsoCode, ContentScheduleAction.Release).Single().Date);
|
||||
Assert.AreEqual(
|
||||
_schedulePublishDate,
|
||||
schedules.GetSchedule(langBe.IsoCode, ContentScheduleAction.Release).Single().Date);
|
||||
Assert.AreEqual(3, schedules.FullSchedule.Count);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Cannot_Schedule_Publish_Unknown_Culture()
|
||||
{
|
||||
var (langEn, langDa, langBe, contentType) = await SetupVariantDoctypeAsync();
|
||||
var content = await CreateVariantContentAsync(
|
||||
langEn,
|
||||
langDa,
|
||||
langBe,
|
||||
contentType);
|
||||
|
||||
var scheduleAttempt = await ContentPublishingService.PublishAsync(
|
||||
content.Key,
|
||||
[
|
||||
new()
|
||||
{
|
||||
Culture = langEn.IsoCode,
|
||||
Schedule = new ContentScheduleModel { PublishDate = _schedulePublishDate },
|
||||
},
|
||||
new()
|
||||
{
|
||||
Culture = langDa.IsoCode,
|
||||
Schedule = new ContentScheduleModel { PublishDate = _schedulePublishDate },
|
||||
},
|
||||
new()
|
||||
{
|
||||
Culture = UnknownCulture,
|
||||
Schedule = new ContentScheduleModel { PublishDate = _schedulePublishDate }
|
||||
},
|
||||
],
|
||||
Constants.Security.SuperUserKey);
|
||||
|
||||
Assert.IsFalse(scheduleAttempt.Success);
|
||||
Assert.AreEqual(ContentPublishingOperationStatus.InvalidCulture, scheduleAttempt.Status);
|
||||
|
||||
var schedules = ContentService.GetContentScheduleByContentId(content.Id);
|
||||
content = ContentService.GetById(content.Key);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual(0, content!.PublishedCultures.Count());
|
||||
Assert.AreEqual(0, schedules.FullSchedule.Count);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Can_Publish_And_Schedule_Different_Cultures()
|
||||
{
|
||||
var (langEn, langDa, langBe, contentType) = await SetupVariantDoctypeAsync();
|
||||
var content = await CreateVariantContentAsync(
|
||||
langEn,
|
||||
langDa,
|
||||
langBe,
|
||||
contentType);
|
||||
|
||||
var scheduleAttempt = await ContentPublishingService.PublishAsync(
|
||||
content.Key,
|
||||
[
|
||||
new()
|
||||
{
|
||||
Culture = langEn.IsoCode,
|
||||
},
|
||||
new()
|
||||
{
|
||||
Culture = langDa.IsoCode,
|
||||
Schedule = new ContentScheduleModel { PublishDate = _schedulePublishDate },
|
||||
},
|
||||
],
|
||||
Constants.Security.SuperUserKey);
|
||||
|
||||
Assert.IsTrue(scheduleAttempt.Success);
|
||||
|
||||
var schedules = ContentService.GetContentScheduleByContentId(content.Id);
|
||||
content = ContentService.GetById(content.Key);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual(1, content!.PublishedCultures.Count());
|
||||
Assert.AreEqual(1, schedules.FullSchedule.Count);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,221 @@
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.ContentPublishing;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
using Umbraco.Cms.Tests.Integration.Testing;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
public partial class ContentPublishingServiceTests : UmbracoIntegrationTestWithContent
|
||||
{
|
||||
[Test]
|
||||
public async Task Can_Schedule_Unpublish_Invariant()
|
||||
{
|
||||
var doctype = await SetupInvariantDoctypeAsync();
|
||||
var content = await CreateInvariantContentAsync(doctype);
|
||||
|
||||
var scheduleAttempt = await ContentPublishingService.PublishAsync(
|
||||
content.Key,
|
||||
[
|
||||
new()
|
||||
{
|
||||
Culture = Constants.System.InvariantCulture,
|
||||
Schedule = new ContentScheduleModel { UnpublishDate = _scheduleUnPublishDate },
|
||||
},
|
||||
],
|
||||
Constants.Security.SuperUserKey);
|
||||
|
||||
Assert.IsTrue(scheduleAttempt.Success);
|
||||
|
||||
var schedules = ContentService.GetContentScheduleByContentId(content.Id);
|
||||
content = ContentService.GetById(content.Key);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual(0, content!.PublishedCultures.Count());
|
||||
Assert.IsNull(content!.PublishDate);
|
||||
Assert.AreEqual(
|
||||
_scheduleUnPublishDate,
|
||||
schedules.GetSchedule(Constants.System.InvariantCulture, ContentScheduleAction.Expire).Single().Date);
|
||||
Assert.AreEqual(1, schedules.FullSchedule.Count);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Can_Schedule_Unpublish_Single_Culture()
|
||||
{
|
||||
var (langEn, langDa, langBe, contentType) = await SetupVariantDoctypeAsync();
|
||||
var content = await CreateVariantContentAsync(
|
||||
langEn,
|
||||
langDa,
|
||||
langBe,
|
||||
contentType);
|
||||
|
||||
var scheduleAttempt = await ContentPublishingService.PublishAsync(
|
||||
content.Key,
|
||||
[
|
||||
new()
|
||||
{
|
||||
Culture = langEn.IsoCode,
|
||||
Schedule = new ContentScheduleModel { UnpublishDate = _schedulePublishDate },
|
||||
},
|
||||
],
|
||||
Constants.Security.SuperUserKey);
|
||||
|
||||
Assert.IsTrue(scheduleAttempt.Success);
|
||||
|
||||
var schedules = ContentService.GetContentScheduleByContentId(content.Id);
|
||||
content = ContentService.GetById(content.Key);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual(0, content!.PublishedCultures.Count());
|
||||
Assert.AreEqual(
|
||||
_schedulePublishDate,
|
||||
schedules.GetSchedule(langEn.IsoCode, ContentScheduleAction.Expire).Single().Date);
|
||||
Assert.AreEqual(1, schedules.FullSchedule.Count);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Can_Schedule_Unpublish_Some_Cultures()
|
||||
{
|
||||
var (langEn, langDa, langBe, contentType) = await SetupVariantDoctypeAsync();
|
||||
var content = await CreateVariantContentAsync(
|
||||
langEn,
|
||||
langDa,
|
||||
langBe,
|
||||
contentType);
|
||||
|
||||
var scheduleAttempt = await ContentPublishingService.PublishAsync(
|
||||
content.Key,
|
||||
[
|
||||
new()
|
||||
{
|
||||
Culture = langEn.IsoCode,
|
||||
Schedule = new ContentScheduleModel { UnpublishDate = _schedulePublishDate },
|
||||
},
|
||||
new()
|
||||
{
|
||||
Culture = langDa.IsoCode,
|
||||
Schedule = new ContentScheduleModel { UnpublishDate = _schedulePublishDate },
|
||||
},
|
||||
],
|
||||
Constants.Security.SuperUserKey);
|
||||
|
||||
Assert.IsTrue(scheduleAttempt.Success);
|
||||
|
||||
var schedules = ContentService.GetContentScheduleByContentId(content.Id);
|
||||
content = ContentService.GetById(content.Key);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual(0, content!.PublishedCultures.Count());
|
||||
Assert.AreEqual(
|
||||
_schedulePublishDate,
|
||||
schedules.GetSchedule(langEn.IsoCode, ContentScheduleAction.Expire).Single().Date);
|
||||
Assert.AreEqual(
|
||||
_schedulePublishDate,
|
||||
schedules.GetSchedule(langDa.IsoCode, ContentScheduleAction.Expire).Single().Date);
|
||||
Assert.AreEqual(2, schedules.FullSchedule.Count);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Can_Schedule_Unpublish_All_Cultures()
|
||||
{
|
||||
var (langEn, langDa, langBe, contentType) = await SetupVariantDoctypeAsync();
|
||||
var content = await CreateVariantContentAsync(
|
||||
langEn,
|
||||
langDa,
|
||||
langBe,
|
||||
contentType);
|
||||
|
||||
var scheduleAttempt = await ContentPublishingService.PublishAsync(
|
||||
content.Key,
|
||||
[
|
||||
new()
|
||||
{
|
||||
Culture = langEn.IsoCode,
|
||||
Schedule = new ContentScheduleModel { UnpublishDate = _schedulePublishDate },
|
||||
},
|
||||
new()
|
||||
{
|
||||
Culture = langDa.IsoCode,
|
||||
Schedule = new ContentScheduleModel { UnpublishDate = _schedulePublishDate },
|
||||
},
|
||||
new()
|
||||
{
|
||||
Culture = langBe.IsoCode,
|
||||
Schedule = new ContentScheduleModel { UnpublishDate = _schedulePublishDate },
|
||||
},
|
||||
],
|
||||
Constants.Security.SuperUserKey);
|
||||
|
||||
Assert.IsTrue(scheduleAttempt.Success);
|
||||
|
||||
var schedules = ContentService.GetContentScheduleByContentId(content.Id);
|
||||
content = ContentService.GetById(content.Key);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual(0, content!.PublishedCultures.Count());
|
||||
Assert.AreEqual(
|
||||
_schedulePublishDate,
|
||||
schedules.GetSchedule(langEn.IsoCode, ContentScheduleAction.Expire).Single().Date);
|
||||
Assert.AreEqual(
|
||||
_schedulePublishDate,
|
||||
schedules.GetSchedule(langDa.IsoCode, ContentScheduleAction.Expire).Single().Date);
|
||||
Assert.AreEqual(
|
||||
_schedulePublishDate,
|
||||
schedules.GetSchedule(langBe.IsoCode, ContentScheduleAction.Expire).Single().Date);
|
||||
Assert.AreEqual(3, schedules.FullSchedule.Count);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Cannot_Schedule_Unpublish_Unknown_Culture()
|
||||
{
|
||||
var (langEn, langDa, langBe, contentType) = await SetupVariantDoctypeAsync();
|
||||
var content = await CreateVariantContentAsync(
|
||||
langEn,
|
||||
langDa,
|
||||
langBe,
|
||||
contentType);
|
||||
|
||||
var scheduleAttempt = await ContentPublishingService.PublishAsync(
|
||||
content.Key,
|
||||
[
|
||||
new()
|
||||
{
|
||||
Culture = langEn.IsoCode,
|
||||
Schedule = new ContentScheduleModel { UnpublishDate = _schedulePublishDate },
|
||||
},
|
||||
new()
|
||||
{
|
||||
Culture = langDa.IsoCode,
|
||||
Schedule = new ContentScheduleModel { UnpublishDate = _schedulePublishDate },
|
||||
},
|
||||
new()
|
||||
{
|
||||
Culture = UnknownCulture,
|
||||
Schedule = new ContentScheduleModel { UnpublishDate = _schedulePublishDate }
|
||||
},
|
||||
],
|
||||
Constants.Security.SuperUserKey);
|
||||
|
||||
Assert.IsFalse(scheduleAttempt.Success);
|
||||
Assert.AreEqual(ContentPublishingOperationStatus.InvalidCulture, scheduleAttempt.Status);
|
||||
|
||||
var schedules = ContentService.GetContentScheduleByContentId(content.Id);
|
||||
content = ContentService.GetById(content.Key);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual(0, content!.PublishedCultures.Count());
|
||||
Assert.AreEqual(0, schedules.FullSchedule.Count);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,248 @@
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.ContentPublishing;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
using Umbraco.Cms.Tests.Integration.Testing;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
public partial class ContentPublishingServiceTests : UmbracoIntegrationTestWithContent
|
||||
{
|
||||
[Test]
|
||||
public async Task Can_UnSchedule_Publish_Invariant()
|
||||
{
|
||||
var doctype = await SetupInvariantDoctypeAsync();
|
||||
var content = await CreateInvariantContentAsync(doctype);
|
||||
|
||||
var scheduleSetupAttempt =
|
||||
await SchedulePublishAndUnPublishInvariantAsync(content);
|
||||
|
||||
if (scheduleSetupAttempt.Success is false)
|
||||
{
|
||||
throw new Exception("Setup failed");
|
||||
}
|
||||
|
||||
var unscheduleAttempt = await ContentPublishingService.PublishAsync(
|
||||
content.Key,
|
||||
[
|
||||
new()
|
||||
{
|
||||
Culture = Constants.System.InvariantCulture,
|
||||
Schedule = new ContentScheduleModel { UnpublishDate = _scheduleUnPublishDate },
|
||||
},
|
||||
],
|
||||
Constants.Security.SuperUserKey);
|
||||
|
||||
Assert.IsTrue(unscheduleAttempt.Success);
|
||||
|
||||
var schedules = ContentService.GetContentScheduleByContentId(content.Id);
|
||||
content = ContentService.GetById(content.Key);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual(0, content!.PublishedCultures.Count());
|
||||
Assert.IsNull(content!.PublishDate);
|
||||
Assert.IsFalse(schedules.GetSchedule(Constants.System.InvariantCulture, ContentScheduleAction.Release).Any());
|
||||
Assert.IsTrue(schedules.GetSchedule(Constants.System.InvariantCulture, ContentScheduleAction.Expire).Any());
|
||||
Assert.AreEqual(1, schedules.FullSchedule.Count);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Can_Unschedule_Publish_Single_Culture()
|
||||
{
|
||||
var setupInfo = await SetupVariantDoctypeAsync();
|
||||
var content = await CreateVariantContentAsync(
|
||||
setupInfo.LangEn,
|
||||
setupInfo.LangDa,
|
||||
setupInfo.LangBe,
|
||||
setupInfo.contentType);
|
||||
|
||||
var scheduleSetupAttempt =
|
||||
await SchedulePublishAndUnPublishForAllCulturesAsync(content, setupInfo);
|
||||
|
||||
if (scheduleSetupAttempt.Success is false)
|
||||
{
|
||||
throw new Exception("Setup failed");
|
||||
}
|
||||
|
||||
var scheduleAttempt = await ContentPublishingService.PublishAsync(
|
||||
content.Key,
|
||||
[
|
||||
new()
|
||||
{
|
||||
Culture = setupInfo.LangEn.IsoCode,
|
||||
Schedule = new ContentScheduleModel { UnpublishDate = _scheduleUnPublishDate },
|
||||
},
|
||||
],
|
||||
Constants.Security.SuperUserKey);
|
||||
|
||||
Assert.IsTrue(scheduleAttempt.Success);
|
||||
|
||||
var schedules = ContentService.GetContentScheduleByContentId(content.Id);
|
||||
content = ContentService.GetById(content.Key);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual(0, content!.PublishedCultures.Count());
|
||||
Assert.IsFalse(schedules.GetSchedule(setupInfo.LangEn.IsoCode, ContentScheduleAction.Release).Any());
|
||||
Assert.AreEqual(5, schedules.FullSchedule.Count);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Can_Unschedule_Publish_Some_Cultures()
|
||||
{
|
||||
var setupInfo = await SetupVariantDoctypeAsync();
|
||||
var content = await CreateVariantContentAsync(
|
||||
setupInfo.LangEn,
|
||||
setupInfo.LangDa,
|
||||
setupInfo.LangBe,
|
||||
setupInfo.contentType);
|
||||
|
||||
var scheduleSetupAttempt =
|
||||
await SchedulePublishAndUnPublishForAllCulturesAsync(content, setupInfo);
|
||||
|
||||
if (scheduleSetupAttempt.Success is false)
|
||||
{
|
||||
throw new Exception("Setup failed");
|
||||
}
|
||||
|
||||
var scheduleAttempt = await ContentPublishingService.PublishAsync(
|
||||
content.Key,
|
||||
[
|
||||
new()
|
||||
{
|
||||
Culture = setupInfo.LangEn.IsoCode,
|
||||
Schedule = new ContentScheduleModel { UnpublishDate = _scheduleUnPublishDate }
|
||||
},
|
||||
new()
|
||||
{
|
||||
Culture = setupInfo.LangDa.IsoCode,
|
||||
Schedule = new ContentScheduleModel { UnpublishDate = _scheduleUnPublishDate }
|
||||
},
|
||||
],
|
||||
Constants.Security.SuperUserKey);
|
||||
|
||||
Assert.IsTrue(scheduleAttempt.Success);
|
||||
|
||||
var schedules = ContentService.GetContentScheduleByContentId(content.Id);
|
||||
content = ContentService.GetById(content.Key);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual(0, content!.PublishedCultures.Count());
|
||||
Assert.IsFalse(schedules.GetSchedule(setupInfo.LangEn.IsoCode, ContentScheduleAction.Release).Any());
|
||||
Assert.IsFalse(schedules.GetSchedule(setupInfo.LangDa.IsoCode, ContentScheduleAction.Release).Any());
|
||||
Assert.AreEqual(4, schedules.FullSchedule.Count);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Can_Unschedule_Publish_All_Cultures()
|
||||
{
|
||||
var setupInfo = await SetupVariantDoctypeAsync();
|
||||
var content = await CreateVariantContentAsync(
|
||||
setupInfo.LangEn,
|
||||
setupInfo.LangDa,
|
||||
setupInfo.LangBe,
|
||||
setupInfo.contentType);
|
||||
|
||||
var scheduleSetupAttempt =
|
||||
await SchedulePublishAndUnPublishForAllCulturesAsync(content, setupInfo);
|
||||
|
||||
if (scheduleSetupAttempt.Success is false)
|
||||
{
|
||||
throw new Exception("Setup failed");
|
||||
}
|
||||
|
||||
var scheduleAttempt = await ContentPublishingService.PublishAsync(
|
||||
content.Key,
|
||||
[
|
||||
new()
|
||||
{
|
||||
Culture = setupInfo.LangEn.IsoCode,
|
||||
Schedule = new ContentScheduleModel { UnpublishDate = _scheduleUnPublishDate },
|
||||
},
|
||||
new()
|
||||
{
|
||||
Culture = setupInfo.LangDa.IsoCode,
|
||||
Schedule = new ContentScheduleModel { UnpublishDate = _scheduleUnPublishDate },
|
||||
},
|
||||
new()
|
||||
{
|
||||
Culture = setupInfo.LangBe.IsoCode,
|
||||
Schedule = new ContentScheduleModel { UnpublishDate = _scheduleUnPublishDate },
|
||||
},
|
||||
],
|
||||
Constants.Security.SuperUserKey);
|
||||
|
||||
Assert.IsTrue(scheduleAttempt.Success);
|
||||
|
||||
var schedules = ContentService.GetContentScheduleByContentId(content.Id);
|
||||
content = ContentService.GetById(content.Key);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual(0, content!.PublishedCultures.Count());
|
||||
Assert.IsFalse(schedules.GetSchedule(setupInfo.LangEn.IsoCode, ContentScheduleAction.Release).Any());
|
||||
Assert.IsFalse(schedules.GetSchedule(setupInfo.LangDa.IsoCode, ContentScheduleAction.Release).Any());
|
||||
Assert.IsFalse(schedules.GetSchedule(setupInfo.LangBe.IsoCode, ContentScheduleAction.Release).Any());
|
||||
Assert.AreEqual(3, schedules.FullSchedule.Count);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Cannot_Unschedule_Publish_Unknown_Culture()
|
||||
{
|
||||
var setupInfo = await SetupVariantDoctypeAsync();
|
||||
var content = await CreateVariantContentAsync(
|
||||
setupInfo.LangEn,
|
||||
setupInfo.LangDa,
|
||||
setupInfo.LangBe,
|
||||
setupInfo.contentType);
|
||||
|
||||
var scheduleSetupAttempt =
|
||||
await SchedulePublishAndUnPublishForAllCulturesAsync(content, setupInfo);
|
||||
|
||||
if (scheduleSetupAttempt.Success is false)
|
||||
{
|
||||
throw new Exception("Setup failed");
|
||||
}
|
||||
|
||||
var scheduleAttempt = await ContentPublishingService.PublishAsync(
|
||||
content.Key,
|
||||
[
|
||||
new()
|
||||
{
|
||||
Culture = setupInfo.LangEn.IsoCode,
|
||||
Schedule = new ContentScheduleModel { UnpublishDate = _scheduleUnPublishDate },
|
||||
},
|
||||
new()
|
||||
{
|
||||
Culture = setupInfo.LangDa.IsoCode,
|
||||
Schedule = new ContentScheduleModel { UnpublishDate = _scheduleUnPublishDate },
|
||||
},
|
||||
new()
|
||||
{
|
||||
Culture = UnknownCulture,
|
||||
Schedule = new ContentScheduleModel { UnpublishDate = _scheduleUnPublishDate },
|
||||
},
|
||||
],
|
||||
Constants.Security.SuperUserKey);
|
||||
|
||||
Assert.IsFalse(scheduleAttempt.Success);
|
||||
Assert.AreEqual(ContentPublishingOperationStatus.InvalidCulture, scheduleAttempt.Status);
|
||||
|
||||
var schedules = ContentService.GetContentScheduleByContentId(content.Id);
|
||||
content = ContentService.GetById(content.Key);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual(0, content!.PublishedCultures.Count());
|
||||
Assert.AreEqual(6, schedules.FullSchedule.Count);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,247 @@
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.ContentPublishing;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
using Umbraco.Cms.Tests.Integration.Testing;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
public partial class ContentPublishingServiceTests : UmbracoIntegrationTestWithContent
|
||||
{
|
||||
[Test]
|
||||
public async Task Can_UnSchedule_Unpublish_Invariant()
|
||||
{
|
||||
var doctype = await SetupInvariantDoctypeAsync();
|
||||
var content = await CreateInvariantContentAsync(doctype);
|
||||
|
||||
var scheduleSetupAttempt =
|
||||
await SchedulePublishAndUnPublishInvariantAsync(content);
|
||||
|
||||
if (scheduleSetupAttempt.Success is false)
|
||||
{
|
||||
throw new Exception("Setup failed");
|
||||
}
|
||||
|
||||
var unscheduleAttempt = await ContentPublishingService.PublishAsync(
|
||||
content.Key,
|
||||
[
|
||||
new()
|
||||
{
|
||||
Culture = Constants.System.InvariantCulture,
|
||||
Schedule = new ContentScheduleModel { PublishDate = _schedulePublishDate },
|
||||
},
|
||||
],
|
||||
Constants.Security.SuperUserKey);
|
||||
|
||||
Assert.IsTrue(unscheduleAttempt.Success);
|
||||
|
||||
var schedules = ContentService.GetContentScheduleByContentId(content.Id);
|
||||
content = ContentService.GetById(content.Key);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual(0, content!.PublishedCultures.Count());
|
||||
Assert.IsNull(content!.PublishDate);
|
||||
Assert.IsFalse(schedules.GetSchedule(Constants.System.InvariantCulture, ContentScheduleAction.Expire).Any());
|
||||
Assert.IsTrue(schedules.GetSchedule(Constants.System.InvariantCulture, ContentScheduleAction.Release).Any());
|
||||
Assert.AreEqual(1, schedules.FullSchedule.Count);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Can_Unschedule_Unpublish_Single_Culture()
|
||||
{
|
||||
var setupInfo = await SetupVariantDoctypeAsync();
|
||||
var content = await CreateVariantContentAsync(
|
||||
setupInfo.LangEn,
|
||||
setupInfo.LangDa,
|
||||
setupInfo.LangBe,
|
||||
setupInfo.contentType);
|
||||
|
||||
var scheduleSetupAttempt =
|
||||
await SchedulePublishAndUnPublishForAllCulturesAsync(content, setupInfo);
|
||||
|
||||
if (scheduleSetupAttempt.Success is false)
|
||||
{
|
||||
throw new Exception("Setup failed");
|
||||
}
|
||||
|
||||
var scheduleAttempt = await ContentPublishingService.PublishAsync(
|
||||
content.Key,
|
||||
[
|
||||
new()
|
||||
{
|
||||
Culture = setupInfo.LangEn.IsoCode,
|
||||
Schedule = new ContentScheduleModel { PublishDate = _schedulePublishDate },
|
||||
},
|
||||
],
|
||||
Constants.Security.SuperUserKey);
|
||||
|
||||
Assert.IsTrue(scheduleAttempt.Success);
|
||||
|
||||
var schedules = ContentService.GetContentScheduleByContentId(content.Id);
|
||||
content = ContentService.GetById(content.Key);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual(0, content!.PublishedCultures.Count());
|
||||
Assert.IsFalse(schedules.GetSchedule(setupInfo.LangEn.IsoCode, ContentScheduleAction.Expire).Any());
|
||||
Assert.AreEqual(5, schedules.FullSchedule.Count);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Can_Unschedule_Unpublish_Some_Cultures()
|
||||
{
|
||||
var setupInfo = await SetupVariantDoctypeAsync();
|
||||
var content = await CreateVariantContentAsync(
|
||||
setupInfo.LangEn,
|
||||
setupInfo.LangDa,
|
||||
setupInfo.LangBe,
|
||||
setupInfo.contentType);
|
||||
|
||||
var scheduleSetupAttempt =
|
||||
await SchedulePublishAndUnPublishForAllCulturesAsync(content, setupInfo);
|
||||
|
||||
if (scheduleSetupAttempt.Success is false)
|
||||
{
|
||||
throw new Exception("Setup failed");
|
||||
}
|
||||
|
||||
var scheduleAttempt = await ContentPublishingService.PublishAsync(
|
||||
content.Key,
|
||||
[
|
||||
new()
|
||||
{
|
||||
Culture = setupInfo.LangEn.IsoCode,
|
||||
Schedule = new ContentScheduleModel { PublishDate = _schedulePublishDate }
|
||||
},
|
||||
new()
|
||||
{
|
||||
Culture = setupInfo.LangDa.IsoCode,
|
||||
Schedule = new ContentScheduleModel { PublishDate = _schedulePublishDate }
|
||||
},
|
||||
],
|
||||
Constants.Security.SuperUserKey);
|
||||
|
||||
Assert.IsTrue(scheduleAttempt.Success);
|
||||
|
||||
var schedules = ContentService.GetContentScheduleByContentId(content.Id);
|
||||
content = ContentService.GetById(content.Key);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual(0, content!.PublishedCultures.Count());
|
||||
Assert.IsFalse(schedules.GetSchedule(setupInfo.LangEn.IsoCode, ContentScheduleAction.Expire).Any());
|
||||
Assert.IsFalse(schedules.GetSchedule(setupInfo.LangDa.IsoCode, ContentScheduleAction.Expire).Any());
|
||||
Assert.AreEqual(4, schedules.FullSchedule.Count);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Can_Unschedule_Unpublish_All_Cultures()
|
||||
{
|
||||
var setupInfo = await SetupVariantDoctypeAsync();
|
||||
var content = await CreateVariantContentAsync(
|
||||
setupInfo.LangEn,
|
||||
setupInfo.LangDa,
|
||||
setupInfo.LangBe,
|
||||
setupInfo.contentType);
|
||||
|
||||
var scheduleSetupAttempt =
|
||||
await SchedulePublishAndUnPublishForAllCulturesAsync(content, setupInfo);
|
||||
|
||||
if (scheduleSetupAttempt.Success is false)
|
||||
{
|
||||
throw new Exception("Setup failed");
|
||||
}
|
||||
|
||||
var scheduleAttempt = await ContentPublishingService.PublishAsync(
|
||||
content.Key,
|
||||
[
|
||||
new()
|
||||
{
|
||||
Culture = setupInfo.LangEn.IsoCode,
|
||||
Schedule = new ContentScheduleModel { PublishDate = _schedulePublishDate },
|
||||
},
|
||||
new()
|
||||
{
|
||||
Culture = setupInfo.LangDa.IsoCode,
|
||||
Schedule = new ContentScheduleModel { PublishDate = _schedulePublishDate },
|
||||
},
|
||||
new()
|
||||
{
|
||||
Culture = setupInfo.LangBe.IsoCode,
|
||||
Schedule = new ContentScheduleModel { PublishDate = _schedulePublishDate },
|
||||
},
|
||||
],
|
||||
Constants.Security.SuperUserKey);
|
||||
|
||||
Assert.IsTrue(scheduleAttempt.Success);
|
||||
|
||||
var schedules = ContentService.GetContentScheduleByContentId(content.Id);
|
||||
content = ContentService.GetById(content.Key);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual(0, content!.PublishedCultures.Count());
|
||||
Assert.IsFalse(schedules.GetSchedule(setupInfo.LangEn.IsoCode, ContentScheduleAction.Expire).Any());
|
||||
Assert.IsFalse(schedules.GetSchedule(setupInfo.LangDa.IsoCode, ContentScheduleAction.Expire).Any());
|
||||
Assert.IsFalse(schedules.GetSchedule(setupInfo.LangBe.IsoCode, ContentScheduleAction.Expire).Any());
|
||||
Assert.AreEqual(3, schedules.FullSchedule.Count);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Cannot_Unschedule_Unpublish_Unknown_Culture()
|
||||
{
|
||||
var setupInfo = await SetupVariantDoctypeAsync();
|
||||
var content = await CreateVariantContentAsync(
|
||||
setupInfo.LangEn,
|
||||
setupInfo.LangDa,
|
||||
setupInfo.LangBe,
|
||||
setupInfo.contentType);
|
||||
|
||||
var scheduleSetupAttempt =
|
||||
await SchedulePublishAndUnPublishForAllCulturesAsync(content, setupInfo);
|
||||
|
||||
if (scheduleSetupAttempt.Success is false)
|
||||
{
|
||||
throw new Exception("Setup failed");
|
||||
}
|
||||
|
||||
var scheduleAttempt = await ContentPublishingService.PublishAsync(
|
||||
content.Key,
|
||||
[
|
||||
new()
|
||||
{
|
||||
Culture = setupInfo.LangEn.IsoCode,
|
||||
Schedule = new ContentScheduleModel { PublishDate = _schedulePublishDate },
|
||||
},
|
||||
new()
|
||||
{
|
||||
Culture = setupInfo.LangDa.IsoCode,
|
||||
Schedule = new ContentScheduleModel { PublishDate = _schedulePublishDate },
|
||||
},
|
||||
new()
|
||||
{
|
||||
Culture = UnknownCulture,
|
||||
Schedule = new ContentScheduleModel { PublishDate = _schedulePublishDate },
|
||||
},
|
||||
],
|
||||
Constants.Security.SuperUserKey);
|
||||
|
||||
Assert.IsFalse(scheduleAttempt.Success);
|
||||
Assert.AreEqual(ContentPublishingOperationStatus.InvalidCulture, scheduleAttempt.Status);
|
||||
var schedules = ContentService.GetContentScheduleByContentId(content.Id);
|
||||
content = ContentService.GetById(content.Key);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.AreEqual(0, content!.PublishedCultures.Count());
|
||||
Assert.AreEqual(6, schedules.FullSchedule.Count);
|
||||
});
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -35,7 +35,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
Database = UmbracoTestOptions.Database.NewSchemaPerTest,
|
||||
PublishedRepositoryEvents = true,
|
||||
WithApplication = true)]
|
||||
public class ContentServiceTests : UmbracoIntegrationTestWithContent
|
||||
internal sealed class ContentServiceTests : UmbracoIntegrationTestWithContent
|
||||
{
|
||||
[SetUp]
|
||||
public void Setup() => ContentRepositoryBase.ThrowOnWarning = true;
|
||||
@@ -214,7 +214,7 @@ public class ContentServiceTests : UmbracoIntegrationTestWithContent
|
||||
ctVariant.Variations = ContentVariation.Culture;
|
||||
ContentTypeService.Save(ctVariant);
|
||||
|
||||
var now = DateTime.Now;
|
||||
var now = DateTime.UtcNow;
|
||||
|
||||
// 10x invariant content, half is scheduled to be published in 5 seconds, the other half is scheduled to be unpublished in 5 seconds
|
||||
var invariant = new List<IContent>();
|
||||
@@ -321,7 +321,7 @@ public class ContentServiceTests : UmbracoIntegrationTestWithContent
|
||||
// Act
|
||||
var content = ContentService.CreateAndSave("Test", Constants.System.Root, "umbTextpage");
|
||||
|
||||
var contentSchedule = ContentScheduleCollection.CreateWithEntry(null, DateTime.Now.AddHours(2));
|
||||
var contentSchedule = ContentScheduleCollection.CreateWithEntry(null, DateTime.UtcNow.AddHours(2));
|
||||
ContentService.Save(content, Constants.Security.SuperUserId, contentSchedule);
|
||||
Assert.AreEqual(1, contentSchedule.FullSchedule.Count);
|
||||
|
||||
@@ -676,7 +676,7 @@ public class ContentServiceTests : UmbracoIntegrationTestWithContent
|
||||
var root = ContentService.GetById(Textpage.Id);
|
||||
ContentService.Publish(root!, root!.AvailableCultures.ToArray());
|
||||
var content = ContentService.GetById(Subpage.Id);
|
||||
var contentSchedule = ContentScheduleCollection.CreateWithEntry(null, DateTime.Now.AddSeconds(1));
|
||||
var contentSchedule = ContentScheduleCollection.CreateWithEntry(null, DateTime.UtcNow.AddSeconds(1));
|
||||
ContentService.PersistContentSchedule(content!, contentSchedule);
|
||||
ContentService.Publish(content, content.AvailableCultures.ToArray());
|
||||
|
||||
@@ -1386,7 +1386,7 @@ public class ContentServiceTests : UmbracoIntegrationTestWithContent
|
||||
{
|
||||
// Arrange
|
||||
var content = ContentService.GetById(Subpage.Id); // This Content expired 5min ago
|
||||
var contentSchedule = ContentScheduleCollection.CreateWithEntry(null, DateTime.Now.AddMinutes(-5));
|
||||
var contentSchedule = ContentScheduleCollection.CreateWithEntry(null, DateTime.UtcNow.AddMinutes(-5));
|
||||
ContentService.Save(content, contentSchedule: contentSchedule);
|
||||
|
||||
var parent = ContentService.GetById(Textpage.Id);
|
||||
@@ -1416,7 +1416,7 @@ public class ContentServiceTests : UmbracoIntegrationTestWithContent
|
||||
|
||||
var content = ContentBuilder.CreateBasicContent(contentType);
|
||||
content.SetCultureName("Hello", "en-US");
|
||||
var contentSchedule = ContentScheduleCollection.CreateWithEntry("en-US", null, DateTime.Now.AddMinutes(-5));
|
||||
var contentSchedule = ContentScheduleCollection.CreateWithEntry("en-US", null, DateTime.UtcNow.AddMinutes(-5));
|
||||
ContentService.Save(content, contentSchedule: contentSchedule);
|
||||
|
||||
var published = ContentService.Publish(content, new[] { "en-US" });
|
||||
@@ -1431,7 +1431,7 @@ public class ContentServiceTests : UmbracoIntegrationTestWithContent
|
||||
{
|
||||
// Arrange
|
||||
var content = ContentService.GetById(Subpage.Id);
|
||||
var contentSchedule = ContentScheduleCollection.CreateWithEntry(DateTime.Now.AddHours(2), null);
|
||||
var contentSchedule = ContentScheduleCollection.CreateWithEntry(DateTime.UtcNow.AddHours(2), null);
|
||||
ContentService.Save(content, Constants.Security.SuperUserId, contentSchedule);
|
||||
|
||||
var parent = ContentService.GetById(Textpage.Id);
|
||||
@@ -1488,7 +1488,7 @@ public class ContentServiceTests : UmbracoIntegrationTestWithContent
|
||||
content.Properties[0].SetValue("Foo", string.Empty);
|
||||
contentService.Save(content);
|
||||
contentService.PersistContentSchedule(content,
|
||||
ContentScheduleCollection.CreateWithEntry(DateTime.Now.AddHours(2), null));
|
||||
ContentScheduleCollection.CreateWithEntry(DateTime.UtcNow.AddHours(2), null));
|
||||
|
||||
// Act
|
||||
var result = contentService.Publish(content, Array.Empty<string>(), userId: Constants.Security.SuperUserId);
|
||||
@@ -1540,7 +1540,7 @@ public class ContentServiceTests : UmbracoIntegrationTestWithContent
|
||||
contentService.Publish(content, Array.Empty<string>());
|
||||
|
||||
contentService.PersistContentSchedule(content,
|
||||
ContentScheduleCollection.CreateWithEntry(DateTime.Now.AddHours(2), null));
|
||||
ContentScheduleCollection.CreateWithEntry(DateTime.UtcNow.AddHours(2), null));
|
||||
contentService.Save(content);
|
||||
|
||||
// Act
|
||||
@@ -1568,7 +1568,7 @@ public class ContentServiceTests : UmbracoIntegrationTestWithContent
|
||||
|
||||
var content = ContentBuilder.CreateBasicContent(contentType);
|
||||
content.SetCultureName("Hello", "en-US");
|
||||
var contentSchedule = ContentScheduleCollection.CreateWithEntry("en-US", DateTime.Now.AddHours(2), null);
|
||||
var contentSchedule = ContentScheduleCollection.CreateWithEntry("en-US", DateTime.UtcNow.AddHours(2), null);
|
||||
ContentService.Save(content, contentSchedule: contentSchedule);
|
||||
|
||||
var published = ContentService.Publish(content, new[] { "en-US" });
|
||||
@@ -1913,11 +1913,11 @@ public class ContentServiceTests : UmbracoIntegrationTestWithContent
|
||||
|
||||
[Test]
|
||||
[LongRunning]
|
||||
public void Ensures_Permissions_Are_Retained_For_Copied_Descendants_With_Explicit_Permissions()
|
||||
public async Task Ensures_Permissions_Are_Retained_For_Copied_Descendants_With_Explicit_Permissions()
|
||||
{
|
||||
// Arrange
|
||||
var userGroup = UserGroupBuilder.CreateUserGroup("1");
|
||||
UserService.Save(userGroup);
|
||||
await UserGroupService.CreateAsync(userGroup, Constants.Security.SuperUserKey);
|
||||
|
||||
var template = TemplateBuilder.CreateTextPageTemplate();
|
||||
FileService.SaveTemplate(template);
|
||||
@@ -1954,11 +1954,11 @@ public class ContentServiceTests : UmbracoIntegrationTestWithContent
|
||||
|
||||
[Test]
|
||||
[LongRunning]
|
||||
public void Ensures_Permissions_Are_Inherited_For_Copied_Descendants()
|
||||
public async Task Ensures_Permissions_Are_Inherited_For_Copied_Descendants()
|
||||
{
|
||||
// Arrange
|
||||
var userGroup = UserGroupBuilder.CreateUserGroup("1");
|
||||
UserService.Save(userGroup);
|
||||
await UserGroupService.CreateAsync(userGroup, Constants.Security.SuperUserKey);
|
||||
|
||||
var template = TemplateBuilder.CreateTextPageTemplate();
|
||||
FileService.SaveTemplate(template);
|
||||
@@ -1969,7 +1969,7 @@ public class ContentServiceTests : UmbracoIntegrationTestWithContent
|
||||
{
|
||||
new(contentType.Key, 0, contentType.Alias)
|
||||
};
|
||||
ContentTypeService.Save(contentType);
|
||||
await ContentTypeService.UpdateAsync(contentType, Constants.Security.SuperUserKey);
|
||||
|
||||
var parentPage = ContentBuilder.CreateSimpleContent(contentType);
|
||||
ContentService.Save(parentPage);
|
||||
@@ -2060,7 +2060,7 @@ public class ContentServiceTests : UmbracoIntegrationTestWithContent
|
||||
|
||||
var editorGroup = await UserGroupService.GetAsync(Constants.Security.EditorGroupKey);
|
||||
editorGroup.StartContentId = content1.Id;
|
||||
UserService.Save(editorGroup);
|
||||
await UserGroupService.UpdateAsync(editorGroup, Constants.Security.SuperUserKey);
|
||||
|
||||
var admin = await UserService.GetAsync(Constants.Security.SuperUserKey);
|
||||
admin.StartContentIds = new[] { content1.Id };
|
||||
@@ -2075,7 +2075,7 @@ public class ContentServiceTests : UmbracoIntegrationTestWithContent
|
||||
Assert.IsTrue(PublicAccessService.AddRule(content1, "test2", "test2").Success);
|
||||
|
||||
var user = await UserService.GetAsync(Constants.Security.SuperUserKey);
|
||||
var userGroup = UserService.GetUserGroupByAlias(user.Groups.First().Alias);
|
||||
var userGroup = await UserGroupService.GetAsync(user.Groups.First().Alias);
|
||||
Assert.IsNotNull(NotificationService.CreateNotification(user, content1, "X"));
|
||||
|
||||
ContentService.SetPermission(content1, "A", new[] { userGroup.Id });
|
||||
|
||||
@@ -5,7 +5,7 @@ using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
public class
|
||||
internal sealed class
|
||||
ContentTypeEditingServiceModelsBuilderDisabledTests : ContentTypeEditingServiceModelsBuilderDisabledTestsBase
|
||||
{
|
||||
// test some properties from IPublishedContent
|
||||
|
||||
@@ -6,6 +6,6 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
/// Unlike <see cref="ContentTypeEditingServiceModelsBuilderEnabledTestsBase"/> this testbase does not configure the modelsbuilder based <see cref="ConfigurePropertySettingsOptions"/>
|
||||
/// which has the same effect as disabling it completely as <see cref="ContentTypeEditingServiceModelsBuilderEnabledTestsBase"/> only loads in that part anyway.
|
||||
/// </summary>
|
||||
public class ContentTypeEditingServiceModelsBuilderDisabledTestsBase : ContentTypeEditingServiceTestsBase
|
||||
internal class ContentTypeEditingServiceModelsBuilderDisabledTestsBase : ContentTypeEditingServiceTestsBase
|
||||
{
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
public class ContentTypeEditingServiceModelsBuilderEnabledTests : ContentTypeEditingServiceModelsBuilderEnabledTestsBase
|
||||
internal sealed class ContentTypeEditingServiceModelsBuilderEnabledTests : ContentTypeEditingServiceModelsBuilderEnabledTestsBase
|
||||
{
|
||||
// test some properties from IPublishedContent
|
||||
[TestCaseSource(nameof(DifferentCapitalizedAlias), new object[] { nameof(IPublishedContent.Id) })]
|
||||
|
||||
@@ -6,7 +6,7 @@ using Umbraco.Cms.Infrastructure.ModelsBuilder.Options;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
public class ContentTypeEditingServiceModelsBuilderEnabledTestsBase : ContentTypeEditingServiceTestsBase
|
||||
internal class ContentTypeEditingServiceModelsBuilderEnabledTestsBase : ContentTypeEditingServiceTestsBase
|
||||
{
|
||||
protected override void CustomTestSetup(IUmbracoBuilder builder)
|
||||
{
|
||||
|
||||
@@ -7,7 +7,7 @@ using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
public partial class ContentTypeEditingServiceTests
|
||||
internal sealed partial class ContentTypeEditingServiceTests
|
||||
{
|
||||
[TestCase(false)]
|
||||
[TestCase(true)]
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
using NUnit.Framework;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.ContentTypeEditing;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
public partial class ContentTypeEditingServiceTests
|
||||
internal sealed partial class ContentTypeEditingServiceTests
|
||||
{
|
||||
[TestCase(true)]
|
||||
[TestCase(false)]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using NUnit.Framework;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.ContentTypeEditing;
|
||||
@@ -6,7 +6,7 @@ using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
public partial class ContentTypeEditingServiceTests
|
||||
internal sealed partial class ContentTypeEditingServiceTests
|
||||
{
|
||||
[TestCase(false)]
|
||||
[TestCase(true)]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
public partial class ContentTypeEditingServiceTests : ContentTypeEditingServiceTestsBase
|
||||
internal sealed partial class ContentTypeEditingServiceTests : ContentTypeEditingServiceTestsBase
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using NUnit.Framework;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models.ContentTypeEditing;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
@@ -13,7 +13,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
Database = UmbracoTestOptions.Database.NewSchemaPerTest,
|
||||
PublishedRepositoryEvents = true,
|
||||
WithApplication = true)]
|
||||
public abstract class ContentTypeEditingServiceTestsBase : UmbracoIntegrationTest
|
||||
internal abstract class ContentTypeEditingServiceTestsBase : UmbracoIntegrationTest
|
||||
{
|
||||
protected IContentTypeEditingService ContentTypeEditingService => GetRequiredService<IContentTypeEditingService>();
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ using Umbraco.Cms.Core;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
public partial class DocumentNavigationServiceTests
|
||||
internal sealed partial class DocumentNavigationServiceTests
|
||||
{
|
||||
[Test]
|
||||
[TestCase("A1B1B217-B02F-4307-862C-A5E22DB729EB", "A1B1B217-B02F-4307-862C-A5E22DB729EB")] // Grandchild 2 to itself
|
||||
|
||||
@@ -3,7 +3,7 @@ using Umbraco.Cms.Core;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
public partial class DocumentNavigationServiceTests
|
||||
internal sealed partial class DocumentNavigationServiceTests
|
||||
{
|
||||
[Test]
|
||||
public async Task Structure_Updates_When_Creating_Content_At_Root()
|
||||
|
||||
@@ -3,7 +3,7 @@ using Umbraco.Cms.Core;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
public partial class DocumentNavigationServiceTests
|
||||
internal sealed partial class DocumentNavigationServiceTests
|
||||
{
|
||||
[Test]
|
||||
[TestCase("E48DD82A-7059-418E-9B82-CDD5205796CF")] // Root
|
||||
|
||||
@@ -3,7 +3,7 @@ using Umbraco.Cms.Core;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
public partial class DocumentNavigationServiceTests
|
||||
internal sealed partial class DocumentNavigationServiceTests
|
||||
{
|
||||
[Test]
|
||||
public async Task Structure_Updates_When_Deleting_From_Recycle_Bin()
|
||||
|
||||
@@ -3,7 +3,7 @@ using Umbraco.Cms.Core;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
public partial class DocumentNavigationServiceTests
|
||||
internal sealed partial class DocumentNavigationServiceTests
|
||||
{
|
||||
[Test]
|
||||
[TestCase("E856AC03-C23E-4F63-9AA9-681B42A58573", "60E0E5C4-084E-4144-A560-7393BEAD2E96")] // Grandchild 1 to Child 2
|
||||
|
||||
@@ -3,7 +3,7 @@ using Umbraco.Cms.Core;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
public partial class DocumentNavigationServiceTests
|
||||
internal sealed partial class DocumentNavigationServiceTests
|
||||
{
|
||||
[Test]
|
||||
public async Task Parent_And_Descendants_Are_Updated_When_Content_Is_Moved_To_Recycle_Bin()
|
||||
|
||||
@@ -7,10 +7,11 @@ using Umbraco.Cms.Core.Services.Navigation;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
public partial class DocumentNavigationServiceTests
|
||||
internal sealed partial class DocumentNavigationServiceTests
|
||||
{
|
||||
[Test]
|
||||
public async Task Structure_Can_Rebuild()
|
||||
[TestCase(1, TestName = "Structure_Can_Rebuild")]
|
||||
[TestCase(2, TestName = "Structure_Can_Rebuild_MultipleTimes")]
|
||||
public async Task Structure_Can_Rebuild(int numberOfRebuilds)
|
||||
{
|
||||
// Arrange
|
||||
Guid nodeKey = Root.Key;
|
||||
@@ -21,6 +22,7 @@ public partial class DocumentNavigationServiceTests
|
||||
DocumentNavigationQueryService.TryGetDescendantsKeys(nodeKey, out IEnumerable<Guid> originalDescendantsKeys);
|
||||
DocumentNavigationQueryService.TryGetAncestorsKeys(nodeKey, out IEnumerable<Guid> originalAncestorsKeys);
|
||||
DocumentNavigationQueryService.TryGetSiblingsKeys(nodeKey, out IEnumerable<Guid> originalSiblingsKeys);
|
||||
DocumentNavigationQueryService.TryGetRootKeys(out IEnumerable<Guid> originalRouteKeys);
|
||||
|
||||
// In-memory navigation structure is empty here
|
||||
var newDocumentNavigationService = new DocumentNavigationService(
|
||||
@@ -30,7 +32,10 @@ public partial class DocumentNavigationServiceTests
|
||||
var initialNodeExists = newDocumentNavigationService.TryGetParentKey(nodeKey, out _);
|
||||
|
||||
// Act
|
||||
await newDocumentNavigationService.RebuildAsync();
|
||||
for (int i = 0; i < numberOfRebuilds; i++)
|
||||
{
|
||||
await newDocumentNavigationService.RebuildAsync();
|
||||
}
|
||||
|
||||
// Capture rebuilt state
|
||||
var nodeExists = newDocumentNavigationService.TryGetParentKey(nodeKey, out Guid? parentKeyFromRebuild);
|
||||
@@ -38,6 +43,7 @@ public partial class DocumentNavigationServiceTests
|
||||
newDocumentNavigationService.TryGetDescendantsKeys(nodeKey, out IEnumerable<Guid> descendantsKeysFromRebuild);
|
||||
newDocumentNavigationService.TryGetAncestorsKeys(nodeKey, out IEnumerable<Guid> ancestorsKeysFromRebuild);
|
||||
newDocumentNavigationService.TryGetSiblingsKeys(nodeKey, out IEnumerable<Guid> siblingsKeysFromRebuild);
|
||||
newDocumentNavigationService.TryGetRootKeys(out IEnumerable<Guid> routeKeysFromRebuild);
|
||||
|
||||
// Assert
|
||||
Assert.Multiple(() =>
|
||||
@@ -53,11 +59,13 @@ public partial class DocumentNavigationServiceTests
|
||||
CollectionAssert.AreEquivalent(originalDescendantsKeys, descendantsKeysFromRebuild);
|
||||
CollectionAssert.AreEquivalent(originalAncestorsKeys, ancestorsKeysFromRebuild);
|
||||
CollectionAssert.AreEquivalent(originalSiblingsKeys, siblingsKeysFromRebuild);
|
||||
CollectionAssert.AreEquivalent(originalRouteKeys, routeKeysFromRebuild);
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task Bin_Structure_Can_Rebuild()
|
||||
[TestCase(1, TestName = "Bin_Structure_Can_Rebuild")]
|
||||
[TestCase(2, TestName = "Bin_Structure_Can_Rebuild_MultipleTimes")]
|
||||
public async Task Bin_Structure_Can_Rebuild(int numberOfRebuilds)
|
||||
{
|
||||
// Arrange
|
||||
Guid nodeKey = Root.Key;
|
||||
@@ -69,6 +77,7 @@ public partial class DocumentNavigationServiceTests
|
||||
DocumentNavigationQueryService.TryGetDescendantsKeysInBin(nodeKey, out IEnumerable<Guid> originalDescendantsKeys);
|
||||
DocumentNavigationQueryService.TryGetAncestorsKeysInBin(nodeKey, out IEnumerable<Guid> originalAncestorsKeys);
|
||||
DocumentNavigationQueryService.TryGetSiblingsKeysInBin(nodeKey, out IEnumerable<Guid> originalSiblingsKeys);
|
||||
DocumentNavigationQueryService.TryGetRootKeys(out IEnumerable<Guid> originalRouteKeys);
|
||||
|
||||
// In-memory navigation structure is empty here
|
||||
var newDocumentNavigationService = new DocumentNavigationService(
|
||||
@@ -78,7 +87,10 @@ public partial class DocumentNavigationServiceTests
|
||||
var initialNodeExists = newDocumentNavigationService.TryGetParentKeyInBin(nodeKey, out _);
|
||||
|
||||
// Act
|
||||
await newDocumentNavigationService.RebuildBinAsync();
|
||||
for (int i = 0; i < numberOfRebuilds; i++)
|
||||
{
|
||||
await newDocumentNavigationService.RebuildBinAsync();
|
||||
}
|
||||
|
||||
// Capture rebuilt state
|
||||
var nodeExists = newDocumentNavigationService.TryGetParentKeyInBin(nodeKey, out Guid? parentKeyFromRebuild);
|
||||
@@ -86,6 +98,7 @@ public partial class DocumentNavigationServiceTests
|
||||
newDocumentNavigationService.TryGetDescendantsKeysInBin(nodeKey, out IEnumerable<Guid> descendantsKeysFromRebuild);
|
||||
newDocumentNavigationService.TryGetAncestorsKeysInBin(nodeKey, out IEnumerable<Guid> ancestorsKeysFromRebuild);
|
||||
newDocumentNavigationService.TryGetSiblingsKeysInBin(nodeKey, out IEnumerable<Guid> siblingsKeysFromRebuild);
|
||||
newDocumentNavigationService.TryGetRootKeys(out IEnumerable<Guid> routeKeysFromRebuild);
|
||||
|
||||
// Assert
|
||||
Assert.Multiple(() =>
|
||||
@@ -101,6 +114,7 @@ public partial class DocumentNavigationServiceTests
|
||||
CollectionAssert.AreEquivalent(originalDescendantsKeys, descendantsKeysFromRebuild);
|
||||
CollectionAssert.AreEquivalent(originalAncestorsKeys, ancestorsKeysFromRebuild);
|
||||
CollectionAssert.AreEquivalent(originalSiblingsKeys, siblingsKeysFromRebuild);
|
||||
CollectionAssert.AreEquivalent(originalRouteKeys, routeKeysFromRebuild);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ using Umbraco.Cms.Core;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
public partial class DocumentNavigationServiceTests
|
||||
internal sealed partial class DocumentNavigationServiceTests
|
||||
{
|
||||
[Test]
|
||||
[TestCase("E856AC03-C23E-4F63-9AA9-681B42A58573", "C6173927-0C59-4778-825D-D7B9F45D8DDE")] // Grandchild 1 to Child 1
|
||||
|
||||
@@ -4,7 +4,7 @@ using Umbraco.Cms.Core.Models.ContentEditing;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
public partial class DocumentNavigationServiceTests
|
||||
internal sealed partial class DocumentNavigationServiceTests
|
||||
{
|
||||
[Test]
|
||||
public async Task Structure_Updates_When_Reversing_Children_Sort_Order()
|
||||
|
||||
@@ -4,7 +4,7 @@ using Umbraco.Cms.Core.Models.ContentEditing;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
public partial class DocumentNavigationServiceTests
|
||||
internal sealed partial class DocumentNavigationServiceTests
|
||||
{
|
||||
[Test]
|
||||
public async Task Structure_Does_Not_Update_When_Updating_Content()
|
||||
|
||||
@@ -6,7 +6,7 @@ using Umbraco.Cms.Tests.Common.Builders;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
public partial class DocumentNavigationServiceTests : DocumentNavigationServiceTestsBase
|
||||
internal sealed partial class DocumentNavigationServiceTests : DocumentNavigationServiceTestsBase
|
||||
{
|
||||
[SetUp]
|
||||
public async Task Setup()
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
[TestFixture]
|
||||
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)]
|
||||
public abstract class DocumentNavigationServiceTestsBase : UmbracoIntegrationTest
|
||||
internal abstract class DocumentNavigationServiceTestsBase : UmbracoIntegrationTest
|
||||
{
|
||||
protected IContentTypeService ContentTypeService => GetRequiredService<IContentTypeService>();
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
[TestFixture]
|
||||
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, Logger = UmbracoTestOptions.Logger.Mock)]
|
||||
public class DocumentUrlServiceTests : UmbracoIntegrationTestWithContent
|
||||
internal sealed class DocumentUrlServiceTests : UmbracoIntegrationTestWithContent
|
||||
{
|
||||
private const string SubSubPage2Key = "48AE405E-5142-4EBE-929F-55EB616F51F2";
|
||||
private const string SubSubPage3Key = "AACF2979-3F53-4184-B071-BA34D3338497";
|
||||
@@ -230,7 +230,7 @@ public class DocumentUrlServiceTests : UmbracoIntegrationTestWithContent
|
||||
// Create a subpage
|
||||
var subsubpage = ContentBuilder.CreateSimpleContent(ContentType, documentName, Subpage.Id);
|
||||
subsubpage.Key = Guid.Parse(documentKey);
|
||||
var contentSchedule = ContentScheduleCollection.CreateWithEntry(DateTime.Now.AddMinutes(-5), null);
|
||||
var contentSchedule = ContentScheduleCollection.CreateWithEntry(DateTime.UtcNow.AddMinutes(-5), null);
|
||||
ContentService.Save(subsubpage, -1, contentSchedule);
|
||||
|
||||
if (loadDraft is false)
|
||||
@@ -248,7 +248,7 @@ public class DocumentUrlServiceTests : UmbracoIntegrationTestWithContent
|
||||
// Create a second root
|
||||
var secondRoot = ContentBuilder.CreateSimpleContent(ContentType, "Second Root", null);
|
||||
secondRoot.Key = new Guid("8E21BCD4-02CA-483D-84B0-1FC92702E198");
|
||||
var contentSchedule = ContentScheduleCollection.CreateWithEntry(DateTime.Now.AddMinutes(-5), null);
|
||||
var contentSchedule = ContentScheduleCollection.CreateWithEntry(DateTime.UtcNow.AddMinutes(-5), null);
|
||||
ContentService.Save(secondRoot, -1, contentSchedule);
|
||||
|
||||
if (loadDraft is false)
|
||||
@@ -266,7 +266,7 @@ public class DocumentUrlServiceTests : UmbracoIntegrationTestWithContent
|
||||
{
|
||||
// Create a second root
|
||||
var secondRoot = ContentBuilder.CreateSimpleContent(ContentType, "Second Root", null);
|
||||
var contentSchedule = ContentScheduleCollection.CreateWithEntry(DateTime.Now.AddMinutes(-5), null);
|
||||
var contentSchedule = ContentScheduleCollection.CreateWithEntry(DateTime.UtcNow.AddMinutes(-5), null);
|
||||
ContentService.Save(secondRoot, -1, contentSchedule);
|
||||
|
||||
// Create a child of second root
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
[TestFixture]
|
||||
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, Logger = UmbracoTestOptions.Logger.Console)]
|
||||
public class DocumentUrlServiceTests_HideTopLevel_False : UmbracoIntegrationTestWithContent
|
||||
internal sealed class DocumentUrlServiceTests_HideTopLevel_False : UmbracoIntegrationTestWithContent
|
||||
{
|
||||
protected IDocumentUrlService DocumentUrlService => GetRequiredService<IDocumentUrlService>();
|
||||
protected ILanguageService LanguageService => GetRequiredService<ILanguageService>();
|
||||
@@ -62,7 +62,7 @@ public class DocumentUrlServiceTests_HideTopLevel_False : UmbracoIntegrationTest
|
||||
// Create a subpage
|
||||
var subsubpage = ContentBuilder.CreateSimpleContent(ContentType, "Sub Page 1", Subpage.Id);
|
||||
subsubpage.Key = new Guid("DF49F477-12F2-4E33-8563-91A7CC1DCDBB");
|
||||
var contentSchedule = ContentScheduleCollection.CreateWithEntry(DateTime.Now.AddMinutes(-5), null);
|
||||
var contentSchedule = ContentScheduleCollection.CreateWithEntry(DateTime.UtcNow.AddMinutes(-5), null);
|
||||
ContentService.Save(subsubpage, -1, contentSchedule);
|
||||
|
||||
if (loadDraft is false)
|
||||
@@ -81,7 +81,7 @@ public class DocumentUrlServiceTests_HideTopLevel_False : UmbracoIntegrationTest
|
||||
// Create a second root
|
||||
var secondRoot = ContentBuilder.CreateSimpleContent(ContentType, "Second Root", null);
|
||||
secondRoot.Key = new Guid("8E21BCD4-02CA-483D-84B0-1FC92702E198");
|
||||
var contentSchedule = ContentScheduleCollection.CreateWithEntry(DateTime.Now.AddMinutes(-5), null);
|
||||
var contentSchedule = ContentScheduleCollection.CreateWithEntry(DateTime.UtcNow.AddMinutes(-5), null);
|
||||
ContentService.Save(secondRoot, -1, contentSchedule);
|
||||
|
||||
if (loadDraft is false)
|
||||
@@ -100,7 +100,7 @@ public class DocumentUrlServiceTests_HideTopLevel_False : UmbracoIntegrationTest
|
||||
{
|
||||
// Create a second root
|
||||
var secondRoot = ContentBuilder.CreateSimpleContent(ContentType, "Second Root", null);
|
||||
var contentSchedule = ContentScheduleCollection.CreateWithEntry(DateTime.Now.AddMinutes(-5), null);
|
||||
var contentSchedule = ContentScheduleCollection.CreateWithEntry(DateTime.UtcNow.AddMinutes(-5), null);
|
||||
ContentService.Save(secondRoot, -1, contentSchedule);
|
||||
|
||||
// Create a child of second root
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
[TestFixture]
|
||||
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)]
|
||||
[SuppressMessage("ReSharper", "NotNullOrRequiredMemberIsNotInitialized")]
|
||||
public class DynamicRootServiceTests : UmbracoIntegrationTest
|
||||
internal sealed class DynamicRootServiceTests : UmbracoIntegrationTest
|
||||
{
|
||||
public enum DynamicRootOrigin
|
||||
{
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
[TestFixture]
|
||||
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)]
|
||||
public class ElementSwitchValidatorTests : UmbracoIntegrationTest
|
||||
internal sealed class ElementSwitchValidatorTests : UmbracoIntegrationTest
|
||||
{
|
||||
private IElementSwitchValidator ElementSwitchValidator => GetRequiredService<IElementSwitchValidator>();
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
[TestFixture]
|
||||
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)]
|
||||
public class LogViewerServiceTests : UmbracoIntegrationTest
|
||||
internal sealed class LogViewerServiceTests : UmbracoIntegrationTest
|
||||
{
|
||||
private ILogViewerService LogViewerService => GetRequiredService<ILogViewerService>();
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using NUnit.Framework;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.ContentEditing;
|
||||
@@ -11,7 +11,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
[TestFixture]
|
||||
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)]
|
||||
public class MediaEditingServiceTests : UmbracoIntegrationTest
|
||||
internal sealed class MediaEditingServiceTests : UmbracoIntegrationTest
|
||||
{
|
||||
protected IMediaTypeService MediaTypeService => GetRequiredService<IMediaTypeService>();
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ using Umbraco.Cms.Core;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
public partial class MediaNavigationServiceTests
|
||||
internal sealed partial class MediaNavigationServiceTests
|
||||
{
|
||||
[Test]
|
||||
public async Task Structure_Updates_When_Creating_Media_At_Root()
|
||||
|
||||
@@ -3,7 +3,7 @@ using Umbraco.Cms.Core;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
public partial class MediaNavigationServiceTests
|
||||
internal sealed partial class MediaNavigationServiceTests
|
||||
{
|
||||
[Test]
|
||||
[TestCase("1CD97C02-8534-4B72-AE9E-AE52EC94CF31")] // Album
|
||||
|
||||
@@ -3,7 +3,7 @@ using Umbraco.Cms.Core;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
public partial class MediaNavigationServiceTests
|
||||
internal sealed partial class MediaNavigationServiceTests
|
||||
{
|
||||
[Test]
|
||||
public async Task Structure_Updates_When_Deleting_From_Recycle_Bin()
|
||||
|
||||
@@ -3,7 +3,7 @@ using Umbraco.Cms.Core;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
public partial class MediaNavigationServiceTests
|
||||
internal sealed partial class MediaNavigationServiceTests
|
||||
{
|
||||
[Test]
|
||||
[TestCase("62BCE72F-8C18-420E-BCAC-112B5ECC95FD", "139DC977-E50F-4382-9728-B278C4B7AC6A")] // Image 4 to Sub-album 1
|
||||
|
||||
@@ -3,7 +3,7 @@ using Umbraco.Cms.Core;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
public partial class MediaNavigationServiceTests
|
||||
internal sealed partial class MediaNavigationServiceTests
|
||||
{
|
||||
[Test]
|
||||
public async Task Structure_Updates_When_Moving_Media_To_Recycle_Bin()
|
||||
|
||||
@@ -7,7 +7,7 @@ using Umbraco.Cms.Core.Services.Navigation;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
public partial class MediaNavigationServiceTests
|
||||
internal sealed partial class MediaNavigationServiceTests
|
||||
{
|
||||
[Test]
|
||||
public async Task Structure_Can_Rebuild()
|
||||
|
||||
@@ -3,7 +3,7 @@ using Umbraco.Cms.Core;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
public partial class MediaNavigationServiceTests
|
||||
internal sealed partial class MediaNavigationServiceTests
|
||||
{
|
||||
[Test]
|
||||
[TestCase("62BCE72F-8C18-420E-BCAC-112B5ECC95FD", "139DC977-E50F-4382-9728-B278C4B7AC6A")] // Image 4 to Sub-album 1
|
||||
|
||||
@@ -4,7 +4,7 @@ using Umbraco.Cms.Core.Models.ContentEditing;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
public partial class MediaNavigationServiceTests
|
||||
internal sealed partial class MediaNavigationServiceTests
|
||||
{
|
||||
[Test]
|
||||
public async Task Structure_Updates_When_Reversing_Children_Sort_Order()
|
||||
|
||||
@@ -4,9 +4,9 @@ using Umbraco.Cms.Core.Models.ContentEditing;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
public partial class MediaNavigationServiceTests
|
||||
internal sealed partial class MediaNavigationServiceTests
|
||||
{
|
||||
[Test]
|
||||
[Test]
|
||||
public async Task Structure_Does_Not_Update_When_Updating_Media()
|
||||
{
|
||||
// Arrange
|
||||
|
||||
@@ -4,7 +4,7 @@ using Umbraco.Cms.Core.Scoping;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
public partial class MediaNavigationServiceTests : MediaNavigationServiceTestsBase
|
||||
internal sealed partial class MediaNavigationServiceTests : MediaNavigationServiceTestsBase
|
||||
{
|
||||
[SetUp]
|
||||
public async Task Setup()
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
[TestFixture]
|
||||
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)]
|
||||
public abstract class MediaNavigationServiceTestsBase : UmbracoIntegrationTest
|
||||
internal abstract class MediaNavigationServiceTestsBase : UmbracoIntegrationTest
|
||||
{
|
||||
protected IMediaTypeService MediaTypeService => GetRequiredService<IMediaTypeService>();
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
public partial class MediaTypeEditingServiceTests
|
||||
internal sealed partial class MediaTypeEditingServiceTests
|
||||
{
|
||||
[Test]
|
||||
public async Task Can_Create_With_All_Basic_Settings()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using NUnit.Framework;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
/// even though those share a base implementation.
|
||||
/// For a more detailed test suite on compositions, check <see cref="ContentTypeEditingServiceTests" />.
|
||||
/// </summary>
|
||||
public partial class MediaTypeEditingServiceTests
|
||||
internal sealed partial class MediaTypeEditingServiceTests
|
||||
{
|
||||
[Test]
|
||||
public async Task Can_Get_Available_Compositions_Only_From_Media_Type_Key()
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
using NUnit.Framework;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
public partial class MediaTypeEditingServiceTests
|
||||
internal sealed partial class MediaTypeEditingServiceTests
|
||||
{
|
||||
[Test]
|
||||
public async Task Can_Get_Default_Folder_Media_Type()
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
using NUnit.Framework;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
public partial class MediaTypeEditingServiceTests
|
||||
internal sealed partial class MediaTypeEditingServiceTests
|
||||
{
|
||||
[TestCase("jpg", Constants.Conventions.MediaTypes.Image)]
|
||||
[TestCase("png", Constants.Conventions.MediaTypes.Image)]
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
using NUnit.Framework;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
public partial class MediaTypeEditingServiceTests
|
||||
internal sealed partial class MediaTypeEditingServiceTests
|
||||
{
|
||||
[Test]
|
||||
public async Task Can_Update_All_Basic_Settings()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Umbraco.Cms.Core.Media;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
/// Tests for the media type editing service. Please notice that a lot of functional test is covered by the content type
|
||||
/// editing service tests, since these services share the same base implementation.
|
||||
/// </summary>
|
||||
public partial class MediaTypeEditingServiceTests : ContentTypeEditingServiceTestsBase
|
||||
internal sealed partial class MediaTypeEditingServiceTests : ContentTypeEditingServiceTestsBase
|
||||
{
|
||||
protected override void ConfigureTestServices(IServiceCollection services)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using NUnit.Framework;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
@@ -12,7 +12,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
/// </summary>
|
||||
[TestFixture]
|
||||
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)]
|
||||
public class MemberGroupServiceTests : UmbracoIntegrationTest
|
||||
internal sealed class MemberGroupServiceTests : UmbracoIntegrationTest
|
||||
{
|
||||
private IMemberGroupService MemberGroupService => GetRequiredService<IMemberGroupService>();
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using NUnit.Framework;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.ContentTypeEditing;
|
||||
@@ -13,7 +13,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
/// Tests for the member type editing service. Please notice that a lot of functional test is covered by the content type
|
||||
/// editing service tests, since these services share the same base implementation.
|
||||
/// </summary>
|
||||
public class MemberTypeEditingServiceTests : ContentTypeEditingServiceTestsBase
|
||||
internal sealed class MemberTypeEditingServiceTests : ContentTypeEditingServiceTestsBase
|
||||
{
|
||||
private IMemberTypeEditingService MemberTypeEditingService => GetRequiredService<IMemberTypeEditingService>();
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
[TestFixture]
|
||||
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)]
|
||||
public class MetricsConsentServiceTest : UmbracoIntegrationTest
|
||||
internal sealed class MetricsConsentServiceTest : UmbracoIntegrationTest
|
||||
{
|
||||
private IMetricsConsentService MetricsConsentService => GetRequiredService<IMetricsConsentService>();
|
||||
|
||||
|
||||
@@ -1,33 +1,23 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core.Cache;
|
||||
using Umbraco.Cms.Core.Handlers;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.ContentEditing;
|
||||
using Umbraco.Cms.Core.Notifications;
|
||||
using Umbraco.Cms.Core.Persistence.Repositories;
|
||||
using Umbraco.Cms.Core.Scoping;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Services.Navigation;
|
||||
using Umbraco.Cms.Core.Sync;
|
||||
using Umbraco.Cms.Infrastructure.DependencyInjection;
|
||||
using Umbraco.Cms.Infrastructure.Examine;
|
||||
using Umbraco.Cms.Infrastructure.Examine.DependencyInjection;
|
||||
using Umbraco.Cms.Infrastructure.HostedServices;
|
||||
using Umbraco.Cms.Infrastructure.Search;
|
||||
using Umbraco.Cms.Tests.Common.Attributes;
|
||||
using Umbraco.Cms.Tests.Common.Builders;
|
||||
using Umbraco.Cms.Tests.Common.Testing;
|
||||
using Umbraco.Cms.Tests.Integration.Testing;
|
||||
using Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Scoping;
|
||||
using Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
[TestFixture]
|
||||
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, Logger = UmbracoTestOptions.Logger.Mock)]
|
||||
public class PublishStatusServiceTest : UmbracoIntegrationTestWithContent
|
||||
internal sealed class PublishStatusServiceTest : UmbracoIntegrationTestWithContent
|
||||
{
|
||||
protected IPublishStatusQueryService PublishStatusQueryService => GetRequiredService<IPublishStatusQueryService>();
|
||||
|
||||
@@ -164,7 +154,7 @@ public class PublishStatusServiceTest : UmbracoIntegrationTestWithContent
|
||||
{
|
||||
var grandchild = ContentBuilder.CreateSimpleContent(ContentType, "Grandchild", Subpage2.Id);
|
||||
|
||||
var contentSchedule = ContentScheduleCollection.CreateWithEntry(DateTime.Now.AddMinutes(-5), null);
|
||||
var contentSchedule = ContentScheduleCollection.CreateWithEntry(DateTime.UtcNow.AddMinutes(-5), null);
|
||||
ContentService.Save(grandchild, -1, contentSchedule);
|
||||
|
||||
var publishResults = ContentService.PublishBranch(Textpage, PublishBranchFilter.IncludeUnpublished, ["*"]);
|
||||
|
||||
@@ -4,7 +4,7 @@ using Umbraco.Cms.Tests.Common.Builders;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
public class PublishedUrlInfoProviderTests : PublishedUrlInfoProviderTestsBase
|
||||
internal sealed class PublishedUrlInfoProviderTests : PublishedUrlInfoProviderTestsBase
|
||||
{
|
||||
|
||||
[Test]
|
||||
@@ -12,7 +12,7 @@ public class PublishedUrlInfoProviderTests : PublishedUrlInfoProviderTestsBase
|
||||
{
|
||||
// Create a second root
|
||||
var secondRoot = ContentBuilder.CreateSimpleContent(ContentType, "Second Root", null);
|
||||
var contentSchedule = ContentScheduleCollection.CreateWithEntry(DateTime.Now.AddMinutes(-5), null);
|
||||
var contentSchedule = ContentScheduleCollection.CreateWithEntry(DateTime.UtcNow.AddMinutes(-5), null);
|
||||
ContentService.Save(secondRoot, -1, contentSchedule);
|
||||
|
||||
// Create a child of second root
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
[TestFixture]
|
||||
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, Logger = UmbracoTestOptions.Logger.Mock)]
|
||||
public abstract class PublishedUrlInfoProviderTestsBase : UmbracoIntegrationTestWithContent
|
||||
internal abstract class PublishedUrlInfoProviderTestsBase : UmbracoIntegrationTestWithContent
|
||||
{
|
||||
protected IDocumentUrlService DocumentUrlService => GetRequiredService<IDocumentUrlService>();
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ using Umbraco.Cms.Tests.Common.Builders;
|
||||
|
||||
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
public class PublishedUrlInfoProvider_hidetoplevel_false : PublishedUrlInfoProviderTestsBase
|
||||
internal sealed class PublishedUrlInfoProvider_hidetoplevel_false : PublishedUrlInfoProviderTestsBase
|
||||
{
|
||||
protected override void CustomTestSetup(IUmbracoBuilder builder)
|
||||
{
|
||||
@@ -19,7 +19,7 @@ public class PublishedUrlInfoProvider_hidetoplevel_false : PublishedUrlInfoProvi
|
||||
{
|
||||
// Create a second root
|
||||
var secondRoot = ContentBuilder.CreateSimpleContent(ContentType, "Second Root", null);
|
||||
var contentSchedule = ContentScheduleCollection.CreateWithEntry(DateTime.Now.AddMinutes(-5), null);
|
||||
var contentSchedule = ContentScheduleCollection.CreateWithEntry(DateTime.UtcNow.AddMinutes(-5), null);
|
||||
ContentService.Save(secondRoot, -1, contentSchedule);
|
||||
|
||||
// Create a child of second root
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Castle.Components.DictionaryAdapter.Xml;
|
||||
using Castle.Components.DictionaryAdapter.Xml;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
@@ -13,7 +13,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
[TestFixture]
|
||||
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)]
|
||||
public class RelationServiceTests : UmbracoIntegrationTest
|
||||
internal sealed class RelationServiceTests : UmbracoIntegrationTest
|
||||
{
|
||||
private IRelationService RelationService => GetRequiredService<IRelationService>();
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
/// </summary>
|
||||
[TestFixture]
|
||||
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)]
|
||||
public class TelemetryProviderTests : UmbracoIntegrationTest
|
||||
internal sealed class TelemetryProviderTests : UmbracoIntegrationTest
|
||||
{
|
||||
private IContentTypeService ContentTypeService => GetRequiredService<IContentTypeService>();
|
||||
|
||||
@@ -48,6 +48,8 @@ public class TelemetryProviderTests : UmbracoIntegrationTest
|
||||
|
||||
private IUserService UserService => GetRequiredService<IUserService>();
|
||||
|
||||
private IUserGroupService UserGroupService => GetRequiredService<IUserGroupService>();
|
||||
|
||||
private IMediaService MediaService => GetRequiredService<IMediaService>();
|
||||
|
||||
private IMediaTypeService MediaTypeService => GetRequiredService<IMediaTypeService>();
|
||||
@@ -266,11 +268,11 @@ public class TelemetryProviderTests : UmbracoIntegrationTest
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void UserTelemetry_Can_Get_With_Saved_UserGroups()
|
||||
public async Task UserTelemetry_Can_Get_With_Saved_UserGroups()
|
||||
{
|
||||
var userGroup = BuildUserGroup("testGroup");
|
||||
|
||||
UserService.Save(userGroup);
|
||||
await UserGroupService.CreateAsync(userGroup, Constants.Security.SuperUserKey);
|
||||
var result = UserTelemetryProvider.GetInformation()
|
||||
.FirstOrDefault(x => x.Name == Constants.Telemetry.UserGroupCount);
|
||||
|
||||
@@ -278,14 +280,13 @@ public class TelemetryProviderTests : UmbracoIntegrationTest
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void UserTelemetry_Can_Get_More_UserGroups()
|
||||
public async Task UserTelemetry_Can_Get_More_UserGroups()
|
||||
{
|
||||
var userGroups = BuildUserGroups(100);
|
||||
|
||||
|
||||
foreach (var userGroup in userGroups)
|
||||
{
|
||||
UserService.Save(userGroup);
|
||||
await UserGroupService.CreateAsync(userGroup, Constants.Security.SuperUserKey);
|
||||
}
|
||||
|
||||
var result = UserTelemetryProvider.GetInformation()
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
using Umbraco.Cms.Core.Models.TemporaryFile;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Services.OperationStatus;
|
||||
using Umbraco.Cms.Tests.Common.Testing;
|
||||
using Umbraco.Cms.Tests.Integration.Attributes;
|
||||
using Umbraco.Cms.Tests.Integration.Testing;
|
||||
|
||||
namespace Umbraco.Cms.Tests.UnitTests.Umbraco.Core.Services;
|
||||
|
||||
[TestFixture]
|
||||
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerFixture)]
|
||||
public class TemporaryFileServiceTests : UmbracoIntegrationTest
|
||||
{
|
||||
private ITemporaryFileService TemporaryFileService => GetRequiredService<ITemporaryFileService>();
|
||||
|
||||
public static void ConfigureAllowedUploadedFileExtensions(IUmbracoBuilder builder)
|
||||
{
|
||||
builder.Services.Configure<ContentSettings>(config =>
|
||||
config.AllowedUploadedFileExtensions = new HashSet<string> { "txt" });
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ConfigureBuilder(ActionName = nameof(ConfigureAllowedUploadedFileExtensions))]
|
||||
public async Task Can_Create_Get_And_Delete_Temporary_File()
|
||||
{
|
||||
var key = Guid.NewGuid();
|
||||
const string FileName = "test.txt";
|
||||
const string FileContents = "test";
|
||||
var model = new CreateTemporaryFileModel
|
||||
{
|
||||
FileName = FileName,
|
||||
Key = key,
|
||||
OpenReadStream = () =>
|
||||
{
|
||||
var stream = new MemoryStream();
|
||||
var writer = new StreamWriter(stream);
|
||||
writer.Write(FileContents);
|
||||
writer.Flush();
|
||||
stream.Position = 0;
|
||||
return stream;
|
||||
}
|
||||
};
|
||||
var createAttempt = await TemporaryFileService.CreateAsync(model);
|
||||
Assert.IsTrue(createAttempt.Success);
|
||||
|
||||
TemporaryFileModel? fileModel = await TemporaryFileService.GetAsync(key);
|
||||
Assert.IsNotNull(fileModel);
|
||||
Assert.AreEqual(key, fileModel.Key);
|
||||
Assert.AreEqual(FileName, fileModel.FileName);
|
||||
|
||||
using (var reader = new StreamReader(fileModel.OpenReadStream()))
|
||||
{
|
||||
string fileContents = reader.ReadToEnd();
|
||||
Assert.AreEqual(FileContents, fileContents);
|
||||
}
|
||||
|
||||
var deleteAttempt = await TemporaryFileService.DeleteAsync(key);
|
||||
Assert.IsTrue(createAttempt.Success);
|
||||
|
||||
fileModel = await TemporaryFileService.GetAsync(key);
|
||||
Assert.IsNull(fileModel);
|
||||
}
|
||||
|
||||
[Test]
|
||||
[ConfigureBuilder(ActionName = nameof(ConfigureAllowedUploadedFileExtensions))]
|
||||
public async Task Cannot_Create_File_Outside_Of_Temporary_Files_Root()
|
||||
{
|
||||
var key = Guid.NewGuid();
|
||||
const string FileName = "../test.txt";
|
||||
var model = new CreateTemporaryFileModel
|
||||
{
|
||||
FileName = FileName,
|
||||
Key = key,
|
||||
OpenReadStream = () =>
|
||||
{
|
||||
var stream = new MemoryStream();
|
||||
var writer = new StreamWriter(stream);
|
||||
writer.Write(string.Empty);
|
||||
writer.Flush();
|
||||
stream.Position = 0;
|
||||
return stream;
|
||||
}
|
||||
};
|
||||
var createAttempt = await TemporaryFileService.CreateAsync(model);
|
||||
Assert.IsFalse(createAttempt.Success);
|
||||
Assert.AreEqual(TemporaryFileOperationStatus.InvalidFileName, createAttempt.Status);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
using NUnit.Framework;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models.Membership;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
@@ -11,7 +11,7 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
|
||||
|
||||
[TestFixture]
|
||||
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)]
|
||||
public class UserGroupServiceValidationTests : UmbracoIntegrationTest
|
||||
internal sealed class UserGroupServiceValidationTests : UmbracoIntegrationTest
|
||||
{
|
||||
private IUserGroupService UserGroupService => GetRequiredService<IUserGroupService>();
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user