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'}
/>