diff --git a/apps/client/src/common/utils/__tests__/urlPresets.test.ts b/apps/client/src/common/utils/__tests__/urlPresets.test.ts index 49a3b64d7..d00bc9f36 100644 --- a/apps/client/src/common/utils/__tests__/urlPresets.test.ts +++ b/apps/client/src/common/utils/__tests__/urlPresets.test.ts @@ -83,7 +83,7 @@ describe('getRouteFromPreset()', () => { }); }); - describe('cuesheet preset options', () => { + describe('cuesheet presets', () => { const cuesheetPreset: URLPreset[] = [ { enabled: true, @@ -96,6 +96,22 @@ describe('getRouteFromPreset()', () => { }, }, ]; + const cuesheetPresetWithoutOptions: URLPreset[] = [ + { + enabled: true, + alias: 'cuesheet-basic', + target: OntimeView.Cuesheet, + search: '', + }, + ]; + const cuesheetPresetWithNavLock: URLPreset[] = [ + { + enabled: true, + alias: 'cuesheet-locked', + target: OntimeView.Cuesheet, + search: 'n=1', + }, + ]; it('keeps cuesheet aliases masked when permissions are stored in preset options', () => { const location = resolvePath('/cuesheet-4685d6'); @@ -106,6 +122,16 @@ describe('getRouteFromPreset()', () => { const location = resolvePath('/cuesheet-4685d6?n=1&token=123'); expect(getRouteFromPreset(location, cuesheetPreset)).toBe('preset/cuesheet-4685d6?n=1&token=123'); }); + + it('keeps cuesheet aliases masked even when preset options are absent', () => { + const location = resolvePath('/cuesheet-basic'); + expect(getRouteFromPreset(location, cuesheetPresetWithoutOptions)).toBe('preset/cuesheet-basic'); + }); + + it('applies navigation lock from preset search params when alias is opened', () => { + const location = resolvePath('/cuesheet-locked'); + expect(getRouteFromPreset(location, cuesheetPresetWithNavLock)).toBe('preset/cuesheet-locked?n=1'); + }); }); }); diff --git a/apps/client/src/common/utils/urlPresets.ts b/apps/client/src/common/utils/urlPresets.ts index 2642ed9bc..4f4207e5f 100644 --- a/apps/client/src/common/utils/urlPresets.ts +++ b/apps/client/src/common/utils/urlPresets.ts @@ -39,11 +39,13 @@ export function getRouteFromPreset(location: Path, urlPresets: URLPreset[]): str // NOTE: verify that this resolves correctly in cloud const currentPath = `${location.pathname}${location.search}`.substring(1); const currentURL = getCurrentPath(location); - const token = new URLSearchParams(location.search).get('token'); - const isLocked = location.search.includes('n=1'); + const locationParams = new URLSearchParams(location.search); + const token = locationParams.get('token'); for (const preset of urlPresets) { if (!preset.enabled) continue; + const presetParams = new URLSearchParams(preset.search); + const isLocked = locationParams.get('n') === '1' || presetParams.get('n') === '1'; /** * If the page is a known alias it would be like * /preset/{alias} <- locked to a preset @@ -129,15 +131,15 @@ function generateMaskedPathFromPreset(alias: string, locked: boolean, token: str const path = `preset/${alias}`; const search = searchParams.toString(); - return search ? `${path}?${search}` : path; + if (!search) { + return path; + } + + return `${path}?${search}`; } function shouldMaskPresetPath(preset: URLPreset): boolean { - if (preset.target !== OntimeView.Cuesheet) { - return false; - } - - return Boolean(preset.options?.read || preset.options?.write); + return preset.target === OntimeView.Cuesheet; } /** diff --git a/apps/server/src/api-data/url-presets/urlPresets.router.ts b/apps/server/src/api-data/url-presets/urlPresets.router.ts index f9518bee5..6a61e3e22 100644 --- a/apps/server/src/api-data/url-presets/urlPresets.router.ts +++ b/apps/server/src/api-data/url-presets/urlPresets.router.ts @@ -43,18 +43,24 @@ router.post('/', validateNewPreset, async (req: Request, res: Response) => { try { const alias = req.params.alias; + const currentPresets = getDataProvider().getUrlPresets(); + const existingPreset = currentPresets.find((preset) => preset.alias === alias); + if (!existingPreset) { + throw new Error(`Preset with alias ${alias} does not exist.`); + } + const updatedPreset: URLPreset = { enabled: req.body.enabled, alias: req.body.alias, target: req.body.target, search: req.body.search, + options: req.body.options ?? existingPreset.options, }; if (alias !== updatedPreset.alias) { throw new Error('Changing alias is not permitted'); } - const currentPresets = getDataProvider().getUrlPresets(); const newPresets = currentPresets.map((preset) => (preset.alias === alias ? updatedPreset : preset)); // Update the URL presets in the data provider diff --git a/packages/types/src/definitions/core/UrlPreset.type.ts b/packages/types/src/definitions/core/UrlPreset.type.ts index 326e9f82b..92d9d9337 100644 --- a/packages/types/src/definitions/core/UrlPreset.type.ts +++ b/packages/types/src/definitions/core/UrlPreset.type.ts @@ -28,9 +28,9 @@ type CuesheetUrlPreset = { enabled: boolean; alias: string; search: string; - options: { - read: string; - write: string; + options?: { + read?: string; + write?: string; }; };