diff --git a/sources/app/api/routes/userRoutes.ts b/sources/app/api/routes/userRoutes.ts index 4c2ecfe..9da4239 100644 --- a/sources/app/api/routes/userRoutes.ts +++ b/sources/app/api/routes/userRoutes.ts @@ -2,11 +2,11 @@ import { z } from "zod"; import { Fastify } from "../types"; import { db } from "@/storage/db"; import { RelationshipStatus } from "@prisma/client"; -import { getPublicUrl } from "@/storage/files"; import { friendAdd } from "@/app/social/friendAdd"; import { Context } from "@/context"; import { friendRemove } from "@/app/social/friendRemove"; import { friendList } from "@/app/social/friendList"; +import { buildUserProfile } from "@/app/social/type"; export async function userRoutes(app: Fastify) { @@ -54,24 +54,11 @@ export async function userRoutes(app: Fastify) { // Build user profile return reply.send({ - user: { - id: user.id, - firstName: user.firstName || '', - lastName: user.lastName, - avatar: user.avatar ? { - path: user.avatar.path, - url: getPublicUrl(user.avatar.path), - width: user.avatar.width, - height: user.avatar.height, - thumbhash: user.avatar.thumbhash - } : null, - username: user.username || (user.githubUser?.profile?.login || ''), - status: status - } + user: buildUserProfile(user, status) }); }); - // Search for user + // Search for users app.get('/v1/user/search', { schema: { querystring: z.object({ @@ -79,10 +66,7 @@ export async function userRoutes(app: Fastify) { }), response: { 200: z.object({ - user: UserProfileSchema - }), - 404: z.object({ - error: z.literal('User not found') + users: z.array(UserProfileSchema) }) } }, @@ -90,8 +74,8 @@ export async function userRoutes(app: Fastify) { }, async (request, reply) => { const { query } = request.query; - // Search for user by username or GitHub login - const user = await db.account.findFirst({ + // Search for users by username, first 10 matches + const users = await db.account.findMany({ where: { username: { startsWith: query, @@ -100,37 +84,27 @@ export async function userRoutes(app: Fastify) { }, include: { githubUser: true + }, + take: 10, + orderBy: { + username: 'asc' } }); - if (!user) { - return reply.code(404).send({ error: 'User not found' }); - } - - // Resolve relationship status - const relationship = await db.userRelationship.findFirst({ - where: { - fromUserId: request.userId, - toUserId: user.id - } - }); - const status: RelationshipStatus = relationship?.status || RelationshipStatus.none; + // Resolve relationship status for each user + const userProfiles = await Promise.all(users.map(async (user) => { + const relationship = await db.userRelationship.findFirst({ + where: { + fromUserId: request.userId, + toUserId: user.id + } + }); + const status: RelationshipStatus = relationship?.status || RelationshipStatus.none; + return buildUserProfile(user, status); + })); return reply.send({ - user: { - id: user.id, - firstName: user.firstName || '', - lastName: user.lastName, - avatar: user.avatar ? { - path: user.avatar.path, - url: getPublicUrl(user.avatar.path), - width: user.avatar.width, - height: user.avatar.height, - thumbhash: user.avatar.thumbhash - } : null, - username: user.username || (user.githubUser?.profile?.login || ''), - status: status - } + users: userProfiles }); }); @@ -204,5 +178,6 @@ const UserProfileSchema = z.object({ thumbhash: z.string().optional() }).nullable(), username: z.string(), + bio: z.string().nullable(), status: RelationshipStatusSchema }); \ No newline at end of file diff --git a/sources/app/github/githubDisconnect.ts b/sources/app/github/githubDisconnect.ts index c42daa5..06f7a20 100644 --- a/sources/app/github/githubDisconnect.ts +++ b/sources/app/github/githubDisconnect.ts @@ -4,14 +4,13 @@ import { log } from "@/utils/log"; import { allocateUserSeq } from "@/storage/seq"; import { buildUpdateAccountUpdate, eventRouter } from "@/app/events/eventRouter"; import { randomKeyNaked } from "@/utils/randomKeyNaked"; -import { Prisma } from "@prisma/client"; /** * Disconnects a GitHub account from a user profile. * * Flow: * 1. Check if user has GitHub connected - early exit if not - * 2. In transaction: clear GitHub link, username, avatar from account and delete GitHub user record + * 2. In transaction: clear GitHub link and username from account (keeps avatar) and delete GitHub user record * 3. Send socket update after transaction completes * * @param ctx - Request context containing user ID @@ -36,13 +35,12 @@ export async function githubDisconnect(ctx: Context): Promise { // Step 2: Transaction for atomic database operations await db.$transaction(async (tx) => { - // Clear GitHub connection, username, and avatar from account + // Clear GitHub connection and username from account (keep avatar) await tx.account.update({ where: { id: userId }, data: { githubUserId: null, - username: null, - avatar: Prisma.JsonNull + username: null } }); @@ -56,8 +54,7 @@ export async function githubDisconnect(ctx: Context): Promise { const updSeq = await allocateUserSeq(userId); const updatePayload = buildUpdateAccountUpdate(userId, { github: null, - username: null, - avatar: null + username: null }, updSeq, randomKeyNaked(12)); eventRouter.emitUpdate({ diff --git a/sources/app/social/type.ts b/sources/app/social/type.ts index 1a14292..deb5edb 100644 --- a/sources/app/social/type.ts +++ b/sources/app/social/type.ts @@ -14,6 +14,7 @@ export type UserProfile = { thumbhash?: string; } | null; username: string; + bio: string | null; status: RelationshipStatus; } @@ -49,6 +50,7 @@ export function buildUserProfile( lastName: account.lastName, avatar, username: account.username || githubProfile?.login || '', + bio: githubProfile?.bio || null, status }; } \ No newline at end of file