미디어 폴더 트리 관리 추가
This commit is contained in:
@@ -43,8 +43,62 @@ const getMediaMetadataMap = async () => {
|
||||
const normalizeMediaCategory = (category) => String(category || '')
|
||||
.trim()
|
||||
.replace(/\s+/g, ' ')
|
||||
.replace(/\/+/g, '/')
|
||||
.replace(/^\/|\/$/g, '')
|
||||
|| '미분류'
|
||||
|
||||
/**
|
||||
* 미디어 폴더 목록 조회
|
||||
* @returns {Promise<Array<string>>} 미디어 폴더 경로 목록
|
||||
*/
|
||||
export const listMediaFolders = async () => {
|
||||
const sql = getPostgresClient()
|
||||
const items = await readMediaDirectory(uploadRoot)
|
||||
const metadataMap = await getMediaMetadataMap()
|
||||
const defaultCategories = items.map((item) => metadataMap[item.url]?.category || item.category)
|
||||
|
||||
if (!sql) {
|
||||
return [...new Set(['미분류', ...defaultCategories])].sort((left, right) => left.localeCompare(right))
|
||||
}
|
||||
|
||||
const rows = await sql`
|
||||
SELECT path
|
||||
FROM media_folders
|
||||
ORDER BY path ASC
|
||||
`
|
||||
|
||||
return [...new Set([
|
||||
'미분류',
|
||||
...rows.map((row) => row.path),
|
||||
...defaultCategories
|
||||
])].sort((left, right) => left.localeCompare(right))
|
||||
}
|
||||
|
||||
/**
|
||||
* 미디어 폴더 생성
|
||||
* @param {string} path - 폴더 경로
|
||||
* @returns {Promise<{ path: string }>} 생성된 폴더
|
||||
*/
|
||||
export const createMediaFolder = async (path) => {
|
||||
const sql = getPostgresClient()
|
||||
const normalizedPath = normalizeMediaCategory(path)
|
||||
|
||||
if (!sql) {
|
||||
throw new Error('DATABASE_REQUIRED')
|
||||
}
|
||||
|
||||
await sql`
|
||||
INSERT INTO media_folders (path)
|
||||
VALUES (${normalizedPath})
|
||||
ON CONFLICT (path) DO UPDATE
|
||||
SET updated_at = now()
|
||||
`
|
||||
|
||||
return {
|
||||
path: normalizedPath
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 미디어 파일명 조각을 안전하게 정리
|
||||
* @param {string} value - 원본 파일명
|
||||
@@ -259,35 +313,56 @@ const moveMediaMetadata = async (currentUrl, nextUrl) => {
|
||||
* @returns {Promise<Object>} 수정된 미디어 항목
|
||||
*/
|
||||
export const updateMediaCategory = async (url, category) => {
|
||||
const [item] = await updateMediaCategories([url], category)
|
||||
|
||||
return item
|
||||
}
|
||||
|
||||
/**
|
||||
* 여러 미디어 카테고리 저장
|
||||
* @param {Array<string>} urls - 미디어 URL 목록
|
||||
* @param {string} category - 미디어 카테고리
|
||||
* @returns {Promise<Array<Object>>} 수정된 미디어 항목 목록
|
||||
*/
|
||||
export const updateMediaCategories = async (urls, category) => {
|
||||
const sql = getPostgresClient()
|
||||
const mediaPath = resolveMediaPath(url)
|
||||
const normalizedCategory = normalizeMediaCategory(category)
|
||||
|
||||
if (!sql) {
|
||||
throw new Error('DATABASE_REQUIRED')
|
||||
}
|
||||
|
||||
await sql`
|
||||
INSERT INTO media_metadata (
|
||||
url,
|
||||
category
|
||||
)
|
||||
VALUES (
|
||||
${url},
|
||||
${normalizeMediaCategory(category)}
|
||||
)
|
||||
ON CONFLICT (url) DO UPDATE
|
||||
SET
|
||||
category = EXCLUDED.category,
|
||||
updated_at = now()
|
||||
`
|
||||
await createMediaFolder(normalizedCategory)
|
||||
|
||||
const item = await createMediaItem(mediaPath)
|
||||
const items = []
|
||||
|
||||
return {
|
||||
...item,
|
||||
category: normalizeMediaCategory(category),
|
||||
usage: []
|
||||
for (const url of [...new Set(urls.filter(Boolean))]) {
|
||||
const mediaPath = resolveMediaPath(url)
|
||||
|
||||
await sql`
|
||||
INSERT INTO media_metadata (
|
||||
url,
|
||||
category
|
||||
)
|
||||
VALUES (
|
||||
${url},
|
||||
${normalizedCategory}
|
||||
)
|
||||
ON CONFLICT (url) DO UPDATE
|
||||
SET
|
||||
category = EXCLUDED.category,
|
||||
updated_at = now()
|
||||
`
|
||||
|
||||
const item = await createMediaItem(mediaPath)
|
||||
items.push({
|
||||
...item,
|
||||
category: normalizedCategory,
|
||||
usage: []
|
||||
})
|
||||
}
|
||||
|
||||
return items
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user