feat(profil): eigenes Profilbild hochladen
Jeder setzt sein Bild unter "Mein Konto", Vorgesetzte und Administratoren auch fuer die Benutzer, die sie verwalten. Wo bisher die Initialen standen, steht jetzt das Bild - Seitenleiste, Kopfzeile, Team, Dashboard, Reports, Projekte, Kunden und die Buchungsliste. Ohne Bild bleiben die Initialen. Der Browser verkleinert das Bild vor dem Hochladen auf ein Quadrat von 256 px und schneidet mittig zu (lib/imageCompress.ts): aus einem 4-MB-Foto werden wenige Kilobyte, und der Server muss kein Bild verarbeiten. Gespeichert wird es als Data-URL in pulse_users.avatar (LONGTEXT). Kein Upload-Verzeichnis, das gesichert und beim Deployment am Leben gehalten werden muesste. Geprueft wird serverseitig in lib/avatar.js: nur PNG, JPEG, GIF, WebP und AVIF als Data-URL, hoechstens 2 MB. SVG ist bewusst nicht erlaubt, es kann Skripte tragen. Externe http(s)-Adressen ebenso wenig - sonst laedt jeder Seitenaufruf ein Bild von einem fremden Server und verraet, wer wann mit Pulse arbeitet. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
2d3d843988
commit
9576d18abc
+4
-1
@@ -125,7 +125,7 @@ export const authApi = {
|
||||
login: (identifier: string, password: string) =>
|
||||
send<{ token: string; user: AppUser }>('POST', '/auth/login', { identifier, password }),
|
||||
me: () => get<{ user: AppUser }>('/auth/me'),
|
||||
updateMe: (changes: Partial<Pick<AppUser, 'theme' | 'theme_mode' | 'color'>>) =>
|
||||
updateMe: (changes: Partial<Pick<AppUser, 'theme' | 'theme_mode' | 'color' | 'avatar'>>) =>
|
||||
send<{ user: AppUser }>('PATCH', '/auth/me', changes),
|
||||
changePassword: (current_password: string, new_password: string) =>
|
||||
send<{ ok: true }>('POST', '/auth/change-password', { current_password, new_password }),
|
||||
@@ -278,6 +278,7 @@ export interface DashboardData {
|
||||
user_id: number;
|
||||
name: string;
|
||||
color: string | null;
|
||||
avatar: string | null;
|
||||
job_title: string | null;
|
||||
is_external: boolean;
|
||||
minutes: number;
|
||||
@@ -293,6 +294,7 @@ export interface DashboardData {
|
||||
user_id: number;
|
||||
user_name: string;
|
||||
user_color: string | null;
|
||||
user_avatar: string | null;
|
||||
project_display: string;
|
||||
customer_color: string | null;
|
||||
task_name: string | null;
|
||||
@@ -312,6 +314,7 @@ export interface GroupRow {
|
||||
key: string | number;
|
||||
name: string;
|
||||
color?: string | null;
|
||||
avatar?: string | null;
|
||||
minutes: number;
|
||||
billable_minutes: number;
|
||||
non_billable_minutes: number;
|
||||
|
||||
Reference in New Issue
Block a user