릴리스: v1.4.32 내부 이름층 topic/template 정리 마감
This commit is contained in:
@@ -67,7 +67,7 @@ function mapUserRow(row) {
|
||||
}
|
||||
}
|
||||
|
||||
function mapGameRow(row) {
|
||||
function mapTopicRow(row) {
|
||||
if (!row) return null
|
||||
return {
|
||||
id: row.id,
|
||||
@@ -81,7 +81,7 @@ function mapGameRow(row) {
|
||||
}
|
||||
}
|
||||
|
||||
function mapGameItemRow(row) {
|
||||
function mapTopicItemRow(row) {
|
||||
if (!row) return null
|
||||
return {
|
||||
id: row.id,
|
||||
@@ -292,8 +292,8 @@ async function ensureSchema() {
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
|
||||
`)
|
||||
|
||||
const gameIsPublicColumns = await query("SHOW COLUMNS FROM topics LIKE 'is_public'")
|
||||
if (!gameIsPublicColumns.length) {
|
||||
const topicIsPublicColumns = await query("SHOW COLUMNS FROM topics LIKE 'is_public'")
|
||||
if (!topicIsPublicColumns.length) {
|
||||
await query('ALTER TABLE topics ADD COLUMN is_public TINYINT(1) NOT NULL DEFAULT 1 AFTER thumbnail_src')
|
||||
await query('UPDATE topics SET is_public = 1 WHERE is_public IS NULL')
|
||||
}
|
||||
@@ -316,8 +316,8 @@ async function ensureSchema() {
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
|
||||
`)
|
||||
|
||||
const gameItemDisplayOrderColumns = await query("SHOW COLUMNS FROM topic_items LIKE 'display_order'")
|
||||
if (!gameItemDisplayOrderColumns.length) {
|
||||
const topicItemDisplayOrderColumns = await query("SHOW COLUMNS FROM topic_items LIKE 'display_order'")
|
||||
if (!topicItemDisplayOrderColumns.length) {
|
||||
await query('ALTER TABLE topic_items ADD COLUMN display_order INT NULL DEFAULT NULL AFTER label')
|
||||
}
|
||||
|
||||
@@ -705,7 +705,7 @@ async function listTopics(currentUserId = '', options = {}) {
|
||||
`,
|
||||
[FREEFORM_TOPIC_ID]
|
||||
)
|
||||
const topics = rows.map(mapGameRow)
|
||||
const topics = rows.map(mapTopicRow)
|
||||
if (!currentUserId) return topics.map((topic) => ({ ...topic, isFavorited: false }))
|
||||
|
||||
const favoriteRows = await query('SELECT topic_id FROM favorite_topics WHERE user_id = ?', [currentUserId])
|
||||
@@ -718,7 +718,7 @@ async function listTopics(currentUserId = '', options = {}) {
|
||||
|
||||
async function findTopicById(id) {
|
||||
const rows = await query('SELECT id, name, thumbnail_src, is_public, display_rank, created_at FROM topics WHERE id = ? LIMIT 1', [id])
|
||||
return mapGameRow(rows[0])
|
||||
return mapTopicRow(rows[0])
|
||||
}
|
||||
|
||||
async function listTopicItems(topicId) {
|
||||
@@ -735,12 +735,12 @@ async function listTopicItems(topicId) {
|
||||
`,
|
||||
[topicId]
|
||||
)
|
||||
return rows.map(mapGameItemRow)
|
||||
return rows.map(mapTopicItemRow)
|
||||
}
|
||||
|
||||
async function findTopicItemById(itemId) {
|
||||
const rows = await query('SELECT id, topic_id, src, label, display_order, created_at FROM topic_items WHERE id = ? LIMIT 1', [itemId])
|
||||
return mapGameItemRow(rows[0])
|
||||
return mapTopicItemRow(rows[0])
|
||||
}
|
||||
|
||||
async function getTopicDetail(topicId) {
|
||||
@@ -868,7 +868,7 @@ async function listUnusedImageAssets({ limit = 100, minAgeHours = 24 } = {}) {
|
||||
|
||||
const referencedSrcs = new Set()
|
||||
|
||||
const [userRows, gameRows, gameItemRows, customItemRows, tierListRows, templateRequestRows] = await Promise.all([
|
||||
const [userRows, topicRows, topicItemRows, customItemRows, tierListRows, templateRequestRows] = await Promise.all([
|
||||
query("SELECT avatar_src FROM users WHERE avatar_src <> ''"),
|
||||
query("SELECT thumbnail_src FROM topics WHERE thumbnail_src <> ''"),
|
||||
query("SELECT src FROM topic_items WHERE src <> ''"),
|
||||
@@ -878,8 +878,8 @@ async function listUnusedImageAssets({ limit = 100, minAgeHours = 24 } = {}) {
|
||||
])
|
||||
|
||||
for (const row of userRows) if (row.avatar_src) referencedSrcs.add(row.avatar_src)
|
||||
for (const row of gameRows) if (row.thumbnail_src) referencedSrcs.add(row.thumbnail_src)
|
||||
for (const row of gameItemRows) if (row.src) referencedSrcs.add(row.src)
|
||||
for (const row of topicRows) if (row.thumbnail_src) referencedSrcs.add(row.thumbnail_src)
|
||||
for (const row of topicItemRows) if (row.src) referencedSrcs.add(row.src)
|
||||
for (const row of customItemRows) if (row.src) referencedSrcs.add(row.src)
|
||||
|
||||
for (const row of tierListRows) {
|
||||
@@ -921,7 +921,7 @@ async function listReferencedUploadUsage() {
|
||||
usageMap.get(src).add(role)
|
||||
}
|
||||
|
||||
const [userRows, gameRows, gameItemRows, customItemRows, tierListRows, templateRequestRows] = await Promise.all([
|
||||
const [userRows, topicRows, topicItemRows, customItemRows, tierListRows, templateRequestRows] = await Promise.all([
|
||||
query("SELECT avatar_src FROM users WHERE avatar_src <> ''"),
|
||||
query("SELECT thumbnail_src FROM topics WHERE thumbnail_src <> ''"),
|
||||
query("SELECT src FROM topic_items WHERE src <> ''"),
|
||||
@@ -931,8 +931,8 @@ async function listReferencedUploadUsage() {
|
||||
])
|
||||
|
||||
for (const row of userRows) addUsage(row.avatar_src, 'avatar')
|
||||
for (const row of gameRows) addUsage(row.thumbnail_src, 'topic-thumbnail')
|
||||
for (const row of gameItemRows) addUsage(row.src, 'topic-item')
|
||||
for (const row of topicRows) addUsage(row.thumbnail_src, 'topic-thumbnail')
|
||||
for (const row of topicItemRows) addUsage(row.src, 'topic-item')
|
||||
for (const row of customItemRows) addUsage(row.src, 'custom-item')
|
||||
|
||||
for (const row of tierListRows) {
|
||||
@@ -964,14 +964,14 @@ function replaceItemSrc(items, fromSrc, toSrc) {
|
||||
async function replaceUploadSourceReferences({ fromSrc, toSrc }) {
|
||||
if (!fromSrc || !toSrc || fromSrc === toSrc) return { updatedRows: 0 }
|
||||
|
||||
const [userResult, gameResult, gameItemResult, customItemResult] = await Promise.all([
|
||||
const [userResult, topicResult, topicItemResult, customItemResult] = await Promise.all([
|
||||
query('UPDATE users SET avatar_src = ? WHERE avatar_src = ?', [toSrc, fromSrc]),
|
||||
query('UPDATE topics SET thumbnail_src = ? WHERE thumbnail_src = ?', [toSrc, fromSrc]),
|
||||
query('UPDATE topic_items SET src = ? WHERE src = ?', [toSrc, fromSrc]),
|
||||
query('UPDATE custom_items SET src = ? WHERE src = ?', [toSrc, fromSrc]),
|
||||
])
|
||||
|
||||
let updatedRows = Number(userResult.affectedRows || 0) + Number(gameResult.affectedRows || 0) + Number(gameItemResult.affectedRows || 0) + Number(customItemResult.affectedRows || 0)
|
||||
let updatedRows = Number(userResult.affectedRows || 0) + Number(topicResult.affectedRows || 0) + Number(topicItemResult.affectedRows || 0) + Number(customItemResult.affectedRows || 0)
|
||||
|
||||
const tierListRows = await query('SELECT id, thumbnail_src, pool_json FROM tierlists')
|
||||
for (const row of tierListRows) {
|
||||
@@ -1120,16 +1120,16 @@ function stripMissingItems(items, missingItemIds, missingSrcs) {
|
||||
async function cleanupMissingUploadReferences() {
|
||||
const stats = {
|
||||
clearedAvatars: 0,
|
||||
clearedGameThumbnails: 0,
|
||||
clearedTopicThumbnails: 0,
|
||||
clearedTierListThumbnails: 0,
|
||||
clearedTemplateRequestThumbnails: 0,
|
||||
deletedGameItems: 0,
|
||||
deletedTopicItems: 0,
|
||||
updatedTierLists: 0,
|
||||
updatedTemplateRequests: 0,
|
||||
deletedCustomItems: 0,
|
||||
}
|
||||
|
||||
const [userRows, gameRows, gameItemRows, customItemRows, tierListRows, templateRequestRows] = await Promise.all([
|
||||
const [userRows, topicRows, topicItemRows, customItemRows, tierListRows, templateRequestRows] = await Promise.all([
|
||||
query("SELECT id, avatar_src FROM users WHERE avatar_src <> ''"),
|
||||
query("SELECT id, thumbnail_src FROM topics WHERE thumbnail_src <> ''"),
|
||||
query("SELECT id, src FROM topic_items WHERE src <> ''"),
|
||||
@@ -1144,16 +1144,16 @@ async function cleanupMissingUploadReferences() {
|
||||
stats.clearedAvatars += 1
|
||||
}
|
||||
|
||||
for (const row of gameRows) {
|
||||
for (const row of topicRows) {
|
||||
if (await fileExistsForUploadSrc(row.thumbnail_src)) continue
|
||||
await query('UPDATE topics SET thumbnail_src = ? WHERE id = ?', ['', row.id])
|
||||
stats.clearedGameThumbnails += 1
|
||||
stats.clearedTopicThumbnails += 1
|
||||
}
|
||||
|
||||
for (const row of gameItemRows) {
|
||||
for (const row of topicItemRows) {
|
||||
if (await fileExistsForUploadSrc(row.src)) continue
|
||||
await deleteTopicItem(row.id)
|
||||
stats.deletedGameItems += 1
|
||||
stats.deletedTopicItems += 1
|
||||
}
|
||||
|
||||
const missingCustomItemIds = new Set()
|
||||
@@ -1313,13 +1313,13 @@ async function createTopicItem({ id, topicId, src, label }) {
|
||||
createdAt,
|
||||
])
|
||||
const rows = await query('SELECT id, topic_id, src, label, display_order, created_at FROM topic_items WHERE id = ? LIMIT 1', [id])
|
||||
return mapGameItemRow(rows[0])
|
||||
return mapTopicItemRow(rows[0])
|
||||
}
|
||||
|
||||
async function updateTopicItemLabel(itemId, label) {
|
||||
await query('UPDATE topic_items SET label = ? WHERE id = ?', [label, itemId])
|
||||
const rows = await query('SELECT id, topic_id, src, label, display_order, created_at FROM topic_items WHERE id = ? LIMIT 1', [itemId])
|
||||
return mapGameItemRow(rows[0])
|
||||
return mapTopicItemRow(rows[0])
|
||||
}
|
||||
|
||||
async function updateTopicItemDisplayOrder(topicId, itemIds) {
|
||||
@@ -1521,7 +1521,7 @@ async function listCustomItems({ queryText = '', page = 1, limit = 50, filterMod
|
||||
const hasQuery = !!searchText
|
||||
const search = `%${searchText}%`
|
||||
|
||||
const [customRows, gameItemRows, assetRows, usageMeta] = await Promise.all([
|
||||
const [customRows, topicItemRows, assetRows, usageMeta] = await Promise.all([
|
||||
query(
|
||||
`
|
||||
SELECT
|
||||
@@ -1569,7 +1569,7 @@ async function listCustomItems({ queryText = '', page = 1, limit = 50, filterMod
|
||||
])
|
||||
|
||||
const templateLinkedBySrc = new Map()
|
||||
gameItemRows.forEach((row) => {
|
||||
topicItemRows.forEach((row) => {
|
||||
if (!row?.src) return
|
||||
if (!templateLinkedBySrc.has(row.src)) templateLinkedBySrc.set(row.src, new Map())
|
||||
templateLinkedBySrc.get(row.src).set(row.topic_id, {
|
||||
@@ -1596,7 +1596,7 @@ async function listCustomItems({ queryText = '', page = 1, limit = 50, filterMod
|
||||
}
|
||||
})
|
||||
|
||||
const templateSrcSet = new Set(gameItemRows.map((row) => row.src).filter(Boolean))
|
||||
const templateSrcSet = new Set(topicItemRows.map((row) => row.src).filter(Boolean))
|
||||
const customSrcSet = new Set(customRows.map((row) => row.src).filter(Boolean))
|
||||
const assetLibraryItems = assetRows
|
||||
.filter((row) => row?.src && !templateSrcSet.has(row.src) && !customSrcSet.has(row.src))
|
||||
@@ -1619,7 +1619,7 @@ async function listCustomItems({ queryText = '', page = 1, limit = 50, filterMod
|
||||
isAssetLibraryItem: true,
|
||||
}))
|
||||
|
||||
const templateItems = gameItemRows.map((row) => ({
|
||||
const templateItems = topicItemRows.map((row) => ({
|
||||
id: row.id,
|
||||
ownerId: '',
|
||||
src: row.src,
|
||||
@@ -1995,12 +1995,12 @@ async function listAdminTierLists({ queryText = '', topicId = '', page = 1, limi
|
||||
const normalizedPage = Math.max(Number(page) || 1, 1)
|
||||
const hasQuery = !!(queryText || '').trim()
|
||||
const resolvedTopicId = (topicId || '').trim()
|
||||
const hasGameId = !!resolvedTopicId
|
||||
const hasTopicId = !!resolvedTopicId
|
||||
const search = `%${(queryText || '').trim()}%`
|
||||
const whereParts = []
|
||||
const params = []
|
||||
|
||||
if (hasGameId) {
|
||||
if (hasTopicId) {
|
||||
whereParts.push('t.topic_id = ?')
|
||||
params.push(resolvedTopicId)
|
||||
}
|
||||
@@ -2080,12 +2080,12 @@ async function listAdminTierLists({ queryText = '', topicId = '', page = 1, limi
|
||||
async function summarizeAdminTierLists({ queryText = '', topicId = '' } = {}) {
|
||||
const hasQuery = !!(queryText || '').trim()
|
||||
const resolvedTopicId = (topicId || '').trim()
|
||||
const hasGameId = !!resolvedTopicId
|
||||
const hasTopicId = !!resolvedTopicId
|
||||
const search = `%${(queryText || '').trim()}%`
|
||||
const whereParts = []
|
||||
const params = []
|
||||
|
||||
if (hasGameId) {
|
||||
if (hasTopicId) {
|
||||
whereParts.push('t.topic_id = ?')
|
||||
params.push(resolvedTopicId)
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@ router.post('/templates', requireAdmin, async (req, res) => {
|
||||
if (exists) return res.status(409).json({ error: 'topic_id_taken' })
|
||||
const template = await createTopic({ id: parsed.data.id, name: parsed.data.name, isPublic: parsed.data.isPublic })
|
||||
if (parsed.data.thumbnailSrc) {
|
||||
const copiedThumb = await copyUploadIntoGameAsset(parsed.data.thumbnailSrc)
|
||||
const copiedThumb = await copyUploadIntoTopicAsset(parsed.data.thumbnailSrc)
|
||||
await updateTopicThumbnail(template.id, copiedThumb)
|
||||
}
|
||||
const savedTemplate = await findTopicById(template.id)
|
||||
@@ -469,7 +469,7 @@ async function promoteLibraryItemToTemplateItem({ item, templateId }) {
|
||||
})
|
||||
}
|
||||
|
||||
async function copyUploadIntoGameAsset(src) {
|
||||
async function copyUploadIntoTopicAsset(src) {
|
||||
if (typeof src !== 'string') return ''
|
||||
const raw = src.trim()
|
||||
if (!raw) return ''
|
||||
@@ -507,7 +507,7 @@ async function promoteTierListItemsToTemplate({ tierList, templateId, itemIds =
|
||||
const createdItems = []
|
||||
|
||||
for (const item of itemsToCopy) {
|
||||
const copiedSrc = await copyUploadIntoGameAsset(item.src)
|
||||
const copiedSrc = await copyUploadIntoTopicAsset(item.src)
|
||||
createdItems.push(
|
||||
await createTopicItem({
|
||||
id: nanoid(),
|
||||
@@ -531,7 +531,7 @@ async function promoteSnapshotItemsToTemplate({ items, templateId }) {
|
||||
const createdItems = []
|
||||
|
||||
for (const item of items || []) {
|
||||
const copiedSrc = await copyUploadIntoGameAsset(item.src)
|
||||
const copiedSrc = await copyUploadIntoTopicAsset(item.src)
|
||||
if (!copiedSrc || existingSrcs.has(copiedSrc)) continue
|
||||
createdItems.push(
|
||||
await createTopicItem({
|
||||
@@ -576,13 +576,13 @@ function pickTemplateRequestItems(templateRequest, itemIds = [], itemLabels = {}
|
||||
async function createTemplateFromTierList({ tierList, templateId, templateName }) {
|
||||
await createTopic({ id: templateId, name: templateName, isPublic: false })
|
||||
if (tierList.thumbnailSrc) {
|
||||
const copiedThumb = await copyUploadIntoGameAsset(tierList.thumbnailSrc)
|
||||
const copiedThumb = await copyUploadIntoTopicAsset(tierList.thumbnailSrc)
|
||||
await updateTopicThumbnail(templateId, copiedThumb)
|
||||
}
|
||||
|
||||
const createdItems = []
|
||||
for (const item of uniqueTierListPoolItems(tierList)) {
|
||||
const copiedSrc = await copyUploadIntoGameAsset(item.src)
|
||||
const copiedSrc = await copyUploadIntoTopicAsset(item.src)
|
||||
createdItems.push(
|
||||
await createTopicItem({
|
||||
id: nanoid(),
|
||||
@@ -600,7 +600,7 @@ async function createTemplateFromRequest({ templateRequest, templateId, template
|
||||
await createTopic({ id: templateId, name: templateName, isPublic: false })
|
||||
|
||||
if (templateRequest.thumbnailSrc) {
|
||||
const copiedThumb = await copyUploadIntoGameAsset(templateRequest.thumbnailSrc)
|
||||
const copiedThumb = await copyUploadIntoTopicAsset(templateRequest.thumbnailSrc)
|
||||
await updateTopicThumbnail(templateId, copiedThumb)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user