add more management capabilities

This commit is contained in:
Garret Patti
2026-04-11 18:33:03 -04:00
parent 1ca90184f5
commit 768c49ef00
16 changed files with 1420 additions and 55 deletions

View File

@@ -1,7 +1,10 @@
import fs from 'fs'
import { NextRequest, NextResponse } from 'next/server'
import { getLibrary, resolveLibraryRoot } from '@/lib/libraries'
import { getLibrary, resolveLibraryRoot, resolveAndJail } from '@/lib/libraries'
import { scanDirectory, scanDirectoryRecursive } from '@/lib/files'
import { requireLibraryAccess } from '@/lib/auth'
import { requireLibraryAccess, requireAdmin } from '@/lib/auth'
import { removeAllAssignmentsForItem } from '@/lib/tags'
import { getDb } from '@/lib/db'
export async function GET(request: NextRequest) {
const { searchParams } = request.nextUrl
@@ -30,3 +33,58 @@ export async function GET(request: NextRequest) {
: scanDirectory(root, libraryId, subpath)
return NextResponse.json(listing)
}
export async function DELETE(request: NextRequest) {
const auth = await requireAdmin(request)
if (auth instanceof NextResponse) return auth
const { searchParams } = request.nextUrl
const libraryId = searchParams.get('libraryId')
const itemPath = searchParams.get('path')
if (!libraryId || !itemPath) {
return NextResponse.json({ error: 'Missing libraryId or path' }, { status: 400 })
}
const library = getLibrary(libraryId)
if (!library) {
return NextResponse.json({ error: 'Library not found' }, { status: 404 })
}
if (library.type !== 'mixed') {
return NextResponse.json({ error: 'Library is not a mixed library' }, { status: 400 })
}
const root = resolveLibraryRoot(library)
let absPath: string
try {
absPath = resolveAndJail(root, itemPath)
} catch {
return NextResponse.json({ error: 'Invalid path' }, { status: 400 })
}
try {
const stat = fs.statSync(absPath)
if (stat.isDirectory()) {
fs.rmSync(absPath, { recursive: true, force: true })
} else {
fs.unlinkSync(absPath)
}
} catch {
return NextResponse.json({ error: 'Failed to delete' }, { status: 500 })
}
const db = getDb()
const itemKey = `${libraryId}:mixed_file:${encodeURIComponent(itemPath)}`
removeAllAssignmentsForItem(itemKey)
db.prepare('DELETE FROM media_items WHERE item_key = ?').run(itemKey)
// For directories, also clean up children
const prefix = `${libraryId}:mixed_file:${encodeURIComponent(itemPath + '/')}`
const children = db.prepare('SELECT item_key FROM media_items WHERE item_key LIKE ?').all(`${prefix}%`) as { item_key: string }[]
for (const child of children) {
removeAllAssignmentsForItem(child.item_key)
}
db.prepare('DELETE FROM media_items WHERE item_key LIKE ?').run(`${prefix}%`)
return new NextResponse(null, { status: 204 })
}