From 50e89f90c9f264ac93cc6882743e21ed70a9f011 Mon Sep 17 00:00:00 2001 From: Rotimi Best Date: Mon, 21 Apr 2025 01:01:23 +0100 Subject: [PATCH] Revert "db: squash migrations" This reverts commit d010531ef7932dc3093621f1771abb90c0b14368. --- packages/svelte-ui/components/button.svelte | 11 + packages/svelte-ui/index.ts | 0 packages/svelte-ui/package.json | 17 + .../20231115082347_remote_schema.sql | 1285 ++++++++ .../migrations/20231118210545_profile.sql | 1 + .../20231207061507_update_get_courses.sql | 22 + .../20231213104402_course_metadata.sql | 1 + ...1_organizationmember_author_profile_id.sql | 11 + .../20240212090837_course_newsfeed.sql | 48 + ...855_add_courseid_to_community_question.sql | 20 + .../20240320081809_email_verification.sql | 6 + .../migrations/20240323154037_translation.sql | 13 + .../migrations/20240406215136_org_billing.sql | 26 + .../migrations/20240509080635_ai_grading.sql | 1 + .../20240516092053_customization.sql | 1 + .../migrations/20240516153823_course_type.sql | 37 + .../20240518054308_new_certificates.sql | 31 + .../20240524192915_get_courses_for_admin.sql | 31 + .../20240528050512_cascade_delete_lesson.sql | 47 + ...40610132742_lesson_language_versioning.sql | 25 + .../20240618210526_lesson_versions.sql | 7 + .../20240701085652_show_explore_courses.sql | 17 + supabase/migrations/20240717053936_rls.sql | 1321 +++++++++ .../20240718200323_rls_auth_fix.sql | 8 + .../20240720100738_fix_autosave_lesson.sql | 59 + .../20240811123634_lesson_section.sql | 145 + .../20240824193502_restrict_accounts.sql | 27 + .../20240904050707_custom_domain.sql | 11 + ...907090948_open_orgplan_for_landingpage.sql | 8 + .../20241016235827_student_analytics.sql | 125 + ...241223012712_validate_mark_as_complete.sql | 18 + .../20241231154543_dashboard_stats.sql | 80 + .../20250106020355_base_migration.sql | 2603 ----------------- .../migrations/20250106020355_polar_setup.sql | 7 + 34 files changed, 3467 insertions(+), 2603 deletions(-) create mode 100644 packages/svelte-ui/components/button.svelte create mode 100644 packages/svelte-ui/index.ts create mode 100644 packages/svelte-ui/package.json create mode 100644 supabase/migrations/20231115082347_remote_schema.sql create mode 100644 supabase/migrations/20231118210545_profile.sql create mode 100644 supabase/migrations/20231207061507_update_get_courses.sql create mode 100644 supabase/migrations/20231213104402_course_metadata.sql create mode 100644 supabase/migrations/20231213105201_organizationmember_author_profile_id.sql create mode 100644 supabase/migrations/20240212090837_course_newsfeed.sql create mode 100644 supabase/migrations/20240212110855_add_courseid_to_community_question.sql create mode 100644 supabase/migrations/20240320081809_email_verification.sql create mode 100644 supabase/migrations/20240323154037_translation.sql create mode 100644 supabase/migrations/20240406215136_org_billing.sql create mode 100644 supabase/migrations/20240509080635_ai_grading.sql create mode 100644 supabase/migrations/20240516092053_customization.sql create mode 100644 supabase/migrations/20240516153823_course_type.sql create mode 100644 supabase/migrations/20240518054308_new_certificates.sql create mode 100644 supabase/migrations/20240524192915_get_courses_for_admin.sql create mode 100644 supabase/migrations/20240528050512_cascade_delete_lesson.sql create mode 100644 supabase/migrations/20240610132742_lesson_language_versioning.sql create mode 100644 supabase/migrations/20240618210526_lesson_versions.sql create mode 100644 supabase/migrations/20240701085652_show_explore_courses.sql create mode 100644 supabase/migrations/20240717053936_rls.sql create mode 100644 supabase/migrations/20240718200323_rls_auth_fix.sql create mode 100644 supabase/migrations/20240720100738_fix_autosave_lesson.sql create mode 100644 supabase/migrations/20240811123634_lesson_section.sql create mode 100644 supabase/migrations/20240824193502_restrict_accounts.sql create mode 100644 supabase/migrations/20240904050707_custom_domain.sql create mode 100644 supabase/migrations/20240907090948_open_orgplan_for_landingpage.sql create mode 100644 supabase/migrations/20241016235827_student_analytics.sql create mode 100644 supabase/migrations/20241223012712_validate_mark_as_complete.sql create mode 100644 supabase/migrations/20241231154543_dashboard_stats.sql delete mode 100644 supabase/migrations/20250106020355_base_migration.sql create mode 100644 supabase/migrations/20250106020355_polar_setup.sql diff --git a/packages/svelte-ui/components/button.svelte b/packages/svelte-ui/components/button.svelte new file mode 100644 index 00000000..054375df --- /dev/null +++ b/packages/svelte-ui/components/button.svelte @@ -0,0 +1,11 @@ + + + diff --git a/packages/svelte-ui/index.ts b/packages/svelte-ui/index.ts new file mode 100644 index 00000000..e69de29b diff --git a/packages/svelte-ui/package.json b/packages/svelte-ui/package.json new file mode 100644 index 00000000..66d514f5 --- /dev/null +++ b/packages/svelte-ui/package.json @@ -0,0 +1,17 @@ +{ + "name": "svelte-ui", + "version": "0.0.0", + "description": "Styles and components for use in svelte websites", + "main": "index.js", + "scripts": { + "lint": "prettier --check --ignore-path=../../.prettierignore .", + "format": "prettier --write --ignore-path=../../.prettierignore ." + }, + "devDependencies": { + "eslint-config-custom": "workspace:*", + "svelte": "^3.9.2" + }, + "keywords": [], + "author": "", + "license": "MIT" +} diff --git a/supabase/migrations/20231115082347_remote_schema.sql b/supabase/migrations/20231115082347_remote_schema.sql new file mode 100644 index 00000000..deb238d4 --- /dev/null +++ b/supabase/migrations/20231115082347_remote_schema.sql @@ -0,0 +1,1285 @@ + +SET statement_timeout = 0; +SET lock_timeout = 0; +SET idle_in_transaction_session_timeout = 0; +SET client_encoding = 'UTF8'; +SET standard_conforming_strings = on; +SELECT pg_catalog.set_config('search_path', '', false); +SET check_function_bodies = false; +SET xmloption = content; +SET client_min_messages = warning; +SET row_security = off; + +CREATE EXTENSION IF NOT EXISTS "pg_net" WITH SCHEMA "extensions"; + +CREATE EXTENSION IF NOT EXISTS "pgsodium" WITH SCHEMA "pgsodium"; + +ALTER SCHEMA "public" OWNER TO "postgres"; + +CREATE EXTENSION IF NOT EXISTS "moddatetime" WITH SCHEMA "extensions"; + +CREATE EXTENSION IF NOT EXISTS "pg_graphql" WITH SCHEMA "graphql"; + +CREATE EXTENSION IF NOT EXISTS "pg_stat_statements" WITH SCHEMA "extensions"; + +CREATE EXTENSION IF NOT EXISTS "pgcrypto" WITH SCHEMA "extensions"; + +CREATE EXTENSION IF NOT EXISTS "pgjwt" WITH SCHEMA "extensions"; + +CREATE EXTENSION IF NOT EXISTS "supabase_vault" WITH SCHEMA "vault"; + +CREATE EXTENSION IF NOT EXISTS "uuid-ossp" WITH SCHEMA "extensions"; + +CREATE EXTENSION IF NOT EXISTS "vector" WITH SCHEMA "extensions"; + +CREATE OR REPLACE FUNCTION "public"."add_them"("a" integer, "b" integer) RETURNS integer + LANGUAGE "sql" IMMUTABLE + AS $$ + SELECT a + b; +$$; + +ALTER FUNCTION "public"."add_them"("a" integer, "b" integer) OWNER TO "postgres"; + +CREATE OR REPLACE FUNCTION "public"."get_courses"("org_id_arg" "uuid", "profile_id_arg" "uuid") RETURNS TABLE("id" "uuid", "org_id" "uuid", "title" character varying, "slug" character varying, "description" character varying, "logo" "text", "banner_image" "text", "cost" bigint, "currency" character varying, "is_published" boolean, "profile_id" "uuid", "role_id" bigint, "total_lessons" bigint, "progress_rate" bigint) + LANGUAGE "plpgsql" + AS $$ +BEGIN + Return query + select course.id, organization.id AS org_id, course.title, course.slug, course.description, course.logo, course.banner_image, course.cost, course.currency, course.is_published, groupmember.profile_id, groupmember.role_id, (select COUNT(*) from lesson as l where l.course_id = course.id) AS total_lessons, (select COUNT(*) from lesson_completion as lc join lesson as l on l.id = lc.lesson_id where l.course_id = course.id and lc.is_complete = true and lc.profile_id = profile_id_arg) AS progress_rate + from course + join "group" on "group".id = course.group_id + join groupmember on groupmember.group_id = course.group_id + join organization on organization.id = "group".organization_id + where course.status = 'ACTIVE' AND organization.id = org_id_arg + -- GROUP BY course.id, groupmember.profile_id + ORDER BY course.created_at DESC; +END; +$$; + +ALTER FUNCTION "public"."get_courses"("org_id_arg" "uuid", "profile_id_arg" "uuid") OWNER TO "postgres"; + +CREATE OR REPLACE FUNCTION "public"."get_exercises"() RETURNS TABLE("course_id" "uuid", "lesson_id" "uuid", "exercise_id" "uuid", "exercise_title" character varying, "points" integer) + LANGUAGE "plpgsql" + AS $$ +BEGIN + Return query + select lesson.course_id course_id, lesson.id lesson_id, exercise.id exercise_id, exercise.title exercise_title, sum(question.points)::int points + from exercise + join lesson on exercise.lesson_id = lesson.id + right join question on question.exercise_id = exercise.id + GROUP BY lesson.course_id, lesson.id, exercise.id, exercise.title + ORDER BY lesson.created_at ASC; +END; +$$; + +ALTER FUNCTION "public"."get_exercises"() OWNER TO "postgres"; + +CREATE OR REPLACE FUNCTION "public"."get_marks"() RETURNS TABLE("course_id" "uuid", "exercise_id" "uuid", "exercise_title" character varying, "exercise_points" integer, "lesson_id" "uuid", "lesson_title" character varying, "status_id" bigint, "total_points_gotten" bigint, "groupmember_id" "uuid", "fullname" "text", "assigned_student_id" character varying, "avatar_url" "text") + LANGUAGE "plpgsql" + AS $$ +BEGIN + Return query + select lesson.course_id course_id, exercise.id exercise_id, exercise.title exercise_title, sum(question.points)::int exercise_points, lesson.id lesson_id, lesson.title lesson_title, submission.status_id, submission.total total_points_gotten, submission.submitted_by groupmember_id, profile.fullname, groupmember.assigned_student_id, profile.avatar_url + from exercise + join lesson on exercise.lesson_id = lesson.id + left join submission on exercise.id = submission.exercise_id + join groupmember on groupmember.id = submission.submitted_by + right join question on question.exercise_id = exercise.id + join profile on profile.id = groupmember.profile_id + GROUP BY exercise.id, lesson.id, submission.status_id, submission.total, submission.submitted_by, profile.fullname, groupmember.assigned_student_id, profile.avatar_url + ORDER BY lesson.created_at ASC; +END; +$$; + +ALTER FUNCTION "public"."get_marks"() OWNER TO "postgres"; + +CREATE OR REPLACE FUNCTION "public"."get_student_exercises"("org_id_arg" "uuid", "profile_id_arg" "uuid") RETURNS TABLE("exercise_id" "uuid", "exercise_title" character varying, "lesson_id" "uuid", "lesson_title" character varying, "status_id" integer, "total" integer) + LANGUAGE "plpgsql" + AS $$ +BEGIN + Return query + select exercise.id as exercise_id, exercise.title as exercise_title, lesson.id as lesson_id, lesson.title as lesson_title, submission.status_id, submission.total + from exercise + inner join lesson on lesson.id = exercise.lesson_id + inner join course on course.id = lesson.course_id + inner join "group" on "group".id = course.group_id + inner join organization on "group".organization_id = organization.id + inner join groupmember on groupmember.group_id = course.group_id + inner join profile on groupmember.profile_id = profile.id + left join submission on submission.submitted_by = groupmember.id + where course.status = 'ACTIVE' AND organization.id = org_id_arg AND profile.id = profile_id_arg; +END; +$$; + +ALTER FUNCTION "public"."get_student_exercises"("org_id_arg" "uuid", "profile_id_arg" "uuid") OWNER TO "postgres"; + +CREATE OR REPLACE FUNCTION "public"."get_user_upcoming_lessons"("profile_id_arg" "uuid", "org_id_arg" "uuid") RETURNS TABLE("course_id" "uuid", "course_title" character varying, "lesson_id" "uuid", "lesson_title" character varying, "call_url" "text", "lesson_at" timestamp with time zone, "is_complete" boolean) + LANGUAGE "plpgsql" + AS $$ +BEGIN + Return query + select course.id course_id, course.title course_title, lesson.id lesson_id, lesson.title lesson_title, lesson.call_url call_url, lesson.lesson_at lesson_at, lesson.is_complete is_complete + from lesson + join course on course.id = lesson.course_id + join "group" on "group".id = course.group_id + join groupmember on groupmember.group_id = course.group_id + where course.status = 'ACTIVE' AND groupmember.profile_id = profile_id_arg AND "group".organization_id = org_id_arg + ORDER BY lesson_at ASC; +END +$$; + +ALTER FUNCTION "public"."get_user_upcoming_lessons"("profile_id_arg" "uuid", "org_id_arg" "uuid") OWNER TO "postgres"; + +SET default_tablespace = ''; + +SET default_table_access_method = "heap"; + +CREATE TABLE IF NOT EXISTS "public"."apps_poll" ( + "id" "uuid" DEFAULT "gen_random_uuid"() NOT NULL, + "created_at" timestamp with time zone DEFAULT "now"() NOT NULL, + "updated_at" timestamp with time zone DEFAULT "now"(), + "question" "text", + "authorId" "uuid", + "isPublic" boolean, + "status" character varying DEFAULT 'draft'::character varying, + "expiration" timestamp with time zone, + "courseId" "uuid" +); + +ALTER TABLE "public"."apps_poll" OWNER TO "postgres"; + +CREATE TABLE IF NOT EXISTS "public"."apps_poll_option" ( + "id" bigint NOT NULL, + "created_at" timestamp with time zone DEFAULT "now"() NOT NULL, + "updated_at" timestamp with time zone, + "poll_id" "uuid", + "label" character varying +); + +ALTER TABLE "public"."apps_poll_option" OWNER TO "postgres"; + +ALTER TABLE "public"."apps_poll_option" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY ( + SEQUENCE NAME "public"."apps_poll_option_id_seq" + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1 +); + +CREATE TABLE IF NOT EXISTS "public"."apps_poll_submission" ( + "id" bigint NOT NULL, + "created_at" timestamp with time zone DEFAULT "now"() NOT NULL, + "poll_option_id" bigint, + "selected_by_id" "uuid", + "poll_id" "uuid" +); + +ALTER TABLE "public"."apps_poll_submission" OWNER TO "postgres"; + +ALTER TABLE "public"."apps_poll_submission" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY ( + SEQUENCE NAME "public"."apps_poll_submision_id_seq" + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1 +); + +CREATE TABLE IF NOT EXISTS "public"."community_answer" ( + "id" "uuid" DEFAULT "extensions"."gen_random_uuid"() NOT NULL, + "created_at" timestamp with time zone DEFAULT "now"(), + "question_id" bigint, + "body" character varying, + "author_id" bigint, + "votes" bigint +); + +ALTER TABLE "public"."community_answer" OWNER TO "postgres"; + +CREATE TABLE IF NOT EXISTS "public"."community_question" ( + "id" bigint NOT NULL, + "created_at" timestamp with time zone DEFAULT "now"(), + "title" character varying, + "body" "text", + "author_id" bigint, + "votes" bigint DEFAULT '0'::bigint, + "organization_id" "uuid", + "slug" "text" +); + +ALTER TABLE "public"."community_question" OWNER TO "postgres"; + +ALTER TABLE "public"."community_question" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY ( + SEQUENCE NAME "public"."community_question_id_seq" + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1 +); + +CREATE TABLE IF NOT EXISTS "public"."course" ( + "title" character varying NOT NULL, + "description" character varying NOT NULL, + "overview" character varying DEFAULT 'Welcome to this amazing course 🚀 '::character varying, + "id" "uuid" DEFAULT "extensions"."uuid_generate_v4"() NOT NULL, + "created_at" timestamp with time zone DEFAULT "now"(), + "updated_at" timestamp with time zone DEFAULT "now"(), + "group_id" "uuid", + "is_template" boolean DEFAULT true, + "logo" "text" DEFAULT ''::"text" NOT NULL, + "slug" character varying, + "metadata" "jsonb" DEFAULT '{"goals": "", "description": "", "requirements": ""}'::"jsonb" NOT NULL, + "cost" bigint DEFAULT '0'::bigint, + "currency" character varying DEFAULT 'NGN'::character varying NOT NULL, + "banner_image" "text", + "is_published" boolean DEFAULT false, + "is_certificate_downloadable" boolean DEFAULT false, + "certificate_theme" "text", + "status" "text" DEFAULT 'ACTIVE'::"text" NOT NULL +); + +ALTER TABLE "public"."course" OWNER TO "postgres"; + +CREATE TABLE IF NOT EXISTS "public"."currency" ( + "id" bigint NOT NULL, + "created_at" timestamp with time zone DEFAULT "now"(), + "name" character varying +); + +ALTER TABLE "public"."currency" OWNER TO "postgres"; + +ALTER TABLE "public"."currency" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY ( + SEQUENCE NAME "public"."currency_id_seq" + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1 +); + +CREATE TABLE IF NOT EXISTS "public"."exercise" ( + "title" character varying NOT NULL, + "description" character varying, + "lesson_id" "uuid", + "created_at" timestamp with time zone DEFAULT "now"(), + "updated_at" timestamp with time zone DEFAULT "now"(), + "id" "uuid" DEFAULT "extensions"."uuid_generate_v4"() NOT NULL, + "due_by" timestamp without time zone +); + +ALTER TABLE "public"."exercise" OWNER TO "postgres"; + +CREATE TABLE IF NOT EXISTS "public"."group" ( + "id" "uuid" DEFAULT "extensions"."uuid_generate_v4"() NOT NULL, + "name" character varying NOT NULL, + "description" "text", + "created_at" timestamp with time zone DEFAULT "now"(), + "updated_at" timestamp with time zone DEFAULT "now"(), + "organization_id" "uuid" +); + +ALTER TABLE "public"."group" OWNER TO "postgres"; + +CREATE TABLE IF NOT EXISTS "public"."group_attendance" ( + "id" bigint NOT NULL, + "created_at" timestamp with time zone DEFAULT "now"(), + "updated_at" timestamp with time zone DEFAULT "now"(), + "course_id" "uuid", + "student_id" "uuid", + "is_present" boolean DEFAULT false, + "lesson_id" "uuid" NOT NULL +); + +ALTER TABLE "public"."group_attendance" OWNER TO "postgres"; + +ALTER TABLE "public"."group_attendance" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY ( + SEQUENCE NAME "public"."group_attendance_id_seq" + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1 +); + +CREATE TABLE IF NOT EXISTS "public"."groupmember" ( + "id" "uuid" DEFAULT "extensions"."uuid_generate_v4"() NOT NULL, + "group_id" "uuid" NOT NULL, + "role_id" bigint NOT NULL, + "profile_id" "uuid", + "email" character varying, + "created_at" timestamp with time zone DEFAULT "now"(), + "assigned_student_id" character varying +); + +ALTER TABLE "public"."groupmember" OWNER TO "postgres"; + +CREATE TABLE IF NOT EXISTS "public"."lesson" ( + "note" character varying, + "video_url" character varying, + "slide_url" character varying, + "course_id" "uuid" NOT NULL, + "id" "uuid" DEFAULT "extensions"."uuid_generate_v4"() NOT NULL, + "created_at" timestamp with time zone DEFAULT "now"(), + "updated_at" timestamp with time zone DEFAULT "now"(), + "title" character varying NOT NULL, + "public" boolean DEFAULT false, + "lesson_at" timestamp with time zone DEFAULT "now"(), + "teacher_id" "uuid", + "is_complete" boolean DEFAULT false, + "call_url" "text", + "order" bigint, + "is_unlocked" boolean DEFAULT false, + "videos" "jsonb" DEFAULT '[]'::"jsonb" +); + +ALTER TABLE "public"."lesson" OWNER TO "postgres"; + +CREATE TABLE IF NOT EXISTS "public"."lesson_comment" ( + "id" bigint NOT NULL, + "created_at" timestamp with time zone DEFAULT "now"() NOT NULL, + "updated_at" timestamp with time zone DEFAULT "now"(), + "lesson_id" "uuid", + "groupmember_id" "uuid", + "comment" "text" +); + +ALTER TABLE "public"."lesson_comment" OWNER TO "postgres"; + +ALTER TABLE "public"."lesson_comment" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY ( + SEQUENCE NAME "public"."lesson_comment_id_seq" + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1 +); + +CREATE TABLE IF NOT EXISTS "public"."lesson_completion" ( + "id" bigint NOT NULL, + "created_at" timestamp with time zone DEFAULT "now"() NOT NULL, + "lesson_id" "uuid", + "profile_id" "uuid", + "is_complete" boolean DEFAULT false, + "updated_at" timestamp with time zone DEFAULT "now"() +); + +ALTER TABLE "public"."lesson_completion" OWNER TO "postgres"; + +ALTER TABLE "public"."lesson_completion" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY ( + SEQUENCE NAME "public"."lesson_completion_id_seq" + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1 +); + +CREATE TABLE IF NOT EXISTS "public"."option" ( + "id" bigint NOT NULL, + "label" character varying NOT NULL, + "is_correct" boolean DEFAULT false NOT NULL, + "question_id" bigint NOT NULL, + "value" "uuid" DEFAULT "extensions"."gen_random_uuid"(), + "created_at" timestamp with time zone DEFAULT "now"(), + "updated_at" timestamp with time zone DEFAULT "now"() +); + +ALTER TABLE "public"."option" OWNER TO "postgres"; + +ALTER TABLE "public"."option" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY ( + SEQUENCE NAME "public"."option_id_seq" + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1 +); + +CREATE TABLE IF NOT EXISTS "public"."organization" ( + "id" "uuid" DEFAULT "extensions"."uuid_generate_v4"() NOT NULL, + "name" character varying NOT NULL, + "siteName" "text", + "avatar_url" "text", + "settings" "jsonb" DEFAULT '{}'::"jsonb", + "landingpage" "jsonb" DEFAULT '{}'::"jsonb", + "theme" "text", + "created_at" timestamp with time zone DEFAULT "timezone"('utc'::"text", "now"()) NOT NULL +); + +ALTER TABLE "public"."organization" OWNER TO "postgres"; + +CREATE TABLE IF NOT EXISTS "public"."organization_contacts" ( + "id" bigint NOT NULL, + "created_at" timestamp with time zone DEFAULT "now"() NOT NULL, + "email" "text", + "phone" "text", + "name" "text", + "message" "text", + "organization_id" "uuid" +); + +ALTER TABLE "public"."organization_contacts" OWNER TO "postgres"; + +ALTER TABLE "public"."organization_contacts" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY ( + SEQUENCE NAME "public"."organization_contacts_id_seq" + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1 +); + +CREATE TABLE IF NOT EXISTS "public"."organization_emaillist" ( + "id" bigint NOT NULL, + "created_at" timestamp with time zone DEFAULT "now"() NOT NULL, + "email" "text", + "organization_id" "uuid" +); + +ALTER TABLE "public"."organization_emaillist" OWNER TO "postgres"; + +ALTER TABLE "public"."organization_emaillist" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY ( + SEQUENCE NAME "public"."organization_emaillist_id_seq" + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1 +); + +CREATE TABLE IF NOT EXISTS "public"."organizationmember" ( + "id" bigint NOT NULL, + "organization_id" "uuid" NOT NULL, + "role_id" bigint NOT NULL, + "profile_id" "uuid", + "email" "text", + "verified" boolean DEFAULT false, + "created_at" timestamp with time zone DEFAULT "timezone"('utc'::"text", "now"()) NOT NULL +); + +ALTER TABLE "public"."organizationmember" OWNER TO "postgres"; + +ALTER TABLE "public"."organizationmember" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY ( + SEQUENCE NAME "public"."organizationmember_id_seq" + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1 +); + +CREATE TABLE IF NOT EXISTS "public"."quiz_play" ( + "id" bigint NOT NULL, + "created_at" timestamp with time zone DEFAULT "now"(), + "updated_at" timestamp with time zone DEFAULT "now"(), + "quiz_id" "uuid", + "players" "json" DEFAULT '[]'::"json", + "started" boolean DEFAULT false, + "currentQuestionId" bigint DEFAULT '0'::bigint, + "showCurrentQuestionAnswer" boolean DEFAULT false, + "isLastQuestion" boolean, + "step" "text" DEFAULT 'CONNECT_TO_PLAY'::"text", + "studentStep" "text" DEFAULT 'PIN_SETUP'::"text", + "pin" "text" +); + +ALTER TABLE "public"."quiz_play" OWNER TO "postgres"; + +ALTER TABLE "public"."quiz_play" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY ( + SEQUENCE NAME "public"."play_quiz_id_seq" + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1 +); + +CREATE TABLE IF NOT EXISTS "public"."profile" ( + "id" "uuid" NOT NULL, + "fullname" "text" NOT NULL, + "username" "text" NOT NULL, + "avatar_url" "text" NULL DEFAULT ''::"text", + "created_at" timestamp with time zone DEFAULT "now"(), + "updated_at" timestamp with time zone DEFAULT "now"(), + "email" character varying, + "can_add_course" boolean DEFAULT true, + "role" character varying, + "goal" character varying, + "source" character varying, + "metadata" "json", + "telegram_chat_id" bigint +); + +ALTER TABLE "public"."profile" OWNER TO "postgres"; + +CREATE TABLE IF NOT EXISTS "public"."question" ( + "id" bigint NOT NULL, + "question_type_id" bigint NOT NULL, + "title" character varying NOT NULL, + "created_at" timestamp with time zone DEFAULT "now"(), + "updated_at" timestamp with time zone DEFAULT "now"(), + "exercise_id" "uuid" NOT NULL, + "name" "uuid" DEFAULT "extensions"."gen_random_uuid"(), + "points" double precision, + "order" bigint +); + +ALTER TABLE "public"."question" OWNER TO "postgres"; + +CREATE TABLE IF NOT EXISTS "public"."question_answer" ( + "id" bigint NOT NULL, + "answers" character varying[], + "question_id" bigint NOT NULL, + "open_answer" "text", + "group_member_id" "uuid" NOT NULL, + "submission_id" "uuid", + "point" bigint DEFAULT '0'::bigint +); + +ALTER TABLE "public"."question_answer" OWNER TO "postgres"; + +ALTER TABLE "public"."question_answer" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY ( + SEQUENCE NAME "public"."question_answer_id_seq" + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1 +); + +ALTER TABLE "public"."question" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY ( + SEQUENCE NAME "public"."question_id_seq" + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1 +); + +CREATE TABLE IF NOT EXISTS "public"."question_type" ( + "id" bigint NOT NULL, + "label" character varying NOT NULL, + "created_at" timestamp with time zone DEFAULT "now"(), + "updated_at" timestamp with time zone DEFAULT "now"(), + "typename" character varying +); + +ALTER TABLE "public"."question_type" OWNER TO "postgres"; + +ALTER TABLE "public"."question_type" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY ( + SEQUENCE NAME "public"."question_type_id_seq" + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1 +); + +CREATE TABLE IF NOT EXISTS "public"."quiz" ( + "id" "uuid" DEFAULT "extensions"."gen_random_uuid"() NOT NULL, + "created_at" timestamp with time zone DEFAULT "now"(), + "updated_at" timestamp with time zone DEFAULT "now"(), + "title" "text", + "questions" "json", + "timelimit" character varying DEFAULT '10s'::character varying, + "theme" character varying DEFAULT 'standard'::character varying, + "organization_id" "uuid" NOT NULL +); + +ALTER TABLE "public"."quiz" OWNER TO "postgres"; + +CREATE TABLE IF NOT EXISTS "public"."role" ( + "type" character varying NOT NULL, + "description" character varying, + "id" bigint NOT NULL, + "updated_at" timestamp with time zone DEFAULT "now"(), + "created_at" timestamp with time zone DEFAULT "now"() +); + +ALTER TABLE "public"."role" OWNER TO "postgres"; + +ALTER TABLE "public"."role" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY ( + SEQUENCE NAME "public"."role_id_seq" + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1 +); + +CREATE TABLE IF NOT EXISTS "public"."submission" ( + "id" "uuid" DEFAULT "extensions"."uuid_generate_v4"() NOT NULL, + "reviewer_id" bigint, + "status_id" bigint DEFAULT '1'::bigint, + "total" bigint DEFAULT '0'::bigint, + "created_at" timestamp with time zone DEFAULT "now"(), + "updated_at" timestamp with time zone DEFAULT "now"(), + "exercise_id" "uuid" NOT NULL, + "submitted_by" "uuid", + "course_id" "uuid" +); + +ALTER TABLE "public"."submission" OWNER TO "postgres"; + +CREATE TABLE IF NOT EXISTS "public"."submissionstatus" ( + "id" bigint NOT NULL, + "label" character varying NOT NULL, + "updated_at" timestamp with time zone DEFAULT "now"() +); + +ALTER TABLE "public"."submissionstatus" OWNER TO "postgres"; + +ALTER TABLE "public"."submissionstatus" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY ( + SEQUENCE NAME "public"."submission_status_id_seq" + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1 +); + +CREATE TABLE IF NOT EXISTS "public"."video_transcripts" ( + "id" bigint NOT NULL, + "created_at" timestamp with time zone DEFAULT "now"() NOT NULL, + "muse_svid" "text", + "transcript" "text", + "downloaded" boolean DEFAULT false, + "link" "text" +); + +ALTER TABLE "public"."video_transcripts" OWNER TO "postgres"; + +ALTER TABLE "public"."video_transcripts" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY ( + SEQUENCE NAME "public"."video_transcripts_id_seq" + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1 +); + +CREATE TABLE IF NOT EXISTS "public"."waitinglist" ( + "id" bigint NOT NULL, + "email" character varying NOT NULL, + "created_at" timestamp with time zone DEFAULT "now"() +); + +ALTER TABLE "public"."waitinglist" OWNER TO "postgres"; + +ALTER TABLE "public"."waitinglist" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY ( + SEQUENCE NAME "public"."waitinglist_id_seq" + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1 +); + +ALTER TABLE ONLY "public"."apps_poll_option" + ADD CONSTRAINT "apps_poll_option_pkey" PRIMARY KEY ("id"); + +ALTER TABLE ONLY "public"."apps_poll" + ADD CONSTRAINT "apps_poll_pkey" PRIMARY KEY ("id"); + +ALTER TABLE ONLY "public"."apps_poll_submission" + ADD CONSTRAINT "apps_poll_submision_pkey" PRIMARY KEY ("id"); + +ALTER TABLE ONLY "public"."community_answer" + ADD CONSTRAINT "community_answer_pkey" PRIMARY KEY ("id"); + +ALTER TABLE ONLY "public"."community_question" + ADD CONSTRAINT "community_question_pkey" PRIMARY KEY ("id"); + +ALTER TABLE ONLY "public"."waitinglist" + ADD CONSTRAINT "constraint_name" UNIQUE ("email"); + +ALTER TABLE ONLY "public"."course" + ADD CONSTRAINT "course_pkey" PRIMARY KEY ("id"); + +ALTER TABLE ONLY "public"."course" + ADD CONSTRAINT "course_slug_key" UNIQUE ("slug"); + +ALTER TABLE ONLY "public"."currency" + ADD CONSTRAINT "currency_pkey" PRIMARY KEY ("id"); + +ALTER TABLE ONLY "public"."exercise" + ADD CONSTRAINT "exercise_pkey" PRIMARY KEY ("id"); + +ALTER TABLE ONLY "public"."group_attendance" + ADD CONSTRAINT "group_attendance_pkey" PRIMARY KEY ("id"); + +ALTER TABLE ONLY "public"."group" + ADD CONSTRAINT "group_pkey" PRIMARY KEY ("id"); + +ALTER TABLE ONLY "public"."groupmember" + ADD CONSTRAINT "groupmember_pkey" PRIMARY KEY ("id"); + +ALTER TABLE ONLY "public"."lesson_comment" + ADD CONSTRAINT "lesson_comment_pkey" PRIMARY KEY ("id"); + +ALTER TABLE ONLY "public"."lesson_completion" + ADD CONSTRAINT "lesson_completion_pkey" PRIMARY KEY ("id"); + +ALTER TABLE ONLY "public"."lesson" + ADD CONSTRAINT "lesson_pkey" PRIMARY KEY ("id"); + +ALTER TABLE ONLY "public"."option" + ADD CONSTRAINT "option_pkey" PRIMARY KEY ("id"); + +ALTER TABLE ONLY "public"."organization_contacts" + ADD CONSTRAINT "organization_contacts_pkey" PRIMARY KEY ("id"); + +ALTER TABLE ONLY "public"."organization_emaillist" + ADD CONSTRAINT "organization_emaillist_pkey" PRIMARY KEY ("id"); + +ALTER TABLE ONLY "public"."organization" + ADD CONSTRAINT "organization_pkey" PRIMARY KEY ("id"); + +ALTER TABLE ONLY "public"."organization" + ADD CONSTRAINT "organization_siteName_key" UNIQUE ("siteName"); + +ALTER TABLE ONLY "public"."organizationmember" + ADD CONSTRAINT "organizationmember_pkey" PRIMARY KEY ("id"); + +ALTER TABLE ONLY "public"."quiz_play" + ADD CONSTRAINT "play_quiz_pkey" PRIMARY KEY ("id"); + +ALTER TABLE ONLY "public"."profile" + ADD CONSTRAINT "profile_pkey" PRIMARY KEY ("id"); + +ALTER TABLE ONLY "public"."profile" + ADD CONSTRAINT "profile_username_key" UNIQUE ("username"); + +ALTER TABLE ONLY "public"."question_answer" + ADD CONSTRAINT "question_answer_pkey" PRIMARY KEY ("id"); + +ALTER TABLE ONLY "public"."question" + ADD CONSTRAINT "question_pkey" PRIMARY KEY ("id"); + +ALTER TABLE ONLY "public"."question_type" + ADD CONSTRAINT "question_type_pkey" PRIMARY KEY ("id"); + +ALTER TABLE ONLY "public"."quiz" + ADD CONSTRAINT "quiz_pkey" PRIMARY KEY ("id"); + +ALTER TABLE ONLY "public"."quiz_play" + ADD CONSTRAINT "quiz_play_pin_key" UNIQUE ("pin"); + +ALTER TABLE ONLY "public"."role" + ADD CONSTRAINT "role_pkey" PRIMARY KEY ("id"); + +ALTER TABLE ONLY "public"."submission" + ADD CONSTRAINT "submission_pkey" PRIMARY KEY ("id"); + +ALTER TABLE ONLY "public"."submissionstatus" + ADD CONSTRAINT "submission_status_pkey" PRIMARY KEY ("id"); + +ALTER TABLE ONLY "public"."groupmember" + ADD CONSTRAINT "unique_entries" UNIQUE ("group_id", "profile_id", "email"); + +ALTER TABLE ONLY "public"."groupmember" + ADD CONSTRAINT "unique_group_email" UNIQUE ("group_id", "email"); + +ALTER TABLE ONLY "public"."groupmember" + ADD CONSTRAINT "unique_group_profile" UNIQUE ("group_id", "profile_id"); + +ALTER TABLE ONLY "public"."video_transcripts" + ADD CONSTRAINT "video_transcripts_pkey" PRIMARY KEY ("id"); + +ALTER TABLE ONLY "public"."waitinglist" + ADD CONSTRAINT "waitinglist_pkey" PRIMARY KEY ("id"); + +CREATE OR REPLACE TRIGGER "handle_exercise_updated_at" BEFORE UPDATE ON "public"."exercise" FOR EACH ROW EXECUTE FUNCTION "extensions"."moddatetime"('updated_at'); + +CREATE OR REPLACE TRIGGER "handle_lesson_updated_at" BEFORE UPDATE ON "public"."lesson" FOR EACH ROW EXECUTE FUNCTION "extensions"."moddatetime"('updated_at'); + +CREATE OR REPLACE TRIGGER "handle_question_type_updated_at" BEFORE UPDATE ON "public"."question_type" FOR EACH ROW EXECUTE FUNCTION "extensions"."moddatetime"('updated_at'); + +CREATE OR REPLACE TRIGGER "handle_question_updated_at" BEFORE UPDATE ON "public"."question" FOR EACH ROW EXECUTE FUNCTION "extensions"."moddatetime"('updated_at'); + +CREATE OR REPLACE TRIGGER "handle_role_updated_at" BEFORE UPDATE ON "public"."role" FOR EACH ROW EXECUTE FUNCTION "extensions"."moddatetime"('updated_at'); + +CREATE OR REPLACE TRIGGER "handle_submission_updated_at" BEFORE UPDATE ON "public"."submission" FOR EACH ROW EXECUTE FUNCTION "extensions"."moddatetime"('updated_at'); + +CREATE OR REPLACE TRIGGER "handle_updated_at" BEFORE UPDATE ON "public"."exercise" FOR EACH ROW EXECUTE FUNCTION "extensions"."moddatetime"('updated_at'); + +CREATE OR REPLACE TRIGGER "handle_updated_at" BEFORE UPDATE ON "public"."lesson" FOR EACH ROW EXECUTE FUNCTION "extensions"."moddatetime"('updated_at'); + +CREATE OR REPLACE TRIGGER "handle_updated_at" BEFORE UPDATE ON "public"."question" FOR EACH ROW EXECUTE FUNCTION "extensions"."moddatetime"('updated_at'); + +ALTER TABLE ONLY "public"."apps_poll" + ADD CONSTRAINT "apps_poll_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "public"."groupmember"("id"); + +ALTER TABLE ONLY "public"."apps_poll" + ADD CONSTRAINT "apps_poll_courseId_fkey" FOREIGN KEY ("courseId") REFERENCES "public"."course"("id"); + +ALTER TABLE ONLY "public"."apps_poll_option" + ADD CONSTRAINT "apps_poll_option_poll_id_fkey" FOREIGN KEY ("poll_id") REFERENCES "public"."apps_poll"("id"); + +ALTER TABLE ONLY "public"."apps_poll_submission" + ADD CONSTRAINT "apps_poll_submission_poll_id_fkey" FOREIGN KEY ("poll_id") REFERENCES "public"."apps_poll"("id"); + +ALTER TABLE ONLY "public"."apps_poll_submission" + ADD CONSTRAINT "apps_poll_submission_poll_option_id_fkey" FOREIGN KEY ("poll_option_id") REFERENCES "public"."apps_poll_option"("id"); + +ALTER TABLE ONLY "public"."apps_poll_submission" + ADD CONSTRAINT "apps_poll_submission_selected_by_id_fkey" FOREIGN KEY ("selected_by_id") REFERENCES "public"."groupmember"("id"); + +ALTER TABLE ONLY "public"."community_answer" + ADD CONSTRAINT "community_answer_author_id_fkey" FOREIGN KEY ("author_id") REFERENCES "public"."organizationmember"("id"); + +ALTER TABLE ONLY "public"."community_answer" + ADD CONSTRAINT "community_answer_question_id_fkey" FOREIGN KEY ("question_id") REFERENCES "public"."community_question"("id"); + +ALTER TABLE ONLY "public"."community_question" + ADD CONSTRAINT "community_question_author_id_fkey" FOREIGN KEY ("author_id") REFERENCES "public"."organizationmember"("id"); + +ALTER TABLE ONLY "public"."community_question" + ADD CONSTRAINT "community_question_organization_id_fkey" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id"); + +ALTER TABLE ONLY "public"."course" + ADD CONSTRAINT "course_group_id_fkey" FOREIGN KEY ("group_id") REFERENCES "public"."group"("id"); + +ALTER TABLE ONLY "public"."exercise" + ADD CONSTRAINT "exercise_lesson_id_fkey" FOREIGN KEY ("lesson_id") REFERENCES "public"."lesson"("id"); + +ALTER TABLE ONLY "public"."group_attendance" + ADD CONSTRAINT "group_attendance_course_id_fkey" FOREIGN KEY ("course_id") REFERENCES "public"."course"("id"); + +ALTER TABLE ONLY "public"."group_attendance" + ADD CONSTRAINT "group_attendance_student_id_fkey" FOREIGN KEY ("student_id") REFERENCES "public"."groupmember"("id"); + +ALTER TABLE ONLY "public"."group" + ADD CONSTRAINT "group_organization_id_fkey" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id"); + +ALTER TABLE ONLY "public"."groupmember" + ADD CONSTRAINT "groupmember_group_id_fkey" FOREIGN KEY ("group_id") REFERENCES "public"."group"("id"); + +ALTER TABLE ONLY "public"."groupmember" + ADD CONSTRAINT "groupmember_profile_id_fkey" FOREIGN KEY ("profile_id") REFERENCES "public"."profile"("id"); + +ALTER TABLE ONLY "public"."groupmember" + ADD CONSTRAINT "groupmember_role_id_fkey" FOREIGN KEY ("role_id") REFERENCES "public"."role"("id"); + +ALTER TABLE ONLY "public"."lesson_comment" + ADD CONSTRAINT "lesson_comment_groupmember_id_fkey" FOREIGN KEY ("groupmember_id") REFERENCES "public"."groupmember"("id"); + +ALTER TABLE ONLY "public"."lesson_comment" + ADD CONSTRAINT "lesson_comment_lesson_id_fkey" FOREIGN KEY ("lesson_id") REFERENCES "public"."lesson"("id"); + +ALTER TABLE ONLY "public"."lesson_completion" + ADD CONSTRAINT "lesson_completion_lesson_id_fkey" FOREIGN KEY ("lesson_id") REFERENCES "public"."lesson"("id"); + +ALTER TABLE ONLY "public"."lesson_completion" + ADD CONSTRAINT "lesson_completion_profile_id_fkey" FOREIGN KEY ("profile_id") REFERENCES "public"."profile"("id"); + +ALTER TABLE ONLY "public"."lesson" + ADD CONSTRAINT "lesson_course_id_fkey" FOREIGN KEY ("course_id") REFERENCES "public"."course"("id"); + +ALTER TABLE ONLY "public"."lesson" + ADD CONSTRAINT "lesson_teacher_id_fkey" FOREIGN KEY ("teacher_id") REFERENCES "public"."profile"("id"); + +ALTER TABLE ONLY "public"."option" + ADD CONSTRAINT "option_question_id_fkey" FOREIGN KEY ("question_id") REFERENCES "public"."question"("id"); + +ALTER TABLE ONLY "public"."organization_contacts" + ADD CONSTRAINT "organization_contacts_organization_id_fkey" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id"); + +ALTER TABLE ONLY "public"."organization_emaillist" + ADD CONSTRAINT "organization_emaillist_organization_id_fkey" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id"); + +ALTER TABLE ONLY "public"."organizationmember" + ADD CONSTRAINT "organizationmember_organization_id_fkey" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id"); + +ALTER TABLE ONLY "public"."organizationmember" + ADD CONSTRAINT "organizationmember_profile_id_fkey" FOREIGN KEY ("profile_id") REFERENCES "public"."profile"("id"); + +ALTER TABLE ONLY "public"."organizationmember" + ADD CONSTRAINT "organizationmember_role_id_fkey" FOREIGN KEY ("role_id") REFERENCES "public"."role"("id"); + +ALTER TABLE ONLY "public"."profile" + ADD CONSTRAINT "profile_id_fkey" FOREIGN KEY ("id") REFERENCES "auth"."users"("id"); + +ALTER TABLE ONLY "public"."question_answer" + ADD CONSTRAINT "question_answer_group_member_id_fkey" FOREIGN KEY ("group_member_id") REFERENCES "public"."groupmember"("id"); + +ALTER TABLE ONLY "public"."question_answer" + ADD CONSTRAINT "question_answer_question_id_fkey" FOREIGN KEY ("question_id") REFERENCES "public"."question"("id"); + +ALTER TABLE ONLY "public"."question_answer" + ADD CONSTRAINT "question_answer_submission_id_fkey" FOREIGN KEY ("submission_id") REFERENCES "public"."submission"("id"); + +ALTER TABLE ONLY "public"."question" + ADD CONSTRAINT "question_exercise_id_fkey" FOREIGN KEY ("exercise_id") REFERENCES "public"."exercise"("id"); + +ALTER TABLE ONLY "public"."question" + ADD CONSTRAINT "question_question_type_id_fkey" FOREIGN KEY ("question_type_id") REFERENCES "public"."question_type"("id"); + +ALTER TABLE ONLY "public"."quiz" + ADD CONSTRAINT "quiz_organization_id_fkey" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id"); + +ALTER TABLE ONLY "public"."quiz_play" + ADD CONSTRAINT "quiz_play_quiz_id_fkey" FOREIGN KEY ("quiz_id") REFERENCES "public"."quiz"("id"); + +ALTER TABLE ONLY "public"."submission" + ADD CONSTRAINT "submission_course_id_fkey" FOREIGN KEY ("course_id") REFERENCES "public"."course"("id"); + +ALTER TABLE ONLY "public"."submission" + ADD CONSTRAINT "submission_exercise_id_fkey" FOREIGN KEY ("exercise_id") REFERENCES "public"."exercise"("id"); + +ALTER TABLE ONLY "public"."submission" + ADD CONSTRAINT "submission_status_id_fkey" FOREIGN KEY ("status_id") REFERENCES "public"."submissionstatus"("id"); + +ALTER TABLE ONLY "public"."submission" + ADD CONSTRAINT "submission_submitted_by_fkey" FOREIGN KEY ("submitted_by") REFERENCES "public"."groupmember"("id"); + +CREATE POLICY "Enable access to all users" ON "public"."course" FOR SELECT USING (true); + +CREATE POLICY "Enable insert for authenticated users only" ON "public"."community_question" FOR INSERT TO "authenticated" WITH CHECK (true); + +CREATE POLICY "Enable insert for authenticated users only" ON "public"."course" FOR INSERT WITH CHECK (("auth"."role"() = 'authenticated'::"text")); + +CREATE POLICY "Enable insert for authenticated users only" ON "public"."lesson_comment" FOR INSERT TO "authenticated" WITH CHECK (true); + +CREATE POLICY "Enable read access for all users" ON "public"."lesson_comment" FOR SELECT USING (true); + +CREATE POLICY "Enable read access for all users" ON "public"."organization_contacts" FOR INSERT WITH CHECK (true); + +CREATE POLICY "Enable read access for all users" ON "public"."organization_emaillist" FOR INSERT WITH CHECK (true); + +CREATE POLICY "Enable update for authenticated users only" ON "public"."course" FOR UPDATE USING (("auth"."role"() = 'authenticated'::"text")) WITH CHECK (("auth"."role"() = 'authenticated'::"text")); + +CREATE POLICY "Public profiles are viewable by everyone." ON "public"."profile" FOR SELECT USING (true); + +CREATE POLICY "Users can insert their own profile." ON "public"."profile" FOR INSERT WITH CHECK (("auth"."uid"() = "id")); + +CREATE POLICY "Users can update own profile." ON "public"."profile" FOR UPDATE USING (("auth"."uid"() = "id")); + +ALTER TABLE "public"."currency" ENABLE ROW LEVEL SECURITY; + +ALTER TABLE "public"."lesson_comment" ENABLE ROW LEVEL SECURITY; + +ALTER TABLE "public"."organization_contacts" ENABLE ROW LEVEL SECURITY; + +ALTER TABLE "public"."organization_emaillist" ENABLE ROW LEVEL SECURITY; + +ALTER TABLE "public"."profile" ENABLE ROW LEVEL SECURITY; + +ALTER TABLE "public"."video_transcripts" ENABLE ROW LEVEL SECURITY; + +REVOKE USAGE ON SCHEMA "public" FROM PUBLIC; +GRANT USAGE ON SCHEMA "public" TO "anon"; +GRANT USAGE ON SCHEMA "public" TO "authenticated"; +GRANT USAGE ON SCHEMA "public" TO "service_role"; +GRANT ALL ON SCHEMA "public" TO PUBLIC; + +GRANT ALL ON FUNCTION "public"."add_them"("a" integer, "b" integer) TO "anon"; +GRANT ALL ON FUNCTION "public"."add_them"("a" integer, "b" integer) TO "authenticated"; +GRANT ALL ON FUNCTION "public"."add_them"("a" integer, "b" integer) TO "service_role"; + +GRANT ALL ON FUNCTION "public"."get_courses"("org_id_arg" "uuid", "profile_id_arg" "uuid") TO "anon"; +GRANT ALL ON FUNCTION "public"."get_courses"("org_id_arg" "uuid", "profile_id_arg" "uuid") TO "authenticated"; +GRANT ALL ON FUNCTION "public"."get_courses"("org_id_arg" "uuid", "profile_id_arg" "uuid") TO "service_role"; + +GRANT ALL ON FUNCTION "public"."get_exercises"() TO "anon"; +GRANT ALL ON FUNCTION "public"."get_exercises"() TO "authenticated"; +GRANT ALL ON FUNCTION "public"."get_exercises"() TO "service_role"; + +GRANT ALL ON FUNCTION "public"."get_marks"() TO "anon"; +GRANT ALL ON FUNCTION "public"."get_marks"() TO "authenticated"; +GRANT ALL ON FUNCTION "public"."get_marks"() TO "service_role"; + +GRANT ALL ON FUNCTION "public"."get_student_exercises"("org_id_arg" "uuid", "profile_id_arg" "uuid") TO "anon"; +GRANT ALL ON FUNCTION "public"."get_student_exercises"("org_id_arg" "uuid", "profile_id_arg" "uuid") TO "authenticated"; +GRANT ALL ON FUNCTION "public"."get_student_exercises"("org_id_arg" "uuid", "profile_id_arg" "uuid") TO "service_role"; + +GRANT ALL ON FUNCTION "public"."get_user_upcoming_lessons"("profile_id_arg" "uuid", "org_id_arg" "uuid") TO "anon"; +GRANT ALL ON FUNCTION "public"."get_user_upcoming_lessons"("profile_id_arg" "uuid", "org_id_arg" "uuid") TO "authenticated"; +GRANT ALL ON FUNCTION "public"."get_user_upcoming_lessons"("profile_id_arg" "uuid", "org_id_arg" "uuid") TO "service_role"; + +GRANT ALL ON TABLE "public"."apps_poll" TO "anon"; +GRANT ALL ON TABLE "public"."apps_poll" TO "authenticated"; +GRANT ALL ON TABLE "public"."apps_poll" TO "service_role"; + +GRANT ALL ON TABLE "public"."apps_poll_option" TO "anon"; +GRANT ALL ON TABLE "public"."apps_poll_option" TO "authenticated"; +GRANT ALL ON TABLE "public"."apps_poll_option" TO "service_role"; + +GRANT ALL ON SEQUENCE "public"."apps_poll_option_id_seq" TO "anon"; +GRANT ALL ON SEQUENCE "public"."apps_poll_option_id_seq" TO "authenticated"; +GRANT ALL ON SEQUENCE "public"."apps_poll_option_id_seq" TO "service_role"; + +GRANT ALL ON TABLE "public"."apps_poll_submission" TO "anon"; +GRANT ALL ON TABLE "public"."apps_poll_submission" TO "authenticated"; +GRANT ALL ON TABLE "public"."apps_poll_submission" TO "service_role"; + +GRANT ALL ON SEQUENCE "public"."apps_poll_submision_id_seq" TO "anon"; +GRANT ALL ON SEQUENCE "public"."apps_poll_submision_id_seq" TO "authenticated"; +GRANT ALL ON SEQUENCE "public"."apps_poll_submision_id_seq" TO "service_role"; + +GRANT ALL ON TABLE "public"."community_answer" TO "anon"; +GRANT ALL ON TABLE "public"."community_answer" TO "authenticated"; +GRANT ALL ON TABLE "public"."community_answer" TO "service_role"; + +GRANT ALL ON TABLE "public"."community_question" TO "anon"; +GRANT ALL ON TABLE "public"."community_question" TO "authenticated"; +GRANT ALL ON TABLE "public"."community_question" TO "service_role"; + +GRANT ALL ON SEQUENCE "public"."community_question_id_seq" TO "anon"; +GRANT ALL ON SEQUENCE "public"."community_question_id_seq" TO "authenticated"; +GRANT ALL ON SEQUENCE "public"."community_question_id_seq" TO "service_role"; + +GRANT ALL ON TABLE "public"."course" TO "anon"; +GRANT ALL ON TABLE "public"."course" TO "authenticated"; +GRANT ALL ON TABLE "public"."course" TO "service_role"; + +GRANT ALL ON TABLE "public"."currency" TO "anon"; +GRANT ALL ON TABLE "public"."currency" TO "authenticated"; +GRANT ALL ON TABLE "public"."currency" TO "service_role"; + +GRANT ALL ON SEQUENCE "public"."currency_id_seq" TO "anon"; +GRANT ALL ON SEQUENCE "public"."currency_id_seq" TO "authenticated"; +GRANT ALL ON SEQUENCE "public"."currency_id_seq" TO "service_role"; + +GRANT ALL ON TABLE "public"."exercise" TO "anon"; +GRANT ALL ON TABLE "public"."exercise" TO "authenticated"; +GRANT ALL ON TABLE "public"."exercise" TO "service_role"; + +GRANT ALL ON TABLE "public"."group" TO "anon"; +GRANT ALL ON TABLE "public"."group" TO "authenticated"; +GRANT ALL ON TABLE "public"."group" TO "service_role"; + +GRANT ALL ON TABLE "public"."group_attendance" TO "anon"; +GRANT ALL ON TABLE "public"."group_attendance" TO "authenticated"; +GRANT ALL ON TABLE "public"."group_attendance" TO "service_role"; + +GRANT ALL ON SEQUENCE "public"."group_attendance_id_seq" TO "anon"; +GRANT ALL ON SEQUENCE "public"."group_attendance_id_seq" TO "authenticated"; +GRANT ALL ON SEQUENCE "public"."group_attendance_id_seq" TO "service_role"; + +GRANT ALL ON TABLE "public"."groupmember" TO "anon"; +GRANT ALL ON TABLE "public"."groupmember" TO "authenticated"; +GRANT ALL ON TABLE "public"."groupmember" TO "service_role"; + +GRANT ALL ON TABLE "public"."lesson" TO "anon"; +GRANT ALL ON TABLE "public"."lesson" TO "authenticated"; +GRANT ALL ON TABLE "public"."lesson" TO "service_role"; + +GRANT ALL ON TABLE "public"."lesson_comment" TO "anon"; +GRANT ALL ON TABLE "public"."lesson_comment" TO "authenticated"; +GRANT ALL ON TABLE "public"."lesson_comment" TO "service_role"; + +GRANT ALL ON SEQUENCE "public"."lesson_comment_id_seq" TO "anon"; +GRANT ALL ON SEQUENCE "public"."lesson_comment_id_seq" TO "authenticated"; +GRANT ALL ON SEQUENCE "public"."lesson_comment_id_seq" TO "service_role"; + +GRANT ALL ON TABLE "public"."lesson_completion" TO "anon"; +GRANT ALL ON TABLE "public"."lesson_completion" TO "authenticated"; +GRANT ALL ON TABLE "public"."lesson_completion" TO "service_role"; + +GRANT ALL ON SEQUENCE "public"."lesson_completion_id_seq" TO "anon"; +GRANT ALL ON SEQUENCE "public"."lesson_completion_id_seq" TO "authenticated"; +GRANT ALL ON SEQUENCE "public"."lesson_completion_id_seq" TO "service_role"; + +GRANT ALL ON TABLE "public"."option" TO "anon"; +GRANT ALL ON TABLE "public"."option" TO "authenticated"; +GRANT ALL ON TABLE "public"."option" TO "service_role"; + +GRANT ALL ON SEQUENCE "public"."option_id_seq" TO "anon"; +GRANT ALL ON SEQUENCE "public"."option_id_seq" TO "authenticated"; +GRANT ALL ON SEQUENCE "public"."option_id_seq" TO "service_role"; + +GRANT ALL ON TABLE "public"."organization" TO "anon"; +GRANT ALL ON TABLE "public"."organization" TO "authenticated"; +GRANT ALL ON TABLE "public"."organization" TO "service_role"; + +GRANT ALL ON TABLE "public"."organization_contacts" TO "anon"; +GRANT ALL ON TABLE "public"."organization_contacts" TO "authenticated"; +GRANT ALL ON TABLE "public"."organization_contacts" TO "service_role"; + +GRANT ALL ON SEQUENCE "public"."organization_contacts_id_seq" TO "anon"; +GRANT ALL ON SEQUENCE "public"."organization_contacts_id_seq" TO "authenticated"; +GRANT ALL ON SEQUENCE "public"."organization_contacts_id_seq" TO "service_role"; + +GRANT ALL ON TABLE "public"."organization_emaillist" TO "anon"; +GRANT ALL ON TABLE "public"."organization_emaillist" TO "authenticated"; +GRANT ALL ON TABLE "public"."organization_emaillist" TO "service_role"; + +GRANT ALL ON SEQUENCE "public"."organization_emaillist_id_seq" TO "anon"; +GRANT ALL ON SEQUENCE "public"."organization_emaillist_id_seq" TO "authenticated"; +GRANT ALL ON SEQUENCE "public"."organization_emaillist_id_seq" TO "service_role"; + +GRANT ALL ON TABLE "public"."organizationmember" TO "anon"; +GRANT ALL ON TABLE "public"."organizationmember" TO "authenticated"; +GRANT ALL ON TABLE "public"."organizationmember" TO "service_role"; + +GRANT ALL ON SEQUENCE "public"."organizationmember_id_seq" TO "anon"; +GRANT ALL ON SEQUENCE "public"."organizationmember_id_seq" TO "authenticated"; +GRANT ALL ON SEQUENCE "public"."organizationmember_id_seq" TO "service_role"; + +GRANT ALL ON TABLE "public"."quiz_play" TO "anon"; +GRANT ALL ON TABLE "public"."quiz_play" TO "authenticated"; +GRANT ALL ON TABLE "public"."quiz_play" TO "service_role"; + +GRANT ALL ON SEQUENCE "public"."play_quiz_id_seq" TO "anon"; +GRANT ALL ON SEQUENCE "public"."play_quiz_id_seq" TO "authenticated"; +GRANT ALL ON SEQUENCE "public"."play_quiz_id_seq" TO "service_role"; + +GRANT ALL ON TABLE "public"."profile" TO "anon"; +GRANT ALL ON TABLE "public"."profile" TO "authenticated"; +GRANT ALL ON TABLE "public"."profile" TO "service_role"; + +GRANT ALL ON TABLE "public"."question" TO "anon"; +GRANT ALL ON TABLE "public"."question" TO "authenticated"; +GRANT ALL ON TABLE "public"."question" TO "service_role"; + +GRANT ALL ON TABLE "public"."question_answer" TO "anon"; +GRANT ALL ON TABLE "public"."question_answer" TO "authenticated"; +GRANT ALL ON TABLE "public"."question_answer" TO "service_role"; + +GRANT ALL ON SEQUENCE "public"."question_answer_id_seq" TO "anon"; +GRANT ALL ON SEQUENCE "public"."question_answer_id_seq" TO "authenticated"; +GRANT ALL ON SEQUENCE "public"."question_answer_id_seq" TO "service_role"; + +GRANT ALL ON SEQUENCE "public"."question_id_seq" TO "anon"; +GRANT ALL ON SEQUENCE "public"."question_id_seq" TO "authenticated"; +GRANT ALL ON SEQUENCE "public"."question_id_seq" TO "service_role"; + +GRANT ALL ON TABLE "public"."question_type" TO "anon"; +GRANT ALL ON TABLE "public"."question_type" TO "authenticated"; +GRANT ALL ON TABLE "public"."question_type" TO "service_role"; + +GRANT ALL ON SEQUENCE "public"."question_type_id_seq" TO "anon"; +GRANT ALL ON SEQUENCE "public"."question_type_id_seq" TO "authenticated"; +GRANT ALL ON SEQUENCE "public"."question_type_id_seq" TO "service_role"; + +GRANT ALL ON TABLE "public"."quiz" TO "anon"; +GRANT ALL ON TABLE "public"."quiz" TO "authenticated"; +GRANT ALL ON TABLE "public"."quiz" TO "service_role"; + +GRANT ALL ON TABLE "public"."role" TO "anon"; +GRANT ALL ON TABLE "public"."role" TO "authenticated"; +GRANT ALL ON TABLE "public"."role" TO "service_role"; + +GRANT ALL ON SEQUENCE "public"."role_id_seq" TO "anon"; +GRANT ALL ON SEQUENCE "public"."role_id_seq" TO "authenticated"; +GRANT ALL ON SEQUENCE "public"."role_id_seq" TO "service_role"; + +GRANT ALL ON TABLE "public"."submission" TO "anon"; +GRANT ALL ON TABLE "public"."submission" TO "authenticated"; +GRANT ALL ON TABLE "public"."submission" TO "service_role"; + +GRANT ALL ON TABLE "public"."submissionstatus" TO "anon"; +GRANT ALL ON TABLE "public"."submissionstatus" TO "authenticated"; +GRANT ALL ON TABLE "public"."submissionstatus" TO "service_role"; + +GRANT ALL ON SEQUENCE "public"."submission_status_id_seq" TO "anon"; +GRANT ALL ON SEQUENCE "public"."submission_status_id_seq" TO "authenticated"; +GRANT ALL ON SEQUENCE "public"."submission_status_id_seq" TO "service_role"; + +GRANT ALL ON TABLE "public"."video_transcripts" TO "anon"; +GRANT ALL ON TABLE "public"."video_transcripts" TO "authenticated"; +GRANT ALL ON TABLE "public"."video_transcripts" TO "service_role"; + +GRANT ALL ON SEQUENCE "public"."video_transcripts_id_seq" TO "anon"; +GRANT ALL ON SEQUENCE "public"."video_transcripts_id_seq" TO "authenticated"; +GRANT ALL ON SEQUENCE "public"."video_transcripts_id_seq" TO "service_role"; + +GRANT ALL ON TABLE "public"."waitinglist" TO "anon"; +GRANT ALL ON TABLE "public"."waitinglist" TO "authenticated"; +GRANT ALL ON TABLE "public"."waitinglist" TO "service_role"; + +GRANT ALL ON SEQUENCE "public"."waitinglist_id_seq" TO "anon"; +GRANT ALL ON SEQUENCE "public"."waitinglist_id_seq" TO "authenticated"; +GRANT ALL ON SEQUENCE "public"."waitinglist_id_seq" TO "service_role"; + +ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON SEQUENCES TO "postgres"; +ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON SEQUENCES TO "anon"; +ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON SEQUENCES TO "authenticated"; +ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON SEQUENCES TO "service_role"; + +ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON FUNCTIONS TO "postgres"; +ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON FUNCTIONS TO "anon"; +ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON FUNCTIONS TO "authenticated"; +ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON FUNCTIONS TO "service_role"; + +ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON TABLES TO "postgres"; +ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON TABLES TO "anon"; +ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON TABLES TO "authenticated"; +ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON TABLES TO "service_role"; + +INSERT INTO "public"."role" (type, description) VALUES ('ADMIN', 'The main controller'); +INSERT INTO "public"."role" (type, description) VALUES ('TUTOR', 'Can make changes to content, courses, but cant control passwords and cant add other tutors'); +INSERT INTO "public"."role" (type, description) VALUES ('STUDENT', 'A student role, can interact with application but cant make changes'); +INSERT INTO "public"."submissionstatus" (label) VALUES ('Submitted'); +INSERT INTO "public"."submissionstatus" (label) VALUES ('In Progress'); +INSERT INTO "public"."submissionstatus" (label) VALUES ('Graded'); + +INSERT INTO "public"."question_type" (label, created_at, updated_at, typename) VALUES ('Single answer', '2021-08-07 18:49:46.246529+00', '2021-08-15 00:57:08.12069+00', 'RADIO'); +INSERT INTO "public"."question_type" (label, created_at, updated_at, typename) VALUES ('Multiple answers', '2021-08-07 18:49:46.246529+00', '2021-08-15 00:57:27.935478+00', 'CHECKBOX'); +INSERT INTO "public"."question_type" (label, created_at, updated_at, typename) VALUES ('Paragraph', '2021-08-07 18:49:46.246529+00', '2021-08-15 00:57:38.634665+00', 'TEXTAREA'); + + +-- First, let's check if the constraint 'buckets_owner_fkey' exists before trying to drop it. +DO $$ +BEGIN + IF EXISTS (SELECT 1 FROM information_schema.constraint_column_usage + WHERE table_schema = 'storage' + AND table_name = 'buckets' + AND constraint_name = 'buckets_owner_fkey') THEN + ALTER TABLE "storage"."buckets" DROP CONSTRAINT "buckets_owner_fkey"; + END IF; +END +$$; + +-- Now, we check if the column 'owner_id' exists in 'buckets' before trying to add it. +DO $$ +BEGIN + IF NOT EXISTS (SELECT 1 FROM information_schema.columns + WHERE table_schema = 'storage' + AND table_name = 'buckets' + AND column_name = 'owner_id') THEN + ALTER TABLE "storage"."buckets" ADD COLUMN "owner_id" text; + END IF; +END +$$; + +-- Similarly, check if 'owner_id' exists in 'objects' before adding it. +DO $$ +BEGIN + IF NOT EXISTS (SELECT 1 FROM information_schema.columns + WHERE table_schema = 'storage' + AND table_name = 'objects' + AND column_name = 'owner_id') THEN + ALTER TABLE "storage"."objects" ADD COLUMN "owner_id" text; + END IF; +END +$$; + + +create policy "Anyone can update an avatar. 1oj01fe_0" +on "storage"."objects" +as permissive +for select +to public +using ((bucket_id = 'avatars'::text)); + + +create policy "Anyone can update an avatar. 1oj01fe_1" +on "storage"."objects" +as permissive +for insert +to public +with check ((bucket_id = 'avatars'::text)); + + +create policy "Avatar images are publicly accessible 1oj01fe_0" +on "storage"."objects" +as permissive +for select +to public +using ((bucket_id = 'avatars'::text)); + +RESET ALL; diff --git a/supabase/migrations/20231118210545_profile.sql b/supabase/migrations/20231118210545_profile.sql new file mode 100644 index 00000000..22008385 --- /dev/null +++ b/supabase/migrations/20231118210545_profile.sql @@ -0,0 +1 @@ +alter table "public"."profile" alter column "avatar_url" set default 'https://pgrest.classroomio.com/storage/v1/object/public/avatars/avatar.png'::text; diff --git a/supabase/migrations/20231207061507_update_get_courses.sql b/supabase/migrations/20231207061507_update_get_courses.sql new file mode 100644 index 00000000..da4d0a43 --- /dev/null +++ b/supabase/migrations/20231207061507_update_get_courses.sql @@ -0,0 +1,22 @@ + +drop function if exists "public"."get_courses"(org_id_arg uuid, profile_id_arg uuid); + +set check_function_bodies = off; + +CREATE OR REPLACE FUNCTION public.get_courses(org_id_arg uuid, profile_id_arg uuid) + RETURNS TABLE(id uuid, org_id uuid, title character varying, slug character varying, description character varying, logo text, banner_image text, cost bigint, currency character varying, is_published boolean, profile_id uuid, role_id bigint, total_lessons bigint, total_students bigint, progress_rate bigint) + LANGUAGE plpgsql +AS $function$ +BEGIN + Return query + select course.id, organization.id AS org_id, course.title, course.slug, course.description, course.logo, course.banner_image, course.cost, course.currency, course.is_published, groupmember.profile_id, groupmember.role_id, (select COUNT(*) from lesson as l where l.course_id = course.id) AS total_lessons, (select COUNT(*) from groupmember as gm where gm.group_id = course.group_id AND gm.role_id = 3) as total_students, (select COUNT(*) from lesson_completion as lc join lesson as l on l.id = lc.lesson_id where l.course_id = course.id and lc.is_complete = true and lc.profile_id = profile_id_arg) AS progress_rate + from course + join "group" on "group".id = course.group_id + join groupmember on groupmember.group_id = course.group_id + join organization on organization.id = "group".organization_id + where course.status = 'ACTIVE' AND organization.id = org_id_arg + -- GROUP BY course.id, groupmember.profile_id + ORDER BY course.created_at DESC; +END; +$function$ +; diff --git a/supabase/migrations/20231213104402_course_metadata.sql b/supabase/migrations/20231213104402_course_metadata.sql new file mode 100644 index 00000000..308e332e --- /dev/null +++ b/supabase/migrations/20231213104402_course_metadata.sql @@ -0,0 +1 @@ +alter table "public"."course" alter column "metadata" set default '{"goals": "", "description": "", "requirements": ""}'::jsonb; \ No newline at end of file diff --git a/supabase/migrations/20231213105201_organizationmember_author_profile_id.sql b/supabase/migrations/20231213105201_organizationmember_author_profile_id.sql new file mode 100644 index 00000000..dd6ee936 --- /dev/null +++ b/supabase/migrations/20231213105201_organizationmember_author_profile_id.sql @@ -0,0 +1,11 @@ +alter table "public"."community_answer" add column "author_profile_id" uuid; + +alter table "public"."community_question" add column "author_profile_id" uuid; + +alter table "public"."community_answer" add constraint "community_answer_author_profile_id_fkey" FOREIGN KEY (author_profile_id) REFERENCES profile(id) not valid; + +alter table "public"."community_answer" validate constraint "community_answer_author_profile_id_fkey"; + +alter table "public"."community_question" add constraint "community_question_author_profile_id_fkey" FOREIGN KEY (author_profile_id) REFERENCES profile(id) not valid; + +alter table "public"."community_question" validate constraint "community_question_author_profile_id_fkey"; \ No newline at end of file diff --git a/supabase/migrations/20240212090837_course_newsfeed.sql b/supabase/migrations/20240212090837_course_newsfeed.sql new file mode 100644 index 00000000..65c0f2f6 --- /dev/null +++ b/supabase/migrations/20240212090837_course_newsfeed.sql @@ -0,0 +1,48 @@ +create table "public"."course_newsfeed" ( + "created_at" timestamp with time zone not null default now(), + "author_id" uuid, + "content" text, + "id" uuid not null default gen_random_uuid(), + "course_id" uuid, + "reaction" jsonb default '{"clap": [], "smile": [], "thumbsup": [], "thumbsdown": []}'::jsonb, + "is_pinned" boolean not null default false +); + + +create table "public"."course_newsfeed_comment" ( + "created_at" timestamp with time zone not null default now(), + "author_id" uuid, + "content" text, + "id" bigint generated by default as identity not null, + "course_newsfeed_id" uuid +); + + +CREATE UNIQUE INDEX course_newsfeed_comment_id_key ON public.course_newsfeed_comment USING btree (id); + +CREATE UNIQUE INDEX course_newsfeed_comment_pkey ON public.course_newsfeed_comment USING btree (id); + +CREATE UNIQUE INDEX course_newsfeed_pkey ON public.course_newsfeed USING btree (id); + +alter table "public"."course_newsfeed" add constraint "course_newsfeed_pkey" PRIMARY KEY using index "course_newsfeed_pkey"; + +alter table "public"."course_newsfeed_comment" add constraint "course_newsfeed_comment_pkey" PRIMARY KEY using index +"course_newsfeed_comment_pkey"; + +alter table "public"."course_newsfeed" add constraint "course_newsfeed_author_id_fkey" FOREIGN KEY (author_id) REFERENCES groupmember(id) not valid; + +alter table "public"."course_newsfeed" validate constraint "course_newsfeed_author_id_fkey"; + +alter table "public"."course_newsfeed" add constraint "course_newsfeed_course_id_fkey" FOREIGN KEY (course_id) REFERENCES course(id) not valid; + +alter table "public"."course_newsfeed" validate constraint "course_newsfeed_course_id_fkey"; + +alter table "public"."course_newsfeed_comment" add constraint "course_newsfeed_comment_id_key" UNIQUE using index "course_newsfeed_comment_id_key"; + +alter table "public"."course_newsfeed_comment" add constraint "course_newsfeed_comment_author_id_fkey" FOREIGN KEY (author_id) REFERENCES groupmember(id) not valid; + +alter table "public"."course_newsfeed_comment" validate constraint "course_newsfeed_comment_author_id_fkey"; + +alter table "public"."course_newsfeed_comment" add constraint "course_newsfeed_comment_course_newsfeed_id_fkey" FOREIGN KEY (course_newsfeed_id) REFERENCES course_newsfeed(id) not valid; + +alter table "public"."course_newsfeed_comment" validate constraint "course_newsfeed_comment_course_newsfeed_id_fkey"; \ No newline at end of file diff --git a/supabase/migrations/20240212110855_add_courseid_to_community_question.sql b/supabase/migrations/20240212110855_add_courseid_to_community_question.sql new file mode 100644 index 00000000..50cc1889 --- /dev/null +++ b/supabase/migrations/20240212110855_add_courseid_to_community_question.sql @@ -0,0 +1,20 @@ +create sequence "public"."test_tenant_id_seq"; + +create table "public"."test_tenant" ( + "id" integer not null default nextval('test_tenant_id_seq'::regclass), + "details" text +); + +truncate "public"."community_question" cascade; + +alter table "public"."community_question" add column "course_id" uuid not null; + +alter sequence "public"."test_tenant_id_seq" owned by "public"."test_tenant"."id"; + +CREATE UNIQUE INDEX test_tenant_pkey ON public.test_tenant USING btree (id); + +alter table "public"."test_tenant" add constraint "test_tenant_pkey" PRIMARY KEY using index "test_tenant_pkey"; + +alter table "public"."community_question" add constraint "community_question_course_id_fkey" FOREIGN KEY (course_id) REFERENCES course(id) not valid; + +alter table "public"."community_question" validate constraint "community_question_course_id_fkey"; \ No newline at end of file diff --git a/supabase/migrations/20240320081809_email_verification.sql b/supabase/migrations/20240320081809_email_verification.sql new file mode 100644 index 00000000..2acd4415 --- /dev/null +++ b/supabase/migrations/20240320081809_email_verification.sql @@ -0,0 +1,6 @@ +alter table "public"."profile" add column "is_email_verified" boolean default false; +alter table "public"."profile" add column "verified_at" timestamp with time zone; + +CREATE UNIQUE INDEX profile_email_key ON public.profile USING btree (email); + +alter table "public"."profile" add constraint "profile_email_key" UNIQUE using index "profile_email_key"; \ No newline at end of file diff --git a/supabase/migrations/20240323154037_translation.sql b/supabase/migrations/20240323154037_translation.sql new file mode 100644 index 00000000..f98fff6c --- /dev/null +++ b/supabase/migrations/20240323154037_translation.sql @@ -0,0 +1,13 @@ +create type "public"."LOCALE" as enum ('en', 'hi', 'fr', 'pt', 'de', 'vi', 'ru', 'es'); + +create table + public.lesson_language ( + id bigint generated by default as identity, + content text null, + lesson_id uuid null default gen_random_uuid (), + locale "LOCALE" default 'en'::"LOCALE", + constraint lesson_language_pkey primary key (id), + constraint public_lesson_language_lesson_id_fkey foreign key (lesson_id) references lesson (id) + ) tablespace pg_default; + +alter table "public"."profile" add column "locale" "LOCALE" default 'en'::"LOCALE"; \ No newline at end of file diff --git a/supabase/migrations/20240406215136_org_billing.sql b/supabase/migrations/20240406215136_org_billing.sql new file mode 100644 index 00000000..019ebf24 --- /dev/null +++ b/supabase/migrations/20240406215136_org_billing.sql @@ -0,0 +1,26 @@ +create type "public"."PLAN" as enum ('EARLY_ADOPTER', 'ENTERPRISE', 'BASIC'); + +create table "public"."organization_plan" ( + "id" bigint generated by default as identity not null, + "activated_at" timestamp with time zone not null default now(), + "org_id" uuid, + "plan_name" "PLAN", + "is_active" boolean, + "deactivated_at" timestamp with time zone, + "updated_at" timestamp with time zone default now(), + "payload" jsonb, + "triggered_by" bigint +); + + +CREATE UNIQUE INDEX organization_plan_pkey ON public.organization_plan USING btree (id); + +alter table "public"."organization_plan" add constraint "organization_plan_pkey" PRIMARY KEY using index "organization_plan_pkey"; + +alter table "public"."organization_plan" add constraint "organization_plan_org_id_fkey" FOREIGN KEY (org_id) REFERENCES organization(id) not valid; + +alter table "public"."organization_plan" validate constraint "organization_plan_org_id_fkey"; + +alter table "public"."organization_plan" add constraint "organization_plan_triggered_by_fkey" FOREIGN KEY (triggered_by) REFERENCES organizationmember(id) not valid; + +alter table "public"."organization_plan" validate constraint "organization_plan_triggered_by_fkey"; diff --git a/supabase/migrations/20240509080635_ai_grading.sql b/supabase/migrations/20240509080635_ai_grading.sql new file mode 100644 index 00000000..5ab7764b --- /dev/null +++ b/supabase/migrations/20240509080635_ai_grading.sql @@ -0,0 +1 @@ +alter table "public"."submission" add column "feedback" text; \ No newline at end of file diff --git a/supabase/migrations/20240516092053_customization.sql b/supabase/migrations/20240516092053_customization.sql new file mode 100644 index 00000000..ab5a162c --- /dev/null +++ b/supabase/migrations/20240516092053_customization.sql @@ -0,0 +1 @@ +alter table "public"."organization" add column "customization" json not null default '{"apps":{"poll":true,"comments":true},"course":{"grading":true,"newsfeed":true},"dashboard":{"exercise":true,"community":true,"bannerText":"","bannerImage":""}}'::json; \ No newline at end of file diff --git a/supabase/migrations/20240516153823_course_type.sql b/supabase/migrations/20240516153823_course_type.sql new file mode 100644 index 00000000..9c5f0c20 --- /dev/null +++ b/supabase/migrations/20240516153823_course_type.sql @@ -0,0 +1,37 @@ +create type "public"."COURSE_TYPE" as enum ('SELF_PACED', 'LIVE_CLASS'); + +alter table "public"."course" add column "type" "COURSE_TYPE" default 'LIVE_CLASS'::"COURSE_TYPE"; + +drop function if exists "public"."get_courses"(org_id_arg uuid, profile_id_arg uuid); + +create +or replace function public.get_courses (org_id_arg uuid, profile_id_arg uuid) returns table ( + id uuid, + org_id uuid, + title character varying, + slug character varying, + description character varying, + logo text, + banner_image text, + cost bigint, + currency character varying, + is_published boolean, + profile_id uuid, + role_id bigint, + total_lessons bigint, + total_students bigint, + progress_rate bigint, + type "COURSE_TYPE" +) language plpgsql as $function$ +BEGIN + Return query + select course.id, organization.id AS org_id, course.title, course.slug, course.description, course.logo, course.banner_image, course.cost, course.currency, course.is_published, groupmember.profile_id, groupmember.role_id, (select COUNT(*) from lesson as l where l.course_id = course.id) AS total_lessons, (select COUNT(*) from groupmember as gm where gm.group_id = course.group_id AND gm.role_id = 3) as total_students, (select COUNT(*) from lesson_completion as lc join lesson as l on l.id = lc.lesson_id where l.course_id = course.id and lc.is_complete = true and lc.profile_id = profile_id_arg) AS progress_rate, course.type as type + from course + join "group" on "group".id = course.group_id + join groupmember on groupmember.group_id = course.group_id + join organization on organization.id = "group".organization_id + where course.status = 'ACTIVE' AND organization.id = org_id_arg + -- GROUP BY course.id, groupmember.profile_id + ORDER BY course.created_at DESC; +END; +$function$; \ No newline at end of file diff --git a/supabase/migrations/20240518054308_new_certificates.sql b/supabase/migrations/20240518054308_new_certificates.sql new file mode 100644 index 00000000..78aa405b --- /dev/null +++ b/supabase/migrations/20240518054308_new_certificates.sql @@ -0,0 +1,31 @@ +set check_function_bodies = off; + +CREATE OR REPLACE FUNCTION public.get_course_progress(course_id_arg uuid, profile_id_arg uuid) + RETURNS TABLE(lessons_count bigint, lessons_completed bigint, exercises_count bigint, exercises_completed bigint) + LANGUAGE plpgsql +AS $function$ +BEGIN +RETURN QUERY +select + count(lesson.id) as lessons_count, + count(lesson_completion.id) as lessons_completed, + count(exercise.id) as exercises_count, + count(submission.id) as exercises_completed +from + course + join "group" on "group".id = course.group_id + join groupmember on groupmember.group_id = course.group_id + join profile on profile.id = groupmember.profile_id + left join lesson on lesson.course_id = course.id + left join lesson_completion on lesson_completion.lesson_id = lesson.id + and lesson_completion.is_complete = true + and lesson_completion.profile_id = profile.id + left join exercise on exercise.lesson_id = lesson.id + left join submission on submission.exercise_id = exercise.id + and submission.submitted_by = groupmember.id +where + course.id = course_id_arg + and profile.id = profile_id_arg; +END; +$function$ +; \ No newline at end of file diff --git a/supabase/migrations/20240524192915_get_courses_for_admin.sql b/supabase/migrations/20240524192915_get_courses_for_admin.sql new file mode 100644 index 00000000..5040b45d --- /dev/null +++ b/supabase/migrations/20240524192915_get_courses_for_admin.sql @@ -0,0 +1,31 @@ +drop function if exists "public"."get_courses"(org_id_arg uuid, profile_id_arg uuid); + +create +or replace function public.get_courses (org_id_arg uuid, profile_id_arg uuid) returns table ( + id uuid, + org_id uuid, + title character varying, + slug character varying, + description character varying, + logo text, + banner_image text, + cost bigint, + currency character varying, + is_published boolean, + total_lessons bigint, + total_students bigint, + progress_rate bigint, + type "COURSE_TYPE", + member_profile_id uuid +) language plpgsql as $function$ +BEGIN + Return query + select course.id, organization.id AS org_id, course.title, course.slug, course.description, course.logo, course.banner_image, course.cost, course.currency, course.is_published, (select COUNT(*) from lesson as l where l.course_id = course.id) AS total_lessons, (select COUNT(*) from groupmember as gm where gm.group_id = course.group_id AND gm.role_id = 3) as total_students, (select COUNT(*) from lesson_completion as lc join lesson as l on l.id = lc.lesson_id where l.course_id = course.id and lc.is_complete = true and lc.profile_id = profile_id_arg) AS progress_rate, course.type as type, (select groupmember.profile_id from groupmember where groupmember.group_id = "group".id and groupmember.profile_id = profile_id_arg) as member_profile_id + from course + join "group" on "group".id = course.group_id + join organization on organization.id = "group".organization_id + where course.status = 'ACTIVE' AND organization.id = org_id_arg + -- GROUP BY course.id, groupmember.profile_id + ORDER BY course.created_at DESC; +END; +$function$; \ No newline at end of file diff --git a/supabase/migrations/20240528050512_cascade_delete_lesson.sql b/supabase/migrations/20240528050512_cascade_delete_lesson.sql new file mode 100644 index 00000000..c1d90e14 --- /dev/null +++ b/supabase/migrations/20240528050512_cascade_delete_lesson.sql @@ -0,0 +1,47 @@ +-- Drop table cause it was never used +drop table if exists public.lesson_progress; + +alter table public.exercise +drop constraint exercise_lesson_id_fkey, +add constraint exercise_lesson_id_fkey foreign key (lesson_id) references lesson (id) +on delete cascade; + +alter table public.lesson_comment +drop constraint lesson_comment_lesson_id_fkey, +add constraint lesson_comment_lesson_id_fkey foreign key (lesson_id) references lesson (id) +on delete cascade; + +alter table public.question +drop constraint question_exercise_id_fkey, +add constraint question_exercise_id_fkey foreign key (exercise_id) references exercise (id) +on delete cascade; + +alter table public.option +drop constraint option_question_id_fkey, +add constraint option_question_id_fkey foreign key (question_id) references question (id) +on delete cascade; + +alter table public.question_answer +drop constraint question_answer_question_id_fkey, +add constraint question_answer_question_id_fkey foreign key (question_id) references question (id) +on delete cascade; + +alter table public.submission +drop constraint submission_exercise_id_fkey, +add constraint submission_exercise_id_fkey foreign key (exercise_id) references exercise (id) +on delete cascade; + +alter table public.submission +drop constraint submission_course_id_fkey, +add constraint submission_course_id_fkey foreign key (course_id) references course (id) +on delete cascade; + +alter table public.question_answer +drop constraint question_answer_submission_id_fkey, +add constraint question_answer_submission_id_fkey foreign key (submission_id) references submission (id) +on delete cascade; + +alter table public.lesson_completion +drop constraint lesson_completion_lesson_id_fkey, +add constraint lesson_completion_lesson_id_fkey foreign key (lesson_id) references lesson (id) +on delete cascade; diff --git a/supabase/migrations/20240610132742_lesson_language_versioning.sql b/supabase/migrations/20240610132742_lesson_language_versioning.sql new file mode 100644 index 00000000..9be4088b --- /dev/null +++ b/supabase/migrations/20240610132742_lesson_language_versioning.sql @@ -0,0 +1,25 @@ +CREATE TABLE lesson_language_history ( + id SERIAL PRIMARY KEY, + lesson_language_id INTEGER REFERENCES lesson_language(id), + old_content TEXT, + new_content TEXT, + timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE FUNCTION update_lesson_language_history() + RETURNS trigger AS $$ +BEGIN + IF TG_OP IN ('INSERT', 'UPDATE') THEN + INSERT INTO lesson_language_history (lesson_language_id, old_content, new_content) + VALUES (NEW.id, COALESCE(OLD.content, ''), NEW.content); + END IF; + RETURN NULL; +END; +$$ LANGUAGE plpgsql; + + +CREATE TRIGGER update_lesson_language_history_trigger +AFTER INSERT +OR +UPDATE ON lesson_language for each row +EXECUTE PROCEDURE update_lesson_language_history(); \ No newline at end of file diff --git a/supabase/migrations/20240618210526_lesson_versions.sql b/supabase/migrations/20240618210526_lesson_versions.sql new file mode 100644 index 00000000..65831088 --- /dev/null +++ b/supabase/migrations/20240618210526_lesson_versions.sql @@ -0,0 +1,7 @@ +create or replace view "public"."lesson_versions" as SELECT llh.old_content, + llh.new_content, + llh."timestamp", + ll.locale, + ll.lesson_id + FROM (lesson_language_history llh + JOIN lesson_language ll ON ((ll.id = llh.lesson_language_id))); \ No newline at end of file diff --git a/supabase/migrations/20240701085652_show_explore_courses.sql b/supabase/migrations/20240701085652_show_explore_courses.sql new file mode 100644 index 00000000..f2ae43d2 --- /dev/null +++ b/supabase/migrations/20240701085652_show_explore_courses.sql @@ -0,0 +1,17 @@ +CREATE OR REPLACE FUNCTION public.get_explore_courses(org_id_arg uuid, profile_id_arg uuid) + RETURNS TABLE(id uuid, org_id uuid, title character varying, slug character varying, description character varying, logo text, banner_image text, cost bigint, currency character varying, is_published boolean, total_lessons bigint, total_students bigint, progress_rate bigint, type "COURSE_TYPE", other_profile_id uuid) + LANGUAGE plpgsql +AS $function$ +BEGIN + Return query + select course.id, organization.id AS org_id, course.title, course.slug, course.description, course.logo, course.banner_image, course.cost, course.currency, course.is_published, (select COUNT(*) from lesson +as l where l.course_id = course.id) AS total_lessons, (select COUNT(*) from groupmember as gm where gm.group_id = course.group_id AND gm.role_id = 3) as total_students, (select COUNT(*) from lesson_completion as lc join lesson as l on l.id = lc.lesson_id where l.course_id = course.id and lc.is_complete = true and lc.profile_id = profile_id_arg) AS progress_rate, course.type as type, (select groupmember.profile_id from groupmember where groupmember.group_id = "group".id and groupmember.profile_id != profile_id_arg +limit 1) as other_profile_id + from course + join "group" on "group".id = course.group_id + join organization on organization.id = "group".organization_id + where course.status = 'ACTIVE' AND course.is_published = true AND organization.id = org_id_arg AND profile_id_arg NOT IN (SELECT groupmember.profile_id FROM groupmember WHERE groupmember.group_id = course.group_id) + ORDER BY course.created_at DESC; +END; +$function$ +; \ No newline at end of file diff --git a/supabase/migrations/20240717053936_rls.sql b/supabase/migrations/20240717053936_rls.sql new file mode 100644 index 00000000..b55c2a22 --- /dev/null +++ b/supabase/migrations/20240717053936_rls.sql @@ -0,0 +1,1321 @@ +drop policy "Enable insert for authenticated users only" on "public"."course"; + +drop policy "Enable update for authenticated users only" on "public"."course"; + +drop policy "Enable insert for authenticated users only" on "public"."lesson_comment"; + +alter table "public"."apps_poll" enable row level security; + +alter table "public"."apps_poll_option" enable row level security; + +alter table "public"."apps_poll_submission" enable row level security; + +alter table "public"."community_answer" enable row level security; + +alter table "public"."community_question" enable row level security; + +alter table "public"."course" enable row level security; + +alter table "public"."course_newsfeed" enable row level security; + +alter table "public"."course_newsfeed_comment" enable row level security; + +alter table "public"."exercise" enable row level security; + +alter table "public"."group" enable row level security; + +alter table "public"."group_attendance" enable row level security; + +alter table "public"."groupmember" enable row level security; + +alter table "public"."lesson" enable row level security; + +alter table "public"."lesson_completion" enable row level security; + +alter table "public"."lesson_language" enable row level security; + +alter table "public"."lesson_language_history" enable row level security; + +alter table "public"."option" enable row level security; + +alter table "public"."organization" enable row level security; + +alter table "public"."organization_plan" enable row level security; + +alter table "public"."organizationmember" enable row level security; + +alter table "public"."question" enable row level security; + +alter table "public"."question_answer" enable row level security; + +alter table "public"."question_type" enable row level security; + +alter table "public"."quiz" enable row level security; + +alter table "public"."quiz_play" enable row level security; + +alter table "public"."role" enable row level security; + +alter table "public"."submission" enable row level security; + +alter table "public"."submissionstatus" enable row level security; + +alter table "public"."test_tenant" enable row level security; + +alter table "public"."waitinglist" enable row level security; + +set check_function_bodies = off; + +CREATE OR REPLACE FUNCTION public.is_org_admin() + RETURNS boolean + LANGUAGE plpgsql + SECURITY DEFINER +AS $function$ +BEGIN + RETURN EXISTS ( + SELECT 1 + FROM organizationmember + WHERE organization_id = organization_id + AND profile_id = (select auth.uid()) + AND role_id = 1 + ); +END; +$function$ +; + +CREATE OR REPLACE FUNCTION public.is_org_admin(org_id uuid) + RETURNS boolean + LANGUAGE plpgsql +AS $function$ +BEGIN + RETURN EXISTS ( + SELECT 1 + FROM organizationmember + WHERE organization_id = org_id + AND profile_id = (select auth.uid()) + AND role_id = 1 + ); +END; +$function$ +; + +CREATE OR REPLACE FUNCTION public.is_org_member() + RETURNS boolean + LANGUAGE plpgsql + SECURITY DEFINER +AS $function$ +BEGIN + RETURN EXISTS ( + SELECT 1 + FROM organizationmember + WHERE organization_id = organization_id + AND profile_id = (select auth.uid()) + ); +END; +$function$ +; + +CREATE OR REPLACE FUNCTION public.is_user_in_course_group(group_id uuid) + RETURNS boolean + LANGUAGE plpgsql + SECURITY DEFINER +AS $function$ begin return exists +(SELECT 1 FROM groupmember member +JOIN "group" g ON g.id = member.group_id +WHERE member.role_id IS NOT NULL +AND member.profile_id = auth.uid() +AND g.id = $1 +); +END; +$function$ +; + +CREATE OR REPLACE FUNCTION public.is_user_in_group_with_role(group_id integer) + RETURNS boolean + LANGUAGE plpgsql + SECURITY DEFINER +AS $function$ +begin + return exists ( + SELECT 1 + FROM organizationmember m + JOIN organization o ON o.organization_id = m.organization_id + WHERE m.role_id IS NOT NULL + AND m.profile_id = auth.uid () + AND EXISTS ( + SELECT 1 + FROM "group" g + WHERE g.group_id = $1 + AND g.organization_id = o.organization_id + ) + ); +END; +$function$ +; + +CREATE OR REPLACE FUNCTION public.is_user_in_group_with_role(group_id uuid) + RETURNS boolean + LANGUAGE plpgsql + SECURITY DEFINER +AS $function$ +begin + return exists ( + SELECT 1 + FROM organizationmember member + JOIN organization o ON o.id = member.organization_id + WHERE member.role_id IS NOT NULL + AND member.profile_id = auth.uid () + AND EXISTS ( + SELECT 1 + FROM "group" g + WHERE g.id = $1 + AND g.organization_id = o.id + ) + ); +END; +$function$ +; + +create policy "Delete only your own poll" +on "public"."apps_poll" +as permissive +for delete +to public +using ((auth.uid() = ( SELECT groupmember.profile_id + FROM groupmember + WHERE (groupmember.id = apps_poll."authorId")))); + + +create policy "Update only your own" +on "public"."apps_poll" +as permissive +for update +to public +using ((auth.uid() = ( SELECT groupmember.profile_id + FROM groupmember + WHERE (groupmember.id = apps_poll."authorId")))) +with check ((auth.uid() = ( SELECT groupmember.profile_id + FROM groupmember + WHERE (groupmember.id = apps_poll."authorId")))); + + +create policy "User must be a course member to INSERT" +on "public"."apps_poll" +as permissive +for insert +to public +with check (is_user_in_course_group(( SELECT groupmember.group_id + FROM groupmember + WHERE (groupmember.id = apps_poll."authorId") + LIMIT 1))); + + +create policy "User must be course member to SELECT" +on "public"."apps_poll" +as permissive +for select +to public +using (is_user_in_course_group(( SELECT groupmember.group_id + FROM groupmember + WHERE (groupmember.id = apps_poll."authorId") + LIMIT 1))); + + +create policy "User must be a course member to INSERT" +on "public"."apps_poll_option" +as permissive +for insert +to public +with check (is_user_in_course_group(( SELECT groupmember.group_id + FROM groupmember + WHERE (groupmember.id = ( SELECT apps_poll."authorId" + FROM apps_poll + WHERE (apps_poll.id = apps_poll_option.poll_id) + LIMIT 1)) + LIMIT 1))); + + +create policy "User must be a course member to UPDATE" +on "public"."apps_poll_option" +as permissive +for update +to public +using (is_user_in_course_group(( SELECT groupmember.group_id + FROM groupmember + WHERE (groupmember.id = ( SELECT apps_poll."authorId" + FROM apps_poll + WHERE (apps_poll.id = apps_poll_option.poll_id) + LIMIT 1)) + LIMIT 1))) +with check (is_user_in_course_group(( SELECT groupmember.group_id + FROM groupmember + WHERE (groupmember.id = ( SELECT apps_poll."authorId" + FROM apps_poll + WHERE (apps_poll.id = apps_poll_option.poll_id) + LIMIT 1)) + LIMIT 1))); + + +create policy "User must be a teacher to DELETE" +on "public"."apps_poll_option" +as permissive +for delete +to public +using (is_user_in_group_with_role(( SELECT groupmember.group_id + FROM groupmember + WHERE (groupmember.id = ( SELECT apps_poll."authorId" + FROM apps_poll + WHERE (apps_poll.id = apps_poll_option.poll_id) + LIMIT 1)) + LIMIT 1))); + + +create policy "User must be course member to SELECT" +on "public"."apps_poll_option" +as permissive +for select +to public +using (is_user_in_course_group(( SELECT groupmember.group_id + FROM groupmember + WHERE (groupmember.id = ( SELECT apps_poll."authorId" + FROM apps_poll + WHERE (apps_poll.id = apps_poll_option.poll_id) + LIMIT 1)) + LIMIT 1))); + + +create policy "Authenticated users can read" +on "public"."apps_poll_submission" +as permissive +for select +to public +using ((auth.uid() IS NOT NULL)); + + +create policy "Delete your own submission" +on "public"."apps_poll_submission" +as permissive +for delete +to public +using ((auth.uid() = ( SELECT groupmember.profile_id + FROM groupmember + WHERE (groupmember.id = apps_poll_submission.selected_by_id)))); + + +create policy "Enable insert for authenticated users only" +on "public"."apps_poll_submission" +as permissive +for insert +to authenticated +with check (true); + + +create policy "Update your own submission" +on "public"."apps_poll_submission" +as permissive +for update +to public +using ((auth.uid() = ( SELECT groupmember.profile_id + FROM groupmember + WHERE (groupmember.id = apps_poll_submission.selected_by_id)))) +with check ((auth.uid() = ( SELECT groupmember.profile_id + FROM groupmember + WHERE (groupmember.id = apps_poll_submission.selected_by_id)))); + + +create policy "Authenticated users can SELECT" +on "public"."community_answer" +as permissive +for select +to public +using ((auth.uid() IS NOT NULL)); + + +create policy "Delete your own answer" +on "public"."community_answer" +as permissive +for delete +to public +using ((auth.uid() = author_profile_id)); + + +create policy "Enable insert for authenticated users only" +on "public"."community_answer" +as permissive +for insert +to authenticated +with check (true); + + +create policy "Update your own answer" +on "public"."community_answer" +as permissive +for update +to public +using ((auth.uid() = author_profile_id)) +with check ((auth.uid() = author_profile_id)); + + +create policy "Authenticated users can SELECT" +on "public"."community_question" +as permissive +for select +to public +using ((auth.uid() IS NOT NULL)); + + +create policy "Delete your own question" +on "public"."community_question" +as permissive +for delete +to public +using ((auth.uid() = author_profile_id)); + + +create policy "Update your own question" +on "public"."community_question" +as permissive +for update +to public +using ((auth.uid() = author_profile_id)) +with check ((auth.uid() = author_profile_id)); + + +create policy "User must be an org member to DELETE" +on "public"."course" +as permissive +for delete +to public +using (is_user_in_group_with_role(group_id)); + + +create policy "User must be an org member to INSERT" +on "public"."course" +as permissive +for insert +to public +with check (is_user_in_group_with_role(group_id)); + + +create policy "User must be an org member to UPDATE" +on "public"."course" +as permissive +for update +to public +using (is_user_in_group_with_role(group_id)) +with check (is_user_in_group_with_role(group_id)); + + +create policy "Delete your own comment" +on "public"."course_newsfeed" +as permissive +for delete +to public +using ((auth.uid() = ( SELECT groupmember.profile_id + FROM groupmember + WHERE (groupmember.id = course_newsfeed.author_id)))); + + +create policy "Update only your own" +on "public"."course_newsfeed" +as permissive +for update +to public +using ((auth.uid() = ( SELECT groupmember.profile_id + FROM groupmember + WHERE (groupmember.id = course_newsfeed.author_id)))) +with check ((auth.uid() = ( SELECT groupmember.profile_id + FROM groupmember + WHERE (groupmember.id = course_newsfeed.author_id)))); + + +create policy "User must be a course member to INSERT" +on "public"."course_newsfeed" +as permissive +for insert +to public +with check (is_user_in_course_group(( SELECT course.group_id + FROM course + WHERE (course.id = course_newsfeed.course_id) + LIMIT 1))); + + +create policy "User must be a course member to SELECT" +on "public"."course_newsfeed" +as permissive +for select +to public +using (is_user_in_course_group(( SELECT course.group_id + FROM course + WHERE (course.id = course_newsfeed.course_id) + LIMIT 1))); + + +create policy "Delete your own" +on "public"."course_newsfeed_comment" +as permissive +for delete +to public +using ((auth.uid() = ( SELECT groupmember.profile_id + FROM groupmember + WHERE (groupmember.id = course_newsfeed_comment.author_id)))); + + +create policy "Update only your own" +on "public"."course_newsfeed_comment" +as permissive +for update +to public +using ((auth.uid() = ( SELECT groupmember.profile_id + FROM groupmember + WHERE (groupmember.id = course_newsfeed_comment.author_id)))) +with check ((auth.uid() = ( SELECT groupmember.profile_id + FROM groupmember + WHERE (groupmember.id = course_newsfeed_comment.author_id)))); + + +create policy "User must be a course member to INSERT" +on "public"."course_newsfeed_comment" +as permissive +for insert +to public +with check (is_user_in_course_group(( SELECT course.group_id + FROM course + WHERE (course.id = ( SELECT course_newsfeed.course_id + FROM course_newsfeed + WHERE (course_newsfeed.id = course_newsfeed_comment.course_newsfeed_id))) + LIMIT 1))); + + +create policy "User must be a course member to SELECT" +on "public"."course_newsfeed_comment" +as permissive +for select +to public +using (is_user_in_course_group(( SELECT course.group_id + FROM course + WHERE (course.id = ( SELECT course_newsfeed.course_id + FROM course_newsfeed + WHERE (course_newsfeed.id = course_newsfeed_comment.course_newsfeed_id))) + LIMIT 1))); + + +create policy "Enable read access for all users" +on "public"."exercise" +as permissive +for select +to public +using (true); + + +create policy "User must be an org member to DELETE" +on "public"."exercise" +as permissive +for delete +to public +using (is_user_in_group_with_role(( SELECT course.group_id + FROM course + WHERE (course.id = ( SELECT lesson.course_id + FROM lesson + WHERE (lesson.id = exercise.lesson_id) + LIMIT 1)) + LIMIT 1))); + + +create policy "User must be an org member to INSERT" +on "public"."exercise" +as permissive +for insert +to public +with check (is_user_in_group_with_role(( SELECT course.group_id + FROM course + WHERE (course.id = ( SELECT lesson.course_id + FROM lesson + WHERE (lesson.id = exercise.lesson_id) + LIMIT 1)) + LIMIT 1))); + + +create policy "User must be an org member to UPDATE" +on "public"."exercise" +as permissive +for update +to public +using (is_user_in_group_with_role(( SELECT course.group_id + FROM course + WHERE (course.id = ( SELECT lesson.course_id + FROM lesson + WHERE (lesson.id = exercise.lesson_id) + LIMIT 1)) + LIMIT 1))) +with check (is_user_in_group_with_role(( SELECT course.group_id + FROM course + WHERE (course.id = ( SELECT lesson.course_id + FROM lesson + WHERE (lesson.id = exercise.lesson_id) + LIMIT 1)) + LIMIT 1))); + + +create policy "Enable insert for authenticated users only" +on "public"."group" +as permissive +for insert +to authenticated +with check (true); + + +create policy "Enable read access for all users" +on "public"."group" +as permissive +for select +to public +using (true); + + +create policy "Only org admins can delete" +on "public"."group" +as permissive +for delete +to public +using (is_org_admin()); + + +create policy "Only org admins can update" +on "public"."group" +as permissive +for update +to public +using (is_org_admin()) +with check (is_org_admin()); + + +create policy "User must be a course member to INSERT" +on "public"."group_attendance" +as permissive +for insert +to public +with check (is_user_in_course_group(( SELECT course.group_id + FROM course + WHERE (course.id = group_attendance.course_id) + LIMIT 1))); + + +create policy "User must be a course member to SELECT" +on "public"."group_attendance" +as permissive +for select +to public +using (is_user_in_course_group(( SELECT course.group_id + FROM course + WHERE (course.id = group_attendance.course_id) + LIMIT 1))); + + +create policy "User must be a course member to UPDATE" +on "public"."group_attendance" +as permissive +for update +to public +using (is_user_in_course_group(( SELECT course.group_id + FROM course + WHERE (course.id = group_attendance.course_id) + LIMIT 1))) +with check (is_user_in_course_group(( SELECT course.group_id + FROM course + WHERE (course.id = group_attendance.course_id) + LIMIT 1))); + + +create policy "User must be an org member to DELETE" +on "public"."group_attendance" +as permissive +for delete +to public +using (is_user_in_group_with_role(( SELECT course.group_id + FROM course + WHERE (course.id = group_attendance.course_id) + LIMIT 1))); + + +create policy "Enable insert for authenticated users only" +on "public"."groupmember" +as permissive +for insert +to authenticated +with check (true); + + +create policy "Enable read access for all users" +on "public"."groupmember" +as permissive +for select +to public +using (true); + + +create policy "User must be an org member to DELETE" +on "public"."groupmember" +as permissive +for delete +to public +using (is_user_in_group_with_role(group_id)); + + +create policy "User must be an org member to UPDATE" +on "public"."groupmember" +as permissive +for update +to public +using (is_user_in_group_with_role(group_id)) +with check (is_user_in_group_with_role(group_id)); + + +create policy "Enable read access for all users" +on "public"."lesson" +as permissive +for select +to public +using (true); + + +create policy "User must be an org member to DELETE" +on "public"."lesson" +as permissive +for delete +to public +using (is_user_in_group_with_role(( SELECT course.group_id + FROM course + WHERE (course.id = lesson.course_id) + LIMIT 1))); + + +create policy "User must be an org member to INSERT" +on "public"."lesson" +as permissive +for insert +to public +with check (is_user_in_group_with_role(( SELECT course.group_id + FROM course + WHERE (course.id = lesson.course_id) + LIMIT 1))); + + +create policy "User must be an org member to UPDATE" +on "public"."lesson" +as permissive +for update +to public +using (is_user_in_group_with_role(( SELECT course.group_id + FROM course + WHERE (course.id = lesson.course_id) + LIMIT 1))) +with check (is_user_in_group_with_role(( SELECT course.group_id + FROM course + WHERE (course.id = lesson.course_id) + LIMIT 1))); + + +create policy "Delete only your own comment" +on "public"."lesson_comment" +as permissive +for delete +to public +using ((auth.uid() = ( SELECT groupmember.profile_id + FROM groupmember + WHERE (groupmember.id = lesson_comment.groupmember_id)))); + + +create policy "Update only your own" +on "public"."lesson_comment" +as permissive +for update +to public +using ((auth.uid() = ( SELECT groupmember.profile_id + FROM groupmember + WHERE (groupmember.id = lesson_comment.groupmember_id)))) +with check ((auth.uid() = ( SELECT groupmember.profile_id + FROM groupmember + WHERE (groupmember.id = lesson_comment.groupmember_id)))); + + +create policy "User must be in course group to INSERT" +on "public"."lesson_comment" +as permissive +for insert +to public +with check (is_user_in_course_group(( SELECT course.group_id + FROM course + WHERE (course.id = ( SELECT lesson.course_id + FROM lesson + WHERE (lesson.id = lesson_comment.lesson_id) + LIMIT 1)) + LIMIT 1))); + + +create policy "Enable read access for all users" +on "public"."lesson_completion" +as permissive +for select +to public +using (true); + + +create policy "User must be an course member to INSERT" +on "public"."lesson_completion" +as permissive +for all +to public +with check (is_user_in_course_group(( SELECT course.group_id + FROM course + WHERE (course.id = ( SELECT lesson.course_id + FROM lesson + WHERE (lesson.id = lesson_completion.lesson_id) + LIMIT 1)) + LIMIT 1))); + + +create policy "User must be an org member to DELETE" +on "public"."lesson_completion" +as permissive +for delete +to public +using (is_user_in_group_with_role(( SELECT course.group_id + FROM course + WHERE (course.id = ( SELECT lesson.course_id + FROM lesson + WHERE (lesson.id = lesson_completion.lesson_id) + LIMIT 1)) + LIMIT 1))); + + +create policy "User must be an org member to UPDATE" +on "public"."lesson_completion" +as permissive +for update +to public +using (is_user_in_group_with_role(( SELECT course.group_id + FROM course + WHERE (course.id = ( SELECT lesson.course_id + FROM lesson + WHERE (lesson.id = lesson_completion.lesson_id) + LIMIT 1)) + LIMIT 1))) +with check (is_user_in_group_with_role(( SELECT course.group_id + FROM course + WHERE (course.id = ( SELECT lesson.course_id + FROM lesson + WHERE (lesson.id = lesson_completion.lesson_id) + LIMIT 1)) + LIMIT 1))); + + +create policy "Enable read access for all users" +on "public"."lesson_language" +as permissive +for select +to public +using (true); + + +create policy "User must be an org member to DELETE" +on "public"."lesson_language" +as permissive +for delete +to public +using (is_user_in_group_with_role(( SELECT course.group_id + FROM course + WHERE (course.id = ( SELECT lesson.course_id + FROM lesson + WHERE (lesson.id = lesson_language.lesson_id) + LIMIT 1)) + LIMIT 1))); + + +create policy "User must be an org member to INSERT" +on "public"."lesson_language" +as permissive +for insert +to public +with check (is_user_in_group_with_role(( SELECT course.group_id + FROM course + WHERE (course.id = ( SELECT lesson.course_id + FROM lesson + WHERE (lesson.id = lesson_language.lesson_id) + LIMIT 1)) + LIMIT 1))); + + +create policy "User must be an org member to UPDATE" +on "public"."lesson_language" +as permissive +for update +to public +using (is_user_in_group_with_role(( SELECT course.group_id + FROM course + WHERE (course.id = ( SELECT lesson.course_id + FROM lesson + WHERE (lesson.id = lesson_language.lesson_id) + LIMIT 1)) + LIMIT 1))) +with check (is_user_in_group_with_role(( SELECT course.group_id + FROM course + WHERE (course.id = ( SELECT lesson.course_id + FROM lesson + WHERE (lesson.id = lesson_language.lesson_id) + LIMIT 1)) + LIMIT 1))); + + +create policy "Authenticated users can SELECT" +on "public"."lesson_language_history" +as permissive +for select +to public +using ((auth.uid() IS NOT NULL)); + + +create policy "Allow authenticated users to SELECT" +on "public"."option" +as permissive +for select +to public +using ((auth.uid() IS NOT NULL)); + + +create policy "User must be an org member to DELETE" +on "public"."option" +as permissive +for delete +to public +using (is_user_in_group_with_role(( SELECT course.group_id + FROM course + WHERE (course.id = ( SELECT lesson.course_id + FROM lesson + WHERE (lesson.id = ( SELECT exercise.lesson_id + FROM exercise + WHERE (exercise.id = ( SELECT question.exercise_id + FROM question + WHERE (question.id = option.question_id) + LIMIT 1)) + LIMIT 1)) + LIMIT 1)) + LIMIT 1))); + + +create policy "User must be an org member to INSERT" +on "public"."option" +as permissive +for insert +to public +with check (is_user_in_group_with_role(( SELECT course.group_id + FROM course + WHERE (course.id = ( SELECT lesson.course_id + FROM lesson + WHERE (lesson.id = ( SELECT exercise.lesson_id + FROM exercise + WHERE (exercise.id = ( SELECT question.exercise_id + FROM question + WHERE (question.id = option.question_id) + LIMIT 1)) + LIMIT 1)) + LIMIT 1)) + LIMIT 1))); + + +create policy "User must be an org member to UPDATE" +on "public"."option" +as permissive +for update +to public +using (is_user_in_group_with_role(( SELECT course.group_id + FROM course + WHERE (course.id = ( SELECT lesson.course_id + FROM lesson + WHERE (lesson.id = ( SELECT exercise.lesson_id + FROM exercise + WHERE (exercise.id = ( SELECT question.exercise_id + FROM question + WHERE (question.id = option.question_id) + LIMIT 1)) + LIMIT 1)) + LIMIT 1)) + LIMIT 1))) +with check (is_user_in_group_with_role(( SELECT course.group_id + FROM course + WHERE (course.id = ( SELECT lesson.course_id + FROM lesson + WHERE (lesson.id = ( SELECT exercise.lesson_id + FROM exercise + WHERE (exercise.id = ( SELECT question.exercise_id + FROM question + WHERE (question.id = option.question_id) + LIMIT 1)) + LIMIT 1)) + LIMIT 1)) + LIMIT 1))); + + +create policy "Authenticated users can delete" +on "public"."organization" +as permissive +for delete +to public +using ((auth.uid() IS NOT NULL)); + + +create policy "Enable read access for all users" +on "public"."organization" +as permissive +for select +to public +using (true); + + +create policy "User must be an admin to INSERT" +on "public"."organization" +as permissive +for insert +to public +with check ((id = ( SELECT organizationmember.organization_id + FROM organizationmember + WHERE ((organizationmember.profile_id = ( SELECT auth.uid() AS uid)) AND (organizationmember.role_id = 1)) + LIMIT 1))); + + +create policy "User must be admin to UPDATE" +on "public"."organization" +as permissive +for update +to public +using ((id in ( SELECT organizationmember.organization_id + FROM organizationmember + WHERE ((organizationmember.profile_id = ( SELECT auth.uid() AS uid)) AND (organizationmember.role_id = 1))))) +with check ((id in ( SELECT organizationmember.organization_id + FROM organizationmember + WHERE ((organizationmember.profile_id = ( SELECT auth.uid() AS uid)) AND (organizationmember.role_id = 1))))); + +create policy "User must be an org member to DELETE" +on "public"."organization_plan" +as permissive +for delete +to public +using (is_org_member()); + + +create policy "User must be an org member to INSERT" +on "public"."organization_plan" +as permissive +for insert +to public +with check (is_org_member()); + + +create policy "User must be an org member to SELECT" +on "public"."organization_plan" +as permissive +for select +to public +using (is_org_member()); + + +create policy "User must be an org member to UPDATE" +on "public"."organization_plan" +as permissive +for update +to public +using (is_org_member()) +with check (is_org_member()); + + +create policy "Allow authenticated users to read." +on "public"."organizationmember" +as permissive +for select +to public +using ((auth.uid() IS NOT NULL)); + + +create policy "Enable insert for authenticated users only" +on "public"."organizationmember" +as permissive +for insert +to authenticated +with check (true); + + +create policy "Only admin can delete" +on "public"."organizationmember" +as permissive +for delete +to public +using (is_org_admin()); + + +create policy "Only admin can update" +on "public"."organizationmember" +as permissive +for update +to public +using (is_org_admin()) +with check (is_org_admin()); + +create policy "Only user can update their account via email" +on "public"."organizationmember" +as PERMISSIVE +for UPDATE +to public +using ( + (select auth.jwt()) ->> 'email' = email +) +with check ( + (select auth.jwt()) ->> 'email' = email +); + +create policy "Only auth users can read profile" +on "public"."profile" +as permissive +for select +to authenticated, anon +using (true); + + +create policy "User can only delete their profiles" +on "public"."profile" +as permissive +for delete +to public +using ((auth.uid() = id)); + + +create policy "Allow authenticated users to SELECT" +on "public"."question" +as permissive +for select +to public +using ((auth.uid() IS NOT NULL)); + + +create policy "User must be an org member to DELETE" +on "public"."question" +as permissive +for delete +to public +using (is_user_in_group_with_role(( SELECT course.group_id + FROM course + WHERE (course.id = ( SELECT lesson.course_id + FROM lesson + WHERE (lesson.id = ( SELECT exercise.lesson_id + FROM exercise + WHERE (exercise.id = question.exercise_id))) + LIMIT 1)) + LIMIT 1))); + + +create policy "User must be an org member to INSERT" +on "public"."question" +as permissive +for insert +to public +with check (is_user_in_group_with_role(( SELECT course.group_id + FROM course + WHERE (course.id = ( SELECT lesson.course_id + FROM lesson + WHERE (lesson.id = ( SELECT exercise.lesson_id + FROM exercise + WHERE (exercise.id = question.exercise_id))) + LIMIT 1)) + LIMIT 1))); + + +create policy "User must be an org member to UPDATE" +on "public"."question" +as permissive +for update +to public +using (is_user_in_group_with_role(( SELECT course.group_id + FROM course + WHERE (course.id = ( SELECT lesson.course_id + FROM lesson + WHERE (lesson.id = ( SELECT exercise.lesson_id + FROM exercise + WHERE (exercise.id = question.exercise_id))) + LIMIT 1)) + LIMIT 1))) +with check (is_user_in_group_with_role(( SELECT course.group_id + FROM course + WHERE (course.id = ( SELECT lesson.course_id + FROM lesson + WHERE (lesson.id = ( SELECT exercise.lesson_id + FROM exercise + WHERE (exercise.id = question.exercise_id))) + LIMIT 1)) + LIMIT 1))); + + +create policy "Only authenticated users can select." +on "public"."question_answer" +as permissive +for select +to public +using ((auth.uid() IS NOT NULL)); + + +create policy "User must be an course member to DELETE" +on "public"."question_answer" +as permissive +for delete +to public +using (is_user_in_course_group(( SELECT course.group_id + FROM course + WHERE (course.id = ( SELECT lesson.course_id + FROM lesson + WHERE (lesson.id = ( SELECT exercise.lesson_id + FROM exercise + WHERE (exercise.id = ( SELECT question.exercise_id + FROM question + WHERE (question.id = question_answer.question_id) + LIMIT 1)) + LIMIT 1)) + LIMIT 1)) + LIMIT 1))); + + +create policy "User must be an course member to INSERT" +on "public"."question_answer" +as permissive +for insert +to public +with check (is_user_in_course_group(( SELECT course.group_id + FROM course + WHERE (course.id = ( SELECT lesson.course_id + FROM lesson + WHERE (lesson.id = ( SELECT exercise.lesson_id + FROM exercise + WHERE (exercise.id = ( SELECT question.exercise_id + FROM question + WHERE (question.id = question_answer.question_id) + LIMIT 1)) + LIMIT 1)) + LIMIT 1)) + LIMIT 1))); + + +create policy "User must be an course member to UPDATE" +on "public"."question_answer" +as permissive +for update +to public +using (is_user_in_course_group(( SELECT course.group_id + FROM course + WHERE (course.id = ( SELECT lesson.course_id + FROM lesson + WHERE (lesson.id = ( SELECT exercise.lesson_id + FROM exercise + WHERE (exercise.id = ( SELECT question.exercise_id + FROM question + WHERE (question.id = question_answer.question_id) + LIMIT 1)) + LIMIT 1)) + LIMIT 1)) + LIMIT 1))) +with check (is_user_in_course_group(( SELECT course.group_id + FROM course + WHERE (course.id = ( SELECT lesson.course_id + FROM lesson + WHERE (lesson.id = ( SELECT exercise.lesson_id + FROM exercise + WHERE (exercise.id = ( SELECT question.exercise_id + FROM question + WHERE (question.id = question_answer.question_id) + LIMIT 1)) + LIMIT 1)) + LIMIT 1)) + LIMIT 1))); + + +create policy "Enable read access for all users" +on "public"."question_type" +as permissive +for select +to public +using (true); + + +create policy "Authenticated users can SELECT" +on "public"."quiz" +as permissive +for select +to authenticated +using (true); + + +create policy "Authenticated users can SELECT" +on "public"."quiz_play" +as permissive +for select +to authenticated +using (true); + + +create policy "Enable read access for all users" +on "public"."role" +as permissive +for select +to public +using (true); + + +create policy "Only authenticated users can SELECT" +on "public"."submission" +as permissive +for select +to authenticated +using (true); + + +create policy "User must be a course member to DELETE" +on "public"."submission" +as permissive +for delete +to public +using (is_user_in_course_group(( SELECT course.group_id + FROM course + WHERE (course.id = submission.course_id) + LIMIT 1))); + + +create policy "User must be a course member to INSERT" +on "public"."submission" +as permissive +for insert +to public +with check (is_user_in_course_group(( SELECT course.group_id + FROM course + WHERE (course.id = submission.course_id) + LIMIT 1))); + + +create policy "User must be a course member to UPDATE" +on "public"."submission" +as permissive +for update +to public +using (is_user_in_course_group(( SELECT course.group_id + FROM course + WHERE (course.id = submission.course_id) + LIMIT 1))) +with check (is_user_in_course_group(( SELECT course.group_id + FROM course + WHERE (course.id = submission.course_id) + LIMIT 1))); + + +create policy "Authenticated users can SELECT" +on "public"."submissionstatus" +as permissive +for select +to authenticated +using (true); + +alter table "public"."course" alter column "currency" set default 'USD'::character varying; diff --git a/supabase/migrations/20240718200323_rls_auth_fix.sql b/supabase/migrations/20240718200323_rls_auth_fix.sql new file mode 100644 index 00000000..7657e414 --- /dev/null +++ b/supabase/migrations/20240718200323_rls_auth_fix.sql @@ -0,0 +1,8 @@ +drop policy "User must be an admin to INSERT" on "public"."organization"; + +create policy "Enable insert for authenticated users only" +on "public"."organization" +as permissive +for insert +to authenticated +with check (true); diff --git a/supabase/migrations/20240720100738_fix_autosave_lesson.sql b/supabase/migrations/20240720100738_fix_autosave_lesson.sql new file mode 100644 index 00000000..bac249b4 --- /dev/null +++ b/supabase/migrations/20240720100738_fix_autosave_lesson.sql @@ -0,0 +1,59 @@ +create policy "User must be an org member to DELETE" +on "public"."lesson_language_history" +as permissive +for delete +to public +using (is_user_in_group_with_role(( SELECT course.group_id + FROM course + WHERE (course.id = ( SELECT lesson.course_id + FROM lesson + WHERE (lesson.id = ( SELECT lesson_language.lesson_id + FROM lesson_language + WHERE (lesson_language.id = lesson_language_history.lesson_language_id))) + LIMIT 1)) + LIMIT 1))); + + +create policy "User must be an org member to INSERT" +on "public"."lesson_language_history" +as permissive +for insert +to public +with check (is_user_in_group_with_role(( SELECT course.group_id + FROM course + WHERE (course.id = ( SELECT lesson.course_id + FROM lesson + WHERE (lesson.id = ( SELECT lesson_language.lesson_id + FROM lesson_language + WHERE (lesson_language.id = lesson_language_history.lesson_language_id))) + LIMIT 1)) + LIMIT 1))); + + +create policy "User must be an org member to UPDATE" +on "public"."lesson_language_history" +as permissive +for update +to public +using (is_user_in_group_with_role(( SELECT course.group_id + FROM course + WHERE (course.id = ( SELECT lesson.course_id + FROM lesson + WHERE (lesson.id = ( SELECT lesson_language.lesson_id + FROM lesson_language + WHERE (lesson_language.id = lesson_language_history.lesson_language_id))) + LIMIT 1)) + LIMIT 1))) +with check (is_user_in_group_with_role(( SELECT course.group_id + FROM course + WHERE (course.id = ( SELECT lesson.course_id + FROM lesson + WHERE (lesson.id = ( SELECT lesson_language.lesson_id + FROM lesson_language + WHERE (lesson_language.id = lesson_language_history.lesson_language_id))) + LIMIT 1)) + LIMIT 1))); + + + + diff --git a/supabase/migrations/20240811123634_lesson_section.sql b/supabase/migrations/20240811123634_lesson_section.sql new file mode 100644 index 00000000..f601fd14 --- /dev/null +++ b/supabase/migrations/20240811123634_lesson_section.sql @@ -0,0 +1,145 @@ +create type "public"."COURSE_VERSION" as enum ('V1', 'V2'); + +alter table "public"."lesson_language_history" drop constraint "lesson_language_history_lesson_language_id_fkey"; + +alter table "public"."lesson_language" drop constraint "public_lesson_language_lesson_id_fkey"; + +create table "public"."lesson_section" ( + "id" uuid not null default gen_random_uuid(), + "created_at" timestamp with time zone not null default now(), + "updated_at" timestamp with time zone default now(), + "title" character varying, + "order" bigint default '0'::bigint, + "course_id" uuid +); + + +alter table "public"."lesson_section" enable row level security; + +alter table "public"."course" add column "version" "COURSE_VERSION" not null default 'V1'::"COURSE_VERSION"; + +alter table "public"."lesson" add column "section_id" uuid; + +CREATE UNIQUE INDEX lesson_section_pkey ON public.lesson_section USING btree (id); + +alter table "public"."lesson_section" add constraint "lesson_section_pkey" PRIMARY KEY using index "lesson_section_pkey"; + +alter table "public"."lesson" add constraint "public_lesson_section_id_fkey" FOREIGN KEY (section_id) REFERENCES lesson_section(id) ON UPDATE CASCADE ON DELETE CASCADE not valid; + +alter table "public"."lesson" validate constraint "public_lesson_section_id_fkey"; + +alter table "public"."lesson_language_history" add constraint "public_lesson_language_history_lesson_language_id_fkey" FOREIGN KEY (lesson_language_id) REFERENCES lesson_language(id) ON UPDATE CASCADE ON DELETE CASCADE not valid; + +alter table "public"."lesson_language_history" validate constraint "public_lesson_language_history_lesson_language_id_fkey"; + +alter table "public"."lesson_section" add constraint "public_lesson_section_course_id_fkey" FOREIGN KEY (course_id) REFERENCES course(id) ON UPDATE CASCADE ON DELETE CASCADE not valid; + +alter table "public"."lesson_section" validate constraint "public_lesson_section_course_id_fkey"; + +alter table "public"."lesson_language" add constraint "public_lesson_language_lesson_id_fkey" FOREIGN KEY (lesson_id) REFERENCES lesson(id) ON UPDATE CASCADE ON DELETE CASCADE not valid; + +alter table "public"."lesson_language" validate constraint "public_lesson_language_lesson_id_fkey"; + +grant delete on table "public"."lesson_section" to "anon"; + +grant insert on table "public"."lesson_section" to "anon"; + +grant references on table "public"."lesson_section" to "anon"; + +grant select on table "public"."lesson_section" to "anon"; + +grant trigger on table "public"."lesson_section" to "anon"; + +grant truncate on table "public"."lesson_section" to "anon"; + +grant update on table "public"."lesson_section" to "anon"; + +grant delete on table "public"."lesson_section" to "authenticated"; + +grant insert on table "public"."lesson_section" to "authenticated"; + +grant references on table "public"."lesson_section" to "authenticated"; + +grant select on table "public"."lesson_section" to "authenticated"; + +grant trigger on table "public"."lesson_section" to "authenticated"; + +grant truncate on table "public"."lesson_section" to "authenticated"; + +grant update on table "public"."lesson_section" to "authenticated"; + +grant delete on table "public"."lesson_section" to "service_role"; + +grant insert on table "public"."lesson_section" to "service_role"; + +grant references on table "public"."lesson_section" to "service_role"; + +grant select on table "public"."lesson_section" to "service_role"; + +grant trigger on table "public"."lesson_section" to "service_role"; + +grant truncate on table "public"."lesson_section" to "service_role"; + +grant update on table "public"."lesson_section" to "service_role"; + +create policy "Enable read access for all users" +on "public"."lesson_section" +as permissive +for select +to public +using (true); + + +create policy "User must be an org member to DELETE" +on "public"."lesson_section" +as permissive +for delete +to public +using (is_user_in_group_with_role(( SELECT course.group_id + FROM course + WHERE (course.id = lesson_section.course_id) + LIMIT 1))); + + +create policy "User must be an org member to INSERT" +on "public"."lesson_section" +as permissive +for insert +to public +with check (is_user_in_group_with_role(( SELECT course.group_id + FROM course + WHERE (course.id = lesson_section.course_id) + LIMIT 1))); + + +create policy "User must be an org member to UPDATE" +on "public"."lesson_section" +as permissive +for update +to public +using (is_user_in_group_with_role(( SELECT course.group_id + FROM course + WHERE (course.id = lesson_section.course_id) + LIMIT 1))) +with check (is_user_in_group_with_role(( SELECT course.group_id + FROM course + WHERE (course.id = lesson_section.course_id) + LIMIT 1))); + +CREATE +OR REPLACE FUNCTION convert_course_to_v2 (course_id uuid) RETURNS void AS $$ +DECLARE + new_section_id bigint; +BEGIN + UPDATE course + SET version = 'V2' + WHERE id = course_id; + + INSERT INTO lesson_section (title, course_id) VALUES ('First Section [edit me]', course_id) RETURNING id INTO new_section_id; + + UPDATE lesson + SET section_id = new_section_id + WHERE course_id = course_id; +END; +$$ LANGUAGE plpgsql; + diff --git a/supabase/migrations/20240824193502_restrict_accounts.sql b/supabase/migrations/20240824193502_restrict_accounts.sql new file mode 100644 index 00000000..0c23ae8e --- /dev/null +++ b/supabase/migrations/20240824193502_restrict_accounts.sql @@ -0,0 +1,27 @@ +drop function if exists "public"."convert_course_to_v2"(course_id uuid); + +alter table "public"."organization" add column "is_restricted" boolean not null default false; + +alter table "public"."profile" add column "is_restricted" boolean not null default false; + +set check_function_bodies = off; + +CREATE +OR REPLACE FUNCTION convert_course_to_v2 (course_id_arg uuid) RETURNS void AS $$ +DECLARE + new_section_id uuid; +BEGIN + UPDATE course + SET version = 'V2' + WHERE id = course_id_arg; + + INSERT INTO lesson_section (title, course_id) VALUES ('First Section [edit me]', course_id_arg) RETURNING id INTO new_section_id; + + UPDATE lesson + SET section_id = new_section_id + WHERE lesson.course_id = course_id_arg; +END; +$$ LANGUAGE plpgsql; + + + diff --git a/supabase/migrations/20240904050707_custom_domain.sql b/supabase/migrations/20240904050707_custom_domain.sql new file mode 100644 index 00000000..2bf1be78 --- /dev/null +++ b/supabase/migrations/20240904050707_custom_domain.sql @@ -0,0 +1,11 @@ +alter table "public"."organization" add column "customCode" text; + +alter table "public"."organization" add column "customDomain" text; + +alter table "public"."organization" add column "favicon" text; + +alter table "public"."organization" add column "isCustomDomainVerified" boolean default false; + +CREATE UNIQUE INDEX "organization_customDomain_key" ON public.organization USING btree ("customDomain"); + +alter table "public"."organization" add constraint "organization_customDomain_key" UNIQUE using index "organization_customDomain_key"; diff --git a/supabase/migrations/20240907090948_open_orgplan_for_landingpage.sql b/supabase/migrations/20240907090948_open_orgplan_for_landingpage.sql new file mode 100644 index 00000000..1c9b6ab4 --- /dev/null +++ b/supabase/migrations/20240907090948_open_orgplan_for_landingpage.sql @@ -0,0 +1,8 @@ +drop policy "User must be an org member to SELECT" on "public"."organization_plan"; + +create policy "Enable read access for all users" +on "public"."organization_plan" +as permissive +for select +to public +using (true); diff --git a/supabase/migrations/20241016235827_student_analytics.sql b/supabase/migrations/20241016235827_student_analytics.sql new file mode 100644 index 00000000..19bead1f --- /dev/null +++ b/supabase/migrations/20241016235827_student_analytics.sql @@ -0,0 +1,125 @@ +create table "public"."analytics_login_events" ( + "id" uuid not null default uuid_generate_v4(), + "user_id" uuid not null, + "logged_in_at" timestamp with time zone default now() +); + +alter table "public"."analytics_login_events" enable row level security; + +CREATE UNIQUE INDEX analytics_login_events_pkey ON public.analytics_login_events USING btree (id); + +CREATE INDEX idx_analytics_login_events_logged_in_at ON public.analytics_login_events USING btree (logged_in_at); + +CREATE INDEX idx_analytics_login_events_user_id ON public.analytics_login_events USING btree (user_id); + +CREATE UNIQUE INDEX analytics_login_events_user_id_unique ON public.analytics_login_events USING btree (user_id); + +alter table "public"."analytics_login_events" add constraint "analytics_login_events_pkey" PRIMARY KEY using index "analytics_login_events_pkey"; + +alter table "public"."analytics_login_events" add constraint "analytics_login_events_user_id_fkey" FOREIGN KEY (user_id) REFERENCES auth.users(id) not valid; + +alter table "public"."analytics_login_events" validate constraint "analytics_login_events_user_id_fkey"; + +alter table "public"."analytics_login_events" add constraint "analytics_login_events_user_id_unique" UNIQUE using index "analytics_login_events_user_id_unique"; + +set check_function_bodies = off; + +CREATE OR REPLACE FUNCTION public.insert_login_event_on_user_login() + RETURNS trigger + LANGUAGE plpgsql + SECURITY DEFINER +AS $function$ +BEGIN + IF (NEW.last_sign_in_at IS NOT NULL) THEN + INSERT INTO public.analytics_login_events (logged_in_at, user_id) + VALUES (NEW.last_sign_in_at, NEW.id) + ON CONFLICT (user_id) DO UPDATE + SET logged_in_at = NEW.last_sign_in_at; + END IF; + RETURN NEW; +END; +$function$ +; + +CREATE TRIGGER insert_login_event_on_user_login_trigger +AFTER UPDATE OF last_sign_in_at ON auth.users +FOR EACH ROW +EXECUTE FUNCTION public.insert_login_event_on_user_login(); + +CREATE OR REPLACE FUNCTION public.insert_login_event_on_user_session_update() + RETURNS trigger + LANGUAGE plpgsql + SECURITY DEFINER +AS $function$ +BEGIN + IF (NEW.updated_at IS NOT NULL AND NEW.updated_at != OLD.updated_at) THEN + INSERT INTO public.analytics_login_events (logged_in_at, user_id) + VALUES (NEW.updated_at, NEW.user_id) + ON CONFLICT (user_id) DO UPDATE + SET logged_in_at = EXCLUDED.logged_in_at + WHERE analytics_login_events.logged_in_at < EXCLUDED.logged_in_at; + END IF; + RETURN NEW; +END; +$function$ +; + +CREATE TRIGGER insert_login_event_on_user_session_update_trigger +AFTER UPDATE OF updated_at ON auth.sessions +FOR EACH ROW +EXECUTE FUNCTION public.insert_login_event_on_user_session_update(); + +grant delete on table "public"."analytics_login_events" to "anon"; + +grant insert on table "public"."analytics_login_events" to "anon"; + +grant references on table "public"."analytics_login_events" to "anon"; + +grant select on table "public"."analytics_login_events" to "anon"; + +grant trigger on table "public"."analytics_login_events" to "anon"; + +grant truncate on table "public"."analytics_login_events" to "anon"; + +grant update on table "public"."analytics_login_events" to "anon"; + +grant delete on table "public"."analytics_login_events" to "authenticated"; + +grant insert on table "public"."analytics_login_events" to "authenticated"; + +grant references on table "public"."analytics_login_events" to "authenticated"; + +grant select on table "public"."analytics_login_events" to "authenticated"; + +grant trigger on table "public"."analytics_login_events" to "authenticated"; + +grant truncate on table "public"."analytics_login_events" to "authenticated"; + +grant update on table "public"."analytics_login_events" to "authenticated"; + +grant delete on table "public"."analytics_login_events" to "service_role"; + +grant insert on table "public"."analytics_login_events" to "service_role"; + +grant references on table "public"."analytics_login_events" to "service_role"; + +grant select on table "public"."analytics_login_events" to "service_role"; + +grant trigger on table "public"."analytics_login_events" to "service_role"; + +grant truncate on table "public"."analytics_login_events" to "service_role"; + +grant update on table "public"."analytics_login_events" to "service_role"; + +create policy "Users can insert their own login events" +on "public"."analytics_login_events" +as permissive +for insert +to authenticated +with check ((auth.uid() = user_id)); + +CREATE POLICY "Enable delete for users based on user_id" +ON "public"."analytics_login_events" +AS PERMISSIVE FOR DELETE +TO public +USING (auth.uid() = user_id); diff --git a/supabase/migrations/20241223012712_validate_mark_as_complete.sql b/supabase/migrations/20241223012712_validate_mark_as_complete.sql new file mode 100644 index 00000000..c855b042 --- /dev/null +++ b/supabase/migrations/20241223012712_validate_mark_as_complete.sql @@ -0,0 +1,18 @@ +set check_function_bodies = off; + +CREATE OR REPLACE FUNCTION public.check_if_student_completed_exercises(lesson_id_arg uuid, groupmember_id_arg uuid) + RETURNS boolean + LANGUAGE plpgsql +AS $function$ +DECLARE + all_exercises_exist boolean; +BEGIN + SELECT COUNT(*) = COUNT(s.id) INTO all_exercises_exist + FROM exercise e + LEFT JOIN submission s ON e.id = s.exercise_id AND s.submitted_by = groupmember_id_arg + WHERE e.lesson_id = lesson_id_arg; + + RETURN all_exercises_exist; +END; +$function$ +; \ No newline at end of file diff --git a/supabase/migrations/20241231154543_dashboard_stats.sql b/supabase/migrations/20241231154543_dashboard_stats.sql new file mode 100644 index 00000000..87127538 --- /dev/null +++ b/supabase/migrations/20241231154543_dashboard_stats.sql @@ -0,0 +1,80 @@ +set check_function_bodies = off; + +create or replace view "public"."dash_org_stats" as SELECT gp.organization_id AS org_id, + count(DISTINCT course.id) AS no_of_courses, + count(DISTINCT gm.profile_id) AS enrolled_students + FROM ((course + JOIN "group" gp ON ((gp.id = course.group_id))) + LEFT JOIN groupmember gm ON (((gm.group_id = gp.id) AND (gm.role_id = 3)))) + WHERE (course.status = 'ACTIVE'::text) + GROUP BY gp.organization_id; + + +CREATE OR REPLACE FUNCTION public.get_dash_org_recent_enrollments(org_id_arg uuid) + RETURNS TABLE(profile_id uuid, avatar_url text, fullname text, course_id uuid, course_title character varying, enrolled_at timestamp with time zone) + LANGUAGE plpgsql +AS $function$ +BEGIN + RETURN QUERY + SELECT + p.id, + p.avatar_url, + p.fullname, + course.id, + course.title, + gm.created_at as enrolled_at + FROM + course + JOIN "group" as gp ON gp.id = course.group_id + LEFT JOIN groupmember as gm ON gm.group_id = gp.id AND gm.role_id = 3 + JOIN profile as p ON p.id = gm.profile_id + WHERE + course.status = 'ACTIVE' + AND gp.organization_id = org_id_arg + GROUP BY + p.id, + course.id, + course.title, + enrolled_at + ORDER BY + enrolled_at DESC + LIMIT 5; +END; +$function$ +; + +CREATE OR REPLACE FUNCTION public.get_dash_org_top_courses(org_id_arg uuid) + RETURNS TABLE(course_id uuid, course_title character varying, total_students integer, completion_percentage integer) + LANGUAGE plpgsql +AS $function$ +BEGIN + RETURN QUERY +SELECT + course_stats.course_id, + course_stats.course_title, + course_stats.total_students::integer, + CASE + WHEN course_stats.total_students * course_stats.total_lessons = 0 THEN 0 + ELSE ROUND((course_stats.completed_lessons::numeric / (course_stats.total_students * course_stats.total_lessons)) * 100)::integer + END as completion_percentage + FROM ( + SELECT + c.id as course_id, + c.title as course_title, + COUNT(DISTINCT gm.id) as total_students, + COUNT(DISTINCT l.id) as total_lessons, + COUNT(DISTINCT lc.id) FILTER (WHERE lc.is_complete = true) as completed_lessons + FROM course c + JOIN "group" g ON g.id = c.group_id + LEFT JOIN groupmember gm ON gm.group_id = g.id and gm.role_id = 3 + LEFT JOIN lesson l ON l.course_id = c.id + LEFT JOIN lesson_completion lc ON lc.lesson_id = l.id + AND lc.profile_id = gm.profile_id + WHERE c.status = 'ACTIVE' AND g.organization_id = org_id_arg + GROUP BY c.id, c.title + ORDER BY completed_lessons DESC + ) as course_stats + LIMIT 5; +END; +$function$ +; diff --git a/supabase/migrations/20250106020355_base_migration.sql b/supabase/migrations/20250106020355_base_migration.sql deleted file mode 100644 index a696925b..00000000 --- a/supabase/migrations/20250106020355_base_migration.sql +++ /dev/null @@ -1,2603 +0,0 @@ - -SET statement_timeout = 0; -SET lock_timeout = 0; -SET idle_in_transaction_session_timeout = 0; -SET client_encoding = 'UTF8'; -SET standard_conforming_strings = on; -SELECT pg_catalog.set_config('search_path', '', false); -SET check_function_bodies = false; -SET xmloption = content; -SET client_min_messages = warning; -SET row_security = off; - -CREATE EXTENSION IF NOT EXISTS "pg_net" WITH SCHEMA "extensions"; - -CREATE EXTENSION IF NOT EXISTS "pgsodium" WITH SCHEMA "pgsodium"; - -ALTER SCHEMA "public" OWNER TO "postgres"; - -COMMENT ON SCHEMA "public" IS 'standard public schema'; - -CREATE EXTENSION IF NOT EXISTS "moddatetime" WITH SCHEMA "extensions"; - -CREATE EXTENSION IF NOT EXISTS "pg_graphql" WITH SCHEMA "graphql"; - -CREATE EXTENSION IF NOT EXISTS "pg_stat_statements" WITH SCHEMA "extensions"; - -CREATE EXTENSION IF NOT EXISTS "pgcrypto" WITH SCHEMA "extensions"; - -CREATE EXTENSION IF NOT EXISTS "pgjwt" WITH SCHEMA "extensions"; - -CREATE EXTENSION IF NOT EXISTS "supabase_vault" WITH SCHEMA "vault"; - -CREATE EXTENSION IF NOT EXISTS "uuid-ossp" WITH SCHEMA "extensions"; - -CREATE EXTENSION IF NOT EXISTS "vector" WITH SCHEMA "extensions"; - -CREATE TYPE "public"."COURSE_TYPE" AS ENUM ( - 'SELF_PACED', - 'LIVE_CLASS' -); - -ALTER TYPE "public"."COURSE_TYPE" OWNER TO "postgres"; - -CREATE TYPE "public"."COURSE_VERSION" AS ENUM ( - 'V1', - 'V2' -); - -ALTER TYPE "public"."COURSE_VERSION" OWNER TO "postgres"; - -CREATE TYPE "public"."LOCALE" AS ENUM ( - 'en', - 'hi', - 'fr', - 'pt', - 'de', - 'vi', - 'ru', - 'es' -); - -ALTER TYPE "public"."LOCALE" OWNER TO "postgres"; - -CREATE TYPE "public"."PLAN" AS ENUM ( - 'EARLY_ADOPTER', - 'ENTERPRISE', - 'BASIC' -); - -ALTER TYPE "public"."PLAN" OWNER TO "postgres"; - -CREATE OR REPLACE FUNCTION "public"."add_them"("a" integer, "b" integer) RETURNS integer - LANGUAGE "sql" IMMUTABLE - AS $$ - SELECT a + b; -$$; - -ALTER FUNCTION "public"."add_them"("a" integer, "b" integer) OWNER TO "postgres"; - -CREATE OR REPLACE FUNCTION "public"."check_if_student_completed_exercises"("lesson_id_arg" "uuid", "groupmember_id_arg" "uuid") RETURNS boolean - LANGUAGE "plpgsql" - AS $$ -DECLARE - all_exercises_exist boolean; -BEGIN - SELECT COUNT(*) = COUNT(s.id) INTO all_exercises_exist - FROM exercise e - LEFT JOIN submission s ON e.id = s.exercise_id AND s.submitted_by = groupmember_id_arg - WHERE e.lesson_id = lesson_id_arg; - - RETURN all_exercises_exist; -END; -$$; - -ALTER FUNCTION "public"."check_if_student_completed_exercises"("lesson_id_arg" "uuid", "groupmember_id_arg" "uuid") OWNER TO "postgres"; - -CREATE OR REPLACE FUNCTION "public"."convert_course_to_v2"("course_id_arg" "uuid") RETURNS "void" - LANGUAGE "plpgsql" - AS $$ -DECLARE - new_section_id uuid; -BEGIN - UPDATE course - SET version = 'V2' - WHERE id = course_id_arg; - - INSERT INTO lesson_section (title, course_id) VALUES ('First Section [edit me]', course_id_arg) RETURNING id INTO new_section_id; - - UPDATE lesson - SET section_id = new_section_id - WHERE lesson.course_id = course_id_arg; -END; -$$; - -ALTER FUNCTION "public"."convert_course_to_v2"("course_id_arg" "uuid") OWNER TO "postgres"; - -CREATE OR REPLACE FUNCTION "public"."get_course_progress"("course_id_arg" "uuid", "profile_id_arg" "uuid") RETURNS TABLE("lessons_count" bigint, "lessons_completed" bigint, "exercises_count" bigint, "exercises_completed" bigint) - LANGUAGE "plpgsql" - AS $$ -BEGIN -RETURN QUERY -select - count(lesson.id) as lessons_count, - count(lesson_completion.id) as lessons_completed, - count(exercise.id) as exercises_count, - count(submission.id) as exercises_completed -from - course - join "group" on "group".id = course.group_id - join groupmember on groupmember.group_id = course.group_id - join profile on profile.id = groupmember.profile_id - left join lesson on lesson.course_id = course.id - left join lesson_completion on lesson_completion.lesson_id = lesson.id - and lesson_completion.is_complete = true - and lesson_completion.profile_id = profile.id - left join exercise on exercise.lesson_id = lesson.id - left join submission on submission.exercise_id = exercise.id - and submission.submitted_by = groupmember.id -where - course.id = course_id_arg - and profile.id = profile_id_arg; -END; -$$; - -ALTER FUNCTION "public"."get_course_progress"("course_id_arg" "uuid", "profile_id_arg" "uuid") OWNER TO "postgres"; - -CREATE OR REPLACE FUNCTION "public"."get_courses"("org_id_arg" "uuid", "profile_id_arg" "uuid") RETURNS TABLE("id" "uuid", "org_id" "uuid", "title" character varying, "slug" character varying, "description" character varying, "logo" "text", "banner_image" "text", "cost" bigint, "currency" character varying, "is_published" boolean, "total_lessons" bigint, "total_students" bigint, "progress_rate" bigint, "type" "public"."COURSE_TYPE", "member_profile_id" "uuid") - LANGUAGE "plpgsql" - AS $$ -BEGIN - Return query - select course.id, organization.id AS org_id, course.title, course.slug, course.description, course.logo, course.banner_image, course.cost, course.currency, course.is_published, (select COUNT(*) from lesson as l where l.course_id = course.id) AS total_lessons, (select COUNT(*) from groupmember as gm where gm.group_id = course.group_id AND gm.role_id = 3) as total_students, (select COUNT(*) from lesson_completion as lc join lesson as l on l.id = lc.lesson_id where l.course_id = course.id and lc.is_complete = true and lc.profile_id = profile_id_arg) AS progress_rate, course.type as type, (select groupmember.profile_id from groupmember where groupmember.group_id = "group".id and groupmember.profile_id = profile_id_arg) as member_profile_id - from course - join "group" on "group".id = course.group_id - join organization on organization.id = "group".organization_id - where course.status = 'ACTIVE' AND organization.id = org_id_arg - -- GROUP BY course.id, groupmember.profile_id - ORDER BY course.created_at DESC; -END; -$$; - -ALTER FUNCTION "public"."get_courses"("org_id_arg" "uuid", "profile_id_arg" "uuid") OWNER TO "postgres"; - -CREATE OR REPLACE FUNCTION "public"."get_dash_org_recent_enrollments"("org_id_arg" "uuid") RETURNS TABLE("profile_id" "uuid", "avatar_url" "text", "fullname" "text", "course_id" "uuid", "course_title" character varying, "enrolled_at" timestamp with time zone) - LANGUAGE "plpgsql" - AS $$ -BEGIN - RETURN QUERY - SELECT - p.id, - p.avatar_url, - p.fullname, - course.id, - course.title, - gm.created_at as enrolled_at - FROM - course - JOIN "group" as gp ON gp.id = course.group_id - LEFT JOIN groupmember as gm ON gm.group_id = gp.id AND gm.role_id = 3 - JOIN profile as p ON p.id = gm.profile_id - WHERE - course.status = 'ACTIVE' - AND gp.organization_id = org_id_arg - GROUP BY - p.id, - course.id, - course.title, - enrolled_at - ORDER BY - enrolled_at DESC - LIMIT 5; -END; -$$; - -ALTER FUNCTION "public"."get_dash_org_recent_enrollments"("org_id_arg" "uuid") OWNER TO "postgres"; - -CREATE OR REPLACE FUNCTION "public"."get_dash_org_top_courses"("org_id_arg" "uuid") RETURNS TABLE("course_id" "uuid", "course_title" character varying, "total_students" integer, "completion_percentage" integer) - LANGUAGE "plpgsql" - AS $$ -BEGIN - RETURN QUERY -SELECT - course_stats.course_id, - course_stats.course_title, - course_stats.total_students::integer, - CASE - WHEN course_stats.total_students * course_stats.total_lessons = 0 THEN 0 - ELSE ROUND((course_stats.completed_lessons::numeric / (course_stats.total_students * course_stats.total_lessons)) * 100)::integer - END as completion_percentage - FROM ( - SELECT - c.id as course_id, - c.title as course_title, - COUNT(DISTINCT gm.id) as total_students, - COUNT(DISTINCT l.id) as total_lessons, - COUNT(DISTINCT lc.id) FILTER (WHERE lc.is_complete = true) as completed_lessons - FROM course c - JOIN "group" g ON g.id = c.group_id - LEFT JOIN groupmember gm ON gm.group_id = g.id and gm.role_id = 3 - LEFT JOIN lesson l ON l.course_id = c.id - LEFT JOIN lesson_completion lc ON lc.lesson_id = l.id - AND lc.profile_id = gm.profile_id - WHERE c.status = 'ACTIVE' AND g.organization_id = org_id_arg - GROUP BY c.id, c.title - ORDER BY completed_lessons DESC - ) as course_stats - LIMIT 5; -END; -$$; - -ALTER FUNCTION "public"."get_dash_org_top_courses"("org_id_arg" "uuid") OWNER TO "postgres"; - -CREATE OR REPLACE FUNCTION "public"."get_exercises"() RETURNS TABLE("course_id" "uuid", "lesson_id" "uuid", "exercise_id" "uuid", "exercise_title" character varying, "points" integer) - LANGUAGE "plpgsql" - AS $$ -BEGIN - Return query - select lesson.course_id course_id, lesson.id lesson_id, exercise.id exercise_id, exercise.title exercise_title, sum(question.points)::int points - from exercise - join lesson on exercise.lesson_id = lesson.id - right join question on question.exercise_id = exercise.id - GROUP BY lesson.course_id, lesson.id, exercise.id, exercise.title - ORDER BY lesson.created_at ASC; -END; -$$; - -ALTER FUNCTION "public"."get_exercises"() OWNER TO "postgres"; - -CREATE OR REPLACE FUNCTION "public"."get_explore_courses"("org_id_arg" "uuid", "profile_id_arg" "uuid") RETURNS TABLE("id" "uuid", "org_id" "uuid", "title" character varying, "slug" character varying, "description" character varying, "logo" "text", "banner_image" "text", "cost" bigint, "currency" character varying, "is_published" boolean, "total_lessons" bigint, "total_students" bigint, "progress_rate" bigint, "type" "public"."COURSE_TYPE", "other_profile_id" "uuid") - LANGUAGE "plpgsql" - AS $$ -BEGIN - Return query - select course.id, organization.id AS org_id, course.title, course.slug, course.description, course.logo, course.banner_image, course.cost, course.currency, course.is_published, (select COUNT(*) from lesson -as l where l.course_id = course.id) AS total_lessons, (select COUNT(*) from groupmember as gm where gm.group_id = course.group_id AND gm.role_id = 3) as total_students, (select COUNT(*) from lesson_completion as lc join lesson as l on l.id = lc.lesson_id where l.course_id = course.id and lc.is_complete = true and lc.profile_id = profile_id_arg) AS progress_rate, course.type as type, (select groupmember.profile_id from groupmember where groupmember.group_id = "group".id and groupmember.profile_id != profile_id_arg -limit 1) as other_profile_id - from course - join "group" on "group".id = course.group_id - join organization on organization.id = "group".organization_id - where course.status = 'ACTIVE' AND course.is_published = true AND organization.id = org_id_arg AND profile_id_arg NOT IN (SELECT groupmember.profile_id FROM groupmember WHERE groupmember.group_id = course.group_id) - ORDER BY course.created_at DESC; -END; -$$; - -ALTER FUNCTION "public"."get_explore_courses"("org_id_arg" "uuid", "profile_id_arg" "uuid") OWNER TO "postgres"; - -CREATE OR REPLACE FUNCTION "public"."get_marks"() RETURNS TABLE("course_id" "uuid", "exercise_id" "uuid", "exercise_title" character varying, "exercise_points" integer, "lesson_id" "uuid", "lesson_title" character varying, "status_id" bigint, "total_points_gotten" bigint, "groupmember_id" "uuid", "fullname" "text", "assigned_student_id" character varying, "avatar_url" "text") - LANGUAGE "plpgsql" - AS $$ -BEGIN - Return query - select lesson.course_id course_id, exercise.id exercise_id, exercise.title exercise_title, sum(question.points)::int exercise_points, lesson.id lesson_id, lesson.title lesson_title, submission.status_id, submission.total total_points_gotten, submission.submitted_by groupmember_id, profile.fullname, groupmember.assigned_student_id, profile.avatar_url - from exercise - join lesson on exercise.lesson_id = lesson.id - left join submission on exercise.id = submission.exercise_id - join groupmember on groupmember.id = submission.submitted_by - right join question on question.exercise_id = exercise.id - join profile on profile.id = groupmember.profile_id - GROUP BY exercise.id, lesson.id, submission.status_id, submission.total, submission.submitted_by, profile.fullname, groupmember.assigned_student_id, profile.avatar_url - ORDER BY lesson.created_at ASC; -END; -$$; - -ALTER FUNCTION "public"."get_marks"() OWNER TO "postgres"; - -CREATE OR REPLACE FUNCTION "public"."get_student_exercises"("org_id_arg" "uuid", "profile_id_arg" "uuid") RETURNS TABLE("exercise_id" "uuid", "exercise_title" character varying, "lesson_id" "uuid", "lesson_title" character varying, "status_id" integer, "total" integer) - LANGUAGE "plpgsql" - AS $$ -BEGIN - Return query - select exercise.id as exercise_id, exercise.title as exercise_title, lesson.id as lesson_id, lesson.title as lesson_title, submission.status_id, submission.total - from exercise - inner join lesson on lesson.id = exercise.lesson_id - inner join course on course.id = lesson.course_id - inner join "group" on "group".id = course.group_id - inner join organization on "group".organization_id = organization.id - inner join groupmember on groupmember.group_id = course.group_id - inner join profile on groupmember.profile_id = profile.id - left join submission on submission.submitted_by = groupmember.id - where course.status = 'ACTIVE' AND organization.id = org_id_arg AND profile.id = profile_id_arg; -END; -$$; - -ALTER FUNCTION "public"."get_student_exercises"("org_id_arg" "uuid", "profile_id_arg" "uuid") OWNER TO "postgres"; - -CREATE OR REPLACE FUNCTION "public"."get_user_upcoming_lessons"("profile_id_arg" "uuid", "org_id_arg" "uuid") RETURNS TABLE("course_id" "uuid", "course_title" character varying, "lesson_id" "uuid", "lesson_title" character varying, "call_url" "text", "lesson_at" timestamp with time zone, "is_complete" boolean) - LANGUAGE "plpgsql" - AS $$ -BEGIN - Return query - select course.id course_id, course.title course_title, lesson.id lesson_id, lesson.title lesson_title, lesson.call_url call_url, lesson.lesson_at lesson_at, lesson.is_complete is_complete - from lesson - join course on course.id = lesson.course_id - join "group" on "group".id = course.group_id - join groupmember on groupmember.group_id = course.group_id - where course.status = 'ACTIVE' AND groupmember.profile_id = profile_id_arg AND "group".organization_id = org_id_arg - ORDER BY lesson_at ASC; -END -$$; - -ALTER FUNCTION "public"."get_user_upcoming_lessons"("profile_id_arg" "uuid", "org_id_arg" "uuid") OWNER TO "postgres"; - -CREATE OR REPLACE FUNCTION "public"."insert_login_event_on_user_login"() RETURNS "trigger" - LANGUAGE "plpgsql" SECURITY DEFINER - AS $$ -BEGIN - IF (NEW.last_sign_in_at IS NOT NULL) THEN - INSERT INTO public.analytics_login_events (logged_in_at, user_id) - VALUES (NEW.last_sign_in_at, NEW.id) - ON CONFLICT (user_id) DO UPDATE - SET logged_in_at = NEW.last_sign_in_at; - END IF; - RETURN NEW; -END; -$$; - -ALTER FUNCTION "public"."insert_login_event_on_user_login"() OWNER TO "postgres"; - -CREATE OR REPLACE FUNCTION "public"."insert_login_event_on_user_session_update"() RETURNS "trigger" - LANGUAGE "plpgsql" SECURITY DEFINER - AS $$ -BEGIN - IF (NEW.updated_at IS NOT NULL AND NEW.updated_at != OLD.updated_at) THEN - INSERT INTO public.analytics_login_events (logged_in_at, user_id) - VALUES (NEW.updated_at, NEW.user_id) - ON CONFLICT (user_id) DO UPDATE - SET logged_in_at = EXCLUDED.logged_in_at - WHERE analytics_login_events.logged_in_at < EXCLUDED.logged_in_at; - END IF; - RETURN NEW; -END; -$$; - -ALTER FUNCTION "public"."insert_login_event_on_user_session_update"() OWNER TO "postgres"; - -CREATE OR REPLACE FUNCTION "public"."is_org_admin"() RETURNS boolean - LANGUAGE "plpgsql" SECURITY DEFINER - AS $$ -BEGIN - RETURN EXISTS ( - SELECT 1 - FROM organizationmember - WHERE organization_id = organization_id - AND profile_id = (select auth.uid()) - AND role_id = 1 - ); -END; -$$; - -ALTER FUNCTION "public"."is_org_admin"() OWNER TO "postgres"; - -CREATE OR REPLACE FUNCTION "public"."is_org_admin"("org_id" "uuid") RETURNS boolean - LANGUAGE "plpgsql" - AS $$ -BEGIN - RETURN EXISTS ( - SELECT 1 - FROM organizationmember - WHERE organization_id = org_id - AND profile_id = (select auth.uid()) - AND role_id = 1 - ); -END; -$$; - -ALTER FUNCTION "public"."is_org_admin"("org_id" "uuid") OWNER TO "postgres"; - -CREATE OR REPLACE FUNCTION "public"."is_org_member"() RETURNS boolean - LANGUAGE "plpgsql" SECURITY DEFINER - AS $$ -BEGIN - RETURN EXISTS ( - SELECT 1 - FROM organizationmember - WHERE organization_id = organization_id - AND profile_id = (select auth.uid()) - ); -END; -$$; - -ALTER FUNCTION "public"."is_org_member"() OWNER TO "postgres"; - -CREATE OR REPLACE FUNCTION "public"."is_user_in_course_group"("group_id" "uuid") RETURNS boolean - LANGUAGE "plpgsql" SECURITY DEFINER - AS $_$ begin return exists -(SELECT 1 FROM groupmember member -JOIN "group" g ON g.id = member.group_id -WHERE member.role_id IS NOT NULL -AND member.profile_id = auth.uid() -AND g.id = $1 -); -END; -$_$; - -ALTER FUNCTION "public"."is_user_in_course_group"("group_id" "uuid") OWNER TO "postgres"; - -CREATE OR REPLACE FUNCTION "public"."is_user_in_group_with_role"("group_id" integer) RETURNS boolean - LANGUAGE "plpgsql" SECURITY DEFINER - AS $_$ -begin - return exists ( - SELECT 1 - FROM organizationmember m - JOIN organization o ON o.organization_id = m.organization_id - WHERE m.role_id IS NOT NULL - AND m.profile_id = auth.uid () - AND EXISTS ( - SELECT 1 - FROM "group" g - WHERE g.group_id = $1 - AND g.organization_id = o.organization_id - ) - ); -END; -$_$; - -ALTER FUNCTION "public"."is_user_in_group_with_role"("group_id" integer) OWNER TO "postgres"; - -CREATE OR REPLACE FUNCTION "public"."is_user_in_group_with_role"("group_id" "uuid") RETURNS boolean - LANGUAGE "plpgsql" SECURITY DEFINER - AS $_$ -begin - return exists ( - SELECT 1 - FROM organizationmember member - JOIN organization o ON o.id = member.organization_id - WHERE member.role_id IS NOT NULL - AND member.profile_id = auth.uid () - AND EXISTS ( - SELECT 1 - FROM "group" g - WHERE g.id = $1 - AND g.organization_id = o.id - ) - ); -END; -$_$; - -ALTER FUNCTION "public"."is_user_in_group_with_role"("group_id" "uuid") OWNER TO "postgres"; - -CREATE OR REPLACE FUNCTION "public"."update_lesson_language_history"() RETURNS "trigger" - LANGUAGE "plpgsql" - AS $$ -BEGIN - IF TG_OP IN ('INSERT', 'UPDATE') THEN - INSERT INTO lesson_language_history (lesson_language_id, old_content, new_content) - VALUES (NEW.id, COALESCE(OLD.content, ''), NEW.content); - END IF; - RETURN NULL; -END; -$$; - -ALTER FUNCTION "public"."update_lesson_language_history"() OWNER TO "postgres"; - -SET default_tablespace = ''; - -SET default_table_access_method = "heap"; - -CREATE TABLE IF NOT EXISTS "public"."analytics_login_events" ( - "id" "uuid" DEFAULT "extensions"."uuid_generate_v4"() NOT NULL, - "user_id" "uuid" NOT NULL, - "logged_in_at" timestamp with time zone DEFAULT "now"() -); - -ALTER TABLE "public"."analytics_login_events" OWNER TO "postgres"; - -CREATE TABLE IF NOT EXISTS "public"."apps_poll" ( - "id" "uuid" DEFAULT "gen_random_uuid"() NOT NULL, - "created_at" timestamp with time zone DEFAULT "now"() NOT NULL, - "updated_at" timestamp with time zone DEFAULT "now"(), - "question" "text", - "authorId" "uuid", - "isPublic" boolean, - "status" character varying DEFAULT 'draft'::character varying, - "expiration" timestamp with time zone, - "courseId" "uuid" -); - -ALTER TABLE "public"."apps_poll" OWNER TO "postgres"; - -CREATE TABLE IF NOT EXISTS "public"."apps_poll_option" ( - "id" bigint NOT NULL, - "created_at" timestamp with time zone DEFAULT "now"() NOT NULL, - "updated_at" timestamp with time zone, - "poll_id" "uuid", - "label" character varying -); - -ALTER TABLE "public"."apps_poll_option" OWNER TO "postgres"; - -ALTER TABLE "public"."apps_poll_option" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY ( - SEQUENCE NAME "public"."apps_poll_option_id_seq" - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1 -); - -CREATE TABLE IF NOT EXISTS "public"."apps_poll_submission" ( - "id" bigint NOT NULL, - "created_at" timestamp with time zone DEFAULT "now"() NOT NULL, - "poll_option_id" bigint, - "selected_by_id" "uuid", - "poll_id" "uuid" -); - -ALTER TABLE "public"."apps_poll_submission" OWNER TO "postgres"; - -ALTER TABLE "public"."apps_poll_submission" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY ( - SEQUENCE NAME "public"."apps_poll_submision_id_seq" - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1 -); - -CREATE TABLE IF NOT EXISTS "public"."community_answer" ( - "id" "uuid" DEFAULT "extensions"."gen_random_uuid"() NOT NULL, - "created_at" timestamp with time zone DEFAULT "now"(), - "question_id" bigint, - "body" character varying, - "author_id" bigint, - "votes" bigint, - "author_profile_id" "uuid" -); - -ALTER TABLE "public"."community_answer" OWNER TO "postgres"; - -CREATE TABLE IF NOT EXISTS "public"."community_question" ( - "id" bigint NOT NULL, - "created_at" timestamp with time zone DEFAULT "now"(), - "title" character varying, - "body" "text", - "author_id" bigint, - "votes" bigint DEFAULT '0'::bigint, - "organization_id" "uuid", - "slug" "text", - "author_profile_id" "uuid", - "course_id" "uuid" NOT NULL -); - -ALTER TABLE "public"."community_question" OWNER TO "postgres"; - -ALTER TABLE "public"."community_question" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY ( - SEQUENCE NAME "public"."community_question_id_seq" - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1 -); - -CREATE TABLE IF NOT EXISTS "public"."course" ( - "title" character varying NOT NULL, - "description" character varying NOT NULL, - "overview" character varying DEFAULT 'Welcome to this amazing course 🚀 '::character varying, - "id" "uuid" DEFAULT "extensions"."uuid_generate_v4"() NOT NULL, - "created_at" timestamp with time zone DEFAULT "now"(), - "updated_at" timestamp with time zone DEFAULT "now"(), - "group_id" "uuid", - "is_template" boolean DEFAULT true, - "logo" "text" DEFAULT ''::"text" NOT NULL, - "slug" character varying, - "metadata" "jsonb" DEFAULT '{"goals": "", "description": "", "requirements": ""}'::"jsonb" NOT NULL, - "cost" bigint DEFAULT '0'::bigint, - "currency" character varying DEFAULT 'USD'::character varying NOT NULL, - "banner_image" "text", - "is_published" boolean DEFAULT false, - "is_certificate_downloadable" boolean DEFAULT false, - "certificate_theme" "text", - "status" "text" DEFAULT 'ACTIVE'::"text" NOT NULL, - "type" "public"."COURSE_TYPE" DEFAULT 'LIVE_CLASS'::"public"."COURSE_TYPE", - "version" "public"."COURSE_VERSION" DEFAULT 'V1'::"public"."COURSE_VERSION" NOT NULL -); - -ALTER TABLE "public"."course" OWNER TO "postgres"; - -CREATE TABLE IF NOT EXISTS "public"."course_newsfeed" ( - "created_at" timestamp with time zone DEFAULT "now"() NOT NULL, - "author_id" "uuid", - "content" "text", - "id" "uuid" DEFAULT "gen_random_uuid"() NOT NULL, - "course_id" "uuid", - "reaction" "jsonb" DEFAULT '{"clap": [], "smile": [], "thumbsup": [], "thumbsdown": []}'::"jsonb", - "is_pinned" boolean DEFAULT false NOT NULL -); - -ALTER TABLE "public"."course_newsfeed" OWNER TO "postgres"; - -CREATE TABLE IF NOT EXISTS "public"."course_newsfeed_comment" ( - "created_at" timestamp with time zone DEFAULT "now"() NOT NULL, - "author_id" "uuid", - "content" "text", - "id" bigint NOT NULL, - "course_newsfeed_id" "uuid" -); - -ALTER TABLE "public"."course_newsfeed_comment" OWNER TO "postgres"; - -ALTER TABLE "public"."course_newsfeed_comment" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY ( - SEQUENCE NAME "public"."course_newsfeed_comment_id_seq" - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1 -); - -CREATE TABLE IF NOT EXISTS "public"."currency" ( - "id" bigint NOT NULL, - "created_at" timestamp with time zone DEFAULT "now"(), - "name" character varying -); - -ALTER TABLE "public"."currency" OWNER TO "postgres"; - -ALTER TABLE "public"."currency" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY ( - SEQUENCE NAME "public"."currency_id_seq" - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1 -); - -CREATE TABLE IF NOT EXISTS "public"."group" ( - "id" "uuid" DEFAULT "extensions"."uuid_generate_v4"() NOT NULL, - "name" character varying NOT NULL, - "description" "text", - "created_at" timestamp with time zone DEFAULT "now"(), - "updated_at" timestamp with time zone DEFAULT "now"(), - "organization_id" "uuid" -); - -ALTER TABLE "public"."group" OWNER TO "postgres"; - -CREATE TABLE IF NOT EXISTS "public"."groupmember" ( - "id" "uuid" DEFAULT "extensions"."uuid_generate_v4"() NOT NULL, - "group_id" "uuid" NOT NULL, - "role_id" bigint NOT NULL, - "profile_id" "uuid", - "email" character varying, - "created_at" timestamp with time zone DEFAULT "now"(), - "assigned_student_id" character varying -); - -ALTER TABLE "public"."groupmember" OWNER TO "postgres"; - -CREATE OR REPLACE VIEW "public"."dash_org_stats" AS - SELECT "gp"."organization_id" AS "org_id", - "count"(DISTINCT "course"."id") AS "no_of_courses", - "count"(DISTINCT "gm"."profile_id") AS "enrolled_students" - FROM (("public"."course" - JOIN "public"."group" "gp" ON (("gp"."id" = "course"."group_id"))) - LEFT JOIN "public"."groupmember" "gm" ON ((("gm"."group_id" = "gp"."id") AND ("gm"."role_id" = 3)))) - WHERE ("course"."status" = 'ACTIVE'::"text") - GROUP BY "gp"."organization_id"; - -ALTER TABLE "public"."dash_org_stats" OWNER TO "postgres"; - -CREATE TABLE IF NOT EXISTS "public"."exercise" ( - "title" character varying NOT NULL, - "description" character varying, - "lesson_id" "uuid", - "created_at" timestamp with time zone DEFAULT "now"(), - "updated_at" timestamp with time zone DEFAULT "now"(), - "id" "uuid" DEFAULT "extensions"."uuid_generate_v4"() NOT NULL, - "due_by" timestamp without time zone -); - -ALTER TABLE "public"."exercise" OWNER TO "postgres"; - -CREATE TABLE IF NOT EXISTS "public"."group_attendance" ( - "id" bigint NOT NULL, - "created_at" timestamp with time zone DEFAULT "now"(), - "updated_at" timestamp with time zone DEFAULT "now"(), - "course_id" "uuid", - "student_id" "uuid", - "is_present" boolean DEFAULT false, - "lesson_id" "uuid" NOT NULL -); - -ALTER TABLE "public"."group_attendance" OWNER TO "postgres"; - -ALTER TABLE "public"."group_attendance" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY ( - SEQUENCE NAME "public"."group_attendance_id_seq" - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1 -); - -CREATE TABLE IF NOT EXISTS "public"."lesson" ( - "note" character varying, - "video_url" character varying, - "slide_url" character varying, - "course_id" "uuid" NOT NULL, - "id" "uuid" DEFAULT "extensions"."uuid_generate_v4"() NOT NULL, - "created_at" timestamp with time zone DEFAULT "now"(), - "updated_at" timestamp with time zone DEFAULT "now"(), - "title" character varying NOT NULL, - "public" boolean DEFAULT false, - "lesson_at" timestamp with time zone DEFAULT "now"(), - "teacher_id" "uuid", - "is_complete" boolean DEFAULT false, - "call_url" "text", - "order" bigint, - "is_unlocked" boolean DEFAULT false, - "videos" "jsonb" DEFAULT '[]'::"jsonb", - "section_id" "uuid" -); - -ALTER TABLE "public"."lesson" OWNER TO "postgres"; - -CREATE TABLE IF NOT EXISTS "public"."lesson_comment" ( - "id" bigint NOT NULL, - "created_at" timestamp with time zone DEFAULT "now"() NOT NULL, - "updated_at" timestamp with time zone DEFAULT "now"(), - "lesson_id" "uuid", - "groupmember_id" "uuid", - "comment" "text" -); - -ALTER TABLE "public"."lesson_comment" OWNER TO "postgres"; - -ALTER TABLE "public"."lesson_comment" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY ( - SEQUENCE NAME "public"."lesson_comment_id_seq" - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1 -); - -CREATE TABLE IF NOT EXISTS "public"."lesson_completion" ( - "id" bigint NOT NULL, - "created_at" timestamp with time zone DEFAULT "now"() NOT NULL, - "lesson_id" "uuid", - "profile_id" "uuid", - "is_complete" boolean DEFAULT false, - "updated_at" timestamp with time zone DEFAULT "now"() -); - -ALTER TABLE "public"."lesson_completion" OWNER TO "postgres"; - -ALTER TABLE "public"."lesson_completion" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY ( - SEQUENCE NAME "public"."lesson_completion_id_seq" - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1 -); - -CREATE TABLE IF NOT EXISTS "public"."lesson_language" ( - "id" bigint NOT NULL, - "content" "text", - "lesson_id" "uuid" DEFAULT "gen_random_uuid"(), - "locale" "public"."LOCALE" DEFAULT 'en'::"public"."LOCALE" -); - -ALTER TABLE "public"."lesson_language" OWNER TO "postgres"; - -CREATE TABLE IF NOT EXISTS "public"."lesson_language_history" ( - "id" integer NOT NULL, - "lesson_language_id" integer, - "old_content" "text", - "new_content" "text", - "timestamp" timestamp without time zone DEFAULT CURRENT_TIMESTAMP NOT NULL -); - -ALTER TABLE "public"."lesson_language_history" OWNER TO "postgres"; - -CREATE SEQUENCE IF NOT EXISTS "public"."lesson_language_history_id_seq" - AS integer - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1; - -ALTER TABLE "public"."lesson_language_history_id_seq" OWNER TO "postgres"; - -ALTER SEQUENCE "public"."lesson_language_history_id_seq" OWNED BY "public"."lesson_language_history"."id"; - -ALTER TABLE "public"."lesson_language" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY ( - SEQUENCE NAME "public"."lesson_language_id_seq" - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1 -); - -CREATE TABLE IF NOT EXISTS "public"."lesson_section" ( - "id" "uuid" DEFAULT "gen_random_uuid"() NOT NULL, - "created_at" timestamp with time zone DEFAULT "now"() NOT NULL, - "updated_at" timestamp with time zone DEFAULT "now"(), - "title" character varying, - "order" bigint DEFAULT '0'::bigint, - "course_id" "uuid" -); - -ALTER TABLE "public"."lesson_section" OWNER TO "postgres"; - -CREATE OR REPLACE VIEW "public"."lesson_versions" AS - SELECT "llh"."old_content", - "llh"."new_content", - "llh"."timestamp", - "ll"."locale", - "ll"."lesson_id" - FROM ("public"."lesson_language_history" "llh" - JOIN "public"."lesson_language" "ll" ON (("ll"."id" = "llh"."lesson_language_id"))); - -ALTER TABLE "public"."lesson_versions" OWNER TO "postgres"; - -CREATE TABLE IF NOT EXISTS "public"."option" ( - "id" bigint NOT NULL, - "label" character varying NOT NULL, - "is_correct" boolean DEFAULT false NOT NULL, - "question_id" bigint NOT NULL, - "value" "uuid" DEFAULT "extensions"."gen_random_uuid"(), - "created_at" timestamp with time zone DEFAULT "now"(), - "updated_at" timestamp with time zone DEFAULT "now"() -); - -ALTER TABLE "public"."option" OWNER TO "postgres"; - -ALTER TABLE "public"."option" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY ( - SEQUENCE NAME "public"."option_id_seq" - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1 -); - -CREATE TABLE IF NOT EXISTS "public"."organization" ( - "id" "uuid" DEFAULT "extensions"."uuid_generate_v4"() NOT NULL, - "name" character varying NOT NULL, - "siteName" "text", - "avatar_url" "text", - "settings" "jsonb" DEFAULT '{}'::"jsonb", - "landingpage" "jsonb" DEFAULT '{}'::"jsonb", - "theme" "text", - "created_at" timestamp with time zone DEFAULT "timezone"('utc'::"text", "now"()) NOT NULL, - "customization" "json" DEFAULT '{"apps":{"poll":true,"comments":true},"course":{"grading":true,"newsfeed":true},"dashboard":{"exercise":true,"community":true,"bannerText":"","bannerImage":""}}'::"json" NOT NULL, - "is_restricted" boolean DEFAULT false NOT NULL, - "customCode" "text", - "customDomain" "text", - "favicon" "text", - "isCustomDomainVerified" boolean DEFAULT false -); - -ALTER TABLE "public"."organization" OWNER TO "postgres"; - -CREATE TABLE IF NOT EXISTS "public"."organization_contacts" ( - "id" bigint NOT NULL, - "created_at" timestamp with time zone DEFAULT "now"() NOT NULL, - "email" "text", - "phone" "text", - "name" "text", - "message" "text", - "organization_id" "uuid" -); - -ALTER TABLE "public"."organization_contacts" OWNER TO "postgres"; - -ALTER TABLE "public"."organization_contacts" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY ( - SEQUENCE NAME "public"."organization_contacts_id_seq" - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1 -); - -CREATE TABLE IF NOT EXISTS "public"."organization_emaillist" ( - "id" bigint NOT NULL, - "created_at" timestamp with time zone DEFAULT "now"() NOT NULL, - "email" "text", - "organization_id" "uuid" -); - -ALTER TABLE "public"."organization_emaillist" OWNER TO "postgres"; - -ALTER TABLE "public"."organization_emaillist" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY ( - SEQUENCE NAME "public"."organization_emaillist_id_seq" - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1 -); - -CREATE TABLE IF NOT EXISTS "public"."organization_plan" ( - "id" bigint NOT NULL, - "activated_at" timestamp with time zone DEFAULT "now"() NOT NULL, - "org_id" "uuid", - "plan_name" "public"."PLAN", - "is_active" boolean, - "deactivated_at" timestamp with time zone, - "updated_at" timestamp with time zone DEFAULT "now"(), - "payload" "jsonb", - "triggered_by" bigint, - "provider" "text" DEFAULT 'lmz'::"text", - "subscription_id" "text" -); - -ALTER TABLE "public"."organization_plan" OWNER TO "postgres"; - -ALTER TABLE "public"."organization_plan" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY ( - SEQUENCE NAME "public"."organization_plan_id_seq" - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1 -); - -CREATE TABLE IF NOT EXISTS "public"."organizationmember" ( - "id" bigint NOT NULL, - "organization_id" "uuid" NOT NULL, - "role_id" bigint NOT NULL, - "profile_id" "uuid", - "email" "text", - "verified" boolean DEFAULT false, - "created_at" timestamp with time zone DEFAULT "timezone"('utc'::"text", "now"()) NOT NULL -); - -ALTER TABLE "public"."organizationmember" OWNER TO "postgres"; - -ALTER TABLE "public"."organizationmember" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY ( - SEQUENCE NAME "public"."organizationmember_id_seq" - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1 -); - -CREATE TABLE IF NOT EXISTS "public"."quiz_play" ( - "id" bigint NOT NULL, - "created_at" timestamp with time zone DEFAULT "now"(), - "updated_at" timestamp with time zone DEFAULT "now"(), - "quiz_id" "uuid", - "players" "json" DEFAULT '[]'::"json", - "started" boolean DEFAULT false, - "currentQuestionId" bigint DEFAULT '0'::bigint, - "showCurrentQuestionAnswer" boolean DEFAULT false, - "isLastQuestion" boolean, - "step" "text" DEFAULT 'CONNECT_TO_PLAY'::"text", - "studentStep" "text" DEFAULT 'PIN_SETUP'::"text", - "pin" "text" -); - -ALTER TABLE "public"."quiz_play" OWNER TO "postgres"; - -ALTER TABLE "public"."quiz_play" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY ( - SEQUENCE NAME "public"."play_quiz_id_seq" - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1 -); - -CREATE TABLE IF NOT EXISTS "public"."profile" ( - "id" "uuid" NOT NULL, - "fullname" "text" NOT NULL, - "username" "text" NOT NULL, - "avatar_url" "text" DEFAULT 'https://pgrest.classroomio.com/storage/v1/object/public/avatars/avatar.png'::"text", - "created_at" timestamp with time zone DEFAULT "now"(), - "updated_at" timestamp with time zone DEFAULT "now"(), - "email" character varying, - "can_add_course" boolean DEFAULT true, - "role" character varying, - "goal" character varying, - "source" character varying, - "metadata" "json", - "telegram_chat_id" bigint, - "is_email_verified" boolean DEFAULT false, - "verified_at" timestamp with time zone, - "locale" "public"."LOCALE" DEFAULT 'en'::"public"."LOCALE", - "is_restricted" boolean DEFAULT false NOT NULL -); - -ALTER TABLE "public"."profile" OWNER TO "postgres"; - -CREATE TABLE IF NOT EXISTS "public"."question" ( - "id" bigint NOT NULL, - "question_type_id" bigint NOT NULL, - "title" character varying NOT NULL, - "created_at" timestamp with time zone DEFAULT "now"(), - "updated_at" timestamp with time zone DEFAULT "now"(), - "exercise_id" "uuid" NOT NULL, - "name" "uuid" DEFAULT "extensions"."gen_random_uuid"(), - "points" double precision, - "order" bigint -); - -ALTER TABLE "public"."question" OWNER TO "postgres"; - -CREATE TABLE IF NOT EXISTS "public"."question_answer" ( - "id" bigint NOT NULL, - "answers" character varying[], - "question_id" bigint NOT NULL, - "open_answer" "text", - "group_member_id" "uuid" NOT NULL, - "submission_id" "uuid", - "point" bigint DEFAULT '0'::bigint -); - -ALTER TABLE "public"."question_answer" OWNER TO "postgres"; - -ALTER TABLE "public"."question_answer" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY ( - SEQUENCE NAME "public"."question_answer_id_seq" - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1 -); - -ALTER TABLE "public"."question" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY ( - SEQUENCE NAME "public"."question_id_seq" - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1 -); - -CREATE TABLE IF NOT EXISTS "public"."question_type" ( - "id" bigint NOT NULL, - "label" character varying NOT NULL, - "created_at" timestamp with time zone DEFAULT "now"(), - "updated_at" timestamp with time zone DEFAULT "now"(), - "typename" character varying -); - -ALTER TABLE "public"."question_type" OWNER TO "postgres"; - -ALTER TABLE "public"."question_type" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY ( - SEQUENCE NAME "public"."question_type_id_seq" - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1 -); - -CREATE TABLE IF NOT EXISTS "public"."quiz" ( - "id" "uuid" DEFAULT "extensions"."gen_random_uuid"() NOT NULL, - "created_at" timestamp with time zone DEFAULT "now"(), - "updated_at" timestamp with time zone DEFAULT "now"(), - "title" "text", - "questions" "json", - "timelimit" character varying DEFAULT '10s'::character varying, - "theme" character varying DEFAULT 'standard'::character varying, - "organization_id" "uuid" NOT NULL -); - -ALTER TABLE "public"."quiz" OWNER TO "postgres"; - -CREATE TABLE IF NOT EXISTS "public"."role" ( - "type" character varying NOT NULL, - "description" character varying, - "id" bigint NOT NULL, - "updated_at" timestamp with time zone DEFAULT "now"(), - "created_at" timestamp with time zone DEFAULT "now"() -); - -ALTER TABLE "public"."role" OWNER TO "postgres"; - -ALTER TABLE "public"."role" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY ( - SEQUENCE NAME "public"."role_id_seq" - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1 -); - -CREATE TABLE IF NOT EXISTS "public"."submission" ( - "id" "uuid" DEFAULT "extensions"."uuid_generate_v4"() NOT NULL, - "reviewer_id" bigint, - "status_id" bigint DEFAULT '1'::bigint, - "total" bigint DEFAULT '0'::bigint, - "created_at" timestamp with time zone DEFAULT "now"(), - "updated_at" timestamp with time zone DEFAULT "now"(), - "exercise_id" "uuid" NOT NULL, - "submitted_by" "uuid", - "course_id" "uuid", - "feedback" "text" -); - -ALTER TABLE "public"."submission" OWNER TO "postgres"; - -CREATE TABLE IF NOT EXISTS "public"."submissionstatus" ( - "id" bigint NOT NULL, - "label" character varying NOT NULL, - "updated_at" timestamp with time zone DEFAULT "now"() -); - -ALTER TABLE "public"."submissionstatus" OWNER TO "postgres"; - -ALTER TABLE "public"."submissionstatus" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY ( - SEQUENCE NAME "public"."submission_status_id_seq" - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1 -); - -CREATE TABLE IF NOT EXISTS "public"."test_tenant" ( - "id" integer NOT NULL, - "details" "text" -); - -ALTER TABLE "public"."test_tenant" OWNER TO "postgres"; - -CREATE SEQUENCE IF NOT EXISTS "public"."test_tenant_id_seq" - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1; - -ALTER TABLE "public"."test_tenant_id_seq" OWNER TO "postgres"; - -ALTER SEQUENCE "public"."test_tenant_id_seq" OWNED BY "public"."test_tenant"."id"; - -CREATE TABLE IF NOT EXISTS "public"."video_transcripts" ( - "id" bigint NOT NULL, - "created_at" timestamp with time zone DEFAULT "now"() NOT NULL, - "muse_svid" "text", - "transcript" "text", - "downloaded" boolean DEFAULT false, - "link" "text" -); - -ALTER TABLE "public"."video_transcripts" OWNER TO "postgres"; - -ALTER TABLE "public"."video_transcripts" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY ( - SEQUENCE NAME "public"."video_transcripts_id_seq" - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1 -); - -CREATE TABLE IF NOT EXISTS "public"."waitinglist" ( - "id" bigint NOT NULL, - "email" character varying NOT NULL, - "created_at" timestamp with time zone DEFAULT "now"() -); - -ALTER TABLE "public"."waitinglist" OWNER TO "postgres"; - -ALTER TABLE "public"."waitinglist" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY ( - SEQUENCE NAME "public"."waitinglist_id_seq" - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1 -); - -ALTER TABLE ONLY "public"."lesson_language_history" ALTER COLUMN "id" SET DEFAULT "nextval"('"public"."lesson_language_history_id_seq"'::"regclass"); - -ALTER TABLE ONLY "public"."test_tenant" ALTER COLUMN "id" SET DEFAULT "nextval"('"public"."test_tenant_id_seq"'::"regclass"); - -ALTER TABLE ONLY "public"."analytics_login_events" - ADD CONSTRAINT "analytics_login_events_pkey" PRIMARY KEY ("id"); - -ALTER TABLE ONLY "public"."analytics_login_events" - ADD CONSTRAINT "analytics_login_events_user_id_unique" UNIQUE ("user_id"); - -ALTER TABLE ONLY "public"."apps_poll_option" - ADD CONSTRAINT "apps_poll_option_pkey" PRIMARY KEY ("id"); - -ALTER TABLE ONLY "public"."apps_poll" - ADD CONSTRAINT "apps_poll_pkey" PRIMARY KEY ("id"); - -ALTER TABLE ONLY "public"."apps_poll_submission" - ADD CONSTRAINT "apps_poll_submision_pkey" PRIMARY KEY ("id"); - -ALTER TABLE ONLY "public"."community_answer" - ADD CONSTRAINT "community_answer_pkey" PRIMARY KEY ("id"); - -ALTER TABLE ONLY "public"."community_question" - ADD CONSTRAINT "community_question_pkey" PRIMARY KEY ("id"); - -ALTER TABLE ONLY "public"."waitinglist" - ADD CONSTRAINT "constraint_name" UNIQUE ("email"); - -ALTER TABLE ONLY "public"."course_newsfeed_comment" - ADD CONSTRAINT "course_newsfeed_comment_id_key" UNIQUE ("id"); - -ALTER TABLE ONLY "public"."course_newsfeed_comment" - ADD CONSTRAINT "course_newsfeed_comment_pkey" PRIMARY KEY ("id"); - -ALTER TABLE ONLY "public"."course_newsfeed" - ADD CONSTRAINT "course_newsfeed_pkey" PRIMARY KEY ("id"); - -ALTER TABLE ONLY "public"."course" - ADD CONSTRAINT "course_pkey" PRIMARY KEY ("id"); - -ALTER TABLE ONLY "public"."course" - ADD CONSTRAINT "course_slug_key" UNIQUE ("slug"); - -ALTER TABLE ONLY "public"."currency" - ADD CONSTRAINT "currency_pkey" PRIMARY KEY ("id"); - -ALTER TABLE ONLY "public"."exercise" - ADD CONSTRAINT "exercise_pkey" PRIMARY KEY ("id"); - -ALTER TABLE ONLY "public"."group_attendance" - ADD CONSTRAINT "group_attendance_pkey" PRIMARY KEY ("id"); - -ALTER TABLE ONLY "public"."group" - ADD CONSTRAINT "group_pkey" PRIMARY KEY ("id"); - -ALTER TABLE ONLY "public"."groupmember" - ADD CONSTRAINT "groupmember_pkey" PRIMARY KEY ("id"); - -ALTER TABLE ONLY "public"."lesson_comment" - ADD CONSTRAINT "lesson_comment_pkey" PRIMARY KEY ("id"); - -ALTER TABLE ONLY "public"."lesson_completion" - ADD CONSTRAINT "lesson_completion_pkey" PRIMARY KEY ("id"); - -ALTER TABLE ONLY "public"."lesson_language_history" - ADD CONSTRAINT "lesson_language_history_pkey" PRIMARY KEY ("id"); - -ALTER TABLE ONLY "public"."lesson_language" - ADD CONSTRAINT "lesson_language_pkey" PRIMARY KEY ("id"); - -ALTER TABLE ONLY "public"."lesson" - ADD CONSTRAINT "lesson_pkey" PRIMARY KEY ("id"); - -ALTER TABLE ONLY "public"."lesson_section" - ADD CONSTRAINT "lesson_section_pkey" PRIMARY KEY ("id"); - -ALTER TABLE ONLY "public"."option" - ADD CONSTRAINT "option_pkey" PRIMARY KEY ("id"); - -ALTER TABLE ONLY "public"."organization_contacts" - ADD CONSTRAINT "organization_contacts_pkey" PRIMARY KEY ("id"); - -ALTER TABLE ONLY "public"."organization" - ADD CONSTRAINT "organization_customDomain_key" UNIQUE ("customDomain"); - -ALTER TABLE ONLY "public"."organization_emaillist" - ADD CONSTRAINT "organization_emaillist_pkey" PRIMARY KEY ("id"); - -ALTER TABLE ONLY "public"."organization" - ADD CONSTRAINT "organization_pkey" PRIMARY KEY ("id"); - -ALTER TABLE ONLY "public"."organization_plan" - ADD CONSTRAINT "organization_plan_pkey" PRIMARY KEY ("id"); - -ALTER TABLE ONLY "public"."organization_plan" - ADD CONSTRAINT "organization_plan_subscription_id_key" UNIQUE ("subscription_id"); - -ALTER TABLE ONLY "public"."organization" - ADD CONSTRAINT "organization_siteName_key" UNIQUE ("siteName"); - -ALTER TABLE ONLY "public"."organizationmember" - ADD CONSTRAINT "organizationmember_pkey" PRIMARY KEY ("id"); - -ALTER TABLE ONLY "public"."quiz_play" - ADD CONSTRAINT "play_quiz_pkey" PRIMARY KEY ("id"); - -ALTER TABLE ONLY "public"."profile" - ADD CONSTRAINT "profile_email_key" UNIQUE ("email"); - -ALTER TABLE ONLY "public"."profile" - ADD CONSTRAINT "profile_pkey" PRIMARY KEY ("id"); - -ALTER TABLE ONLY "public"."profile" - ADD CONSTRAINT "profile_username_key" UNIQUE ("username"); - -ALTER TABLE ONLY "public"."question_answer" - ADD CONSTRAINT "question_answer_pkey" PRIMARY KEY ("id"); - -ALTER TABLE ONLY "public"."question" - ADD CONSTRAINT "question_pkey" PRIMARY KEY ("id"); - -ALTER TABLE ONLY "public"."question_type" - ADD CONSTRAINT "question_type_pkey" PRIMARY KEY ("id"); - -ALTER TABLE ONLY "public"."quiz" - ADD CONSTRAINT "quiz_pkey" PRIMARY KEY ("id"); - -ALTER TABLE ONLY "public"."quiz_play" - ADD CONSTRAINT "quiz_play_pin_key" UNIQUE ("pin"); - -ALTER TABLE ONLY "public"."role" - ADD CONSTRAINT "role_pkey" PRIMARY KEY ("id"); - -ALTER TABLE ONLY "public"."submission" - ADD CONSTRAINT "submission_pkey" PRIMARY KEY ("id"); - -ALTER TABLE ONLY "public"."submissionstatus" - ADD CONSTRAINT "submission_status_pkey" PRIMARY KEY ("id"); - -ALTER TABLE ONLY "public"."test_tenant" - ADD CONSTRAINT "test_tenant_pkey" PRIMARY KEY ("id"); - -ALTER TABLE ONLY "public"."groupmember" - ADD CONSTRAINT "unique_entries" UNIQUE ("group_id", "profile_id", "email"); - -ALTER TABLE ONLY "public"."groupmember" - ADD CONSTRAINT "unique_group_email" UNIQUE ("group_id", "email"); - -ALTER TABLE ONLY "public"."groupmember" - ADD CONSTRAINT "unique_group_profile" UNIQUE ("group_id", "profile_id"); - -ALTER TABLE ONLY "public"."video_transcripts" - ADD CONSTRAINT "video_transcripts_pkey" PRIMARY KEY ("id"); - -ALTER TABLE ONLY "public"."waitinglist" - ADD CONSTRAINT "waitinglist_pkey" PRIMARY KEY ("id"); - -CREATE INDEX "idx_analytics_login_events_logged_in_at" ON "public"."analytics_login_events" USING "btree" ("logged_in_at"); - -CREATE INDEX "idx_analytics_login_events_user_id" ON "public"."analytics_login_events" USING "btree" ("user_id"); - -CREATE OR REPLACE TRIGGER "handle_exercise_updated_at" BEFORE UPDATE ON "public"."exercise" FOR EACH ROW EXECUTE FUNCTION "extensions"."moddatetime"('updated_at'); - -CREATE OR REPLACE TRIGGER "handle_lesson_updated_at" BEFORE UPDATE ON "public"."lesson" FOR EACH ROW EXECUTE FUNCTION "extensions"."moddatetime"('updated_at'); - -CREATE OR REPLACE TRIGGER "handle_question_type_updated_at" BEFORE UPDATE ON "public"."question_type" FOR EACH ROW EXECUTE FUNCTION "extensions"."moddatetime"('updated_at'); - -CREATE OR REPLACE TRIGGER "handle_question_updated_at" BEFORE UPDATE ON "public"."question" FOR EACH ROW EXECUTE FUNCTION "extensions"."moddatetime"('updated_at'); - -CREATE OR REPLACE TRIGGER "handle_role_updated_at" BEFORE UPDATE ON "public"."role" FOR EACH ROW EXECUTE FUNCTION "extensions"."moddatetime"('updated_at'); - -CREATE OR REPLACE TRIGGER "handle_submission_updated_at" BEFORE UPDATE ON "public"."submission" FOR EACH ROW EXECUTE FUNCTION "extensions"."moddatetime"('updated_at'); - -CREATE OR REPLACE TRIGGER "handle_updated_at" BEFORE UPDATE ON "public"."exercise" FOR EACH ROW EXECUTE FUNCTION "extensions"."moddatetime"('updated_at'); - -CREATE OR REPLACE TRIGGER "handle_updated_at" BEFORE UPDATE ON "public"."lesson" FOR EACH ROW EXECUTE FUNCTION "extensions"."moddatetime"('updated_at'); - -CREATE OR REPLACE TRIGGER "handle_updated_at" BEFORE UPDATE ON "public"."question" FOR EACH ROW EXECUTE FUNCTION "extensions"."moddatetime"('updated_at'); - -CREATE OR REPLACE TRIGGER "update_lesson_language_history_trigger" AFTER INSERT OR UPDATE ON "public"."lesson_language" FOR EACH ROW EXECUTE FUNCTION "public"."update_lesson_language_history"(); - -ALTER TABLE ONLY "public"."analytics_login_events" - ADD CONSTRAINT "analytics_login_events_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "auth"."users"("id"); - -ALTER TABLE ONLY "public"."apps_poll" - ADD CONSTRAINT "apps_poll_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "public"."groupmember"("id"); - -ALTER TABLE ONLY "public"."apps_poll" - ADD CONSTRAINT "apps_poll_courseId_fkey" FOREIGN KEY ("courseId") REFERENCES "public"."course"("id"); - -ALTER TABLE ONLY "public"."apps_poll_option" - ADD CONSTRAINT "apps_poll_option_poll_id_fkey" FOREIGN KEY ("poll_id") REFERENCES "public"."apps_poll"("id"); - -ALTER TABLE ONLY "public"."apps_poll_submission" - ADD CONSTRAINT "apps_poll_submission_poll_id_fkey" FOREIGN KEY ("poll_id") REFERENCES "public"."apps_poll"("id"); - -ALTER TABLE ONLY "public"."apps_poll_submission" - ADD CONSTRAINT "apps_poll_submission_poll_option_id_fkey" FOREIGN KEY ("poll_option_id") REFERENCES "public"."apps_poll_option"("id"); - -ALTER TABLE ONLY "public"."apps_poll_submission" - ADD CONSTRAINT "apps_poll_submission_selected_by_id_fkey" FOREIGN KEY ("selected_by_id") REFERENCES "public"."groupmember"("id"); - -ALTER TABLE ONLY "public"."community_answer" - ADD CONSTRAINT "community_answer_author_id_fkey" FOREIGN KEY ("author_id") REFERENCES "public"."organizationmember"("id"); - -ALTER TABLE ONLY "public"."community_answer" - ADD CONSTRAINT "community_answer_author_profile_id_fkey" FOREIGN KEY ("author_profile_id") REFERENCES "public"."profile"("id"); - -ALTER TABLE ONLY "public"."community_answer" - ADD CONSTRAINT "community_answer_question_id_fkey" FOREIGN KEY ("question_id") REFERENCES "public"."community_question"("id"); - -ALTER TABLE ONLY "public"."community_question" - ADD CONSTRAINT "community_question_author_id_fkey" FOREIGN KEY ("author_id") REFERENCES "public"."organizationmember"("id"); - -ALTER TABLE ONLY "public"."community_question" - ADD CONSTRAINT "community_question_author_profile_id_fkey" FOREIGN KEY ("author_profile_id") REFERENCES "public"."profile"("id"); - -ALTER TABLE ONLY "public"."community_question" - ADD CONSTRAINT "community_question_course_id_fkey" FOREIGN KEY ("course_id") REFERENCES "public"."course"("id"); - -ALTER TABLE ONLY "public"."community_question" - ADD CONSTRAINT "community_question_organization_id_fkey" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id"); - -ALTER TABLE ONLY "public"."course" - ADD CONSTRAINT "course_group_id_fkey" FOREIGN KEY ("group_id") REFERENCES "public"."group"("id"); - -ALTER TABLE ONLY "public"."course_newsfeed" - ADD CONSTRAINT "course_newsfeed_author_id_fkey" FOREIGN KEY ("author_id") REFERENCES "public"."groupmember"("id"); - -ALTER TABLE ONLY "public"."course_newsfeed_comment" - ADD CONSTRAINT "course_newsfeed_comment_author_id_fkey" FOREIGN KEY ("author_id") REFERENCES "public"."groupmember"("id"); - -ALTER TABLE ONLY "public"."course_newsfeed_comment" - ADD CONSTRAINT "course_newsfeed_comment_course_newsfeed_id_fkey" FOREIGN KEY ("course_newsfeed_id") REFERENCES "public"."course_newsfeed"("id"); - -ALTER TABLE ONLY "public"."course_newsfeed" - ADD CONSTRAINT "course_newsfeed_course_id_fkey" FOREIGN KEY ("course_id") REFERENCES "public"."course"("id"); - -ALTER TABLE ONLY "public"."exercise" - ADD CONSTRAINT "exercise_lesson_id_fkey" FOREIGN KEY ("lesson_id") REFERENCES "public"."lesson"("id") ON DELETE CASCADE; - -ALTER TABLE ONLY "public"."group_attendance" - ADD CONSTRAINT "group_attendance_course_id_fkey" FOREIGN KEY ("course_id") REFERENCES "public"."course"("id"); - -ALTER TABLE ONLY "public"."group_attendance" - ADD CONSTRAINT "group_attendance_student_id_fkey" FOREIGN KEY ("student_id") REFERENCES "public"."groupmember"("id"); - -ALTER TABLE ONLY "public"."group" - ADD CONSTRAINT "group_organization_id_fkey" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id"); - -ALTER TABLE ONLY "public"."groupmember" - ADD CONSTRAINT "groupmember_group_id_fkey" FOREIGN KEY ("group_id") REFERENCES "public"."group"("id"); - -ALTER TABLE ONLY "public"."groupmember" - ADD CONSTRAINT "groupmember_profile_id_fkey" FOREIGN KEY ("profile_id") REFERENCES "public"."profile"("id"); - -ALTER TABLE ONLY "public"."groupmember" - ADD CONSTRAINT "groupmember_role_id_fkey" FOREIGN KEY ("role_id") REFERENCES "public"."role"("id"); - -ALTER TABLE ONLY "public"."lesson_comment" - ADD CONSTRAINT "lesson_comment_groupmember_id_fkey" FOREIGN KEY ("groupmember_id") REFERENCES "public"."groupmember"("id"); - -ALTER TABLE ONLY "public"."lesson_comment" - ADD CONSTRAINT "lesson_comment_lesson_id_fkey" FOREIGN KEY ("lesson_id") REFERENCES "public"."lesson"("id") ON DELETE CASCADE; - -ALTER TABLE ONLY "public"."lesson_completion" - ADD CONSTRAINT "lesson_completion_lesson_id_fkey" FOREIGN KEY ("lesson_id") REFERENCES "public"."lesson"("id") ON DELETE CASCADE; - -ALTER TABLE ONLY "public"."lesson_completion" - ADD CONSTRAINT "lesson_completion_profile_id_fkey" FOREIGN KEY ("profile_id") REFERENCES "public"."profile"("id"); - -ALTER TABLE ONLY "public"."lesson" - ADD CONSTRAINT "lesson_course_id_fkey" FOREIGN KEY ("course_id") REFERENCES "public"."course"("id"); - -ALTER TABLE ONLY "public"."lesson" - ADD CONSTRAINT "lesson_teacher_id_fkey" FOREIGN KEY ("teacher_id") REFERENCES "public"."profile"("id"); - -ALTER TABLE ONLY "public"."option" - ADD CONSTRAINT "option_question_id_fkey" FOREIGN KEY ("question_id") REFERENCES "public"."question"("id") ON DELETE CASCADE; - -ALTER TABLE ONLY "public"."organization_contacts" - ADD CONSTRAINT "organization_contacts_organization_id_fkey" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id"); - -ALTER TABLE ONLY "public"."organization_emaillist" - ADD CONSTRAINT "organization_emaillist_organization_id_fkey" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id"); - -ALTER TABLE ONLY "public"."organization_plan" - ADD CONSTRAINT "organization_plan_org_id_fkey" FOREIGN KEY ("org_id") REFERENCES "public"."organization"("id"); - -ALTER TABLE ONLY "public"."organization_plan" - ADD CONSTRAINT "organization_plan_triggered_by_fkey" FOREIGN KEY ("triggered_by") REFERENCES "public"."organizationmember"("id"); - -ALTER TABLE ONLY "public"."organizationmember" - ADD CONSTRAINT "organizationmember_organization_id_fkey" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id"); - -ALTER TABLE ONLY "public"."organizationmember" - ADD CONSTRAINT "organizationmember_profile_id_fkey" FOREIGN KEY ("profile_id") REFERENCES "public"."profile"("id"); - -ALTER TABLE ONLY "public"."organizationmember" - ADD CONSTRAINT "organizationmember_role_id_fkey" FOREIGN KEY ("role_id") REFERENCES "public"."role"("id"); - -ALTER TABLE ONLY "public"."profile" - ADD CONSTRAINT "profile_id_fkey" FOREIGN KEY ("id") REFERENCES "auth"."users"("id"); - -ALTER TABLE ONLY "public"."lesson_language_history" - ADD CONSTRAINT "public_lesson_language_history_lesson_language_id_fkey" FOREIGN KEY ("lesson_language_id") REFERENCES "public"."lesson_language"("id") ON UPDATE CASCADE ON DELETE CASCADE; - -ALTER TABLE ONLY "public"."lesson_language" - ADD CONSTRAINT "public_lesson_language_lesson_id_fkey" FOREIGN KEY ("lesson_id") REFERENCES "public"."lesson"("id") ON UPDATE CASCADE ON DELETE CASCADE; - -ALTER TABLE ONLY "public"."lesson_section" - ADD CONSTRAINT "public_lesson_section_course_id_fkey" FOREIGN KEY ("course_id") REFERENCES "public"."course"("id") ON UPDATE CASCADE ON DELETE CASCADE; - -ALTER TABLE ONLY "public"."lesson" - ADD CONSTRAINT "public_lesson_section_id_fkey" FOREIGN KEY ("section_id") REFERENCES "public"."lesson_section"("id") ON UPDATE CASCADE ON DELETE CASCADE; - -ALTER TABLE ONLY "public"."question_answer" - ADD CONSTRAINT "question_answer_group_member_id_fkey" FOREIGN KEY ("group_member_id") REFERENCES "public"."groupmember"("id"); - -ALTER TABLE ONLY "public"."question_answer" - ADD CONSTRAINT "question_answer_question_id_fkey" FOREIGN KEY ("question_id") REFERENCES "public"."question"("id") ON DELETE CASCADE; - -ALTER TABLE ONLY "public"."question_answer" - ADD CONSTRAINT "question_answer_submission_id_fkey" FOREIGN KEY ("submission_id") REFERENCES "public"."submission"("id") ON DELETE CASCADE; - -ALTER TABLE ONLY "public"."question" - ADD CONSTRAINT "question_exercise_id_fkey" FOREIGN KEY ("exercise_id") REFERENCES "public"."exercise"("id") ON DELETE CASCADE; - -ALTER TABLE ONLY "public"."question" - ADD CONSTRAINT "question_question_type_id_fkey" FOREIGN KEY ("question_type_id") REFERENCES "public"."question_type"("id"); - -ALTER TABLE ONLY "public"."quiz" - ADD CONSTRAINT "quiz_organization_id_fkey" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id"); - -ALTER TABLE ONLY "public"."quiz_play" - ADD CONSTRAINT "quiz_play_quiz_id_fkey" FOREIGN KEY ("quiz_id") REFERENCES "public"."quiz"("id"); - -ALTER TABLE ONLY "public"."submission" - ADD CONSTRAINT "submission_course_id_fkey" FOREIGN KEY ("course_id") REFERENCES "public"."course"("id") ON DELETE CASCADE; - -ALTER TABLE ONLY "public"."submission" - ADD CONSTRAINT "submission_exercise_id_fkey" FOREIGN KEY ("exercise_id") REFERENCES "public"."exercise"("id") ON DELETE CASCADE; - -ALTER TABLE ONLY "public"."submission" - ADD CONSTRAINT "submission_status_id_fkey" FOREIGN KEY ("status_id") REFERENCES "public"."submissionstatus"("id"); - -ALTER TABLE ONLY "public"."submission" - ADD CONSTRAINT "submission_submitted_by_fkey" FOREIGN KEY ("submitted_by") REFERENCES "public"."groupmember"("id"); - -CREATE POLICY "Allow authenticated users to SELECT" ON "public"."option" FOR SELECT USING (("auth"."uid"() IS NOT NULL)); - -CREATE POLICY "Allow authenticated users to SELECT" ON "public"."question" FOR SELECT USING (("auth"."uid"() IS NOT NULL)); - -CREATE POLICY "Allow authenticated users to read." ON "public"."organizationmember" FOR SELECT USING (("auth"."uid"() IS NOT NULL)); - -CREATE POLICY "Authenticated users can SELECT" ON "public"."community_answer" FOR SELECT USING (("auth"."uid"() IS NOT NULL)); - -CREATE POLICY "Authenticated users can SELECT" ON "public"."community_question" FOR SELECT USING (("auth"."uid"() IS NOT NULL)); - -CREATE POLICY "Authenticated users can SELECT" ON "public"."lesson_language_history" FOR SELECT USING (("auth"."uid"() IS NOT NULL)); - -CREATE POLICY "Authenticated users can SELECT" ON "public"."quiz" FOR SELECT TO "authenticated" USING (true); - -CREATE POLICY "Authenticated users can SELECT" ON "public"."quiz_play" FOR SELECT TO "authenticated" USING (true); - -CREATE POLICY "Authenticated users can SELECT" ON "public"."submissionstatus" FOR SELECT TO "authenticated" USING (true); - -CREATE POLICY "Authenticated users can delete" ON "public"."organization" FOR DELETE USING (("auth"."uid"() IS NOT NULL)); - -CREATE POLICY "Authenticated users can read" ON "public"."apps_poll_submission" FOR SELECT USING (("auth"."uid"() IS NOT NULL)); - -CREATE POLICY "Delete only your own comment" ON "public"."lesson_comment" FOR DELETE USING (("auth"."uid"() = ( SELECT "groupmember"."profile_id" - FROM "public"."groupmember" - WHERE ("groupmember"."id" = "lesson_comment"."groupmember_id")))); - -CREATE POLICY "Delete only your own poll" ON "public"."apps_poll" FOR DELETE USING (("auth"."uid"() = ( SELECT "groupmember"."profile_id" - FROM "public"."groupmember" - WHERE ("groupmember"."id" = "apps_poll"."authorId")))); - -CREATE POLICY "Delete your own" ON "public"."course_newsfeed_comment" FOR DELETE USING (("auth"."uid"() = ( SELECT "groupmember"."profile_id" - FROM "public"."groupmember" - WHERE ("groupmember"."id" = "course_newsfeed_comment"."author_id")))); - -CREATE POLICY "Delete your own answer" ON "public"."community_answer" FOR DELETE USING (("auth"."uid"() = "author_profile_id")); - -CREATE POLICY "Delete your own comment" ON "public"."course_newsfeed" FOR DELETE USING (("auth"."uid"() = ( SELECT "groupmember"."profile_id" - FROM "public"."groupmember" - WHERE ("groupmember"."id" = "course_newsfeed"."author_id")))); - -CREATE POLICY "Delete your own question" ON "public"."community_question" FOR DELETE USING (("auth"."uid"() = "author_profile_id")); - -CREATE POLICY "Delete your own submission" ON "public"."apps_poll_submission" FOR DELETE USING (("auth"."uid"() = ( SELECT "groupmember"."profile_id" - FROM "public"."groupmember" - WHERE ("groupmember"."id" = "apps_poll_submission"."selected_by_id")))); - -CREATE POLICY "Enable access to all users" ON "public"."course" FOR SELECT USING (true); - -CREATE POLICY "Enable delete for users based on user_id" ON "public"."analytics_login_events" FOR DELETE USING (("auth"."uid"() = "user_id")); - -CREATE POLICY "Enable insert for authenticated users only" ON "public"."apps_poll_submission" FOR INSERT TO "authenticated" WITH CHECK (true); - -CREATE POLICY "Enable insert for authenticated users only" ON "public"."community_answer" FOR INSERT TO "authenticated" WITH CHECK (true); - -CREATE POLICY "Enable insert for authenticated users only" ON "public"."community_question" FOR INSERT TO "authenticated" WITH CHECK (true); - -CREATE POLICY "Enable insert for authenticated users only" ON "public"."group" FOR INSERT TO "authenticated" WITH CHECK (true); - -CREATE POLICY "Enable insert for authenticated users only" ON "public"."groupmember" FOR INSERT TO "authenticated" WITH CHECK (true); - -CREATE POLICY "Enable insert for authenticated users only" ON "public"."organization" FOR INSERT TO "authenticated" WITH CHECK (true); - -CREATE POLICY "Enable insert for authenticated users only" ON "public"."organizationmember" FOR INSERT TO "authenticated" WITH CHECK (true); - -CREATE POLICY "Enable read access for all users" ON "public"."exercise" FOR SELECT USING (true); - -CREATE POLICY "Enable read access for all users" ON "public"."group" FOR SELECT USING (true); - -CREATE POLICY "Enable read access for all users" ON "public"."groupmember" FOR SELECT USING (true); - -CREATE POLICY "Enable read access for all users" ON "public"."lesson" FOR SELECT USING (true); - -CREATE POLICY "Enable read access for all users" ON "public"."lesson_comment" FOR SELECT USING (true); - -CREATE POLICY "Enable read access for all users" ON "public"."lesson_completion" FOR SELECT USING (true); - -CREATE POLICY "Enable read access for all users" ON "public"."lesson_language" FOR SELECT USING (true); - -CREATE POLICY "Enable read access for all users" ON "public"."lesson_section" FOR SELECT USING (true); - -CREATE POLICY "Enable read access for all users" ON "public"."organization" FOR SELECT USING (true); - -CREATE POLICY "Enable read access for all users" ON "public"."organization_contacts" FOR INSERT WITH CHECK (true); - -CREATE POLICY "Enable read access for all users" ON "public"."organization_emaillist" FOR INSERT WITH CHECK (true); - -CREATE POLICY "Enable read access for all users" ON "public"."organization_plan" FOR SELECT USING (true); - -CREATE POLICY "Enable read access for all users" ON "public"."question_type" FOR SELECT USING (true); - -CREATE POLICY "Enable read access for all users" ON "public"."role" FOR SELECT USING (true); - -CREATE POLICY "Only admin can delete" ON "public"."organizationmember" FOR DELETE USING ("public"."is_org_admin"()); - -CREATE POLICY "Only admin can update" ON "public"."organizationmember" FOR UPDATE USING ("public"."is_org_admin"()) WITH CHECK ("public"."is_org_admin"()); - -CREATE POLICY "Only auth users can read profile" ON "public"."profile" FOR SELECT TO "authenticated", "anon" USING (true); - -CREATE POLICY "Only authenticated users can SELECT" ON "public"."submission" FOR SELECT TO "authenticated" USING (true); - -CREATE POLICY "Only authenticated users can select." ON "public"."question_answer" FOR SELECT USING (("auth"."uid"() IS NOT NULL)); - -CREATE POLICY "Only org admins can delete" ON "public"."group" FOR DELETE USING ("public"."is_org_admin"()); - -CREATE POLICY "Only org admins can update" ON "public"."group" FOR UPDATE USING ("public"."is_org_admin"()) WITH CHECK ("public"."is_org_admin"()); - -CREATE POLICY "Only user can update their account via email" ON "public"."organizationmember" FOR UPDATE USING (((( SELECT "auth"."jwt"() AS "jwt") ->> 'email'::"text") = "email")) WITH CHECK (((( SELECT "auth"."jwt"() AS "jwt") ->> 'email'::"text") = "email")); - -CREATE POLICY "Public profiles are viewable by everyone." ON "public"."profile" FOR SELECT USING (true); - -CREATE POLICY "Update only your own" ON "public"."apps_poll" FOR UPDATE USING (("auth"."uid"() = ( SELECT "groupmember"."profile_id" - FROM "public"."groupmember" - WHERE ("groupmember"."id" = "apps_poll"."authorId")))) WITH CHECK (("auth"."uid"() = ( SELECT "groupmember"."profile_id" - FROM "public"."groupmember" - WHERE ("groupmember"."id" = "apps_poll"."authorId")))); - -CREATE POLICY "Update only your own" ON "public"."course_newsfeed" FOR UPDATE USING (("auth"."uid"() = ( SELECT "groupmember"."profile_id" - FROM "public"."groupmember" - WHERE ("groupmember"."id" = "course_newsfeed"."author_id")))) WITH CHECK (("auth"."uid"() = ( SELECT "groupmember"."profile_id" - FROM "public"."groupmember" - WHERE ("groupmember"."id" = "course_newsfeed"."author_id")))); - -CREATE POLICY "Update only your own" ON "public"."course_newsfeed_comment" FOR UPDATE USING (("auth"."uid"() = ( SELECT "groupmember"."profile_id" - FROM "public"."groupmember" - WHERE ("groupmember"."id" = "course_newsfeed_comment"."author_id")))) WITH CHECK (("auth"."uid"() = ( SELECT "groupmember"."profile_id" - FROM "public"."groupmember" - WHERE ("groupmember"."id" = "course_newsfeed_comment"."author_id")))); - -CREATE POLICY "Update only your own" ON "public"."lesson_comment" FOR UPDATE USING (("auth"."uid"() = ( SELECT "groupmember"."profile_id" - FROM "public"."groupmember" - WHERE ("groupmember"."id" = "lesson_comment"."groupmember_id")))) WITH CHECK (("auth"."uid"() = ( SELECT "groupmember"."profile_id" - FROM "public"."groupmember" - WHERE ("groupmember"."id" = "lesson_comment"."groupmember_id")))); - -CREATE POLICY "Update your own answer" ON "public"."community_answer" FOR UPDATE USING (("auth"."uid"() = "author_profile_id")) WITH CHECK (("auth"."uid"() = "author_profile_id")); - -CREATE POLICY "Update your own question" ON "public"."community_question" FOR UPDATE USING (("auth"."uid"() = "author_profile_id")) WITH CHECK (("auth"."uid"() = "author_profile_id")); - -CREATE POLICY "Update your own submission" ON "public"."apps_poll_submission" FOR UPDATE USING (("auth"."uid"() = ( SELECT "groupmember"."profile_id" - FROM "public"."groupmember" - WHERE ("groupmember"."id" = "apps_poll_submission"."selected_by_id")))) WITH CHECK (("auth"."uid"() = ( SELECT "groupmember"."profile_id" - FROM "public"."groupmember" - WHERE ("groupmember"."id" = "apps_poll_submission"."selected_by_id")))); - -CREATE POLICY "User can only delete their profiles" ON "public"."profile" FOR DELETE USING (("auth"."uid"() = "id")); - -CREATE POLICY "User must be a course member to DELETE" ON "public"."submission" FOR DELETE USING ("public"."is_user_in_course_group"(( SELECT "course"."group_id" - FROM "public"."course" - WHERE ("course"."id" = "submission"."course_id") - LIMIT 1))); - -CREATE POLICY "User must be a course member to INSERT" ON "public"."apps_poll" FOR INSERT WITH CHECK ("public"."is_user_in_course_group"(( SELECT "groupmember"."group_id" - FROM "public"."groupmember" - WHERE ("groupmember"."id" = "apps_poll"."authorId") - LIMIT 1))); - -CREATE POLICY "User must be a course member to INSERT" ON "public"."apps_poll_option" FOR INSERT WITH CHECK ("public"."is_user_in_course_group"(( SELECT "groupmember"."group_id" - FROM "public"."groupmember" - WHERE ("groupmember"."id" = ( SELECT "apps_poll"."authorId" - FROM "public"."apps_poll" - WHERE ("apps_poll"."id" = "apps_poll_option"."poll_id") - LIMIT 1)) - LIMIT 1))); - -CREATE POLICY "User must be a course member to INSERT" ON "public"."course_newsfeed" FOR INSERT WITH CHECK ("public"."is_user_in_course_group"(( SELECT "course"."group_id" - FROM "public"."course" - WHERE ("course"."id" = "course_newsfeed"."course_id") - LIMIT 1))); - -CREATE POLICY "User must be a course member to INSERT" ON "public"."course_newsfeed_comment" FOR INSERT WITH CHECK ("public"."is_user_in_course_group"(( SELECT "course"."group_id" - FROM "public"."course" - WHERE ("course"."id" = ( SELECT "course_newsfeed"."course_id" - FROM "public"."course_newsfeed" - WHERE ("course_newsfeed"."id" = "course_newsfeed_comment"."course_newsfeed_id"))) - LIMIT 1))); - -CREATE POLICY "User must be a course member to INSERT" ON "public"."group_attendance" FOR INSERT WITH CHECK ("public"."is_user_in_course_group"(( SELECT "course"."group_id" - FROM "public"."course" - WHERE ("course"."id" = "group_attendance"."course_id") - LIMIT 1))); - -CREATE POLICY "User must be a course member to INSERT" ON "public"."submission" FOR INSERT WITH CHECK ("public"."is_user_in_course_group"(( SELECT "course"."group_id" - FROM "public"."course" - WHERE ("course"."id" = "submission"."course_id") - LIMIT 1))); - -CREATE POLICY "User must be a course member to SELECT" ON "public"."course_newsfeed" FOR SELECT USING ("public"."is_user_in_course_group"(( SELECT "course"."group_id" - FROM "public"."course" - WHERE ("course"."id" = "course_newsfeed"."course_id") - LIMIT 1))); - -CREATE POLICY "User must be a course member to SELECT" ON "public"."course_newsfeed_comment" FOR SELECT USING ("public"."is_user_in_course_group"(( SELECT "course"."group_id" - FROM "public"."course" - WHERE ("course"."id" = ( SELECT "course_newsfeed"."course_id" - FROM "public"."course_newsfeed" - WHERE ("course_newsfeed"."id" = "course_newsfeed_comment"."course_newsfeed_id"))) - LIMIT 1))); - -CREATE POLICY "User must be a course member to SELECT" ON "public"."group_attendance" FOR SELECT USING ("public"."is_user_in_course_group"(( SELECT "course"."group_id" - FROM "public"."course" - WHERE ("course"."id" = "group_attendance"."course_id") - LIMIT 1))); - -CREATE POLICY "User must be a course member to UPDATE" ON "public"."apps_poll_option" FOR UPDATE USING ("public"."is_user_in_course_group"(( SELECT "groupmember"."group_id" - FROM "public"."groupmember" - WHERE ("groupmember"."id" = ( SELECT "apps_poll"."authorId" - FROM "public"."apps_poll" - WHERE ("apps_poll"."id" = "apps_poll_option"."poll_id") - LIMIT 1)) - LIMIT 1))) WITH CHECK ("public"."is_user_in_course_group"(( SELECT "groupmember"."group_id" - FROM "public"."groupmember" - WHERE ("groupmember"."id" = ( SELECT "apps_poll"."authorId" - FROM "public"."apps_poll" - WHERE ("apps_poll"."id" = "apps_poll_option"."poll_id") - LIMIT 1)) - LIMIT 1))); - -CREATE POLICY "User must be a course member to UPDATE" ON "public"."group_attendance" FOR UPDATE USING ("public"."is_user_in_course_group"(( SELECT "course"."group_id" - FROM "public"."course" - WHERE ("course"."id" = "group_attendance"."course_id") - LIMIT 1))) WITH CHECK ("public"."is_user_in_course_group"(( SELECT "course"."group_id" - FROM "public"."course" - WHERE ("course"."id" = "group_attendance"."course_id") - LIMIT 1))); - -CREATE POLICY "User must be a course member to UPDATE" ON "public"."submission" FOR UPDATE USING ("public"."is_user_in_course_group"(( SELECT "course"."group_id" - FROM "public"."course" - WHERE ("course"."id" = "submission"."course_id") - LIMIT 1))) WITH CHECK ("public"."is_user_in_course_group"(( SELECT "course"."group_id" - FROM "public"."course" - WHERE ("course"."id" = "submission"."course_id") - LIMIT 1))); - -CREATE POLICY "User must be a teacher to DELETE" ON "public"."apps_poll_option" FOR DELETE USING ("public"."is_user_in_group_with_role"(( SELECT "groupmember"."group_id" - FROM "public"."groupmember" - WHERE ("groupmember"."id" = ( SELECT "apps_poll"."authorId" - FROM "public"."apps_poll" - WHERE ("apps_poll"."id" = "apps_poll_option"."poll_id") - LIMIT 1)) - LIMIT 1))); - -CREATE POLICY "User must be admin to UPDATE" ON "public"."organization" FOR UPDATE USING (("id" IN ( SELECT "organizationmember"."organization_id" - FROM "public"."organizationmember" - WHERE (("organizationmember"."profile_id" = ( SELECT "auth"."uid"() AS "uid")) AND ("organizationmember"."role_id" = 1))))) WITH CHECK (("id" IN ( SELECT "organizationmember"."organization_id" - FROM "public"."organizationmember" - WHERE (("organizationmember"."profile_id" = ( SELECT "auth"."uid"() AS "uid")) AND ("organizationmember"."role_id" = 1))))); - -CREATE POLICY "User must be an course member to DELETE" ON "public"."question_answer" FOR DELETE USING ("public"."is_user_in_course_group"(( SELECT "course"."group_id" - FROM "public"."course" - WHERE ("course"."id" = ( SELECT "lesson"."course_id" - FROM "public"."lesson" - WHERE ("lesson"."id" = ( SELECT "exercise"."lesson_id" - FROM "public"."exercise" - WHERE ("exercise"."id" = ( SELECT "question"."exercise_id" - FROM "public"."question" - WHERE ("question"."id" = "question_answer"."question_id") - LIMIT 1)) - LIMIT 1)) - LIMIT 1)) - LIMIT 1))); - -CREATE POLICY "User must be an course member to INSERT" ON "public"."lesson_completion" WITH CHECK ("public"."is_user_in_course_group"(( SELECT "course"."group_id" - FROM "public"."course" - WHERE ("course"."id" = ( SELECT "lesson"."course_id" - FROM "public"."lesson" - WHERE ("lesson"."id" = "lesson_completion"."lesson_id") - LIMIT 1)) - LIMIT 1))); - -CREATE POLICY "User must be an course member to INSERT" ON "public"."question_answer" FOR INSERT WITH CHECK ("public"."is_user_in_course_group"(( SELECT "course"."group_id" - FROM "public"."course" - WHERE ("course"."id" = ( SELECT "lesson"."course_id" - FROM "public"."lesson" - WHERE ("lesson"."id" = ( SELECT "exercise"."lesson_id" - FROM "public"."exercise" - WHERE ("exercise"."id" = ( SELECT "question"."exercise_id" - FROM "public"."question" - WHERE ("question"."id" = "question_answer"."question_id") - LIMIT 1)) - LIMIT 1)) - LIMIT 1)) - LIMIT 1))); - -CREATE POLICY "User must be an course member to UPDATE" ON "public"."question_answer" FOR UPDATE USING ("public"."is_user_in_course_group"(( SELECT "course"."group_id" - FROM "public"."course" - WHERE ("course"."id" = ( SELECT "lesson"."course_id" - FROM "public"."lesson" - WHERE ("lesson"."id" = ( SELECT "exercise"."lesson_id" - FROM "public"."exercise" - WHERE ("exercise"."id" = ( SELECT "question"."exercise_id" - FROM "public"."question" - WHERE ("question"."id" = "question_answer"."question_id") - LIMIT 1)) - LIMIT 1)) - LIMIT 1)) - LIMIT 1))) WITH CHECK ("public"."is_user_in_course_group"(( SELECT "course"."group_id" - FROM "public"."course" - WHERE ("course"."id" = ( SELECT "lesson"."course_id" - FROM "public"."lesson" - WHERE ("lesson"."id" = ( SELECT "exercise"."lesson_id" - FROM "public"."exercise" - WHERE ("exercise"."id" = ( SELECT "question"."exercise_id" - FROM "public"."question" - WHERE ("question"."id" = "question_answer"."question_id") - LIMIT 1)) - LIMIT 1)) - LIMIT 1)) - LIMIT 1))); - -CREATE POLICY "User must be an org member to DELETE" ON "public"."course" FOR DELETE USING ("public"."is_user_in_group_with_role"("group_id")); - -CREATE POLICY "User must be an org member to DELETE" ON "public"."exercise" FOR DELETE USING ("public"."is_user_in_group_with_role"(( SELECT "course"."group_id" - FROM "public"."course" - WHERE ("course"."id" = ( SELECT "lesson"."course_id" - FROM "public"."lesson" - WHERE ("lesson"."id" = "exercise"."lesson_id") - LIMIT 1)) - LIMIT 1))); - -CREATE POLICY "User must be an org member to DELETE" ON "public"."group_attendance" FOR DELETE USING ("public"."is_user_in_group_with_role"(( SELECT "course"."group_id" - FROM "public"."course" - WHERE ("course"."id" = "group_attendance"."course_id") - LIMIT 1))); - -CREATE POLICY "User must be an org member to DELETE" ON "public"."groupmember" FOR DELETE USING ("public"."is_user_in_group_with_role"("group_id")); - -CREATE POLICY "User must be an org member to DELETE" ON "public"."lesson" FOR DELETE USING ("public"."is_user_in_group_with_role"(( SELECT "course"."group_id" - FROM "public"."course" - WHERE ("course"."id" = "lesson"."course_id") - LIMIT 1))); - -CREATE POLICY "User must be an org member to DELETE" ON "public"."lesson_completion" FOR DELETE USING ("public"."is_user_in_group_with_role"(( SELECT "course"."group_id" - FROM "public"."course" - WHERE ("course"."id" = ( SELECT "lesson"."course_id" - FROM "public"."lesson" - WHERE ("lesson"."id" = "lesson_completion"."lesson_id") - LIMIT 1)) - LIMIT 1))); - -CREATE POLICY "User must be an org member to DELETE" ON "public"."lesson_language" FOR DELETE USING ("public"."is_user_in_group_with_role"(( SELECT "course"."group_id" - FROM "public"."course" - WHERE ("course"."id" = ( SELECT "lesson"."course_id" - FROM "public"."lesson" - WHERE ("lesson"."id" = "lesson_language"."lesson_id") - LIMIT 1)) - LIMIT 1))); - -CREATE POLICY "User must be an org member to DELETE" ON "public"."lesson_language_history" FOR DELETE USING ("public"."is_user_in_group_with_role"(( SELECT "course"."group_id" - FROM "public"."course" - WHERE ("course"."id" = ( SELECT "lesson"."course_id" - FROM "public"."lesson" - WHERE ("lesson"."id" = ( SELECT "lesson_language"."lesson_id" - FROM "public"."lesson_language" - WHERE ("lesson_language"."id" = "lesson_language_history"."lesson_language_id"))) - LIMIT 1)) - LIMIT 1))); - -CREATE POLICY "User must be an org member to DELETE" ON "public"."lesson_section" FOR DELETE USING ("public"."is_user_in_group_with_role"(( SELECT "course"."group_id" - FROM "public"."course" - WHERE ("course"."id" = "lesson_section"."course_id") - LIMIT 1))); - -CREATE POLICY "User must be an org member to DELETE" ON "public"."option" FOR DELETE USING ("public"."is_user_in_group_with_role"(( SELECT "course"."group_id" - FROM "public"."course" - WHERE ("course"."id" = ( SELECT "lesson"."course_id" - FROM "public"."lesson" - WHERE ("lesson"."id" = ( SELECT "exercise"."lesson_id" - FROM "public"."exercise" - WHERE ("exercise"."id" = ( SELECT "question"."exercise_id" - FROM "public"."question" - WHERE ("question"."id" = "option"."question_id") - LIMIT 1)) - LIMIT 1)) - LIMIT 1)) - LIMIT 1))); - -CREATE POLICY "User must be an org member to DELETE" ON "public"."organization_plan" FOR DELETE USING ("public"."is_org_member"()); - -CREATE POLICY "User must be an org member to DELETE" ON "public"."question" FOR DELETE USING ("public"."is_user_in_group_with_role"(( SELECT "course"."group_id" - FROM "public"."course" - WHERE ("course"."id" = ( SELECT "lesson"."course_id" - FROM "public"."lesson" - WHERE ("lesson"."id" = ( SELECT "exercise"."lesson_id" - FROM "public"."exercise" - WHERE ("exercise"."id" = "question"."exercise_id"))) - LIMIT 1)) - LIMIT 1))); - -CREATE POLICY "User must be an org member to INSERT" ON "public"."course" FOR INSERT WITH CHECK ("public"."is_user_in_group_with_role"("group_id")); - -CREATE POLICY "User must be an org member to INSERT" ON "public"."exercise" FOR INSERT WITH CHECK ("public"."is_user_in_group_with_role"(( SELECT "course"."group_id" - FROM "public"."course" - WHERE ("course"."id" = ( SELECT "lesson"."course_id" - FROM "public"."lesson" - WHERE ("lesson"."id" = "exercise"."lesson_id") - LIMIT 1)) - LIMIT 1))); - -CREATE POLICY "User must be an org member to INSERT" ON "public"."lesson" FOR INSERT WITH CHECK ("public"."is_user_in_group_with_role"(( SELECT "course"."group_id" - FROM "public"."course" - WHERE ("course"."id" = "lesson"."course_id") - LIMIT 1))); - -CREATE POLICY "User must be an org member to INSERT" ON "public"."lesson_language" FOR INSERT WITH CHECK ("public"."is_user_in_group_with_role"(( SELECT "course"."group_id" - FROM "public"."course" - WHERE ("course"."id" = ( SELECT "lesson"."course_id" - FROM "public"."lesson" - WHERE ("lesson"."id" = "lesson_language"."lesson_id") - LIMIT 1)) - LIMIT 1))); - -CREATE POLICY "User must be an org member to INSERT" ON "public"."lesson_language_history" FOR INSERT WITH CHECK ("public"."is_user_in_group_with_role"(( SELECT "course"."group_id" - FROM "public"."course" - WHERE ("course"."id" = ( SELECT "lesson"."course_id" - FROM "public"."lesson" - WHERE ("lesson"."id" = ( SELECT "lesson_language"."lesson_id" - FROM "public"."lesson_language" - WHERE ("lesson_language"."id" = "lesson_language_history"."lesson_language_id"))) - LIMIT 1)) - LIMIT 1))); - -CREATE POLICY "User must be an org member to INSERT" ON "public"."lesson_section" FOR INSERT WITH CHECK ("public"."is_user_in_group_with_role"(( SELECT "course"."group_id" - FROM "public"."course" - WHERE ("course"."id" = "lesson_section"."course_id") - LIMIT 1))); - -CREATE POLICY "User must be an org member to INSERT" ON "public"."option" FOR INSERT WITH CHECK ("public"."is_user_in_group_with_role"(( SELECT "course"."group_id" - FROM "public"."course" - WHERE ("course"."id" = ( SELECT "lesson"."course_id" - FROM "public"."lesson" - WHERE ("lesson"."id" = ( SELECT "exercise"."lesson_id" - FROM "public"."exercise" - WHERE ("exercise"."id" = ( SELECT "question"."exercise_id" - FROM "public"."question" - WHERE ("question"."id" = "option"."question_id") - LIMIT 1)) - LIMIT 1)) - LIMIT 1)) - LIMIT 1))); - -CREATE POLICY "User must be an org member to INSERT" ON "public"."organization_plan" FOR INSERT WITH CHECK ("public"."is_org_member"()); - -CREATE POLICY "User must be an org member to INSERT" ON "public"."question" FOR INSERT WITH CHECK ("public"."is_user_in_group_with_role"(( SELECT "course"."group_id" - FROM "public"."course" - WHERE ("course"."id" = ( SELECT "lesson"."course_id" - FROM "public"."lesson" - WHERE ("lesson"."id" = ( SELECT "exercise"."lesson_id" - FROM "public"."exercise" - WHERE ("exercise"."id" = "question"."exercise_id"))) - LIMIT 1)) - LIMIT 1))); - -CREATE POLICY "User must be an org member to UPDATE" ON "public"."course" FOR UPDATE USING ("public"."is_user_in_group_with_role"("group_id")) WITH CHECK ("public"."is_user_in_group_with_role"("group_id")); - -CREATE POLICY "User must be an org member to UPDATE" ON "public"."exercise" FOR UPDATE USING ("public"."is_user_in_group_with_role"(( SELECT "course"."group_id" - FROM "public"."course" - WHERE ("course"."id" = ( SELECT "lesson"."course_id" - FROM "public"."lesson" - WHERE ("lesson"."id" = "exercise"."lesson_id") - LIMIT 1)) - LIMIT 1))) WITH CHECK ("public"."is_user_in_group_with_role"(( SELECT "course"."group_id" - FROM "public"."course" - WHERE ("course"."id" = ( SELECT "lesson"."course_id" - FROM "public"."lesson" - WHERE ("lesson"."id" = "exercise"."lesson_id") - LIMIT 1)) - LIMIT 1))); - -CREATE POLICY "User must be an org member to UPDATE" ON "public"."groupmember" FOR UPDATE USING ("public"."is_user_in_group_with_role"("group_id")) WITH CHECK ("public"."is_user_in_group_with_role"("group_id")); - -CREATE POLICY "User must be an org member to UPDATE" ON "public"."lesson" FOR UPDATE USING ("public"."is_user_in_group_with_role"(( SELECT "course"."group_id" - FROM "public"."course" - WHERE ("course"."id" = "lesson"."course_id") - LIMIT 1))) WITH CHECK ("public"."is_user_in_group_with_role"(( SELECT "course"."group_id" - FROM "public"."course" - WHERE ("course"."id" = "lesson"."course_id") - LIMIT 1))); - -CREATE POLICY "User must be an org member to UPDATE" ON "public"."lesson_completion" FOR UPDATE USING ("public"."is_user_in_group_with_role"(( SELECT "course"."group_id" - FROM "public"."course" - WHERE ("course"."id" = ( SELECT "lesson"."course_id" - FROM "public"."lesson" - WHERE ("lesson"."id" = "lesson_completion"."lesson_id") - LIMIT 1)) - LIMIT 1))) WITH CHECK ("public"."is_user_in_group_with_role"(( SELECT "course"."group_id" - FROM "public"."course" - WHERE ("course"."id" = ( SELECT "lesson"."course_id" - FROM "public"."lesson" - WHERE ("lesson"."id" = "lesson_completion"."lesson_id") - LIMIT 1)) - LIMIT 1))); - -CREATE POLICY "User must be an org member to UPDATE" ON "public"."lesson_language" FOR UPDATE USING ("public"."is_user_in_group_with_role"(( SELECT "course"."group_id" - FROM "public"."course" - WHERE ("course"."id" = ( SELECT "lesson"."course_id" - FROM "public"."lesson" - WHERE ("lesson"."id" = "lesson_language"."lesson_id") - LIMIT 1)) - LIMIT 1))) WITH CHECK ("public"."is_user_in_group_with_role"(( SELECT "course"."group_id" - FROM "public"."course" - WHERE ("course"."id" = ( SELECT "lesson"."course_id" - FROM "public"."lesson" - WHERE ("lesson"."id" = "lesson_language"."lesson_id") - LIMIT 1)) - LIMIT 1))); - -CREATE POLICY "User must be an org member to UPDATE" ON "public"."lesson_language_history" FOR UPDATE USING ("public"."is_user_in_group_with_role"(( SELECT "course"."group_id" - FROM "public"."course" - WHERE ("course"."id" = ( SELECT "lesson"."course_id" - FROM "public"."lesson" - WHERE ("lesson"."id" = ( SELECT "lesson_language"."lesson_id" - FROM "public"."lesson_language" - WHERE ("lesson_language"."id" = "lesson_language_history"."lesson_language_id"))) - LIMIT 1)) - LIMIT 1))) WITH CHECK ("public"."is_user_in_group_with_role"(( SELECT "course"."group_id" - FROM "public"."course" - WHERE ("course"."id" = ( SELECT "lesson"."course_id" - FROM "public"."lesson" - WHERE ("lesson"."id" = ( SELECT "lesson_language"."lesson_id" - FROM "public"."lesson_language" - WHERE ("lesson_language"."id" = "lesson_language_history"."lesson_language_id"))) - LIMIT 1)) - LIMIT 1))); - -CREATE POLICY "User must be an org member to UPDATE" ON "public"."lesson_section" FOR UPDATE USING ("public"."is_user_in_group_with_role"(( SELECT "course"."group_id" - FROM "public"."course" - WHERE ("course"."id" = "lesson_section"."course_id") - LIMIT 1))) WITH CHECK ("public"."is_user_in_group_with_role"(( SELECT "course"."group_id" - FROM "public"."course" - WHERE ("course"."id" = "lesson_section"."course_id") - LIMIT 1))); - -CREATE POLICY "User must be an org member to UPDATE" ON "public"."option" FOR UPDATE USING ("public"."is_user_in_group_with_role"(( SELECT "course"."group_id" - FROM "public"."course" - WHERE ("course"."id" = ( SELECT "lesson"."course_id" - FROM "public"."lesson" - WHERE ("lesson"."id" = ( SELECT "exercise"."lesson_id" - FROM "public"."exercise" - WHERE ("exercise"."id" = ( SELECT "question"."exercise_id" - FROM "public"."question" - WHERE ("question"."id" = "option"."question_id") - LIMIT 1)) - LIMIT 1)) - LIMIT 1)) - LIMIT 1))) WITH CHECK ("public"."is_user_in_group_with_role"(( SELECT "course"."group_id" - FROM "public"."course" - WHERE ("course"."id" = ( SELECT "lesson"."course_id" - FROM "public"."lesson" - WHERE ("lesson"."id" = ( SELECT "exercise"."lesson_id" - FROM "public"."exercise" - WHERE ("exercise"."id" = ( SELECT "question"."exercise_id" - FROM "public"."question" - WHERE ("question"."id" = "option"."question_id") - LIMIT 1)) - LIMIT 1)) - LIMIT 1)) - LIMIT 1))); - -CREATE POLICY "User must be an org member to UPDATE" ON "public"."organization_plan" FOR UPDATE USING ("public"."is_org_member"()) WITH CHECK ("public"."is_org_member"()); - -CREATE POLICY "User must be an org member to UPDATE" ON "public"."question" FOR UPDATE USING ("public"."is_user_in_group_with_role"(( SELECT "course"."group_id" - FROM "public"."course" - WHERE ("course"."id" = ( SELECT "lesson"."course_id" - FROM "public"."lesson" - WHERE ("lesson"."id" = ( SELECT "exercise"."lesson_id" - FROM "public"."exercise" - WHERE ("exercise"."id" = "question"."exercise_id"))) - LIMIT 1)) - LIMIT 1))) WITH CHECK ("public"."is_user_in_group_with_role"(( SELECT "course"."group_id" - FROM "public"."course" - WHERE ("course"."id" = ( SELECT "lesson"."course_id" - FROM "public"."lesson" - WHERE ("lesson"."id" = ( SELECT "exercise"."lesson_id" - FROM "public"."exercise" - WHERE ("exercise"."id" = "question"."exercise_id"))) - LIMIT 1)) - LIMIT 1))); - -CREATE POLICY "User must be course member to SELECT" ON "public"."apps_poll" FOR SELECT USING ("public"."is_user_in_course_group"(( SELECT "groupmember"."group_id" - FROM "public"."groupmember" - WHERE ("groupmember"."id" = "apps_poll"."authorId") - LIMIT 1))); - -CREATE POLICY "User must be course member to SELECT" ON "public"."apps_poll_option" FOR SELECT USING ("public"."is_user_in_course_group"(( SELECT "groupmember"."group_id" - FROM "public"."groupmember" - WHERE ("groupmember"."id" = ( SELECT "apps_poll"."authorId" - FROM "public"."apps_poll" - WHERE ("apps_poll"."id" = "apps_poll_option"."poll_id") - LIMIT 1)) - LIMIT 1))); - -CREATE POLICY "User must be in course group to INSERT" ON "public"."lesson_comment" FOR INSERT WITH CHECK ("public"."is_user_in_course_group"(( SELECT "course"."group_id" - FROM "public"."course" - WHERE ("course"."id" = ( SELECT "lesson"."course_id" - FROM "public"."lesson" - WHERE ("lesson"."id" = "lesson_comment"."lesson_id") - LIMIT 1)) - LIMIT 1))); - -CREATE POLICY "Users can insert their own login events" ON "public"."analytics_login_events" FOR INSERT TO "authenticated" WITH CHECK (("auth"."uid"() = "user_id")); - -CREATE POLICY "Users can insert their own profile." ON "public"."profile" FOR INSERT WITH CHECK (("auth"."uid"() = "id")); - -CREATE POLICY "Users can update own profile." ON "public"."profile" FOR UPDATE USING (("auth"."uid"() = "id")); - -ALTER TABLE "public"."analytics_login_events" ENABLE ROW LEVEL SECURITY; - -ALTER TABLE "public"."apps_poll" ENABLE ROW LEVEL SECURITY; - -ALTER TABLE "public"."apps_poll_option" ENABLE ROW LEVEL SECURITY; - -ALTER TABLE "public"."apps_poll_submission" ENABLE ROW LEVEL SECURITY; - -ALTER TABLE "public"."community_answer" ENABLE ROW LEVEL SECURITY; - -ALTER TABLE "public"."community_question" ENABLE ROW LEVEL SECURITY; - -ALTER TABLE "public"."course" ENABLE ROW LEVEL SECURITY; - -ALTER TABLE "public"."course_newsfeed" ENABLE ROW LEVEL SECURITY; - -ALTER TABLE "public"."course_newsfeed_comment" ENABLE ROW LEVEL SECURITY; - -ALTER TABLE "public"."currency" ENABLE ROW LEVEL SECURITY; - -ALTER TABLE "public"."exercise" ENABLE ROW LEVEL SECURITY; - -ALTER TABLE "public"."group" ENABLE ROW LEVEL SECURITY; - -ALTER TABLE "public"."group_attendance" ENABLE ROW LEVEL SECURITY; - -ALTER TABLE "public"."groupmember" ENABLE ROW LEVEL SECURITY; - -ALTER TABLE "public"."lesson" ENABLE ROW LEVEL SECURITY; - -ALTER TABLE "public"."lesson_comment" ENABLE ROW LEVEL SECURITY; - -ALTER TABLE "public"."lesson_completion" ENABLE ROW LEVEL SECURITY; - -ALTER TABLE "public"."lesson_language" ENABLE ROW LEVEL SECURITY; - -ALTER TABLE "public"."lesson_language_history" ENABLE ROW LEVEL SECURITY; - -ALTER TABLE "public"."lesson_section" ENABLE ROW LEVEL SECURITY; - -ALTER TABLE "public"."option" ENABLE ROW LEVEL SECURITY; - -ALTER TABLE "public"."organization" ENABLE ROW LEVEL SECURITY; - -ALTER TABLE "public"."organization_contacts" ENABLE ROW LEVEL SECURITY; - -ALTER TABLE "public"."organization_emaillist" ENABLE ROW LEVEL SECURITY; - -ALTER TABLE "public"."organization_plan" ENABLE ROW LEVEL SECURITY; - -ALTER TABLE "public"."organizationmember" ENABLE ROW LEVEL SECURITY; - -ALTER TABLE "public"."profile" ENABLE ROW LEVEL SECURITY; - -ALTER TABLE "public"."question" ENABLE ROW LEVEL SECURITY; - -ALTER TABLE "public"."question_answer" ENABLE ROW LEVEL SECURITY; - -ALTER TABLE "public"."question_type" ENABLE ROW LEVEL SECURITY; - -ALTER TABLE "public"."quiz" ENABLE ROW LEVEL SECURITY; - -ALTER TABLE "public"."quiz_play" ENABLE ROW LEVEL SECURITY; - -ALTER TABLE "public"."role" ENABLE ROW LEVEL SECURITY; - -ALTER TABLE "public"."submission" ENABLE ROW LEVEL SECURITY; - -ALTER TABLE "public"."submissionstatus" ENABLE ROW LEVEL SECURITY; - -ALTER TABLE "public"."test_tenant" ENABLE ROW LEVEL SECURITY; - -ALTER TABLE "public"."video_transcripts" ENABLE ROW LEVEL SECURITY; - -ALTER TABLE "public"."waitinglist" ENABLE ROW LEVEL SECURITY; - -ALTER PUBLICATION "supabase_realtime" OWNER TO "postgres"; - -REVOKE USAGE ON SCHEMA "public" FROM PUBLIC; -GRANT USAGE ON SCHEMA "public" TO "anon"; -GRANT USAGE ON SCHEMA "public" TO "authenticated"; -GRANT USAGE ON SCHEMA "public" TO "service_role"; -GRANT ALL ON SCHEMA "public" TO PUBLIC; - -GRANT ALL ON FUNCTION "public"."add_them"("a" integer, "b" integer) TO "anon"; -GRANT ALL ON FUNCTION "public"."add_them"("a" integer, "b" integer) TO "authenticated"; -GRANT ALL ON FUNCTION "public"."add_them"("a" integer, "b" integer) TO "service_role"; - -GRANT ALL ON FUNCTION "public"."check_if_student_completed_exercises"("lesson_id_arg" "uuid", "groupmember_id_arg" "uuid") TO "anon"; -GRANT ALL ON FUNCTION "public"."check_if_student_completed_exercises"("lesson_id_arg" "uuid", "groupmember_id_arg" "uuid") TO "authenticated"; -GRANT ALL ON FUNCTION "public"."check_if_student_completed_exercises"("lesson_id_arg" "uuid", "groupmember_id_arg" "uuid") TO "service_role"; - -GRANT ALL ON FUNCTION "public"."convert_course_to_v2"("course_id_arg" "uuid") TO "anon"; -GRANT ALL ON FUNCTION "public"."convert_course_to_v2"("course_id_arg" "uuid") TO "authenticated"; -GRANT ALL ON FUNCTION "public"."convert_course_to_v2"("course_id_arg" "uuid") TO "service_role"; - -GRANT ALL ON FUNCTION "public"."get_course_progress"("course_id_arg" "uuid", "profile_id_arg" "uuid") TO "anon"; -GRANT ALL ON FUNCTION "public"."get_course_progress"("course_id_arg" "uuid", "profile_id_arg" "uuid") TO "authenticated"; -GRANT ALL ON FUNCTION "public"."get_course_progress"("course_id_arg" "uuid", "profile_id_arg" "uuid") TO "service_role"; - -GRANT ALL ON FUNCTION "public"."get_courses"("org_id_arg" "uuid", "profile_id_arg" "uuid") TO "anon"; -GRANT ALL ON FUNCTION "public"."get_courses"("org_id_arg" "uuid", "profile_id_arg" "uuid") TO "authenticated"; -GRANT ALL ON FUNCTION "public"."get_courses"("org_id_arg" "uuid", "profile_id_arg" "uuid") TO "service_role"; - -GRANT ALL ON FUNCTION "public"."get_dash_org_recent_enrollments"("org_id_arg" "uuid") TO "anon"; -GRANT ALL ON FUNCTION "public"."get_dash_org_recent_enrollments"("org_id_arg" "uuid") TO "authenticated"; -GRANT ALL ON FUNCTION "public"."get_dash_org_recent_enrollments"("org_id_arg" "uuid") TO "service_role"; - -GRANT ALL ON FUNCTION "public"."get_dash_org_top_courses"("org_id_arg" "uuid") TO "anon"; -GRANT ALL ON FUNCTION "public"."get_dash_org_top_courses"("org_id_arg" "uuid") TO "authenticated"; -GRANT ALL ON FUNCTION "public"."get_dash_org_top_courses"("org_id_arg" "uuid") TO "service_role"; - -GRANT ALL ON FUNCTION "public"."get_exercises"() TO "anon"; -GRANT ALL ON FUNCTION "public"."get_exercises"() TO "authenticated"; -GRANT ALL ON FUNCTION "public"."get_exercises"() TO "service_role"; - -GRANT ALL ON FUNCTION "public"."get_explore_courses"("org_id_arg" "uuid", "profile_id_arg" "uuid") TO "anon"; -GRANT ALL ON FUNCTION "public"."get_explore_courses"("org_id_arg" "uuid", "profile_id_arg" "uuid") TO "authenticated"; -GRANT ALL ON FUNCTION "public"."get_explore_courses"("org_id_arg" "uuid", "profile_id_arg" "uuid") TO "service_role"; - -GRANT ALL ON FUNCTION "public"."get_marks"() TO "anon"; -GRANT ALL ON FUNCTION "public"."get_marks"() TO "authenticated"; -GRANT ALL ON FUNCTION "public"."get_marks"() TO "service_role"; - -GRANT ALL ON FUNCTION "public"."get_student_exercises"("org_id_arg" "uuid", "profile_id_arg" "uuid") TO "anon"; -GRANT ALL ON FUNCTION "public"."get_student_exercises"("org_id_arg" "uuid", "profile_id_arg" "uuid") TO "authenticated"; -GRANT ALL ON FUNCTION "public"."get_student_exercises"("org_id_arg" "uuid", "profile_id_arg" "uuid") TO "service_role"; - -GRANT ALL ON FUNCTION "public"."get_user_upcoming_lessons"("profile_id_arg" "uuid", "org_id_arg" "uuid") TO "anon"; -GRANT ALL ON FUNCTION "public"."get_user_upcoming_lessons"("profile_id_arg" "uuid", "org_id_arg" "uuid") TO "authenticated"; -GRANT ALL ON FUNCTION "public"."get_user_upcoming_lessons"("profile_id_arg" "uuid", "org_id_arg" "uuid") TO "service_role"; - -GRANT ALL ON FUNCTION "public"."insert_login_event_on_user_login"() TO "anon"; -GRANT ALL ON FUNCTION "public"."insert_login_event_on_user_login"() TO "authenticated"; -GRANT ALL ON FUNCTION "public"."insert_login_event_on_user_login"() TO "service_role"; - -GRANT ALL ON FUNCTION "public"."insert_login_event_on_user_session_update"() TO "anon"; -GRANT ALL ON FUNCTION "public"."insert_login_event_on_user_session_update"() TO "authenticated"; -GRANT ALL ON FUNCTION "public"."insert_login_event_on_user_session_update"() TO "service_role"; - -GRANT ALL ON FUNCTION "public"."is_org_admin"() TO "anon"; -GRANT ALL ON FUNCTION "public"."is_org_admin"() TO "authenticated"; -GRANT ALL ON FUNCTION "public"."is_org_admin"() TO "service_role"; - -GRANT ALL ON FUNCTION "public"."is_org_admin"("org_id" "uuid") TO "anon"; -GRANT ALL ON FUNCTION "public"."is_org_admin"("org_id" "uuid") TO "authenticated"; -GRANT ALL ON FUNCTION "public"."is_org_admin"("org_id" "uuid") TO "service_role"; - -GRANT ALL ON FUNCTION "public"."is_org_member"() TO "anon"; -GRANT ALL ON FUNCTION "public"."is_org_member"() TO "authenticated"; -GRANT ALL ON FUNCTION "public"."is_org_member"() TO "service_role"; - -GRANT ALL ON FUNCTION "public"."is_user_in_course_group"("group_id" "uuid") TO "anon"; -GRANT ALL ON FUNCTION "public"."is_user_in_course_group"("group_id" "uuid") TO "authenticated"; -GRANT ALL ON FUNCTION "public"."is_user_in_course_group"("group_id" "uuid") TO "service_role"; - -GRANT ALL ON FUNCTION "public"."is_user_in_group_with_role"("group_id" integer) TO "anon"; -GRANT ALL ON FUNCTION "public"."is_user_in_group_with_role"("group_id" integer) TO "authenticated"; -GRANT ALL ON FUNCTION "public"."is_user_in_group_with_role"("group_id" integer) TO "service_role"; - -GRANT ALL ON FUNCTION "public"."is_user_in_group_with_role"("group_id" "uuid") TO "anon"; -GRANT ALL ON FUNCTION "public"."is_user_in_group_with_role"("group_id" "uuid") TO "authenticated"; -GRANT ALL ON FUNCTION "public"."is_user_in_group_with_role"("group_id" "uuid") TO "service_role"; - -GRANT ALL ON FUNCTION "public"."update_lesson_language_history"() TO "anon"; -GRANT ALL ON FUNCTION "public"."update_lesson_language_history"() TO "authenticated"; -GRANT ALL ON FUNCTION "public"."update_lesson_language_history"() TO "service_role"; - -GRANT ALL ON TABLE "public"."analytics_login_events" TO "anon"; -GRANT ALL ON TABLE "public"."analytics_login_events" TO "authenticated"; -GRANT ALL ON TABLE "public"."analytics_login_events" TO "service_role"; - -GRANT ALL ON TABLE "public"."apps_poll" TO "anon"; -GRANT ALL ON TABLE "public"."apps_poll" TO "authenticated"; -GRANT ALL ON TABLE "public"."apps_poll" TO "service_role"; - -GRANT ALL ON TABLE "public"."apps_poll_option" TO "anon"; -GRANT ALL ON TABLE "public"."apps_poll_option" TO "authenticated"; -GRANT ALL ON TABLE "public"."apps_poll_option" TO "service_role"; - -GRANT ALL ON SEQUENCE "public"."apps_poll_option_id_seq" TO "anon"; -GRANT ALL ON SEQUENCE "public"."apps_poll_option_id_seq" TO "authenticated"; -GRANT ALL ON SEQUENCE "public"."apps_poll_option_id_seq" TO "service_role"; - -GRANT ALL ON TABLE "public"."apps_poll_submission" TO "anon"; -GRANT ALL ON TABLE "public"."apps_poll_submission" TO "authenticated"; -GRANT ALL ON TABLE "public"."apps_poll_submission" TO "service_role"; - -GRANT ALL ON SEQUENCE "public"."apps_poll_submision_id_seq" TO "anon"; -GRANT ALL ON SEQUENCE "public"."apps_poll_submision_id_seq" TO "authenticated"; -GRANT ALL ON SEQUENCE "public"."apps_poll_submision_id_seq" TO "service_role"; - -GRANT ALL ON TABLE "public"."community_answer" TO "anon"; -GRANT ALL ON TABLE "public"."community_answer" TO "authenticated"; -GRANT ALL ON TABLE "public"."community_answer" TO "service_role"; - -GRANT ALL ON TABLE "public"."community_question" TO "anon"; -GRANT ALL ON TABLE "public"."community_question" TO "authenticated"; -GRANT ALL ON TABLE "public"."community_question" TO "service_role"; - -GRANT ALL ON SEQUENCE "public"."community_question_id_seq" TO "anon"; -GRANT ALL ON SEQUENCE "public"."community_question_id_seq" TO "authenticated"; -GRANT ALL ON SEQUENCE "public"."community_question_id_seq" TO "service_role"; - -GRANT ALL ON TABLE "public"."course" TO "anon"; -GRANT ALL ON TABLE "public"."course" TO "authenticated"; -GRANT ALL ON TABLE "public"."course" TO "service_role"; - -GRANT ALL ON TABLE "public"."course_newsfeed" TO "anon"; -GRANT ALL ON TABLE "public"."course_newsfeed" TO "authenticated"; -GRANT ALL ON TABLE "public"."course_newsfeed" TO "service_role"; - -GRANT ALL ON TABLE "public"."course_newsfeed_comment" TO "anon"; -GRANT ALL ON TABLE "public"."course_newsfeed_comment" TO "authenticated"; -GRANT ALL ON TABLE "public"."course_newsfeed_comment" TO "service_role"; - -GRANT ALL ON SEQUENCE "public"."course_newsfeed_comment_id_seq" TO "anon"; -GRANT ALL ON SEQUENCE "public"."course_newsfeed_comment_id_seq" TO "authenticated"; -GRANT ALL ON SEQUENCE "public"."course_newsfeed_comment_id_seq" TO "service_role"; - -GRANT ALL ON TABLE "public"."currency" TO "anon"; -GRANT ALL ON TABLE "public"."currency" TO "authenticated"; -GRANT ALL ON TABLE "public"."currency" TO "service_role"; - -GRANT ALL ON SEQUENCE "public"."currency_id_seq" TO "anon"; -GRANT ALL ON SEQUENCE "public"."currency_id_seq" TO "authenticated"; -GRANT ALL ON SEQUENCE "public"."currency_id_seq" TO "service_role"; - -GRANT ALL ON TABLE "public"."group" TO "anon"; -GRANT ALL ON TABLE "public"."group" TO "authenticated"; -GRANT ALL ON TABLE "public"."group" TO "service_role"; - -GRANT ALL ON TABLE "public"."groupmember" TO "anon"; -GRANT ALL ON TABLE "public"."groupmember" TO "authenticated"; -GRANT ALL ON TABLE "public"."groupmember" TO "service_role"; - -GRANT ALL ON TABLE "public"."dash_org_stats" TO "anon"; -GRANT ALL ON TABLE "public"."dash_org_stats" TO "authenticated"; -GRANT ALL ON TABLE "public"."dash_org_stats" TO "service_role"; - -GRANT ALL ON TABLE "public"."exercise" TO "anon"; -GRANT ALL ON TABLE "public"."exercise" TO "authenticated"; -GRANT ALL ON TABLE "public"."exercise" TO "service_role"; - -GRANT ALL ON TABLE "public"."group_attendance" TO "anon"; -GRANT ALL ON TABLE "public"."group_attendance" TO "authenticated"; -GRANT ALL ON TABLE "public"."group_attendance" TO "service_role"; - -GRANT ALL ON SEQUENCE "public"."group_attendance_id_seq" TO "anon"; -GRANT ALL ON SEQUENCE "public"."group_attendance_id_seq" TO "authenticated"; -GRANT ALL ON SEQUENCE "public"."group_attendance_id_seq" TO "service_role"; - -GRANT ALL ON TABLE "public"."lesson" TO "anon"; -GRANT ALL ON TABLE "public"."lesson" TO "authenticated"; -GRANT ALL ON TABLE "public"."lesson" TO "service_role"; - -GRANT ALL ON TABLE "public"."lesson_comment" TO "anon"; -GRANT ALL ON TABLE "public"."lesson_comment" TO "authenticated"; -GRANT ALL ON TABLE "public"."lesson_comment" TO "service_role"; - -GRANT ALL ON SEQUENCE "public"."lesson_comment_id_seq" TO "anon"; -GRANT ALL ON SEQUENCE "public"."lesson_comment_id_seq" TO "authenticated"; -GRANT ALL ON SEQUENCE "public"."lesson_comment_id_seq" TO "service_role"; - -GRANT ALL ON TABLE "public"."lesson_completion" TO "anon"; -GRANT ALL ON TABLE "public"."lesson_completion" TO "authenticated"; -GRANT ALL ON TABLE "public"."lesson_completion" TO "service_role"; - -GRANT ALL ON SEQUENCE "public"."lesson_completion_id_seq" TO "anon"; -GRANT ALL ON SEQUENCE "public"."lesson_completion_id_seq" TO "authenticated"; -GRANT ALL ON SEQUENCE "public"."lesson_completion_id_seq" TO "service_role"; - -GRANT ALL ON TABLE "public"."lesson_language" TO "anon"; -GRANT ALL ON TABLE "public"."lesson_language" TO "authenticated"; -GRANT ALL ON TABLE "public"."lesson_language" TO "service_role"; - -GRANT ALL ON TABLE "public"."lesson_language_history" TO "anon"; -GRANT ALL ON TABLE "public"."lesson_language_history" TO "authenticated"; -GRANT ALL ON TABLE "public"."lesson_language_history" TO "service_role"; - -GRANT ALL ON SEQUENCE "public"."lesson_language_history_id_seq" TO "anon"; -GRANT ALL ON SEQUENCE "public"."lesson_language_history_id_seq" TO "authenticated"; -GRANT ALL ON SEQUENCE "public"."lesson_language_history_id_seq" TO "service_role"; - -GRANT ALL ON SEQUENCE "public"."lesson_language_id_seq" TO "anon"; -GRANT ALL ON SEQUENCE "public"."lesson_language_id_seq" TO "authenticated"; -GRANT ALL ON SEQUENCE "public"."lesson_language_id_seq" TO "service_role"; - -GRANT ALL ON TABLE "public"."lesson_section" TO "anon"; -GRANT ALL ON TABLE "public"."lesson_section" TO "authenticated"; -GRANT ALL ON TABLE "public"."lesson_section" TO "service_role"; - -GRANT ALL ON TABLE "public"."lesson_versions" TO "anon"; -GRANT ALL ON TABLE "public"."lesson_versions" TO "authenticated"; -GRANT ALL ON TABLE "public"."lesson_versions" TO "service_role"; - -GRANT ALL ON TABLE "public"."option" TO "anon"; -GRANT ALL ON TABLE "public"."option" TO "authenticated"; -GRANT ALL ON TABLE "public"."option" TO "service_role"; - -GRANT ALL ON SEQUENCE "public"."option_id_seq" TO "anon"; -GRANT ALL ON SEQUENCE "public"."option_id_seq" TO "authenticated"; -GRANT ALL ON SEQUENCE "public"."option_id_seq" TO "service_role"; - -GRANT ALL ON TABLE "public"."organization" TO "anon"; -GRANT ALL ON TABLE "public"."organization" TO "authenticated"; -GRANT ALL ON TABLE "public"."organization" TO "service_role"; - -GRANT ALL ON TABLE "public"."organization_contacts" TO "anon"; -GRANT ALL ON TABLE "public"."organization_contacts" TO "authenticated"; -GRANT ALL ON TABLE "public"."organization_contacts" TO "service_role"; - -GRANT ALL ON SEQUENCE "public"."organization_contacts_id_seq" TO "anon"; -GRANT ALL ON SEQUENCE "public"."organization_contacts_id_seq" TO "authenticated"; -GRANT ALL ON SEQUENCE "public"."organization_contacts_id_seq" TO "service_role"; - -GRANT ALL ON TABLE "public"."organization_emaillist" TO "anon"; -GRANT ALL ON TABLE "public"."organization_emaillist" TO "authenticated"; -GRANT ALL ON TABLE "public"."organization_emaillist" TO "service_role"; - -GRANT ALL ON SEQUENCE "public"."organization_emaillist_id_seq" TO "anon"; -GRANT ALL ON SEQUENCE "public"."organization_emaillist_id_seq" TO "authenticated"; -GRANT ALL ON SEQUENCE "public"."organization_emaillist_id_seq" TO "service_role"; - -GRANT ALL ON TABLE "public"."organization_plan" TO "anon"; -GRANT ALL ON TABLE "public"."organization_plan" TO "authenticated"; -GRANT ALL ON TABLE "public"."organization_plan" TO "service_role"; - -GRANT ALL ON SEQUENCE "public"."organization_plan_id_seq" TO "anon"; -GRANT ALL ON SEQUENCE "public"."organization_plan_id_seq" TO "authenticated"; -GRANT ALL ON SEQUENCE "public"."organization_plan_id_seq" TO "service_role"; - -GRANT ALL ON TABLE "public"."organizationmember" TO "anon"; -GRANT ALL ON TABLE "public"."organizationmember" TO "authenticated"; -GRANT ALL ON TABLE "public"."organizationmember" TO "service_role"; - -GRANT ALL ON SEQUENCE "public"."organizationmember_id_seq" TO "anon"; -GRANT ALL ON SEQUENCE "public"."organizationmember_id_seq" TO "authenticated"; -GRANT ALL ON SEQUENCE "public"."organizationmember_id_seq" TO "service_role"; - -GRANT ALL ON TABLE "public"."quiz_play" TO "anon"; -GRANT ALL ON TABLE "public"."quiz_play" TO "authenticated"; -GRANT ALL ON TABLE "public"."quiz_play" TO "service_role"; - -GRANT ALL ON SEQUENCE "public"."play_quiz_id_seq" TO "anon"; -GRANT ALL ON SEQUENCE "public"."play_quiz_id_seq" TO "authenticated"; -GRANT ALL ON SEQUENCE "public"."play_quiz_id_seq" TO "service_role"; - -GRANT ALL ON TABLE "public"."profile" TO "anon"; -GRANT ALL ON TABLE "public"."profile" TO "authenticated"; -GRANT ALL ON TABLE "public"."profile" TO "service_role"; - -GRANT ALL ON TABLE "public"."question" TO "anon"; -GRANT ALL ON TABLE "public"."question" TO "authenticated"; -GRANT ALL ON TABLE "public"."question" TO "service_role"; - -GRANT ALL ON TABLE "public"."question_answer" TO "anon"; -GRANT ALL ON TABLE "public"."question_answer" TO "authenticated"; -GRANT ALL ON TABLE "public"."question_answer" TO "service_role"; - -GRANT ALL ON SEQUENCE "public"."question_answer_id_seq" TO "anon"; -GRANT ALL ON SEQUENCE "public"."question_answer_id_seq" TO "authenticated"; -GRANT ALL ON SEQUENCE "public"."question_answer_id_seq" TO "service_role"; - -GRANT ALL ON SEQUENCE "public"."question_id_seq" TO "anon"; -GRANT ALL ON SEQUENCE "public"."question_id_seq" TO "authenticated"; -GRANT ALL ON SEQUENCE "public"."question_id_seq" TO "service_role"; - -GRANT ALL ON TABLE "public"."question_type" TO "anon"; -GRANT ALL ON TABLE "public"."question_type" TO "authenticated"; -GRANT ALL ON TABLE "public"."question_type" TO "service_role"; - -GRANT ALL ON SEQUENCE "public"."question_type_id_seq" TO "anon"; -GRANT ALL ON SEQUENCE "public"."question_type_id_seq" TO "authenticated"; -GRANT ALL ON SEQUENCE "public"."question_type_id_seq" TO "service_role"; - -GRANT ALL ON TABLE "public"."quiz" TO "anon"; -GRANT ALL ON TABLE "public"."quiz" TO "authenticated"; -GRANT ALL ON TABLE "public"."quiz" TO "service_role"; - -GRANT ALL ON TABLE "public"."role" TO "anon"; -GRANT ALL ON TABLE "public"."role" TO "authenticated"; -GRANT ALL ON TABLE "public"."role" TO "service_role"; - -GRANT ALL ON SEQUENCE "public"."role_id_seq" TO "anon"; -GRANT ALL ON SEQUENCE "public"."role_id_seq" TO "authenticated"; -GRANT ALL ON SEQUENCE "public"."role_id_seq" TO "service_role"; - -GRANT ALL ON TABLE "public"."submission" TO "anon"; -GRANT ALL ON TABLE "public"."submission" TO "authenticated"; -GRANT ALL ON TABLE "public"."submission" TO "service_role"; - -GRANT ALL ON TABLE "public"."submissionstatus" TO "anon"; -GRANT ALL ON TABLE "public"."submissionstatus" TO "authenticated"; -GRANT ALL ON TABLE "public"."submissionstatus" TO "service_role"; - -GRANT ALL ON SEQUENCE "public"."submission_status_id_seq" TO "anon"; -GRANT ALL ON SEQUENCE "public"."submission_status_id_seq" TO "authenticated"; -GRANT ALL ON SEQUENCE "public"."submission_status_id_seq" TO "service_role"; - -GRANT ALL ON TABLE "public"."test_tenant" TO "anon"; -GRANT ALL ON TABLE "public"."test_tenant" TO "authenticated"; -GRANT ALL ON TABLE "public"."test_tenant" TO "service_role"; - -GRANT ALL ON SEQUENCE "public"."test_tenant_id_seq" TO "anon"; -GRANT ALL ON SEQUENCE "public"."test_tenant_id_seq" TO "authenticated"; -GRANT ALL ON SEQUENCE "public"."test_tenant_id_seq" TO "service_role"; - -GRANT ALL ON TABLE "public"."video_transcripts" TO "anon"; -GRANT ALL ON TABLE "public"."video_transcripts" TO "authenticated"; -GRANT ALL ON TABLE "public"."video_transcripts" TO "service_role"; - -GRANT ALL ON SEQUENCE "public"."video_transcripts_id_seq" TO "anon"; -GRANT ALL ON SEQUENCE "public"."video_transcripts_id_seq" TO "authenticated"; -GRANT ALL ON SEQUENCE "public"."video_transcripts_id_seq" TO "service_role"; - -GRANT ALL ON TABLE "public"."waitinglist" TO "anon"; -GRANT ALL ON TABLE "public"."waitinglist" TO "authenticated"; -GRANT ALL ON TABLE "public"."waitinglist" TO "service_role"; - -GRANT ALL ON SEQUENCE "public"."waitinglist_id_seq" TO "anon"; -GRANT ALL ON SEQUENCE "public"."waitinglist_id_seq" TO "authenticated"; -GRANT ALL ON SEQUENCE "public"."waitinglist_id_seq" TO "service_role"; - -ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON SEQUENCES TO "postgres"; -ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON SEQUENCES TO "anon"; -ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON SEQUENCES TO "authenticated"; -ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON SEQUENCES TO "service_role"; - -ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON FUNCTIONS TO "postgres"; -ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON FUNCTIONS TO "anon"; -ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON FUNCTIONS TO "authenticated"; -ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON FUNCTIONS TO "service_role"; - -ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON TABLES TO "postgres"; -ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON TABLES TO "anon"; -ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON TABLES TO "authenticated"; -ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON TABLES TO "service_role"; - -RESET ALL; - --- --- Dumped schema changes for auth and storage --- - -CREATE OR REPLACE TRIGGER "insert_login_event_on_user_login_trigger" AFTER UPDATE OF "last_sign_in_at" ON "auth"."users" FOR EACH ROW EXECUTE FUNCTION "public"."insert_login_event_on_user_login"(); - -CREATE OR REPLACE TRIGGER "insert_login_event_on_user_session_update_trigger" AFTER UPDATE OF "updated_at" ON "auth"."sessions" FOR EACH ROW EXECUTE FUNCTION "public"."insert_login_event_on_user_session_update"(); - -CREATE POLICY "Anyone can update an avatar. 1oj01fe_0" ON "storage"."objects" FOR SELECT USING (("bucket_id" = 'avatars'::"text")); - -CREATE POLICY "Anyone can update an avatar. 1oj01fe_1" ON "storage"."objects" FOR INSERT WITH CHECK (("bucket_id" = 'avatars'::"text")); - -CREATE POLICY "Avatar images are publicly accessible 1oj01fe_0" ON "storage"."objects" FOR SELECT USING (("bucket_id" = 'avatars'::"text")); - diff --git a/supabase/migrations/20250106020355_polar_setup.sql b/supabase/migrations/20250106020355_polar_setup.sql new file mode 100644 index 00000000..299989df --- /dev/null +++ b/supabase/migrations/20250106020355_polar_setup.sql @@ -0,0 +1,7 @@ +alter table "public"."organization_plan" add column "provider" text default 'lmz'::text; + +alter table "public"."organization_plan" add column "subscription_id" text; + +CREATE UNIQUE INDEX organization_plan_subscription_id_key ON public.organization_plan USING btree (subscription_id); + +alter table "public"."organization_plan" add constraint "organization_plan_subscription_id_key" UNIQUE using index "organization_plan_subscription_id_key"; \ No newline at end of file