- Manually trigger the cleanup process to delete sermons according to the retention policy.
- This will also run automatically on a daily schedule.
-
+
+
+
+
+ Automatically archive sermons that are 1 day past their most recent date.
+ This moves them to the "Previous Sermons" list on the home page.
+ This also runs automatically on a daily schedule.
+
+
+
+
+
+
+ Manually trigger the cleanup process to delete sermons according to the retention policy.
+ This will also run automatically on a daily schedule.
+
+
+
+
+
+ {{ autoArchiveError }}
+
+
+ {{ autoArchiveSuccess }}
@@ -450,6 +474,9 @@ const retentionPolicy = ref('forever')
const savingRetentionPolicy = ref(false)
const retentionPolicyError = ref('')
const retentionPolicySuccess = ref('')
+const autoArchiving = ref(false)
+const autoArchiveError = ref('')
+const autoArchiveSuccess = ref('')
const cleaningUp = ref(false)
const cleanupError = ref('')
const cleanupSuccess = ref('')
@@ -756,6 +783,27 @@ async function handleRetentionPolicyChange() {
}
}
+async function handleAutoArchive() {
+ autoArchiveError.value = ''
+ autoArchiveSuccess.value = ''
+ autoArchiving.value = true
+
+ try {
+ const result = await $fetch('/api/sermons/auto-archive', {
+ method: 'POST'
+ })
+
+ autoArchiveSuccess.value = result.message
+
+ // Refresh sermon list after auto-archive
+ await refreshSermons()
+ } catch (e: any) {
+ autoArchiveError.value = e.data?.message || 'Failed to run auto-archive'
+ } finally {
+ autoArchiving.value = false
+ }
+}
+
async function handleManualCleanup() {
if (!confirm('Are you sure you want to run the cleanup process?\n\nThis will permanently delete all sermons older than the retention policy. This action cannot be undone.')) {
return
diff --git a/server/api/sermons/auto-archive.post.ts b/server/api/sermons/auto-archive.post.ts
new file mode 100644
index 0000000..42f1980
--- /dev/null
+++ b/server/api/sermons/auto-archive.post.ts
@@ -0,0 +1,41 @@
+import { getSessionUsername } from '~/server/utils/auth'
+import { autoArchiveOldSermons, getUserByUsername } from '~/server/utils/database'
+
+export default defineEventHandler(async (event) => {
+ // Check authentication
+ const username = await getSessionUsername(event)
+
+ if (!username) {
+ throw createError({
+ statusCode: 401,
+ message: 'Unauthorized'
+ })
+ }
+
+ // Check admin role
+ const user = getUserByUsername(username)
+
+ if (!user || user.is_admin !== 1) {
+ throw createError({
+ statusCode: 403,
+ message: 'Forbidden - Admin access required'
+ })
+ }
+
+ try {
+ const result = autoArchiveOldSermons()
+
+ return {
+ success: true,
+ message: result.archivedCount > 0
+ ? `Successfully auto-archived ${result.archivedCount} sermon(s)`
+ : 'No sermons needed to be archived',
+ archivedCount: result.archivedCount
+ }
+ } catch (error: any) {
+ throw createError({
+ statusCode: 500,
+ message: error.message || 'Failed to auto-archive sermons'
+ })
+ }
+})
diff --git a/server/plugins/sermon-cleanup.ts b/server/plugins/sermon-cleanup.ts
index 72aa638..e1ea12e 100644
--- a/server/plugins/sermon-cleanup.ts
+++ b/server/plugins/sermon-cleanup.ts
@@ -1,4 +1,4 @@
-import { getSetting, deleteOldSermons, deleteExpiredSessions, getDatabase } from '../utils/database'
+import { getSetting, deleteOldSermons, deleteExpiredSessions, autoArchiveOldSermons, getDatabase } from '../utils/database'
// Map retention policy to days
const retentionDaysMap: Record = {
@@ -12,6 +12,20 @@ const retentionDaysMap: Record = {
'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
@@ -75,6 +89,7 @@ async function runPasswordResetCleanup() {
async function runAllCleanupTasks() {
console.log('[Cleanup] Starting scheduled cleanup tasks')
+ await runSermonAutoArchive()
await runSermonCleanup()
await runSessionCleanup()
await runRateLimitCleanup()
diff --git a/server/utils/database.ts b/server/utils/database.ts
index 65b0eb6..8f508b0 100644
--- a/server/utils/database.ts
+++ b/server/utils/database.ts
@@ -372,6 +372,62 @@ export function archiveSermon(id: number) {
return db.prepare('UPDATE sermons SET archived = 1 WHERE id = ?').run(id)
}
+export function unarchiveSermon(id: number) {
+ const db = getDatabase()
+ return db.prepare('UPDATE sermons SET archived = 0 WHERE id = ?').run(id)
+}
+
+// Get the most recent date from a sermon (checking both primary date and additional dates)
+function getMostRecentSermonDate(sermon: any): Date {
+ const dates: string[] = [sermon.date]
+
+ // Add additional dates if they exist
+ if (sermon.dates) {
+ try {
+ const additionalDates = JSON.parse(sermon.dates)
+ dates.push(...additionalDates)
+ } catch {
+ // If parsing fails, just use primary date
+ }
+ }
+
+ // Convert all dates to Date objects and find the most recent
+ const dateTimes = dates.map(dateStr => {
+ const date = new Date(dateStr + 'T00:00:00')
+ return date.getTime()
+ })
+
+ return new Date(Math.max(...dateTimes))
+}
+
+export function autoArchiveOldSermons(): { archivedCount: number } {
+ const db = getDatabase()
+
+ // Get all non-archived sermons
+ const sermons = db.prepare('SELECT * FROM sermons WHERE archived = 0').all() as any[]
+
+ const now = new Date()
+ now.setHours(0, 0, 0, 0) // Start of today
+
+ let archivedCount = 0
+
+ for (const sermon of sermons) {
+ const mostRecentDate = getMostRecentSermonDate(sermon)
+
+ // Calculate days difference
+ const oneDayAfterSermon = new Date(mostRecentDate)
+ oneDayAfterSermon.setDate(oneDayAfterSermon.getDate() + 1)
+
+ // If it's been at least 1 day since the most recent sermon date, archive it
+ if (now >= oneDayAfterSermon) {
+ archiveSermon(sermon.id!)
+ archivedCount++
+ }
+ }
+
+ return { archivedCount }
+}
+
export function getSermonBySlug(slug: string) {
const db = getDatabase()
return db.prepare('SELECT * FROM sermons WHERE slug = ?').get(slug) as Sermon | undefined