Skip to content

Commit 7bbef2a

Browse files
authored
V14: Fix member mapping (#16106)
* convert key to name before saving roles * Rework MemberEditingService to convert keys * Rename variable to groups * Extract to variable
1 parent 94bf4ef commit 7bbef2a

File tree

7 files changed

+38
-13
lines changed

7 files changed

+38
-13
lines changed

src/Umbraco.Cms.Api.Management/Factories/MemberPresentationFactory.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,26 +18,31 @@ internal sealed class MemberPresentationFactory : IMemberPresentationFactory
1818
private readonly IMemberService _memberService;
1919
private readonly IMemberTypeService _memberTypeService;
2020
private readonly ITwoFactorLoginService _twoFactorLoginService;
21+
private readonly IMemberGroupService _memberGroupService;
2122

2223
public MemberPresentationFactory(
2324
IUmbracoMapper umbracoMapper,
2425
IMemberService memberService,
2526
IMemberTypeService memberTypeService,
26-
ITwoFactorLoginService twoFactorLoginService)
27+
ITwoFactorLoginService twoFactorLoginService,
28+
IMemberGroupService memberGroupService)
2729
{
2830
_umbracoMapper = umbracoMapper;
2931
_memberService = memberService;
3032
_memberTypeService = memberTypeService;
3133
_twoFactorLoginService = twoFactorLoginService;
34+
_memberGroupService = memberGroupService;
3235
}
3336

3437
public async Task<MemberResponseModel> CreateResponseModelAsync(IMember member, IUser currentUser)
3538
{
3639
MemberResponseModel responseModel = _umbracoMapper.Map<MemberResponseModel>(member)!;
3740

3841
responseModel.IsTwoFactorEnabled = await _twoFactorLoginService.IsTwoFactorEnabledAsync(member.Key);
39-
responseModel.Groups = _memberService.GetAllRoles(member.Username);
42+
IEnumerable<string> roles = _memberService.GetAllRoles(member.Username);
4043

44+
// Get the member groups per role, so we can return the group keys
45+
responseModel.Groups = roles.Select(x => _memberGroupService.GetByName(x)).WhereNotNull().Select(x => x.Key).ToArray();
4146
return currentUser.HasAccessToSensitiveData()
4247
? responseModel
4348
: await RemoveSensitiveDataAsync(member, responseModel);

src/Umbraco.Cms.Api.Management/ViewModels/Member/CreateMemberRequestModel.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ public class CreateMemberRequestModel : CreateContentRequestModelBase<MemberValu
1212

1313
public required ReferenceByIdModel MemberType { get; set; }
1414

15-
public IEnumerable<string>? Groups { get; set; }
15+
public IEnumerable<Guid>? Groups { get; set; }
1616

1717
public bool IsApproved { get; set; }
1818
}

src/Umbraco.Cms.Api.Management/ViewModels/Member/MemberResponseModel.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,5 @@ public class MemberResponseModel : ContentResponseModelBase<MemberValueModel, Me
2525

2626
public DateTime? LastPasswordChangeDate { get; set; }
2727

28-
public IEnumerable<string> Groups { get; set; } = [];
28+
public IEnumerable<Guid> Groups { get; set; } = [];
2929
}

src/Umbraco.Cms.Api.Management/ViewModels/Member/UpdateMemberRequestModel.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ public class UpdateMemberRequestModel : UpdateContentRequestModelBase<MemberValu
1212

1313
public string? NewPassword { get; set; }
1414

15-
public IEnumerable<string>? Groups { get; set; }
15+
public IEnumerable<Guid>? Groups { get; set; }
1616

1717
public bool IsApproved { get; set; }
1818

src/Umbraco.Core/Models/ContentEditing/MemberEditingModelBase.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ public abstract class MemberEditingModelBase : ContentEditingModelBase
44
{
55
public bool IsApproved { get; set; }
66

7-
public IEnumerable<string>? Roles { get; set; }
7+
public IEnumerable<Guid>? Roles { get; set; }
88

99
public string Email { get; set; } = string.Empty;
1010

src/Umbraco.Infrastructure/Services/MemberEditingService.cs

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ internal sealed class MemberEditingService : IMemberEditingService
1818
private readonly ITwoFactorLoginService _twoFactorLoginService;
1919
private readonly IPasswordChanger<MemberIdentityUser> _passwordChanger;
2020
private readonly ILogger<MemberEditingService> _logger;
21+
private readonly IMemberGroupService _memberGroupService;
2122

2223
public MemberEditingService(
2324
IMemberService memberService,
@@ -26,7 +27,8 @@ public MemberEditingService(
2627
IMemberManager memberManager,
2728
ITwoFactorLoginService twoFactorLoginService,
2829
IPasswordChanger<MemberIdentityUser> passwordChanger,
29-
ILogger<MemberEditingService> logger)
30+
ILogger<MemberEditingService> logger,
31+
IMemberGroupService memberGroupService)
3032
{
3133
_memberService = memberService;
3234
_memberTypeService = memberTypeService;
@@ -35,6 +37,7 @@ public MemberEditingService(
3537
_twoFactorLoginService = twoFactorLoginService;
3638
_passwordChanger = passwordChanger;
3739
_logger = logger;
40+
_memberGroupService = memberGroupService;
3841
}
3942

4043
public async Task<IMember?> GetAsync(Guid key)
@@ -246,16 +249,29 @@ private async Task<MemberEditingOperationStatus> ValidateMemberDataAsync(MemberE
246249
return MemberEditingOperationStatus.Success;
247250
}
248251

249-
private async Task<bool> UpdateRoles(IEnumerable<string>? roles, MemberIdentityUser identityMember)
252+
private async Task<bool> UpdateRoles(IEnumerable<Guid>? roles, MemberIdentityUser identityMember)
250253
{
254+
// We have to convert the GUIDS to names here, as roles on a member are stored by name, not key.
255+
var memberGroups = new List<IMemberGroup>();
256+
foreach (Guid key in roles ?? Enumerable.Empty<Guid>())
257+
{
258+
259+
IMemberGroup? group = await _memberGroupService.GetAsync(key);
260+
if (group is not null)
261+
{
262+
memberGroups.Add(group);
263+
}
264+
}
265+
251266
// We're gonna look up the current roles now because the below code can cause
252267
// events to be raised and developers could be manually adding roles to members in
253268
// their handlers. If we don't look this up now there's a chance we'll just end up
254269
// removing the roles they've assigned.
255270
IEnumerable<string> currentRoles = (await _memberManager.GetRolesAsync(identityMember)).ToList();
256271

257272
// find the ones to remove and remove them
258-
var rolesToRemove = currentRoles.Except(roles ?? Enumerable.Empty<string>()).ToArray();
273+
IEnumerable<string> memberGroupNames = memberGroups.Select(x => x.Name).WhereNotNull().ToArray();
274+
var rolesToRemove = currentRoles.Except(memberGroupNames).ToArray();
259275

260276
// Now let's do the role provider stuff - now that we've saved the content item (that is important since
261277
// if we are changing the username, it must be persisted before looking up the member roles).
@@ -270,8 +286,8 @@ private async Task<bool> UpdateRoles(IEnumerable<string>? roles, MemberIdentityU
270286
}
271287

272288
// find the ones to add and add them
273-
var rolesToAdd = roles?.Except(currentRoles).ToArray();
274-
if (rolesToAdd?.Any() is true)
289+
var rolesToAdd = memberGroupNames.Except(currentRoles).ToArray();
290+
if (rolesToAdd.Any())
275291
{
276292
// add the ones submitted
277293
IdentityResult identityResult = await _memberManager.AddToRolesAsync(identityMember, rolesToAdd);

tests/Umbraco.Tests.Integration/Umbraco.Infrastructure/Services/MemberEditingServiceTests.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ public class MemberEditingServiceTests : UmbracoIntegrationTest
2525

2626
private IUserService UserService => GetRequiredService<IUserService>();
2727

28+
private IMemberGroupService MemberGroupService => GetRequiredService<IMemberGroupService>();
29+
2830
[Test]
2931
public async Task Can_Create_Member()
3032
{
@@ -129,6 +131,7 @@ public async Task Can_Change_Member_Roles()
129131
{
130132
MemberService.AddRole("RoleTwo");
131133
MemberService.AddRole("RoleThree");
134+
var groups = new[] { MemberGroupService.GetByName("RoleTwo"), MemberGroupService.GetByName("RoleThree") };
132135

133136
var member = await CreateMemberAsync();
134137

@@ -138,7 +141,7 @@ public async Task Can_Change_Member_Roles()
138141
Username = member.Username,
139142
IsApproved = true,
140143
InvariantName = member.Name,
141-
Roles = new [] { "RoleTwo", "RoleThree" }
144+
Roles = groups.Select(x => x.Key),
142145
};
143146

144147
var result = await MemberEditingService.UpdateAsync(member.Key, updateModel, SuperUser());
@@ -432,6 +435,7 @@ private async Task<IMember> CreateMemberAsync(Guid? key = null, bool titleIsSens
432435
memberType.SetIsSensitiveProperty("title", titleIsSensitive);
433436
MemberTypeService.Save(memberType);
434437
MemberService.AddRole("RoleOne");
438+
var group = MemberGroupService.GetByName("RoleOne");
435439

436440
var createModel = new MemberCreateModel
437441
{
@@ -441,7 +445,7 @@ private async Task<IMember> CreateMemberAsync(Guid? key = null, bool titleIsSens
441445
Password = "SuperSecret123",
442446
IsApproved = true,
443447
ContentTypeKey = memberType.Key,
444-
Roles = new [] { "RoleOne" },
448+
Roles = new [] { group.Key },
445449
InvariantName = "T. Est",
446450
InvariantProperties = new[]
447451
{

0 commit comments

Comments
 (0)