fix(opds): include public smart scopes in OPDS feeds

Allow users to access public smart scopes through the OPDS endpoint. Currently, the service only queries smart scopes owned by the requesting user, which prevents public smart scopes created by other users from showing up on devices like KOReader.

Fixes #560
This commit is contained in:
neon
2026-07-06 04:27:15 +00:00
parent fe57701f51
commit 000c380f4f
2 changed files with 8 additions and 2 deletions
@@ -204,10 +204,16 @@ describe('OpdsBookService', () => {
}); });
it('returns user collections and smartScopes', async () => { it('returns user collections and smartScopes', async () => {
const { service } = makeService([[{ id: 4, name: 'Favorites', bookCount: 1 }], [{ id: 7, name: 'Unread', icon: 'sparkles' }]]); const { service, db } = makeService([[{ id: 4, name: 'Favorites', bookCount: 1 }], [{ id: 7, name: 'Unread', icon: 'sparkles' }]]);
await expect(service.getUserCollections(8)).resolves.toEqual([{ id: 4, name: 'Favorites', bookCount: 1 }]); await expect(service.getUserCollections(8)).resolves.toEqual([{ id: 4, name: 'Favorites', bookCount: 1 }]);
await expect(service.getUserSmartScopes(8)).resolves.toEqual([{ id: 7, name: 'Unread', icon: 'sparkles' }]); await expect(service.getUserSmartScopes(8)).resolves.toEqual([{ id: 7, name: 'Unread', icon: 'sparkles' }]);
const chains = (db.select as ReturnType<typeof vi.fn>).mock.results.map((r) => r.value as Record<string, unknown>);
const smartScopeChain = chains[1]!;
const whereClause = (smartScopeChain.where as ReturnType<typeof vi.fn>).mock.calls[0]?.[0];
expect(collectValues(whereClause)).toContain(8);
expect(collectValues(whereClause)).toContain(true);
}); });
it('enforces validateBookAccess ownership checks', async () => { it('enforces validateBookAccess ownership checks', async () => {
+1 -1
View File
@@ -440,7 +440,7 @@ export class OpdsBookService {
icon: smartScopes.icon, icon: smartScopes.icon,
}) })
.from(smartScopes) .from(smartScopes)
.where(eq(smartScopes.userId, userId)) .where(or(eq(smartScopes.userId, userId), eq(smartScopes.isPublic, true)))
.orderBy(smartScopes.name); .orderBy(smartScopes.name);
} }