feat: Add password field to AuthUser schema and update user management logic

This commit introduces a new optional `password` field to the `AuthUserUpdateRequest` schema, allowing users to update their passwords. The ManageUsers component is updated to handle password input, including validation for minimum length and an option to keep the current password. Additionally, the backend logic is modified to hash and store the new password when provided. Documentation has been updated to reflect these changes.
This commit is contained in:
tanyar09 2025-12-05 15:08:26 -05:00
parent 8f31e1942f
commit 0a109b198a
4 changed files with 32 additions and 0 deletions

View File

@ -27,6 +27,7 @@ export interface AuthUserUpdateRequest {
has_write_access: boolean
is_active?: boolean
role?: string
password?: string
}
export interface AuthUsersListResponse {

View File

@ -165,6 +165,7 @@ export default function ManageUsers() {
has_write_access: false,
is_active: true,
role: 'User',
password: '',
})
const [grantFrontendPermission, setGrantFrontendPermission] = useState(false)
@ -701,6 +702,9 @@ const getDisplayRoleLabel = (user: UserResponse): string => {
has_write_access: authEditForm.has_write_access,
is_active: authEditForm.is_active,
role: authEditForm.role,
password: authEditForm.password && authEditForm.password.trim() !== ''
? authEditForm.password
: undefined,
}
await authUsersApi.updateUser(editingAuthUser.id, updateData)
setEditingAuthUser(null)
@ -711,6 +715,7 @@ const getDisplayRoleLabel = (user: UserResponse): string => {
has_write_access: false,
is_active: true,
role: 'User',
password: '',
})
loadAuthUsers()
} catch (err: any) {
@ -788,6 +793,7 @@ const getDisplayRoleLabel = (user: UserResponse): string => {
has_write_access: user.has_write_access === true,
is_active: user.is_active !== false, // Default to true if null/undefined
role: userRole,
password: '', // Always start with empty password
})
}
@ -1792,6 +1798,24 @@ const getDisplayRoleLabel = (user: UserResponse): string => {
required
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
New Password (leave empty to keep current)
</label>
<input
type="password"
value={authEditForm.password || ''}
onChange={(e) =>
setAuthEditForm({ ...authEditForm, password: e.target.value })
}
className="w-full px-3 py-2 border border-gray-300 rounded-md"
minLength={6}
placeholder="Leave empty to keep current password"
/>
<p className="text-xs text-gray-500 mt-1">
Minimum 6 characters. Leave empty to keep the current password.
</p>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1">
Role *

View File

@ -421,6 +421,12 @@ def update_auth_user(
"has_write_access": request.has_write_access,
}
# Update password if provided
if request.password and request.password.strip():
password_hash = hash_password(request.password)
update_fields.append("password_hash = :password_hash")
update_params["password_hash"] = password_hash
if request.is_active is not None:
update_fields.append("is_active = :is_active")
update_params["is_active"] = request.is_active

View File

@ -47,6 +47,7 @@ class AuthUserUpdateRequest(BaseModel):
has_write_access: bool = Field(..., description="Write access (required)")
is_active: Optional[bool] = Field(None, description="Active status (optional)")
role: Optional[str] = Field(None, description="Role: 'Admin' or 'User' (optional)")
password: Optional[str] = Field(None, min_length=6, description="New password (optional, minimum 6 characters, leave empty to keep current)")
class AuthUsersListResponse(BaseModel):