-
Notifications
You must be signed in to change notification settings - Fork 2.4k
/
UserDisplayDriver.cs
157 lines (138 loc) · 6.51 KB
/
UserDisplayDriver.cs
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
using System.Security.Claims;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc.Localization;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using OrchardCore.DisplayManagement.Handlers;
using OrchardCore.DisplayManagement.Notify;
using OrchardCore.DisplayManagement.Views;
using OrchardCore.Modules;
using OrchardCore.Mvc.ModelBinding;
using OrchardCore.Users.Handlers;
using OrchardCore.Users.Models;
using OrchardCore.Users.ViewModels;
namespace OrchardCore.Users.Drivers;
public sealed class UserDisplayDriver : DisplayDriver<User>
{
private readonly UserManager<IUser> _userManager;
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly INotifier _notifier;
private readonly IAuthorizationService _authorizationService;
private readonly IEnumerable<IUserEventHandler> _userEventHandlers;
private readonly ILogger _logger;
internal readonly IHtmlLocalizer H;
internal readonly IStringLocalizer S;
public UserDisplayDriver(
UserManager<IUser> userManager,
IHttpContextAccessor httpContextAccessor,
INotifier notifier,
ILogger<UserDisplayDriver> logger,
IEnumerable<IUserEventHandler> userEventHandlers,
IAuthorizationService authorizationService,
IHtmlLocalizer<UserDisplayDriver> htmlLocalizer,
IStringLocalizer<UserDisplayDriver> stringLocalizer)
{
_userManager = userManager;
_httpContextAccessor = httpContextAccessor;
_notifier = notifier;
_authorizationService = authorizationService;
_logger = logger;
_userEventHandlers = userEventHandlers;
H = htmlLocalizer;
S = stringLocalizer;
}
public override Task<IDisplayResult> DisplayAsync(User user, BuildDisplayContext context)
{
return CombineAsync(
Initialize<SummaryAdminUserViewModel>("UserFields", model => model.User = user).Location("SummaryAdmin", "Header:1"),
Initialize<SummaryAdminUserViewModel>("UserInfo", model => model.User = user).Location("DetailAdmin", "Content:5"),
Initialize<SummaryAdminUserViewModel>("UserButtons", model => model.User = user).Location("SummaryAdmin", "Actions:1"),
Initialize<SummaryAdminUserViewModel>("UserActionsMenu", model => model.User = user).Location("SummaryAdmin", "ActionsMenu:5")
);
}
public override async Task<IDisplayResult> EditAsync(User user, BuildEditorContext context)
{
if (!await _authorizationService.AuthorizeAsync(_httpContextAccessor.HttpContext.User, CommonPermissions.EditUsers, user))
{
return null;
}
return Initialize<EditUserViewModel>("UserFields_Edit", model =>
{
model.EmailConfirmed = user.EmailConfirmed;
model.IsEnabled = user.IsEnabled;
model.IsNewRequest = context.IsNew;
// The current user cannot disable themselves, nor can a user without permission to manage this user disable them.
model.IsEditingDisabled = IsCurrentUser(user);
})
.Location("Content:1.5");
}
public override async Task<IDisplayResult> UpdateAsync(User user, UpdateEditorContext context)
{
// To prevent html injection when updating the user must meet all authorization requirements.
if (!await _authorizationService.AuthorizeAsync(_httpContextAccessor.HttpContext.User, CommonPermissions.EditUsers, user))
{
// When the user is only editing their profile never update this part of the user.
return await EditAsync(user, context);
}
var model = new EditUserViewModel();
await context.Updater.TryUpdateModelAsync(model, Prefix);
if (context.IsNew)
{
if (string.IsNullOrWhiteSpace(model.Password))
{
context.Updater.ModelState.AddModelError(Prefix, nameof(model.Password), S["A password is required"]);
}
if (model.Password != model.PasswordConfirmation)
{
context.Updater.ModelState.AddModelError(Prefix, nameof(model.Password), S["The password and the password confirmation fields must match."]);
}
}
if (!context.Updater.ModelState.IsValid)
{
return await EditAsync(user, context);
}
var isEditingDisabled = IsCurrentUser(user);
if (!isEditingDisabled && !model.IsEnabled && user.IsEnabled)
{
var enabledUsersOfAdminRole = (await _userManager.GetUsersInRoleAsync(OrchardCoreConstants.Roles.Administrator))
.Cast<User>()
.Where(user => user.IsEnabled)
.ToList();
if (enabledUsersOfAdminRole.Count == 1 && user.UserId == enabledUsersOfAdminRole.First().UserId)
{
await _notifier.WarningAsync(H["Cannot disable the only enabled administrator."]);
}
else
{
user.IsEnabled = model.IsEnabled;
var userContext = new UserContext(user);
// TODO This handler should be invoked through the create or update methods.
// otherwise it will not be invoked when a workflow, or other operation, changes this value.
await _userEventHandlers.InvokeAsync((handler, context) => handler.DisabledAsync(userContext), userContext, _logger);
}
}
else if (!isEditingDisabled && model.IsEnabled && !user.IsEnabled)
{
user.IsEnabled = model.IsEnabled;
var userContext = new UserContext(user);
// TODO This handler should be invoked through the create or update methods.
// otherwise it will not be invoked when a workflow, or other operation, changes this value.
await _userEventHandlers.InvokeAsync((handler, context) => handler.EnabledAsync(userContext), userContext, _logger);
}
if (context.Updater.ModelState.IsValid)
{
if (model.EmailConfirmed && !await _userManager.IsEmailConfirmedAsync(user))
{
var token = await _userManager.GenerateEmailConfirmationTokenAsync(user);
await _userManager.ConfirmEmailAsync(user, token);
}
}
return await EditAsync(user, context);
}
private bool IsCurrentUser(User user)
{
return _httpContextAccessor.HttpContext.User.FindFirstValue(ClaimTypes.NameIdentifier) == user.UserId;
}
}