New backoffice: User controller (#13947)

* Add UserResponseModel

* Add factory to created UserResponseModel

* Add GetByKey controller

* Add GetAllUsers endpoint

* User proper response model

* Make naming consistent

* Order by username in GetAll

* Add user filter endpoint

* Fix includer user states

* Remove gravatar from the backend

* Send user avatars in response

* Add create user model

* start working on create

* Validate the create model

* Add authorization to create

* Use UserRepository instead of UserService to ValidateSessíonId

* Create IBackofficeUserStore interface

This is essentially a core-friendly version of the BackOfficeUserStore, additionally it contains basic methods for managing users, I.E. Get users, save users, create users, etc.

* Remove more usages of user service

* Remove usages of IUserService in BackofficeUserStore

* Add documentation

* Fix tests and DI

* add IBackOfficeUserStoreAccessor to resolve it in singleton services

* Resolve circular dependency

* Remove obsolete constructor

* Add core friendly user manager

* Finish createasync in user service

* Add WIP create endpoint

* Save newly creates users user groups

* Use service scope for user service

* Remove now unnecessary accessors

* Add response types

* Add update user endpoint

* Add EmailUserInviteSender

* Add technology free way of creating confirmation token

* Add invite uri provider

* Add invite user to user service

* Add invite user controller

* Add delete endpoint

* Add operation status responses

* Add operation status responses

* Added temporary file uploads including a repository implementation using local temp folder.

* Add Disable users endpoint

* missing files

* Fixed copy paste error

* Fix create users return type

* Updated OpenApi.json

* Updated OpenApi.json

* Handle if created failed in identity

* Add enable user

* Make users plural in enable/disable

We're doing the operation on multiple entities

* Added file extension check

* Add unlock user endpoint

* Clean up. Removed old TemporaryFileService and UploadFileService and updated dictionary items to use this new items

* Clean up

* Add reset password

* Add UpdateUserGroupsOnUsers method

* Add UpdateUserGroups

* Get rid of stream directly on TemporaryFileModel, and use delegate to open stream instead.

* Fix post merge

* Use keys instead of IDs

* Add ClearAvatar endpoint

* Review changes

* Moved models to their own files

* Reverted launch settings

* Move enlist extension to its own namespace

* Create set avatar endpoint

* Add reponse types

* Remove infrastructure extension after merge

* Add Cmapatibility suppressions

* Add test suppression

* Add integration tests

* Fix issue found in tests

* Add invited user to UserInvitationResult

* Add more tests

* Add update tests

* Hide different tests under parent

* Return DuplicatUserName user operation status if username matches an email

* Add update tests

* Change sorted set to HashSet

It doesn't work if it's not IComparable

* Change ID to Key when checking super

* Add get tests

* Add more GetAllTests

* Move tests to the right namespace

* Add filter test

* Fix including disabled users bug found by test

* Add test to ensure invited user state

* Add test case for UserState.All

* Add more filter tests

* Add enable disable tests

* Add resolver for keys and ids

* Replace usages of IUserService with IUserIdKeyResolver

* Add CompatibilitySuppressions

* Add UserIdKeyResolverTests

* Fix UserIdKeyResolver

* Add missing user operation results

* Updates from review

* ID not key

* Post instead of patch

* Use set instead of params for enable/disable

* Don't call to array

* Use sets for usergroup keys and user keys instead

* LanguageIsoCode instead of Language

* Update CompatibilitySuppressions after changin enumerable to set

---------

Co-authored-by: Bjarke Berg <mail@bergmania.dk>
Co-authored-by: kjac <kja@umbraco.dk>
This commit is contained in:
Mole
2023-03-29 08:14:47 +02:00
committed by GitHub
parent 313eed96b9
commit 9b626d02c8
95 changed files with 4254 additions and 326 deletions

View File

@@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- https://learn.microsoft.com/en-us/dotnet/fundamentals/package-validation/diagnostic-ids -->
<Suppressions xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>

View File

@@ -0,0 +1,143 @@
using NUnit.Framework;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.Membership;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Services.OperationStatus;
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
public partial class UserServiceCrudTests
{
[Test]
[TestCase("test@email.com", "test@email.com", true, true)]
[TestCase("test@email.com", "notTheUserName@email.com", true, false)]
[TestCase("NotAnEmail", "test@email.com", true, false)]
[TestCase("test@email.com", "test@email.com", false, true)]
[TestCase("NotAnEmail", "test@email.com", false, true)]
[TestCase("aDifferentEmail@email.com", "test@email.com", false, true)]
public async Task Creating_User_Name_Must_Be_Email(
string username,
string email,
bool userNameIsEmailEnabled,
bool shouldSucceed)
{
var securitySettings = new SecuritySettings { UsernameIsEmail = userNameIsEmailEnabled };
var userService = CreateUserService(securitySettings);
var userGroup = await UserGroupService.GetAsync(Constants.Security.AdminGroupAlias);
var creationModel = new UserCreateModel
{
UserName = username,
Email = email,
Name = "Test Mc. Gee",
UserGroups = new HashSet<IUserGroup> { userGroup! }
};
var result = await userService.CreateAsync(Constants.Security.SuperUserKey, creationModel, true);
if (shouldSucceed is false)
{
Assert.IsFalse(result.Success);
Assert.AreEqual(UserOperationStatus.UserNameIsNotEmail, result.Status);
return;
}
Assert.IsTrue(result.Success);
Assert.AreEqual(UserOperationStatus.Success, result.Status);
var createdUser = result.Result.CreatedUser;
Assert.IsNotNull(createdUser);
Assert.AreEqual(username, createdUser.Username);
Assert.AreEqual(email, createdUser.Email);
}
[Test]
public async Task Cannot_Create_User_With_Duplicate_Email()
{
var email = "test@test.com";
var userGroup = await UserGroupService.GetAsync(Constants.Security.AdminGroupAlias);
var initialUserCreateModel = new UserCreateModel
{
UserName = "Test1",
Email = email,
Name = "Test Mc. Gee",
UserGroups = new HashSet<IUserGroup> { userGroup! }
};
var userService = CreateUserService(new SecuritySettings { UsernameIsEmail = false });
var result = await userService.CreateAsync(Constants.Security.SuperUserKey, initialUserCreateModel, true);
Assert.IsTrue(result.Success);
var duplicateUserCreateModel = new UserCreateModel
{
UserName = "Test2",
Email = email,
Name = "Duplicate Mc. Gee",
UserGroups = new HashSet<IUserGroup> { userGroup! }
};
var secondResult = await userService.CreateAsync(Constants.Security.SuperUserKey, duplicateUserCreateModel, true);
Assert.IsFalse(secondResult.Success);
Assert.AreEqual(UserOperationStatus.DuplicateEmail, secondResult.Status);
}
[Test]
public async Task Cannot_Create_User_With_Duplicate_UserName()
{
var userName = "UserName";
var userGroup = await UserGroupService.GetAsync(Constants.Security.AdminGroupAlias);
var initialUserCreateModel = new UserCreateModel
{
UserName = userName,
Email = "test@email.com",
Name = "Test Mc. Gee",
UserGroups = new HashSet<IUserGroup> { userGroup! }
};
var userService = CreateUserService(new SecuritySettings { UsernameIsEmail = false });
var result = await userService.CreateAsync(Constants.Security.SuperUserKey, initialUserCreateModel, true);
Assert.IsTrue(result.Success);
var duplicateUserCreateModel = new UserCreateModel
{
UserName = userName,
Email = "another@email.com",
Name = "Duplicate Mc. Gee",
UserGroups = new HashSet<IUserGroup> { userGroup! }
};
var secondResult = await userService.CreateAsync(Constants.Security.SuperUserKey, duplicateUserCreateModel, true);
Assert.IsFalse(secondResult.Success);
Assert.AreEqual(UserOperationStatus.DuplicateUserName, secondResult.Status);
}
[Test]
public async Task Cannot_Create_User_Without_User_Group()
{
UserCreateModel userCreateModel = new UserCreateModel
{
UserName = "NoUser@Group.com",
Email = "NoUser@Group.com",
Name = "NoUser@Group.com",
};
IUserService userService = CreateUserService();
var result = await userService.CreateAsync(Constants.Security.SuperUserKey, userCreateModel, true);
Assert.IsFalse(result.Success);
Assert.AreEqual(UserOperationStatus.NoUserGroup, result.Status);
}
[Test]
public async Task Performing_User_Must_Exist_When_Creating()
{
IUserService userService = CreateUserService();
var result = await userService.CreateAsync(Guid.Empty, new UserCreateModel(), true);
Assert.IsFalse(result.Success);
Assert.AreEqual(UserOperationStatus.MissingUser, result.Status);
}
}

View File

@@ -0,0 +1,70 @@
using NUnit.Framework;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.Membership;
using Umbraco.Cms.Core.Services.OperationStatus;
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
public partial class UserServiceCrudTests
{
[Test]
public async Task Delete_Returns_Not_Found_If_Not_Found()
{
var userService = CreateUserService();
var result = await userService.DeleteAsync(Guid.NewGuid());
Assert.AreEqual(UserOperationStatus.NotFound, result);
}
[Test]
public async Task Cannot_Delete_User_With_Login()
{
var userGroup = await UserGroupService.GetAsync(Constants.Security.AdminGroupAlias);
var userCreateModel = new UserCreateModel
{
Email = "test@test.com",
UserName = "test@test.com",
Name = "test@test.com",
UserGroups = new HashSet<IUserGroup> { userGroup! }
};
var userService = CreateUserService();
var creationResult = await userService.CreateAsync(Constants.Security.SuperUserKey, userCreateModel, true);
Assert.IsTrue(creationResult.Success);
var createdUser = creationResult.Result.CreatedUser;
createdUser!.LastLoginDate = DateTime.Now;
userService.Save(createdUser);
var result = await userService.DeleteAsync(createdUser.Key);
Assert.AreEqual(UserOperationStatus.CannotDelete, result);
// Asset that it is in fact not deleted
var postDeletedUser = await userService.GetAsync(createdUser.Key);
Assert.IsNotNull(postDeletedUser);
Assert.AreEqual(createdUser.Key, postDeletedUser.Key);
}
[Test]
public async Task Can_Delete_User_That_Has_Not_Logged_In()
{
var userGroup = await UserGroupService.GetAsync(Constants.Security.AdminGroupAlias);
var userCreateModel = new UserCreateModel
{
Email = "test@test.com",
UserName = "test@test.com",
Name = "test@test.com",
UserGroups = new HashSet<IUserGroup> { userGroup! }
};
var userService = CreateUserService();
var creationResult = await userService.CreateAsync(Constants.Security.SuperUserKey, userCreateModel, true);
Assert.IsTrue(creationResult.Success);
var deletionResult = await userService.DeleteAsync(creationResult.Result.CreatedUser!.Key);
Assert.AreEqual(UserOperationStatus.Success, deletionResult);
// Make sure it's actually deleted
var postDeletedUser = await userService.GetAsync(creationResult.Result.CreatedUser.Key);
Assert.IsNull(postDeletedUser);
}
}

View File

@@ -0,0 +1,245 @@
using NUnit.Framework;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.Membership;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Services.OperationStatus;
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
public partial class UserServiceCrudTests
{
[Test]
[TestCase(UserState.Disabled)]
[TestCase(UserState.All)]
public async Task Cannot_Request_Disabled_If_Hidden(UserState includeState)
{
var userService = CreateUserService(new SecuritySettings {HideDisabledUsersInBackOffice = true});
var editorGroup = await UserGroupService.GetAsync(Constants.Security.EditorGroupAlias);
var createModel = new UserCreateModel
{
UserName = "editor@mail.com",
Email = "editor@mail.com",
Name = "Editor",
UserGroups = new HashSet<IUserGroup> {editorGroup!}
};
var createAttempt = await userService.CreateAsync(Constants.Security.SuperUserKey, createModel, true);
Assert.IsTrue(createAttempt.Success);
var disableStatus =
await userService.DisableAsync(Constants.Security.SuperUserKey, new HashSet<Guid>{ createAttempt.Result.CreatedUser!.Key });
Assert.AreEqual(UserOperationStatus.Success, disableStatus);
var filter = new UserFilter {IncludeUserStates = new SortedSet<UserState> {includeState}};
var filterAttempt = await userService.FilterAsync(Constants.Security.SuperUserKey, filter, 0, 1000);
Assert.IsTrue(filterAttempt.Success);
Assert.AreEqual(0, filterAttempt.Result.Items.Count());
}
[Test]
public async Task Only_Super_User_Can_Filter_Super_user()
{
var userService = CreateUserService();
var editorGroup = await UserGroupService.GetAsync(Constants.Security.EditorGroupAlias);
var adminGroup = await UserGroupService.GetAsync(Constants.Security.AdminGroupAlias);
var nonSuperCreateModel = new UserCreateModel
{
Email = "not@super.com",
UserName = "not@super.com",
UserGroups = new HashSet<IUserGroup> {editorGroup!, adminGroup!},
Name = "Not A Super User"
};
var createEditorAttempt =
await userService.CreateAsync(Constants.Security.SuperUserKey, nonSuperCreateModel, true);
Assert.IsTrue(createEditorAttempt.Success);
var editor = createEditorAttempt.Result.CreatedUser;
// An empty filter is essentially the same as "Give me everything" but you still can't see super users.
var filter = new UserFilter();
var filterAttempt = await userService.FilterAsync(editor!.Key, filter, 0, 10000);
Assert.IsTrue(filterAttempt.Success);
var result = filterAttempt.Result;
Assert.IsNotNull(result);
Assert.AreEqual(1, result.Items.Count());
Assert.AreEqual(1, result.Total);
var onlyUser = result.Items.First();
Assert.AreEqual(editor.Key, onlyUser.Key);
}
[Test]
public async Task Super_User_Can_Filter_Super_User()
{
var userService = CreateUserService();
var editorGroup = await UserGroupService.GetAsync(Constants.Security.EditorGroupAlias);
var nonSuperCreateModel = new UserCreateModel
{
Email = "not@super.com",
UserName = "not@super.com",
UserGroups = new HashSet<IUserGroup> {editorGroup!},
Name = "Not A Super User"
};
var createEditorAttempt =
await userService.CreateAsync(Constants.Security.SuperUserKey, nonSuperCreateModel, true);
Assert.IsTrue(createEditorAttempt.Success);
var filter = new UserFilter {NameFilters = new SortedSet<string> {"admin"}};
var filterAttempt = await userService.FilterAsync(Constants.Security.SuperUserKey, filter, 0, 10000);
Assert.IsTrue(filterAttempt.Success);
var result = filterAttempt.Result;
Assert.AreEqual(1, result.Items.Count());
Assert.AreEqual(1, result.Total);
Assert.IsNotNull(result.Items.FirstOrDefault(x => x.Key == Constants.Security.SuperUserKey));
}
[Test]
public async Task Only_Admins_Can_Filter_Admins()
{
var userService = CreateUserService();
var adminGroup = await UserGroupService.GetAsync(Constants.Security.AdminGroupAlias);
var editorGroup = await UserGroupService.GetAsync(Constants.Security.EditorGroupAlias);
var editorCreateModel = new UserCreateModel
{
UserName = "editor@mail.com",
Email = "editor@mail.com",
Name = "Editor Mc. Gee",
UserGroups = new HashSet<IUserGroup> {editorGroup!}
};
var adminCreateModel = new UserCreateModel
{
UserName = "admin@mail.com",
Email = "admin@mail.com",
Name = "Admin Mc. Gee",
UserGroups = new HashSet<IUserGroup> {adminGroup!, editorGroup}
};
var createEditorAttempt =
await userService.CreateAsync(Constants.Security.SuperUserKey, editorCreateModel, true);
var createAdminAttempt = await userService.CreateAsync(Constants.Security.SuperUserKey, adminCreateModel, true);
Assert.IsTrue(createEditorAttempt.Success);
Assert.IsTrue(createAdminAttempt.Success);
var filter = new UserFilter {IncludedUserGroups = new SortedSet<Guid> {adminGroup!.Key}};
var editorFilterAttempt =
await userService.FilterAsync(createEditorAttempt.Result.CreatedUser!.Key, filter, 0, 10000);
Assert.IsTrue(editorFilterAttempt.Success);
var editorAllUsers = editorFilterAttempt.Result.Items.ToList();
Assert.AreEqual(0, editorAllUsers.Count);
var adminFilterAttempt =
await userService.FilterAsync(createAdminAttempt.Result.CreatedUser!.Key, filter, 0, 10000);
Assert.IsTrue(adminFilterAttempt.Success);
var adminAllUsers = adminFilterAttempt.Result.Items.ToList();
Assert.AreEqual(1, adminAllUsers.Count);
Assert.IsNotNull(adminAllUsers.FirstOrDefault(x => x.Key == createAdminAttempt.Result.CreatedUser!.Key));
}
private async Task CreateTestUsers(IUserService userService)
{
var editorGroup = await UserGroupService.GetAsync(Constants.Security.EditorGroupAlias);
var adminGroup = await UserGroupService.GetAsync(Constants.Security.AdminGroupAlias);
var writerGroup = await UserGroupService.GetAsync(Constants.Security.WriterGroupAlias);
var translatorGroup = await UserGroupService.GetAsync(Constants.Security.TranslatorGroupAlias);
var createModels = new List<UserCreateModel>
{
new()
{
UserName = "editor@email.com",
Email = "editor@email.com",
Name = "Editor",
UserGroups = new HashSet<IUserGroup> {editorGroup!}
},
new()
{
UserName = "admin@email.com",
Email = "admin@email.com",
Name = "Admin",
UserGroups = new HashSet<IUserGroup> {adminGroup!}
},
new()
{
UserName = "write@email.com",
Email = "write@email.com",
Name = "Write",
UserGroups = new HashSet<IUserGroup> {writerGroup}
},
new()
{
UserName = "translator@email.com",
Email = "translator@email.com",
Name = "Translator",
UserGroups = new HashSet<IUserGroup> {translatorGroup}
},
new()
{
UserName = "EverythingButAdmin@email.com",
Email = "EverythingButAdmin@email.com",
Name = "Everything But Admin",
UserGroups = new HashSet<IUserGroup> {editorGroup, writerGroup, translatorGroup}
}
};
foreach (var model in createModels)
{
var result = await userService.CreateAsync(Constants.Security.SuperUserKey, model);
Assert.IsTrue(result.Success);
}
}
[Test]
public async Task Can_Include_User_Groups()
{
var userService = CreateUserService();
await CreateTestUsers(userService);
var writerGroup = await UserGroupService.GetAsync(Constants.Security.WriterGroupAlias);
var filter = new UserFilter
{
IncludedUserGroups = new SortedSet<Guid> { writerGroup!.Key }
};
var onlyWritesResult = await userService.FilterAsync(Constants.Security.SuperUserKey, filter, 0, 1000);
Assert.IsTrue(onlyWritesResult.Success);
var users = onlyWritesResult.Result.Items.ToList();
Assert.IsTrue(users.Any());
Assert.IsFalse(users.Any(x => x.Groups.FirstOrDefault(y => y.Key == writerGroup.Key) is null));
}
[Test]
public async Task Can_Exclude_User_Groups()
{
var userService = CreateUserService();
await CreateTestUsers(userService);
var editorGroup = await UserGroupService.GetAsync(Constants.Security.EditorGroupAlias);
var filter = new UserFilter
{
ExcludeUserGroups = new SortedSet<Guid> { editorGroup!.Key }
};
var noEditorResult = await userService.FilterAsync(Constants.Security.SuperUserKey, filter, 0, 1000);
Assert.IsTrue(noEditorResult);
var users = noEditorResult.Result.Items.ToList();
Assert.IsTrue(users.Any());
Assert.IsFalse(users.Any(x => x.Groups.FirstOrDefault(y => y.Key == editorGroup.Key) is not null));
}
}

View File

@@ -0,0 +1,162 @@
using NUnit.Framework;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.Membership;
using Umbraco.Cms.Core.Services.OperationStatus;
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
public partial class UserServiceCrudTests
{
[Test]
public async Task Only_Super_User_Can_Get_Super_user()
{
var userService = CreateUserService();
var editorGroup = await UserGroupService.GetAsync(Constants.Security.EditorGroupAlias);
var adminGroup = await UserGroupService.GetAsync(Constants.Security.AdminGroupAlias);
var nonSuperCreateModel = new UserCreateModel
{
Email = "not@super.com",
UserName = "not@super.com",
UserGroups = new HashSet<IUserGroup> { editorGroup!, adminGroup! },
Name = "Not A Super User"
};
var createEditorAttempt = await userService.CreateAsync(Constants.Security.SuperUserKey, nonSuperCreateModel, true);
Assert.IsTrue(createEditorAttempt.Success);
var editor = createEditorAttempt.Result.CreatedUser;
var allUsersAttempt = await userService.GetAllAsync(editor!.Key, 0, 10000);
Assert.IsTrue(allUsersAttempt.Success);
var result = allUsersAttempt.Result;
Assert.IsNotNull(result);
Assert.AreEqual(1, result.Items.Count());
Assert.AreEqual(1, result.Total);
var onlyUser = result.Items.First();
Assert.AreEqual(editor.Key, onlyUser.Key);
}
[Test]
public async Task Super_User_Can_See_Super_User()
{
var userService = CreateUserService();
var editorGroup = await UserGroupService.GetAsync(Constants.Security.EditorGroupAlias);
var nonSuperCreateModel = new UserCreateModel
{
Email = "not@super.com",
UserName = "not@super.com",
UserGroups = new HashSet<IUserGroup> { editorGroup! },
Name = "Not A Super User"
};
var createEditorAttempt = await userService.CreateAsync(Constants.Security.SuperUserKey, nonSuperCreateModel, true);
Assert.IsTrue(createEditorAttempt.Success);
var editor = createEditorAttempt.Result.CreatedUser;
var allUsersAttempt = await userService.GetAllAsync(Constants.Security.SuperUserKey, 0, 10000);
Assert.IsTrue(allUsersAttempt.Success);
var result = allUsersAttempt.Result;
Assert.AreEqual(2, result.Items.Count());
Assert.AreEqual(2, result.Total);
Assert.IsTrue(result.Items.Any(x => x.Key == Constants.Security.SuperUserKey));
Assert.IsTrue(result.Items.Any(x => x.Key == editor!.Key));
}
[Test]
public async Task Only_Admins_Can_See_Admins()
{
var userService = CreateUserService();
var adminGroup = await UserGroupService.GetAsync(Constants.Security.AdminGroupAlias);
var editorGroup = await UserGroupService.GetAsync(Constants.Security.EditorGroupAlias);
var editorCreateModel = new UserCreateModel
{
UserName = "editor@mail.com",
Email = "editor@mail.com",
Name = "Editor Mc. Gee",
UserGroups = new HashSet<IUserGroup> { editorGroup! }
};
var adminCreateModel = new UserCreateModel
{
UserName = "admin@mail.com",
Email = "admin@mail.com",
Name = "Admin Mc. Gee",
UserGroups = new HashSet<IUserGroup> { adminGroup!, editorGroup }
};
var createEditorAttempt = await userService.CreateAsync(Constants.Security.SuperUserKey, editorCreateModel, true);
var createAdminAttempt = await userService.CreateAsync(Constants.Security.SuperUserKey, adminCreateModel, true);
Assert.IsTrue(createEditorAttempt.Success);
Assert.IsTrue(createAdminAttempt.Success);
var editorAllUsersAttempt = await userService.GetAllAsync(createEditorAttempt.Result.CreatedUser!.Key, 0, 10000);
Assert.IsTrue(editorAllUsersAttempt.Success);
var editorAllUsers = editorAllUsersAttempt.Result.Items.ToList();
Assert.AreEqual(1, editorAllUsers.Count);
Assert.AreEqual(createEditorAttempt.Result.CreatedUser!.Key, editorAllUsers.First().Key);
var adminAllUsersAttempt = await userService.GetAllAsync(createAdminAttempt.Result.CreatedUser!.Key, 0, 10000);
Assert.IsTrue(adminAllUsersAttempt.Success);
var adminAllUsers = adminAllUsersAttempt.Result.Items.ToList();
Assert.AreEqual(2, adminAllUsers.Count);
Assert.IsTrue(adminAllUsers.Any(x => x.Key == createEditorAttempt.Result.CreatedUser!.Key));
Assert.IsTrue(adminAllUsers.Any(x => x.Key == createAdminAttempt.Result.CreatedUser!.Key));
}
[Test]
public async Task Cannot_See_Disabled_When_HideDisabled_Is_True()
{
var userService = CreateUserService(securitySettings: new SecuritySettings { HideDisabledUsersInBackOffice = true });
var editorGroup = await UserGroupService.GetAsync(Constants.Security.EditorGroupAlias);
var firstEditorCreateModel = new UserCreateModel
{
UserName = "firstEditor@mail.com",
Email = "firstEditor@mail.com",
Name = "First Editor",
UserGroups = new HashSet<IUserGroup> { editorGroup! }
};
var firstEditorResult = await userService.CreateAsync(Constants.Security.SuperUserKey, firstEditorCreateModel, true);
Assert.IsTrue(firstEditorResult.Success);
var secondEditorCreateModel = new UserCreateModel
{
UserName = "secondEditor@mail.com",
Email = "secondEditor@mail.com",
Name = "Second Editor",
UserGroups = new HashSet<IUserGroup> {editorGroup}
};
var secondEditorResult = await userService.CreateAsync(Constants.Security.SuperUserKey, secondEditorCreateModel, true);
Assert.IsTrue(secondEditorResult.Success);
var disableStatus = await userService.DisableAsync(Constants.Security.SuperUserKey, new HashSet<Guid>{ secondEditorResult.Result.CreatedUser!.Key });
Assert.AreEqual(disableStatus, UserOperationStatus.Success);
var allUsersAttempt = await userService.GetAllAsync(Constants.Security.SuperUserKey, 0, 10000);
Assert.IsTrue(allUsersAttempt.Success);
var allUsers = allUsersAttempt.Result!.Items.ToList();
Assert.AreEqual(2, allUsers.Count);
Assert.IsTrue(allUsers.Any(x => x.Key == firstEditorResult.Result.CreatedUser!.Key));
Assert.IsTrue(allUsers.Any(x => x.Key == Constants.Security.SuperUserKey));
}
[Test]
public async Task Requesting_User_Must_Exist_When_Calling_Get_All()
{
var userService = CreateUserService();
var getAllAttempt = await userService.GetAllAsync(Guid.NewGuid(), 0, 10000);
Assert.IsFalse(getAllAttempt.Success);
Assert.AreEqual(UserOperationStatus.MissingUser, getAllAttempt.Status);
Assert.IsNull(getAllAttempt.Result);
}
}

View File

@@ -0,0 +1,164 @@
using NUnit.Framework;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.Membership;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Services.OperationStatus;
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
public partial class UserServiceCrudTests
{
[Test]
[TestCase("test@email.com", "test@email.com", true, true)]
[TestCase("test@email.com", "notTheUserName@email.com", true, false)]
[TestCase("NotAnEmail", "test@email.com", true, false)]
[TestCase("test@email.com", "test@email.com", false, true)]
[TestCase("NotAnEmail", "test@email.com", false, true)]
[TestCase("aDifferentEmail@email.com", "test@email.com", false, true)]
public async Task Invite_User_Name_Must_Be_Email(
string username,
string email,
bool userNameIsEmailEnabled,
bool shouldSucceed)
{
var securitySettings = new SecuritySettings { UsernameIsEmail = userNameIsEmailEnabled };
var userService = CreateUserService(securitySettings);
var userGroup = await UserGroupService.GetAsync(Constants.Security.AdminGroupAlias);
var inviteModel = new UserInviteModel
{
UserName = username,
Email = email,
Name = "Test Mc. Gee",
UserGroups = new HashSet<IUserGroup> { userGroup! }
};
var result = await userService.InviteAsync(Constants.Security.SuperUserKey, inviteModel);
if (shouldSucceed is false)
{
Assert.IsFalse(result.Success);
Assert.AreEqual(UserOperationStatus.UserNameIsNotEmail, result.Status);
return;
}
Assert.IsTrue(result.Success);
Assert.AreEqual(UserOperationStatus.Success, result.Status);
var invitedUser = result.Result.InvitedUser;
Assert.IsNotNull(invitedUser);
Assert.AreEqual(username, invitedUser.Username);
Assert.AreEqual(email, invitedUser.Email);
}
[Test]
public async Task Cannot_Invite_User_With_Duplicate_Email()
{
var email = "test@test.com";
var userGroup = await UserGroupService.GetAsync(Constants.Security.AdminGroupAlias);
var initialUserCreateModel = new UserCreateModel
{
UserName = "Test1",
Email = email,
Name = "Test Mc. Gee",
UserGroups = new HashSet<IUserGroup> { userGroup! }
};
var userService = CreateUserService(new SecuritySettings { UsernameIsEmail = false });
var result = await userService.CreateAsync(Constants.Security.SuperUserKey, initialUserCreateModel, true);
Assert.IsTrue(result.Success);
var duplicateUserInviteModel = new UserInviteModel
{
UserName = "Test2",
Email = email,
Name = "Duplicate Mc. Gee",
UserGroups = new HashSet<IUserGroup> { userGroup! }
};
var secondResult = await userService.InviteAsync(Constants.Security.SuperUserKey, duplicateUserInviteModel);
Assert.IsFalse(secondResult.Success);
Assert.AreEqual(UserOperationStatus.DuplicateEmail, secondResult.Status);
}
[Test]
public async Task Cannot_Invite_User_With_Duplicate_UserName()
{
var userName = "UserName";
var userGroup = await UserGroupService.GetAsync(Constants.Security.AdminGroupAlias);
var initialUserCreateModel = new UserCreateModel
{
UserName = userName,
Email = "test@email.com",
Name = "Test Mc. Gee",
UserGroups = new HashSet<IUserGroup> { userGroup! }
};
var userService = CreateUserService(new SecuritySettings { UsernameIsEmail = false });
var result = await userService.CreateAsync(Constants.Security.SuperUserKey, initialUserCreateModel, true);
Assert.IsTrue(result.Success);
var duplicateUserInviteModelModel = new UserInviteModel
{
UserName = userName,
Email = "another@email.com",
Name = "Duplicate Mc. Gee",
UserGroups = new HashSet<IUserGroup> { userGroup! }
};
var secondResult = await userService.InviteAsync(Constants.Security.SuperUserKey, duplicateUserInviteModelModel);
Assert.IsFalse(secondResult.Success);
Assert.AreEqual(UserOperationStatus.DuplicateUserName, secondResult.Status);
}
[Test]
public async Task Cannot_Invite_User_Without_User_Group()
{
UserInviteModel userInviteModel = new UserInviteModel
{
UserName = "NoUser@Group.com",
Email = "NoUser@Group.com",
Name = "NoUser@Group.com",
};
IUserService userService = CreateUserService();
var result = await userService.InviteAsync(Constants.Security.SuperUserKey, userInviteModel);
Assert.IsFalse(result.Success);
Assert.AreEqual(UserOperationStatus.NoUserGroup, result.Status);
}
[Test]
public async Task Performing_User_Must_Exist_When_Inviting()
{
IUserService userService = CreateUserService();
var result = await userService.InviteAsync(Guid.Empty, new UserInviteModel());
Assert.IsFalse(result.Success);
Assert.AreEqual(UserOperationStatus.MissingUser, result.Status);
}
[Test]
public async Task Invited_Users_Has_Invited_state()
{
var userGroup = await UserGroupService.GetAsync(Constants.Security.AdminGroupAlias);
UserInviteModel userInviteModel = new UserInviteModel
{
UserName = "some@email.com",
Email = "some@email.com",
Name = "Bob",
UserGroups = new HashSet<IUserGroup> {userGroup!},
};
IUserService userService = CreateUserService();
var result = await userService.InviteAsync(Constants.Security.SuperUserKey, userInviteModel);
Assert.IsTrue(result.Success);
var invitedUser = await userService.GetAsync(result.Result.InvitedUser!.Key);
Assert.IsNotNull(invitedUser);
Assert.AreEqual(UserState.Invited, invitedUser.UserState);
}
}

View File

@@ -0,0 +1,107 @@
using NUnit.Framework;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.Membership;
using Umbraco.Cms.Core.Services.OperationStatus;
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
public partial class UserServiceCrudTests
{
[Test]
public async Task Can_Enable_User()
{
var editorUserGroup = await UserGroupService.GetAsync(Constants.Security.EditorGroupAlias);
var userCreateModel = new UserCreateModel
{
UserName = "test@email.com",
Email = "test@email.com",
Name = "Test User",
UserGroups = new HashSet<IUserGroup> { editorUserGroup }
};
var userService = CreateUserService();
var createAttempt = await userService.CreateAsync(Constants.Security.SuperUserKey, userCreateModel, false);
Assert.IsTrue(createAttempt.Success);
var user = createAttempt.Result.CreatedUser;
Assert.AreEqual(UserState.Disabled, user!.UserState);
var enableStatus = await userService.EnableAsync(Constants.Security.SuperUserKey, new HashSet<Guid> { user.Key });
Assert.AreEqual(UserOperationStatus.Success, enableStatus);
var updatedUser = await userService.GetAsync(user.Key);
// The user has not logged in, so after enabling the user, the user state should be inactive
Assert.AreEqual(UserState.Inactive, updatedUser!.UserState);
}
[Test]
public async Task Can_Disable_User()
{
var editorUserGroup = await UserGroupService.GetAsync(Constants.Security.EditorGroupAlias);
var userCreateModel = new UserCreateModel
{
UserName = "test@email.com",
Email = "test@email.com",
Name = "Test User",
UserGroups = new HashSet<IUserGroup> { editorUserGroup }
};
var userService = CreateUserService();
var createAttempt = await userService.CreateAsync(Constants.Security.SuperUserKey, userCreateModel, true);
Assert.IsTrue(createAttempt.Success);
var user = createAttempt.Result.CreatedUser;
Assert.AreEqual(UserState.Inactive, user!.UserState);
var disableStatus = await userService.DisableAsync(Constants.Security.SuperUserKey, new HashSet<Guid> { user.Key });
Assert.AreEqual(UserOperationStatus.Success, disableStatus);
}
[Test]
public async Task User_Cannot_Disable_Self()
{
var adminUserGroup = await UserGroupService.GetAsync(Constants.Security.AdminGroupAlias);
var userCreateModel = new UserCreateModel
{
UserName = "test@email.com",
Email = "test@email.com",
Name = "Test User",
UserGroups = new HashSet<IUserGroup> { adminUserGroup }
};
var userService = CreateUserService();
var createAttempt = await userService.CreateAsync(Constants.Security.SuperUserKey, userCreateModel, true);
Assert.IsTrue(createAttempt.Success);
var createdUser = createAttempt.Result.CreatedUser;
var disableStatus = await userService.DisableAsync(createdUser!.Key, new HashSet<Guid>{ createdUser.Key });
Assert.AreEqual(UserOperationStatus.CannotDisableSelf, disableStatus);
}
[Test]
public async Task Cannot_Disable_Invited_User()
{
var editorUserGroup = await UserGroupService.GetAsync(Constants.Security.EditorGroupAlias);
var userInviteModel = new UserInviteModel
{
UserName = "test@email.com",
Email = "test@email.com",
Name = "Test User",
UserGroups = new HashSet<IUserGroup> { editorUserGroup }
};
var userService = CreateUserService();
var userInviteAttempt = await userService.InviteAsync(Constants.Security.SuperUserKey, userInviteModel);
Assert.IsTrue(userInviteAttempt.Success);
var invitedUser = userInviteAttempt.Result.InvitedUser;
var disableStatus = await userService.DisableAsync(Constants.Security.SuperUserKey, new HashSet<Guid> { invitedUser!.Key });
Assert.AreEqual(UserOperationStatus.CannotDisableInvitedUser, disableStatus);
}
}

View File

@@ -0,0 +1,189 @@
using Moq;
using NUnit.Framework;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.Membership;
using Umbraco.Cms.Core.Security;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Services.OperationStatus;
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
public partial class UserServiceCrudTests
{
private SortedSet<Guid> GetKeysFromIds(IEnumerable<int>? ids, UmbracoObjectTypes type)
{
IEnumerable<Guid>? keys = ids?
.Select(x => EntityService.GetKey(x, type))
.Where(x => x.Success)
.Select(x => x.Result);
return keys is null
? new SortedSet<Guid>()
: new SortedSet<Guid>(keys);
}
private async Task<UserUpdateModel> MapUserToUpdateModel(IUser user)
{
var groups = await UserGroupService.GetAsync(user.Groups.Select(x => x.Id).ToArray());
return new UserUpdateModel
{
ExistingUser = user,
Email = user.Email,
Name = user.Name,
UserName = user.Username,
Language = user.Language,
ContentStartNodeKeys = GetKeysFromIds(user.StartContentIds, UmbracoObjectTypes.Document),
MediaStartNodeKeys = GetKeysFromIds(user.StartMediaIds, UmbracoObjectTypes.Media),
UserGroups = groups,
};
}
private async Task<(UserUpdateModel updateModel, IUser createdUser)> CreateUserForUpdate(
IUserService userService,
string email = "test@test.com",
string userName = "test@test.com")
{
var userGroup = await UserGroupService.GetAsync(Constants.Security.AdminGroupAlias);
var createUserModel = new UserCreateModel
{
Email = email,
UserName = userName,
Name = "Test Mc. Gee",
UserGroups = new HashSet<IUserGroup> { userGroup! }
};
var createExistingUser = await userService.CreateAsync(Constants.Security.SuperUserKey, createUserModel, true);
Assert.IsTrue(createExistingUser.Success);
Assert.IsNotNull(createExistingUser.Result.CreatedUser);
var savedUser = createExistingUser.Result.CreatedUser;
var updateModel = await MapUserToUpdateModel(savedUser);
return (updateModel, createExistingUser.Result.CreatedUser);
}
[Test]
[TestCase(true, false)]
[TestCase(false, true)]
public async Task Cannot_Change_Email_When_Deny_Local_Login_Is_True(bool denyLocalLogin, bool shouldSucceed)
{
var localLoginSetting = new Mock<ILocalLoginSettingProvider>();
localLoginSetting.Setup(x => x.HasDenyLocalLogin()).Returns(denyLocalLogin);
var userService = CreateUserService(
localLoginSettingProvider: localLoginSetting.Object,
securitySettings: new SecuritySettings { UsernameIsEmail = false });
var (updateModel, _) = await CreateUserForUpdate(userService);
var updatedEmail = "updated@email.com";
updateModel.Email = updatedEmail;
var result = await userService.UpdateAsync(Constants.Security.SuperUserKey, updateModel);
if (shouldSucceed is false)
{
Assert.IsFalse(result.Success);
Assert.AreEqual(UserOperationStatus.EmailCannotBeChanged, result.Status);
return;
}
Assert.IsTrue(result.Success);
// We'll get the user again to ensure that the changes has been persisted
var updatedUser = await userService.GetAsync(result.Result.Key);
Assert.IsNotNull(updatedUser);
Assert.AreEqual(updatedEmail, updatedUser.Email);
}
[Test]
[TestCase("same@email.com", "same@email.com", true)]
[TestCase("different@email.com", "another@email.com", false)]
[TestCase("notAnEmail", "some@email.com", false)]
public async Task UserName_And_Email_Must_Be_same_When_UserNameIsEmail_Equals_True(string userName, string email, bool shouldSucceed)
{
var userService = CreateUserService(securitySettings: new SecuritySettings { UsernameIsEmail = true });
var (updateModel, createdUser) = await CreateUserForUpdate(userService);
updateModel.UserName = userName;
updateModel.Email = email;
var result = await userService.UpdateAsync(Constants.Security.SuperUserKey, updateModel);
if (shouldSucceed is false)
{
Assert.IsFalse(result.Success);
Assert.AreEqual(UserOperationStatus.UserNameIsNotEmail, result.Status);
return;
}
Assert.IsTrue(result.Success);
var updatedUser = await userService.GetAsync(createdUser.Key);
Assert.IsNotNull(updatedUser);
Assert.AreEqual(userName, updatedUser.Username);
Assert.AreEqual(email, updatedUser.Email);
}
[Test]
public async Task Cannot_Change_Email_To_Duplicate_Email_On_Update()
{
var userService = CreateUserService();
var userGroup = await UserGroupService.GetAsync(Constants.Security.AdminGroupAlias);
var email = "thiswillbe@duplicate.com";
var createModel = new UserCreateModel
{
Email = email,
UserName = email,
Name = "Test Mc. Gee",
UserGroups = new HashSet<IUserGroup> { userGroup! }
};
var createExisting = await userService.CreateAsync(Constants.Security.SuperUserKey, createModel, true);
Assert.IsTrue(createExisting.Success);
var (updateModel, _) = await CreateUserForUpdate(userService);
updateModel.Email = email;
updateModel.UserName = email;
var updateAttempt = await userService.UpdateAsync(Constants.Security.SuperUserKey, updateModel);
Assert.IsFalse(updateAttempt.Success);
Assert.AreEqual(UserOperationStatus.DuplicateEmail, updateAttempt.Status);
}
[Test]
[TestCase("TestUser", "test@user.com", "TestUser", "another@email.com")]
[TestCase("test@email.com", "test@email.com", "test@email.com", "different@email.com")]
[TestCase("SomeName", "test@email.com", "test@email.com", "different@email.com")]
public async Task Cannot_Change_User_Name_To_Duplicate_UserName(string existingUserName, string existingEmail, string updateUserName, string updateEmail)
{
// We also ensure that your username cannot be the same as another users email.
var userService = CreateUserService(new SecuritySettings { UsernameIsEmail = false });
var userGroup = await UserGroupService.GetAsync(Constants.Security.AdminGroupAlias);
var createModel = new UserCreateModel
{
Email = existingEmail,
UserName = existingUserName,
Name = "Test Mc. Gee",
UserGroups = new HashSet<IUserGroup> { userGroup! }
};
var createExisting = await userService.CreateAsync(Constants.Security.SuperUserKey, createModel, true);
Assert.IsTrue(createExisting.Success);
var (updateModel, _) = await CreateUserForUpdate(userService);
updateModel.Email = updateEmail;
updateModel.UserName = updateUserName;
var updateAttempt = await userService.UpdateAsync(Constants.Security.SuperUserKey, updateModel);
Assert.IsFalse(updateAttempt.Success);
Assert.AreEqual(UserOperationStatus.DuplicateUserName, updateAttempt.Status);
}
}

View File

@@ -0,0 +1,87 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Moq;
using NUnit.Framework;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Editors;
using Umbraco.Cms.Core.Events;
using Umbraco.Cms.Core.IO;
using Umbraco.Cms.Core.Models.Membership;
using Umbraco.Cms.Core.Persistence.Repositories;
using Umbraco.Cms.Core.Scoping;
using Umbraco.Cms.Core.Security;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Services.OperationStatus;
using Umbraco.Cms.Core.Strings;
using Umbraco.Cms.Tests.Common.Testing;
using Umbraco.Cms.Tests.Integration.Testing;
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.Services;
[TestFixture]
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)]
public partial class UserServiceCrudTests : UmbracoIntegrationTest
{
private IUserGroupService UserGroupService => GetRequiredService<IUserGroupService>();
private IEntityService EntityService => GetRequiredService<IEntityService>();
protected override void ConfigureTestServices(IServiceCollection services)
{
base.ConfigureTestServices(services);
services.RemoveAll<IInviteUriProvider>();
services.AddScoped<IInviteUriProvider, TestUriProvider>();
}
// This is resolved from the service scope, so we have to add it to the service collection.
private class TestUriProvider : IInviteUriProvider
{
public Task<Attempt<Uri, UserOperationStatus>> CreateInviteUriAsync(IUser invitee)
{
var fakePath = "https://localhost:44331/fakeInviteEndpoint";
Attempt<Uri, UserOperationStatus> attempt = Attempt<Uri, UserOperationStatus>.Succeed(UserOperationStatus.Success, new Uri(fakePath));
return Task.FromResult(attempt);
}
}
private IUserService CreateUserService(
SecuritySettings? securitySettings = null,
IUserInviteSender? inviteSender = null,
ILocalLoginSettingProvider? localLoginSettingProvider = null)
{
securitySettings ??= GetRequiredService<IOptions<SecuritySettings>>().Value;
IOptions<SecuritySettings> securityOptions = Options.Create(securitySettings);
if (inviteSender is null)
{
var senderMock = new Mock<IUserInviteSender>();
senderMock.Setup(x => x.CanSendInvites()).Returns(true);
inviteSender = senderMock.Object;
}
localLoginSettingProvider ??= GetRequiredService<ILocalLoginSettingProvider>();
return new UserService(
GetRequiredService<ICoreScopeProvider>(),
GetRequiredService<ILoggerFactory>(),
GetRequiredService<IEventMessagesFactory>(),
GetRequiredService<IUserRepository>(),
GetRequiredService<IUserGroupRepository>(),
GetRequiredService<IOptions<GlobalSettings>>(),
securityOptions,
GetRequiredService<UserEditorAuthorizationHelper>(),
GetRequiredService<IServiceScopeFactory>(),
GetRequiredService<IEntityService>(),
localLoginSettingProvider,
inviteSender,
GetRequiredService<MediaFileManager>(),
GetRequiredService<ITemporaryFileService>(),
GetRequiredService<IShortStringHelper>(),
GetRequiredService<IOptions<ContentSettings>>());
}
}

View File

@@ -1,9 +1,13 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using NUnit.Framework;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Events;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Models.Membership;
using Umbraco.Cms.Core.Persistence.Repositories;
using Umbraco.Cms.Core.Security;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Tests.Common;
@@ -16,24 +20,42 @@ namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Security;
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)]
public class BackOfficeUserStoreTests : UmbracoIntegrationTest
{
private IUserService UserService => GetRequiredService<IUserService>();
private IEntityService EntityService => GetRequiredService<IEntityService>();
private IExternalLoginWithKeyService ExternalLoginService => GetRequiredService<IExternalLoginWithKeyService>();
private IUmbracoMapper UmbracoMapper => GetRequiredService<IUmbracoMapper>();
private ILocalizedTextService TextService => GetRequiredService<ILocalizedTextService>();
private ITwoFactorLoginService TwoFactorLoginService => GetRequiredService<ITwoFactorLoginService>();
private IUserGroupService UserGroupService => GetRequiredService<IUserGroupService>();
private IUserRepository UserRepository => GetRequiredService<IUserRepository>();
private IRuntimeState RuntimeState => GetRequiredService<IRuntimeState>();
private IEventMessagesFactory EventMessagesFactory => GetRequiredService<IEventMessagesFactory>();
private ILogger<BackOfficeUserStore> Logger = NullLogger<BackOfficeUserStore>.Instance;
private BackOfficeUserStore GetUserStore()
=> new(
ScopeProvider,
UserService,
EntityService,
ExternalLoginService,
new TestOptionsSnapshot<GlobalSettings>(GlobalSettings),
UmbracoMapper,
new BackOfficeErrorDescriber(TextService),
AppCaches,
TwoFactorLoginService
TwoFactorLoginService,
UserGroupService,
UserRepository,
RuntimeState,
EventMessagesFactory,
Logger
);
[Test]

View File

@@ -0,0 +1,76 @@
using NUnit.Framework;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.Membership;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Tests.Common.Testing;
using Umbraco.Cms.Tests.Integration.Testing;
namespace Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services;
[TestFixture]
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)]
public class UserIdKeyResolverTests : UmbracoIntegrationTest
{
private IUserService UserService => GetRequiredService<IUserService>();
private IUserGroupService UserGroupService => GetRequiredService<IUserGroupService>();
private IUserIdKeyResolver UserIdKeyResolver => GetRequiredService<IUserIdKeyResolver>();
[Test]
public async Task Can_Resolve_Id_To_Key()
{
var userGroup = await UserGroupService.GetAsync(Constants.Security.AdminGroupAlias);
var userCreateModel = new UserCreateModel
{
UserName = "test@test.com",
Email = "test@test.com",
Name = "Test Mc. Gee",
UserGroups = new HashSet<IUserGroup> { userGroup! }
};
var creationResult = await UserService.CreateAsync(Constants.Security.SuperUserKey, userCreateModel);
Assert.IsTrue(creationResult.Success);
var createdUser = creationResult.Result.CreatedUser;
Assert.IsNotNull(createdUser);
var resolvedKey = await UserIdKeyResolver.GetAsync(createdUser.Id);
Assert.AreEqual(createdUser.Key, resolvedKey);
}
[Test]
public async Task Can_Resolve_Key_To_Id()
{
var userGroup = await UserGroupService.GetAsync(Constants.Security.AdminGroupAlias);
var userCreateModel = new UserCreateModel
{
UserName = "test@test.com",
Email = "test@test.com",
Name = "Test Mc. Gee",
UserGroups = new HashSet<IUserGroup> { userGroup! }
};
var creationResult = await UserService.CreateAsync(Constants.Security.SuperUserKey, userCreateModel);
Assert.IsTrue(creationResult.Success);
var createdUser = creationResult.Result.CreatedUser;
Assert.IsNotNull(createdUser);
var resolvedId = await UserIdKeyResolver.GetAsync(createdUser.Key);
Assert.AreEqual(createdUser.Id, resolvedId);
}
[Test]
public async Task Unknown_Key_Resolves_To_Null()
{
var resolvedId = await UserIdKeyResolver.GetAsync(Guid.NewGuid());
Assert.IsNull(resolvedId);
}
[Test]
public async Task Unknown_Id_Resolves_To_Null()
{
var resolvedKey = await UserIdKeyResolver.GetAsync(1234567890);
Assert.IsNull(resolvedKey);
}
}

View File

@@ -61,5 +61,26 @@
<Compile Update="Umbraco.Infrastructure\Services\ContentEditingServiceTests.Update.cs">
<DependentUpon>ContentEditingServiceTests.cs</DependentUpon>
</Compile>
<Compile Update="Umbraco.Core\Services\UserServiceCrudTests.Create.cs">
<DependentUpon>UserServiceCrudTests.cs</DependentUpon>
</Compile>
<Compile Update="Umbraco.Core\Services\UserServiceCrudTests.Delete.cs">
<DependentUpon>UserServiceCrudTests.cs</DependentUpon>
</Compile>
<Compile Update="Umbraco.Core\Services\UserServiceCrudTests.Filter.cs">
<DependentUpon>UserServiceCrudTests.cs</DependentUpon>
</Compile>
<Compile Update="Umbraco.Core\Services\UserServiceCrudTests.Get.cs">
<DependentUpon>UserServiceCrudTests.cs</DependentUpon>
</Compile>
<Compile Update="Umbraco.Core\Services\UserServiceCrudTests.Invite.cs">
<DependentUpon>UserServiceCrudTests.cs</DependentUpon>
</Compile>
<Compile Update="Umbraco.Core\Services\UserServiceCrudTests.Update.cs">
<DependentUpon>UserServiceCrudTests.cs</DependentUpon>
</Compile>
<Compile Update="Umbraco.Core\Services\UserServiceCrudTests.PartialUpdates.cs">
<DependentUpon>UserServiceCrudTests.cs</DependentUpon>
</Compile>
</ItemGroup>
</Project>