태그 슬러그와 코드 라벨 개선
This commit is contained in:
@@ -174,16 +174,24 @@ const normalizeTagSlugs = (tags = []) => {
|
||||
const out = []
|
||||
|
||||
for (const tag of tags) {
|
||||
const trimmed = String(tag).trim().normalize('NFC')
|
||||
if (!trimmed) {
|
||||
const normalized = String(tag)
|
||||
.trim()
|
||||
.normalize('NFC')
|
||||
.toLowerCase()
|
||||
.replace(/[\\/]+/g, '-')
|
||||
.replace(/\s+/g, '-')
|
||||
.replace(/[^a-z0-9가-힣-]+/g, '')
|
||||
.replace(/-+/g, '-')
|
||||
.replace(/^-|-$/g, '')
|
||||
if (!normalized) {
|
||||
continue
|
||||
}
|
||||
const dedupeKey = trimmed.toLowerCase()
|
||||
const dedupeKey = normalized.toLowerCase()
|
||||
if (seen.has(dedupeKey)) {
|
||||
continue
|
||||
}
|
||||
seen.add(dedupeKey)
|
||||
out.push(trimmed)
|
||||
out.push(normalized)
|
||||
}
|
||||
|
||||
return out
|
||||
@@ -210,14 +218,37 @@ const getTagNameFromSlug = (slug) => {
|
||||
.join(' ')
|
||||
}
|
||||
|
||||
/**
|
||||
* 새 태그 표시 이름을 정리한다.
|
||||
* @param {string} value - 원본 표시 이름
|
||||
* @returns {string} 표시 이름
|
||||
*/
|
||||
const normalizeTagDisplayName = (value) => String(value || '')
|
||||
.normalize('NFC')
|
||||
.trim()
|
||||
.replace(/\s*\/\s*/g, '/')
|
||||
.replace(/\s+/g, ' ')
|
||||
|
||||
/**
|
||||
* 태그 슬러그에 대응하는 표시 이름을 반환한다.
|
||||
* @param {string} slug - 태그 슬러그
|
||||
* @param {Object} tagNames - 태그 표시 이름 맵
|
||||
* @returns {string} 태그명
|
||||
*/
|
||||
const resolveTagName = (slug, tagNames = {}) => {
|
||||
const inputName = normalizeTagDisplayName(tagNames[slug])
|
||||
return inputName || getTagNameFromSlug(slug)
|
||||
}
|
||||
|
||||
/**
|
||||
* 게시물 태그 연결 저장
|
||||
* @param {Function} sql - PostgreSQL 트랜잭션 클라이언트
|
||||
* @param {string} postId - 게시물 ID
|
||||
* @param {Array<string>} tags - 태그 슬러그 목록
|
||||
* @param {Object} tagNames - 태그 표시 이름 맵
|
||||
* @returns {Promise<void>} 저장 결과
|
||||
*/
|
||||
const syncPostTags = async (sql, postId, tags) => {
|
||||
const syncPostTags = async (sql, postId, tags, tagNames = {}) => {
|
||||
const tagSlugs = normalizeTagSlugs(tags)
|
||||
|
||||
await sql`
|
||||
@@ -228,7 +259,7 @@ const syncPostTags = async (sql, postId, tags) => {
|
||||
for (const [index, slug] of tagSlugs.entries()) {
|
||||
const tagRows = await sql`
|
||||
INSERT INTO tags (name, slug, tag_type, sort_order)
|
||||
VALUES (${getTagNameFromSlug(slug)}, ${slug}, 'general', 0)
|
||||
VALUES (${resolveTagName(slug, tagNames)}, ${slug}, 'general', 0)
|
||||
ON CONFLICT (slug) DO UPDATE
|
||||
SET updated_at = now()
|
||||
RETURNING id
|
||||
@@ -400,7 +431,7 @@ export const createAdminPost = async (input, authorId) => {
|
||||
RETURNING *
|
||||
`
|
||||
|
||||
await syncPostTags(transaction, insertedRows[0].id, input.tags)
|
||||
await syncPostTags(transaction, insertedRows[0].id, input.tags, input.tagNames)
|
||||
|
||||
return insertedRows
|
||||
})
|
||||
@@ -452,7 +483,7 @@ export const updateAdminPost = async (id, input, editorId) => {
|
||||
return []
|
||||
}
|
||||
|
||||
await syncPostTags(transaction, id, input.tags)
|
||||
await syncPostTags(transaction, id, input.tags, input.tagNames)
|
||||
|
||||
return updatedRows
|
||||
})
|
||||
|
||||
@@ -26,7 +26,8 @@ export const adminPostInputSchema = z.object({
|
||||
ogImage: z.string().trim().nullable().default(null),
|
||||
status: postStatusSchema.default('draft'),
|
||||
publishedAt: z.string().datetime().nullable().default(null),
|
||||
tags: z.array(z.string().trim().min(1)).default([])
|
||||
tags: z.array(z.string().trim().min(1)).default([]),
|
||||
tagNames: z.record(z.string()).default({})
|
||||
})
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user