a497104661
Existing PostAttachments that are actually archives (filed opaquely before the magic-byte gate) need extracting retroactively. cleanup_service. reextract_archive_attachments scans PostAttachments, magic-detects the archives, and for each reconstructs the post's sidecar from the DB + re-runs attach_in_place in a temp dir — so the members extract and re-link to the SAME post via find_or_create_post (source_id + external_post_id). Idempotent (members dedupe by sha256). Enqueues thumbnail+ML for new members. Wired as a maintenance-queue Celery task (tasks/admin) + POST /api/admin/maintenance/reextract-archives (202) + a "Re-extract archive attachments" card in Settings → Maintenance. Test: a zip stored under a mangled extension-less name extracts + links its member to the post via ImageProvenance, and a second run is a no-op (idempotent). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
47 lines
1.6 KiB
Vue
47 lines
1.6 KiB
Vue
<template>
|
|
<!-- #713: re-extract PostAttachments that are really archives but were filed
|
|
opaquely before the magic-byte gate, and attach their images to the post. -->
|
|
<v-card>
|
|
<v-card-title>Re-extract archive attachments</v-card-title>
|
|
<v-card-text>
|
|
<p class="text-body-2 mb-3">
|
|
Some posts attached an archive (zip) whose images weren't extracted
|
|
because the downloaded file had no usable extension. This scans existing
|
|
attachments, extracts any that are really archives, and attaches their
|
|
images to the post. Idempotent — safe to run more than once.
|
|
</p>
|
|
<v-btn color="primary" rounded="pill" :loading="busy" @click="run">
|
|
<v-icon start>mdi-folder-zip-outline</v-icon> Re-extract archives now
|
|
</v-btn>
|
|
<span v-if="queued" class="ml-3 text-caption text-success">Queued ✓</span>
|
|
<QueueStatusBar queue="maintenance" queue-label="Maintenance" />
|
|
</v-card-text>
|
|
</v-card>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref } from 'vue'
|
|
|
|
import { useApi } from '../../composables/useApi.js'
|
|
import { toast } from '../../utils/toast.js'
|
|
import QueueStatusBar from './QueueStatusBar.vue'
|
|
|
|
const api = useApi()
|
|
const busy = ref(false)
|
|
const queued = ref(false)
|
|
|
|
async function run () {
|
|
busy.value = true
|
|
queued.value = false
|
|
try {
|
|
await api.post('/api/admin/maintenance/reextract-archives')
|
|
queued.value = true
|
|
toast({ text: 'Archive re-extract queued', type: 'success' })
|
|
} catch (e) {
|
|
toast({ text: e?.body?.detail || e?.message || 'Failed to queue', type: 'error' })
|
|
} finally {
|
|
busy.value = false
|
|
}
|
|
}
|
|
</script>
|