Files
ReadMeABook/tests/helpers/prisma.ts
T
kikootwo 09cff5b68d Add per-user ignored audiobooks feature
Introduce a per-user "ignored audiobooks" feature to suppress auto-requests. Changes include:

- Database: add Prisma model IgnoredAudiobook and SQL migration to create ignored_audiobooks table with indexes and FK to users.
- Backend: new API routes to list, add, delete, and check ignored audiobooks (/api/user/ignored-audiobooks, /check/:asin, /:id). Add annotateWithIgnoreStatus utility and integrate it into multiple audiobook list endpoints (popular, new-releases, category, search, authors, series).
- Request creator: add ignore-list check (with sibling-ASIN expansion) and a bypassIgnore option for manual requests; return an 'ignored' reason when blocked.
- Frontend: hooks (useIsIgnored, useToggleIgnore, useIgnoredList) and UI updates — AudiobookCard shows an "Ignored" indicator and AudiobookDetailsModal adds an ignore toggle and propagates local state changes.
- Misc: adjust deduplication duration tolerance (to 5% / min 10 minutes), tweak SWR refresh intervals for shelves/syncing, and small logging/info updates.
- Tests: add unit tests for request-creator ignore logic and update existing tests/mocks to account for ignore annotation; extend prisma test helper with ignoredAudiobook mock.

This commit implements the ignore-list end-to-end (DB, server, client, and tests) so users can ignore specific ASINs and have auto-request flows respect that preference.
2026-03-11 11:56:35 -04:00

65 lines
1.9 KiB
TypeScript

/**
* Component: Prisma Mock Factory
* Documentation: documentation/backend/database.md
*/
import { vi } from 'vitest';
type PrismaModelMock = {
findMany: ReturnType<typeof vi.fn>;
findFirst: ReturnType<typeof vi.fn>;
findUnique: ReturnType<typeof vi.fn>;
create: ReturnType<typeof vi.fn>;
createMany: ReturnType<typeof vi.fn>;
update: ReturnType<typeof vi.fn>;
updateMany: ReturnType<typeof vi.fn>;
upsert: ReturnType<typeof vi.fn>;
delete: ReturnType<typeof vi.fn>;
deleteMany: ReturnType<typeof vi.fn>;
count: ReturnType<typeof vi.fn>;
};
const createModelMock = (): PrismaModelMock => ({
findMany: vi.fn(),
findFirst: vi.fn(),
findUnique: vi.fn(),
create: vi.fn(() => Promise.resolve({})),
createMany: vi.fn(() => Promise.resolve({ count: 0 })),
update: vi.fn(() => Promise.resolve({})),
updateMany: vi.fn(() => Promise.resolve({})),
upsert: vi.fn(() => Promise.resolve({})),
delete: vi.fn(() => Promise.resolve({})),
deleteMany: vi.fn(() => Promise.resolve({})),
count: vi.fn(),
});
export const createPrismaMock = () => ({
configuration: createModelMock(),
user: createModelMock(),
request: createModelMock(),
audiobook: createModelMock(),
downloadHistory: createModelMock(),
plexLibrary: createModelMock(),
audibleCache: createModelMock(),
job: createModelMock(),
jobEvent: createModelMock(),
scheduledJob: createModelMock(),
bookDateConfig: createModelMock(),
bookDateRecommendation: createModelMock(),
bookDateSwipe: createModelMock(),
goodreadsShelf: createModelMock(),
bookMapping: createModelMock(),
hardcoverShelf: createModelMock(),
apiToken: createModelMock(),
work: createModelMock(),
workAsin: createModelMock(),
watchedSeries: createModelMock(),
watchedAuthor: createModelMock(),
userHomeSection: createModelMock(),
audibleCacheCategory: createModelMock(),
ignoredAudiobook: createModelMock(),
$queryRaw: vi.fn(),
$transaction: vi.fn(),
$disconnect: vi.fn(),
});