Private
Public Access
Add user profile management: display name + avatar upload (Gitea issue #12)
Users can set a display name (shown instead of username in the message list, room member list, TopBar, and admin Users tab) and upload a real avatar, replacing the generated color-initial avatars everywhere a user appears. Avatars are square-cropped and downscaled to 512px, reusing app/storage.py's upload primitives from image uploads with a new square option. Two deliberate divergences from message-image handling, documented in backend/README.md: the previous avatar file is deleted on replace/remove (safe since it's strictly one file per user), and avatar serving is not room-gated and uses a short cache (identity-addressed and mutable, unlike a message image's permanent content-addressed URL). Frontend: new ProfileModal reachable from the TopBar account menu; AuthContext gains updateUser() so a profile change reflects instantly everywhere without a refetch.
This commit is contained in:
@@ -17,7 +17,9 @@ import {
|
||||
} from '../api/admin'
|
||||
import { ApiError } from '../api/client'
|
||||
import { createApiToken, createBot, listApiTokens, listBots, revokeApiToken } from '../api/bots'
|
||||
import { getUserAvatarUrl } from '../api/users'
|
||||
import { useAuth } from '../context/AuthContext'
|
||||
import { hashIndex } from '../lib/avatar'
|
||||
import type {
|
||||
AdminRoom,
|
||||
AdminUser,
|
||||
@@ -29,6 +31,7 @@ import type {
|
||||
WebhookIncomingAdmin,
|
||||
} from '../types'
|
||||
import { TopBar } from '../components/TopBar'
|
||||
import { UserAvatar } from '../components/UserAvatar'
|
||||
import './AdminPage.css'
|
||||
|
||||
type Tab = 'users' | 'rooms' | 'bots' | 'audit' | 'settings'
|
||||
@@ -243,6 +246,7 @@ export function AdminPage() {
|
||||
<table className="admin-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>Username</th>
|
||||
<th>Email</th>
|
||||
<th>Status</th>
|
||||
@@ -253,7 +257,15 @@ export function AdminPage() {
|
||||
<tbody>
|
||||
{users.map((u) => (
|
||||
<tr key={u.id}>
|
||||
<td>{u.username}</td>
|
||||
<td>
|
||||
<UserAvatar
|
||||
username={u.username}
|
||||
colorIndex={hashIndex(u.username)}
|
||||
size={28}
|
||||
avatarUrl={u.avatar_filename ? getUserAvatarUrl(u.id, u.avatar_filename) : null}
|
||||
/>
|
||||
</td>
|
||||
<td>{u.display_name || u.username}</td>
|
||||
<td>{u.email}</td>
|
||||
<td>
|
||||
<span className={`status-badge ${u.is_active ? 'active' : 'inactive'}`}>
|
||||
|
||||
Reference in New Issue
Block a user