From f2d9203ea22a52c6d64efa67fd994eab3784f621 Mon Sep 17 00:00:00 2001 From: Joshen Lim Date: Wed, 27 Nov 2024 23:11:19 +0800 Subject: [PATCH] Prevent non owners from editing shared snippets (#30692) * Prevent non owners from editing shared snippets * Add guard against saving snippet which is shared + has folder id * FIX --- .../interfaces/SQLEditor/MonacoEditor.tsx | 120 ++++++++++-------- apps/studio/state/sql-editor-v2.ts | 47 ++++--- 2 files changed, 98 insertions(+), 69 deletions(-) diff --git a/apps/studio/components/interfaces/SQLEditor/MonacoEditor.tsx b/apps/studio/components/interfaces/SQLEditor/MonacoEditor.tsx index b0571a93f66..08c0dfd01ff 100644 --- a/apps/studio/components/interfaces/SQLEditor/MonacoEditor.tsx +++ b/apps/studio/components/interfaces/SQLEditor/MonacoEditor.tsx @@ -8,13 +8,14 @@ import { useLocalStorageQuery } from 'hooks/misc/useLocalStorage' import { useSelectedProject } from 'hooks/misc/useSelectedProject' import { LOCAL_STORAGE_KEYS } from 'lib/constants' import { useProfile } from 'lib/profile' +import { useAppStateSnapshot } from 'state/app-state' import { useSqlEditorV2StateSnapshot } from 'state/sql-editor-v2' import { cn } from 'ui' +import { Admonition } from 'ui-patterns' +import { useIsAssistantV2Enabled } from '../App/FeaturePreview/FeaturePreviewContext' import { untitledSnippetTitle } from './SQLEditor.constants' import type { IStandaloneCodeEditor } from './SQLEditor.types' import { createSqlSnippetSkeletonV2 } from './SQLEditor.utils' -import { useIsAssistantV2Enabled } from '../App/FeaturePreview/FeaturePreviewContext' -import { useAppStateSnapshot } from 'state/app-state' export type MonacoEditorProps = { id: string @@ -50,6 +51,8 @@ const MonacoEditor = ({ ) const snippet = snapV2.snippets[id] + const disableEdit = + snippet?.snippet.visibility === 'project' && snippet?.snippet.owner_id !== profile?.id const executeQueryRef = useRef(executeQuery) executeQueryRef.current = executeQuery @@ -152,57 +155,68 @@ const MonacoEditor = ({ }, []) return ( - + <> + {disableEdit && ( + + )} + + ) } diff --git a/apps/studio/state/sql-editor-v2.ts b/apps/studio/state/sql-editor-v2.ts index 8e8cfad29fe..6e6b7af792a 100644 --- a/apps/studio/state/sql-editor-v2.ts +++ b/apps/studio/state/sql-editor-v2.ts @@ -462,22 +462,37 @@ if (typeof window !== 'undefined') { const folder = state.folders[id] if (snippet) { - debouncedUpdateSnippet(id, snippet.projectRef, { - id, - type: 'sql', - name: snippet.snippet.name ?? 'Untitled', - description: snippet.snippet.description ?? '', - visibility: snippet.snippet.visibility ?? 'user', - project_id: snippet.snippet.project_id ?? 0, - owner_id: snippet.snippet.owner_id, - folder_id: snippet.snippet.folder_id, - content: { - ...snippet.snippet.content, - content_id: id, - favorite: snippet.snippet.favorite, - }, - }) - sqlEditorState.needsSaving.delete(id) + const { + name, + description, + visibility, + project_id, + owner_id, + folder_id, + content, + favorite, + } = snippet.snippet + + if (visibility === 'project' && !!folder_id) { + toast.error('Shared snippet cannot be within a folder') + } else { + debouncedUpdateSnippet(id, snippet.projectRef, { + id, + type: 'sql', + name: name ?? 'Untitled', + description: description ?? '', + visibility: visibility ?? 'user', + project_id: project_id ?? 0, + owner_id: owner_id, + folder_id: folder_id, + content: { + ...content, + content_id: id, + favorite: favorite, + }, + }) + sqlEditorState.needsSaving.delete(id) + } } else if (folder) { upsertFolder(id, folder.projectRef, folder.folder.name) sqlEditorState.needsSaving.delete(id)