1- using Umbraco . Cms . Api . Management . Routing ;
1+ using Microsoft . Extensions . DependencyInjection ;
22using Microsoft . Extensions . Options ;
3+ using Umbraco . Cms . Api . Management . Routing ;
34using Umbraco . Cms . Api . Management . Security ;
45using Umbraco . Cms . Api . Management . ViewModels ;
56using Umbraco . Cms . Api . Management . ViewModels . User ;
67using Umbraco . Cms . Api . Management . ViewModels . User . Current ;
7- using Umbraco . Cms . Core ;
88using Umbraco . Cms . Api . Management . ViewModels . User . Item ;
9+ using Umbraco . Cms . Api . Management . ViewModels . UserGroup ;
10+ using Umbraco . Cms . Api . Management . ViewModels . UserGroup . Permissions ;
11+ using Umbraco . Cms . Core ;
912using Umbraco . Cms . Core . Cache ;
1013using Umbraco . Cms . Core . Configuration . Models ;
14+ using Umbraco . Cms . Core . DependencyInjection ;
1115using Umbraco . Cms . Core . IO ;
1216using Umbraco . Cms . Core . Mail ;
1317using Umbraco . Cms . Core . Media ;
@@ -20,7 +24,6 @@ namespace Umbraco.Cms.Api.Management.Factories;
2024
2125public class UserPresentationFactory : IUserPresentationFactory
2226{
23-
2427 private readonly IEntityService _entityService ;
2528 private readonly AppCaches _appCaches ;
2629 private readonly MediaFileManager _mediaFileManager ;
@@ -31,7 +34,10 @@ public class UserPresentationFactory : IUserPresentationFactory
3134 private readonly IPasswordConfigurationPresentationFactory _passwordConfigurationPresentationFactory ;
3235 private readonly IBackOfficeExternalLoginProviders _externalLoginProviders ;
3336 private readonly SecuritySettings _securitySettings ;
37+ private readonly IUserService _userService ;
38+ private readonly IContentService _contentService ;
3439
40+ [ Obsolete ( "Please use the constructor taking all parameters. Scheduled for removal in Umbraco 17." ) ]
3541 public UserPresentationFactory (
3642 IEntityService entityService ,
3743 AppCaches appCaches ,
@@ -43,6 +49,35 @@ public UserPresentationFactory(
4349 IPasswordConfigurationPresentationFactory passwordConfigurationPresentationFactory ,
4450 IOptionsSnapshot < SecuritySettings > securitySettings ,
4551 IBackOfficeExternalLoginProviders externalLoginProviders )
52+ : this (
53+ entityService ,
54+ appCaches ,
55+ mediaFileManager ,
56+ imageUrlGenerator ,
57+ userGroupPresentationFactory ,
58+ absoluteUrlBuilder ,
59+ emailSender ,
60+ passwordConfigurationPresentationFactory ,
61+ securitySettings ,
62+ externalLoginProviders ,
63+ StaticServiceProvider . Instance . GetRequiredService < IUserService > ( ) ,
64+ StaticServiceProvider . Instance . GetRequiredService < IContentService > ( ) )
65+ {
66+ }
67+
68+ public UserPresentationFactory (
69+ IEntityService entityService ,
70+ AppCaches appCaches ,
71+ MediaFileManager mediaFileManager ,
72+ IImageUrlGenerator imageUrlGenerator ,
73+ IUserGroupPresentationFactory userGroupPresentationFactory ,
74+ IAbsoluteUrlBuilder absoluteUrlBuilder ,
75+ IEmailSender emailSender ,
76+ IPasswordConfigurationPresentationFactory passwordConfigurationPresentationFactory ,
77+ IOptionsSnapshot < SecuritySettings > securitySettings ,
78+ IBackOfficeExternalLoginProviders externalLoginProviders ,
79+ IUserService userService ,
80+ IContentService contentService )
4681 {
4782 _entityService = entityService ;
4883 _appCaches = appCaches ;
@@ -54,6 +89,8 @@ public UserPresentationFactory(
5489 _externalLoginProviders = externalLoginProviders ;
5590 _securitySettings = securitySettings . Value ;
5691 _absoluteUrlBuilder = absoluteUrlBuilder ;
92+ _userService = userService ;
93+ _contentService = contentService ;
5794 }
5895
5996 public UserResponseModel CreateResponseModel ( IUser user )
@@ -195,7 +232,7 @@ public async Task<CurrentUserResponseModel> CreateCurrentUserResponseModelAsync(
195232 var contentStartNodeIds = user . CalculateContentStartNodeIds ( _entityService , _appCaches ) ;
196233 var documentStartNodeKeys = GetKeysFromIds ( contentStartNodeIds , UmbracoObjectTypes . Document ) ;
197234
198- var permissions = presentationGroups . SelectMany ( x => x . Permissions ) . ToHashSet ( ) ;
235+ var permissions = GetAggregatedGranularPermissions ( user , presentationGroups ) ;
199236 var fallbackPermissions = presentationGroups . SelectMany ( x => x . FallbackPermissions ) . ToHashSet ( ) ;
200237
201238 var hasAccessToAllLanguages = presentationGroups . Any ( x => x . HasAccessToAllLanguages ) ;
@@ -225,6 +262,42 @@ public async Task<CurrentUserResponseModel> CreateCurrentUserResponseModelAsync(
225262 } ) ;
226263 }
227264
265+ private HashSet < IPermissionPresentationModel > GetAggregatedGranularPermissions ( IUser user , IEnumerable < UserGroupResponseModel > presentationGroups )
266+ {
267+ var permissions = presentationGroups . SelectMany ( x => x . Permissions ) . ToHashSet ( ) ;
268+
269+ // The raw permission data consists of several permissions for each document. We want to aggregate this server-side so
270+ // we return one set of aggregate permissions per document that the client will use.
271+
272+ // Get the unique document keys that have granular permissions.
273+ IEnumerable < Guid > documentKeysWithGranularPermissions = permissions
274+ . Where ( x => x is DocumentPermissionPresentationModel )
275+ . Cast < DocumentPermissionPresentationModel > ( )
276+ . Select ( x => x . Document . Id )
277+ . Distinct ( ) ;
278+
279+ var aggregatedPermissions = new HashSet < IPermissionPresentationModel > ( ) ;
280+ foreach ( Guid documentKey in documentKeysWithGranularPermissions )
281+ {
282+ // Retrieve the path of the document.
283+ var path = _contentService . GetById ( documentKey ) ? . Path ;
284+ if ( string . IsNullOrEmpty ( path ) )
285+ {
286+ continue ;
287+ }
288+
289+ // With the path we can call the same logic as used server-side for authorizing access to resources.
290+ EntityPermissionSet permissionsForPath = _userService . GetPermissionsForPath ( user , path ) ;
291+ aggregatedPermissions . Add ( new DocumentPermissionPresentationModel
292+ {
293+ Document = new ReferenceByIdModel ( documentKey ) ,
294+ Verbs = permissionsForPath . GetAllPermissions ( )
295+ } ) ;
296+ }
297+
298+ return aggregatedPermissions ;
299+ }
300+
228301 public async Task < CalculatedUserStartNodesResponseModel > CreateCalculatedUserStartNodesResponseModelAsync ( IUser user )
229302 {
230303 var mediaStartNodeIds = user . CalculateMediaStartNodeIds ( _entityService , _appCaches ) ;
0 commit comments