Files
sori.studio/server/utils/admin-site-settings-input.js

93 lines
4.0 KiB
JavaScript

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'
import { normalizeSocialLinks } from '../../lib/social-links.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),
socialLinks: z.unknown().optional().default([]),
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(''),
adHomeFeedCode: z.string().max(50000).optional().default(''),
adSidebarCode: z.string().max(50000).optional().default(''),
adPostTopCode: z.string().max(50000).optional().default(''),
adPostBottomCode: 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),
socialLinks: normalizeSocialLinks(data.socialLinks),
announcementUrl: normalizeAnnouncementUrl(data.announcementUrl),
announcementBackgroundColor: normalizeAnnouncementBackgroundColor(data.announcementBackgroundColor),
announcementAlignment: normalizeAnnouncementAlignment(data.announcementAlignment),
signupBlockedUsernames: normalizeSignupBlockedUsernames(data.signupBlockedUsernames)
}))
/**
* 관리자 사이트 설정 입력값 정리
* @param {unknown} body - 요청 본문
* @returns {import('zod').SafeParseReturnType<unknown, Object>} 검증 결과
*/
export const parseAdminSiteSettingsInput = (body) => adminSiteSettingsInputSchema.safeParse(body)