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.6 KiB
TypeScript
52 lines
1.6 KiB
TypeScript
/**
|
|
* Component: Release Key Normalizer Tests
|
|
* Documentation: documentation/backend/database.md
|
|
*/
|
|
|
|
import { describe, expect, it } from 'vitest';
|
|
import { normalizeReleaseKey } from '@/lib/utils/release-key';
|
|
|
|
describe('normalizeReleaseKey', () => {
|
|
it('lowercases ASCII characters', () => {
|
|
expect(normalizeReleaseKey('SomeReleaseName')).toBe('somereleasename');
|
|
});
|
|
|
|
it('trims leading and trailing whitespace', () => {
|
|
expect(normalizeReleaseKey(' hello ')).toBe('hello');
|
|
});
|
|
|
|
it('combines trim and lowercase', () => {
|
|
expect(normalizeReleaseKey(' MIXED.Case Release ')).toBe('mixed.case release');
|
|
});
|
|
|
|
it('preserves internal whitespace', () => {
|
|
expect(normalizeReleaseKey('the templar legacy')).toBe('the templar legacy');
|
|
});
|
|
|
|
it('returns empty string for empty input', () => {
|
|
expect(normalizeReleaseKey('')).toBe('');
|
|
});
|
|
|
|
it('returns empty string for whitespace-only input', () => {
|
|
expect(normalizeReleaseKey(' ')).toBe('');
|
|
});
|
|
|
|
it('passes through unicode characters (with native lowercasing)', () => {
|
|
expect(normalizeReleaseKey('Éclair')).toBe('éclair');
|
|
});
|
|
|
|
it('is idempotent — normalizing a normalized value is a no-op', () => {
|
|
const once = normalizeReleaseKey(' Some Release ');
|
|
expect(normalizeReleaseKey(once)).toBe(once);
|
|
});
|
|
|
|
it('treats different-case variants of the same release as the same key', () => {
|
|
expect(normalizeReleaseKey('THE.TEMPLAR.LEGACY')).toBe(
|
|
normalizeReleaseKey('the.templar.legacy')
|
|
);
|
|
expect(normalizeReleaseKey(' The.Templar.Legacy ')).toBe(
|
|
normalizeReleaseKey('the.templar.legacy')
|
|
);
|
|
});
|
|
});
|