feat(center): user display name + GET/PATCH /auth/me
- User.name column, defaults to email on register - GET /auth/me, PATCH /auth/me to view/change own name (api-key exempt) - login + guild members responses now include name Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -91,6 +91,7 @@ export class AuthService {
|
||||
const passwordHash = await bcrypt.hash(input.password, 10);
|
||||
const user = this.userRepo.create({
|
||||
email: input.email,
|
||||
name: input.email,
|
||||
passwordHash,
|
||||
refreshTokenHash: null,
|
||||
});
|
||||
@@ -107,6 +108,7 @@ export class AuthService {
|
||||
return {
|
||||
id: saved.id,
|
||||
email: saved.email,
|
||||
name: saved.name ?? saved.email,
|
||||
createdAt: saved.createdAt,
|
||||
};
|
||||
}
|
||||
@@ -141,12 +143,44 @@ export class AuthService {
|
||||
user: {
|
||||
id: user.id,
|
||||
email: user.email,
|
||||
name: user.name ?? user.email,
|
||||
},
|
||||
guilds,
|
||||
guildAccessTokens,
|
||||
};
|
||||
}
|
||||
|
||||
async getMe(accessToken: string) {
|
||||
const payload = this.verifyCenterAccessToken(accessToken);
|
||||
const userId = String(payload.sub ?? '');
|
||||
const user = await this.userRepo.findOne({ where: { id: userId } });
|
||||
if (!user) throw new UnauthorizedException('user not found');
|
||||
return { id: user.id, email: user.email, name: user.name ?? user.email };
|
||||
}
|
||||
|
||||
async updateMe(accessToken: string, name: string) {
|
||||
const payload = this.verifyCenterAccessToken(accessToken);
|
||||
const userId = String(payload.sub ?? '');
|
||||
const user = await this.userRepo.findOne({ where: { id: userId } });
|
||||
if (!user) throw new UnauthorizedException('user not found');
|
||||
|
||||
const trimmed = name.trim();
|
||||
if (!trimmed) throw new ConflictException('name must not be empty');
|
||||
|
||||
user.name = trimmed;
|
||||
await this.userRepo.save(user);
|
||||
|
||||
await this.audit.write({
|
||||
action: 'auth.update_profile',
|
||||
actorId: user.id,
|
||||
targetType: 'user',
|
||||
targetId: user.id,
|
||||
detail: JSON.stringify({ name: trimmed }),
|
||||
});
|
||||
|
||||
return { id: user.id, email: user.email, name: user.name };
|
||||
}
|
||||
|
||||
async listMyGuilds(accessToken: string) {
|
||||
const payload = this.verifyCenterAccessToken(accessToken);
|
||||
const userId = String(payload.sub ?? '');
|
||||
@@ -194,7 +228,15 @@ export class AuthService {
|
||||
|
||||
const userMap = new Map(users.map((u) => [u.id, u]));
|
||||
return members
|
||||
.map((m) => ({ userId: m.userId, email: userMap.get(m.userId)?.email ?? '', status: m.status }))
|
||||
.map((m) => {
|
||||
const u = userMap.get(m.userId);
|
||||
return {
|
||||
userId: m.userId,
|
||||
email: u?.email ?? '',
|
||||
name: u?.name ?? u?.email ?? '',
|
||||
status: m.status,
|
||||
};
|
||||
})
|
||||
.filter((x) => !!x.email);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user