From 72fd2283e0eb1aa39e23543f404c38cd56032cf4 Mon Sep 17 00:00:00 2001 From: Ronni Skansing Date: Thu, 12 Feb 2026 23:07:32 +0100 Subject: [PATCH] restrict available campaign actions in different context Signed-off-by: Ronni Skansing --- frontend/src/lib/components/FileField.svelte | 4 +- .../src/routes/campaign/[id]/+page.svelte | 206 ++++++++++++++---- 2 files changed, 166 insertions(+), 44 deletions(-) diff --git a/frontend/src/lib/components/FileField.svelte b/frontend/src/lib/components/FileField.svelte index 977136d..e085132 100644 --- a/frontend/src/lib/components/FileField.svelte +++ b/frontend/src/lib/components/FileField.svelte @@ -14,6 +14,7 @@ export let multiple = false; export let name = 'files'; export let accept = '*'; + export let disabled = false; // bind to parent form element, if there is one let parentForm = null; // listen to parent form reset event, if one exists @@ -69,6 +70,7 @@ {multiple} {required} {placeholder} - class="border-solid border-2 border-gray-300 dark:border-gray-600 py-2 px-2 rounded-md file:px-4 file:py-2 file:text-white file:cursor-pointer file:text-sm file:font-semibold bg-white dark:bg-gray-700 file:bg-cta-blue hover:cursor-pointer file:hover:bg-blue-600 dark:file:bg-indigo-600 dark:file:hover:bg-indigo-700 file:border-hidden file:rounded-md text-gray-900 dark:text-white transition-colors duration-200" + {disabled} + class="border-solid border-2 border-gray-300 dark:border-gray-600 py-2 px-2 rounded-md file:px-4 file:py-2 file:text-white file:cursor-pointer file:text-sm file:font-semibold bg-white dark:bg-gray-700 file:bg-cta-blue hover:cursor-pointer file:hover:bg-blue-600 dark:file:bg-indigo-600 dark:file:hover:bg-indigo-700 file:border-hidden file:rounded-md text-gray-900 dark:text-white transition-colors duration-200 disabled:opacity-50 disabled:cursor-not-allowed file:disabled:cursor-not-allowed" /> diff --git a/frontend/src/routes/campaign/[id]/+page.svelte b/frontend/src/routes/campaign/[id]/+page.svelte index 202e58c..68e7d06 100644 --- a/frontend/src/routes/campaign/[id]/+page.svelte +++ b/frontend/src/routes/campaign/[id]/+page.svelte @@ -868,7 +868,35 @@ } }; + // check if user is in the correct context for campaign actions + const isContextMismatch = () => { + const context = appStateService.getContext(); + + // if campaign is global (no companyID) + if (!campaign.companyID) { + // user must be in global/shared context + return context.current !== AppStateService.CONTEXT.SHARED; + } + + // if campaign belongs to a company + // user must be in that specific company context + return ( + context.current !== AppStateService.CONTEXT.COMPANY || + context.companyID !== campaign.companyID + ); + }; + const campaignUpdateDisabledAndTitle = (campaign) => { + // check for context mismatch first + if (isContextMismatch()) { + return { + disabled: true, + title: campaign.companyID + ? 'Switch to company view to perform this action' + : 'Switch to global view to perform this action' + }; + } + const c = globalButtonDisabledAttributes(campaign, contextCompanyID); if (c?.disabled) { return c; @@ -1614,27 +1642,52 @@ Manage

- {#if !campaignUpdateDisabledAndTitle(campaign).disabled} - +
+ Update - {/if} - +
- Close - - + Close + +
+
- Anonymize - + + Anonymize + +
@@ -1658,7 +1711,19 @@

Import

- Reported CSV +
+ Reported CSV +
@@ -1755,12 +1820,16 @@ openDeleteEventAlert(event)} - disabled={!!campaign.closedAt || !!campaign.anonymizedAt} - title={campaign.closedAt - ? 'Cannot delete events from closed campaign' - : campaign.anonymizedAt - ? 'Cannot delete events from anonymized campaign' - : 'Delete event'} + disabled={!!campaign.closedAt || !!campaign.anonymizedAt || isContextMismatch()} + title={isContextMismatch() + ? campaign.companyID + ? 'Switch to company view to perform this action' + : 'Switch to global view to perform this action' + : campaign.closedAt + ? 'Cannot delete events from closed campaign' + : campaign.anonymizedAt + ? 'Cannot delete events from anonymized campaign' + : 'Delete event'} /> @@ -1846,24 +1915,51 @@ showSendMessageModal(recp.id, recp.recipient)} - disabled={!!campaign.closedAt || recp.cancelledAt} + disabled={!!campaign.closedAt || recp.cancelledAt || isContextMismatch()} /> onClickCopyURL(recp.id)} /> onClickCopyEmailContent(recp.id)} /> @@ -1871,14 +1967,34 @@ onClickSetEmailSent(recp.id, recp.recipient)} - disabled={!!campaign.closedAt || recp.cancelledAt} + disabled={!!campaign.closedAt || recp.cancelledAt || isContextMismatch()} /> {/if} onClickPreviewEmail(recp.id)} /> @@ -1943,12 +2059,16 @@ openDeleteEventAlert(event)} - disabled={!!campaign.closedAt || !!campaign.anonymizedAt} - title={campaign.closedAt - ? 'Cannot delete events from closed campaign' - : campaign.anonymizedAt - ? 'Cannot delete events from anonymized campaign' - : 'Delete event'} + disabled={!!campaign.closedAt || !!campaign.anonymizedAt || isContextMismatch()} + title={isContextMismatch() + ? campaign.companyID + ? 'Switch to company view to perform this action' + : 'Switch to global view to perform this action' + : campaign.closedAt + ? 'Cannot delete events from closed campaign' + : campaign.anonymizedAt + ? 'Cannot delete events from anonymized campaign' + : 'Delete event'} />