mirror of
https://github.com/kikootwo/ReadMeABook.git
synced 2026-06-02 20:30:10 +00:00
b1492fc32e
Introduce a per-request release blocklist to auto-block permanently failing releases and provide admin management. Changes include: - Database: add BlockedRelease model (blocked_releases) to Prisma schema with unique (requestId, releaseKey) and indexes; documented in backend database docs. - Service & utils: new blocklist.service, release-key and filter helpers for normalization and matching; processors updated to emit auto-blocks (monitor-download, organize-files, search processors, RSS). - HTTP API: add admin endpoints GET/DELETE /api/admin/blocklist, DELETE /api/admin/blocklist/[id], and GET /api/admin/blocklist/by-request/[requestId]. - Admin UI: new /admin/blocklist page and numerous React components (toolbar, filters, table, rows, pagination, skeleton, chips, date picker) with URL-driven state hook and per-row unblock UX. - Tests: add unit/integration tests for service, routes, utils, and updated processor tests. The blocklist is idempotent (upsert), filters search results before ranking (interactive search shows badges only), and admin-only APIs require auth. This commit wires docs, API, DB, frontend and tests for the new feature.
52 lines
1.7 KiB
TypeScript
52 lines
1.7 KiB
TypeScript
/**
|
|
* Component: Admin Blocklist — Single Unblock
|
|
* Documentation: documentation/admin-features/release-blocklist.md
|
|
*
|
|
* DELETE /api/admin/blocklist/[id] → removes a single blocklist entry.
|
|
*/
|
|
|
|
import { NextRequest, NextResponse } from 'next/server';
|
|
import { requireAuth, requireAdmin, AuthenticatedRequest } from '@/lib/middleware/auth';
|
|
import { Prisma } from '@/generated/prisma';
|
|
import { RMABLogger } from '@/lib/utils/logger';
|
|
import { removeBlock } from '@/lib/services/blocklist.service';
|
|
|
|
const logger = RMABLogger.create('API.Admin.Blocklist.Unblock');
|
|
|
|
export async function DELETE(
|
|
request: NextRequest,
|
|
{ params }: { params: Promise<{ id: string }> }
|
|
) {
|
|
return requireAuth(request, async (req: AuthenticatedRequest) => {
|
|
return requireAdmin(req, async () => {
|
|
const { id } = await params;
|
|
if (!id || typeof id !== 'string' || id.trim().length === 0) {
|
|
return NextResponse.json({ error: 'Invalid id' }, { status: 400 });
|
|
}
|
|
|
|
try {
|
|
await removeBlock(id);
|
|
return NextResponse.json({ success: true });
|
|
} catch (error) {
|
|
if (
|
|
error instanceof Prisma.PrismaClientKnownRequestError &&
|
|
error.code === 'P2025'
|
|
) {
|
|
return NextResponse.json(
|
|
{ error: 'NotFound', message: 'Blocklist entry not found' },
|
|
{ status: 404 }
|
|
);
|
|
}
|
|
logger.error('Failed to remove blocklist entry', {
|
|
id,
|
|
error: error instanceof Error ? error.message : String(error),
|
|
});
|
|
return NextResponse.json(
|
|
{ error: 'Failed to remove blocklist entry' },
|
|
{ status: 500 }
|
|
);
|
|
}
|
|
});
|
|
});
|
|
}
|