-
Notifications
You must be signed in to change notification settings - Fork 227
Fix: resource blocks console #2949
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,3 @@ | ||
| <!-- Loads AGENTS.md into AI assistant context --> | ||
|
|
||
| @AGENTS.md |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,6 +3,7 @@ import { get } from 'svelte/store'; | |
| import { sdk } from '$lib/stores/sdk'; | ||
| import { projectRegion } from '$routes/(console)/project-[region]-[project]/store'; | ||
| import type { Models } from '@appwrite.io/console'; | ||
| import { error } from '@sveltejs/kit'; | ||
|
|
||
| /** | ||
| * Returns the current project ID. | ||
|
|
@@ -45,5 +46,50 @@ export function getProjectEndpoint(): string { | |
| } | ||
|
|
||
| export function isProjectBlocked(project: Models.Project | null | undefined): boolean { | ||
| return project?.status !== 'paused' && !!project?.blocks?.length; | ||
| const hasGlobalProjectBlock = (project?.blocks ?? []).some((block) => { | ||
| const type = block.resourceType?.trim().toLowerCase(); | ||
| const id = block.resourceId?.trim(); | ||
|
|
||
| // Global project block: | ||
| // - legacy: both type and id empty | ||
| // - new: resourceType === 'projects' with no specific resourceId | ||
| const isLegacyGlobal = !type && !id; | ||
| const isProjectsGlobal = type === 'projects' && !id; | ||
|
|
||
| return isLegacyGlobal || isProjectsGlobal; | ||
| }); | ||
|
|
||
| return project?.status !== 'paused' && hasGlobalProjectBlock; | ||
| } | ||
|
|
||
| export function isResourceBlocked( | ||
| project: Models.Project | null | undefined, | ||
| resourceType: string, | ||
| resourceId: string | ||
| ): boolean { | ||
| const normalizedType = resourceType.trim().toLowerCase(); | ||
| const normalizedId = resourceId.trim(); | ||
|
|
||
| return (project?.blocks ?? []).some((block) => { | ||
| const type = block.resourceType?.trim().toLowerCase(); | ||
| const id = block.resourceId?.trim(); | ||
|
|
||
| return type === normalizedType && id === normalizedId; | ||
| }); | ||
| } | ||
|
|
||
| export function guardResourceBlock( | ||
| project: Models.Project | null | undefined, | ||
| resourceType: string | string[], | ||
| resourceId: string | ||
| ) { | ||
| const resourceTypes = Array.isArray(resourceType) ? resourceType : [resourceType]; | ||
| const isBlocked = resourceTypes.some((type) => isResourceBlocked(project, type, resourceId)); | ||
|
|
||
| if (isBlocked) { | ||
| error(403, { | ||
| type: 'general_resource_blocked', | ||
| message: 'This resource page cannot be accessed.' | ||
| }); | ||
| } | ||
| } | ||
|
Comment on lines
+81
to
95
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The resource type strings passed to Consider centralising these strings in an enum or const object alongside export const BlockResourceType = {
TEAMS: 'teams',
USERS: 'users',
DATABASES: 'databases',
FUNCTIONS: 'functions',
BUCKETS: 'buckets',
FILES: 'files',
MESSAGES: 'messages',
PROVIDERS: 'providers',
TOPICS: 'topics',
SITES: 'sites',
TABLES: 'tables',
COLLECTIONS: 'collections',
} as const;This makes them easy to audit against the API contract and prevents typos across the 11 call-sites. |
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isResourceBlockedskips the paused-project guardisProjectBlockedexplicitly returnsfalsefor paused projects (project?.status !== 'paused') so that the "project paused" overlay is shown instead of the blocked-project overlay.isResourceBlockedhas no equivalent guard, so a paused project that also carries a resource-level block will trigger a 403 error page instead of the paused overlay when a user navigates to that resource.If paused projects should never surface resource-level 403s (and let the parent layout's paused UI take over), consider mirroring the status guard: