feat: add dedicated model photo separate from avatar

Adds a `photo` field to the users table (and a migration) that serves
as a dedicated profile/card image for models. This is now used in model
cards and on the model single page, while `avatar` is reserved for
comments, article authors, and the user profile page.

- DB: `photo` column on `users` with FK to `files`
- GraphQL: exposed on ModelType, UserType, AdminUserDetailType; photoId arg on adminUpdateUser
- Services: photo field in MODELS_QUERY, MODEL_BY_SLUG_QUERY, ADMIN_GET/UPDATE_USER
- Frontend: model cards and single page use `photo ?? avatar` fallback
- Admin: model photo upload section in user edit page

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-08 10:54:27 +01:00
parent 2980c0b637
commit 4d81266cb1
10 changed files with 56 additions and 3 deletions

View File

@@ -962,6 +962,10 @@ export default {
artist_name: "Artist name",
avatar: "Avatar",
banner: "Banner",
model_photo: "Model photo",
model_photo_hint: "Used in model cards and on the model profile page. Avatar is used for comments and article authors.",
model_photo_uploaded: "Model photo uploaded",
model_photo_failed: "Model photo upload failed",
is_admin: "Administrator",
is_admin_hint: "Grants full admin access to the dashboard",
photos: "Photo gallery",

View File

@@ -491,6 +491,7 @@ const MODELS_QUERY = gql`
description
avatar
banner
photo
tags
date_created
photos {
@@ -540,6 +541,7 @@ const MODEL_BY_SLUG_QUERY = gql`
description
avatar
banner
photo
tags
date_created
photos {
@@ -1151,6 +1153,7 @@ const ADMIN_UPDATE_USER_MUTATION = gql`
$artistName: String
$avatarId: String
$bannerId: String
$photoId: String
) {
adminUpdateUser(
userId: $userId
@@ -1161,6 +1164,7 @@ const ADMIN_UPDATE_USER_MUTATION = gql`
artistName: $artistName
avatarId: $avatarId
bannerId: $bannerId
photoId: $photoId
) {
id
email
@@ -1171,6 +1175,7 @@ const ADMIN_UPDATE_USER_MUTATION = gql`
is_admin
avatar
banner
photo
date_created
}
}
@@ -1185,6 +1190,7 @@ export async function adminUpdateUser(input: {
artistName?: string;
avatarId?: string;
bannerId?: string;
photoId?: string;
}) {
return loggedApiCall(
"adminUpdateUser",
@@ -1228,6 +1234,7 @@ const ADMIN_GET_USER_QUERY = gql`
is_admin
avatar
banner
photo
description
tags
email_verified