import { z } from 'zod' import { DEFAULT_ANNOUNCEMENT_ALIGNMENT, DEFAULT_ANNOUNCEMENT_BACKGROUND_COLOR, isValidAnnouncementBackgroundColor, normalizeAnnouncementAlignment, normalizeAnnouncementBackgroundColor, normalizeAnnouncementUrl } from '../../lib/announcement-bar.js' import { DEFAULT_BRAND_COLOR, isValidBrandColor, normalizeBrandColor } from '../../lib/brand-color.js' import { DEFAULT_SIGNUP_BLOCKED_USERNAMES, MAX_SIGNUP_BLOCKED_USERNAME_COUNT, MAX_SIGNUP_BLOCKED_USERNAME_LENGTH, normalizeSignupBlockedUsernames } from '../../lib/signup-blocked-usernames.js' export const adminSiteSettingsInputSchema = z.object({ title: z.string().trim().min(1), description: z.string().trim().min(1), siteUrl: z.string().trim().url(), logoText: z.string().trim().max(8).optional().default('井'), logoUrl: z.string().trim().max(500).optional().default(''), faviconUrl: z.string().trim().max(500).optional().default(''), copyrightText: z.string().trim().min(1), showPostUpdatedAt: z.boolean().optional().default(false), homeCoverImageUrl: z.string().trim().max(500).optional().default(''), homeCoverDarkImageUrl: z.string().trim().max(500).optional().default(''), homeCoverTitle: z.string().trim().max(120).optional().default(''), homeCoverText: z.string().trim().max(280).optional().default(''), brandColor: z.string().trim().optional().default(DEFAULT_BRAND_COLOR), announcementEnabled: z.boolean().optional().default(false), announcementText: z.string().trim().max(200).optional().default(''), announcementUrl: z.string().trim().max(500).optional().default(''), announcementBackgroundColor: z.string().trim().optional().default(DEFAULT_ANNOUNCEMENT_BACKGROUND_COLOR), announcementAlignment: z.string().trim().optional().default(DEFAULT_ANNOUNCEMENT_ALIGNMENT), signupBlockedUsernames: z.array( z.string().trim().min(1).max(MAX_SIGNUP_BLOCKED_USERNAME_LENGTH) ).max(MAX_SIGNUP_BLOCKED_USERNAME_COUNT).optional().default([...DEFAULT_SIGNUP_BLOCKED_USERNAMES]), adsTxt: z.string().max(20000).optional().default(''), customHeadCode: z.string().max(50000).optional().default(''), customFooterCode: z.string().max(50000).optional().default('') }).superRefine((data, ctx) => { if (!isValidAnnouncementBackgroundColor(data.announcementBackgroundColor)) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: '어나운스 바 배경색이 올바르지 않습니다.', path: ['announcementBackgroundColor'] }) } if (!isValidBrandColor(data.brandColor)) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: '브랜드 컬러가 올바르지 않습니다.', path: ['brandColor'] }) } if (data.announcementEnabled && !data.announcementText.trim()) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: '어나운스 바를 사용할 때는 공지 문구를 입력해야 합니다.', path: ['announcementText'] }) } }).transform((data) => ({ ...data, brandColor: normalizeBrandColor(data.brandColor), announcementUrl: normalizeAnnouncementUrl(data.announcementUrl), announcementBackgroundColor: normalizeAnnouncementBackgroundColor(data.announcementBackgroundColor), announcementAlignment: normalizeAnnouncementAlignment(data.announcementAlignment), signupBlockedUsernames: normalizeSignupBlockedUsernames(data.signupBlockedUsernames) })) /** * 관리자 사이트 설정 입력값 정리 * @param {unknown} body - 요청 본문 * @returns {import('zod').SafeParseReturnType} 검증 결과 */ export const parseAdminSiteSettingsInput = (body) => adminSiteSettingsInputSchema.safeParse(body)