|
@@ -3,6 +3,7 @@ using Inversion;
|
|
|
using Astralis;
|
|
using Astralis;
|
|
|
using Invercargill;
|
|
using Invercargill;
|
|
|
using Invercargill.DataStructures;
|
|
using Invercargill.DataStructures;
|
|
|
|
|
+using Spry.Authorisation;
|
|
|
|
|
|
|
|
namespace Spry.Authentication.Components {
|
|
namespace Spry.Authentication.Components {
|
|
|
|
|
|
|
@@ -29,10 +30,9 @@ namespace Spry.Authentication.Components {
|
|
|
*/
|
|
*/
|
|
|
public class UserDetailsComponent : Component {
|
|
public class UserDetailsComponent : Component {
|
|
|
|
|
|
|
|
- private User _user;
|
|
|
|
|
- private PermissionService _permission_service = inject<PermissionService>();
|
|
|
|
|
|
|
+ private UserProjection _user;
|
|
|
|
|
+ private AuthorisationContext _auth_context = inject<AuthorisationContext>();
|
|
|
private UserService _user_service = inject<UserService>();
|
|
private UserService _user_service = inject<UserService>();
|
|
|
- private SessionService _session_service = inject<SessionService>();
|
|
|
|
|
private ComponentFactory _factory = inject<ComponentFactory>();
|
|
private ComponentFactory _factory = inject<ComponentFactory>();
|
|
|
private HttpContext _http_context = inject<HttpContext>();
|
|
private HttpContext _http_context = inject<HttpContext>();
|
|
|
|
|
|
|
@@ -57,7 +57,7 @@ namespace Spry.Authentication.Components {
|
|
|
// State Properties (must be public for template expression access)
|
|
// State Properties (must be public for template expression access)
|
|
|
// =========================================================================
|
|
// =========================================================================
|
|
|
|
|
|
|
|
- public string user_id { get; private set; default = ""; }
|
|
|
|
|
|
|
+ public int64 user_id { get; private set; default = 0; }
|
|
|
public string username { get; private set; default = ""; }
|
|
public string username { get; private set; default = ""; }
|
|
|
public string email { get; private set; default = ""; }
|
|
public string email { get; private set; default = ""; }
|
|
|
public string created_at { get; private set; default = ""; }
|
|
public string created_at { get; private set; default = ""; }
|
|
@@ -75,13 +75,23 @@ namespace Spry.Authentication.Components {
|
|
|
*
|
|
*
|
|
|
* @param user The user to display
|
|
* @param user The user to display
|
|
|
*/
|
|
*/
|
|
|
- public void set_user(User user) {
|
|
|
|
|
|
|
+ public void set_user(UserProjection user) {
|
|
|
_user = user;
|
|
_user = user;
|
|
|
user_id = user.id;
|
|
user_id = user.id;
|
|
|
username = user.username;
|
|
username = user.username;
|
|
|
email = user.email;
|
|
email = user.email;
|
|
|
- created_at = user.created_at.format("%Y-%m-%d %H:%M:%S UTC");
|
|
|
|
|
- permissions = user.permissions;
|
|
|
|
|
|
|
+ created_at = user.created.format("%Y-%m-%d %H:%M:%S UTC");
|
|
|
|
|
+ // Convert ImmutableLot<string> to string[]
|
|
|
|
|
+ var perm_list = new List<string>();
|
|
|
|
|
+ foreach (var perm in user.permissions) {
|
|
|
|
|
+ perm_list.append(perm);
|
|
|
|
|
+ }
|
|
|
|
|
+ var perm_array = new string[perm_list.length()];
|
|
|
|
|
+ int i = 0;
|
|
|
|
|
+ foreach (var perm in perm_list) {
|
|
|
|
|
+ perm_array[i++] = perm;
|
|
|
|
|
+ }
|
|
|
|
|
+ permissions = perm_array;
|
|
|
permission_count = permissions.length;
|
|
permission_count = permissions.length;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -90,7 +100,7 @@ namespace Spry.Authentication.Components {
|
|
|
*
|
|
*
|
|
|
* @return The user being displayed
|
|
* @return The user being displayed
|
|
|
*/
|
|
*/
|
|
|
- public User get_user() {
|
|
|
|
|
|
|
+ public UserProjection get_user() {
|
|
|
return _user;
|
|
return _user;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -122,7 +132,7 @@ namespace Spry.Authentication.Components {
|
|
|
<tbody>
|
|
<tbody>
|
|
|
<tr>
|
|
<tr>
|
|
|
<td style="padding: 0.5rem 0; font-weight: 500; width: 150px; vertical-align: top;">User ID</td>
|
|
<td style="padding: 0.5rem 0; font-weight: 500; width: 150px; vertical-align: top;">User ID</td>
|
|
|
- <td style="padding: 0.5rem 0;"><code content-expr="this.user_id" style="font-size: 0.85rem; background: #f5f5f5; padding: 0.125rem 0.25rem; border-radius: 3px;"></code></td>
|
|
|
|
|
|
|
+ <td style="padding: 0.5rem 0;"><code content-expr="this.user_id.to_string()" style="font-size: 0.85rem; background: #f5f5f5; padding: 0.125rem 0.25rem; border-radius: 3px;"></code></td>
|
|
|
</tr>
|
|
</tr>
|
|
|
<tr>
|
|
<tr>
|
|
|
<td style="padding: 0.5rem 0; font-weight: 500;">Username</td>
|
|
<td style="padding: 0.5rem 0; font-weight: 500;">Username</td>
|
|
@@ -174,7 +184,7 @@ namespace Spry.Authentication.Components {
|
|
|
<tbody>
|
|
<tbody>
|
|
|
<tr>
|
|
<tr>
|
|
|
<td style="padding: 0.5rem 0; font-weight: 500; width: 150px;">User ID</td>
|
|
<td style="padding: 0.5rem 0; font-weight: 500; width: 150px;">User ID</td>
|
|
|
- <td style="padding: 0.5rem 0;"><code content-expr="this.user_id" style="font-size: 0.85rem; background: #f5f5f5; padding: 0.125rem 0.25rem; border-radius: 3px;"></code></td>
|
|
|
|
|
|
|
+ <td style="padding: 0.5rem 0;"><code content-expr="this.user_id.to_string()" style="font-size: 0.85rem; background: #f5f5f5; padding: 0.125rem 0.25rem; border-radius: 3px;"></code></td>
|
|
|
</tr>
|
|
</tr>
|
|
|
<tr>
|
|
<tr>
|
|
|
<td style="padding: 0.5rem 0; font-weight: 500;">Username *</td>
|
|
<td style="padding: 0.5rem 0; font-weight: 500;">Username *</td>
|
|
@@ -373,26 +383,45 @@ namespace Spry.Authentication.Components {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
try {
|
|
|
- // Update user object
|
|
|
|
|
- _user.set_username(new_username);
|
|
|
|
|
- _user.email = new_email;
|
|
|
|
|
-
|
|
|
|
|
|
|
+ // Update user using alter_user
|
|
|
|
|
+ yield _user_service.alter_user(
|
|
|
|
|
+ _user.id,
|
|
|
|
|
+ new_username,
|
|
|
|
|
+ new_email,
|
|
|
|
|
+ _user.forename ?? "",
|
|
|
|
|
+ _user.surname ?? "",
|
|
|
|
|
+ _user.date_of_birth,
|
|
|
|
|
+ _user.enabled
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
// Update password if provided
|
|
// Update password if provided
|
|
|
if (new_password.length > 0) {
|
|
if (new_password.length > 0) {
|
|
|
- yield _user_service.set_password_async(_user, new_password);
|
|
|
|
|
|
|
+ yield _user_service.set_password(_user.id, new_password);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- // Persist user changes
|
|
|
|
|
- yield _user_service.update_user_async(_user);
|
|
|
|
|
|
|
|
|
|
// Update permissions - clear all and re-add
|
|
// Update permissions - clear all and re-add
|
|
|
- yield _permission_service.clear_all_permissions_async(_user);
|
|
|
|
|
|
|
+ yield _user_service.clear_user_permissions(_user.id);
|
|
|
foreach (var perm in _editing_permissions) {
|
|
foreach (var perm in _editing_permissions) {
|
|
|
- yield _permission_service.set_permission_async(_user, perm);
|
|
|
|
|
|
|
+ yield _user_service.set_user_permission(_user.id, perm);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // Update local state
|
|
|
|
|
- set_user(_user);
|
|
|
|
|
|
|
+ // Fetch updated user projection to refresh local state
|
|
|
|
|
+ var updated_permissions = yield _user_service.get_user_permissions(_user.id);
|
|
|
|
|
+ // Update local state with new values
|
|
|
|
|
+ username = new_username;
|
|
|
|
|
+ email = new_email;
|
|
|
|
|
+ var perm_list = new List<string>();
|
|
|
|
|
+ foreach (var perm in updated_permissions) {
|
|
|
|
|
+ perm_list.append(perm);
|
|
|
|
|
+ }
|
|
|
|
|
+ var perm_array = new string[perm_list.length()];
|
|
|
|
|
+ int i = 0;
|
|
|
|
|
+ foreach (var perm in perm_list) {
|
|
|
|
|
+ perm_array[i++] = perm;
|
|
|
|
|
+ }
|
|
|
|
|
+ permissions = perm_array;
|
|
|
|
|
+ permission_count = permissions.length;
|
|
|
|
|
+
|
|
|
is_editing = false;
|
|
is_editing = false;
|
|
|
error_message = null;
|
|
error_message = null;
|
|
|
_editing_permissions = null;
|
|
_editing_permissions = null;
|
|
@@ -412,20 +441,30 @@ namespace Spry.Authentication.Components {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private async void handle_delete_user_async() throws Error {
|
|
private async void handle_delete_user_async() throws Error {
|
|
|
- // Prevent self-deletion
|
|
|
|
|
- var auth_result = yield _session_service.authenticate_request_async(_http_context, _user_service);
|
|
|
|
|
- if (auth_result.is_authenticated && auth_result.user != null) {
|
|
|
|
|
- if (auth_result.user.id == user_id) {
|
|
|
|
|
- // Can't delete self - show error
|
|
|
|
|
- error_message = "Cannot delete your own account";
|
|
|
|
|
- yield prepare();
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // Check authorization using AuthorisationContext
|
|
|
|
|
+ if (_auth_context.is_anonymous()) {
|
|
|
|
|
+ error_message = "You must be logged in to delete users";
|
|
|
|
|
+ yield prepare();
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (!_auth_context.has_permission("user-management")) {
|
|
|
|
|
+ error_message = "You do not have permission to delete users";
|
|
|
|
|
+ yield prepare();
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Prevent self-deletion - compare int64 user ids
|
|
|
|
|
+ int64? current_user_id = _auth_context.token.user_identifier.as_int64_or_null();
|
|
|
|
|
+ if (current_user_id != null && current_user_id == user_id) {
|
|
|
|
|
+ error_message = "Cannot delete your own account";
|
|
|
|
|
+ yield prepare();
|
|
|
|
|
+ return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Delete the user
|
|
// Delete the user
|
|
|
try {
|
|
try {
|
|
|
- yield _user_service.delete_user_async(user_id);
|
|
|
|
|
|
|
+ yield _user_service.delete_user(user_id);
|
|
|
|
|
|
|
|
// Set hx-refresh header to cause page reload
|
|
// Set hx-refresh header to cause page reload
|
|
|
// This ensures the user list is refreshed without needing parent references
|
|
// This ensures the user list is refreshed without needing parent references
|