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:
@@ -29,6 +29,7 @@ export const users = pgTable(
|
||||
role: roleEnum("role").notNull().default("viewer"),
|
||||
avatar: text("avatar").references(() => files.id, { onDelete: "set null" }),
|
||||
banner: text("banner").references(() => files.id, { onDelete: "set null" }),
|
||||
photo: text("photo").references(() => files.id, { onDelete: "set null" }),
|
||||
is_admin: boolean("is_admin").notNull().default(false),
|
||||
email_verified: boolean("email_verified").notNull().default(false),
|
||||
email_verify_token: text("email_verify_token"),
|
||||
|
||||
@@ -134,6 +134,7 @@ builder.mutationField("adminUpdateUser", (t) =>
|
||||
artistName: t.arg.string(),
|
||||
avatarId: t.arg.string(),
|
||||
bannerId: t.arg.string(),
|
||||
photoId: t.arg.string(),
|
||||
},
|
||||
resolve: async (_root, args, ctx) => {
|
||||
requireAdmin(ctx);
|
||||
@@ -149,6 +150,7 @@ builder.mutationField("adminUpdateUser", (t) =>
|
||||
updates.artist_name = args.artistName;
|
||||
if (args.avatarId !== undefined && args.avatarId !== null) updates.avatar = args.avatarId;
|
||||
if (args.bannerId !== undefined && args.bannerId !== null) updates.banner = args.bannerId;
|
||||
if (args.photoId !== undefined && args.photoId !== null) updates.photo = args.photoId;
|
||||
|
||||
const updated = await ctx.db
|
||||
.update(users)
|
||||
|
||||
@@ -55,6 +55,7 @@ export const UserType = builder.objectRef<User>("User").implement({
|
||||
is_admin: t.exposeBoolean("is_admin"),
|
||||
avatar: t.exposeString("avatar", { nullable: true }),
|
||||
banner: t.exposeString("banner", { nullable: true }),
|
||||
photo: t.exposeString("photo", { nullable: true }),
|
||||
email_verified: t.exposeBoolean("email_verified"),
|
||||
date_created: t.expose("date_created", { type: "DateTime" }),
|
||||
}),
|
||||
@@ -75,6 +76,7 @@ export const CurrentUserType = builder.objectRef<User>("CurrentUser").implement(
|
||||
is_admin: t.exposeBoolean("is_admin"),
|
||||
avatar: t.exposeString("avatar", { nullable: true }),
|
||||
banner: t.exposeString("banner", { nullable: true }),
|
||||
photo: t.exposeString("photo", { nullable: true }),
|
||||
email_verified: t.exposeBoolean("email_verified"),
|
||||
date_created: t.expose("date_created", { type: "DateTime" }),
|
||||
}),
|
||||
@@ -133,6 +135,7 @@ export const ModelType = builder.objectRef<Model>("Model").implement({
|
||||
description: t.exposeString("description", { nullable: true }),
|
||||
avatar: t.exposeString("avatar", { nullable: true }),
|
||||
banner: t.exposeString("banner", { nullable: true }),
|
||||
photo: t.exposeString("photo", { nullable: true }),
|
||||
tags: t.exposeStringList("tags", { nullable: true }),
|
||||
date_created: t.expose("date_created", { type: "DateTime" }),
|
||||
photos: t.expose("photos", { type: [ModelPhotoType], nullable: true }),
|
||||
@@ -416,6 +419,7 @@ export const AdminUserDetailType = builder.objectRef<AdminUserDetail>("AdminUser
|
||||
is_admin: t.exposeBoolean("is_admin"),
|
||||
avatar: t.exposeString("avatar", { nullable: true }),
|
||||
banner: t.exposeString("banner", { nullable: true }),
|
||||
photo: t.exposeString("photo", { nullable: true }),
|
||||
email_verified: t.exposeBoolean("email_verified"),
|
||||
date_created: t.expose("date_created", { type: "DateTime" }),
|
||||
photos: t.expose("photos", { type: [ModelPhotoType] }),
|
||||
|
||||
1
packages/backend/src/migrations/0003_model_photo.sql
Normal file
1
packages/backend/src/migrations/0003_model_photo.sql
Normal file
@@ -0,0 +1 @@
|
||||
ALTER TABLE "users" ADD COLUMN "photo" text REFERENCES "files"("id") ON DELETE set null;
|
||||
Reference in New Issue
Block a user