Skip to content

Commit 2163640

Browse files
committed
eng-1702-invite-new-member
1 parent 84728f3 commit 2163640

4 files changed

Lines changed: 120 additions & 11 deletions

File tree

apps/website/app/utils/supabase/account.ts

Lines changed: 72 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ import type { DGSupabaseClient } from "@repo/database/lib/client";
33

44
type AgentType = Database["public"]["Enums"]["AgentType"] | "group";
55

6-
export const getSessionUserData = async (
6+
export const getSessionBaseUserData = async (
77
client: DGSupabaseClient,
88
): Promise<{
99
id: string;
10-
name: string;
10+
name?: string;
1111
type: AgentType;
1212
email?: string;
1313
} | null> => {
@@ -33,16 +33,38 @@ export const getSessionUserData = async (
3333
return { name, id, email, type: "group" };
3434
}
3535
}
36-
const accountReq = await client
37-
.from("PlatformAccount")
38-
.select("name")
39-
.eq("dg_account", session.data.session.user.id)
40-
.eq("agent_type", "person")
41-
.maybeSingle();
42-
if (accountReq.error || !accountReq.data) {
43-
return null;
36+
return { id, type: "person", email };
37+
};
38+
39+
export const getSessionUserData = async (
40+
client: DGSupabaseClient,
41+
): Promise<{
42+
id: string;
43+
name: string;
44+
type: AgentType;
45+
email?: string;
46+
} | null> => {
47+
const data = await getSessionBaseUserData(client);
48+
if (data === null) return null;
49+
if (!data.name && data.type === "person") {
50+
const accountReq = await client
51+
.from("PlatformAccount")
52+
.select("name")
53+
.eq("dg_account", data.id)
54+
.eq("agent_type", "person")
55+
.maybeSingle();
56+
if (accountReq.error || !accountReq.data?.name) {
57+
return null;
58+
}
59+
return { ...data, name: accountReq.data.name };
4460
}
45-
return { id, name: accountReq.data.name, type: "person", email };
61+
if (data.name === undefined) return null;
62+
return data as {
63+
id: string;
64+
name: string; // typescript is being dumb
65+
type: AgentType;
66+
email?: string;
67+
};
4668
};
4769

4870
export const getGroupMemberList = async (
@@ -80,3 +102,42 @@ export const getGroupMemberList = async (
80102
}[]
81103
);
82104
};
105+
106+
export const createGroupInvitation = async ({
107+
client,
108+
groupId,
109+
admin = false,
110+
}: {
111+
client: DGSupabaseClient;
112+
groupId: string;
113+
admin: boolean;
114+
}): Promise<string | null> => {
115+
const userData = await getSessionBaseUserData(client);
116+
if (!userData) return null;
117+
const membershipReq = await client
118+
.from("group_membership")
119+
.select("admin")
120+
.eq("group_id", groupId)
121+
.eq("member_id", userData.id)
122+
.maybeSingle();
123+
if (membershipReq.data?.admin !== true) return null;
124+
const { data, error } = await client.rpc("create_secret_token", {
125+
v_payload: JSON.stringify({ groupId, type: "groupInvitation", admin }),
126+
expiry_interval: "60d",
127+
});
128+
if (error || !data) return null;
129+
return data;
130+
};
131+
132+
export const acceptGroupInvitation = async (
133+
client: DGSupabaseClient,
134+
token: string,
135+
): Promise<string | null> => {
136+
const userData = await getSessionBaseUserData(client);
137+
if (!userData) return "Not logged in";
138+
const { data, error } = await client.rpc("accept_group_invitation", {
139+
token,
140+
});
141+
if (error || !data) return "This token does not exist";
142+
return null;
143+
};

packages/database/src/dbTypes.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1314,6 +1314,7 @@ export type Database = {
13141314
isSetofReturn: false
13151315
}
13161316
}
1317+
accept_group_invitation: { Args: { token: string }; Returns: boolean }
13171318
account_in_shared_space: {
13181319
Args: {
13191320
access_level?: Database["public"]["Enums"]["SpaceAccessPermissions"]
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
CREATE OR REPLACE FUNCTION public.accept_group_invitation(token varchar) RETURNS boolean
2+
SET search_path = '' SECURITY DEFINER
3+
LANGUAGE plpgsql AS $$
4+
DECLARE
5+
v_creator UUID;
6+
token_info JSONB;
7+
v_group_id UUID;
8+
token_type varchar;
9+
as_admin BOOLEAN;
10+
is_admin BOOLEAN;
11+
BEGIN
12+
BEGIN
13+
SELECT creator INTO v_creator STRICT FROM public.secret_token WHERE id=token;
14+
SELECT public.get_secret_token(token) INTO token_info STRICT;
15+
SELECT (token_info->>'groupId')::UUID, token_info->>'type', (token_info->'admin')::boolean INTO v_group_id, token_type, as_admin STRICT;
16+
SELECT admin INTO is_admin FROM public.group_membership WHERE member_id = v_creator AND group_id = v_group_id;
17+
IF is_admin IS NOT true THEN RETURN false; END IF;
18+
INSERT INTO public.group_membership (group_id, member_id, admin) VALUES (v_group_id, auth.uid(), as_admin);
19+
RETURN true;
20+
EXCEPTION WHEN OTHERS THEN RETURN false;
21+
END;
22+
END;
23+
$$;

packages/database/supabase/schemas/account.sql

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,30 @@ LANGUAGE sql AS $$
473473
SELECT pa.id, pa.name, pa.platform, pa.agent_type, gm.admin FROM public.my_accounts AS pa JOIN public.group_membership AS gm ON (pa.dg_account=gm.member_id) WHERE gm.group_id=p_group_id;
474474
$$;
475475

476+
CREATE OR REPLACE FUNCTION public.accept_group_invitation(token varchar) RETURNS boolean
477+
SET search_path = '' SECURITY DEFINER
478+
LANGUAGE plpgsql AS $$
479+
DECLARE
480+
v_creator UUID;
481+
token_info JSONB;
482+
v_group_id UUID;
483+
token_type varchar;
484+
as_admin BOOLEAN;
485+
is_admin BOOLEAN;
486+
BEGIN
487+
BEGIN
488+
SELECT creator INTO v_creator STRICT FROM public.secret_token WHERE id=token;
489+
SELECT public.get_secret_token(token) INTO token_info STRICT;
490+
SELECT (token_info->>'groupId')::UUID, token_info->>'type', (token_info->'admin')::boolean INTO v_group_id, token_type, as_admin STRICT;
491+
SELECT admin INTO is_admin FROM public.group_membership WHERE member_id = v_creator AND group_id = v_group_id;
492+
IF is_admin IS NOT true THEN RETURN false; END IF;
493+
INSERT INTO public.group_membership (group_id, member_id, admin) VALUES (v_group_id, auth.uid(), as_admin);
494+
RETURN true;
495+
EXCEPTION WHEN OTHERS THEN RETURN false;
496+
END;
497+
END;
498+
$$;
499+
476500
DROP POLICY IF EXISTS platform_account_policy ON public."PlatformAccount";
477501

478502
DROP POLICY IF EXISTS platform_account_select_policy ON public."PlatformAccount";

0 commit comments

Comments
 (0)