feat(quick-260630-gbh-01): avatar storage endpoints + enriched /auth/me
- Add avatarPath String? column to User model (migration: add_user_avatar)
- POST /users/me/avatar: 2MB limit, image/png/jpeg/webp allowlist, writes to user-files/avatars/{userId}.{ext}
- GET /users/me/avatar: streams avatar with Cache-Control: no-store
- AuthService.getMe(): returns isLocalUser + hasAvatar without leaking passwordHash/ldapDn
- AuthController GET /auth/me: now returns enriched profile via getMe()
This commit is contained in:
@@ -182,6 +182,40 @@ export class AuthService {
|
||||
this.logger.log(`Password reset completed for user ${resetToken.userId}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return enriched profile for the currently authenticated user.
|
||||
* T-gbh-03: Only public fields + isLocalUser/hasAvatar returned — never
|
||||
* passwordHash or ldapDn.
|
||||
*/
|
||||
async getMe(userId: string) {
|
||||
const user = await this.prisma.user.findUnique({
|
||||
where: { id: userId },
|
||||
select: {
|
||||
id: true,
|
||||
username: true,
|
||||
displayName: true,
|
||||
role: true,
|
||||
tenantId: true,
|
||||
mustChangePassword: true,
|
||||
passwordHash: true,
|
||||
ldapDn: true,
|
||||
avatarPath: true,
|
||||
},
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { passwordHash, ldapDn, avatarPath, ...publicFields } = user;
|
||||
|
||||
return {
|
||||
...publicFields,
|
||||
isLocalUser: !!passwordHash && !ldapDn,
|
||||
hasAvatar: !!avatarPath,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Change password for the currently logged-in user.
|
||||
* Verifies current password before allowing change.
|
||||
|
||||
Reference in New Issue
Block a user