mirror of
https://github.com/bookorbit/bookorbit.git
synced 2026-11-03 00:11:37 -06:00
fix(koreader): accept optional KOSync document metadata (#966)
* fix(koreader): accept optional KOSync document metadata * fix(koreader): reject null progress metadata
This commit is contained in:
@@ -8,6 +8,29 @@ import { KoreaderSaveProgressDto } from './koreader-progress.dto';
|
||||
const BASE = { document: 'abc123', percentage: 0.42 };
|
||||
|
||||
describe('KoreaderSaveProgressDto', () => {
|
||||
it('accepts optional document metadata from newer KOSync clients', async () => {
|
||||
const metadata = { filename: 'book.epub', title: 'Book', authors: 'Author' };
|
||||
const dto = plainToInstance(KoreaderSaveProgressDto, { ...BASE, metadata });
|
||||
const errors = await validate(dto, { whitelist: true, forbidNonWhitelisted: true });
|
||||
|
||||
expect(errors).toHaveLength(0);
|
||||
expect(dto.metadata).toEqual(metadata);
|
||||
});
|
||||
|
||||
it('rejects metadata values that are not objects', async () => {
|
||||
const dto = plainToInstance(KoreaderSaveProgressDto, { ...BASE, metadata: 'book.epub' });
|
||||
const errors = await validate(dto);
|
||||
|
||||
expect(errors).toEqual([expect.objectContaining({ property: 'metadata' })]);
|
||||
});
|
||||
|
||||
it('rejects explicit null metadata', async () => {
|
||||
const dto = plainToInstance(KoreaderSaveProgressDto, { ...BASE, metadata: null });
|
||||
const errors = await validate(dto);
|
||||
|
||||
expect(errors).toEqual([expect.objectContaining({ property: 'metadata' })]);
|
||||
});
|
||||
|
||||
it('accepts an xpointer string progress from reflowable documents', async () => {
|
||||
const dto = plainToInstance(KoreaderSaveProgressDto, { ...BASE, progress: '/body/DocFragment[8]/body/p[12]/text().0' });
|
||||
const errors = await validate(dto);
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
import { Transform } from 'class-transformer';
|
||||
import { IsNumber, IsOptional, IsString, Max, Min } from 'class-validator';
|
||||
import { IsNumber, IsObject, IsOptional, IsString, Max, Min, ValidateIf } from 'class-validator';
|
||||
|
||||
export class KoreaderSaveProgressDto {
|
||||
@IsString()
|
||||
document!: string;
|
||||
|
||||
@IsObject()
|
||||
@ValidateIf((_object, value) => value !== undefined)
|
||||
metadata?: Record<string, unknown>;
|
||||
|
||||
@IsNumber()
|
||||
@Min(0)
|
||||
@Max(1)
|
||||
|
||||
@@ -150,6 +150,22 @@ describe('KOReader progress position routing (e2e)', { timeout: 180_000 }, () =>
|
||||
expect((await readerProgress(epub.bookFileId)).pageNumber).toBeNull();
|
||||
});
|
||||
|
||||
it('accepts document metadata on progress sync requests', async () => {
|
||||
const response = await ctx.app.inject({
|
||||
method: 'PUT',
|
||||
url: '/api/v1/koreader/syncs/progress',
|
||||
headers: deviceHeaders(),
|
||||
payload: {
|
||||
document: epubHash,
|
||||
percentage: 0.35,
|
||||
progress: XPOINTER,
|
||||
metadata: { filename: 'progress-position-book.epub', title: 'Progress Position Book', authors: 'Test Author' },
|
||||
},
|
||||
});
|
||||
|
||||
expect(response.statusCode).toBe(200);
|
||||
});
|
||||
|
||||
it('replaces a page saved by the web reader instead of discarding it', async () => {
|
||||
await saveFromWebReader(comic.bookFileId, { percentage: 12, pageNumber: 34 });
|
||||
expect((await storedProgress(comic.bookFileId))?.pageNumber).toBe(34);
|
||||
|
||||
Reference in New Issue
Block a user