mirror of
https://github.com/kikootwo/ReadMeABook.git
synced 2026-06-02 20:30:10 +00:00
Add release blocklist feature
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.
This commit is contained in:
@@ -111,12 +111,32 @@ PostgreSQL database storing users, audiobooks, requests, downloads, configuratio
|
||||
- Indexes: `job_id`, `created_at`
|
||||
- **Purpose:** Store detailed event logs for job operations (shown in admin logs UI)
|
||||
|
||||
### Blocked_Releases
|
||||
- `id` (UUID PK), `request_id` (FK → Requests, CASCADE on hard delete)
|
||||
- `release_name` (text) - original release title as the indexer returned it
|
||||
- `release_key` (text) - normalized lookup key: `trim().toLowerCase()` of release_name
|
||||
- `release_hash` (nullable) - `torrentHash` (qBit) OR `nzbId` (SAB/NZBGet); mutually exclusive in source
|
||||
- `indexer_name` (nullable), `indexer_id` (int, nullable)
|
||||
- `source` ('organize_fail'|'download_fail'|'manual'; 'manual' reserved for v2)
|
||||
- `reason` (text) - short, e.g. "No audiobook files found", "Download failed (par2)"
|
||||
- `reason_detail` (text, nullable) - raw client error string (SAB failMessage, NZBGet Par/Unpack code)
|
||||
- `download_history_id` (nullable) - traceability to the DownloadHistory row that drove the block
|
||||
- `job_id` (nullable) - origin job; also drives JobEvent emission via RMABLogger.forJob
|
||||
- `created_at` (timestamp)
|
||||
- Unique: `(request_id, release_key)` - idempotency for concurrent auto-block writes
|
||||
- Indexes: `request_id`, `release_key`, `release_hash`, `created_at DESC`
|
||||
- **Purpose:** Per-request blocklist. Search processors filter their candidate set against this table so future searches skip releases that have already failed for the same request.
|
||||
- **Soft/hard delete:** Soft-delete (sets `requests.deleted_at`) does NOT cascade - blocklist entries survive. Hard-delete cascades and wipes entries.
|
||||
- **Match rules:** Case-insensitive exact match on `release_key` OR exact match on `release_hash`.
|
||||
- **Service:** Single writer is `src/lib/services/blocklist.service.ts` (`addAutoBlock` is idempotent via upsert; never throws).
|
||||
|
||||
## Relationships
|
||||
|
||||
- User → Requests (1:many)
|
||||
- Audiobook → Requests (1:many)
|
||||
- Request → Download History (1:many)
|
||||
- Request → Jobs (1:many, nullable)
|
||||
- Request → Blocked Releases (1:many, CASCADE on hard delete)
|
||||
- Job → Job Events (1:many, CASCADE delete)
|
||||
|
||||
## Setup Strategy
|
||||
|
||||
Reference in New Issue
Block a user