Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 188576f8ac |
@@ -1083,6 +1083,8 @@ async function cleanupMissingUploadReferences() {
|
|||||||
const stats = {
|
const stats = {
|
||||||
clearedAvatars: 0,
|
clearedAvatars: 0,
|
||||||
clearedGameThumbnails: 0,
|
clearedGameThumbnails: 0,
|
||||||
|
clearedTierListThumbnails: 0,
|
||||||
|
clearedTemplateRequestThumbnails: 0,
|
||||||
deletedGameItems: 0,
|
deletedGameItems: 0,
|
||||||
updatedTierLists: 0,
|
updatedTierLists: 0,
|
||||||
updatedTemplateRequests: 0,
|
updatedTemplateRequests: 0,
|
||||||
@@ -1124,67 +1126,69 @@ async function cleanupMissingUploadReferences() {
|
|||||||
missingCustomSrcs.add(row.src)
|
missingCustomSrcs.add(row.src)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (missingCustomItemIds.size || missingCustomSrcs.size) {
|
for (const row of tierListRows) {
|
||||||
for (const row of tierListRows) {
|
const groups = parseJson(row.groups_json, [])
|
||||||
const groups = parseJson(row.groups_json, [])
|
const pool = parseJson(row.pool_json, [])
|
||||||
const pool = parseJson(row.pool_json, [])
|
let changed = false
|
||||||
let changed = false
|
let nextThumbnail = row.thumbnail_src || ''
|
||||||
let nextThumbnail = row.thumbnail_src || ''
|
|
||||||
|
|
||||||
if (row.thumbnail_src && !(await fileExistsForUploadSrc(row.thumbnail_src))) {
|
if (row.thumbnail_src && !(await fileExistsForUploadSrc(row.thumbnail_src))) {
|
||||||
nextThumbnail = ''
|
nextThumbnail = ''
|
||||||
changed = true
|
changed = true
|
||||||
}
|
stats.clearedTierListThumbnails += 1
|
||||||
|
}
|
||||||
|
|
||||||
const strippedPool = stripMissingItems(pool, missingCustomItemIds, missingCustomSrcs)
|
const strippedPool = stripMissingItems(pool, missingCustomItemIds, missingCustomSrcs)
|
||||||
const strippedGroups = stripItemIdsFromGroups(groups, missingCustomItemIds)
|
const strippedGroups = stripItemIdsFromGroups(groups, missingCustomItemIds)
|
||||||
if (strippedPool.changed || strippedGroups.changed) changed = true
|
if (strippedPool.changed || strippedGroups.changed) changed = true
|
||||||
|
|
||||||
if (changed) {
|
if (changed) {
|
||||||
await query('UPDATE tierlists SET thumbnail_src = ?, groups_json = ?, pool_json = ?, updated_at = ? WHERE id = ?', [
|
await query('UPDATE tierlists SET thumbnail_src = ?, groups_json = ?, pool_json = ?, updated_at = ? WHERE id = ?', [
|
||||||
|
nextThumbnail,
|
||||||
|
serializeJson(strippedGroups.groups),
|
||||||
|
serializeJson(strippedPool.items),
|
||||||
|
now(),
|
||||||
|
row.id,
|
||||||
|
])
|
||||||
|
stats.updatedTierLists += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const row of templateRequestRows) {
|
||||||
|
const groups = parseJson(row.groups_json, [])
|
||||||
|
const items = parseJson(row.items_json, [])
|
||||||
|
const boardItems = parseJson(row.board_items_json, [])
|
||||||
|
let changed = false
|
||||||
|
let nextThumbnail = row.thumbnail_src_snapshot || ''
|
||||||
|
|
||||||
|
if (row.thumbnail_src_snapshot && !(await fileExistsForUploadSrc(row.thumbnail_src_snapshot))) {
|
||||||
|
nextThumbnail = ''
|
||||||
|
changed = true
|
||||||
|
stats.clearedTemplateRequestThumbnails += 1
|
||||||
|
}
|
||||||
|
|
||||||
|
const strippedItems = stripMissingItems(items, missingCustomItemIds, missingCustomSrcs)
|
||||||
|
const strippedBoardItems = stripMissingItems(boardItems, missingCustomItemIds, missingCustomSrcs)
|
||||||
|
const strippedGroups = stripItemIdsFromGroups(groups, missingCustomItemIds)
|
||||||
|
if (strippedItems.changed || strippedBoardItems.changed || strippedGroups.changed) changed = true
|
||||||
|
|
||||||
|
if (changed) {
|
||||||
|
await query(
|
||||||
|
'UPDATE template_requests SET thumbnail_src_snapshot = ?, groups_json = ?, items_json = ?, board_items_json = ?, updated_at = ? WHERE id = ?',
|
||||||
|
[
|
||||||
nextThumbnail,
|
nextThumbnail,
|
||||||
serializeJson(strippedGroups.groups),
|
serializeJson(strippedGroups.groups),
|
||||||
serializeJson(strippedPool.items),
|
serializeJson(strippedItems.items),
|
||||||
|
serializeJson(strippedBoardItems.items),
|
||||||
now(),
|
now(),
|
||||||
row.id,
|
row.id,
|
||||||
])
|
]
|
||||||
stats.updatedTierLists += 1
|
)
|
||||||
}
|
stats.updatedTemplateRequests += 1
|
||||||
}
|
|
||||||
|
|
||||||
for (const row of templateRequestRows) {
|
|
||||||
const groups = parseJson(row.groups_json, [])
|
|
||||||
const items = parseJson(row.items_json, [])
|
|
||||||
const boardItems = parseJson(row.board_items_json, [])
|
|
||||||
let changed = false
|
|
||||||
let nextThumbnail = row.thumbnail_src_snapshot || ''
|
|
||||||
|
|
||||||
if (row.thumbnail_src_snapshot && !(await fileExistsForUploadSrc(row.thumbnail_src_snapshot))) {
|
|
||||||
nextThumbnail = ''
|
|
||||||
changed = true
|
|
||||||
}
|
|
||||||
|
|
||||||
const strippedItems = stripMissingItems(items, missingCustomItemIds, missingCustomSrcs)
|
|
||||||
const strippedBoardItems = stripMissingItems(boardItems, missingCustomItemIds, missingCustomSrcs)
|
|
||||||
const strippedGroups = stripItemIdsFromGroups(groups, missingCustomItemIds)
|
|
||||||
if (strippedItems.changed || strippedBoardItems.changed || strippedGroups.changed) changed = true
|
|
||||||
|
|
||||||
if (changed) {
|
|
||||||
await query(
|
|
||||||
'UPDATE template_requests SET thumbnail_src_snapshot = ?, groups_json = ?, items_json = ?, board_items_json = ?, updated_at = ? WHERE id = ?',
|
|
||||||
[
|
|
||||||
nextThumbnail,
|
|
||||||
serializeJson(strippedGroups.groups),
|
|
||||||
serializeJson(strippedItems.items),
|
|
||||||
serializeJson(strippedBoardItems.items),
|
|
||||||
now(),
|
|
||||||
row.id,
|
|
||||||
]
|
|
||||||
)
|
|
||||||
stats.updatedTemplateRequests += 1
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (missingCustomItemIds.size) {
|
||||||
await deleteCustomItems(Array.from(missingCustomItemIds))
|
await deleteCustomItems(Array.from(missingCustomItemIds))
|
||||||
stats.deletedCustomItems = missingCustomItemIds.size
|
stats.deletedCustomItems = missingCustomItemIds.size
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
# 의사결정 이력
|
# 의사결정 이력
|
||||||
|
|
||||||
|
## 2026-04-02 v1.3.66
|
||||||
|
- 누락 참조 정리 도구는 커스텀 아이템 누락이 없어도 티어표/요청 썸네일 누락을 항상 따로 정리해야 하므로, 썸네일 정리를 커스텀 아이템 분기에 묶어두면 안 된다고 정리했다.
|
||||||
|
|
||||||
## 2026-04-02 v1.3.65
|
## 2026-04-02 v1.3.65
|
||||||
- 누락 파일 수치가 계속 쌓이는 상태에서는 원인 분석만으로는 운영 부담이 줄지 않으므로, 실제 파일이 없는 참조만 골라 썸네일/아바타/게임 아이템/커스텀 아이템 참조를 정리하는 관리자 액션을 제공하는 편이 맞다고 정리했다.
|
- 누락 파일 수치가 계속 쌓이는 상태에서는 원인 분석만으로는 운영 부담이 줄지 않으므로, 실제 파일이 없는 참조만 골라 썸네일/아바타/게임 아이템/커스텀 아이템 참조를 정리하는 관리자 액션을 제공하는 편이 맞다고 정리했다.
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
# 업데이트 로그
|
# 업데이트 로그
|
||||||
|
|
||||||
|
## 2026-04-02 v1.3.66
|
||||||
|
- `누락 참조 정리`는 처음엔 누락 커스텀 아이템이 있을 때만 티어표/요청 썸네일까지 함께 보던 조건 때문에, 누락 썸네일만 남아 있으면 수치가 줄지 않던 문제가 있었으므로 분기를 풀어 티어표 썸네일과 요청 썸네일도 항상 실제 파일 존재 여부를 확인해 정리하도록 수정함.
|
||||||
|
- 정리 완료 메시지에도 `티어표 썸네일`, `요청 썸네일` 항목을 추가해 어떤 종류의 누락 참조가 실제로 정리됐는지 바로 알 수 있게 함.
|
||||||
|
|
||||||
## 2026-04-02 v1.3.65
|
## 2026-04-02 v1.3.65
|
||||||
- 관리자 이미지 최적화 패널에 `누락 참조 정리` 액션을 추가해, 실제 파일이 없는 `/uploads/...` 참조만 대상으로 썸네일/아바타는 비우고 누락된 게임 아이템·커스텀 아이템은 관련 티어표/템플릿 요청 참조와 함께 정리할 수 있게 함.
|
- 관리자 이미지 최적화 패널에 `누락 참조 정리` 액션을 추가해, 실제 파일이 없는 `/uploads/...` 참조만 대상으로 썸네일/아바타는 비우고 누락된 게임 아이템·커스텀 아이템은 관련 티어표/템플릿 요청 참조와 함께 정리할 수 있게 함.
|
||||||
- 따라서 예전 수동 파일 정리나 레거시 데이터로 인해 쌓인 `누락 파일`은 단순 통계로만 남지 않고, 관리자 화면에서 실제로 줄일 수 있는 관리 도구를 갖게 됨.
|
- 따라서 예전 수동 파일 정리나 레거시 데이터로 인해 쌓인 `누락 파일`은 단순 통계로만 남지 않고, 관리자 화면에서 실제로 줄일 수 있는 관리 도구를 갖게 됨.
|
||||||
|
|||||||
@@ -677,7 +677,14 @@ async function cleanupMissingImageReferences() {
|
|||||||
const data = await api.cleanupAdminMissingImageReferences()
|
const data = await api.cleanupAdminMissingImageReferences()
|
||||||
await Promise.all([refreshImageDiagnostics(), refreshGames(), refreshCustomItems(), refreshTemplateRequests()])
|
await Promise.all([refreshImageDiagnostics(), refreshGames(), refreshCustomItems(), refreshTemplateRequests()])
|
||||||
const result = data.result || {}
|
const result = data.result || {}
|
||||||
success.value = `누락 참조를 정리했어요. 아바타 ${result.clearedAvatars || 0}건, 게임 썸네일 ${result.clearedGameThumbnails || 0}건, 게임 아이템 ${result.deletedGameItems || 0}건, 커스텀 아이템 ${result.deletedCustomItems || 0}건`
|
success.value =
|
||||||
|
`누락 참조를 정리했어요. ` +
|
||||||
|
`아바타 ${result.clearedAvatars || 0}건, ` +
|
||||||
|
`게임 썸네일 ${result.clearedGameThumbnails || 0}건, ` +
|
||||||
|
`티어표 썸네일 ${result.clearedTierListThumbnails || 0}건, ` +
|
||||||
|
`요청 썸네일 ${result.clearedTemplateRequestThumbnails || 0}건, ` +
|
||||||
|
`게임 아이템 ${result.deletedGameItems || 0}건, ` +
|
||||||
|
`커스텀 아이템 ${result.deletedCustomItems || 0}건`
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
error.value = '누락 이미지 참조 정리에 실패했어요.'
|
error.value = '누락 이미지 참조 정리에 실패했어요.'
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
Reference in New Issue
Block a user