From 1088d9d09c5e00e3b9870ce5458ee0ddd84767b2 Mon Sep 17 00:00:00 2001 From: James Mathew Date: Sat, 7 Mar 2026 20:19:42 -0800 Subject: [PATCH 1/8] added server --- nsc-events-nextjs/lib/supabaseClient.ts | 4 +++- nsc-events-nextjs/lib/supabaseServer.ts | 26 +++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 nsc-events-nextjs/lib/supabaseServer.ts diff --git a/nsc-events-nextjs/lib/supabaseClient.ts b/nsc-events-nextjs/lib/supabaseClient.ts index 79f2054..80d2279 100644 --- a/nsc-events-nextjs/lib/supabaseClient.ts +++ b/nsc-events-nextjs/lib/supabaseClient.ts @@ -7,4 +7,6 @@ export const createClient = () => createBrowserClient( supabaseUrl!, supabaseKey!, - ); \ No newline at end of file + ); + +export default createClient; \ No newline at end of file diff --git a/nsc-events-nextjs/lib/supabaseServer.ts b/nsc-events-nextjs/lib/supabaseServer.ts new file mode 100644 index 0000000..f2df5ea --- /dev/null +++ b/nsc-events-nextjs/lib/supabaseServer.ts @@ -0,0 +1,26 @@ +import { createServerClient } from '@supabase/ssr'; +import { cookies } from 'next/headers'; + +export function createSupabaseServerClient() { + const cookieStore = cookies(); + + return createServerClient( + process.env.NEXT_PUBLIC_SUPABASE_URL!, + process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!, + { + cookies: { + getAll() { + return cookieStore.getAll(); + }, + setAll(cookiesToSet) { + try { + cookiesToSet.forEach(({ name, value, options }) => cookieStore.set(name, value, options)); + } catch { + // Ignore in some SSR contexts + } + }, + }, + } + ); +} +export default createSupabaseServerClient; \ No newline at end of file From fc9ad64a5324c9f3276f6b9fa0e6469dc11dcc0f Mon Sep 17 00:00:00 2001 From: James Mathew Date: Sat, 7 Mar 2026 22:21:08 -0800 Subject: [PATCH 2/8] creating tables for migration --- .gitignore | 3 ++- supabase/migrations/20260308054222_create_users_table.sql | 6 ++++++ .../migrations/20260308054732_create_activities_table.sql | 0 .../20260308054804_create_activity_tags_table.sql | 0 .../20260308054835_create_event_registrations_table.sql | 0 supabase/migrations/20260308054843_create_media_table.sql | 0 supabase/migrations/20260308054851_create_tags_table.sql | 0 supabase/seed.sql | 0 8 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 supabase/migrations/20260308054222_create_users_table.sql create mode 100644 supabase/migrations/20260308054732_create_activities_table.sql create mode 100644 supabase/migrations/20260308054804_create_activity_tags_table.sql create mode 100644 supabase/migrations/20260308054835_create_event_registrations_table.sql create mode 100644 supabase/migrations/20260308054843_create_media_table.sql create mode 100644 supabase/migrations/20260308054851_create_tags_table.sql create mode 100644 supabase/seed.sql diff --git a/.gitignore b/.gitignore index 3c3dc2d..743f763 100644 --- a/.gitignore +++ b/.gitignore @@ -70,4 +70,5 @@ e2e/.env e2e/.env.local # Playwright generated files -.auth/ \ No newline at end of file +.auth/ +notes.md \ No newline at end of file diff --git a/supabase/migrations/20260308054222_create_users_table.sql b/supabase/migrations/20260308054222_create_users_table.sql new file mode 100644 index 0000000..de8a97a --- /dev/null +++ b/supabase/migrations/20260308054222_create_users_table.sql @@ -0,0 +1,6 @@ +-- Migration: create_users_table +-- Creates users table for NSC Events + +CREATE TABLE IF NOT EXISTS users ( +id +); \ No newline at end of file diff --git a/supabase/migrations/20260308054732_create_activities_table.sql b/supabase/migrations/20260308054732_create_activities_table.sql new file mode 100644 index 0000000..e69de29 diff --git a/supabase/migrations/20260308054804_create_activity_tags_table.sql b/supabase/migrations/20260308054804_create_activity_tags_table.sql new file mode 100644 index 0000000..e69de29 diff --git a/supabase/migrations/20260308054835_create_event_registrations_table.sql b/supabase/migrations/20260308054835_create_event_registrations_table.sql new file mode 100644 index 0000000..e69de29 diff --git a/supabase/migrations/20260308054843_create_media_table.sql b/supabase/migrations/20260308054843_create_media_table.sql new file mode 100644 index 0000000..e69de29 diff --git a/supabase/migrations/20260308054851_create_tags_table.sql b/supabase/migrations/20260308054851_create_tags_table.sql new file mode 100644 index 0000000..e69de29 diff --git a/supabase/seed.sql b/supabase/seed.sql new file mode 100644 index 0000000..e69de29 From 02b7e9cf625d51581c3a337fee3a177d641e3130 Mon Sep 17 00:00:00 2001 From: James Mathew Date: Sun, 8 Mar 2026 21:05:32 -0700 Subject: [PATCH 3/8] created users and media tables --- .../20260308054222_create_users_table.sql | 6 ----- ...20260308054732_create_activities_table.sql | 0 ...60308054804_create_activity_tags_table.sql | 0 ...54835_create_event_registrations_table.sql | 0 .../20260308054843_create_media_table.sql | 0 .../20260308054851_create_tags_table.sql | 0 ...2010_create_update_updated_at_function.sql | 7 ++++++ .../20260309032220_create_users_table.sql | 23 +++++++++++++++++++ .../20260309034258_create_media_table.sql | 21 +++++++++++++++++ 9 files changed, 51 insertions(+), 6 deletions(-) delete mode 100644 supabase/migrations/20260308054222_create_users_table.sql delete mode 100644 supabase/migrations/20260308054732_create_activities_table.sql delete mode 100644 supabase/migrations/20260308054804_create_activity_tags_table.sql delete mode 100644 supabase/migrations/20260308054835_create_event_registrations_table.sql delete mode 100644 supabase/migrations/20260308054843_create_media_table.sql delete mode 100644 supabase/migrations/20260308054851_create_tags_table.sql create mode 100644 supabase/migrations/20260309032010_create_update_updated_at_function.sql create mode 100644 supabase/migrations/20260309032220_create_users_table.sql create mode 100644 supabase/migrations/20260309034258_create_media_table.sql diff --git a/supabase/migrations/20260308054222_create_users_table.sql b/supabase/migrations/20260308054222_create_users_table.sql deleted file mode 100644 index de8a97a..0000000 --- a/supabase/migrations/20260308054222_create_users_table.sql +++ /dev/null @@ -1,6 +0,0 @@ --- Migration: create_users_table --- Creates users table for NSC Events - -CREATE TABLE IF NOT EXISTS users ( -id -); \ No newline at end of file diff --git a/supabase/migrations/20260308054732_create_activities_table.sql b/supabase/migrations/20260308054732_create_activities_table.sql deleted file mode 100644 index e69de29..0000000 diff --git a/supabase/migrations/20260308054804_create_activity_tags_table.sql b/supabase/migrations/20260308054804_create_activity_tags_table.sql deleted file mode 100644 index e69de29..0000000 diff --git a/supabase/migrations/20260308054835_create_event_registrations_table.sql b/supabase/migrations/20260308054835_create_event_registrations_table.sql deleted file mode 100644 index e69de29..0000000 diff --git a/supabase/migrations/20260308054843_create_media_table.sql b/supabase/migrations/20260308054843_create_media_table.sql deleted file mode 100644 index e69de29..0000000 diff --git a/supabase/migrations/20260308054851_create_tags_table.sql b/supabase/migrations/20260308054851_create_tags_table.sql deleted file mode 100644 index e69de29..0000000 diff --git a/supabase/migrations/20260309032010_create_update_updated_at_function.sql b/supabase/migrations/20260309032010_create_update_updated_at_function.sql new file mode 100644 index 0000000..82f2f94 --- /dev/null +++ b/supabase/migrations/20260309032010_create_update_updated_at_function.sql @@ -0,0 +1,7 @@ +CREATE OR REPLACE FUNCTION public.update_updated_at_column() +RETURNS TRIGGER AS $$ +BEGIN + NEW.updated_at = now(); + RETURN NEW; +END; +$$ LANGUAGE plpgsql; \ No newline at end of file diff --git a/supabase/migrations/20260309032220_create_users_table.sql b/supabase/migrations/20260309032220_create_users_table.sql new file mode 100644 index 0000000..5b459e1 --- /dev/null +++ b/supabase/migrations/20260309032220_create_users_table.sql @@ -0,0 +1,23 @@ +-- Migration: create_users_table +-- Creates users table for NSC Events + +CREATE TABLE IF NOT EXISTS public.users ( + id uuid PRIMARY KEY DEFAULT gen_random_uuid(), + first_name varchar NOT NULL, + last_name varchar NOT NULL, + pronouns varchar, + email varchar NOT NULL UNIQUE, + google_credentials jsonb, + reset_password_token varchar UNIQUE, + reset_password_expires timestamptz, + created_at timestamptz DEFAULT now(), + updated_at timestamptz DEFAULT now() +); + +-- Enable Row Level Security (RLS) +ALTER TABLE public.users ENABLE ROW LEVEL SECURITY; + +CREATE OR REPLACE TRIGGER update_users_updated_at + BEFORE UPDATE ON public.users + FOR EACH ROW + EXECUTE FUNCTION public.update_updated_at_column(); \ No newline at end of file diff --git a/supabase/migrations/20260309034258_create_media_table.sql b/supabase/migrations/20260309034258_create_media_table.sql new file mode 100644 index 0000000..40eaf73 --- /dev/null +++ b/supabase/migrations/20260309034258_create_media_table.sql @@ -0,0 +1,21 @@ +CREATE TABLE IF NOT EXISTS public.media ( + id uuid PRIMARY KEY DEFAULT gen_random_uuid(), + filename varchar NOT NULL, + original_name varchar NOT NULL, + mime_type varchar, + size bigint NOT NULL, + s3_key varchar, + s3_url varchar, + type varchar, + uploaded_by_user_id uuid NOT NULL REFERENCES public.users(id) ON DELETE SET NULL, + created_at timestamptz DEFAULT now(), + updated_at timestamptz DEFAULT now() +); + +-- Enable Row Level Security (RLS) +ALTER TABLE public.media ENABLE ROW LEVEL SECURITY; + +CREATE OR REPLACE TRIGGER update_media_updated_at + BEFORE UPDATE ON public.media + FOR EACH ROW + EXECUTE FUNCTION public.update_updated_at_column(); \ No newline at end of file From afdbbbb200abe5129170ebdc6c45d0551b5ca36c Mon Sep 17 00:00:00 2001 From: James Mathew Date: Mon, 9 Mar 2026 21:00:13 -0700 Subject: [PATCH 4/8] database migration in progress --- .../20260309032220_create_users_table.sql | 12 +++++ .../20260309034258_create_media_table.sql | 14 ++++++ .../20260310014930_create_tags_table.sql | 21 ++++++++ ...20260310022009_create_activities_table.sql | 50 +++++++++++++++++++ ...31659_create_event_registrations_table.sql | 48 ++++++++++++++++++ ...60310035012_create_activity_tags_table.sql | 12 +++++ 6 files changed, 157 insertions(+) create mode 100644 supabase/migrations/20260310014930_create_tags_table.sql create mode 100644 supabase/migrations/20260310022009_create_activities_table.sql create mode 100644 supabase/migrations/20260310031659_create_event_registrations_table.sql create mode 100644 supabase/migrations/20260310035012_create_activity_tags_table.sql diff --git a/supabase/migrations/20260309032220_create_users_table.sql b/supabase/migrations/20260309032220_create_users_table.sql index 5b459e1..d6eb0c7 100644 --- a/supabase/migrations/20260309032220_create_users_table.sql +++ b/supabase/migrations/20260309032220_create_users_table.sql @@ -17,6 +17,18 @@ CREATE TABLE IF NOT EXISTS public.users ( -- Enable Row Level Security (RLS) ALTER TABLE public.users ENABLE ROW LEVEL SECURITY; +-- users can only read/update their own row +CREATE POLICY "Users can view own profile" + ON public.users + FOR SELECT + USING (auth.uid() = id); + +CREATE POLICY "Users can update own profile" + ON public.users + FOR UPDATE + USING (auth.uid() = id) + WITH CHECK (auth.uid() = id); + CREATE OR REPLACE TRIGGER update_users_updated_at BEFORE UPDATE ON public.users FOR EACH ROW diff --git a/supabase/migrations/20260309034258_create_media_table.sql b/supabase/migrations/20260309034258_create_media_table.sql index 40eaf73..9ad1299 100644 --- a/supabase/migrations/20260309034258_create_media_table.sql +++ b/supabase/migrations/20260309034258_create_media_table.sql @@ -15,6 +15,20 @@ CREATE TABLE IF NOT EXISTS public.media ( -- Enable Row Level Security (RLS) ALTER TABLE public.media ENABLE ROW LEVEL SECURITY; +-- Uploader can view/update/delete their own media +CREATE POLICY "Users can manage own media" + ON public.media + FOR ALL + USING (auth.uid() = uploaded_by_user_id) + WITH CHECK (auth.uid() = uploaded_by_user_id); + +-- public can access to media +CREATE POLICY "Public can view media" + ON public.media + FOR SELECT + USING (true); + +-- Update updated at CREATE OR REPLACE TRIGGER update_media_updated_at BEFORE UPDATE ON public.media FOR EACH ROW diff --git a/supabase/migrations/20260310014930_create_tags_table.sql b/supabase/migrations/20260310014930_create_tags_table.sql new file mode 100644 index 0000000..cc7f03d --- /dev/null +++ b/supabase/migrations/20260310014930_create_tags_table.sql @@ -0,0 +1,21 @@ +CREATE TABLE IF NOT EXISTS public.tags ( + id uuid PRIMARY KEY DEFAULT gen_random_uuid(), + name varchar NOT NULL UNIQUE, + slug varchar NOT NULL UNIQUE, + created_at timestamptz DEFAULT now(), + updated_at timestamptz DEFAULT now() +); + +-- Enable Row Level Security (RLS) +ALTER TABLE public.tags ENABLE ROW LEVEL SECURITY; + +-- everyone can see tags +CREATE POLICY "Public read access to tags" + ON public.tags + FOR SELECT + USING (true); + +CREATE OR REPLACE TRIGGER update_tags_updated_at + BEFORE UPDATE ON public.tags + FOR EACH ROW + EXECUTE FUNCTION public.update_updated_at_column(); \ No newline at end of file diff --git a/supabase/migrations/20260310022009_create_activities_table.sql b/supabase/migrations/20260310022009_create_activities_table.sql new file mode 100644 index 0000000..7e6bd94 --- /dev/null +++ b/supabase/migrations/20260310022009_create_activities_table.sql @@ -0,0 +1,50 @@ +CREATE TABLE IF NOT EXISTS public.activities ( + id uuid PRIMARY KEY DEFAULT gen_random_uuid(), + created_by_user_id uuid NOT NULL REFERENCES public.users(id) ON DELETE SET NULL, + event_title varchar NOT NULL, + event_description text NOT NULL, + start_date timestamptz NOT NULL, + end_date timestamptz NOT NULL, + event_location varchar NOT NULL, + event_host varchar NOT NULL, + event_meeting_url varchar, + event_registration varchar, + event_capacity varchar NOT NULL, + event_schedule varchar, + event_speakers text, + event_prerequisites varchar, + event_cancellation_policy varchar, + event_contact varchar NOT NULL, + event_social_media jsonb, + event_privacy varchar, + event_accessibility varchar, + event_note varchar, + is_hidden boolean DEFAULT false, + is_archived boolean DEFAULT false, + cover_photo_id uuid REFERENCES public.media(id) ON DELETE SET NULL, + document_id uuid REFERENCES public.media(id) ON DELETE SET NULL, + created_at timestamptz DEFAULT now(), + updated_at timestamptz DEFAULT now() +); + +-- Enable Row Level Security (RLS) +ALTER TABLE public.activities ENABLE ROW LEVEL SECURITY; + +-- Creator can view/update/delete their own events +CREATE POLICY "Creators can manage own events" + ON public.activities + FOR ALL + USING (auth.uid() = created_by_user_id) + WITH CHECK (auth.uid() = created_by_user_id); + +-- public have read access to activities +CREATE POLICY "Public can view activity" + ON public.activities + FOR SELECT + USING (true); + +-- Update updated at +CREATE OR REPLACE TRIGGER update_activities_updated_at + BEFORE UPDATE ON public.activities + FOR EACH ROW + EXECUTE FUNCTION public.update_updated_at_column(); \ No newline at end of file diff --git a/supabase/migrations/20260310031659_create_event_registrations_table.sql b/supabase/migrations/20260310031659_create_event_registrations_table.sql new file mode 100644 index 0000000..38ed0e7 --- /dev/null +++ b/supabase/migrations/20260310031659_create_event_registrations_table.sql @@ -0,0 +1,48 @@ +CREATE TABLE IF NOT EXISTS public.event_registrations ( + id uuid PRIMARY KEY DEFAULT gen_random_uuid(), + activity_id uuid NOT NULL REFERENCES public.activities(id) ON DELETE SET NULL, + user_id uuid NOT NULL REFERENCES public.users(id) ON DELETE SET NULL, + college varchar NOT NULL, + year_of_study varchar NOT NULL, + is_attended boolean DEFAULT false, + created_at timestamptz DEFAULT now(), + updated_at timestamptz DEFAULT now() +); + +-- Enable Row Level Security (RLS) +ALTER TABLE public.event_registrations ENABLE ROW LEVEL SECURITY; + +CREATE POLICY "Users view own registrations" + ON public.event_registrations + FOR SELECT + USING (auth.uid() = user_id); + +CREATE POLICY "Users can register themselves" + ON public.event_registrations + FOR INSERT + WITH CHECK (auth.uid() = user_id); + +CREATE POLICY "Users can remove own registrations" + ON public.event_registrations + FOR DELETE + USING (auth.uid() = user_id); + +CREATE POLICY "Users can change own registrations" + ON public.event_registrations + FOR UPDATE + USING (auth.uid() = user_id); + +CREATE POLICY "Creators view registrations for their events" + ON public.event_registrations + FOR SELECT + USING ( + EXISTS ( + SELECT 1 FROM public.activities activity + WHERE activity.id = activity_id + AND activity.created_by_user_id = auth.uid()) + ); +-- Update updated at +CREATE OR REPLACE TRIGGER update_event_registrations_updated_at + BEFORE UPDATE ON public.event_registrations + FOR EACH ROW + EXECUTE FUNCTION public.update_updated_at_column(); \ No newline at end of file diff --git a/supabase/migrations/20260310035012_create_activity_tags_table.sql b/supabase/migrations/20260310035012_create_activity_tags_table.sql new file mode 100644 index 0000000..d1c4b45 --- /dev/null +++ b/supabase/migrations/20260310035012_create_activity_tags_table.sql @@ -0,0 +1,12 @@ +CREATE TABLE IF NOT EXISTS public.activity_tags ( + activity_id uuid NOT NULL REFERENCES public.activities(id) ON DELETE CASCADE, + tag_id uuid NOT NULL REFERENCES public.tags(id) ON DELETE CASCADE, + PRIMARY KEY (activity_id, tag_id) +); + +ALTER TABLE public.activity_tags ENABLE ROW LEVEL SECURITY; + +CREATE POLICY "Public can view activity tags" + ON public.activity_tags + FOR SELECT + USING (true); \ No newline at end of file From 0b759c3c29089cc19aa3beb227e1d32c1a50b8ef Mon Sep 17 00:00:00 2001 From: James Mathew Date: Tue, 10 Mar 2026 19:39:20 -0700 Subject: [PATCH 5/8] created admin user --- .../migrations/20260309032220_create_users_table.sql | 8 ++++++++ supabase/seed.sql | 12 ++++++++++++ 2 files changed, 20 insertions(+) diff --git a/supabase/migrations/20260309032220_create_users_table.sql b/supabase/migrations/20260309032220_create_users_table.sql index d6eb0c7..b18c883 100644 --- a/supabase/migrations/20260309032220_create_users_table.sql +++ b/supabase/migrations/20260309032220_create_users_table.sql @@ -1,11 +1,14 @@ -- Migration: create_users_table -- Creates users table for NSC Events +CREATE TYPE public.user_role_type AS ENUM ('user', 'creator', 'admin'); + CREATE TABLE IF NOT EXISTS public.users ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), first_name varchar NOT NULL, last_name varchar NOT NULL, pronouns varchar, + user_role user_role_type NOT NULL DEFAULT 'user', email varchar NOT NULL UNIQUE, google_credentials jsonb, reset_password_token varchar UNIQUE, @@ -17,6 +20,11 @@ CREATE TABLE IF NOT EXISTS public.users ( -- Enable Row Level Security (RLS) ALTER TABLE public.users ENABLE ROW LEVEL SECURITY; +CREATE POLICY "Admins manage all users" + ON public.users + FOR ALL + USING ((SELECT user_role FROM public.users WHERE id = auth.uid()) = 'admin'); + -- users can only read/update their own row CREATE POLICY "Users can view own profile" ON public.users diff --git a/supabase/seed.sql b/supabase/seed.sql index e69de29..9634ffa 100644 --- a/supabase/seed.sql +++ b/supabase/seed.sql @@ -0,0 +1,12 @@ +INSERT INTO public.users ( + first_name, + last_name, + user_role, + email +) +VALUES ( + 'Admin', + 'NSC', + 'admin', + 'admin@gmail.com' +); \ No newline at end of file From 38ba8c520c0eadf184215a0f0083c9f410643eeb Mon Sep 17 00:00:00 2001 From: James Mathew Date: Tue, 10 Mar 2026 20:20:43 -0700 Subject: [PATCH 6/8] adding admin user in progress --- supabase/seed.sql | 29 ++++++++++++++++++++++-- supabase/snippets/Untitled query 790.sql | 1 + 2 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 supabase/snippets/Untitled query 790.sql diff --git a/supabase/seed.sql b/supabase/seed.sql index 9634ffa..59933a4 100644 --- a/supabase/seed.sql +++ b/supabase/seed.sql @@ -1,12 +1,37 @@ +WITH new_admin AS ( +INSERT INTO auth.users ( + id, + email, + encrypted_password, + email_confirmed_at, + created_at, + updated_at, + aud, + role +) +VALUES ( + gen_random_uuid(), + 'admin@gmail.com', + crypt('Admin123!', gen_salt('bf')), + now(), + now(), + now(), + 'authenticated', + 'authenticated' +) +RETURNING id, email +) INSERT INTO public.users ( + id, first_name, last_name, user_role, email ) -VALUES ( +SELECT + id, 'Admin', 'NSC', 'admin', 'admin@gmail.com' -); \ No newline at end of file +FROM new_admin; \ No newline at end of file diff --git a/supabase/snippets/Untitled query 790.sql b/supabase/snippets/Untitled query 790.sql new file mode 100644 index 0000000..ef1f2b2 --- /dev/null +++ b/supabase/snippets/Untitled query 790.sql @@ -0,0 +1 @@ +select * from public.users; \ No newline at end of file From edb5f53ed88268db2cd0db781f0d385c817c2b86 Mon Sep 17 00:00:00 2001 From: James Mathew Date: Thu, 12 Mar 2026 16:44:16 -0700 Subject: [PATCH 7/8] created db and added admin user. resolves issue #169 --- nsc-events-nextjs/lib/supabaseClient.ts | 4 +-- supabase/seed.sql | 48 ++++++++++++++++--------- 2 files changed, 33 insertions(+), 19 deletions(-) diff --git a/nsc-events-nextjs/lib/supabaseClient.ts b/nsc-events-nextjs/lib/supabaseClient.ts index 80d2279..af039f3 100644 --- a/nsc-events-nextjs/lib/supabaseClient.ts +++ b/nsc-events-nextjs/lib/supabaseClient.ts @@ -3,10 +3,10 @@ import { createBrowserClient } from "@supabase/ssr"; const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL; const supabaseKey = process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_DEFAULT_KEY; -export const createClient = () => +export const supabase = () => createBrowserClient( supabaseUrl!, supabaseKey!, ); -export default createClient; \ No newline at end of file +export default supabase; \ No newline at end of file diff --git a/supabase/seed.sql b/supabase/seed.sql index 59933a4..9f5a139 100644 --- a/supabase/seed.sql +++ b/supabase/seed.sql @@ -1,37 +1,51 @@ -WITH new_admin AS ( +-- ============================================= +-- SEED DATA FOR LOCAL DEVELOPMENT ONLY +-- Creates a real auth user + matching public.users row +-- ============================================= + +-- 1. Create the admin user in Supabase Auth (auth.users) +-- Password = admin123 (CHANGE THIS AFTER FIRST LOGIN!) INSERT INTO auth.users ( + instance_id, id, + aud, + role, email, - encrypted_password, + encrypted_password, email_confirmed_at, created_at, - updated_at, - aud, - role + updated_at ) VALUES ( - gen_random_uuid(), + '00000000-0000-0000-0000-000000000000', + gen_random_uuid(), + 'authenticated', + 'authenticated', 'admin@gmail.com', crypt('Admin123!', gen_salt('bf')), - now(), now(), now(), - 'authenticated', - 'authenticated' -) -RETURNING id, email -) + now() +); + INSERT INTO public.users ( id, first_name, last_name, + pronouns, user_role, - email + email, + created_at, + updated_at ) -SELECT +SELECT id, 'Admin', - 'NSC', + 'User', + 'They/Them', 'admin', - 'admin@gmail.com' -FROM new_admin; \ No newline at end of file + 'admin@gmail.com', + now(), + now() +FROM auth.users +WHERE email = 'admin@gmail.com'; \ No newline at end of file From 105cb300d77240cab9e10dfe6a2fc2d170f99aa6 Mon Sep 17 00:00:00 2001 From: James Mathew Date: Sat, 14 Mar 2026 00:14:17 -0700 Subject: [PATCH 8/8] auth partly done, need to check if server side auth needed for every action. --- nsc-events-nextjs/app/auth/sign-in/page.tsx | 121 +++++++++--------- nsc-events-nextjs/hooks/useAuth.tsx | 23 ++-- nsc-events-nextjs/lib/supabaseClient.ts | 4 +- package-lock.json | 16 +-- .../20260309032220_create_users_table.sql | 19 ++- supabase/seed.sql | 36 ++++-- supabase/snippets/Untitled query 790.sql | 2 +- 7 files changed, 121 insertions(+), 100 deletions(-) diff --git a/nsc-events-nextjs/app/auth/sign-in/page.tsx b/nsc-events-nextjs/app/auth/sign-in/page.tsx index 14299e1..dc42f01 100644 --- a/nsc-events-nextjs/app/auth/sign-in/page.tsx +++ b/nsc-events-nextjs/app/auth/sign-in/page.tsx @@ -6,9 +6,11 @@ import Image from "next/image"; import { Container, Paper, Box, TextField, Button, Typography, Link as MuiLink, useMediaQuery } from "@mui/material"; import { textFieldStyle } from "@/components/InputFields"; import { useTheme } from "@mui/material"; +import { createClient } from "@/lib/supabaseClient"; +const supabase = createClient(); -const URL = process.env.NSC_EVENTS_PUBLIC_API_URL; -console.log('Sign-in Dev API Address: ', URL); +// const URL = process.env.NSC_EVENTS_PUBLIC_API_URL; +// console.log('Sign-in Dev API Address: ', URL); const Signin = () => { const { palette } = useTheme(); @@ -17,7 +19,7 @@ const Signin = () => { const lightImagePath = '/images/blue_nsc_logo.png'; const imagePath = palette.mode === "dark" ? darkImagePath : lightImagePath; - + const [error, setError] = useState(""); const [userInfo, setUserInfo] = useState({ email: "", @@ -25,7 +27,7 @@ const Signin = () => { }); const router = useRouter(); - + const theme = useTheme(); const isMobile = useMediaQuery(theme.breakpoints.down('sm')); const isTablet = useMediaQuery(theme.breakpoints.between('sm', 'md')); @@ -40,51 +42,43 @@ const Signin = () => { const handleSubmit: FormEventHandler = async (e) => { e.preventDefault(); - + setError("") try { - if (!URL) { - setError("API URL not configured"); - return; - } - - const loginEndpoint = `${URL}/auth/login`; - - const res = await fetch(loginEndpoint, { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - email, - password, - }), + + const { data, error } = await supabase.auth.signInWithPassword({ + email, + password }); - - if (!res.ok) { - const errorText = await res.text(); - setError("Invalid email or password"); + + if (error) { + setError(error.message || "Invalid email or password"); return; } - - const data = await res.json(); - - if (!data.token) { - setError("Login response missing token"); - return; + + if (!data.session) { + setError("Login was sucessful, but no session was returned") } - - const { token } = data; - let userRole; - + + const token = data.session.access_token; + localStorage.setItem("token", token); + window.dispatchEvent(new CustomEvent('auth-change')); + + let userRole: string | undefined; + try { const payload = JSON.parse(atob(token.split(".")[1])); - userRole = payload.role; + userRole = payload.app_metadata?.role; + + if (!userRole) { + userRole = 'user'; + } + localStorage.setItem("role", userRole); + } catch (parseError) { - setError("Invalid token format"); - return; + console.error("Could not parse JWT:", parseError); + userRole = 'user'; } - - localStorage.setItem("token", token); - window.dispatchEvent(new CustomEvent('auth-change')); - + if (userRole === "admin") { router.push("/admin"); } else if (userRole === "creator") { @@ -92,41 +86,42 @@ const Signin = () => { } else { router.push("/"); } - } catch (err) { + } + catch (err) { setError("An error occurred during login"); console.error("Login error:", err); } }; return ( - - - { @@ -11,11 +14,12 @@ const useAuth = () => { const checkAuth = () => { try { + // console.log("local storage in use auth hook", localStorage) const token = localStorage.getItem('token'); - + // Trim whitespace and check if token exists const trimmedToken = token?.trim(); - + if (!trimmedToken) { setIsAuth(false); setUser(null); @@ -26,6 +30,7 @@ const useAuth = () => { // Validate JWT format (must have 3 parts) const parts = trimmedToken.split('.'); + if (parts.length !== 3) { console.error('Invalid JWT format'); setUser(null); @@ -33,10 +38,12 @@ const useAuth = () => { } // Decode token payload - const payload = parts[1]; - const decoded = atob(payload); - const user = JSON.parse(decoded); - + const payload = JSON.parse(atob(trimmedToken.split(".")[1]));; + // const decoded = atob(payload); + const user = payload.app_metadata; + // console.log("payload", payload) + // console.log("decoded", decoded) + // console.log("user", user) setUser(user); } catch (error) { // Handle any decoding or parsing errors gracefully diff --git a/nsc-events-nextjs/lib/supabaseClient.ts b/nsc-events-nextjs/lib/supabaseClient.ts index af039f3..71c2bdc 100644 --- a/nsc-events-nextjs/lib/supabaseClient.ts +++ b/nsc-events-nextjs/lib/supabaseClient.ts @@ -3,10 +3,8 @@ import { createBrowserClient } from "@supabase/ssr"; const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL; const supabaseKey = process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_DEFAULT_KEY; -export const supabase = () => +export const createClient = () => createBrowserClient( supabaseUrl!, supabaseKey!, ); - -export default supabase; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 9e07688..4c89415 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11892,7 +11892,6 @@ "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", "dev": true, - "peer": true, "dependencies": { "tslib": "^2.1.0" } @@ -12727,9 +12726,9 @@ } }, "node_modules/supabase": { - "version": "2.76.15", - "resolved": "https://registry.npmjs.org/supabase/-/supabase-2.76.15.tgz", - "integrity": "sha512-m69o1XPAzZaIWfQiEeT+KY/Ci3OSA663RyoH9xECbXSxhr7dsipLCpCqT1E4MCob0mMhHh/7A+Eltx4y1qSwiQ==", + "version": "2.78.1", + "resolved": "https://registry.npmjs.org/supabase/-/supabase-2.78.1.tgz", + "integrity": "sha512-fCIE/LTTr1IGrrYLqYBI3w89QU1qW+mRVtUi/Dmrtj+oXtDX4E8VgfFlXZpoYsXy86cfE9RZXUJVAGgvdNfTPg==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -12737,7 +12736,7 @@ "bin-links": "^6.0.0", "https-proxy-agent": "^7.0.2", "node-fetch": "^3.3.2", - "tar": "7.5.9" + "tar": "7.5.11" }, "bin": { "supabase": "bin/supabase" @@ -12813,9 +12812,9 @@ } }, "node_modules/supabase/node_modules/tar": { - "version": "7.5.9", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.9.tgz", - "integrity": "sha512-BTLcK0xsDh2+PUe9F6c2TlRp4zOOBMTkoQHQIWSIzI0R7KG46uEwq4OPk2W7bZcprBMsuaeFsqwYr7pjh6CuHg==", + "version": "7.5.11", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.11.tgz", + "integrity": "sha512-ChjMH33/KetonMTAtpYdgUFr0tbz69Fp2v7zWxQfYZX4g5ZN2nOBXm1R2xyA+lMIKrLKIoKAwFj93jE/avX9cQ==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { @@ -13300,7 +13299,6 @@ "version": "0.3.27", "resolved": "https://registry.npmjs.org/typeorm/-/typeorm-0.3.27.tgz", "integrity": "sha512-pNV1bn+1n8qEe8tUNsNdD8ejuPcMAg47u2lUGnbsajiNUr3p2Js1XLKQjBMH0yMRMDfdX8T+fIRejFmIwy9x4A==", - "peer": true, "dependencies": { "@sqltools/formatter": "^1.2.5", "ansis": "^3.17.0", diff --git a/supabase/migrations/20260309032220_create_users_table.sql b/supabase/migrations/20260309032220_create_users_table.sql index b18c883..16466b9 100644 --- a/supabase/migrations/20260309032220_create_users_table.sql +++ b/supabase/migrations/20260309032220_create_users_table.sql @@ -1,14 +1,14 @@ -- Migration: create_users_table -- Creates users table for NSC Events -CREATE TYPE public.user_role_type AS ENUM ('user', 'creator', 'admin'); +CREATE TYPE public.user_role AS ENUM ('user', 'creator', 'admin'); CREATE TABLE IF NOT EXISTS public.users ( id uuid PRIMARY KEY DEFAULT gen_random_uuid(), first_name varchar NOT NULL, last_name varchar NOT NULL, pronouns varchar, - user_role user_role_type NOT NULL DEFAULT 'user', + role user_role NOT NULL DEFAULT 'user', email varchar NOT NULL UNIQUE, google_credentials jsonb, reset_password_token varchar UNIQUE, @@ -20,10 +20,17 @@ CREATE TABLE IF NOT EXISTS public.users ( -- Enable Row Level Security (RLS) ALTER TABLE public.users ENABLE ROW LEVEL SECURITY; -CREATE POLICY "Admins manage all users" - ON public.users - FOR ALL - USING ((SELECT user_role FROM public.users WHERE id = auth.uid()) = 'admin'); +-- CREATE POLICY "Admins can read all users" +-- ON public.users +-- FOR SELECT +-- USING ( +-- EXISTS ( +-- SELECT 1 +-- FROM public.users +-- WHERE id = auth.uid() +-- AND role = 'admin' +-- ) +-- ); -- users can only read/update their own row CREATE POLICY "Users can view own profile" diff --git a/supabase/seed.sql b/supabase/seed.sql index 9f5a139..18f6468 100644 --- a/supabase/seed.sql +++ b/supabase/seed.sql @@ -1,10 +1,5 @@ --- ============================================= --- SEED DATA FOR LOCAL DEVELOPMENT ONLY --- Creates a real auth user + matching public.users row --- ============================================= --- 1. Create the admin user in Supabase Auth (auth.users) --- Password = admin123 (CHANGE THIS AFTER FIRST LOGIN!) +-- 1. Insert into auth.users (Supabase Auth table) INSERT INTO auth.users ( instance_id, id, @@ -13,27 +8,41 @@ INSERT INTO auth.users ( email, encrypted_password, email_confirmed_at, + confirmation_token, + email_change, + email_change_token_new, + recovery_token, + raw_app_meta_data, + raw_user_meta_data, created_at, updated_at ) VALUES ( - '00000000-0000-0000-0000-000000000000', + '00000000-0000-0000-0000-000000000000'::uuid, gen_random_uuid(), 'authenticated', 'authenticated', 'admin@gmail.com', crypt('Admin123!', gen_salt('bf')), now(), + '', + '', + '', + '', + '{"provider":"email","providers":["email"],"role":"admin"}'::jsonb, + '{}'::jsonb, now(), now() ); +-- 2. Insert matching row in public.users +-- Uses the same id as the auth user above INSERT INTO public.users ( id, first_name, last_name, pronouns, - user_role, + role, email, created_at, updated_at @@ -43,9 +52,16 @@ SELECT 'Admin', 'User', 'They/Them', - 'admin', + 'admin', 'admin@gmail.com', now(), now() FROM auth.users -WHERE email = 'admin@gmail.com'; \ No newline at end of file +WHERE email = 'admin@gmail.com' +ON CONFLICT (id) DO UPDATE +SET + first_name = EXCLUDED.first_name, + last_name = EXCLUDED.last_name, + pronouns = EXCLUDED.pronouns, + role = EXCLUDED.role, + updated_at = now(); \ No newline at end of file diff --git a/supabase/snippets/Untitled query 790.sql b/supabase/snippets/Untitled query 790.sql index ef1f2b2..69e5c6c 100644 --- a/supabase/snippets/Untitled query 790.sql +++ b/supabase/snippets/Untitled query 790.sql @@ -1 +1 @@ -select * from public.users; \ No newline at end of file +SELECT * from public.users \ No newline at end of file