You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

85 lines
2.5 KiB

import { dbGlobal } from "drizzle-pkg/lib/db";
import { users } from "drizzle-pkg/lib/schema/auth";
import { eq } from "drizzle-orm";
import { visibilitySchema, type Visibility } from "#server/constants/visibility";
import { z } from "zod";
const publicSlugValue = z
.string()
.regex(/^[a-z0-9]([a-z0-9-]{0,28}[a-z0-9])?$/)
.min(3)
.max(30);
const linkItemSchema = z.object({
label: z.string().min(1).max(80),
url: z.string().url().max(2000),
visibility: visibilitySchema,
});
export type SocialLinkItem = z.infer<typeof linkItemSchema>;
export async function getProfileRow(userId: number) {
const [row] = await dbGlobal.select().from(users).where(eq(users.id, userId)).limit(1);
return row ?? null;
}
export async function updateProfile(
userId: number,
patch: {
nickname?: string | null;
avatar?: string | null;
avatarVisibility?: Visibility;
bioMarkdown?: string | null;
bioVisibility?: Visibility;
socialLinks?: SocialLinkItem[];
publicSlug?: string | null;
},
) {
const updates: Record<string, unknown> = {};
if (patch.nickname !== undefined) {
updates.nickname = patch.nickname?.trim() || null;
}
if (patch.avatar !== undefined) {
updates.avatar = patch.avatar?.trim() || null;
}
if (patch.avatarVisibility !== undefined) {
updates.avatarVisibility = visibilitySchema.parse(patch.avatarVisibility);
}
if (patch.bioMarkdown !== undefined) {
updates.bioMarkdown = patch.bioMarkdown?.trim() || null;
}
if (patch.bioVisibility !== undefined) {
updates.bioVisibility = visibilitySchema.parse(patch.bioVisibility);
}
if (patch.socialLinks !== undefined) {
const parsed = z.array(linkItemSchema).max(50).parse(patch.socialLinks);
updates.socialLinksJson = JSON.stringify(parsed);
}
if (patch.publicSlug !== undefined) {
if (patch.publicSlug === null || patch.publicSlug === "") {
updates.publicSlug = null;
} else {
updates.publicSlug = publicSlugValue.parse(patch.publicSlug.trim().toLowerCase());
}
}
if (Object.keys(updates).length === 0) {
return getProfileRow(userId);
}
await dbGlobal.update(users).set(updates as never).where(eq(users.id, userId));
return getProfileRow(userId);
}
export function parseSocialLinksJson(raw: string | null | undefined): SocialLinkItem[] {
if (!raw || raw === "[]") {
return [];
}
try {
const data = JSON.parse(raw) as unknown;
return z.array(linkItemSchema).parse(data);
} catch {
return [];
}
}