Skip to content

Commit 767a0f6

Browse files
authored
Merge pull request #2949 from appwrite/fix-resource-blocks-console
Fix: resource blocks console
2 parents ff79de3 + 0a89a98 commit 767a0f6

14 files changed

Lines changed: 99 additions & 18 deletions

File tree

AGENTS.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -152,12 +152,12 @@ await sdk.forProject(region, projectId).tablesDB.listTables();
152152

153153
The databases feature unifies multiple database backends behind a polymorph API (`$database/(entity)/helpers/sdk.ts`):
154154

155-
| Type | Entity | Field | Record | Status |
156-
| ------------- | ---------- | --------- | -------- | ------------------------ |
157-
| `tablesdb` | table | column | row | Implemented |
158-
| `documentsdb` | collection | attribute | document | Implemented |
159-
| `vectorsdb` | -- | -- | -- | Not yet implemented |
160-
| `dedicateddb` | table | column | row | Cross-repo (cloud/edge) |
155+
| Type | Entity | Field | Record | Status |
156+
| ------------- | ---------- | --------- | -------- | ----------------------- |
157+
| `tablesdb` | table | column | row | Implemented |
158+
| `documentsdb` | collection | attribute | document | Implemented |
159+
| `vectorsdb` | -- | -- | -- | Not yet implemented |
160+
| `dedicateddb` | table | column | row | Cross-repo (cloud/edge) |
161161

162162
- `useDatabaseSdk()` returns a unified interface regardless of backing type
163163
- `useTerminology()` returns singular/plural names for the current database type

CLAUDE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
<!-- Loads AGENTS.md into AI assistant context -->
2+
23
@AGENTS.md

src/lib/helpers/project.ts

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { get } from 'svelte/store';
33
import { sdk } from '$lib/stores/sdk';
44
import { projectRegion } from '$routes/(console)/project-[region]-[project]/store';
55
import type { Models } from '@appwrite.io/console';
6+
import { error } from '@sveltejs/kit';
67

78
/**
89
* Returns the current project ID.
@@ -45,5 +46,50 @@ export function getProjectEndpoint(): string {
4546
}
4647

4748
export function isProjectBlocked(project: Models.Project | null | undefined): boolean {
48-
return project?.status !== 'paused' && !!project?.blocks?.length;
49+
const hasGlobalProjectBlock = (project?.blocks ?? []).some((block) => {
50+
const type = block.resourceType?.trim().toLowerCase();
51+
const id = block.resourceId?.trim();
52+
53+
// Global project block:
54+
// - legacy: both type and id empty
55+
// - new: resourceType === 'projects' with no specific resourceId
56+
const isLegacyGlobal = !type && !id;
57+
const isProjectsGlobal = type === 'projects' && !id;
58+
59+
return isLegacyGlobal || isProjectsGlobal;
60+
});
61+
62+
return project?.status !== 'paused' && hasGlobalProjectBlock;
63+
}
64+
65+
export function isResourceBlocked(
66+
project: Models.Project | null | undefined,
67+
resourceType: string,
68+
resourceId: string
69+
): boolean {
70+
const normalizedType = resourceType.trim().toLowerCase();
71+
const normalizedId = resourceId.trim();
72+
73+
return (project?.blocks ?? []).some((block) => {
74+
const type = block.resourceType?.trim().toLowerCase();
75+
const id = block.resourceId?.trim();
76+
77+
return type === normalizedType && id === normalizedId;
78+
});
79+
}
80+
81+
export function guardResourceBlock(
82+
project: Models.Project | null | undefined,
83+
resourceType: string | string[],
84+
resourceId: string
85+
) {
86+
const resourceTypes = Array.isArray(resourceType) ? resourceType : [resourceType];
87+
const isBlocked = resourceTypes.some((type) => isResourceBlocked(project, type, resourceId));
88+
89+
if (isBlocked) {
90+
error(403, {
91+
type: 'general_resource_blocked',
92+
message: 'This resource page cannot be accessed.'
93+
});
94+
}
4995
}

src/routes/(console)/project-[region]-[project]/auth/teams/team-[team]/+layout.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,13 @@ import Header from './header.svelte';
33
import { sdk } from '$lib/stores/sdk';
44
import type { LayoutLoad } from './$types';
55
import { Dependencies } from '$lib/constants';
6+
import { guardResourceBlock } from '$lib/helpers/project';
67

7-
export const load: LayoutLoad = async ({ params, depends }) => {
8+
export const load: LayoutLoad = async ({ params, depends, parent }) => {
89
depends(Dependencies.TEAM);
10+
const { project } = await parent();
11+
guardResourceBlock(project, 'teams', params.team);
12+
913
return {
1014
header: Header,
1115
breadcrumbs: Breadcrumbs,

src/routes/(console)/project-[region]-[project]/auth/user-[user]/+layout.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@ import Breadcrumbs from './breadcrumbs.svelte';
33
import Header from './header.svelte';
44
import { sdk } from '$lib/stores/sdk';
55
import { Dependencies } from '$lib/constants';
6+
import { guardResourceBlock } from '$lib/helpers/project';
67

7-
export const load: LayoutLoad = async ({ params, depends }) => {
8+
export const load: LayoutLoad = async ({ params, depends, parent }) => {
89
depends(Dependencies.USER);
10+
const { project } = await parent();
11+
guardResourceBlock(project, 'users', params.user);
912

1013
const [user, userFactors] = await Promise.all([
1114
sdk.forProject(params.region, params.project).users.get({ userId: params.user }),

src/routes/(console)/project-[region]-[project]/databases/database-[database]/+layout.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@ import type { LayoutLoad } from './$types';
44
import Breadcrumbs from './breadcrumbs.svelte';
55
import Header from './header.svelte';
66
import SubNavigation from './subNavigation.svelte';
7+
import { guardResourceBlock } from '$lib/helpers/project';
78

8-
export const load: LayoutLoad = async ({ params, depends }) => {
9+
export const load: LayoutLoad = async ({ params, depends, parent }) => {
910
depends(Dependencies.DATABASE);
11+
const { project } = await parent();
12+
guardResourceBlock(project, 'databases', params.database);
1013

1114
const database = await sdk.forProject(params.region, params.project).tablesDB.get({
1215
databaseId: params.database

src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+layout.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ import Header from './header.svelte';
22
import type { LayoutLoad } from './$types';
33
import { Dependencies } from '$lib/constants';
44
import { Breadcrumbs, useDatabaseSdk } from '$database/(entity)';
5+
import { guardResourceBlock } from '$lib/helpers/project';
56

67
export const load: LayoutLoad = async ({ params, depends, parent }) => {
7-
const { database } = await parent();
8+
const { database, project } = await parent();
89
depends(Dependencies.TABLE);
10+
guardResourceBlock(project, ['tables', 'collections'], params.table);
911

1012
const databaseSdk = useDatabaseSdk(params.region, params.project, database.type);
1113

src/routes/(console)/project-[region]-[project]/functions/function-[function]/+layout.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,13 @@ import Breadcrumbs from './breadcrumbs.svelte';
55
import Header from './header.svelte';
66
import { Query } from '@appwrite.io/console';
77
import { RuleType } from '$lib/stores/sdk';
8+
import { guardResourceBlock } from '$lib/helpers/project';
89

9-
export const load: LayoutLoad = async ({ params, depends }) => {
10+
export const load: LayoutLoad = async ({ params, depends, parent }) => {
1011
depends(Dependencies.FUNCTION);
1112
depends(Dependencies.DEPLOYMENTS);
13+
const { project } = await parent();
14+
guardResourceBlock(project, 'functions', params.function);
1215

1316
const func = await sdk
1417
.forProject(params.region, params.project)

src/routes/(console)/project-[region]-[project]/messaging/message-[message]/+layout.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@ import Header from './header.svelte';
44
import { sdk } from '$lib/stores/sdk';
55
import { Dependencies } from '$lib/constants';
66
import type { Models } from '@appwrite.io/console';
7+
import { guardResourceBlock } from '$lib/helpers/project';
78

8-
export const load: LayoutLoad = async ({ params, depends }) => {
9+
export const load: LayoutLoad = async ({ params, depends, parent }) => {
910
depends(Dependencies.MESSAGING_MESSAGE);
11+
const { project } = await parent();
12+
guardResourceBlock(project, 'messages', params.message);
1013

1114
const message = await sdk
1215
.forProject(params.region, params.project)

src/routes/(console)/project-[region]-[project]/messaging/providers/provider-[provider]/+layout.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@ import Breadcrumbs from './breadcrumbs.svelte';
33
import Header from './header.svelte';
44
import { sdk } from '$lib/stores/sdk';
55
import { Dependencies } from '$lib/constants';
6+
import { guardResourceBlock } from '$lib/helpers/project';
67

7-
export const load: LayoutLoad = async ({ params, depends }) => {
8+
export const load: LayoutLoad = async ({ params, depends, parent }) => {
89
depends(Dependencies.MESSAGING_PROVIDER);
10+
const { project } = await parent();
11+
guardResourceBlock(project, 'providers', params.provider);
912

1013
return {
1114
header: Header,

0 commit comments

Comments
 (0)