Add sermon retention policy feature
Implemented a configurable retention policy system for sermons with automatic cleanup: - Added settings table to store retention policy configuration - Created API endpoints for getting/setting retention policy - Added Database Settings section to admin page with retention options (forever, 1-10 years) - Implemented manual cleanup endpoint for on-demand deletion - Added automated daily cleanup task via Nitro plugin - Sermons are deleted based on their date field according to the retention policy 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
128
pages/admin.vue
128
pages/admin.vue
@@ -346,8 +346,68 @@
|
||||
</NuxtLink>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<!-- Database Settings Section -->
|
||||
<div class="bg-white shadow-lg rounded-lg p-8 mt-8">
|
||||
<h2 class="text-2xl font-bold text-gray-900 mb-6">Database Settings</h2>
|
||||
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<label for="retention-policy" class="block text-sm font-medium text-gray-700 mb-2">
|
||||
Sermon Retention Policy
|
||||
</label>
|
||||
<p class="text-sm text-gray-600 mb-3">
|
||||
Choose how long to keep sermons in the database. Older sermons will be automatically deleted based on this policy.
|
||||
</p>
|
||||
<select
|
||||
id="retention-policy"
|
||||
v-model="retentionPolicy"
|
||||
@change="handleRetentionPolicyChange"
|
||||
:disabled="savingRetentionPolicy"
|
||||
class="block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-blue-500 focus:border-blue-500 disabled:opacity-50"
|
||||
>
|
||||
<option value="forever">Keep Forever</option>
|
||||
<option value="1_month">1 Month</option>
|
||||
<option value="3_months">3 Months</option>
|
||||
<option value="6_months">6 Months</option>
|
||||
<option value="1_year">1 Year</option>
|
||||
<option value="3_years">3 Years</option>
|
||||
<option value="5_years">5 Years</option>
|
||||
<option value="10_years">10 Years</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div v-if="retentionPolicyError" class="text-red-600 text-sm">
|
||||
{{ retentionPolicyError }}
|
||||
</div>
|
||||
<div v-if="retentionPolicySuccess" class="text-green-600 text-sm">
|
||||
{{ retentionPolicySuccess }}
|
||||
</div>
|
||||
|
||||
<div class="border-t pt-4 mt-4">
|
||||
<button
|
||||
@click="handleManualCleanup"
|
||||
:disabled="cleaningUp"
|
||||
class="px-6 py-2 bg-orange-600 text-white rounded-md hover:bg-orange-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-orange-500 disabled:opacity-50 disabled:cursor-not-allowed font-medium"
|
||||
>
|
||||
{{ cleaningUp ? 'Running Cleanup...' : 'Run Cleanup Now' }}
|
||||
</button>
|
||||
<p class="text-xs text-gray-500 mt-2">
|
||||
Manually trigger the cleanup process to delete sermons according to the retention policy.
|
||||
This will also run automatically on a daily schedule.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div v-if="cleanupError" class="text-red-600 text-sm">
|
||||
{{ cleanupError }}
|
||||
</div>
|
||||
<div v-if="cleanupSuccess" class="text-green-600 text-sm">
|
||||
{{ cleanupSuccess }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
|
||||
<Footer />
|
||||
</div>
|
||||
</template>
|
||||
@@ -384,6 +444,21 @@ const error = ref('')
|
||||
const success = ref('')
|
||||
const loading = ref(false)
|
||||
|
||||
// Database settings state
|
||||
const retentionPolicy = ref('forever')
|
||||
const savingRetentionPolicy = ref(false)
|
||||
const retentionPolicyError = ref('')
|
||||
const retentionPolicySuccess = ref('')
|
||||
const cleaningUp = ref(false)
|
||||
const cleanupError = ref('')
|
||||
const cleanupSuccess = ref('')
|
||||
|
||||
// Fetch current retention policy
|
||||
const { data: retentionPolicyData } = await useFetch('/api/settings/retention-policy')
|
||||
if (retentionPolicyData.value) {
|
||||
retentionPolicy.value = retentionPolicyData.value.retentionPolicy
|
||||
}
|
||||
|
||||
// Check if selected sermon is archived
|
||||
const isSelectedSermonArchived = computed(() => {
|
||||
if (!selectedSermonId.value || !allSermons.value) return false
|
||||
@@ -648,4 +723,55 @@ async function handleLogout() {
|
||||
await $fetch('/api/auth/logout', { method: 'POST' })
|
||||
await navigateTo('/login')
|
||||
}
|
||||
|
||||
async function handleRetentionPolicyChange() {
|
||||
retentionPolicyError.value = ''
|
||||
retentionPolicySuccess.value = ''
|
||||
savingRetentionPolicy.value = true
|
||||
|
||||
try {
|
||||
await $fetch('/api/settings/retention-policy', {
|
||||
method: 'POST',
|
||||
body: {
|
||||
retentionPolicy: retentionPolicy.value
|
||||
}
|
||||
})
|
||||
|
||||
retentionPolicySuccess.value = 'Retention policy saved successfully!'
|
||||
|
||||
// Clear success message after 3 seconds
|
||||
setTimeout(() => {
|
||||
retentionPolicySuccess.value = ''
|
||||
}, 3000)
|
||||
} catch (e: any) {
|
||||
retentionPolicyError.value = e.data?.message || 'Failed to save retention policy'
|
||||
} finally {
|
||||
savingRetentionPolicy.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
|
||||
}
|
||||
|
||||
cleanupError.value = ''
|
||||
cleanupSuccess.value = ''
|
||||
cleaningUp.value = true
|
||||
|
||||
try {
|
||||
const result = await $fetch('/api/sermons/cleanup', {
|
||||
method: 'POST'
|
||||
})
|
||||
|
||||
cleanupSuccess.value = result.message + ` (${result.deletedCount} sermon${result.deletedCount !== 1 ? 's' : ''} deleted)`
|
||||
|
||||
// Refresh sermon list after cleanup
|
||||
await refreshSermons()
|
||||
} catch (e: any) {
|
||||
cleanupError.value = e.data?.message || 'Failed to run cleanup'
|
||||
} finally {
|
||||
cleaningUp.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user