feat(profile): системные бейджи рядом с ником

- участники сервера отдают список бейджей из badges_json (AGENT.md 7.2):
  список расширяемый, назначается только системой
- клиент: каталог бейджей (щит администратора инстанса, корона владельца,
  ранний сторонник, проверенный), неизвестные показываются нейтральной меткой
- бейджи видны в ленте, списке участников и друзьях вместо текстовой плашки
- тесты: Go (бейджи в списке участников) и Vitest (каталог и отрисовка)
This commit is contained in:
2026-09-21 18:10:39 +03:00
parent 0f0060e8a4
commit b43452aa04
19 changed files with 266 additions and 19 deletions
+11 -2
View File
@@ -384,13 +384,17 @@ type GuildMemberProfile struct {
JoinedAt time.Time
TimeoutUntil *time.Time
RoleIDs []uint64
// Badges — системные бейджи пользователя (AGENT.md 7.2): список
// расширяемый, назначается только системой.
Badges []string
}
// ListGuildMemberProfiles возвращает участников сервера с профилями и ролями.
func (s *Store) ListGuildMemberProfiles(ctx context.Context, guildID uint64) ([]GuildMemberProfile, error) {
rows, err := s.reader.QueryContext(ctx, `
SELECT m.user_id, u.username, u.display_name, m.nickname, u.avatar_file_id,
u.status, u.custom_status, u.is_instance_admin, m.joined_at, m.timeout_until
u.status, u.custom_status, u.is_instance_admin, m.joined_at, m.timeout_until,
u.badges_json
FROM guild_members m
JOIN users u ON u.id = m.user_id
WHERE m.guild_id = ? AND u.deleted_at IS NULL
@@ -409,11 +413,16 @@ func (s *Store) ListGuildMemberProfiles(ctx context.Context, guildID uint64) ([]
isAdmin int
joinedAt string
timeoutUntil sql.NullString
badges string
)
if err := rows.Scan(&profile.UserID, &profile.Username, &profile.DisplayName, &nickname,
&avatarID, &profile.Status, &profile.CustomStatus, &isAdmin, &joinedAt, &timeoutUntil); err != nil {
&avatarID, &profile.Status, &profile.CustomStatus, &isAdmin, &joinedAt, &timeoutUntil,
&badges); err != nil {
return nil, err
}
if err := json.Unmarshal([]byte(badges), &profile.Badges); err != nil {
profile.Badges = nil
}
if nickname.Valid {
profile.Nickname = nickname.String
}