From 6268e327b915e26b694b428b77e6171ed14527b2 Mon Sep 17 00:00:00 2001 From: Carlos Valente Date: Thu, 19 Feb 2026 16:01:55 +0100 Subject: [PATCH] refactor: mask cuesheet presets --- .../common/utils/__tests__/urlPresets.test.ts | 25 +++++++++++++++++ apps/client/src/common/utils/urlPresets.ts | 28 ++++++++++++++++++- e2e/tests/features/206-url-preset.spec.ts | 2 ++ 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/apps/client/src/common/utils/__tests__/urlPresets.test.ts b/apps/client/src/common/utils/__tests__/urlPresets.test.ts index 52835ed20..49a3b64d7 100644 --- a/apps/client/src/common/utils/__tests__/urlPresets.test.ts +++ b/apps/client/src/common/utils/__tests__/urlPresets.test.ts @@ -82,6 +82,31 @@ describe('getRouteFromPreset()', () => { expect(getRouteFromPreset(location, presets)).toBe('timer?user=guest&alias=demopage&n=1&token=123'); }); }); + + describe('cuesheet preset options', () => { + const cuesheetPreset: URLPreset[] = [ + { + enabled: true, + alias: 'cuesheet-4685d6', + target: OntimeView.Cuesheet, + search: '', + options: { + read: 'full', + write: '-', + }, + }, + ]; + + it('keeps cuesheet aliases masked when permissions are stored in preset options', () => { + const location = resolvePath('/cuesheet-4685d6'); + expect(getRouteFromPreset(location, cuesheetPreset)).toBe('preset/cuesheet-4685d6'); + }); + + it('preserves feature params when redirecting masked cuesheet aliases', () => { + const location = resolvePath('/cuesheet-4685d6?n=1&token=123'); + expect(getRouteFromPreset(location, cuesheetPreset)).toBe('preset/cuesheet-4685d6?n=1&token=123'); + }); + }); }); describe('generatePathFromPreset()', () => { diff --git a/apps/client/src/common/utils/urlPresets.ts b/apps/client/src/common/utils/urlPresets.ts index 95dbce7b0..2642ed9bc 100644 --- a/apps/client/src/common/utils/urlPresets.ts +++ b/apps/client/src/common/utils/urlPresets.ts @@ -53,7 +53,9 @@ export function getRouteFromPreset(location: Path, urlPresets: URLPreset[]): str * we need to compare the saved preset to the current path to see if we need to redirect */ if (preset.alias === currentURL || preset.target === currentURL) { - const newPath = generatePathFromPreset(preset.target, preset.search, preset.alias, isLocked, token); + const newPath = shouldMaskPresetPath(preset) + ? generateMaskedPathFromPreset(preset.alias, isLocked, token) + : generatePathFromPreset(preset.target, preset.search, preset.alias, isLocked, token); /** * if the current path is equivalent to the new path, we return null * this means we will not redirect @@ -114,6 +116,30 @@ export function generatePathFromPreset( return `${path.pathname}?${searchParams}`.substring(1); } +function generateMaskedPathFromPreset(alias: string, locked: boolean, token: string | null): string { + const searchParams = new URLSearchParams(); + + if (locked) { + searchParams.set('n', '1'); + } + + if (token) { + searchParams.set('token', token); + } + + const path = `preset/${alias}`; + const search = searchParams.toString(); + return search ? `${path}?${search}` : path; +} + +function shouldMaskPresetPath(preset: URLPreset): boolean { + if (preset.target !== OntimeView.Cuesheet) { + return false; + } + + return Boolean(preset.options?.read || preset.options?.write); +} + /** * Utility checks if two paths are equivalent * For preset paths, only compares the path (since params are stored in session) diff --git a/e2e/tests/features/206-url-preset.spec.ts b/e2e/tests/features/206-url-preset.spec.ts index ad7b45209..6a72bde69 100644 --- a/e2e/tests/features/206-url-preset.spec.ts +++ b/e2e/tests/features/206-url-preset.spec.ts @@ -220,6 +220,8 @@ test.describe('Sharing from cuesheet', () => { // Verify that the title is visible and editable await expect(page.getByTestId('cuesheet-event').getByRole('cell', { name: 'title' })).toBeVisible(); + await page.getByTestId('cuesheet-event').getByTestId('cuesheet-editor-title').click(); + await expect(page.getByTestId('cuesheet-event').getByTestId('cuesheet-editor-title').locator('input')).toBeVisible(); // other elements are not there await expect(page.getByRole('cell', { name: 'Duration' })).toBeHidden();