Skip to content

Commit e754eb7

Browse files
authored
ENG-1426 Bug in public.upsert_account_in_space, my_permissions_in_space
* eng-1426 bug in public.upsert_account_in_space, still using editor * Do not change value when null update params * typing * use greatest, not aggregate max * least, not greatest! * add group logic to my_permissions_in_space * sqruff * use default rather than escalating permissions
1 parent 0e02a3a commit e754eb7

4 files changed

Lines changed: 202 additions & 88 deletions

File tree

apps/roam/src/utils/syncDgNodesToSupabase.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ const getAllUsers = async (): Promise<AccountLocalInput[]> => {
349349
email: null,
350350
email_trusted: null,
351351
space_editor: null,
352+
permissions: null,
352353
}));
353354
};
354355

packages/database/src/dbTypes.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1542,10 +1542,10 @@ export type Database = {
15421542
create_account_in_space: {
15431543
Args: {
15441544
account_local_id_: string
1545-
editor_?: boolean
15461545
email_?: string
15471546
email_trusted?: boolean
15481547
name_: string
1548+
permissions_?: Database["public"]["Enums"]["SpaceAccessPermissions"]
15491549
space_id_: number
15501550
}
15511551
Returns: number
@@ -1660,6 +1660,10 @@ export type Database = {
16601660
text_content: string
16611661
}[]
16621662
}
1663+
my_permissions_in_space: {
1664+
Args: { space_id_: number }
1665+
Returns: Database["public"]["Enums"]["SpaceAccessPermissions"]
1666+
}
16631667
my_space_ids: {
16641668
Args: {
16651669
access_level?: Database["public"]["Enums"]["SpaceAccessPermissions"]
@@ -1798,6 +1802,9 @@ export type Database = {
17981802
email: string | null
17991803
email_trusted: boolean | null
18001804
space_editor: boolean | null
1805+
permissions:
1806+
| Database["public"]["Enums"]["SpaceAccessPermissions"]
1807+
| null
18011808
}
18021809
concept_local_input: {
18031810
epistemic_status: Database["public"]["Enums"]["EpistemicStatus"] | null
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
ALTER TYPE public.account_local_input ADD ATTRIBUTE permissions public."SpaceAccessPermissions";
2+
3+
CREATE OR REPLACE FUNCTION public.my_permissions_in_space(
4+
space_id_ BIGINT
5+
) RETURNS public."SpaceAccessPermissions"
6+
SET search_path = ''
7+
LANGUAGE sql
8+
AS $$
9+
SELECT permissions FROM public."SpaceAccess" WHERE space_id=space_id_ AND account_uid = auth.uid();
10+
$$;
11+
12+
CREATE OR REPLACE FUNCTION public.upsert_account_in_space(
13+
space_id_ BIGINT,
14+
local_account public.account_local_input
15+
) RETURNS BIGINT
16+
SECURITY DEFINER
17+
SET search_path = ''
18+
LANGUAGE plpgsql
19+
AS $$
20+
DECLARE
21+
platform_ public."Platform";
22+
account_id_ BIGINT;
23+
user_uid UUID;
24+
permissions_ public."SpaceAccessPermissions";
25+
BEGIN
26+
SELECT platform INTO STRICT platform_ FROM public."Space" WHERE id = space_id_;
27+
INSERT INTO public."PlatformAccount" AS pa (
28+
account_local_id, name, platform
29+
) VALUES (
30+
local_account.account_local_id, local_account.name, platform_
31+
) ON CONFLICT (account_local_id, platform) DO UPDATE SET
32+
name = COALESCE(NULLIF(TRIM(EXCLUDED.name), ''), pa.name)
33+
RETURNING id, dg_account INTO STRICT account_id_, user_uid;
34+
IF user_uid IS NOT NULL THEN
35+
-- is any permission specified in the input?
36+
permissions_ := COALESCE(
37+
local_account.permissions,
38+
CASE WHEN local_account.space_editor IS true THEN 'editor' -- legacy
39+
WHEN local_account.space_editor IS false THEN 'reader' END);
40+
INSERT INTO public."SpaceAccess" as sa (space_id, account_uid, permissions)
41+
VALUES (space_id_, user_uid, least(my_permissions_in_space(space_id_), COALESCE(permissions_, 'editor')))
42+
ON CONFLICT (space_id, account_uid)
43+
DO UPDATE SET permissions = CASE
44+
WHEN permissions_ IS NULL THEN permissions
45+
ELSE least(my_permissions_in_space(space_id_), permissions_)
46+
END;
47+
END IF;
48+
INSERT INTO public."LocalAccess" (space_id, account_id) values (space_id_, account_id_)
49+
ON CONFLICT (space_id, account_id)
50+
DO NOTHING;
51+
IF local_account.email IS NOT NULL THEN
52+
-- TODO: how to distinguish basic untrusted from platform placeholder email?
53+
INSERT INTO public."AgentIdentifier" as ai (account_id, value, identifier_type, trusted) VALUES (account_id_, local_account.email, 'email', COALESCE(local_account.email_trusted, false))
54+
ON CONFLICT (value, identifier_type, account_id)
55+
DO UPDATE SET trusted = COALESCE(local_account.email_trusted, ai.trusted, false);
56+
END IF;
57+
RETURN account_id_;
58+
END;
59+
$$;
60+
61+
62+
DROP FUNCTION create_account_in_space;
63+
64+
CREATE OR REPLACE FUNCTION create_account_in_space(
65+
space_id_ BIGINT,
66+
account_local_id_ varchar,
67+
name_ varchar,
68+
email_ varchar = null,
69+
email_trusted boolean = true,
70+
permissions_ public."SpaceAccessPermissions" = 'editor'
71+
) RETURNS BIGINT
72+
SECURITY DEFINER
73+
SET search_path = ''
74+
LANGUAGE sql
75+
AS $$
76+
SELECT public.upsert_account_in_space(space_id_, ROW(name_, account_local_id_ ,email_, email_trusted, null, permissions_)::public.account_local_input);
77+
$$;
78+
79+
CREATE OR REPLACE FUNCTION public.my_permissions_in_space(
80+
space_id_ BIGINT
81+
) RETURNS public."SpaceAccessPermissions"
82+
SET search_path = ''
83+
LANGUAGE sql
84+
AS $$
85+
SELECT max(permissions) FROM public."SpaceAccess"
86+
JOIN public.my_user_accounts() ON (account_uid = my_user_accounts)
87+
WHERE space_id=space_id_;
88+
$$;

packages/database/supabase/schemas/account.sql

Lines changed: 105 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -169,9 +169,9 @@ GRANT ALL ON TABLE public.group_membership TO authenticated;
169169
GRANT ALL ON TABLE public.group_membership TO service_role;
170170

171171
CREATE OR REPLACE VIEW public.my_groups AS
172-
SELECT id, split_part(email,'@',1) AS name FROM auth.users
173-
JOIN public.group_membership ON (group_id=id)
174-
WHERE member_id = auth.uid();
172+
SELECT id, split_part(email, '@', 1) AS name FROM auth.users
173+
JOIN public.group_membership ON (group_id = id)
174+
WHERE member_id = auth.uid();
175175

176176
CREATE TYPE public.account_local_input AS (
177177
-- PlatformAccount columns
@@ -180,92 +180,10 @@ CREATE TYPE public.account_local_input AS (
180180
-- local values
181181
email VARCHAR,
182182
email_trusted BOOLEAN,
183-
space_editor BOOLEAN
183+
space_editor BOOLEAN,
184+
permissions public."SpaceAccessPermissions"
184185
);
185186

186-
CREATE OR REPLACE FUNCTION public.upsert_account_in_space(
187-
space_id_ BIGINT,
188-
local_account public.account_local_input
189-
) RETURNS BIGINT
190-
SECURITY DEFINER
191-
SET search_path = ''
192-
LANGUAGE plpgsql
193-
AS $$
194-
DECLARE
195-
platform_ public."Platform";
196-
account_id_ BIGINT;
197-
user_uid UUID;
198-
BEGIN
199-
SELECT platform INTO STRICT platform_ FROM public."Space" WHERE id = space_id_;
200-
INSERT INTO public."PlatformAccount" AS pa (
201-
account_local_id, name, platform
202-
) VALUES (
203-
local_account.account_local_id, local_account.name, platform_
204-
) ON CONFLICT (account_local_id, platform) DO UPDATE SET
205-
name = COALESCE(NULLIF(TRIM(EXCLUDED.name), ''), pa.name)
206-
RETURNING id, dg_account INTO STRICT account_id_, user_uid;
207-
IF user_uid IS NOT NULL THEN
208-
INSERT INTO public."SpaceAccess" as sa (space_id, account_uid, permissions)
209-
VALUES (space_id_, user_uid,
210-
CASE WHEN COALESCE(local_account.space_editor, true) THEN 'editor'
211-
ELSE 'reader' END)
212-
ON CONFLICT (space_id, account_uid)
213-
DO UPDATE SET permissions = CASE
214-
WHEN COALESCE(local_account.space_editor, sa.editor, true) THEN 'editor'
215-
ELSE 'reader' END;
216-
END IF;
217-
INSERT INTO public."LocalAccess" (space_id, account_id) values (space_id_, account_id_)
218-
ON CONFLICT (space_id, account_id)
219-
DO NOTHING;
220-
IF local_account.email IS NOT NULL THEN
221-
-- TODO: how to distinguish basic untrusted from platform placeholder email?
222-
INSERT INTO public."AgentIdentifier" as ai (account_id, value, identifier_type, trusted) VALUES (account_id_, local_account.email, 'email', COALESCE(local_account.email_trusted, false))
223-
ON CONFLICT (value, identifier_type, account_id)
224-
DO UPDATE SET trusted = COALESCE(local_account.email_trusted, ai.trusted, false);
225-
END IF;
226-
RETURN account_id_;
227-
END;
228-
$$;
229-
230-
CREATE OR REPLACE FUNCTION public.upsert_accounts_in_space(
231-
space_id_ BIGINT,
232-
accounts JSONB
233-
) RETURNS SETOF BIGINT
234-
SECURITY DEFINER
235-
SET search_path = ''
236-
LANGUAGE plpgsql
237-
AS $$
238-
DECLARE
239-
platform_ public."Platform";
240-
account_id_ BIGINT;
241-
account_row JSONB;
242-
local_account public.account_local_input;
243-
BEGIN
244-
SELECT platform INTO STRICT platform_ FROM public."Space" WHERE id = space_id_;
245-
FOR account_row IN SELECT * FROM jsonb_array_elements(accounts)
246-
LOOP
247-
local_account := jsonb_populate_record(NULL::public.account_local_input, account_row);
248-
RETURN NEXT public.upsert_account_in_space(space_id_, local_account);
249-
END LOOP;
250-
END;
251-
$$;
252-
253-
-- legacy
254-
CREATE OR REPLACE FUNCTION public.create_account_in_space(
255-
space_id_ BIGINT,
256-
account_local_id_ varchar,
257-
name_ varchar,
258-
email_ varchar = null,
259-
email_trusted boolean = true,
260-
editor_ boolean = true
261-
) RETURNS BIGINT
262-
SECURITY DEFINER
263-
SET search_path = ''
264-
LANGUAGE sql
265-
AS $$
266-
SELECT public.upsert_account_in_space(space_id_, ROW(name_, account_local_id_ ,email_, email_trusted, editor_)::public.account_local_input);
267-
$$;
268-
269187

270188
CREATE OR REPLACE FUNCTION public.is_my_account(account_id BIGINT) RETURNS boolean
271189
STABLE SECURITY DEFINER
@@ -307,6 +225,17 @@ $$;
307225

308226
COMMENT ON FUNCTION public.my_user_accounts IS 'security utility: The uids which give me access, either as myself or as a group member.';
309227

228+
CREATE OR REPLACE FUNCTION public.my_permissions_in_space(
229+
space_id_ BIGINT
230+
) RETURNS public."SpaceAccessPermissions"
231+
SET search_path = ''
232+
LANGUAGE sql
233+
AS $$
234+
SELECT max(permissions) FROM public."SpaceAccess"
235+
JOIN public.my_user_accounts() ON (account_uid = my_user_accounts)
236+
WHERE space_id=space_id_;
237+
$$;
238+
310239
CREATE OR REPLACE FUNCTION public.in_group(group_id_ UUID) RETURNS BOOLEAN
311240
STABLE SECURITY DEFINER
312241
SET search_path = ''
@@ -391,6 +320,95 @@ $$;
391320

392321
COMMENT ON FUNCTION public.unowned_account_in_shared_space IS 'security utility: does current user share a space with this unowned account?';
393322

323+
324+
CREATE OR REPLACE FUNCTION public.upsert_account_in_space(
325+
space_id_ BIGINT,
326+
local_account public.account_local_input
327+
) RETURNS BIGINT
328+
SECURITY DEFINER
329+
SET search_path = ''
330+
LANGUAGE plpgsql
331+
AS $$
332+
DECLARE
333+
platform_ public."Platform";
334+
account_id_ BIGINT;
335+
user_uid UUID;
336+
permissions_ public."SpaceAccessPermissions";
337+
BEGIN
338+
SELECT platform INTO STRICT platform_ FROM public."Space" WHERE id = space_id_;
339+
INSERT INTO public."PlatformAccount" AS pa (
340+
account_local_id, name, platform
341+
) VALUES (
342+
local_account.account_local_id, local_account.name, platform_
343+
) ON CONFLICT (account_local_id, platform) DO UPDATE SET
344+
name = COALESCE(NULLIF(TRIM(EXCLUDED.name), ''), pa.name)
345+
RETURNING id, dg_account INTO STRICT account_id_, user_uid;
346+
IF user_uid IS NOT NULL THEN
347+
-- is any permission specified in the input?
348+
permissions_ := COALESCE(
349+
local_account.permissions,
350+
CASE WHEN local_account.space_editor IS true THEN 'editor' -- legacy
351+
WHEN local_account.space_editor IS false THEN 'reader' END);
352+
INSERT INTO public."SpaceAccess" as sa (space_id, account_uid, permissions)
353+
VALUES (space_id_, user_uid, least(my_permissions_in_space(space_id_), COALESCE(permissions_, 'editor')))
354+
ON CONFLICT (space_id, account_uid)
355+
DO UPDATE SET permissions = CASE
356+
WHEN permissions_ IS NULL THEN permissions
357+
ELSE least(my_permissions_in_space(space_id_), permissions_)
358+
END;
359+
END IF;
360+
INSERT INTO public."LocalAccess" (space_id, account_id) values (space_id_, account_id_)
361+
ON CONFLICT (space_id, account_id)
362+
DO NOTHING;
363+
IF local_account.email IS NOT NULL THEN
364+
-- TODO: how to distinguish basic untrusted from platform placeholder email?
365+
INSERT INTO public."AgentIdentifier" as ai (account_id, value, identifier_type, trusted) VALUES (account_id_, local_account.email, 'email', COALESCE(local_account.email_trusted, false))
366+
ON CONFLICT (value, identifier_type, account_id)
367+
DO UPDATE SET trusted = COALESCE(local_account.email_trusted, ai.trusted, false);
368+
END IF;
369+
RETURN account_id_;
370+
END;
371+
$$;
372+
373+
CREATE OR REPLACE FUNCTION public.upsert_accounts_in_space(
374+
space_id_ BIGINT,
375+
accounts JSONB
376+
) RETURNS SETOF BIGINT
377+
SECURITY DEFINER
378+
SET search_path = ''
379+
LANGUAGE plpgsql
380+
AS $$
381+
DECLARE
382+
platform_ public."Platform";
383+
account_id_ BIGINT;
384+
account_row JSONB;
385+
local_account public.account_local_input;
386+
BEGIN
387+
SELECT platform INTO STRICT platform_ FROM public."Space" WHERE id = space_id_;
388+
FOR account_row IN SELECT * FROM jsonb_array_elements(accounts)
389+
LOOP
390+
local_account := jsonb_populate_record(NULL::public.account_local_input, account_row);
391+
RETURN NEXT public.upsert_account_in_space(space_id_, local_account);
392+
END LOOP;
393+
END;
394+
$$;
395+
396+
-- legacy
397+
CREATE OR REPLACE FUNCTION public.create_account_in_space(
398+
space_id_ BIGINT,
399+
account_local_id_ varchar,
400+
name_ varchar,
401+
email_ varchar = null,
402+
email_trusted boolean = true,
403+
permissions_ public."SpaceAccessPermissions" = 'editor'
404+
) RETURNS BIGINT
405+
SECURITY DEFINER
406+
SET search_path = ''
407+
LANGUAGE sql
408+
AS $$
409+
SELECT public.upsert_account_in_space(space_id_, ROW(name_, account_local_id_ ,email_, email_trusted, null, permissions_)::public.account_local_input);
410+
$$;
411+
394412
-- Space: Allow anyone to insert, but only users who are members of the space can update or select
395413

396414
ALTER TABLE public."Space" ENABLE ROW LEVEL SECURITY;

0 commit comments

Comments
 (0)