wip league admin tools

This commit is contained in:
2025-12-28 12:04:12 +01:00
parent 5dc8c2399c
commit 6edf12fda8
401 changed files with 15365 additions and 6047 deletions

View File

@@ -0,0 +1,67 @@
import { describe, expect, it, vi } from 'vitest';
import { requestContextMiddleware } from '@adapters/http/RequestContext';
import { Result } from '@core/shared/application/Result';
import { getActorFromRequestContext } from './getActorFromRequestContext';
import { requireLeagueAdminOrOwner } from '../league/LeagueAuthorization';
async function withRequestContext<T>(req: Record<string, unknown>, fn: () => Promise<T>): Promise<T> {
const res = {};
return await new Promise<T>((resolve, reject) => {
requestContextMiddleware(req as any, res as any, () => {
fn().then(resolve, reject);
});
});
}
describe('ActorFromSession', () => {
it('derives actor from authenticated session (request.user), not request payload', async () => {
const req: any = {
user: { userId: 'driver-from-session' },
body: { driverId: 'driver-from-body' },
};
await withRequestContext(req, async () => {
const actor = getActorFromRequestContext();
expect(actor).toEqual({ userId: 'driver-from-session', driverId: 'driver-from-session' });
});
});
it('permission helper invokes league admin check using session-derived actor (ignores payload)', async () => {
const getLeagueAdminPermissionsUseCase = {
execute: vi.fn(async () => Result.ok(undefined)),
};
const req: any = {
user: { userId: 'driver-from-session' },
body: { performerDriverId: 'driver-from-body' },
};
await withRequestContext(req, async () => {
await expect(
requireLeagueAdminOrOwner('league-1', getLeagueAdminPermissionsUseCase as any),
).resolves.toBeUndefined();
});
expect(getLeagueAdminPermissionsUseCase.execute).toHaveBeenCalledWith({
leagueId: 'league-1',
performerDriverId: 'driver-from-session',
});
});
it('permission helper rejects when league admin check fails', async () => {
const getLeagueAdminPermissionsUseCase = {
execute: vi.fn(async () =>
Result.err({ code: 'USER_NOT_MEMBER', details: { message: 'nope' } } as any),
),
};
const req: any = { user: { userId: 'driver-from-session' } };
await withRequestContext(req, async () => {
await expect(
requireLeagueAdminOrOwner('league-1', getLeagueAdminPermissionsUseCase as any),
).rejects.toThrow('Forbidden');
});
});
});

View File

@@ -0,0 +1,25 @@
import { getHttpRequestContext } from '@adapters/http/RequestContext';
export type Actor = {
userId: string;
driverId: string;
};
type AuthenticatedRequest = {
user?: { userId: string };
};
export function getActorFromRequestContext(): Actor {
const ctx = getHttpRequestContext();
const req = ctx.req as unknown as AuthenticatedRequest;
const userId = req.user?.userId;
if (!userId) {
throw new Error('Unauthorized');
}
// Current canonical mapping:
// - The authenticated session identity is `userId`.
// - In the current system, that `userId` is also treated as the performer `driverId`.
return { userId, driverId: userId };
}