forked from OrchardCMS/Orchard
-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathUserRolesPartDriver.cs
More file actions
188 lines (167 loc) · 8.88 KB
/
UserRolesPartDriver.cs
File metadata and controls
188 lines (167 loc) · 8.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
using System;
using System.Collections.Generic;
using System.Linq;
using Orchard.ContentManagement;
using Orchard.ContentManagement.Drivers;
using Orchard.ContentManagement.Handlers;
using Orchard.Data;
using Orchard.Localization;
using Orchard.Roles.Events;
using Orchard.Roles.Models;
using Orchard.Roles.Services;
using Orchard.Roles.ViewModels;
using Orchard.Security;
using Orchard.UI.Notify;
namespace Orchard.Roles.Drivers
{
public class UserRolesPartDriver : ContentPartDriver<UserRolesPart>
{
private readonly IRepository<UserRolesPartRecord> _userRolesRepository;
private readonly IRoleService _roleService;
private readonly INotifier _notifier;
private readonly IAuthenticationService _authenticationService;
private readonly IAuthorizationService _authorizationService;
private readonly IRoleEventHandler _roleEventHandlers;
private const string TemplateName = "Parts/Roles.UserRoles";
public UserRolesPartDriver(
IRepository<UserRolesPartRecord> userRolesRepository,
IRoleService roleService,
INotifier notifier,
IAuthenticationService authenticationService,
IAuthorizationService authorizationService,
IRoleEventHandler roleEventHandlers)
{
_userRolesRepository = userRolesRepository;
_roleService = roleService;
_notifier = notifier;
_authenticationService = authenticationService;
_authorizationService = authorizationService;
_roleEventHandlers = roleEventHandlers;
T = NullLocalizer.Instance;
_allRoles = new Lazy<IEnumerable<RoleRecord>>(() => _roleService.GetRoles());
}
protected override string Prefix => "UserRoles";
public Localizer T { get; set; }
private readonly Lazy<IEnumerable<RoleRecord>> _allRoles;
protected override DriverResult Editor(UserRolesPart userRolesPart, dynamic shapeHelper) =>
ContentShape("Parts_Roles_UserRoles_Edit", () =>
{
var currentUser = _authenticationService.GetAuthenticatedUser();
// Get the roles we are authorized to assign
var authorizedRoleIds = _allRoles.Value
.Where(rr => _authorizationService.TryCheckAccess(
Permissions.CreatePermissionForAssignRole(rr.Name),
currentUser,
userRolesPart))
.Select(rr => rr.Id).ToList();
// If the user has no roles they can assign, we will show nothing
if (!authorizedRoleIds.Any())
{
return null;
}
var securityCriticalPermissions = _roleService.GetSecurityCriticalPermissions().ToHashSet();
var model = new UserRolesViewModel
{
User = userRolesPart.As<IUser>(),
UserRoles = userRolesPart,
Roles = _allRoles.Value.Select(role => new UserRoleEntry
{
RoleId = role.Id,
Name = role.Name,
Granted = userRolesPart.Roles.Contains(role.Name),
HasSecurityCriticalPermissions = role.RolesPermissions.Any(p => securityCriticalPermissions.Contains(p.Permission.Name))
}).ToList(),
AuthorizedRoleIds = authorizedRoleIds,
};
return shapeHelper.EditorTemplate(TemplateName: TemplateName, Model: model, Prefix: Prefix);
});
protected override DriverResult Editor(UserRolesPart userRolesPart, IUpdateModel updater, dynamic shapeHelper)
{
var currentUser = _authenticationService.GetAuthenticatedUser();
// Get the roles we are authorized to assign
var authorizedRoleIds = _allRoles.Value
.Where(rr => _authorizationService.TryCheckAccess(
Permissions.CreatePermissionForAssignRole(rr.Name),
currentUser,
userRolesPart))
.Select(rr => rr.Id).ToList();
var model = BuildEditorViewModel(userRolesPart);
if (updater.TryUpdateModel(model, Prefix, null, null))
{
// We only have something to do for the roles the user is allowed to assign. We do this check
// after the TryUpdateModel so that even if we do nothing, we'll display things as the user
// changed them.
if (authorizedRoleIds.Any())
{
// Find all RoleRecord objects for the user: these are roles that are already
// assigned to them.
var currentUserRoleRecords = _userRolesRepository.Fetch(x => x.UserId == model.User.Id).ToArray();
var currentRoleRecords = currentUserRoleRecords.Select(x => x.Role);
// The roles the user should have after the update (pending a verification that
// the currentUser is allowed to assign them)
var targetRoleRecords = model.Roles.Where(x => x.Granted).Select(x => _roleService.GetRole(x.RoleId)).ToArray();
foreach (var addingRole in targetRoleRecords
.Where(x =>
// user doesn't have the role yet
!currentRoleRecords.Contains(x)
// && we are authorized to assign this role
&& authorizedRoleIds.Contains(x.Id)))
{
_notifier.Warning(T("Adding role {0} to user {1}", addingRole.Name, userRolesPart.As<IUser>().UserName));
_userRolesRepository.Create(new UserRolesPartRecord { UserId = model.User.Id, Role = addingRole });
_roleEventHandlers.UserAdded(new UserAddedContext { Role = addingRole, User = model.User });
}
foreach (var removingRole in currentUserRoleRecords
.Where(x =>
// user has this role that they shouldn't
!targetRoleRecords.Contains(x.Role)
// && we are authorized to assign this role
&& authorizedRoleIds.Contains(x.Role.Id)))
{
_notifier.Warning(T("Removing role {0} from user {1}", removingRole.Role.Name, userRolesPart.As<IUser>().UserName));
_userRolesRepository.Delete(removingRole);
_roleEventHandlers.UserRemoved(new UserRemovedContext { Role = removingRole.Role, User = model.User });
}
}
}
model.AuthorizedRoleIds = authorizedRoleIds;
return ContentShape("Parts_Roles_UserRoles_Edit",
() => shapeHelper.EditorTemplate(TemplateName: TemplateName, Model: model, Prefix: Prefix));
}
private static UserRolesViewModel BuildEditorViewModel(UserRolesPart userRolesPart) =>
new UserRolesViewModel { User = userRolesPart.As<IUser>(), UserRoles = userRolesPart };
protected override void Importing(UserRolesPart part, ImportContentContext context)
{
// Don't do anything if the tag is not specified.
if (context.Data.Element(part.PartDefinition.Name) == null)
{
return;
}
context.ImportAttribute(part.PartDefinition.Name, "Roles", roles =>
{
var userRoles = roles.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
// create new roles
foreach (var role in userRoles)
{
var roleRecord = _roleService.GetRoleByName(role);
// create the role if it doesn't already exist
if (roleRecord == null)
{
_roleService.CreateRole(role);
}
}
var currentUserRoleRecords = _userRolesRepository.Fetch(x => x.UserId == part.ContentItem.Id).ToList();
var currentRoleRecords = currentUserRoleRecords.Select(x => x.Role).ToList();
var targetRoleRecords = userRoles.Select(x => _roleService.GetRoleByName(x)).ToList();
foreach (var addingRole in targetRoleRecords.Where(x => !currentRoleRecords.Contains(x)))
{
_userRolesRepository.Create(new UserRolesPartRecord { UserId = part.ContentItem.Id, Role = addingRole });
}
});
}
protected override void Exporting(UserRolesPart part, ExportContentContext context)
{
context.Element(part.PartDefinition.Name).SetAttributeValue("Roles", string.Join(",", part.Roles));
}
}
}