99 lines
3.5 KiB
TypeScript
99 lines
3.5 KiB
TypeScript
import { routes, routeMatchers } from '../../../apps/website/lib/routing/RouteConfig';
|
|
|
|
export type RouteAccess = 'public' | 'auth' | 'admin' | 'sponsor';
|
|
export type RouteParams = Record<string, string>;
|
|
|
|
export interface WebsiteRouteDefinition {
|
|
pathTemplate: string;
|
|
params?: RouteParams;
|
|
access: RouteAccess;
|
|
expectedPathTemplate?: string;
|
|
allowNotFound?: boolean;
|
|
}
|
|
|
|
export class WebsiteRouteManager {
|
|
private static readonly IDs = {
|
|
LEAGUE: 'league-1',
|
|
DRIVER: 'driver-1',
|
|
TEAM: 'team-1',
|
|
RACE: 'race-1',
|
|
PROTEST: 'protest-1',
|
|
} as const;
|
|
|
|
public resolvePathTemplate(pathTemplate: string, params: RouteParams = {}): string {
|
|
return pathTemplate.replace(/\[([^\]]+)\]/g, (_match, key) => {
|
|
const replacement = params[key];
|
|
if (!replacement) {
|
|
throw new Error(`Missing route param "${key}" for template "${pathTemplate}"`);
|
|
}
|
|
return replacement;
|
|
});
|
|
}
|
|
|
|
public getWebsiteRouteInventory(): WebsiteRouteDefinition[] {
|
|
const result: WebsiteRouteDefinition[] = [];
|
|
|
|
const pushRoute = (pathTemplate: string, params?: RouteParams) => {
|
|
result.push({
|
|
pathTemplate,
|
|
...(params ? { params } : {}),
|
|
access: this.getAccessLevel(pathTemplate),
|
|
});
|
|
};
|
|
|
|
const processGroup = (groupRoutes: Record<string, string | ((id: string) => string)>) => {
|
|
Object.values(groupRoutes).forEach((value) => {
|
|
if (typeof value === 'function') {
|
|
const template = value(WebsiteRouteManager.IDs.LEAGUE);
|
|
pushRoute(template, { id: WebsiteRouteManager.IDs.LEAGUE });
|
|
return;
|
|
}
|
|
|
|
pushRoute(value);
|
|
});
|
|
};
|
|
|
|
processGroup(routes.auth);
|
|
processGroup(routes.public);
|
|
processGroup(routes.protected);
|
|
processGroup(routes.sponsor);
|
|
processGroup(routes.admin);
|
|
processGroup(routes.league);
|
|
processGroup(routes.race);
|
|
processGroup(routes.team);
|
|
processGroup(routes.driver);
|
|
processGroup(routes.error);
|
|
|
|
return result.sort((a, b) => a.pathTemplate.localeCompare(b.pathTemplate));
|
|
}
|
|
|
|
public getParamEdgeCases(): WebsiteRouteDefinition[] {
|
|
return [
|
|
{ pathTemplate: '/races/[id]', params: { id: 'does-not-exist' }, access: 'public', allowNotFound: true },
|
|
{ pathTemplate: '/leagues/[id]', params: { id: 'does-not-exist' }, access: 'public', allowNotFound: true },
|
|
];
|
|
}
|
|
|
|
public getFaultInjectionRoutes(): WebsiteRouteDefinition[] {
|
|
return [
|
|
{ pathTemplate: '/leagues/[id]', params: { id: WebsiteRouteManager.IDs.LEAGUE }, access: 'public' },
|
|
{ pathTemplate: '/leagues/[id]/schedule/admin', params: { id: WebsiteRouteManager.IDs.LEAGUE }, access: 'admin' },
|
|
{ pathTemplate: '/sponsor/dashboard', access: 'sponsor' },
|
|
{ pathTemplate: '/races/[id]', params: { id: WebsiteRouteManager.IDs.RACE }, access: 'public' },
|
|
];
|
|
}
|
|
|
|
public getAuthDriftRoutes(): WebsiteRouteDefinition[] {
|
|
return [{ pathTemplate: '/sponsor/dashboard', access: 'sponsor' }];
|
|
}
|
|
|
|
public getAccessLevel(pathTemplate: string): RouteAccess {
|
|
// NOTE: `routeMatchers.isInGroup(path, 'public')` is prefix-based and will treat everything
|
|
// as public because the home route is `/`. Use `isPublic()` for correct classification.
|
|
if (routeMatchers.isInGroup(pathTemplate, 'admin')) return 'admin';
|
|
if (routeMatchers.isInGroup(pathTemplate, 'sponsor')) return 'sponsor';
|
|
if (routeMatchers.isPublic(pathTemplate)) return 'public';
|
|
if (routeMatchers.requiresAuth(pathTemplate)) return 'auth';
|
|
return 'public';
|
|
}
|
|
} |