Skip to content

Commit

Permalink
Add member "kind" - and refactor user "type" to "kind" for consistency (
Browse files Browse the repository at this point in the history
#16979)

* Rename UserType to UserKind

* Add MemberKind to tell API members from regular ones

* Remove user kind from invite user endpoint

---------

Co-authored-by: Mads Rasmussen <[email protected]>
  • Loading branch information
kjac and madsrasmussen committed Sep 3, 2024
1 parent 2a6b376 commit 874055e
Show file tree
Hide file tree
Showing 28 changed files with 129 additions and 73 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ internal static class MemberBuilderExtensions
{
internal static IUmbracoBuilder AddMember(this IUmbracoBuilder builder)
{
builder.Services.AddTransient<IMemberPresentationFactory, MemberPresentationFactory>();
builder.Services.AddSingleton<IMemberPresentationFactory, MemberPresentationFactory>();
builder.Services.AddTransient<IMemberEditingPresentationFactory, MemberEditingPresentationFactory>();

builder.WithCollectionBuilder<MapDefinitionCollectionBuilder>().Add<MemberMapDefinition>();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
using Umbraco.Cms.Api.Management.ViewModels.Content;
using Microsoft.Extensions.Options;
using Umbraco.Cms.Api.Management.ViewModels.Content;
using Umbraco.Cms.Api.Management.ViewModels.Member;
using Umbraco.Cms.Api.Management.ViewModels.Member.Item;
using Umbraco.Cms.Api.Management.ViewModels.MemberType;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Extensions;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Models;
Expand All @@ -19,26 +21,31 @@ internal sealed class MemberPresentationFactory : IMemberPresentationFactory
private readonly IMemberTypeService _memberTypeService;
private readonly ITwoFactorLoginService _twoFactorLoginService;
private readonly IMemberGroupService _memberGroupService;
private readonly DeliveryApiSettings _deliveryApiSettings;
private IEnumerable<Guid>? _clientCredentialsMemberKeys;

public MemberPresentationFactory(
IUmbracoMapper umbracoMapper,
IMemberService memberService,
IMemberTypeService memberTypeService,
ITwoFactorLoginService twoFactorLoginService,
IMemberGroupService memberGroupService)
IMemberGroupService memberGroupService,
IOptions<DeliveryApiSettings> deliveryApiSettings)
{
_umbracoMapper = umbracoMapper;
_memberService = memberService;
_memberTypeService = memberTypeService;
_twoFactorLoginService = twoFactorLoginService;
_memberGroupService = memberGroupService;
_deliveryApiSettings = deliveryApiSettings.Value;
}

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

responseModel.IsTwoFactorEnabled = await _twoFactorLoginService.IsTwoFactorEnabledAsync(member.Key);
responseModel.Kind = GetMemberKind(member.Key);
IEnumerable<string> roles = _memberService.GetAllRoles(member.Username);

// Get the member groups per role, so we can return the group keys
Expand Down Expand Up @@ -71,7 +78,8 @@ private MemberItemResponseModel CreateItemResponseModel<T>(T entity)
{
Id = entity.Key,
MemberType = _umbracoMapper.Map<MemberTypeReferenceResponseModel>(entity)!,
Variants = CreateVariantsItemResponseModels(entity)
Variants = CreateVariantsItemResponseModels(entity),
Kind = GetMemberKind(entity.Key)
};

private static IEnumerable<VariantItemResponseModel> CreateVariantsItemResponseModels(ITreeEntity entity)
Expand Down Expand Up @@ -108,4 +116,24 @@ private async Task<MemberResponseModel> RemoveSensitiveDataAsync(IMember member,

return responseModel;
}

private MemberKind GetMemberKind(Guid key)
{
if (_clientCredentialsMemberKeys is null)
{
IEnumerable<string> clientCredentialsMemberUserNames = _deliveryApiSettings
.MemberAuthorization?
.ClientCredentialsFlow?
.AssociatedMembers
.Select(m => m.UserName).ToArray()
?? [];

_clientCredentialsMemberKeys = clientCredentialsMemberUserNames
.Select(_memberService.GetByUsername)
.WhereNotNull()
.Select(m => m.Key).ToArray();
}

return _clientCredentialsMemberKeys.Contains(key) ? MemberKind.Api : MemberKind.Default;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ public UserResponseModel CreateResponseModel(IUser user)
LastLockoutDate = user.LastLockoutDate,
LastPasswordChangeDate = user.LastPasswordChangeDate,
IsAdmin = user.IsAdmin(),
Type = user.Type
Kind = user.Kind
};

return responseModel;
Expand All @@ -93,7 +93,7 @@ public UserItemResponseModel CreateItemResponseModel(IUser user) =>
Name = user.Name ?? user.Username,
AvatarUrls = user.GetUserAvatarUrls(_appCaches.RuntimeCache, _mediaFileManager, _imageUrlGenerator)
.Select(url => _absoluteUrlBuilder.ToAbsoluteUrl(url).ToString()),
Type = user.Type
Kind = user.Kind
};

public async Task<UserCreateModel> CreateCreationModelAsync(CreateUserRequestModel requestModel)
Expand All @@ -105,7 +105,7 @@ public async Task<UserCreateModel> CreateCreationModelAsync(CreateUserRequestMod
Name = requestModel.Name,
UserName = requestModel.UserName,
UserGroupKeys = requestModel.UserGroupIds.Select(x => x.Id).ToHashSet(),
Type = requestModel.Type
Kind = requestModel.Kind
};

return await Task.FromResult(createModel);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public MemberMapDefinition(PropertyEditorCollection propertyEditorCollection)
public void DefineMaps(IUmbracoMapper mapper)
=> mapper.Define<IMember, MemberResponseModel>((_, _) => new MemberResponseModel(), Map);

// Umbraco.Code.MapAll -IsTwoFactorEnabled -Groups
// Umbraco.Code.MapAll -IsTwoFactorEnabled -Groups -Kind
private void Map(IMember source, MemberResponseModel target, MapperContext context)
{
target.Id = source.Key;
Expand Down
55 changes: 33 additions & 22 deletions src/Umbraco.Cms.Api.Management/OpenApi.json
Original file line number Diff line number Diff line change
Expand Up @@ -35493,8 +35493,8 @@
"CreateUserRequestModel": {
"required": [
"email",
"kind",
"name",
"type",
"userGroupIds",
"userName"
],
Expand Down Expand Up @@ -35525,8 +35525,8 @@
"format": "uuid",
"nullable": true
},
"type": {
"$ref": "#/components/schemas/UserTypeModel"
"kind": {
"$ref": "#/components/schemas/UserKindModel"
}
},
"additionalProperties": false
Expand Down Expand Up @@ -38244,7 +38244,6 @@
"required": [
"email",
"name",
"type",
"userGroupIds",
"userName"
],
Expand Down Expand Up @@ -38275,9 +38274,6 @@
"format": "uuid",
"nullable": true
},
"type": {
"$ref": "#/components/schemas/UserTypeModel"
},
"message": {
"type": "string",
"nullable": true
Expand Down Expand Up @@ -39415,6 +39411,7 @@
"MemberItemResponseModel": {
"required": [
"id",
"kind",
"memberType",
"variants"
],
Expand All @@ -39440,10 +39437,20 @@
}
]
}
},
"kind": {
"$ref": "#/components/schemas/MemberKindModel"
}
},
"additionalProperties": false
},
"MemberKindModel": {
"enum": [
"Default",
"Api"
],
"type": "string"
},
"MemberResponseModel": {
"required": [
"email",
Expand All @@ -39453,6 +39460,7 @@
"isApproved",
"isLockedOut",
"isTwoFactorEnabled",
"kind",
"memberType",
"username",
"values",
Expand Down Expand Up @@ -39531,6 +39539,9 @@
"type": "string",
"format": "uuid"
}
},
"kind": {
"$ref": "#/components/schemas/MemberKindModel"
}
},
"additionalProperties": false
Expand Down Expand Up @@ -45082,8 +45093,8 @@
"required": [
"avatarUrls",
"id",
"name",
"type"
"kind",
"name"
],
"type": "object",
"properties": {
Expand All @@ -45100,12 +45111,19 @@
"type": "string"
}
},
"type": {
"$ref": "#/components/schemas/UserTypeModel"
"kind": {
"$ref": "#/components/schemas/UserKindModel"
}
},
"additionalProperties": false
},
"UserKindModel": {
"enum": [
"Default",
"Api"
],
"type": "string"
},
"UserOrderModel": {
"enum": [
"UserName",
Expand Down Expand Up @@ -45172,10 +45190,10 @@
"hasMediaRootAccess",
"id",
"isAdmin",
"kind",
"mediaStartNodeIds",
"name",
"state",
"type",
"updateDate",
"userGroupIds",
"userName"
Expand Down Expand Up @@ -45277,8 +45295,8 @@
"isAdmin": {
"type": "boolean"
},
"type": {
"$ref": "#/components/schemas/UserTypeModel"
"kind": {
"$ref": "#/components/schemas/UserKindModel"
}
},
"additionalProperties": false
Expand Down Expand Up @@ -45339,13 +45357,6 @@
},
"additionalProperties": false
},
"UserTypeModel": {
"enum": [
"Default",
"Api"
],
"type": "string"
},
"VariantItemResponseModel": {
"required": [
"name"
Expand Down Expand Up @@ -45566,4 +45577,4 @@
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Umbraco.Cms.Api.Management.ViewModels.Content;
using Umbraco.Cms.Api.Management.ViewModels.Item;
using Umbraco.Cms.Api.Management.ViewModels.MemberType;
using Umbraco.Cms.Core.Models.Membership;

namespace Umbraco.Cms.Api.Management.ViewModels.Member.Item;

Expand All @@ -9,4 +10,6 @@ public class MemberItemResponseModel : ItemResponseModelBase
public MemberTypeReferenceResponseModel MemberType { get; set; } = new();

public IEnumerable<VariantItemResponseModel> Variants { get; set; } = Enumerable.Empty<VariantItemResponseModel>();

public MemberKind Kind { get; set; }
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Umbraco.Cms.Api.Management.ViewModels.Content;
using Umbraco.Cms.Api.Management.ViewModels.MemberType;
using Umbraco.Cms.Core.Models.Membership;

namespace Umbraco.Cms.Api.Management.ViewModels.Member;

Expand All @@ -26,4 +27,6 @@ public class MemberResponseModel : ContentResponseModelBase<MemberValueModel, Me
public DateTimeOffset? LastPasswordChangeDate { get; set; }

public IEnumerable<Guid> Groups { get; set; } = [];

public MemberKind Kind { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@

namespace Umbraco.Cms.Api.Management.ViewModels.User;

public class CreateUserRequestModel : UserPresentationBase
public class CreateUserRequestModel : CreateUserRequestModelBase
{
public Guid? Id { get; set; }

public UserType Type { get; set; }
public UserKind Kind { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Umbraco.Cms.Api.Management.ViewModels.User;

public class CreateUserRequestModelBase : UserPresentationBase
{
public Guid? Id { get; set; }
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace Umbraco.Cms.Api.Management.ViewModels.User;

public class InviteUserRequestModel : CreateUserRequestModel
public class InviteUserRequestModel : CreateUserRequestModelBase
{
public string? Message { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ public class UserItemResponseModel : NamedItemResponseModelBase
{
public IEnumerable<string> AvatarUrls { get; set; } = Enumerable.Empty<string>();

public UserType Type { get; set; }
public UserKind Kind { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,5 @@ public class UserResponseModel : UserPresentationBase

public bool IsAdmin { get; set; }

public UserType Type { get; set; }
public UserKind Kind { get; set; }
}
2 changes: 1 addition & 1 deletion src/Umbraco.Core/Models/Membership/IUser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public interface IUser : IMembershipUser, IRememberBeingDirty
/// <summary>
/// The type of user.
/// </summary>
UserType Type { get; set; }
UserKind Kind { get; set; }

void RemoveGroup(string group);

Expand Down
7 changes: 7 additions & 0 deletions src/Umbraco.Core/Models/Membership/MemberKind.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Umbraco.Cms.Core.Models.Membership;

public enum MemberKind
{
Default = 0,
Api
}
8 changes: 4 additions & 4 deletions src/Umbraco.Core/Models/Membership/User.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public class User : EntityBase, IUser, IProfile
private HashSet<IReadOnlyUserGroup> _userGroups;

private string _username;
private UserType _type;
private UserKind _kind;

/// <summary>
/// Constructor for creating a new/empty user
Expand Down Expand Up @@ -359,10 +359,10 @@ public string? Language
}

[DataMember]
public UserType Type
public UserKind Kind
{
get => _type;
set => SetPropertyValueAndDetectChanges(value, ref _type, nameof(Type));
get => _kind;
set => SetPropertyValueAndDetectChanges(value, ref _kind, nameof(Kind));
}

/// <summary>
Expand Down
Loading

0 comments on commit 874055e

Please sign in to comment.