Skip to content

Commit d9ccbb2

Browse files
fhennigclaude
andauthored
fix(website): show 403 error instead of 404 when editing unowned collection (#1323)
resolves #1160 ## Summary - Visiting `collections/<id>/edit` for a collection you don't own previously returned a generic 404 redirect - Now returns a proper 403 HTTP status and renders a friendly "Not authorized" error page --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent d99b569 commit d9ccbb2

2 files changed

Lines changed: 27 additions & 5 deletions

File tree

website/src/pages/collections/[pathFragment]/[id]/edit.astro

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import { getDashboardsConfig, getBackendHost } from '../../../../config';
66
import { defaultBreadcrumbs } from '../../../../layouts/Breadcrumbs';
77
import ContaineredPageLayout from '../../../../layouts/ContaineredPage/ContaineredPageLayout.astro';
88
import { getInstanceLogger } from '../../../../logger.ts';
9+
import { PageContainer } from '../../../../styles/containers/PageContainer';
10+
import { PageHeadline } from '../../../../styles/containers/PageHeadline';
911
import { organismConfig, organismFromPathFragment } from '../../../../types/Organism';
1012
import { Page } from '../../../../types/pages';
1113
import { getErrorLogMessage } from '../../../../util/getErrorLogMessage.ts';
@@ -28,11 +30,13 @@ const currentUserId = Astro.locals.gsUserId;
2830
const config = getDashboardsConfig();
2931
3032
let collection;
33+
let isNotOwner = false;
3134
if (currentUserId !== undefined) {
3235
try {
3336
collection = await new BackendService(getBackendHost()).getCollection({ id });
3437
if (currentUserId !== collection.ownedBy) {
35-
return Astro.redirect('/404');
38+
isNotOwner = true;
39+
Astro.response.status = 403;
3640
}
3741
} catch (error) {
3842
if (error instanceof BackendError && error.status === 404) {
@@ -57,7 +61,14 @@ const collectionTitle = collection !== undefined ? `#${id} ${collection.name}` :
5761
]}
5862
>
5963
{
60-
currentUserId !== undefined ? (
64+
currentUserId === undefined ? (
65+
<NotLoggedIn />
66+
) : isNotOwner ? (
67+
<PageContainer>
68+
<PageHeadline>Not authorized</PageHeadline>
69+
<div>You do not have permission to edit this collection.</div>
70+
</PageContainer>
71+
) : (
6172
<CollectionEdit
6273
client:only='react'
6374
organism={organism}
@@ -68,8 +79,6 @@ const collectionTitle = collection !== undefined ? `#${id} ${collection.name}` :
6879
collection!
6980
}
7081
/>
71-
) : (
72-
<NotLoggedIn />
7382
)
7483
}
7584
</ContaineredPageLayout>

website/tests/collections/collectionForm.spec.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { expect } from '@playwright/test';
22

33
import { test } from '../e2e.fixture.ts';
4-
import { E2E_GITHUB_ID } from '../helpers/auth.ts';
4+
import { E2E_GITHUB_ID, setupAuthCookie } from '../helpers/auth.ts';
55
import { createCollection, deleteCollection, syncUser } from '../helpers/backendClient.ts';
66

77
const ORGANISM = 'covid';
@@ -159,6 +159,19 @@ test.describe('Edit collection page', () => {
159159
await expect(authenticatedCollectionFormPage.collectionDescriptionTextarea()).toHaveValue('');
160160
});
161161

162+
test('shows "Not authorized" with 403 when editing a collection owned by another user', async ({
163+
page,
164+
request,
165+
}) => {
166+
const otherUserId = await syncUser(request, 'e2e-other-99999');
167+
await setupAuthCookie(page, 'e2e-other', otherUserId);
168+
169+
const response = await page.goto(`/collections/${ORGANISM}/${getCollectionId()}/edit`);
170+
171+
expect(response?.status()).toBe(403);
172+
await expect(page.getByRole('heading', { name: 'Not authorized' })).toBeVisible();
173+
});
174+
162175
test('"Delete collection" shows confirmation dialog; Cancel dismisses it', async ({
163176
authenticatedCollectionFormPage,
164177
}) => {

0 commit comments

Comments
 (0)