mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
refactor(routing): namespace board mod queue under board mod routes
Updated the canonical board mod queue URL to /:boardIdentifier/mod/queue and made legacy /:boardIdentifier/modqueue paths resolve to not found. Tightened route helpers so board-scoped mod URLs no longer fall through as generic board pages.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { isFeedRoute, normalizeMultiboardFeedPath } from '../route-utils';
|
||||
import { isBoardModRoute, isFeedRoute, isLegacyBoardModQueueRoute, isModQueueRoute, isValidBoardModRoute, normalizeMultiboardFeedPath } from '../route-utils';
|
||||
|
||||
describe('normalizeMultiboardFeedPath', () => {
|
||||
it('normalizes /all/3 -> /all', () => {
|
||||
@@ -41,4 +41,41 @@ describe('isFeedRoute', () => {
|
||||
expect(isFeedRoute('/subs/catalog/1w')).toBe(false);
|
||||
expect(isFeedRoute('/all/1w/3')).toBe(false);
|
||||
});
|
||||
|
||||
it('returns false for board-scoped mod namespace paths', () => {
|
||||
expect(isFeedRoute('/biz/mod')).toBe(false);
|
||||
expect(isFeedRoute('/biz/mod/queue')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('board mod routes', () => {
|
||||
it('recognizes canonical mod queue routes', () => {
|
||||
expect(isModQueueRoute('/mod/queue')).toBe(true);
|
||||
expect(isModQueueRoute('/biz/mod/queue')).toBe(true);
|
||||
expect(isModQueueRoute('/biz/mod/queue/settings')).toBe(true);
|
||||
});
|
||||
|
||||
it('does not recognize legacy board modqueue routes', () => {
|
||||
expect(isModQueueRoute('/biz/modqueue')).toBe(false);
|
||||
});
|
||||
|
||||
it('recognizes legacy board modqueue routes for rejection', () => {
|
||||
expect(isLegacyBoardModQueueRoute('/biz/modqueue')).toBe(true);
|
||||
expect(isLegacyBoardModQueueRoute('/biz/modqueue/settings')).toBe(true);
|
||||
expect(isLegacyBoardModQueueRoute('/biz/mod/queue')).toBe(false);
|
||||
});
|
||||
|
||||
it('recognizes board mod namespace paths', () => {
|
||||
expect(isBoardModRoute('/biz/mod')).toBe(true);
|
||||
expect(isBoardModRoute('/biz/mod/queue')).toBe(true);
|
||||
expect(isBoardModRoute('/mod/queue')).toBe(false);
|
||||
});
|
||||
|
||||
it('validates allowed board mod routes', () => {
|
||||
expect(isValidBoardModRoute('/biz/mod/queue')).toBe(true);
|
||||
expect(isValidBoardModRoute('/biz/mod/queue/settings')).toBe(true);
|
||||
expect(isValidBoardModRoute('/biz/mod')).toBe(false);
|
||||
expect(isValidBoardModRoute('/biz/mod/log')).toBe(false);
|
||||
expect(isValidBoardModRoute('/biz/modqueue')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -120,7 +120,7 @@ export const isFeedRoute = (pathname: string): boolean => {
|
||||
|
||||
if (normalizedPath.includes('/thread/')) return false;
|
||||
if (normalizedPath.startsWith('/pending/')) return false;
|
||||
if (normalizedPath.includes('/modqueue')) return false;
|
||||
if (isBoardModRoute(normalizedPath) || isModQueueRoute(normalizedPath)) return false;
|
||||
|
||||
const pathWithoutSettings = normalizedPath.replace(/\/settings$/, '');
|
||||
const segments = pathWithoutSettings.split('/').filter(Boolean);
|
||||
@@ -147,9 +147,38 @@ export const isPendingPostRoute = (pathname: string): boolean => {
|
||||
return normalizedPath.startsWith('/pending/');
|
||||
};
|
||||
|
||||
export const isBoardModRoute = (pathname: string): boolean => {
|
||||
const normalizedPath = pathname.replace(/\/$/, '');
|
||||
return /^\/[^/]+\/mod(?:\/.*)?$/.test(normalizedPath);
|
||||
};
|
||||
|
||||
export const isLegacyBoardModQueueRoute = (pathname: string): boolean => {
|
||||
const normalizedPath = pathname.replace(/\/$/, '');
|
||||
return /^\/[^/]+\/modqueue(?:\/settings)?$/.test(normalizedPath);
|
||||
};
|
||||
|
||||
export const isModQueueRoute = (pathname: string): boolean => {
|
||||
const normalizedPath = pathname.replace(/\/settings$/, '');
|
||||
return normalizedPath.includes('/modqueue');
|
||||
const normalizedPath = pathname.replace(/\/settings$/, '').replace(/\/$/, '');
|
||||
return normalizedPath === '/mod/queue' || /^\/[^/]+\/mod\/queue$/.test(normalizedPath);
|
||||
};
|
||||
|
||||
const VALID_MOD_PATHS = ['/mod', '/mod/settings', '/mod/catalog', '/mod/catalog/settings', '/mod/queue', '/mod/queue/settings'];
|
||||
const VALID_BOARD_MOD_SUBPATHS = ['queue', 'queue/settings'];
|
||||
|
||||
export const isValidModRoute = (pathname: string): boolean => {
|
||||
const normalized = pathname.replace(/\/$/, '');
|
||||
return VALID_MOD_PATHS.includes(normalized);
|
||||
};
|
||||
|
||||
export const isValidBoardModRoute = (pathname: string): boolean => {
|
||||
const normalizedPath = pathname.replace(/\/$/, '');
|
||||
const match = normalizedPath.match(/^\/[^/]+\/mod(?:\/(.*))?$/);
|
||||
if (!match) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const subpath = match[1] ?? '';
|
||||
return VALID_BOARD_MOD_SUBPATHS.includes(subpath);
|
||||
};
|
||||
|
||||
/** Page numbers 1–10 for board feed pagination */
|
||||
@@ -228,7 +257,7 @@ export const getFeedCacheKey = (pathname: string): string | null => {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (normalizedPath.includes('/modqueue')) {
|
||||
if (isBoardModRoute(normalizedPath) || isModQueueRoute(normalizedPath)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -82,10 +82,11 @@ export const is5chanLink = (url: string): boolean => {
|
||||
// - /{boardIdentifier} (directory code or address)
|
||||
// - /{boardIdentifier}/thread/{commentCid}
|
||||
// - /{boardIdentifier}/catalog
|
||||
// - /{boardIdentifier}/mod/queue
|
||||
// - /all, /subs, /mod, /pending/{index}
|
||||
return (
|
||||
/^\/p\/[^/]+(\/c\/[^/]+)?$/.test(routePath) ||
|
||||
/^\/[^/]+(\/thread\/[^/]+|\/catalog)?$/.test(routePath) ||
|
||||
/^\/[^/]+(\/thread\/[^/]+|\/catalog|\/mod\/queue)?$/.test(routePath) ||
|
||||
/^\/(all|subscriptions|mod)(\/catalog|\/thread\/[^/]+)?(\/[^/]+)?$/.test(routePath) ||
|
||||
/^\/pending\/[^/]+$/.test(routePath)
|
||||
);
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { isBoardModRoute, isModQueueRoute } from './route-utils';
|
||||
|
||||
export type ParamsType = {
|
||||
accountCommentIndex?: string;
|
||||
boardIdentifier?: string;
|
||||
@@ -17,6 +19,7 @@ export const isBoardView = (pathname: string, params: ParamsType): boolean => {
|
||||
pathname.startsWith('/all') ||
|
||||
pathname.startsWith('/subs') ||
|
||||
pathname.startsWith('/mod') ||
|
||||
isBoardModRoute(pathname) ||
|
||||
pathname.startsWith('/pending') ||
|
||||
pathname === '/' ||
|
||||
pathname.startsWith('/faq') ||
|
||||
@@ -53,7 +56,7 @@ export const isModView = (pathname: string): boolean => {
|
||||
};
|
||||
|
||||
export const isModQueueView = (pathname: string): boolean => {
|
||||
return pathname.includes('/modqueue');
|
||||
return isModQueueRoute(pathname);
|
||||
};
|
||||
|
||||
export const isPendingPostView = (pathname: string, params: ParamsType): boolean => {
|
||||
|
||||
Reference in New Issue
Block a user