mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-20 22:16:26 +00:00
refactor(server): plan 4 — inline canAccessTrip/isOwner off DatabaseService (plugins + MCP surfaces)
This commit is contained in:
@@ -16,7 +16,7 @@ import { BucketItemExistsError } from '../../../src/nest/atlas/atlas.service';
|
||||
import { VacayRpc } from '../../../src/nest/vacay/vacay.rpc';
|
||||
import { JournalRpc } from '../../../src/nest/journey/journal.rpc';
|
||||
import { CollectionsRpc } from '../../../src/nest/collections/collections.rpc';
|
||||
import type { DatabaseService } from '../../../src/nest/database/database.service';
|
||||
import type { TripsRepository } from '../../../src/db/repositories/Trips.repository';
|
||||
import type { PermissionsService } from '../../../src/nest/permissions/permissions.service';
|
||||
import type { AddonsService } from '../../../src/nest/addons/addons.service';
|
||||
import type { UsersRepository } from '../../../src/db/repositories/Users.repository';
|
||||
@@ -39,9 +39,9 @@ function build(overrides: {
|
||||
collections?: Record<string, unknown>;
|
||||
} = {}) {
|
||||
const db = {
|
||||
canAccessTrip: vi.fn(async () => ({ id: 1, user_id: 42 })),
|
||||
findAccessible: vi.fn(async () => ({ id: 1, user_id: 42 })),
|
||||
prepare: vi.fn(() => ({ get: () => ({ role: 'user' }), all: () => [] })),
|
||||
} as unknown as DatabaseService;
|
||||
} as unknown as TripsRepository;
|
||||
const guards = new PluginGuards(
|
||||
db,
|
||||
{ checkPermission: vi.fn(() => true) } as unknown as PermissionsService,
|
||||
|
||||
@@ -20,7 +20,7 @@ import { VacayRpc } from '../../../src/nest/vacay/vacay.rpc';
|
||||
import { JournalRpc } from '../../../src/nest/journey/journal.rpc';
|
||||
import { CollectionsRpc } from '../../../src/nest/collections/collections.rpc';
|
||||
import { CostsRpc } from '../../../src/nest/budget/costs.rpc';
|
||||
import type { DatabaseService } from '../../../src/nest/database/database.service';
|
||||
import type { TripsRepository } from '../../../src/db/repositories/Trips.repository';
|
||||
import type { PermissionsService } from '../../../src/nest/permissions/permissions.service';
|
||||
import type { AddonsService } from '../../../src/nest/addons/addons.service';
|
||||
import type { UsersRepository } from '../../../src/db/repositories/Users.repository';
|
||||
@@ -57,9 +57,9 @@ function spyService(calls: string[], name: string) {
|
||||
function build(addonOn: boolean) {
|
||||
const calls: string[] = [];
|
||||
const db = {
|
||||
canAccessTrip: vi.fn(async () => ({ id: 1, user_id: 42 })),
|
||||
findAccessible: vi.fn(async () => ({ id: 1, user_id: 42 })),
|
||||
prepare: vi.fn(() => ({ get: () => ({ role: 'user' }), all: () => [] })),
|
||||
} as unknown as DatabaseService;
|
||||
} as unknown as TripsRepository;
|
||||
const guards = new PluginGuards(
|
||||
db,
|
||||
{ checkPermission: vi.fn(() => true) } as unknown as PermissionsService,
|
||||
|
||||
@@ -16,7 +16,7 @@ vi.mock('../../../src/db/database', () => ({
|
||||
db: { prepare: () => ({ all: () => tripDays.value }) },
|
||||
canAccessTrip,
|
||||
}));
|
||||
import { DatabaseService } from '../../../src/nest/database/database.service';
|
||||
import type { TripsRepository } from '../../../src/db/repositories/Trips.repository';
|
||||
vi.mock('../../../src/nest/plugins/kill-switch', () => ({ pluginsEnabled }));
|
||||
|
||||
import { DayScheduleController } from '../../../src/nest/plugins/contributions/day-schedule.controller';
|
||||
@@ -32,7 +32,7 @@ function controller(invoke: (id: string) => unknown, providers = ['p1']) {
|
||||
} as unknown as PluginHooks;
|
||||
// CT1 (Plan 3j Task 5) — the day-id-set read is now DaysRepository.listIdsByTrip.
|
||||
const days = { listIdsByTrip: vi.fn(async () => tripDays.value.map((d) => d.id)) } as unknown as DaysRepository;
|
||||
return { c: new DayScheduleController(runtime, { canAccessTrip } as unknown as DatabaseService, days), runtime };
|
||||
return { c: new DayScheduleController(runtime, { findAccessible: canAccessTrip } as unknown as TripsRepository, days), runtime };
|
||||
}
|
||||
const item = (over: Record<string, unknown> = {}) => ({ id: 's1', dayId: 10, label: 'Charging', ...over });
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ vi.mock('../../../src/db/database', () => ({
|
||||
db: { prepare: () => ({ all: () => tripDays.value }) },
|
||||
canAccessTrip,
|
||||
}));
|
||||
import { DatabaseService } from '../../../src/nest/database/database.service';
|
||||
import type { TripsRepository } from '../../../src/db/repositories/Trips.repository';
|
||||
vi.mock('../../../src/nest/plugins/kill-switch', () => ({ pluginsEnabled }));
|
||||
|
||||
import { DayTintsController } from '../../../src/nest/plugins/contributions/day-tints.controller';
|
||||
@@ -32,7 +32,7 @@ function controller(invoke: (id: string) => unknown, providers = ['p1']) {
|
||||
} as unknown as PluginHooks;
|
||||
// CT2 (Plan 3j Task 5) — the day-id-set read is now DaysRepository.listIdsByTrip.
|
||||
const days = { listIdsByTrip: vi.fn(async () => tripDays.value.map((d) => d.id)) } as unknown as DaysRepository;
|
||||
return { c: new DayTintsController(runtime, { canAccessTrip } as unknown as DatabaseService, days), runtime };
|
||||
return { c: new DayTintsController(runtime, { findAccessible: canAccessTrip } as unknown as TripsRepository, days), runtime };
|
||||
}
|
||||
const tint = (over: Record<string, unknown> = {}) => ({ dayId: 10, tone: 'success', ...over });
|
||||
|
||||
|
||||
@@ -65,7 +65,6 @@ import { UnreadableLlmResponse } from '../../../src/nest/llm-parse/clients/opena
|
||||
import { getPluginDataDb, closePluginDataDb } from '../../../src/nest/plugins/host/plugin-host-state';
|
||||
import { verifyChain } from '../../../src/nest/plugins/host/plugin-audit';
|
||||
import { db as mockDb } from '../../../src/db/database';
|
||||
import { DatabaseService } from '../../../src/nest/database/database.service';
|
||||
import { RealtimeService } from '../../../src/nest/realtime/realtime.service';
|
||||
import type { PermissionsService } from '../../../src/nest/permissions/permissions.service';
|
||||
import type { AddonsService } from '../../../src/nest/addons/addons.service';
|
||||
@@ -154,6 +153,13 @@ type RawDb = {
|
||||
const raw = mockDb as unknown as RawDb;
|
||||
|
||||
const tripsRepo = {
|
||||
// Plan 4 Task 2 — PluginGuards' own canAccessTrip delegate is now this
|
||||
// repository's findAccessible directly (same access rule the old
|
||||
// `db/database` mock factory above encoded: trip 1 belongs to user 5,
|
||||
// user 6 is a member).
|
||||
async findAccessible(tripId: number | string, userId: number) {
|
||||
return Number(tripId) === 1 && (userId === 5 || userId === 6) ? { id: 1, user_id: 5, currency: null } : undefined;
|
||||
},
|
||||
async sharesTripWith(userIdA: number, userIdB: number) {
|
||||
return !!raw
|
||||
.prepare(
|
||||
@@ -283,17 +289,6 @@ const scheduledTasksRepo = {
|
||||
},
|
||||
} as unknown as PluginScheduledTasksRepository;
|
||||
|
||||
const dbs = new DatabaseService(mockDb);
|
||||
// Plan 3c Task 0b: `canAccessTrip` is `TripsRepository.findAccessible` now,
|
||||
// which needs a real EntityManager over the full migrated schema — this
|
||||
// file's `mockDb` is a hand-trimmed `:memory:` table set (no `currency`
|
||||
// column on `trips`, among others), so a real repository read isn't
|
||||
// possible against it. Spied directly with the exact access rule the old
|
||||
// `db/database` mock factory above encoded (trip 1 belongs to user 5, user 6
|
||||
// is a member), which is now dead code for this purpose.
|
||||
vi.spyOn(dbs, 'canAccessTrip').mockImplementation(async (tripId, userId) =>
|
||||
Number(tripId) === 1 && (userId === 5 || userId === 6) ? { id: 1, user_id: 5, currency: null } : undefined,
|
||||
);
|
||||
// Plan 3j Task 1: PluginGuards' own role lookup (PG3/PG4) now goes through
|
||||
// UsersRepository.getRole, not `dbs.prepare(...)`. Same reasoning as the
|
||||
// canAccessTrip spy above — a real UsersRepository would need a real
|
||||
@@ -315,11 +310,14 @@ const usersRepo = {
|
||||
);
|
||||
},
|
||||
} as unknown as UsersRepository;
|
||||
const guards = new PluginGuards(dbs, permissions, addons, usersRepo);
|
||||
// Plan 4 Task 2 — PluginGuards'/MetaRpc's/HostSurfaceRpc's own DatabaseService
|
||||
// params are gone: canAccessTrip now reads through the TripsRepository each
|
||||
// already injects (`tripsRepo` above, findAccessible-only).
|
||||
const guards = new PluginGuards(tripsRepo, permissions, addons, usersRepo);
|
||||
const registry = createTestPluginRegistry([
|
||||
new DbRpc(userSettings),
|
||||
new MetaRpc(dbs, guards, metaRepo, tripsRepo, placesRepo, daysRepo, reservationsRepo, dayAccommodationsRepo),
|
||||
new HostSurfaceRpc(dbs, new RealtimeService(), notifications, llmConfig, oauth, guards, pluginAuditRepo, usersRepo, tripsRepo, scheduledTasksRepo),
|
||||
new MetaRpc(guards, metaRepo, tripsRepo, placesRepo, daysRepo, reservationsRepo, dayAccommodationsRepo),
|
||||
new HostSurfaceRpc(new RealtimeService(), notifications, llmConfig, oauth, guards, pluginAuditRepo, usersRepo, tripsRepo, scheduledTasksRepo),
|
||||
]);
|
||||
const factory = new PluginRpcHostFactory(pluginAuditRepo, registry as unknown as PluginRpcRegistryService);
|
||||
const stubRouter: PluginCallRouter = { callPlugin: async () => undefined, emitPluginEvent: async () => {} };
|
||||
|
||||
@@ -16,7 +16,7 @@ vi.mock('../../../src/nest/plugins/kill-switch', () => ({ pluginsEnabled }));
|
||||
|
||||
import { MapLayersController } from '../../../src/nest/plugins/contributions/map-layers.controller';
|
||||
import type { PluginHooks } from '../../../src/nest/plugins/plugin-hooks.service';
|
||||
import type { DatabaseService } from '../../../src/nest/database/database.service';
|
||||
import type { TripsRepository } from '../../../src/db/repositories/Trips.repository';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const req = (id?: number) => ({ user: id === undefined ? undefined : { id } }) as any;
|
||||
@@ -25,7 +25,7 @@ function controller(invoke: (id: string) => unknown, providers = ['p1']) {
|
||||
providersOf: vi.fn(() => providers),
|
||||
mapLayers: vi.fn(async (id: string) => invoke(id)),
|
||||
} as unknown as PluginHooks;
|
||||
return { c: new MapLayersController(runtime, { canAccessTrip } as unknown as DatabaseService), runtime };
|
||||
return { c: new MapLayersController(runtime, { findAccessible: canAccessTrip } as unknown as TripsRepository), runtime };
|
||||
}
|
||||
const line = (n = 3, over: Record<string, unknown> = {}) => ({
|
||||
type: 'polyline',
|
||||
|
||||
@@ -15,7 +15,7 @@ vi.mock('../../../src/nest/plugins/kill-switch', () => ({ pluginsEnabled }));
|
||||
|
||||
import { MapMarkersController } from '../../../src/nest/plugins/contributions/map-markers.controller';
|
||||
import type { PluginHooks } from '../../../src/nest/plugins/plugin-hooks.service';
|
||||
import type { DatabaseService } from '../../../src/nest/database/database.service';
|
||||
import type { TripsRepository } from '../../../src/db/repositories/Trips.repository';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const req = (id?: number) => ({ user: id === undefined ? undefined : { id } }) as any;
|
||||
@@ -24,7 +24,7 @@ function controller(invoke: (id: string) => unknown, providers = ['p1']) {
|
||||
providersOf: vi.fn(() => providers),
|
||||
mapMarkers: vi.fn(async (id: string) => invoke(id)),
|
||||
} as unknown as PluginHooks;
|
||||
return { c: new MapMarkersController(runtime, { canAccessTrip } as unknown as DatabaseService), runtime };
|
||||
return { c: new MapMarkersController(runtime, { findAccessible: canAccessTrip } as unknown as TripsRepository), runtime };
|
||||
}
|
||||
const mk = (over: Record<string, unknown> = {}) => ({ id: 'm1', lat: 48.85, lng: 2.35, ...over });
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ vi.mock('../../../src/nest/plugins/kill-switch', () => ({ pluginsEnabled }));
|
||||
|
||||
import { PdfSectionsController } from '../../../src/nest/plugins/contributions/pdf-sections.controller';
|
||||
import type { PluginHooks } from '../../../src/nest/plugins/plugin-hooks.service';
|
||||
import type { DatabaseService } from '../../../src/nest/database/database.service';
|
||||
import type { TripsRepository } from '../../../src/db/repositories/Trips.repository';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const req = (id?: number) => ({ user: id === undefined ? undefined : { id } }) as any;
|
||||
@@ -25,7 +25,7 @@ function controller(invoke: (id: string) => unknown, providers = ['p1']) {
|
||||
providersOf: vi.fn(() => providers),
|
||||
pdfSections: vi.fn(async (id: string) => invoke(id)),
|
||||
} as unknown as PluginHooks;
|
||||
return { c: new PdfSectionsController(runtime, { canAccessTrip } as unknown as DatabaseService), runtime };
|
||||
return { c: new PdfSectionsController(runtime, { findAccessible: canAccessTrip } as unknown as TripsRepository), runtime };
|
||||
}
|
||||
const sec = (over: Record<string, unknown> = {}) => ({ title: 'Weather', ...over });
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ vi.mock('../../../src/db/database', () => ({
|
||||
db: { prepare: () => ({ get: (placeId: number) => placeTrip(placeId) }) },
|
||||
canAccessTrip,
|
||||
}));
|
||||
import { DatabaseService } from '../../../src/nest/database/database.service';
|
||||
import type { TripsRepository } from '../../../src/db/repositories/Trips.repository';
|
||||
vi.mock('../../../src/nest/plugins/kill-switch', () => ({ pluginsEnabled }));
|
||||
|
||||
import { PlaceDetailsController } from '../../../src/nest/plugins/contributions/place-details.controller';
|
||||
@@ -26,7 +26,7 @@ function controller(over: Partial<PluginHooks> = {}) {
|
||||
} as unknown as PluginHooks;
|
||||
// CT7 (Plan 3j Task 5) — the place's owning trip id is now Places.repository.ts#findTripId.
|
||||
const places = { findTripId: vi.fn(async (placeId: number) => placeTrip(placeId)?.trip_id) } as unknown as PlacesRepository;
|
||||
return { c: new PlaceDetailsController(runtime, { canAccessTrip } as unknown as DatabaseService, places), runtime };
|
||||
return { c: new PlaceDetailsController(runtime, { findAccessible: canAccessTrip } as unknown as TripsRepository, places), runtime };
|
||||
}
|
||||
|
||||
describe('PlaceDetailsController', () => {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
||||
import { PluginGuards } from '../../../src/nest/plugins/host/plugin-guards.service';
|
||||
import { BadParams, ForbiddenResource } from '../../../src/nest/plugins/host/rpc-errors';
|
||||
import type { DatabaseService } from '../../../src/nest/database/database.service';
|
||||
import type { TripsRepository } from '../../../src/db/repositories/Trips.repository';
|
||||
import { PermissionsService } from '../../../src/nest/permissions/permissions.service';
|
||||
import type { AddonsService } from '../../../src/nest/addons/addons.service';
|
||||
import type { UsersRepository } from '../../../src/db/repositories/Users.repository';
|
||||
@@ -47,10 +47,10 @@ const ctx = (actingUserId: number | undefined): PluginRpcContext => ({
|
||||
*/
|
||||
function build(overrides: { role?: string | null; allow?: boolean; addonOn?: boolean } = {}) {
|
||||
const db = {
|
||||
canAccessTrip: vi.fn(async (tripId: number, userId: number) =>
|
||||
findAccessible: vi.fn(async (tripId: number, userId: number) =>
|
||||
tripId === 1 && userId === 42 ? { id: 1, user_id: 42 } : undefined,
|
||||
),
|
||||
} as unknown as DatabaseService;
|
||||
} as unknown as TripsRepository;
|
||||
const users = {
|
||||
getRole: vi.fn(async () => ('role' in overrides ? (overrides.role ?? null) : 'user')),
|
||||
} as unknown as UsersRepository;
|
||||
@@ -149,8 +149,8 @@ describe('PluginGuards — requireTripEdit and canEditAs', () => {
|
||||
|
||||
it('PGUARD-014 a non-owner member is flagged as shared', async () => {
|
||||
const db = {
|
||||
canAccessTrip: vi.fn(async () => ({ id: 1, user_id: 7 })),
|
||||
} as unknown as DatabaseService;
|
||||
findAccessible: vi.fn(async () => ({ id: 1, user_id: 7 })),
|
||||
} as unknown as TripsRepository;
|
||||
const users = { getRole: vi.fn(async () => 'user') } as unknown as UsersRepository;
|
||||
const permissions = { checkPermission: vi.fn(() => true) } as unknown as PermissionsService;
|
||||
const guards = new PluginGuards(db, permissions, {} as AddonsService, users);
|
||||
@@ -201,8 +201,8 @@ describe('PluginGuards — canEditAs/canCreateAs against a real UsersRepository
|
||||
orm = await createTestOrm(testDb);
|
||||
const permissions = new PermissionsService(orm.repo(AppSettings), new UnitOfWork(orm.em));
|
||||
const db = {
|
||||
canAccessTrip: vi.fn(async (tripId: number) => (tripId === 1 ? { id: 1, user_id: ownerId } : undefined)),
|
||||
} as unknown as DatabaseService;
|
||||
findAccessible: vi.fn(async (tripId: number) => (tripId === 1 ? { id: 1, user_id: ownerId } : undefined)),
|
||||
} as unknown as TripsRepository;
|
||||
// The permissions cache is module-scoped (permissions-cache.ts), not
|
||||
// per-instance — invalidate before every case so a stored override from
|
||||
// another describe block in this same worker can't leak in.
|
||||
|
||||
@@ -16,7 +16,7 @@ vi.mock('../../../src/db/database', () => ({
|
||||
db: { prepare: () => ({ get: () => (capabilitiesRow.value === undefined ? undefined : { capabilities: capabilitiesRow.value }) }) },
|
||||
canAccessTrip,
|
||||
}));
|
||||
import { DatabaseService } from '../../../src/nest/database/database.service';
|
||||
import type { TripsRepository } from '../../../src/db/repositories/Trips.repository';
|
||||
vi.mock('../../../src/nest/plugins/kill-switch', () => ({ pluginsEnabled }));
|
||||
|
||||
import { PluginRoutesController } from '../../../src/nest/plugins/contributions/plugin-routes.controller';
|
||||
@@ -36,7 +36,7 @@ function controller(invoke: () => unknown, providers = ['ev-plug']) {
|
||||
const plugins = {
|
||||
findCapabilities: vi.fn(async () => (capabilitiesRow.value === undefined ? null : capabilitiesRow.value)),
|
||||
} as unknown as PluginsRepository;
|
||||
return { c: new PluginRoutesController(runtime, { canAccessTrip } as unknown as DatabaseService, plugins), runtime };
|
||||
return { c: new PluginRoutesController(runtime, { findAccessible: canAccessTrip } as unknown as TripsRepository, plugins), runtime };
|
||||
}
|
||||
const wp = (n = 3) => Array.from({ length: n }, (_, i) => ({ lat: 48 + i * 0.1, lng: 2 + i * 0.1 }));
|
||||
const goodRoute = (n = 3, over: Record<string, unknown> = {}) => ({
|
||||
|
||||
@@ -42,6 +42,7 @@ import { RpcRateLimiter, DEFAULT_RPC_LIMIT } from '../../../src/nest/plugins/hos
|
||||
import { createTestOrm, type TestOrm } from '../../helpers/test-orm';
|
||||
import { AppSettings } from '../../../src/db/entities/AppSettings.entity';
|
||||
import { Users } from '../../../src/db/entities/Users.entity';
|
||||
import { Trips } from '../../../src/db/entities/Trips.entity';
|
||||
import type { PluginRpcHost } from '../../../src/nest/plugins/host/rpc-host';
|
||||
import type { RpcRequest, RpcResponse, RpcError } from '../../../src/nest/plugins/protocol/envelope';
|
||||
import type { EntityManager } from '@mikro-orm/core';
|
||||
@@ -76,7 +77,9 @@ beforeAll(async () => {
|
||||
// above), not a stub, because this suite's whole point is proving that
|
||||
// read fails outside withRequestContext and succeeds inside it (D6/C3).
|
||||
// A mocked UsersRepository would defeat that regression coverage.
|
||||
guards = new PluginGuards(dbs, permissions, await createTestAddonsService(testDb, dbs), t.repo(Users));
|
||||
// Plan 4 Task 2 — PluginGuards' own canAccessTrip delegate is now
|
||||
// TripsRepository.findAccessible; same REAL-repository reasoning applies.
|
||||
guards = new PluginGuards(t.repo(Trips), permissions, await createTestAddonsService(testDb, dbs), t.repo(Users));
|
||||
userId = createUser(testDb, { role: 'user' }).user.id;
|
||||
// An admin has tightened trip_create from its 'everybody' default.
|
||||
testDb.prepare("INSERT OR REPLACE INTO app_settings (key, value) VALUES ('perm_trip_create', 'admin')").run();
|
||||
|
||||
@@ -24,7 +24,7 @@ import { DaysRpc } from '../../../src/nest/days/days.rpc';
|
||||
import { VacayRpc } from '../../../src/nest/vacay/vacay.rpc';
|
||||
import { NotFoundError, ValidationError } from '../../../src/nest/trips/trips.service';
|
||||
import type { EntityManager } from '@mikro-orm/core';
|
||||
import type { DatabaseService } from '../../../src/nest/database/database.service';
|
||||
import type { TripsRepository } from '../../../src/db/repositories/Trips.repository';
|
||||
import type { PermissionsService } from '../../../src/nest/permissions/permissions.service';
|
||||
import type { AddonsService } from '../../../src/nest/addons/addons.service';
|
||||
import type { UsersRepository } from '../../../src/db/repositories/Users.repository';
|
||||
@@ -42,9 +42,9 @@ const ALL = new Set([
|
||||
|
||||
function guardsFor() {
|
||||
const db = {
|
||||
canAccessTrip: vi.fn(async () => ({ id: 1, user_id: 42 })),
|
||||
findAccessible: vi.fn(async () => ({ id: 1, user_id: 42 })),
|
||||
prepare: vi.fn(() => ({ get: () => ({ role: 'user' }), all: () => [] })),
|
||||
} as unknown as DatabaseService;
|
||||
} as unknown as TripsRepository;
|
||||
// Plan 3c Task 7: TripsRpc's RP1-RP6 resolve `EntityManager.getRepository(...)`
|
||||
// now, not `db.prepare(...)` — a generic fake repository (same shape regardless
|
||||
// of which entity class was requested) covers every RP method these fallback
|
||||
|
||||
@@ -18,7 +18,7 @@ import { TripsRpc } from '../../../src/nest/trips/trips.rpc';
|
||||
import { DbRpc } from '../../../src/nest/plugins/host/rpc/db.rpc';
|
||||
import { PluginGuards } from '../../../src/nest/plugins/host/plugin-guards.service';
|
||||
import type { EntityManager } from '@mikro-orm/core';
|
||||
import type { DatabaseService } from '../../../src/nest/database/database.service';
|
||||
import type { TripsRepository } from '../../../src/db/repositories/Trips.repository';
|
||||
import type { PluginUserSettingsService } from '../../../src/nest/plugins/plugin-user-settings.service';
|
||||
|
||||
const req = (method: string, params: Record<string, unknown>): RpcRequest => ({ k: 'req', id: 'x', method, params });
|
||||
@@ -36,9 +36,9 @@ const dbRegistry = () => {
|
||||
/** trips.getById lives on the decorators now, so the audit cases bind it through them. */
|
||||
const tripsRegistry = () => {
|
||||
const db = {
|
||||
canAccessTrip: async (tripId: number, userId: number) => (tripId === 1 && userId === 42 ? { id: 1, user_id: 42 } : undefined),
|
||||
findAccessible: async (tripId: number, userId: number) => (tripId === 1 && userId === 42 ? { id: 1, user_id: 42 } : undefined),
|
||||
prepare: () => ({ get: () => ({ id: 1, title: 'Japan' }), all: () => [] }),
|
||||
} as unknown as DatabaseService;
|
||||
} as unknown as TripsRepository;
|
||||
const guards = new PluginGuards(db, {} as never, {} as never, {} as never);
|
||||
// Plan 3c Task 7: trips.getById (RP1) now reads through
|
||||
// `EntityManager.getRepository(Trips).findRaw(...)`, not `db.prepare(...)`.
|
||||
|
||||
@@ -17,7 +17,7 @@ vi.mock('../../../src/nest/plugins/kill-switch', () => ({ pluginsEnabled }));
|
||||
|
||||
import { TripCardContributionsController } from '../../../src/nest/plugins/contributions/trip-card-contributions.controller';
|
||||
import type { PluginHooks } from '../../../src/nest/plugins/plugin-hooks.service';
|
||||
import type { DatabaseService } from '../../../src/nest/database/database.service';
|
||||
import type { TripsRepository } from '../../../src/db/repositories/Trips.repository';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const req = (id?: number) => ({ user: id === undefined ? undefined : { id } }) as any;
|
||||
@@ -26,7 +26,7 @@ function controller(invoke: (id: string, args: unknown[]) => unknown, providers
|
||||
providersOf: vi.fn(() => providers),
|
||||
tripCards: vi.fn(async (id: string, _h: string, _fn: string, args: unknown[]) => invoke(id, args)),
|
||||
} as unknown as PluginHooks;
|
||||
return { c: new TripCardContributionsController(runtime, { canAccessTrip } as unknown as DatabaseService), runtime };
|
||||
return { c: new TripCardContributionsController(runtime, { findAccessible: canAccessTrip } as unknown as TripsRepository), runtime };
|
||||
}
|
||||
const badge = (over: Record<string, unknown> = {}) => ({ tripId: 1, id: 'b1', label: 'Visa', ...over });
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ vi.mock('../../../src/nest/plugins/kill-switch', () => ({ pluginsEnabled }));
|
||||
|
||||
import { TripWarningsController } from '../../../src/nest/plugins/contributions/trip-warnings.controller';
|
||||
import type { PluginHooks } from '../../../src/nest/plugins/plugin-hooks.service';
|
||||
import type { DatabaseService } from '../../../src/nest/database/database.service';
|
||||
import type { TripsRepository } from '../../../src/db/repositories/Trips.repository';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const req = (id?: number) => ({ user: id === undefined ? undefined : { id } }) as any;
|
||||
@@ -20,7 +20,7 @@ function controller(over: Partial<PluginHooks> = {}) {
|
||||
id === 'p2' ? [{ level: 'error', message: 'Day 3 is overpacked', dayId: 3 }] : [{ level: 'warning', message: 'Museum closed Mon', placeId: 7 }]),
|
||||
...over,
|
||||
} as unknown as PluginHooks;
|
||||
return { c: new TripWarningsController(runtime, { canAccessTrip } as unknown as DatabaseService), runtime };
|
||||
return { c: new TripWarningsController(runtime, { findAccessible: canAccessTrip } as unknown as TripsRepository), runtime };
|
||||
}
|
||||
|
||||
describe('TripWarningsController', () => {
|
||||
|
||||
@@ -16,7 +16,7 @@ vi.mock('../../../src/nest/plugins/kill-switch', () => ({ pluginsEnabled }));
|
||||
|
||||
import { ViewContributionsController } from '../../../src/nest/plugins/contributions/view-contributions.controller';
|
||||
import type { PluginHooks } from '../../../src/nest/plugins/plugin-hooks.service';
|
||||
import type { DatabaseService } from '../../../src/nest/database/database.service';
|
||||
import type { TripsRepository } from '../../../src/db/repositories/Trips.repository';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const req = (id?: number) => ({ user: id === undefined ? undefined : { id } }) as any;
|
||||
@@ -25,7 +25,7 @@ function controller(invoke: (id: string) => unknown, providers = ['p1']) {
|
||||
providersOf: vi.fn(() => providers),
|
||||
tableContributions: vi.fn(async (id: string) => invoke(id)),
|
||||
} as unknown as PluginHooks;
|
||||
return { c: new ViewContributionsController(runtime, { canAccessTrip } as unknown as DatabaseService), runtime };
|
||||
return { c: new ViewContributionsController(runtime, { findAccessible: canAccessTrip } as unknown as TripsRepository), runtime };
|
||||
}
|
||||
const col = (over: Record<string, unknown> = {}) => ({ kind: 'column', entityId: 1, id: 'c1', label: 'X', ...over });
|
||||
const act = (over: Record<string, unknown> = {}) => ({ kind: 'action', entityId: 1, id: 'a1', label: 'Go', target: { kind: 'frame', sub: '/ui' }, ...over });
|
||||
|
||||
Reference in New Issue
Block a user