Remove podcast checklist backend, calendar events and reminder emails; v2.14.3
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
99b19faede
commit
13d0eb6651
12 files changed
+3
-534
No files matched your search
-133
@@ -26,7 +26,6 @@ import {
|
||||
QR_CODES_FILE,
|
||||
REPLY_TEMPLATES_FILE,
|
||||
REPLY_HISTORY_FILE,
|
||||
PODCAST_CHECKLIST_FILE,
|
||||
BACKUP_DIR,
|
||||
UPLOADS_DIR,
|
||||
UPLOADS_META_FILE,
|
||||
@@ -34,7 +33,6 @@ import {
|
||||
EPISODE_PLAYS_FILE,
|
||||
ANALYTICS_EVENTS_FILE,
|
||||
EMAIL_SETTINGS_FILE,
|
||||
CALENDAR_EVENTS_FILE,
|
||||
AUDIT_LOG_FILE,
|
||||
WEBHOOKS_FILE,
|
||||
STUDY_SESSIONS_FILE,
|
||||
@@ -51,8 +49,6 @@ import {
|
||||
MAX_STUDY_NOTES_PER_USER,
|
||||
MAX_STUDY_NOTE_LENGTH,
|
||||
MAX_STUDY_COMMENTS,
|
||||
DEFAULT_PODCAST_CHECKLIST_TASKS,
|
||||
buildDefaultPodcastChecklist,
|
||||
} from './config.js'
|
||||
import { state } from './state.js'
|
||||
|
||||
@@ -424,36 +420,6 @@ export function loadEmailSettingsFromDisk() {
|
||||
})
|
||||
}
|
||||
|
||||
// ── Calendar events ────────────────────────────────────────────────────────
|
||||
|
||||
export function queueCalendarEventsWrite() {
|
||||
state.calendarEventsWritePromise = state.calendarEventsWritePromise
|
||||
.then(async () => {
|
||||
await mkdir(DATA_DIR, { recursive: true })
|
||||
await writeFile(
|
||||
CALENDAR_EVENTS_FILE,
|
||||
JSON.stringify({ events: state.calendarEvents, updatedAt: new Date().toISOString() }, null, 2),
|
||||
'utf8',
|
||||
)
|
||||
})
|
||||
.catch(err => {
|
||||
console.error('[calendar-events] failed to write:', err)
|
||||
})
|
||||
}
|
||||
|
||||
export function loadCalendarEventsFromDisk() {
|
||||
return readFile(CALENDAR_EVENTS_FILE, 'utf8')
|
||||
.then(raw => {
|
||||
const parsed = JSON.parse(raw)
|
||||
if (Array.isArray(parsed?.events)) {
|
||||
state.calendarEvents = parsed.events
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
// No file yet — start with empty array
|
||||
})
|
||||
}
|
||||
|
||||
// ── Audit log ─────────────────────────────────────────────────────────────
|
||||
|
||||
export function appendAuditEntry(action, details) {
|
||||
@@ -552,32 +518,6 @@ export async function fireWebhooks(eventType, payload) {
|
||||
}
|
||||
}
|
||||
|
||||
// ── Podcast checklist ──────────────────────────────────────────────────────
|
||||
|
||||
export function queuePodcastChecklistWrite() {
|
||||
const updatedAt = new Date().toISOString()
|
||||
state.podcastChecklistWritePromise = state.podcastChecklistWritePromise.then(async () => {
|
||||
await mkdir(DATA_DIR, { recursive: true })
|
||||
await writeFile(
|
||||
PODCAST_CHECKLIST_FILE,
|
||||
JSON.stringify({ checklist: state.podcastChecklist, updatedAt }, null, 2),
|
||||
'utf8',
|
||||
)
|
||||
})
|
||||
return state.podcastChecklistWritePromise
|
||||
}
|
||||
|
||||
export function loadPodcastChecklistFromDisk() {
|
||||
return readFile(PODCAST_CHECKLIST_FILE, 'utf8')
|
||||
.then(raw => {
|
||||
const parsed = JSON.parse(raw)
|
||||
state.podcastChecklist = sanitizePodcastChecklist(parsed?.checklist)
|
||||
})
|
||||
.catch(() => {
|
||||
state.podcastChecklist = buildDefaultPodcastChecklist()
|
||||
})
|
||||
}
|
||||
|
||||
// ── Study users ────────────────────────────────────────────────────────────
|
||||
|
||||
export function queueStudyUsersWrite() {
|
||||
@@ -1074,7 +1014,6 @@ export async function createBackupSnapshot(reason = 'scheduled') {
|
||||
reason,
|
||||
adminContent: null,
|
||||
draftContent: null,
|
||||
podcastChecklist: state.podcastChecklist,
|
||||
publishState: state.publishState,
|
||||
hitStats: state.hitStats,
|
||||
visitorStats: state.visitorStats,
|
||||
@@ -1200,7 +1139,6 @@ export async function restoreFromBackup(filename) {
|
||||
state.contactSubmissions = sanitizeLoadedContactSubmissions(parsed?.contactSubmissions)
|
||||
state.replyTemplates = sanitizeReplyTemplates(parsed?.replyTemplates)
|
||||
state.replyHistory = sanitizeReplyHistory(parsed?.replyHistory)
|
||||
state.podcastChecklist = sanitizePodcastChecklist(parsed?.podcastChecklist)
|
||||
|
||||
queueHitStatsWrite()
|
||||
queueVisitorStatsWrite()
|
||||
@@ -1209,7 +1147,6 @@ export async function restoreFromBackup(filename) {
|
||||
queueContactSubmissionsWrite()
|
||||
queueReplyTemplatesWrite()
|
||||
queueReplyHistoryWrite()
|
||||
queuePodcastChecklistWrite()
|
||||
|
||||
await Promise.all([
|
||||
state.hitStatsWritePromise,
|
||||
@@ -1219,7 +1156,6 @@ export async function restoreFromBackup(filename) {
|
||||
state.contactSubmissionsWritePromise,
|
||||
state.replyTemplatesWritePromise,
|
||||
state.replyHistoryWritePromise,
|
||||
state.podcastChecklistWritePromise,
|
||||
])
|
||||
await refreshContentCaches()
|
||||
await createBackupSnapshot('post-restore')
|
||||
@@ -1393,75 +1329,6 @@ export function sanitizeReplyHistory(value) {
|
||||
}))
|
||||
}
|
||||
|
||||
function sanitizeChecklistTask(task) {
|
||||
const label = typeof task?.label === 'string' ? task.label.trim().slice(0, 120) : ''
|
||||
if (!label) return null
|
||||
const phase = task?.phase === 'post' ? 'post' : 'pre'
|
||||
const id = typeof task?.id === 'string' && task.id.trim() ? task.id.trim() : randomUUID()
|
||||
return { id, label, phase }
|
||||
}
|
||||
|
||||
export function sanitizePodcastChecklist(value) {
|
||||
const fallback = buildDefaultPodcastChecklist()
|
||||
const source = value && typeof value === 'object' && !Array.isArray(value) ? value : {}
|
||||
|
||||
const taskInput = Array.isArray(source.tasks) ? source.tasks : fallback.tasks
|
||||
const seenTaskIds = new Set()
|
||||
const tasks = []
|
||||
|
||||
for (const item of taskInput) {
|
||||
const safeTask = sanitizeChecklistTask(item)
|
||||
if (!safeTask) continue
|
||||
if (seenTaskIds.has(safeTask.id)) continue
|
||||
seenTaskIds.add(safeTask.id)
|
||||
tasks.push(safeTask)
|
||||
}
|
||||
|
||||
if (tasks.length === 0) {
|
||||
for (const task of fallback.tasks) {
|
||||
tasks.push({ ...task })
|
||||
seenTaskIds.add(task.id)
|
||||
}
|
||||
}
|
||||
|
||||
const taskIds = tasks.map(task => task.id)
|
||||
const episodesInput = Array.isArray(source.episodes) ? source.episodes : fallback.episodes
|
||||
const episodes = []
|
||||
|
||||
for (const item of episodesInput) {
|
||||
if (!item || typeof item !== 'object' || Array.isArray(item)) continue
|
||||
const id = typeof item.id === 'string' && item.id.trim() ? item.id.trim() : randomUUID()
|
||||
const series = typeof item.series === 'string' ? item.series.trim().slice(0, 80) : ''
|
||||
const title = typeof item.title === 'string' ? item.title.trim().slice(0, 180) : ''
|
||||
const rawEpisodeNumber = Number(item.episodeNumber)
|
||||
const episodeNumber = Number.isFinite(rawEpisodeNumber) && rawEpisodeNumber >= 0
|
||||
? Math.round(rawEpisodeNumber)
|
||||
: null
|
||||
const datePublished = typeof item.datePublished === 'string' && /^\d{4}-\d{2}-\d{2}$/.test(item.datePublished.trim())
|
||||
? item.datePublished.trim()
|
||||
: ''
|
||||
const sourceTasks = item.tasks && typeof item.tasks === 'object' && !Array.isArray(item.tasks)
|
||||
? item.tasks
|
||||
: {}
|
||||
const taskState = {}
|
||||
for (const taskId of taskIds) {
|
||||
taskState[taskId] = sourceTasks[taskId] === true
|
||||
}
|
||||
const reminderDays = Number.isFinite(Number(item.reminderDays)) && Number(item.reminderDays) >= 0 ? Number(item.reminderDays) : 0
|
||||
const reminderSentAt = typeof item.reminderSentAt === 'string' && item.reminderSentAt ? item.reminderSentAt : undefined
|
||||
const startTime = typeof item.startTime === 'string' && /^\d{2}:\d{2}$/.test(item.startTime) ? item.startTime : undefined
|
||||
const PROD_STATUSES = ['idea', 'recorded', 'edited', 'scheduled', 'published']
|
||||
const productionStatus = PROD_STATUSES.includes(item.productionStatus) ? item.productionStatus : undefined
|
||||
episodes.push({ id, series, episodeNumber, title, datePublished, expanded: item.expanded === true, tasks: taskState, reminderDays, reminderSentAt, ...(startTime ? { startTime } : {}), ...(productionStatus ? { productionStatus } : {}) })
|
||||
}
|
||||
|
||||
if (episodes.length === 0) {
|
||||
return fallback
|
||||
}
|
||||
|
||||
return { tasks, episodes }
|
||||
}
|
||||
|
||||
function normalizeStudyUsername(value) {
|
||||
if (typeof value !== 'string') return ''
|
||||
return value.trim().toLowerCase()
|
||||
|
||||
Reference in new issue
Block a user