Add admin password reset option for users (#5180)

## Summary
- add backend support for admins to reset user passwords and optionally
email notifications when SMTP is enabled
- surface mail capability in admin settings data for the UI
- add a shared change-password modal hooked into People and Team user
actions with random password generation and email options

## Testing
- not run (not requested)


------
[Codex
Task](https://chatgpt.com/codex/tasks/task_b_6934b978fe3c83289b5b95dec79b3d38)

---------

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
This commit is contained in:
Anthony Stirling
2025-12-10 10:10:40 +00:00
committed by GitHub
co-authored by Copilot Autofix powered by AI
parent c980ee10c0
commit 9c03914edd
10 changed files with 577 additions and 11 deletions
@@ -37,6 +37,7 @@ export interface AdminSettingsData {
grandfatheredUserCount: number;
licenseMaxUsers: number;
premiumEnabled: boolean;
mailEnabled: boolean;
}
export interface CreateUserRequest {
@@ -97,6 +98,15 @@ export interface InviteToken {
expiresAt: string;
}
export interface ChangeUserPasswordRequest {
username: string;
newPassword?: string;
generateRandom?: boolean;
sendEmail?: boolean;
includePassword?: boolean;
forcePasswordChange?: boolean;
}
/**
* User Management Service
* Provides functions to interact with user management backend APIs
@@ -254,4 +264,31 @@ export const userManagementService = {
const response = await apiClient.post<{ deletedCount: number }>('/api/v1/invite/cleanup');
return response.data;
},
/**
* Change another user's password (admin only)
*/
async changeUserPassword(data: ChangeUserPasswordRequest): Promise<void> {
const formData = new FormData();
formData.append('username', data.username);
if (data.newPassword) {
formData.append('newPassword', data.newPassword);
}
if (data.generateRandom !== undefined) {
formData.append('generateRandom', data.generateRandom.toString());
}
if (data.sendEmail !== undefined) {
formData.append('sendEmail', data.sendEmail.toString());
}
if (data.includePassword !== undefined) {
formData.append('includePassword', data.includePassword.toString());
}
if (data.forcePasswordChange !== undefined) {
formData.append('forcePasswordChange', data.forcePasswordChange.toString());
}
await apiClient.post('/api/v1/user/admin/changePasswordForUser', formData, {
suppressErrorToast: true, // Component will handle error display
} as any);
},
};