terms: agreement pages + site Notion-style editor + rp cancel fix
- 5종 약관(map/resourcepack/mod/installer/installer-rp) markdown 시드 + manifest/terms/ 노출 - 사이트 /op/agreement 목록 + Notion 스타일 markdown 에디터 (슬래시 명령어, 미리보기) - 메인 installer: 음악퀴즈 선택 직후 약관 동의 페이지(맵·모드·설치기) 추가 - rp installer: 음악퀴즈 선택 직후 약관 동의 페이지(리소스팩·설치기) 추가 - rp installer 취소 버그 수정: buildResourcepackZip 단계간 + archive.abort() 폴링 - rp installer 취소 UX: 즉시 "취소 중…" 표시, 취소 시 installFailed 알림 생략 - 0.2.6 → 0.3.0 (큰 기능) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -6,13 +6,18 @@ import {
|
||||
listPackKeys,
|
||||
loadPackDefinition,
|
||||
loadPackList,
|
||||
loadTerm,
|
||||
normalizePackDefinition,
|
||||
normalizePackList,
|
||||
readAccounts,
|
||||
renamePack,
|
||||
sanitizePackKey,
|
||||
savePackList
|
||||
saveTerm,
|
||||
savePackList,
|
||||
isTermKind,
|
||||
TERM_KINDS
|
||||
} from '../../shared/store.js'
|
||||
import type { TermKind } from '../../shared/store.js'
|
||||
import { fetchReleaseVersions } from '../../shared/mojang.js'
|
||||
import { fetchPlaylistEntries, fetchVideoMeta, YtDlpUnavailableError } from '../youtube.js'
|
||||
import { requireAuth } from '../middleware/auth.js'
|
||||
@@ -295,6 +300,56 @@ opRouter.get('/op/datapack/:packName/images-zip', requireAuth, async (req, res,
|
||||
}
|
||||
})
|
||||
|
||||
// ─── /op/agreement ─────────────────────────────────────────────────────
|
||||
// 약관(Markdown) 5종 편집기. 사이트에서는 노션 스타일의 슬래시 명령으로
|
||||
// 마크다운을 작성하고, 인스톨러는 /manifest/terms/<kind>.md 로 받아 표시한다.
|
||||
const TERM_LABELS: Record<TermKind, string> = {
|
||||
'map': '맵 약관',
|
||||
'resourcepack': '리소스팩 약관',
|
||||
'mod': '모드 약관',
|
||||
'installer': '설치기 약관',
|
||||
'installer-rp': '리소스팩 설치기 약관'
|
||||
}
|
||||
|
||||
opRouter.get('/op/agreement', requireAuth, (req, res) => {
|
||||
const items = TERM_KINDS.map((kind) => ({ kind, label: TERM_LABELS[kind] }))
|
||||
res.render('op/terms', { userId: req.session.userId, items })
|
||||
})
|
||||
|
||||
opRouter.get('/op/agreement/:kind', requireAuth, async (req, res, next) => {
|
||||
try {
|
||||
const kind = pickFirstValue(req.params.kind)
|
||||
if (!isTermKind(kind)) {
|
||||
res.status(404).send(t('errors.unknown'))
|
||||
return
|
||||
}
|
||||
const content = await loadTerm(kind)
|
||||
res.render('op/termsEditor', {
|
||||
userId: req.session.userId,
|
||||
kind,
|
||||
label: TERM_LABELS[kind],
|
||||
content
|
||||
})
|
||||
} catch (error) {
|
||||
next(error)
|
||||
}
|
||||
})
|
||||
|
||||
opRouter.post('/op/agreement/:kind', requireAuth, async (req, res, next) => {
|
||||
try {
|
||||
const kind = pickFirstValue(req.params.kind)
|
||||
if (!isTermKind(kind)) {
|
||||
res.status(404).json({ ok: false, message: t('errors.unknown') })
|
||||
return
|
||||
}
|
||||
const content = typeof req.body?.content === 'string' ? req.body.content : ''
|
||||
await saveTerm(kind, content)
|
||||
res.json({ ok: true })
|
||||
} catch (error) {
|
||||
next(error)
|
||||
}
|
||||
})
|
||||
|
||||
opRouter.post('/op/dashboard/:packName', requireAuth, async (req, res, next) => {
|
||||
try {
|
||||
const packKey = sanitizePackKey(pickFirstValue(req.params.packName))
|
||||
|
||||
Reference in New Issue
Block a user