From 323af75624988d5e45d0cbebe878cf1094cc95ff Mon Sep 17 00:00:00 2001 From: younusraza909 Date: Sat, 19 Oct 2024 22:26:36 +0500 Subject: [PATCH 1/3] Created a supabase migration and updated readme for migration step --- README.md | 70 ++++-- supabase/.gitignore | 4 + supabase/config.toml | 202 ++++++++++++++++++ .../20241019162345_create_tables.sql | 62 ++++++ supabase/seed.sql | 0 5 files changed, 326 insertions(+), 12 deletions(-) create mode 100644 supabase/.gitignore create mode 100644 supabase/config.toml create mode 100644 supabase/migrations/20241019162345_create_tables.sql create mode 100644 supabase/seed.sql diff --git a/README.md b/README.md index 0cae4ac..485ba75 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # Slack Clone ## Tech Stacks Used + - Vite React(for frontend) - Node.js (for backend) - Supabase (as a backend service) @@ -9,27 +10,35 @@ ### Features Overview #### Authentication + - Users can login using OAuth with Google and GitHub, or using their email and password. - Password reset functionality via email. #### Homepage Features + 1. **Todo List** + - Create, view, and delete personal todo lists. 2. **Google Calendar Integration** + - Authenticate with Google to manage events in the primary Google Calendar linked to the user's account. 3. **Direct Messaging** + - Initiate and manage conversations, share text and images (up to 50MB). 4. **Channel Management** + - Create channels, add/remove admins, assign/delete tasks to channel members and assign task to any member of the channel also, direct message members,channel deletion. - Role-based access (Admin, Member). 5. **Search Functionality** + - Search for channels and users(with whom conversation is started) within the Slack Clone. 6. **Responsive Design** + - User interface adapts to different screen sizes for optimal user experience. ## Setup Instructions @@ -37,22 +46,52 @@ ### Environment Variables - Create a .env file in the root directory of your project and define the following variables: -VITE_SUPABASE_URL= -VITE_SUPABASE_KEY= -VITE_Backend_Port= + VITE_SUPABASE_URL= + VITE_SUPABASE_KEY= + VITE_Backend_Port= - Create a .env file in the Back_end directory with following variables: -Port= -EMAIL_USER= -EMAIL_PASS= -CLIENT_ID= -CLIENT_SECRET= -REDIRECT_URL= -API_KEY= -SESSION_SECRET= + Port=`` + EMAIL_USER=`` + EMAIL_PASS=`` + CLIENT_ID=`` + CLIENT_SECRET=`` + REDIRECT_URL=`` + API_KEY=`` + SESSION_SECRET=`` + +# Run Migration to Create Tables + +There is a migration file in this project that you can run to create tables. +Below are the commands you need to run: + +##### 1. Login to Supabase + +```bash +npx supabase login +``` + +This will prompt you to log in through the browser. -### Database Tables +##### 2. Link your project + +```bash +npx supabase link +``` + +This command will ask you to link your project, so make sure a project is already there in supabase + +##### 3. Run the migration + +```bash +npx supabase db push +``` + +This will execute the migration in your newly created project. + +### Database Tables Description 1. **user_data**: + - **Columns**: - `id` (uuid) - `updated_at` (timestamp) @@ -64,6 +103,7 @@ SESSION_SECRET= - **Purpose**: Stores user information including username, avatar URL, email, phone number, and hashed password. 2. **direct_messages**: + - **Columns**: - `id` (uuid) - `created_at` (timestamp) @@ -71,6 +111,7 @@ SESSION_SECRET= - **Purpose**: Stores contact information related to direct messaging. 3. **chats_dm**: + - **Columns**: - `id` (uuid) - `created_at` (timestamp) @@ -78,6 +119,7 @@ SESSION_SECRET= - **Purpose**: Stores direct messages between users. 4. **channels_messages**: + - **Columns**: - `channel_id` (uuid) - `created_at` (timestamp) @@ -87,6 +129,7 @@ SESSION_SECRET= - **Purpose**: Stores messages and metadata for channels. 5. **channels_list**: + - **Columns**: - `id` (uuid) - `created_at` (timestamp) @@ -94,6 +137,7 @@ SESSION_SECRET= - **Purpose**: Lists channels that a user is a member of. 6. **Todo_list**: + - **Columns**: - `id` (uuid) - `created_at` (timestamp) @@ -101,6 +145,7 @@ SESSION_SECRET= - **Purpose**: Stores user-specific todo lists. 7. **Mails_sent**: + - **Columns**: - `task_id` (uuid) - `created_at` (timestamp) @@ -109,6 +154,7 @@ SESSION_SECRET= - **Purpose**: Tracks emails sent as reminders for tasks. 8. **Channels_todolist**: + - **Columns**: - `id` (uuid) - `created_at` (timestamp) diff --git a/supabase/.gitignore b/supabase/.gitignore new file mode 100644 index 0000000..a3ad880 --- /dev/null +++ b/supabase/.gitignore @@ -0,0 +1,4 @@ +# Supabase +.branches +.temp +.env diff --git a/supabase/config.toml b/supabase/config.toml new file mode 100644 index 0000000..a4438f8 --- /dev/null +++ b/supabase/config.toml @@ -0,0 +1,202 @@ +# A string used to distinguish different Supabase projects on the same host. Defaults to the +# working directory name when running `supabase init`. +project_id = "GSoC_Slack-Clone" + +[api] +enabled = true +# Port to use for the API URL. +port = 54321 +# Schemas to expose in your API. Tables, views and stored procedures in this schema will get API +# endpoints. `public` is always included. +schemas = ["public", "graphql_public"] +# Extra schemas to add to the search_path of every request. `public` is always included. +extra_search_path = ["public", "extensions"] +# The maximum number of rows returns from a view, table, or stored procedure. Limits payload size +# for accidental or malicious requests. +max_rows = 1000 + +[api.tls] +enabled = false + +[db] +# Port to use for the local database URL. +port = 54322 +# Port used by db diff command to initialize the shadow database. +shadow_port = 54320 +# The database major version to use. This has to be the same as your remote database's. Run `SHOW +# server_version;` on the remote database to check. +major_version = 15 + +[db.pooler] +enabled = false +# Port to use for the local connection pooler. +port = 54329 +# Specifies when a server connection can be reused by other clients. +# Configure one of the supported pooler modes: `transaction`, `session`. +pool_mode = "transaction" +# How many server connections to allow per user/database pair. +default_pool_size = 20 +# Maximum number of client connections allowed. +max_client_conn = 100 + +[realtime] +enabled = true +# Bind realtime via either IPv4 or IPv6. (default: IPv4) +# ip_version = "IPv6" +# The maximum length in bytes of HTTP request headers. (default: 4096) +# max_header_length = 4096 + +[studio] +enabled = true +# Port to use for Supabase Studio. +port = 54323 +# External URL of the API server that frontend connects to. +api_url = "http://127.0.0.1" +# OpenAI API Key to use for Supabase AI in the Supabase Studio. +openai_api_key = "env(OPENAI_API_KEY)" + +# Email testing server. Emails sent with the local dev setup are not actually sent - rather, they +# are monitored, and you can view the emails that would have been sent from the web interface. +[inbucket] +enabled = true +# Port to use for the email testing server web interface. +port = 54324 +# Uncomment to expose additional ports for testing user applications that send emails. +# smtp_port = 54325 +# pop3_port = 54326 + +[storage] +enabled = true +# The maximum file size allowed (e.g. "5MB", "500KB"). +file_size_limit = "50MiB" + +[storage.image_transformation] +enabled = true + +# Uncomment to configure local storage buckets +# [storage.buckets.images] +# public = false +# file_size_limit = "50MiB" +# allowed_mime_types = ["image/png", "image/jpeg"] + +[auth] +enabled = true +# The base URL of your website. Used as an allow-list for redirects and for constructing URLs used +# in emails. +site_url = "http://127.0.0.1:3000" +# A list of *exact* URLs that auth providers are permitted to redirect to post authentication. +additional_redirect_urls = ["https://127.0.0.1:3000"] +# How long tokens are valid for, in seconds. Defaults to 3600 (1 hour), maximum 604,800 (1 week). +jwt_expiry = 3600 +# If disabled, the refresh token will never expire. +enable_refresh_token_rotation = true +# Allows refresh tokens to be reused after expiry, up to the specified interval in seconds. +# Requires enable_refresh_token_rotation = true. +refresh_token_reuse_interval = 10 +# Allow/disallow new user signups to your project. +enable_signup = true +# Allow/disallow anonymous sign-ins to your project. +enable_anonymous_sign_ins = false +# Allow/disallow testing manual linking of accounts +enable_manual_linking = false + +[auth.email] +# Allow/disallow new user signups via email to your project. +enable_signup = true +# If enabled, a user will be required to confirm any email change on both the old, and new email +# addresses. If disabled, only the new email is required to confirm. +double_confirm_changes = true +# If enabled, users need to confirm their email address before signing in. +enable_confirmations = false +# Controls the minimum amount of time that must pass before sending another signup confirmation or password reset email. +max_frequency = "1s" + +# Use a production-ready SMTP server +# [auth.email.smtp] +# host = "smtp.sendgrid.net" +# port = 587 +# user = "apikey" +# pass = "env(SENDGRID_API_KEY)" +# admin_email = "admin@email.com" +# sender_name = "Admin" + +# Uncomment to customize email template +# [auth.email.template.invite] +# subject = "You have been invited" +# content_path = "./supabase/templates/invite.html" + +[auth.sms] +# Allow/disallow new user signups via SMS to your project. +enable_signup = true +# If enabled, users need to confirm their phone number before signing in. +enable_confirmations = false +# Template for sending OTP to users +template = "Your code is {{ .Code }} ." +# Controls the minimum amount of time that must pass before sending another sms otp. +max_frequency = "5s" + +# Use pre-defined map of phone number to OTP for testing. +# [auth.sms.test_otp] +# 4152127777 = "123456" + +# Configure logged in session timeouts. +# [auth.sessions] +# Force log out after the specified duration. +# timebox = "24h" +# Force log out if the user has been inactive longer than the specified duration. +# inactivity_timeout = "8h" + +# This hook runs before a token is issued and allows you to add additional claims based on the authentication method used. +# [auth.hook.custom_access_token] +# enabled = true +# uri = "pg-functions:////" + +# Configure one of the supported SMS providers: `twilio`, `twilio_verify`, `messagebird`, `textlocal`, `vonage`. +[auth.sms.twilio] +enabled = false +account_sid = "" +message_service_sid = "" +# DO NOT commit your Twilio auth token to git. Use environment variable substitution instead: +auth_token = "env(SUPABASE_AUTH_SMS_TWILIO_AUTH_TOKEN)" + +# Use an external OAuth provider. The full list of providers are: `apple`, `azure`, `bitbucket`, +# `discord`, `facebook`, `github`, `gitlab`, `google`, `keycloak`, `linkedin_oidc`, `notion`, `twitch`, +# `twitter`, `slack`, `spotify`, `workos`, `zoom`. +[auth.external.apple] +enabled = false +client_id = "" +# DO NOT commit your OAuth provider secret to git. Use environment variable substitution instead: +secret = "env(SUPABASE_AUTH_EXTERNAL_APPLE_SECRET)" +# Overrides the default auth redirectUrl. +redirect_uri = "" +# Overrides the default auth provider URL. Used to support self-hosted gitlab, single-tenant Azure, +# or any other third-party OIDC providers. +url = "" +# If enabled, the nonce check will be skipped. Required for local sign in with Google auth. +skip_nonce_check = false + +[edge_runtime] +enabled = true +# Configure one of the supported request policies: `oneshot`, `per_worker`. +# Use `oneshot` for hot reload, or `per_worker` for load testing. +policy = "oneshot" +inspector_port = 8083 + +[analytics] +enabled = true +port = 54327 +# Configure one of the supported backends: `postgres`, `bigquery`. +backend = "postgres" + +# Experimental features may be deprecated any time +[experimental] +# Configures Postgres storage engine to use OrioleDB (S3) +orioledb_version = "" +# Configures S3 bucket URL, eg. .s3-.amazonaws.com +s3_host = "env(S3_HOST)" +# Configures S3 bucket region, eg. us-east-1 +s3_region = "env(S3_REGION)" +# Configures AWS_ACCESS_KEY_ID for S3 bucket +s3_access_key = "env(S3_ACCESS_KEY)" +# Configures AWS_SECRET_ACCESS_KEY for S3 bucket +s3_secret_key = "env(S3_SECRET_KEY)" diff --git a/supabase/migrations/20241019162345_create_tables.sql b/supabase/migrations/20241019162345_create_tables.sql new file mode 100644 index 0000000..adcad21 --- /dev/null +++ b/supabase/migrations/20241019162345_create_tables.sql @@ -0,0 +1,62 @@ +-- Table: user_data +CREATE TABLE IF NOT EXISTS user_data ( + id uuid DEFAULT uuid_generate_v4() PRIMARY KEY, + updated_at timestamp with time zone DEFAULT now() NOT NULL, + username text NOT NULL, + avatar_url text, + email text NOT NULL, + phone text, + hashed_password text NOT NULL +); + +-- Table: direct_messages +CREATE TABLE IF NOT EXISTS direct_messages ( + id uuid DEFAULT uuid_generate_v4() PRIMARY KEY, + created_at timestamp with time zone DEFAULT now() NOT NULL, + dm_chats jsonb NOT NULL +); + +-- Table: chats_dm +CREATE TABLE IF NOT EXISTS chats_dm ( + id uuid DEFAULT uuid_generate_v4() PRIMARY KEY, + created_at timestamp with time zone DEFAULT now() NOT NULL, + messages jsonb NOT NULL +); + +-- Table: channels_messages +CREATE TABLE IF NOT EXISTS channels_messages ( + channel_id uuid DEFAULT uuid_generate_v4() PRIMARY KEY, + created_at timestamp with time zone DEFAULT now() NOT NULL, + messages jsonb NOT NULL, + channel_name text NOT NULL, + channel_members jsonb NOT NULL +); + +-- Table: channels_list +CREATE TABLE IF NOT EXISTS channels_list ( + id uuid DEFAULT uuid_generate_v4() PRIMARY KEY, + created_at timestamp with time zone DEFAULT now() NOT NULL, + channels jsonb NOT NULL +); + +-- Table: todo_list +CREATE TABLE IF NOT EXISTS todo_list ( + id uuid DEFAULT uuid_generate_v4() PRIMARY KEY, + created_at timestamp with time zone DEFAULT now() NOT NULL, + todo_list jsonb NOT NULL +); + +-- Table: mails_sent +CREATE TABLE IF NOT EXISTS mails_sent ( + task_id uuid DEFAULT uuid_generate_v4() PRIMARY KEY, + created_at timestamp with time zone DEFAULT now() NOT NULL, + last_sent text NOT NULL, + t_f boolean NOT NULL +); + +-- Table: channels_todolist +CREATE TABLE IF NOT EXISTS channels_todolist ( + id uuid DEFAULT uuid_generate_v4() PRIMARY KEY, + created_at timestamp with time zone DEFAULT now() NOT NULL, + todo_list jsonb NOT NULL +); diff --git a/supabase/seed.sql b/supabase/seed.sql new file mode 100644 index 0000000..e69de29 From 6635af3fa2ee2414a25f6bda1746d4063dce7a62 Mon Sep 17 00:00:00 2001 From: Muhammad Younus Raza <48213629+younusraza909@users.noreply.github.com> Date: Mon, 21 Oct 2024 10:39:57 +0500 Subject: [PATCH 2/3] Updated triggers , Change RSL and real time setting as in updated readme file --- .../20241019162345_create_tables.sql | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/supabase/migrations/20241019162345_create_tables.sql b/supabase/migrations/20241019162345_create_tables.sql index adcad21..8b00d1c 100644 --- a/supabase/migrations/20241019162345_create_tables.sql +++ b/supabase/migrations/20241019162345_create_tables.sql @@ -1,3 +1,6 @@ +-- Enable uuid generation extension (if not enabled) +CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; + -- Table: user_data CREATE TABLE IF NOT EXISTS user_data ( id uuid DEFAULT uuid_generate_v4() PRIMARY KEY, @@ -9,6 +12,10 @@ CREATE TABLE IF NOT EXISTS user_data ( hashed_password text NOT NULL ); +-- Disable RLS and Enable Realtime for user_data +ALTER TABLE user_data ENABLE REPLICA TRIGGER ALL; +ALTER TABLE user_data DISABLE ROW LEVEL SECURITY; + -- Table: direct_messages CREATE TABLE IF NOT EXISTS direct_messages ( id uuid DEFAULT uuid_generate_v4() PRIMARY KEY, @@ -16,6 +23,10 @@ CREATE TABLE IF NOT EXISTS direct_messages ( dm_chats jsonb NOT NULL ); +-- Disable RLS and Enable Realtime for direct_messages +ALTER TABLE direct_messages ENABLE REPLICA TRIGGER ALL; +ALTER TABLE direct_messages DISABLE ROW LEVEL SECURITY; + -- Table: chats_dm CREATE TABLE IF NOT EXISTS chats_dm ( id uuid DEFAULT uuid_generate_v4() PRIMARY KEY, @@ -23,6 +34,10 @@ CREATE TABLE IF NOT EXISTS chats_dm ( messages jsonb NOT NULL ); +-- Disable RLS and Enable Realtime for chats_dm +ALTER TABLE chats_dm ENABLE REPLICA TRIGGER ALL; +ALTER TABLE chats_dm DISABLE ROW LEVEL SECURITY; + -- Table: channels_messages CREATE TABLE IF NOT EXISTS channels_messages ( channel_id uuid DEFAULT uuid_generate_v4() PRIMARY KEY, @@ -32,6 +47,10 @@ CREATE TABLE IF NOT EXISTS channels_messages ( channel_members jsonb NOT NULL ); +-- Disable RLS and Enable Realtime for channels_messages +ALTER TABLE channels_messages ENABLE REPLICA TRIGGER ALL; +ALTER TABLE channels_messages DISABLE ROW LEVEL SECURITY; + -- Table: channels_list CREATE TABLE IF NOT EXISTS channels_list ( id uuid DEFAULT uuid_generate_v4() PRIMARY KEY, @@ -39,6 +58,10 @@ CREATE TABLE IF NOT EXISTS channels_list ( channels jsonb NOT NULL ); +-- Disable RLS and Enable Realtime for channels_list +ALTER TABLE channels_list ENABLE REPLICA TRIGGER ALL; +ALTER TABLE channels_list DISABLE ROW LEVEL SECURITY; + -- Table: todo_list CREATE TABLE IF NOT EXISTS todo_list ( id uuid DEFAULT uuid_generate_v4() PRIMARY KEY, @@ -46,6 +69,10 @@ CREATE TABLE IF NOT EXISTS todo_list ( todo_list jsonb NOT NULL ); +-- Disable RLS and Enable Realtime for todo_list +ALTER TABLE todo_list ENABLE REPLICA TRIGGER ALL; +ALTER TABLE todo_list DISABLE ROW LEVEL SECURITY; + -- Table: mails_sent CREATE TABLE IF NOT EXISTS mails_sent ( task_id uuid DEFAULT uuid_generate_v4() PRIMARY KEY, @@ -54,9 +81,58 @@ CREATE TABLE IF NOT EXISTS mails_sent ( t_f boolean NOT NULL ); +-- Disable RLS and Enable Realtime for mails_sent +ALTER TABLE mails_sent ENABLE REPLICA TRIGGER ALL; +ALTER TABLE mails_sent DISABLE ROW LEVEL SECURITY; + -- Table: channels_todolist CREATE TABLE IF NOT EXISTS channels_todolist ( id uuid DEFAULT uuid_generate_v4() PRIMARY KEY, created_at timestamp with time zone DEFAULT now() NOT NULL, todo_list jsonb NOT NULL ); + +-- Disable RLS and Enable Realtime for channels_todolist +ALTER TABLE channels_todolist ENABLE REPLICA TRIGGER ALL; +ALTER TABLE channels_todolist DISABLE ROW LEVEL SECURITY; + +-- Trigger function for handling new user sign-up +CREATE OR REPLACE FUNCTION public.handle_new_user() +RETURNS TRIGGER AS $$ +BEGIN + INSERT INTO public.user_data (id, username, avatar_url, email, phone) + VALUES ( + NEW.id, + NEW.raw_user_meta_data->>'username', + NEW.raw_user_meta_data->>'avatar_url', + NEW.email, + NEW.raw_user_meta_data->>'phone' + ); + RETURN NEW; +END; +$$ LANGUAGE plpgsql SECURITY DEFINER; + +-- Create trigger for new user sign-up +CREATE TRIGGER on_auth_user_created +AFTER INSERT ON auth.users +FOR EACH ROW EXECUTE FUNCTION public.handle_new_user(); + +-- Trigger function to update channel members in channels_list +CREATE OR REPLACE FUNCTION public.handle_channel_member_add() +RETURNS TRIGGER AS $$ +BEGIN + UPDATE channels_list + SET channels = jsonb_set( + channels_list.channels, + '{members}', + coalesce(channels_list.channels->'members', '[]'::jsonb) || to_jsonb(NEW) + ) + WHERE id = NEW.channel_id; + RETURN NEW; +END; +$$ LANGUAGE plpgsql SECURITY DEFINER; + +-- Create trigger to invoke handle_channel_member_add() on new member insert +CREATE TRIGGER on_channel_member_added +AFTER INSERT ON channels_messages +FOR EACH ROW EXECUTE FUNCTION public.handle_channel_member_add(); From 0202d13357850a767f6fbb3f88d193f8778c0669 Mon Sep 17 00:00:00 2001 From: Muhammad Younus Raza <48213629+younusraza909@users.noreply.github.com> Date: Wed, 23 Oct 2024 10:49:11 +0500 Subject: [PATCH 3/3] added more checks --- .../migrations/20241019162345_create_tables.sql | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/supabase/migrations/20241019162345_create_tables.sql b/supabase/migrations/20241019162345_create_tables.sql index 8b00d1c..83fa836 100644 --- a/supabase/migrations/20241019162345_create_tables.sql +++ b/supabase/migrations/20241019162345_create_tables.sql @@ -9,7 +9,7 @@ CREATE TABLE IF NOT EXISTS user_data ( avatar_url text, email text NOT NULL, phone text, - hashed_password text NOT NULL + hashed_password text -- Allow NULL to avoid trigger failure if not set initially ); -- Disable RLS and Enable Realtime for user_data @@ -40,7 +40,7 @@ ALTER TABLE chats_dm DISABLE ROW LEVEL SECURITY; -- Table: channels_messages CREATE TABLE IF NOT EXISTS channels_messages ( - channel_id uuid DEFAULT uuid_generate_v4() PRIMARY KEY, + id uuid DEFAULT uuid_generate_v4() PRIMARY KEY, created_at timestamp with time zone DEFAULT now() NOT NULL, messages jsonb NOT NULL, channel_name text NOT NULL, @@ -100,13 +100,14 @@ ALTER TABLE channels_todolist DISABLE ROW LEVEL SECURITY; CREATE OR REPLACE FUNCTION public.handle_new_user() RETURNS TRIGGER AS $$ BEGIN - INSERT INTO public.user_data (id, username, avatar_url, email, phone) + INSERT INTO public.user_data (id, username, avatar_url, email, phone, hashed_password) VALUES ( NEW.id, NEW.raw_user_meta_data->>'username', NEW.raw_user_meta_data->>'avatar_url', NEW.email, - NEW.raw_user_meta_data->>'phone' + NEW.raw_user_meta_data->>'phone', + 'default_password_hash' -- Placeholder value to avoid NULL issues ); RETURN NEW; END; @@ -125,7 +126,10 @@ BEGIN SET channels = jsonb_set( channels_list.channels, '{members}', - coalesce(channels_list.channels->'members', '[]'::jsonb) || to_jsonb(NEW) + coalesce( + channels_list.channels->'members', + '[]'::jsonb + ) || to_jsonb(NEW) ) WHERE id = NEW.channel_id; RETURN NEW;