Add intelligent auto-archiving system that automatically moves sermons to the "Previous Sermons" list when they are 1 day past their most recent date. Features: - Auto-archive logic that checks both primary and additional sermon dates - Finds the most recent date across all dates for a sermon - Archives sermon 1 day after the most recent date has passed - Manual trigger via "Run Auto-Archive Now" button on admin page - Automatic daily execution via scheduled cleanup task - Clear admin UI with explanatory text and status messages - Manual archive/unarchive functionality preserved Implementation: - Added getMostRecentSermonDate() helper to find latest date from primary and additional dates - Added autoArchiveOldSermons() function to database utils - Created /api/sermons/auto-archive endpoint for manual triggering - Integrated into daily cleanup plugin schedule - Updated admin UI with auto-archive button and status indicators - Added unarchiveSermon() function for completeness The system runs automatically every 24 hours and can be manually triggered by admins. Sermons are moved to the previous sermons dropdown on the home page exactly 1 day after their final presentation date, ensuring the main page always shows current and upcoming content while preserving access to past sermons. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
125 lines
4.0 KiB
TypeScript
125 lines
4.0 KiB
TypeScript
import { getSetting, deleteOldSermons, deleteExpiredSessions, autoArchiveOldSermons, getDatabase } from '../utils/database'
|
|
|
|
// Map retention policy to days
|
|
const retentionDaysMap: Record<string, number> = {
|
|
'forever': 0,
|
|
'1_month': 30,
|
|
'3_months': 90,
|
|
'6_months': 180,
|
|
'1_year': 365,
|
|
'3_years': 1095,
|
|
'5_years': 1825,
|
|
'10_years': 3650
|
|
}
|
|
|
|
async function runSermonAutoArchive() {
|
|
try {
|
|
const result = autoArchiveOldSermons()
|
|
|
|
if (result.archivedCount > 0) {
|
|
console.log(`[Sermon Auto-Archive] Archived ${result.archivedCount} sermon(s) that passed their most recent date`)
|
|
} else {
|
|
console.log(`[Sermon Auto-Archive] No sermons needed archiving`)
|
|
}
|
|
} catch (error) {
|
|
console.error('[Sermon Auto-Archive] Error running auto-archive:', error)
|
|
}
|
|
}
|
|
|
|
async function runSermonCleanup() {
|
|
try {
|
|
// Get the retention policy setting
|
|
const setting = getSetting('sermon_retention_policy')
|
|
const retentionPolicy = setting ? setting.value : 'forever'
|
|
|
|
const retentionDays = retentionDaysMap[retentionPolicy] || 0
|
|
|
|
if (retentionDays === 0) {
|
|
console.log('[Sermon Cleanup] Retention policy is set to forever, skipping cleanup')
|
|
return
|
|
}
|
|
|
|
// Delete old sermons
|
|
const result = deleteOldSermons(retentionDays)
|
|
|
|
if (result.changes > 0) {
|
|
console.log(`[Sermon Cleanup] Deleted ${result.changes} sermon(s) older than ${retentionDays} days`)
|
|
} else {
|
|
console.log(`[Sermon Cleanup] No sermons to delete (policy: ${retentionPolicy})`)
|
|
}
|
|
} catch (error) {
|
|
console.error('[Sermon Cleanup] Error running sermon cleanup:', error)
|
|
}
|
|
}
|
|
|
|
async function runSessionCleanup() {
|
|
try {
|
|
const result = deleteExpiredSessions()
|
|
if (result.changes > 0) {
|
|
console.log(`[Session Cleanup] Deleted ${result.changes} expired session(s)`)
|
|
}
|
|
} catch (error) {
|
|
console.error('[Session Cleanup] Error cleaning expired sessions:', error)
|
|
}
|
|
}
|
|
|
|
async function runRateLimitCleanup() {
|
|
try {
|
|
const db = getDatabase()
|
|
const result = db.prepare("DELETE FROM rate_limits WHERE reset_at <= datetime('now')").run()
|
|
if (result.changes > 0) {
|
|
console.log(`[Rate Limit Cleanup] Deleted ${result.changes} expired rate limit(s)`)
|
|
}
|
|
} catch (error) {
|
|
console.error('[Rate Limit Cleanup] Error cleaning expired rate limits:', error)
|
|
}
|
|
}
|
|
|
|
async function runPasswordResetCleanup() {
|
|
try {
|
|
const db = getDatabase()
|
|
const result = db.prepare("DELETE FROM password_reset_codes WHERE expires_at <= datetime('now')").run()
|
|
if (result.changes > 0) {
|
|
console.log(`[Password Reset Cleanup] Deleted ${result.changes} expired reset code(s)`)
|
|
}
|
|
} catch (error) {
|
|
console.error('[Password Reset Cleanup] Error cleaning expired password reset codes:', error)
|
|
}
|
|
}
|
|
|
|
async function runAllCleanupTasks() {
|
|
console.log('[Cleanup] Starting scheduled cleanup tasks')
|
|
await runSermonAutoArchive()
|
|
await runSermonCleanup()
|
|
await runSessionCleanup()
|
|
await runRateLimitCleanup()
|
|
await runPasswordResetCleanup()
|
|
console.log('[Cleanup] All cleanup tasks completed')
|
|
}
|
|
|
|
export default defineNitroPlugin((nitroApp) => {
|
|
console.log('[Cleanup Plugin] Initializing scheduled cleanup tasks')
|
|
|
|
// Run all cleanup tasks at startup (after a short delay)
|
|
setTimeout(async () => {
|
|
console.log('[Cleanup] Running initial cleanup')
|
|
await runAllCleanupTasks()
|
|
}, 10000) // 10 seconds after startup
|
|
|
|
// Schedule cleanup to run daily (every 24 hours) for sermons
|
|
const dailyInterval = 24 * 60 * 60 * 1000 // 24 hours in milliseconds
|
|
setInterval(async () => {
|
|
await runAllCleanupTasks()
|
|
}, dailyInterval)
|
|
|
|
// Run session/rate-limit cleanup more frequently (every hour)
|
|
// This prevents these tables from growing too large
|
|
const hourlyInterval = 60 * 60 * 1000 // 1 hour in milliseconds
|
|
setInterval(async () => {
|
|
console.log('[Cleanup] Running hourly cleanup')
|
|
await runSessionCleanup()
|
|
await runRateLimitCleanup()
|
|
await runPasswordResetCleanup()
|
|
}, hourlyInterval)
|
|
})
|