feat: setup drizzle (#594)
* chore: migration to SvelteKit 2 * stage 1: migrate to svelte 5 and fix rerendering issues * stage 2: fix more $: reactivity across dashboard * fix merge conflicts * chore: migrate code in main to svelte 5 * chore: update preventDefault * chore: simplify tsconfig and remove unused mobileMenuRef in MobileMenu.svelte * chore: enforce .ts across dashboard * rename from classroomio-com to website * stage-3: Replace carbon icon svelte with lucide icon * update lock file * chore: finish icon replacement * fix: settings and setup page multiple rerender * stage 3: More icon and rerendering fixes * feat: setup drizzle and better auth * fix: onboarding validation error showing translation key #586 (#593) * fix: onboarding validation error showing translation key #586 * fix: remove debug log for profile update errors * chore: add a clean command * fix: remove message from email verification response
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
import 'dotenv/config';
|
||||
|
||||
import { defineConfig } from 'drizzle-kit';
|
||||
|
||||
export default defineConfig({
|
||||
schema: './src/schema.ts',
|
||||
out: './src/migrations',
|
||||
dialect: 'postgresql',
|
||||
dbCredentials: {
|
||||
url: process.env.DATABASE_URL!
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1 @@
|
||||
[]
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "@cio/db",
|
||||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"db": "drizzle-kit",
|
||||
"move-users": "tsx src/scripts/supabase-to-betterauth.ts",
|
||||
"pull": "drizzle-kit pull --config drizzle.config.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@cio/tsconfig": "workspace:*",
|
||||
"better-auth": "^1.3.28",
|
||||
"drizzle-kit": "^0.31.5",
|
||||
"drizzle-orm": "^0.44.6",
|
||||
"pg": "^8.16.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^24.8.1",
|
||||
"@types/pg": "^8.15.5",
|
||||
"dotenv": "^17.2.3",
|
||||
"tsx": "^4.20.3",
|
||||
"typescript": "^5.9.3"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
import { pgTable, text, timestamp, boolean } from "drizzle-orm/pg-core";
|
||||
|
||||
export const user = pgTable("user", {
|
||||
id: text("id").primaryKey(),
|
||||
name: text("name").notNull(),
|
||||
email: text("email").notNull().unique(),
|
||||
emailVerified: boolean("email_verified").default(false).notNull(),
|
||||
image: text("image"),
|
||||
createdAt: timestamp("created_at").defaultNow().notNull(),
|
||||
updatedAt: timestamp("updated_at")
|
||||
.defaultNow()
|
||||
.$onUpdate(() => /* @__PURE__ */ new Date())
|
||||
.notNull(),
|
||||
role: text("role"),
|
||||
banned: boolean("banned").default(false),
|
||||
banReason: text("ban_reason"),
|
||||
banExpires: timestamp("ban_expires"),
|
||||
isAnonymous: boolean("is_anonymous"),
|
||||
});
|
||||
|
||||
export const session = pgTable("session", {
|
||||
id: text("id").primaryKey(),
|
||||
expiresAt: timestamp("expires_at").notNull(),
|
||||
token: text("token").notNull().unique(),
|
||||
createdAt: timestamp("created_at").defaultNow().notNull(),
|
||||
updatedAt: timestamp("updated_at")
|
||||
.$onUpdate(() => /* @__PURE__ */ new Date())
|
||||
.notNull(),
|
||||
ipAddress: text("ip_address"),
|
||||
userAgent: text("user_agent"),
|
||||
userId: text("user_id")
|
||||
.notNull()
|
||||
.references(() => user.id, { onDelete: "cascade" }),
|
||||
impersonatedBy: text("impersonated_by"),
|
||||
});
|
||||
|
||||
export const account = pgTable("account", {
|
||||
id: text("id").primaryKey(),
|
||||
accountId: text("account_id").notNull(),
|
||||
providerId: text("provider_id").notNull(),
|
||||
userId: text("user_id")
|
||||
.notNull()
|
||||
.references(() => user.id, { onDelete: "cascade" }),
|
||||
accessToken: text("access_token"),
|
||||
refreshToken: text("refresh_token"),
|
||||
idToken: text("id_token"),
|
||||
accessTokenExpiresAt: timestamp("access_token_expires_at"),
|
||||
refreshTokenExpiresAt: timestamp("refresh_token_expires_at"),
|
||||
scope: text("scope"),
|
||||
password: text("password"),
|
||||
createdAt: timestamp("created_at").defaultNow().notNull(),
|
||||
updatedAt: timestamp("updated_at")
|
||||
.$onUpdate(() => /* @__PURE__ */ new Date())
|
||||
.notNull(),
|
||||
});
|
||||
|
||||
export const verification = pgTable("verification", {
|
||||
id: text("id").primaryKey(),
|
||||
identifier: text("identifier").notNull(),
|
||||
value: text("value").notNull(),
|
||||
expiresAt: timestamp("expires_at").notNull(),
|
||||
createdAt: timestamp("created_at").defaultNow().notNull(),
|
||||
updatedAt: timestamp("updated_at")
|
||||
.defaultNow()
|
||||
.$onUpdate(() => /* @__PURE__ */ new Date())
|
||||
.notNull(),
|
||||
});
|
||||
@@ -0,0 +1,25 @@
|
||||
import * as schema from '@db/schema';
|
||||
|
||||
import { admin, anonymous } from 'better-auth/plugins';
|
||||
|
||||
import { betterAuth } from 'better-auth';
|
||||
import { db } from '@db/drizzle';
|
||||
import { drizzleAdapter } from 'better-auth/adapters/drizzle';
|
||||
|
||||
export const auth = betterAuth({
|
||||
database: drizzleAdapter(db, {
|
||||
provider: 'pg',
|
||||
schema
|
||||
}),
|
||||
emailVerification: {},
|
||||
emailAndPassword: {
|
||||
enabled: true
|
||||
},
|
||||
socialProviders: {
|
||||
google: {
|
||||
clientId: process.env.GOOGLE_CLIENT_ID!,
|
||||
clientSecret: process.env.GOOGLE_CLIENT_SECRET!
|
||||
}
|
||||
},
|
||||
plugins: [admin(), anonymous()]
|
||||
});
|
||||
@@ -0,0 +1,60 @@
|
||||
import 'dotenv/config';
|
||||
|
||||
import * as schema from './schema';
|
||||
|
||||
import { SQL, sql } from 'drizzle-orm';
|
||||
|
||||
import { drizzle } from 'drizzle-orm/node-postgres';
|
||||
|
||||
const connectionString = process.env.DATABASE_URL ?? process.env.PRIVATE_DATABASE_URL ?? '';
|
||||
|
||||
export const db = drizzle(connectionString, {
|
||||
schema
|
||||
});
|
||||
|
||||
export * from 'drizzle-orm';
|
||||
export * from './schema';
|
||||
|
||||
/**
|
||||
* Creates a SQL expression that returns the length of a JSON array column
|
||||
*
|
||||
* @param column The column containing the JSON array
|
||||
* @returns A SQL expression that can be used in where clauses
|
||||
*/
|
||||
function jsonArrayLength(column: any) {
|
||||
// Create a SQL expression using Drizzle's sql template literal
|
||||
const sqlExpression = sql`jsonb_array_length(${column})`;
|
||||
|
||||
// Return an object with utility methods for comparison operations
|
||||
return {
|
||||
// Check if array length equals a specific value
|
||||
equals: (length: number): SQL<unknown> => {
|
||||
return sql`${sqlExpression} = ${length}`;
|
||||
},
|
||||
// Check if array length is greater than a specific value
|
||||
gt: (length: number): SQL<unknown> => {
|
||||
return sql`${sqlExpression} > ${length}`;
|
||||
},
|
||||
// Check if array length is less than a specific value
|
||||
lt: (length: number): SQL<unknown> => {
|
||||
return sql`${sqlExpression} < ${length}`;
|
||||
},
|
||||
// Check if array length is greater than or equal to a specific value
|
||||
gte: (length: number): SQL<unknown> => {
|
||||
return sql`${sqlExpression} >= ${length}`;
|
||||
},
|
||||
// Check if array length is less than or equal to a specific value
|
||||
lte: (length: number): SQL<unknown> => {
|
||||
return sql`${sqlExpression} <= ${length}`;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const explainAnalyze = async (d: typeof db, query: any) => {
|
||||
console.log(query.sql);
|
||||
const debugResult = await d.execute(sql`EXPLAIN ANALYZE ${query}`);
|
||||
console.debug(debugResult);
|
||||
return query;
|
||||
};
|
||||
|
||||
export { explainAnalyze, jsonArrayLength };
|
||||
@@ -0,0 +1,644 @@
|
||||
-- CREATE TYPE "public"."COURSE_TYPE" AS ENUM('SELF_PACED', 'LIVE_CLASS');--> statement-breakpoint
|
||||
-- CREATE TYPE "public"."COURSE_VERSION" AS ENUM('V1', 'V2');--> statement-breakpoint
|
||||
-- CREATE TYPE "public"."LOCALE" AS ENUM('en', 'hi', 'fr', 'pt', 'de', 'vi', 'ru', 'es', 'pl', 'da');--> statement-breakpoint
|
||||
-- CREATE TYPE "public"."PLAN" AS ENUM('EARLY_ADOPTER', 'ENTERPRISE', 'BASIC');--> statement-breakpoint
|
||||
-- CREATE TABLE "analytics_login_events" (
|
||||
-- "id" uuid PRIMARY KEY DEFAULT uuid_generate_v4() NOT NULL,
|
||||
-- "user_id" uuid NOT NULL,
|
||||
-- "logged_in_at" timestamp with time zone DEFAULT now(),
|
||||
-- CONSTRAINT "analytics_login_events_user_id_unique" UNIQUE("user_id")
|
||||
-- );
|
||||
-- --> statement-breakpoint
|
||||
-- ALTER TABLE "analytics_login_events" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||
-- CREATE TABLE "apps_poll" (
|
||||
-- "id" uuid PRIMARY KEY 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" varchar DEFAULT 'draft',
|
||||
-- "expiration" timestamp with time zone,
|
||||
-- "courseId" uuid
|
||||
-- );
|
||||
-- --> statement-breakpoint
|
||||
-- ALTER TABLE "apps_poll" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||
-- CREATE TABLE "apps_poll_option" (
|
||||
-- "id" bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (sequence name "apps_poll_option_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854776000 START WITH 1 CACHE 1),
|
||||
-- "created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
-- "updated_at" timestamp with time zone,
|
||||
-- "poll_id" uuid,
|
||||
-- "label" varchar
|
||||
-- );
|
||||
-- --> statement-breakpoint
|
||||
-- ALTER TABLE "apps_poll_option" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||
-- CREATE TABLE "apps_poll_submission" (
|
||||
-- "id" bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (sequence name "apps_poll_submision_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854776000 START WITH 1 CACHE 1),
|
||||
-- "created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
-- "poll_option_id" bigint,
|
||||
-- "selected_by_id" uuid,
|
||||
-- "poll_id" uuid
|
||||
-- );
|
||||
-- --> statement-breakpoint
|
||||
-- ALTER TABLE "apps_poll_submission" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||
-- CREATE TABLE "community_answer" (
|
||||
-- "id" uuid PRIMARY KEY DEFAULT extensions.gen_random_uuid() NOT NULL,
|
||||
-- "created_at" timestamp with time zone DEFAULT now(),
|
||||
-- "question_id" bigint,
|
||||
-- "body" varchar,
|
||||
-- "author_id" bigint,
|
||||
-- "votes" bigint,
|
||||
-- "author_profile_id" uuid
|
||||
-- );
|
||||
-- --> statement-breakpoint
|
||||
-- ALTER TABLE "community_answer" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||
-- CREATE TABLE "community_question" (
|
||||
-- "id" bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (sequence name "community_question_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854776000 START WITH 1 CACHE 1),
|
||||
-- "created_at" timestamp with time zone DEFAULT now(),
|
||||
-- "title" varchar,
|
||||
-- "body" text,
|
||||
-- "author_id" bigint,
|
||||
-- "votes" bigint DEFAULT '0',
|
||||
-- "organization_id" uuid,
|
||||
-- "slug" text,
|
||||
-- "author_profile_id" uuid,
|
||||
-- "course_id" uuid NOT NULL
|
||||
-- );
|
||||
-- --> statement-breakpoint
|
||||
-- ALTER TABLE "community_question" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||
-- CREATE TABLE "course" (
|
||||
-- "title" varchar NOT NULL,
|
||||
-- "description" varchar NOT NULL,
|
||||
-- "overview" varchar DEFAULT 'Welcome to this amazing course 🚀 ',
|
||||
-- "id" uuid PRIMARY KEY DEFAULT 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 '' NOT NULL,
|
||||
-- "slug" varchar,
|
||||
-- "metadata" jsonb DEFAULT '{"goals":"","description":"","requirements":""}'::jsonb NOT NULL,
|
||||
-- "cost" bigint DEFAULT '0',
|
||||
-- "currency" varchar DEFAULT 'USD' NOT NULL,
|
||||
-- "banner_image" text,
|
||||
-- "is_published" boolean DEFAULT false,
|
||||
-- "is_certificate_downloadable" boolean DEFAULT false,
|
||||
-- "certificate_theme" text,
|
||||
-- "status" text DEFAULT 'ACTIVE' NOT NULL,
|
||||
-- "type" "COURSE_TYPE" DEFAULT 'LIVE_CLASS',
|
||||
-- "version" "COURSE_VERSION" DEFAULT 'V1' NOT NULL,
|
||||
-- CONSTRAINT "course_slug_key" UNIQUE("slug")
|
||||
-- );
|
||||
-- --> statement-breakpoint
|
||||
-- ALTER TABLE "course" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||
-- CREATE TABLE "course_newsfeed" (
|
||||
-- "created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
-- "author_id" uuid,
|
||||
-- "content" text,
|
||||
-- "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
-- "course_id" uuid,
|
||||
-- "reaction" jsonb DEFAULT '{"clap":[],"smile":[],"thumbsup":[],"thumbsdown":[]}'::jsonb,
|
||||
-- "is_pinned" boolean DEFAULT false NOT NULL
|
||||
-- );
|
||||
-- --> statement-breakpoint
|
||||
-- ALTER TABLE "course_newsfeed" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||
-- CREATE TABLE "course_newsfeed_comment" (
|
||||
-- "created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
-- "author_id" uuid,
|
||||
-- "content" text,
|
||||
-- "id" bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (sequence name "course_newsfeed_comment_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854776000 START WITH 1 CACHE 1),
|
||||
-- "course_newsfeed_id" uuid,
|
||||
-- CONSTRAINT "course_newsfeed_comment_id_key" UNIQUE("id")
|
||||
-- );
|
||||
-- --> statement-breakpoint
|
||||
-- ALTER TABLE "course_newsfeed_comment" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||
-- CREATE TABLE "currency" (
|
||||
-- "id" bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (sequence name "currency_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854776000 START WITH 1 CACHE 1),
|
||||
-- "created_at" timestamp with time zone DEFAULT now(),
|
||||
-- "name" varchar
|
||||
-- );
|
||||
-- --> statement-breakpoint
|
||||
-- CREATE TABLE "exercise" (
|
||||
-- "title" varchar NOT NULL,
|
||||
-- "description" varchar,
|
||||
-- "lesson_id" uuid,
|
||||
-- "created_at" timestamp with time zone DEFAULT now(),
|
||||
-- "updated_at" timestamp with time zone DEFAULT now(),
|
||||
-- "id" uuid PRIMARY KEY DEFAULT uuid_generate_v4() NOT NULL,
|
||||
-- "due_by" timestamp
|
||||
-- );
|
||||
-- --> statement-breakpoint
|
||||
-- ALTER TABLE "exercise" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||
-- CREATE TABLE "group" (
|
||||
-- "id" uuid PRIMARY KEY DEFAULT uuid_generate_v4() NOT NULL,
|
||||
-- "name" varchar NOT NULL,
|
||||
-- "description" text,
|
||||
-- "created_at" timestamp with time zone DEFAULT now(),
|
||||
-- "updated_at" timestamp with time zone DEFAULT now(),
|
||||
-- "organization_id" uuid
|
||||
-- );
|
||||
-- --> statement-breakpoint
|
||||
-- ALTER TABLE "group" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||
-- CREATE TABLE "group_attendance" (
|
||||
-- "id" bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (sequence name "group_attendance_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854776000 START WITH 1 CACHE 1),
|
||||
-- "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
|
||||
-- );
|
||||
-- --> statement-breakpoint
|
||||
-- ALTER TABLE "group_attendance" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||
-- CREATE TABLE "groupmember" (
|
||||
-- "id" uuid PRIMARY KEY DEFAULT uuid_generate_v4() NOT NULL,
|
||||
-- "group_id" uuid NOT NULL,
|
||||
-- "role_id" bigint NOT NULL,
|
||||
-- "profile_id" uuid,
|
||||
-- "email" varchar,
|
||||
-- "created_at" timestamp with time zone DEFAULT now(),
|
||||
-- "assigned_student_id" varchar,
|
||||
-- CONSTRAINT "unique_entries" UNIQUE("group_id","profile_id","email"),
|
||||
-- CONSTRAINT "unique_group_email" UNIQUE("group_id","email"),
|
||||
-- CONSTRAINT "unique_group_profile" UNIQUE("group_id","profile_id")
|
||||
-- );
|
||||
-- --> statement-breakpoint
|
||||
-- ALTER TABLE "groupmember" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||
-- CREATE TABLE "lesson" (
|
||||
-- "note" varchar,
|
||||
-- "video_url" varchar,
|
||||
-- "slide_url" varchar,
|
||||
-- "course_id" uuid NOT NULL,
|
||||
-- "id" uuid PRIMARY KEY DEFAULT uuid_generate_v4() NOT NULL,
|
||||
-- "created_at" timestamp with time zone DEFAULT now(),
|
||||
-- "updated_at" timestamp with time zone DEFAULT now(),
|
||||
-- "title" varchar 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,
|
||||
-- "documents" jsonb DEFAULT '[]'::jsonb
|
||||
-- );
|
||||
-- --> statement-breakpoint
|
||||
-- ALTER TABLE "lesson" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||
-- CREATE TABLE "lesson_comment" (
|
||||
-- "id" bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (sequence name "lesson_comment_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854776000 START WITH 1 CACHE 1),
|
||||
-- "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
|
||||
-- );
|
||||
-- --> statement-breakpoint
|
||||
-- ALTER TABLE "lesson_comment" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||
-- CREATE TABLE "lesson_completion" (
|
||||
-- "id" bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (sequence name "lesson_completion_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854776000 START WITH 1 CACHE 1),
|
||||
-- "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(),
|
||||
-- CONSTRAINT "unique_lesson_profile" UNIQUE("lesson_id","profile_id")
|
||||
-- );
|
||||
-- --> statement-breakpoint
|
||||
-- ALTER TABLE "lesson_completion" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||
-- CREATE TABLE "lesson_language" (
|
||||
-- "id" bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (sequence name "lesson_language_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854776000 START WITH 1 CACHE 1),
|
||||
-- "content" text,
|
||||
-- "lesson_id" uuid DEFAULT gen_random_uuid(),
|
||||
-- "locale" "LOCALE" DEFAULT 'en'
|
||||
-- );
|
||||
-- --> statement-breakpoint
|
||||
-- ALTER TABLE "lesson_language" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||
-- CREATE TABLE "lesson_language_history" (
|
||||
-- "id" serial PRIMARY KEY NOT NULL,
|
||||
-- "lesson_language_id" integer,
|
||||
-- "old_content" text,
|
||||
-- "new_content" text,
|
||||
-- "timestamp" timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL
|
||||
-- );
|
||||
-- --> statement-breakpoint
|
||||
-- ALTER TABLE "lesson_language_history" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||
-- CREATE TABLE "lesson_section" (
|
||||
-- "id" uuid PRIMARY KEY 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" varchar,
|
||||
-- "order" bigint DEFAULT '0',
|
||||
-- "course_id" uuid
|
||||
-- );
|
||||
-- --> statement-breakpoint
|
||||
-- ALTER TABLE "lesson_section" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||
-- CREATE TABLE "option" (
|
||||
-- "id" bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (sequence name "option_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854776000 START WITH 1 CACHE 1),
|
||||
-- "label" varchar 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()
|
||||
-- );
|
||||
-- --> statement-breakpoint
|
||||
-- ALTER TABLE "option" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||
-- CREATE TABLE "organization" (
|
||||
-- "id" uuid PRIMARY KEY DEFAULT uuid_generate_v4() NOT NULL,
|
||||
-- "name" varchar 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,
|
||||
-- CONSTRAINT "organization_siteName_key" UNIQUE("siteName"),
|
||||
-- CONSTRAINT "organization_customDomain_key" UNIQUE("customDomain")
|
||||
-- );
|
||||
-- --> statement-breakpoint
|
||||
-- ALTER TABLE "organization" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||
-- CREATE TABLE "organization_contacts" (
|
||||
-- "id" bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (sequence name "organization_contacts_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854776000 START WITH 1 CACHE 1),
|
||||
-- "created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
-- "email" text,
|
||||
-- "phone" text,
|
||||
-- "name" text,
|
||||
-- "message" text,
|
||||
-- "organization_id" uuid
|
||||
-- );
|
||||
-- --> statement-breakpoint
|
||||
-- ALTER TABLE "organization_contacts" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||
-- CREATE TABLE "organization_emaillist" (
|
||||
-- "id" bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (sequence name "organization_emaillist_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854776000 START WITH 1 CACHE 1),
|
||||
-- "created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
-- "email" text,
|
||||
-- "organization_id" uuid
|
||||
-- );
|
||||
-- --> statement-breakpoint
|
||||
-- ALTER TABLE "organization_emaillist" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||
-- CREATE TABLE "organization_plan" (
|
||||
-- "id" bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (sequence name "organization_plan_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854776000 START WITH 1 CACHE 1),
|
||||
-- "activated_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
-- "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,
|
||||
-- "provider" text DEFAULT 'lmz',
|
||||
-- "subscription_id" text,
|
||||
-- CONSTRAINT "organization_plan_subscription_id_key" UNIQUE("subscription_id")
|
||||
-- );
|
||||
-- --> statement-breakpoint
|
||||
-- ALTER TABLE "organization_plan" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||
-- CREATE TABLE "organizationmember" (
|
||||
-- "id" bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (sequence name "organizationmember_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854776000 START WITH 1 CACHE 1),
|
||||
-- "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
|
||||
-- );
|
||||
-- --> statement-breakpoint
|
||||
-- ALTER TABLE "organizationmember" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||
-- CREATE TABLE "profile" (
|
||||
-- "id" uuid PRIMARY KEY NOT NULL,
|
||||
-- "fullname" text NOT NULL,
|
||||
-- "username" text NOT NULL,
|
||||
-- "avatar_url" text DEFAULT 'https://tapaozmyjsuykgerrfkt.supabase.co/storage/v1/object/public/avatars/avatar.png',
|
||||
-- "created_at" timestamp with time zone DEFAULT now(),
|
||||
-- "updated_at" timestamp with time zone DEFAULT now(),
|
||||
-- "email" varchar,
|
||||
-- "can_add_course" boolean DEFAULT true,
|
||||
-- "role" varchar,
|
||||
-- "goal" varchar,
|
||||
-- "source" varchar,
|
||||
-- "metadata" json,
|
||||
-- "telegram_chat_id" bigint,
|
||||
-- "is_email_verified" boolean DEFAULT false,
|
||||
-- "verified_at" timestamp with time zone,
|
||||
-- "locale" "LOCALE" DEFAULT 'en',
|
||||
-- "is_restricted" boolean DEFAULT false NOT NULL,
|
||||
-- CONSTRAINT "profile_username_key" UNIQUE("username"),
|
||||
-- CONSTRAINT "profile_email_key" UNIQUE("email")
|
||||
-- );
|
||||
-- --> statement-breakpoint
|
||||
-- ALTER TABLE "profile" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||
-- CREATE TABLE "question" (
|
||||
-- "id" bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (sequence name "question_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854776000 START WITH 1 CACHE 1),
|
||||
-- "question_type_id" bigint NOT NULL,
|
||||
-- "title" varchar 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
|
||||
-- );
|
||||
-- --> statement-breakpoint
|
||||
-- ALTER TABLE "question" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||
-- CREATE TABLE "question_answer" (
|
||||
-- "id" bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (sequence name "question_answer_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854776000 START WITH 1 CACHE 1),
|
||||
-- "answers" varchar[],
|
||||
-- "question_id" bigint NOT NULL,
|
||||
-- "open_answer" text,
|
||||
-- "group_member_id" uuid NOT NULL,
|
||||
-- "submission_id" uuid,
|
||||
-- "point" bigint DEFAULT '0'
|
||||
-- );
|
||||
-- --> statement-breakpoint
|
||||
-- ALTER TABLE "question_answer" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||
-- CREATE TABLE "question_type" (
|
||||
-- "id" bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (sequence name "question_type_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854776000 START WITH 1 CACHE 1),
|
||||
-- "label" varchar NOT NULL,
|
||||
-- "created_at" timestamp with time zone DEFAULT now(),
|
||||
-- "updated_at" timestamp with time zone DEFAULT now(),
|
||||
-- "typename" varchar
|
||||
-- );
|
||||
-- --> statement-breakpoint
|
||||
-- ALTER TABLE "question_type" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||
-- CREATE TABLE "quiz" (
|
||||
-- "id" uuid PRIMARY KEY 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" varchar DEFAULT '10s',
|
||||
-- "theme" varchar DEFAULT 'standard',
|
||||
-- "organization_id" uuid NOT NULL
|
||||
-- );
|
||||
-- --> statement-breakpoint
|
||||
-- ALTER TABLE "quiz" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||
-- CREATE TABLE "quiz_play" (
|
||||
-- "id" bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (sequence name "play_quiz_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854776000 START WITH 1 CACHE 1),
|
||||
-- "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',
|
||||
-- "showCurrentQuestionAnswer" boolean DEFAULT false,
|
||||
-- "isLastQuestion" boolean,
|
||||
-- "step" text DEFAULT 'CONNECT_TO_PLAY',
|
||||
-- "studentStep" text DEFAULT 'PIN_SETUP',
|
||||
-- "pin" text,
|
||||
-- CONSTRAINT "quiz_play_pin_key" UNIQUE("pin")
|
||||
-- );
|
||||
-- --> statement-breakpoint
|
||||
-- ALTER TABLE "quiz_play" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||
-- CREATE TABLE "role" (
|
||||
-- "type" varchar NOT NULL,
|
||||
-- "description" varchar,
|
||||
-- "id" bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (sequence name "role_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854776000 START WITH 1 CACHE 1),
|
||||
-- "updated_at" timestamp with time zone DEFAULT now(),
|
||||
-- "created_at" timestamp with time zone DEFAULT now()
|
||||
-- );
|
||||
-- --> statement-breakpoint
|
||||
-- ALTER TABLE "role" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||
-- CREATE TABLE "submission" (
|
||||
-- "id" uuid PRIMARY KEY DEFAULT uuid_generate_v4() NOT NULL,
|
||||
-- "reviewer_id" bigint,
|
||||
-- "status_id" bigint DEFAULT '1',
|
||||
-- "total" bigint DEFAULT '0',
|
||||
-- "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
|
||||
-- );
|
||||
-- --> statement-breakpoint
|
||||
-- ALTER TABLE "submission" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||
-- CREATE TABLE "submissionstatus" (
|
||||
-- "id" bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (sequence name "submission_status_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854776000 START WITH 1 CACHE 1),
|
||||
-- "label" varchar NOT NULL,
|
||||
-- "updated_at" timestamp with time zone DEFAULT now()
|
||||
-- );
|
||||
-- --> statement-breakpoint
|
||||
-- ALTER TABLE "submissionstatus" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||
-- CREATE TABLE "test_tenant" (
|
||||
-- "id" serial PRIMARY KEY NOT NULL,
|
||||
-- "details" text
|
||||
-- );
|
||||
-- --> statement-breakpoint
|
||||
-- CREATE TABLE "video_transcripts" (
|
||||
-- "id" bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (sequence name "video_transcripts_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854776000 START WITH 1 CACHE 1),
|
||||
-- "created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||||
-- "muse_svid" text,
|
||||
-- "transcript" text,
|
||||
-- "downloaded" boolean DEFAULT false,
|
||||
-- "link" text
|
||||
-- );
|
||||
-- --> statement-breakpoint
|
||||
-- CREATE TABLE "waitinglist" (
|
||||
-- "id" bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (sequence name "waitinglist_id_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 9223372036854776000 START WITH 1 CACHE 1),
|
||||
-- "email" varchar NOT NULL,
|
||||
-- "created_at" timestamp with time zone DEFAULT now(),
|
||||
-- CONSTRAINT "constraint_name" UNIQUE("email")
|
||||
-- );
|
||||
-- --> statement-breakpoint
|
||||
-- ALTER TABLE "analytics_login_events" ADD CONSTRAINT "analytics_login_events_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
-- ALTER TABLE "apps_poll" ADD CONSTRAINT "apps_poll_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "public"."groupmember"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
-- ALTER TABLE "apps_poll" ADD CONSTRAINT "apps_poll_courseId_fkey" FOREIGN KEY ("courseId") REFERENCES "public"."course"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
-- ALTER TABLE "apps_poll_option" ADD CONSTRAINT "apps_poll_option_poll_id_fkey" FOREIGN KEY ("poll_id") REFERENCES "public"."apps_poll"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
-- ALTER TABLE "apps_poll_submission" ADD CONSTRAINT "apps_poll_submission_poll_id_fkey" FOREIGN KEY ("poll_id") REFERENCES "public"."apps_poll"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
-- ALTER TABLE "apps_poll_submission" ADD CONSTRAINT "apps_poll_submission_poll_option_id_fkey" FOREIGN KEY ("poll_option_id") REFERENCES "public"."apps_poll_option"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
-- ALTER TABLE "apps_poll_submission" ADD CONSTRAINT "apps_poll_submission_selected_by_id_fkey" FOREIGN KEY ("selected_by_id") REFERENCES "public"."groupmember"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
-- ALTER TABLE "community_answer" ADD CONSTRAINT "community_answer_author_id_fkey" FOREIGN KEY ("author_id") REFERENCES "public"."organizationmember"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
-- ALTER TABLE "community_answer" ADD CONSTRAINT "community_answer_author_profile_id_fkey" FOREIGN KEY ("author_profile_id") REFERENCES "public"."profile"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
-- ALTER TABLE "community_answer" ADD CONSTRAINT "community_answer_question_id_fkey" FOREIGN KEY ("question_id") REFERENCES "public"."community_question"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
-- ALTER TABLE "community_question" ADD CONSTRAINT "community_question_author_id_fkey" FOREIGN KEY ("author_id") REFERENCES "public"."organizationmember"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
-- ALTER TABLE "community_question" ADD CONSTRAINT "community_question_author_profile_id_fkey" FOREIGN KEY ("author_profile_id") REFERENCES "public"."profile"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
-- ALTER TABLE "community_question" ADD CONSTRAINT "community_question_course_id_fkey" FOREIGN KEY ("course_id") REFERENCES "public"."course"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
-- ALTER TABLE "community_question" ADD CONSTRAINT "community_question_organization_id_fkey" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
-- ALTER TABLE "course" ADD CONSTRAINT "course_group_id_fkey" FOREIGN KEY ("group_id") REFERENCES "public"."group"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
-- ALTER TABLE "course_newsfeed" ADD CONSTRAINT "course_newsfeed_author_id_fkey" FOREIGN KEY ("author_id") REFERENCES "public"."groupmember"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
-- ALTER TABLE "course_newsfeed" ADD CONSTRAINT "course_newsfeed_course_id_fkey" FOREIGN KEY ("course_id") REFERENCES "public"."course"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
-- ALTER TABLE "course_newsfeed_comment" ADD CONSTRAINT "course_newsfeed_comment_author_id_fkey" FOREIGN KEY ("author_id") REFERENCES "public"."groupmember"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
-- ALTER TABLE "course_newsfeed_comment" ADD CONSTRAINT "course_newsfeed_comment_course_newsfeed_id_fkey" FOREIGN KEY ("course_newsfeed_id") REFERENCES "public"."course_newsfeed"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
-- ALTER TABLE "exercise" ADD CONSTRAINT "exercise_lesson_id_fkey" FOREIGN KEY ("lesson_id") REFERENCES "public"."lesson"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
-- ALTER TABLE "group" ADD CONSTRAINT "group_organization_id_fkey" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
-- ALTER TABLE "group_attendance" ADD CONSTRAINT "group_attendance_course_id_fkey" FOREIGN KEY ("course_id") REFERENCES "public"."course"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
-- ALTER TABLE "group_attendance" ADD CONSTRAINT "group_attendance_student_id_fkey" FOREIGN KEY ("student_id") REFERENCES "public"."groupmember"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
-- ALTER TABLE "groupmember" ADD CONSTRAINT "groupmember_group_id_fkey" FOREIGN KEY ("group_id") REFERENCES "public"."group"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
-- ALTER TABLE "groupmember" ADD CONSTRAINT "groupmember_profile_id_fkey" FOREIGN KEY ("profile_id") REFERENCES "public"."profile"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
-- ALTER TABLE "groupmember" ADD CONSTRAINT "groupmember_role_id_fkey" FOREIGN KEY ("role_id") REFERENCES "public"."role"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
-- ALTER TABLE "lesson" ADD CONSTRAINT "lesson_course_id_fkey" FOREIGN KEY ("course_id") REFERENCES "public"."course"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
-- ALTER TABLE "lesson" ADD CONSTRAINT "lesson_teacher_id_fkey" FOREIGN KEY ("teacher_id") REFERENCES "public"."profile"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
-- ALTER TABLE "lesson" ADD CONSTRAINT "public_lesson_section_id_fkey" FOREIGN KEY ("section_id") REFERENCES "public"."lesson_section"("id") ON DELETE cascade ON UPDATE cascade;--> statement-breakpoint
|
||||
-- ALTER TABLE "lesson_comment" ADD CONSTRAINT "lesson_comment_groupmember_id_fkey" FOREIGN KEY ("groupmember_id") REFERENCES "public"."groupmember"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
-- ALTER TABLE "lesson_comment" ADD CONSTRAINT "lesson_comment_lesson_id_fkey" FOREIGN KEY ("lesson_id") REFERENCES "public"."lesson"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
-- ALTER TABLE "lesson_completion" ADD CONSTRAINT "lesson_completion_lesson_id_fkey" FOREIGN KEY ("lesson_id") REFERENCES "public"."lesson"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
-- ALTER TABLE "lesson_completion" ADD CONSTRAINT "lesson_completion_profile_id_fkey" FOREIGN KEY ("profile_id") REFERENCES "public"."profile"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
-- ALTER TABLE "lesson_language" ADD CONSTRAINT "public_lesson_language_lesson_id_fkey" FOREIGN KEY ("lesson_id") REFERENCES "public"."lesson"("id") ON DELETE cascade ON UPDATE cascade;--> statement-breakpoint
|
||||
-- ALTER TABLE "lesson_language_history" ADD CONSTRAINT "public_lesson_language_history_lesson_language_id_fkey" FOREIGN KEY ("lesson_language_id") REFERENCES "public"."lesson_language"("id") ON DELETE cascade ON UPDATE cascade;--> statement-breakpoint
|
||||
-- ALTER TABLE "lesson_section" ADD CONSTRAINT "public_lesson_section_course_id_fkey" FOREIGN KEY ("course_id") REFERENCES "public"."course"("id") ON DELETE cascade ON UPDATE cascade;--> statement-breakpoint
|
||||
-- ALTER TABLE "option" ADD CONSTRAINT "option_question_id_fkey" FOREIGN KEY ("question_id") REFERENCES "public"."question"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
-- ALTER TABLE "organization_contacts" ADD CONSTRAINT "organization_contacts_organization_id_fkey" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
-- ALTER TABLE "organization_emaillist" ADD CONSTRAINT "organization_emaillist_organization_id_fkey" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
-- ALTER TABLE "organization_plan" ADD CONSTRAINT "organization_plan_org_id_fkey" FOREIGN KEY ("org_id") REFERENCES "public"."organization"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
-- ALTER TABLE "organization_plan" ADD CONSTRAINT "organization_plan_triggered_by_fkey" FOREIGN KEY ("triggered_by") REFERENCES "public"."organizationmember"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
-- ALTER TABLE "organizationmember" ADD CONSTRAINT "organizationmember_organization_id_fkey" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
-- ALTER TABLE "organizationmember" ADD CONSTRAINT "organizationmember_profile_id_fkey" FOREIGN KEY ("profile_id") REFERENCES "public"."profile"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
-- ALTER TABLE "organizationmember" ADD CONSTRAINT "organizationmember_role_id_fkey" FOREIGN KEY ("role_id") REFERENCES "public"."role"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
-- ALTER TABLE "profile" ADD CONSTRAINT "profile_id_fkey" FOREIGN KEY ("id") REFERENCES "public"."user"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
-- ALTER TABLE "question" ADD CONSTRAINT "question_exercise_id_fkey" FOREIGN KEY ("exercise_id") REFERENCES "public"."exercise"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
-- ALTER TABLE "question" ADD CONSTRAINT "question_question_type_id_fkey" FOREIGN KEY ("question_type_id") REFERENCES "public"."question_type"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
-- ALTER TABLE "question_answer" ADD CONSTRAINT "question_answer_group_member_id_fkey" FOREIGN KEY ("group_member_id") REFERENCES "public"."groupmember"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
-- ALTER TABLE "question_answer" ADD CONSTRAINT "question_answer_question_id_fkey" FOREIGN KEY ("question_id") REFERENCES "public"."question"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
-- ALTER TABLE "question_answer" ADD CONSTRAINT "question_answer_submission_id_fkey" FOREIGN KEY ("submission_id") REFERENCES "public"."submission"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
-- ALTER TABLE "quiz" ADD CONSTRAINT "quiz_organization_id_fkey" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
-- ALTER TABLE "quiz_play" ADD CONSTRAINT "quiz_play_quiz_id_fkey" FOREIGN KEY ("quiz_id") REFERENCES "public"."quiz"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
-- ALTER TABLE "submission" ADD CONSTRAINT "submission_course_id_fkey" FOREIGN KEY ("course_id") REFERENCES "public"."course"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
-- ALTER TABLE "submission" ADD CONSTRAINT "submission_exercise_id_fkey" FOREIGN KEY ("exercise_id") REFERENCES "public"."exercise"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
-- ALTER TABLE "submission" ADD CONSTRAINT "submission_status_id_fkey" FOREIGN KEY ("status_id") REFERENCES "public"."submissionstatus"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
-- ALTER TABLE "submission" ADD CONSTRAINT "submission_submitted_by_fkey" FOREIGN KEY ("submitted_by") REFERENCES "public"."groupmember"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint
|
||||
-- CREATE INDEX "idx_analytics_login_events_logged_in_at" ON "analytics_login_events" USING btree ("logged_in_at" timestamptz_ops);--> statement-breakpoint
|
||||
-- CREATE INDEX "idx_analytics_login_events_user_id" ON "analytics_login_events" USING btree ("user_id" uuid_ops);--> statement-breakpoint
|
||||
-- CREATE 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);--> statement-breakpoint
|
||||
-- CREATE 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);--> statement-breakpoint
|
||||
-- CREATE POLICY "Enable delete for users based on user_id" ON "analytics_login_events" AS PERMISSIVE FOR DELETE TO public USING ((auth.uid() = user_id));--> statement-breakpoint
|
||||
-- CREATE POLICY "Users can insert their own login events" ON "analytics_login_events" AS PERMISSIVE FOR INSERT TO "authenticated";--> statement-breakpoint
|
||||
-- CREATE POLICY "Delete only your own poll" ON "apps_poll" AS PERMISSIVE FOR DELETE TO public USING ((auth.uid() = ( SELECT groupmember.profile_id
|
||||
-- FROM groupmember
|
||||
-- WHERE (groupmember.id = apps_poll."authorId"))));--> statement-breakpoint
|
||||
-- CREATE POLICY "Update only your own" ON "apps_poll" AS PERMISSIVE FOR UPDATE TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be a course member to INSERT" ON "apps_poll" AS PERMISSIVE FOR INSERT TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be course member to SELECT" ON "apps_poll" AS PERMISSIVE FOR SELECT TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be a course member to INSERT" ON "apps_poll_option" AS PERMISSIVE FOR INSERT TO public WITH CHECK (is_user_in_course_group_or_admin(( 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)));--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be a course member to UPDATE" ON "apps_poll_option" AS PERMISSIVE FOR UPDATE TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be a teacher to DELETE" ON "apps_poll_option" AS PERMISSIVE FOR DELETE TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be course member to SELECT" ON "apps_poll_option" AS PERMISSIVE FOR SELECT TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "Authenticated users can read" ON "apps_poll_submission" AS PERMISSIVE FOR SELECT TO public USING ((auth.uid() IS NOT NULL));--> statement-breakpoint
|
||||
-- CREATE POLICY "Delete your own submission" ON "apps_poll_submission" AS PERMISSIVE FOR DELETE TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "Enable insert for authenticated users only" ON "apps_poll_submission" AS PERMISSIVE FOR INSERT TO "authenticated";--> statement-breakpoint
|
||||
-- CREATE POLICY "Update your own submission" ON "apps_poll_submission" AS PERMISSIVE FOR UPDATE TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "Authenticated users can SELECT" ON "community_answer" AS PERMISSIVE FOR SELECT TO public USING ((auth.uid() IS NOT NULL));--> statement-breakpoint
|
||||
-- CREATE POLICY "Delete your own answer" ON "community_answer" AS PERMISSIVE FOR DELETE TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "Enable insert for authenticated users only" ON "community_answer" AS PERMISSIVE FOR INSERT TO "authenticated";--> statement-breakpoint
|
||||
-- CREATE POLICY "Update your own answer" ON "community_answer" AS PERMISSIVE FOR UPDATE TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "Authenticated users can SELECT" ON "community_question" AS PERMISSIVE FOR SELECT TO public USING ((auth.uid() IS NOT NULL));--> statement-breakpoint
|
||||
-- CREATE POLICY "Delete your own question" ON "community_question" AS PERMISSIVE FOR DELETE TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "Enable insert for authenticated users only" ON "community_question" AS PERMISSIVE FOR INSERT TO "authenticated";--> statement-breakpoint
|
||||
-- CREATE POLICY "Update your own question" ON "community_question" AS PERMISSIVE FOR UPDATE TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "Enable access to all users if PUBLIC or to course members when " ON "course" AS PERMISSIVE FOR SELECT TO public USING ((is_published OR is_user_in_course_group_or_admin(group_id)));--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be an org member to DELETE" ON "course" AS PERMISSIVE FOR DELETE TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be an org member to INSERT" ON "course" AS PERMISSIVE FOR INSERT TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be an org member to UPDATE" ON "course" AS PERMISSIVE FOR UPDATE TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "Delete your own comment" ON "course_newsfeed" AS PERMISSIVE FOR DELETE TO public USING ((auth.uid() = ( SELECT groupmember.profile_id
|
||||
-- FROM groupmember
|
||||
-- WHERE (groupmember.id = course_newsfeed.author_id))));--> statement-breakpoint
|
||||
-- CREATE POLICY "Update only your own" ON "course_newsfeed" AS PERMISSIVE FOR UPDATE TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be a course member to INSERT" ON "course_newsfeed" AS PERMISSIVE FOR INSERT TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be a course member to SELECT" ON "course_newsfeed" AS PERMISSIVE FOR SELECT TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "Delete your own" ON "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))));--> statement-breakpoint
|
||||
-- CREATE POLICY "Update only your own" ON "course_newsfeed_comment" AS PERMISSIVE FOR UPDATE TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be a course member to INSERT" ON "course_newsfeed_comment" AS PERMISSIVE FOR INSERT TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be a course member to SELECT" ON "course_newsfeed_comment" AS PERMISSIVE FOR SELECT TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "Enable read access for all users" ON "exercise" AS PERMISSIVE FOR SELECT TO public USING (true);--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be an org member to DELETE" ON "exercise" AS PERMISSIVE FOR DELETE TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be an org member to INSERT" ON "exercise" AS PERMISSIVE FOR INSERT TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be an org member to UPDATE" ON "exercise" AS PERMISSIVE FOR UPDATE TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "Enable insert for authenticated users only" ON "group" AS PERMISSIVE FOR INSERT TO "authenticated" WITH CHECK (true);--> statement-breakpoint
|
||||
-- CREATE POLICY "Enable read access for all users" ON "group" AS PERMISSIVE FOR SELECT TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "Only org admins can delete" ON "group" AS PERMISSIVE FOR DELETE TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "Only org admins can update" ON "group" AS PERMISSIVE FOR UPDATE TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be a course member to INSERT" ON "group_attendance" AS PERMISSIVE FOR INSERT TO public WITH CHECK (is_user_in_course_group_or_admin(( SELECT course.group_id
|
||||
-- FROM course
|
||||
-- WHERE (course.id = group_attendance.course_id)
|
||||
-- LIMIT 1)));--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be a course member to SELECT" ON "group_attendance" AS PERMISSIVE FOR SELECT TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be a course member to UPDATE" ON "group_attendance" AS PERMISSIVE FOR UPDATE TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be an org member to DELETE" ON "group_attendance" AS PERMISSIVE FOR DELETE TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "Enable insert for authenticated users only" ON "groupmember" AS PERMISSIVE FOR INSERT TO "authenticated" WITH CHECK (true);--> statement-breakpoint
|
||||
-- CREATE POLICY "Enable read access for all users" ON "groupmember" AS PERMISSIVE FOR SELECT TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be an org member to DELETE" ON "groupmember" AS PERMISSIVE FOR DELETE TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be an org member to UPDATE" ON "groupmember" AS PERMISSIVE FOR UPDATE TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "Enable read access for all users" ON "lesson" AS PERMISSIVE FOR SELECT TO public USING (true);--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be an org member to DELETE" ON "lesson" AS PERMISSIVE FOR DELETE TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be an org member to INSERT" ON "lesson" AS PERMISSIVE FOR INSERT TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be an org member to UPDATE" ON "lesson" AS PERMISSIVE FOR UPDATE TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "Delete only your own comment" ON "lesson_comment" AS PERMISSIVE FOR DELETE TO public USING ((auth.uid() = ( SELECT groupmember.profile_id
|
||||
-- FROM groupmember
|
||||
-- WHERE (groupmember.id = lesson_comment.groupmember_id))));--> statement-breakpoint
|
||||
-- CREATE POLICY "Enable read access for all users" ON "lesson_comment" AS PERMISSIVE FOR SELECT TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "Update only your own" ON "lesson_comment" AS PERMISSIVE FOR UPDATE TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be in course group to INSERT" ON "lesson_comment" AS PERMISSIVE FOR INSERT TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "Enable read access for all users" ON "lesson_completion" AS PERMISSIVE FOR SELECT TO public USING (true);--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be an course member or Admin to perform ALL operation" ON "lesson_completion" AS PERMISSIVE FOR ALL TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be an org member to DELETE" ON "lesson_completion" AS PERMISSIVE FOR DELETE TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be an org member to UPDATE" ON "lesson_completion" AS PERMISSIVE FOR UPDATE TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "Enable read access for all users" ON "lesson_language" AS PERMISSIVE FOR SELECT TO public USING (true);--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be an org member to DELETE" ON "lesson_language" AS PERMISSIVE FOR DELETE TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be an org member to INSERT" ON "lesson_language" AS PERMISSIVE FOR INSERT TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be an org member to UPDATE" ON "lesson_language" AS PERMISSIVE FOR UPDATE TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "Authenticated users can SELECT" ON "lesson_language_history" AS PERMISSIVE FOR SELECT TO public USING ((auth.uid() IS NOT NULL));--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be an org member to DELETE" ON "lesson_language_history" AS PERMISSIVE FOR DELETE TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be an org member to INSERT" ON "lesson_language_history" AS PERMISSIVE FOR INSERT TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be an org member to UPDATE" ON "lesson_language_history" AS PERMISSIVE FOR UPDATE TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "Enable read access for all users" ON "lesson_section" AS PERMISSIVE FOR SELECT TO public USING (true);--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be an org member to DELETE" ON "lesson_section" AS PERMISSIVE FOR DELETE TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be an org member to INSERT" ON "lesson_section" AS PERMISSIVE FOR INSERT TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be an org member to UPDATE" ON "lesson_section" AS PERMISSIVE FOR UPDATE TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "Allow authenticated users to SELECT" ON "option" AS PERMISSIVE FOR SELECT TO public USING ((auth.uid() IS NOT NULL));--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be an org member to DELETE" ON "option" AS PERMISSIVE FOR DELETE TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be an org member to INSERT" ON "option" AS PERMISSIVE FOR INSERT TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be an org member to UPDATE" ON "option" AS PERMISSIVE FOR UPDATE TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "Authenticated users can delete" ON "organization" AS PERMISSIVE FOR DELETE TO public USING ((auth.uid() IS NOT NULL));--> statement-breakpoint
|
||||
-- CREATE POLICY "Enable insert for authenticated users only" ON "organization" AS PERMISSIVE FOR INSERT TO "authenticated";--> statement-breakpoint
|
||||
-- CREATE POLICY "Enable read access for all users" ON "organization" AS PERMISSIVE FOR SELECT TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be admin to UPDATE" ON "organization" AS PERMISSIVE FOR UPDATE TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "Enable read access for all users" ON "organization_contacts" AS PERMISSIVE FOR INSERT TO public WITH CHECK (true);--> statement-breakpoint
|
||||
-- CREATE POLICY "Enable read access for all users" ON "organization_emaillist" AS PERMISSIVE FOR INSERT TO public WITH CHECK (true);--> statement-breakpoint
|
||||
-- CREATE POLICY "Enable read access for all users" ON "organization_plan" AS PERMISSIVE FOR SELECT TO public USING (true);--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be an org member to DELETE" ON "organization_plan" AS PERMISSIVE FOR DELETE TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be an org member to INSERT" ON "organization_plan" AS PERMISSIVE FOR INSERT TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be an org member to UPDATE" ON "organization_plan" AS PERMISSIVE FOR UPDATE TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "Allow authenticated users to read." ON "organizationmember" AS PERMISSIVE FOR SELECT TO public USING ((auth.uid() IS NOT NULL));--> statement-breakpoint
|
||||
-- CREATE POLICY "Enable insert for authenticated users only" ON "organizationmember" AS PERMISSIVE FOR INSERT TO "authenticated";--> statement-breakpoint
|
||||
-- CREATE POLICY "Only admin can delete" ON "organizationmember" AS PERMISSIVE FOR DELETE TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "Only admin can update" ON "organizationmember" AS PERMISSIVE FOR UPDATE TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "Only user can update their account via email" ON "organizationmember" AS PERMISSIVE FOR UPDATE TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be an admin to INSERT or allow if no existing member" ON "organizationmember" AS PERMISSIVE FOR INSERT TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "Only auth users can read profile" ON "profile" AS PERMISSIVE FOR SELECT TO "anon", "authenticated" USING (true);--> statement-breakpoint
|
||||
-- CREATE POLICY "Public profiles are viewable by everyone." ON "profile" AS PERMISSIVE FOR SELECT TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "User can only delete their profiles" ON "profile" AS PERMISSIVE FOR DELETE TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "Users can insert their own profile." ON "profile" AS PERMISSIVE FOR INSERT TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "Users can update own profile." ON "profile" AS PERMISSIVE FOR UPDATE TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "Allow authenticated users to SELECT" ON "question" AS PERMISSIVE FOR SELECT TO public USING ((auth.uid() IS NOT NULL));--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be an org member to DELETE" ON "question" AS PERMISSIVE FOR DELETE TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be an org member to INSERT" ON "question" AS PERMISSIVE FOR INSERT TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be an org member to UPDATE" ON "question" AS PERMISSIVE FOR UPDATE TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "Only authenticated users can select." ON "question_answer" AS PERMISSIVE FOR SELECT TO public USING ((auth.uid() IS NOT NULL));--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be an course member to DELETE" ON "question_answer" AS PERMISSIVE FOR DELETE TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be an course member to INSERT" ON "question_answer" AS PERMISSIVE FOR INSERT TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be an course member to UPDATE" ON "question_answer" AS PERMISSIVE FOR UPDATE TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "Enable read access for all users" ON "question_type" AS PERMISSIVE FOR SELECT TO public USING (true);--> statement-breakpoint
|
||||
-- CREATE POLICY "Authenticated users can SELECT" ON "quiz" AS PERMISSIVE FOR SELECT TO "authenticated" USING (true);--> statement-breakpoint
|
||||
-- CREATE POLICY "Authenticated users can SELECT" ON "quiz_play" AS PERMISSIVE FOR SELECT TO "authenticated" USING (true);--> statement-breakpoint
|
||||
-- CREATE POLICY "Enable read access for all users" ON "role" AS PERMISSIVE FOR SELECT TO public USING (true);--> statement-breakpoint
|
||||
-- CREATE POLICY "Only authenticated users can SELECT" ON "submission" AS PERMISSIVE FOR SELECT TO "authenticated" USING (true);--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be a course member to DELETE" ON "submission" AS PERMISSIVE FOR DELETE TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be a course member to INSERT" ON "submission" AS PERMISSIVE FOR INSERT TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "User must be a course member to UPDATE" ON "submission" AS PERMISSIVE FOR UPDATE TO public;--> statement-breakpoint
|
||||
-- CREATE POLICY "Authenticated users can SELECT" ON "submissionstatus" AS PERMISSIVE FOR SELECT TO "authenticated" USING (true);
|
||||
|
||||
select id from public.profile limit 1;
|
||||
@@ -0,0 +1,47 @@
|
||||
CREATE TABLE "account" (
|
||||
"id" text PRIMARY KEY NOT NULL,
|
||||
"account_id" text NOT NULL,
|
||||
"provider_id" text NOT NULL,
|
||||
"user_id" text NOT NULL,
|
||||
"access_token" text,
|
||||
"refresh_token" text,
|
||||
"id_token" text,
|
||||
"access_token_expires_at" timestamp,
|
||||
"refresh_token_expires_at" timestamp,
|
||||
"scope" text,
|
||||
"password" text,
|
||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "session" (
|
||||
"id" text PRIMARY KEY NOT NULL,
|
||||
"expires_at" timestamp NOT NULL,
|
||||
"token" text NOT NULL,
|
||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp NOT NULL,
|
||||
"ip_address" text,
|
||||
"user_agent" text,
|
||||
"user_id" text NOT NULL,
|
||||
"impersonated_by" text,
|
||||
CONSTRAINT "session_token_unique" UNIQUE("token")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "user" (
|
||||
"id" text PRIMARY KEY NOT NULL,
|
||||
"name" text NOT NULL,
|
||||
"email" text NOT NULL,
|
||||
"email_verified" boolean DEFAULT false NOT NULL,
|
||||
"image" text,
|
||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp DEFAULT now() NOT NULL,
|
||||
"role" text,
|
||||
"banned" boolean DEFAULT false,
|
||||
"ban_reason" text,
|
||||
"ban_expires" timestamp,
|
||||
"is_anonymous" boolean,
|
||||
CONSTRAINT "user_email_unique" UNIQUE("email")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "account" ADD CONSTRAINT "account_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "session" ADD CONSTRAINT "session_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"version": "7",
|
||||
"dialect": "postgresql",
|
||||
"entries": [
|
||||
{
|
||||
"idx": 0,
|
||||
"version": "7",
|
||||
"when": 1760910273722,
|
||||
"tag": "0000_stale_storm",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 1,
|
||||
"version": "7",
|
||||
"when": 1760912065001,
|
||||
"tag": "0001_tranquil_thunderbolts",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,424 @@
|
||||
import {
|
||||
analyticsLoginEvents,
|
||||
appsPoll,
|
||||
appsPollOption,
|
||||
appsPollSubmission,
|
||||
communityAnswer,
|
||||
communityQuestion,
|
||||
course,
|
||||
courseNewsfeed,
|
||||
courseNewsfeedComment,
|
||||
exercise,
|
||||
group,
|
||||
groupAttendance,
|
||||
groupmember,
|
||||
lesson,
|
||||
lessonComment,
|
||||
lessonCompletion,
|
||||
lessonLanguage,
|
||||
lessonLanguageHistory,
|
||||
lessonSection,
|
||||
option,
|
||||
organization,
|
||||
organizationContacts,
|
||||
organizationEmaillist,
|
||||
organizationPlan,
|
||||
organizationmember,
|
||||
profile,
|
||||
question,
|
||||
questionAnswer,
|
||||
questionType,
|
||||
quiz,
|
||||
quizPlay,
|
||||
role,
|
||||
submission,
|
||||
submissionstatus
|
||||
} from './schema';
|
||||
|
||||
import { relations } from 'drizzle-orm/relations';
|
||||
import { user } from './auth-schema';
|
||||
|
||||
export const analyticsLoginEventsRelations = relations(analyticsLoginEvents, ({ one }) => ({
|
||||
usersInAuth: one(user, {
|
||||
fields: [analyticsLoginEvents.userId],
|
||||
references: [user.id]
|
||||
})
|
||||
}));
|
||||
|
||||
export const usersInAuthRelations = relations(user, ({ many }) => ({
|
||||
analyticsLoginEvents: many(analyticsLoginEvents),
|
||||
profiles: many(profile)
|
||||
}));
|
||||
|
||||
export const lessonSectionRelations = relations(lessonSection, ({ one, many }) => ({
|
||||
course: one(course, {
|
||||
fields: [lessonSection.courseId],
|
||||
references: [course.id]
|
||||
}),
|
||||
lessons: many(lesson)
|
||||
}));
|
||||
|
||||
export const courseRelations = relations(course, ({ one, many }) => ({
|
||||
lessonSections: many(lessonSection),
|
||||
groupAttendances: many(groupAttendance),
|
||||
submissions: many(submission),
|
||||
group: one(group, {
|
||||
fields: [course.groupId],
|
||||
references: [group.id]
|
||||
}),
|
||||
appsPolls: many(appsPoll),
|
||||
lessons: many(lesson),
|
||||
communityQuestions: many(communityQuestion),
|
||||
courseNewsfeeds: many(courseNewsfeed)
|
||||
}));
|
||||
|
||||
export const groupRelations = relations(group, ({ one, many }) => ({
|
||||
organization: one(organization, {
|
||||
fields: [group.organizationId],
|
||||
references: [organization.id]
|
||||
}),
|
||||
courses: many(course),
|
||||
groupmembers: many(groupmember)
|
||||
}));
|
||||
|
||||
export const organizationRelations = relations(organization, ({ many }) => ({
|
||||
groups: many(group),
|
||||
organizationContacts: many(organizationContacts),
|
||||
quizzes: many(quiz),
|
||||
organizationEmaillists: many(organizationEmaillist),
|
||||
communityQuestions: many(communityQuestion),
|
||||
organizationPlans: many(organizationPlan),
|
||||
organizationmembers: many(organizationmember)
|
||||
}));
|
||||
|
||||
export const groupAttendanceRelations = relations(groupAttendance, ({ one }) => ({
|
||||
course: one(course, {
|
||||
fields: [groupAttendance.courseId],
|
||||
references: [course.id]
|
||||
}),
|
||||
groupmember: one(groupmember, {
|
||||
fields: [groupAttendance.studentId],
|
||||
references: [groupmember.id]
|
||||
})
|
||||
}));
|
||||
|
||||
export const groupmemberRelations = relations(groupmember, ({ one, many }) => ({
|
||||
groupAttendances: many(groupAttendance),
|
||||
lessonComments: many(lessonComment),
|
||||
submissions: many(submission),
|
||||
appsPolls: many(appsPoll),
|
||||
appsPollSubmissions: many(appsPollSubmission),
|
||||
group: one(group, {
|
||||
fields: [groupmember.groupId],
|
||||
references: [group.id]
|
||||
}),
|
||||
profile: one(profile, {
|
||||
fields: [groupmember.profileId],
|
||||
references: [profile.id]
|
||||
}),
|
||||
role: one(role, {
|
||||
fields: [groupmember.roleId],
|
||||
references: [role.id]
|
||||
}),
|
||||
courseNewsfeeds: many(courseNewsfeed),
|
||||
courseNewsfeedComments: many(courseNewsfeedComment),
|
||||
questionAnswers: many(questionAnswer)
|
||||
}));
|
||||
|
||||
export const appsPollOptionRelations = relations(appsPollOption, ({ one, many }) => ({
|
||||
appsPoll: one(appsPoll, {
|
||||
fields: [appsPollOption.pollId],
|
||||
references: [appsPoll.id]
|
||||
}),
|
||||
appsPollSubmissions: many(appsPollSubmission)
|
||||
}));
|
||||
|
||||
export const appsPollRelations = relations(appsPoll, ({ one, many }) => ({
|
||||
appsPollOptions: many(appsPollOption),
|
||||
groupmember: one(groupmember, {
|
||||
fields: [appsPoll.authorId],
|
||||
references: [groupmember.id]
|
||||
}),
|
||||
course: one(course, {
|
||||
fields: [appsPoll.courseId],
|
||||
references: [course.id]
|
||||
}),
|
||||
appsPollSubmissions: many(appsPollSubmission)
|
||||
}));
|
||||
|
||||
export const profileRelations = relations(profile, ({ one, many }) => ({
|
||||
usersInAuth: one(user, {
|
||||
fields: [profile.id],
|
||||
references: [user.id]
|
||||
}),
|
||||
lessons: many(lesson),
|
||||
groupmembers: many(groupmember),
|
||||
lessonCompletions: many(lessonCompletion),
|
||||
communityAnswers: many(communityAnswer),
|
||||
communityQuestions: many(communityQuestion),
|
||||
organizationmembers: many(organizationmember)
|
||||
}));
|
||||
|
||||
export const optionRelations = relations(option, ({ one }) => ({
|
||||
question: one(question, {
|
||||
fields: [option.questionId],
|
||||
references: [question.id]
|
||||
})
|
||||
}));
|
||||
|
||||
export const questionRelations = relations(question, ({ one, many }) => ({
|
||||
options: many(option),
|
||||
exercise: one(exercise, {
|
||||
fields: [question.exerciseId],
|
||||
references: [exercise.id]
|
||||
}),
|
||||
questionType: one(questionType, {
|
||||
fields: [question.questionTypeId],
|
||||
references: [questionType.id]
|
||||
}),
|
||||
questionAnswers: many(questionAnswer)
|
||||
}));
|
||||
|
||||
export const quizPlayRelations = relations(quizPlay, ({ one }) => ({
|
||||
quiz: one(quiz, {
|
||||
fields: [quizPlay.quizId],
|
||||
references: [quiz.id]
|
||||
})
|
||||
}));
|
||||
|
||||
export const quizRelations = relations(quiz, ({ one, many }) => ({
|
||||
quizPlays: many(quizPlay),
|
||||
organization: one(organization, {
|
||||
fields: [quiz.organizationId],
|
||||
references: [organization.id]
|
||||
})
|
||||
}));
|
||||
|
||||
export const organizationContactsRelations = relations(organizationContacts, ({ one }) => ({
|
||||
organization: one(organization, {
|
||||
fields: [organizationContacts.organizationId],
|
||||
references: [organization.id]
|
||||
})
|
||||
}));
|
||||
|
||||
export const lessonCommentRelations = relations(lessonComment, ({ one }) => ({
|
||||
groupmember: one(groupmember, {
|
||||
fields: [lessonComment.groupmemberId],
|
||||
references: [groupmember.id]
|
||||
}),
|
||||
lesson: one(lesson, {
|
||||
fields: [lessonComment.lessonId],
|
||||
references: [lesson.id]
|
||||
})
|
||||
}));
|
||||
|
||||
export const lessonRelations = relations(lesson, ({ one, many }) => ({
|
||||
lessonComments: many(lessonComment),
|
||||
course: one(course, {
|
||||
fields: [lesson.courseId],
|
||||
references: [course.id]
|
||||
}),
|
||||
profile: one(profile, {
|
||||
fields: [lesson.teacherId],
|
||||
references: [profile.id]
|
||||
}),
|
||||
lessonSection: one(lessonSection, {
|
||||
fields: [lesson.sectionId],
|
||||
references: [lessonSection.id]
|
||||
}),
|
||||
exercises: many(exercise),
|
||||
lessonCompletions: many(lessonCompletion),
|
||||
lessonLanguages: many(lessonLanguage)
|
||||
}));
|
||||
|
||||
export const submissionRelations = relations(submission, ({ one, many }) => ({
|
||||
course: one(course, {
|
||||
fields: [submission.courseId],
|
||||
references: [course.id]
|
||||
}),
|
||||
exercise: one(exercise, {
|
||||
fields: [submission.exerciseId],
|
||||
references: [exercise.id]
|
||||
}),
|
||||
submissionstatus: one(submissionstatus, {
|
||||
fields: [submission.statusId],
|
||||
references: [submissionstatus.id]
|
||||
}),
|
||||
groupmember: one(groupmember, {
|
||||
fields: [submission.submittedBy],
|
||||
references: [groupmember.id]
|
||||
}),
|
||||
questionAnswers: many(questionAnswer)
|
||||
}));
|
||||
|
||||
export const exerciseRelations = relations(exercise, ({ one, many }) => ({
|
||||
submissions: many(submission),
|
||||
lesson: one(lesson, {
|
||||
fields: [exercise.lessonId],
|
||||
references: [lesson.id]
|
||||
}),
|
||||
questions: many(question)
|
||||
}));
|
||||
|
||||
export const submissionstatusRelations = relations(submissionstatus, ({ many }) => ({
|
||||
submissions: many(submission)
|
||||
}));
|
||||
|
||||
export const organizationEmaillistRelations = relations(organizationEmaillist, ({ one }) => ({
|
||||
organization: one(organization, {
|
||||
fields: [organizationEmaillist.organizationId],
|
||||
references: [organization.id]
|
||||
})
|
||||
}));
|
||||
|
||||
export const appsPollSubmissionRelations = relations(appsPollSubmission, ({ one }) => ({
|
||||
appsPoll: one(appsPoll, {
|
||||
fields: [appsPollSubmission.pollId],
|
||||
references: [appsPoll.id]
|
||||
}),
|
||||
appsPollOption: one(appsPollOption, {
|
||||
fields: [appsPollSubmission.pollOptionId],
|
||||
references: [appsPollOption.id]
|
||||
}),
|
||||
groupmember: one(groupmember, {
|
||||
fields: [appsPollSubmission.selectedById],
|
||||
references: [groupmember.id]
|
||||
})
|
||||
}));
|
||||
|
||||
export const roleRelations = relations(role, ({ many }) => ({
|
||||
groupmembers: many(groupmember),
|
||||
organizationmembers: many(organizationmember)
|
||||
}));
|
||||
|
||||
export const lessonCompletionRelations = relations(lessonCompletion, ({ one }) => ({
|
||||
lesson: one(lesson, {
|
||||
fields: [lessonCompletion.lessonId],
|
||||
references: [lesson.id]
|
||||
}),
|
||||
profile: one(profile, {
|
||||
fields: [lessonCompletion.profileId],
|
||||
references: [profile.id]
|
||||
})
|
||||
}));
|
||||
|
||||
export const communityAnswerRelations = relations(communityAnswer, ({ one }) => ({
|
||||
organizationmember: one(organizationmember, {
|
||||
fields: [communityAnswer.authorId],
|
||||
references: [organizationmember.id]
|
||||
}),
|
||||
profile: one(profile, {
|
||||
fields: [communityAnswer.authorProfileId],
|
||||
references: [profile.id]
|
||||
}),
|
||||
communityQuestion: one(communityQuestion, {
|
||||
fields: [communityAnswer.questionId],
|
||||
references: [communityQuestion.id]
|
||||
})
|
||||
}));
|
||||
|
||||
export const organizationmemberRelations = relations(organizationmember, ({ one, many }) => ({
|
||||
communityAnswers: many(communityAnswer),
|
||||
communityQuestions: many(communityQuestion),
|
||||
organizationPlans: many(organizationPlan),
|
||||
organization: one(organization, {
|
||||
fields: [organizationmember.organizationId],
|
||||
references: [organization.id]
|
||||
}),
|
||||
profile: one(profile, {
|
||||
fields: [organizationmember.profileId],
|
||||
references: [profile.id]
|
||||
}),
|
||||
role: one(role, {
|
||||
fields: [organizationmember.roleId],
|
||||
references: [role.id]
|
||||
})
|
||||
}));
|
||||
|
||||
export const communityQuestionRelations = relations(communityQuestion, ({ one, many }) => ({
|
||||
communityAnswers: many(communityAnswer),
|
||||
organizationmember: one(organizationmember, {
|
||||
fields: [communityQuestion.authorId],
|
||||
references: [organizationmember.id]
|
||||
}),
|
||||
profile: one(profile, {
|
||||
fields: [communityQuestion.authorProfileId],
|
||||
references: [profile.id]
|
||||
}),
|
||||
course: one(course, {
|
||||
fields: [communityQuestion.courseId],
|
||||
references: [course.id]
|
||||
}),
|
||||
organization: one(organization, {
|
||||
fields: [communityQuestion.organizationId],
|
||||
references: [organization.id]
|
||||
})
|
||||
}));
|
||||
|
||||
export const courseNewsfeedRelations = relations(courseNewsfeed, ({ one, many }) => ({
|
||||
groupmember: one(groupmember, {
|
||||
fields: [courseNewsfeed.authorId],
|
||||
references: [groupmember.id]
|
||||
}),
|
||||
course: one(course, {
|
||||
fields: [courseNewsfeed.courseId],
|
||||
references: [course.id]
|
||||
}),
|
||||
courseNewsfeedComments: many(courseNewsfeedComment)
|
||||
}));
|
||||
|
||||
export const courseNewsfeedCommentRelations = relations(courseNewsfeedComment, ({ one }) => ({
|
||||
groupmember: one(groupmember, {
|
||||
fields: [courseNewsfeedComment.authorId],
|
||||
references: [groupmember.id]
|
||||
}),
|
||||
courseNewsfeed: one(courseNewsfeed, {
|
||||
fields: [courseNewsfeedComment.courseNewsfeedId],
|
||||
references: [courseNewsfeed.id]
|
||||
})
|
||||
}));
|
||||
|
||||
export const organizationPlanRelations = relations(organizationPlan, ({ one }) => ({
|
||||
organization: one(organization, {
|
||||
fields: [organizationPlan.orgId],
|
||||
references: [organization.id]
|
||||
}),
|
||||
organizationmember: one(organizationmember, {
|
||||
fields: [organizationPlan.triggeredBy],
|
||||
references: [organizationmember.id]
|
||||
})
|
||||
}));
|
||||
|
||||
export const lessonLanguageRelations = relations(lessonLanguage, ({ one, many }) => ({
|
||||
lesson: one(lesson, {
|
||||
fields: [lessonLanguage.lessonId],
|
||||
references: [lesson.id]
|
||||
}),
|
||||
lessonLanguageHistories: many(lessonLanguageHistory)
|
||||
}));
|
||||
|
||||
export const lessonLanguageHistoryRelations = relations(lessonLanguageHistory, ({ one }) => ({
|
||||
lessonLanguage: one(lessonLanguage, {
|
||||
fields: [lessonLanguageHistory.lessonLanguageId],
|
||||
references: [lessonLanguage.id]
|
||||
})
|
||||
}));
|
||||
|
||||
export const questionTypeRelations = relations(questionType, ({ many }) => ({
|
||||
questions: many(question)
|
||||
}));
|
||||
|
||||
export const questionAnswerRelations = relations(questionAnswer, ({ one }) => ({
|
||||
groupmember: one(groupmember, {
|
||||
fields: [questionAnswer.groupMemberId],
|
||||
references: [groupmember.id]
|
||||
}),
|
||||
question: one(question, {
|
||||
fields: [questionAnswer.questionId],
|
||||
references: [question.id]
|
||||
}),
|
||||
submission: one(submission, {
|
||||
fields: [questionAnswer.submissionId],
|
||||
references: [submission.id]
|
||||
})
|
||||
}));
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,173 @@
|
||||
import 'dotenv/config';
|
||||
|
||||
import { admin, anonymous } from 'better-auth/plugins';
|
||||
|
||||
import { Pool } from 'pg';
|
||||
import { User as SupabaseUser } from '@supabase/supabase-js';
|
||||
import { betterAuth } from 'better-auth';
|
||||
|
||||
// We create a custom betterAuth here because this code works well with pg
|
||||
const auth = betterAuth({
|
||||
database: new Pool({
|
||||
connectionString: process.env.DATABASE_URL
|
||||
}),
|
||||
emailVerification: {},
|
||||
emailAndPassword: {
|
||||
enabled: true
|
||||
},
|
||||
|
||||
socialProviders: {
|
||||
google: {
|
||||
clientId: process.env.GOOGLE_CLIENT_ID!,
|
||||
clientSecret: process.env.GOOGLE_CLIENT_SECRET!
|
||||
}
|
||||
},
|
||||
plugins: [admin(), anonymous()],
|
||||
|
||||
user: {
|
||||
modelName: 'user',
|
||||
fields: {
|
||||
emailVerified: 'email_verified',
|
||||
createdAt: 'created_at',
|
||||
updatedAt: 'updated_at'
|
||||
}
|
||||
},
|
||||
account: {
|
||||
modelName: 'account',
|
||||
fields: {
|
||||
userId: 'user_id',
|
||||
createdAt: 'created_at',
|
||||
updatedAt: 'updated_at',
|
||||
accountId: 'account_id',
|
||||
providerId: 'provider_id'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
type User = SupabaseUser & {
|
||||
is_super_admin: boolean;
|
||||
raw_user_meta_data: {
|
||||
avatar_url: string;
|
||||
};
|
||||
encrypted_password: string;
|
||||
email_confirmed_at: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
is_anonymous: boolean;
|
||||
profile_fullname: string;
|
||||
identities: {
|
||||
provider: string;
|
||||
identity_data: {
|
||||
sub: string;
|
||||
email: string;
|
||||
};
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
};
|
||||
};
|
||||
|
||||
const migrateFromSupabase = async () => {
|
||||
const ctx = await auth.$context;
|
||||
const db = ctx.options.database as Pool;
|
||||
const users = await db
|
||||
.query(
|
||||
`
|
||||
SELECT
|
||||
u.*,
|
||||
COALESCE(
|
||||
json_agg(
|
||||
i.* ORDER BY i.id
|
||||
) FILTER (WHERE i.id IS NOT NULL),
|
||||
'[]'::json
|
||||
) as identities,
|
||||
p.fullname as profile_fullname -- Select fullname from public.profile
|
||||
FROM auth.users u
|
||||
LEFT JOIN auth.identities i ON u.id = i.user_id
|
||||
LEFT JOIN public.profile p ON u.id = p.id -- LEFT JOIN with public.profile
|
||||
GROUP BY u.id, p.fullname
|
||||
`
|
||||
)
|
||||
.then((res) => res.rows as User[]);
|
||||
|
||||
console.log('users length', users.length);
|
||||
|
||||
for (const user of users) {
|
||||
if (!user.email) {
|
||||
continue;
|
||||
}
|
||||
const userName = user.profile_fullname || user.email;
|
||||
console.log('inserting user', user.email);
|
||||
|
||||
let shouldContinue = false;
|
||||
await ctx.adapter
|
||||
.create({
|
||||
model: 'user',
|
||||
forceAllowId: true,
|
||||
data: {
|
||||
id: user.id,
|
||||
email: user.email,
|
||||
name: userName,
|
||||
role: user.is_super_admin ? 'admin' : user.role,
|
||||
emailVerified: !!user.email_confirmed_at,
|
||||
image: user.raw_user_meta_data?.avatar_url || '',
|
||||
createdAt: new Date(user.created_at),
|
||||
updatedAt: new Date(user.updated_at)
|
||||
}
|
||||
})
|
||||
.catch((e) => {
|
||||
console.log('catch');
|
||||
shouldContinue = true;
|
||||
});
|
||||
|
||||
if (shouldContinue) {
|
||||
console.log('Continue');
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const identity of user.identities) {
|
||||
const existingAccounts = await ctx.internalAdapter.findAccounts(user.id);
|
||||
|
||||
if (identity.provider === 'email') {
|
||||
console.log('email provider', identity);
|
||||
const hasCredential = existingAccounts.find((account) => account.providerId === 'credential');
|
||||
console.log('hasCredential', hasCredential);
|
||||
if (!hasCredential) {
|
||||
console.log('doesnt have credentials');
|
||||
await ctx.adapter
|
||||
.create({
|
||||
model: 'account',
|
||||
data: {
|
||||
userId: user.id,
|
||||
providerId: 'credential',
|
||||
accountId: user.id,
|
||||
password: user.encrypted_password,
|
||||
createdAt: new Date(user.created_at),
|
||||
updatedAt: new Date(user.updated_at)
|
||||
}
|
||||
})
|
||||
.catch((e) => {
|
||||
console.log('catch error', e);
|
||||
});
|
||||
}
|
||||
}
|
||||
const supportedProviders = Object.keys(ctx.options.socialProviders || {});
|
||||
if (supportedProviders.includes(identity.provider)) {
|
||||
const hasAccount = existingAccounts.find((account) => account.providerId === identity.provider);
|
||||
if (!hasAccount) {
|
||||
await ctx.adapter.create({
|
||||
model: 'account',
|
||||
data: {
|
||||
userId: user.id,
|
||||
providerId: identity.provider,
|
||||
accountId: identity.identity_data?.sub,
|
||||
createdAt: new Date(identity.created_at ?? user.created_at),
|
||||
updatedAt: new Date(identity.updated_at ?? user.updated_at)
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
migrateFromSupabase();
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"extends": "@cio/tsconfig/base.json",
|
||||
"include": ["src"],
|
||||
"exclude": ["node_modules"],
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@db/*": ["./src/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,155 @@
|
||||
[
|
||||
{
|
||||
"instance_id": "00000000-0000-0000-0000-000000000000",
|
||||
"id": "01676a50-bb56-4c5e-8a61-fb9e9190fb10",
|
||||
"aud": "authenticated",
|
||||
"role": "authenticated",
|
||||
"email": "[email protected]",
|
||||
"encrypted_password": "$2a$10$WmfPO84h.8SbkZWSzXAygead77QQQXdeO5XIMd8iXk8SFQKB3Udy2",
|
||||
"email_confirmed_at": "2023-11-22T10:09:32.250Z",
|
||||
"invited_at": null,
|
||||
"confirmation_token": "",
|
||||
"confirmation_sent_at": null,
|
||||
"recovery_token": "",
|
||||
"recovery_sent_at": null,
|
||||
"email_change_token_new": "",
|
||||
"email_change": "",
|
||||
"email_change_sent_at": null,
|
||||
"last_sign_in_at": "2023-12-04T12:57:34.337Z",
|
||||
"raw_app_meta_data": { "provider": "email", "providers": ["email"] },
|
||||
"raw_user_meta_data": {},
|
||||
"is_super_admin": null,
|
||||
"created_at": "2023-11-22T10:09:32.171Z",
|
||||
"updated_at": "2023-12-16T14:00:35.986Z",
|
||||
"phone": null,
|
||||
"phone_confirmed_at": null,
|
||||
"phone_change": "",
|
||||
"phone_change_token": "",
|
||||
"phone_change_sent_at": null,
|
||||
"confirmed_at": "2023-11-22T10:09:32.250Z",
|
||||
"email_change_token_current": "",
|
||||
"email_change_confirm_status": 0,
|
||||
"banned_until": null,
|
||||
"reauthentication_token": "",
|
||||
"reauthentication_sent_at": null,
|
||||
"is_sso_user": false,
|
||||
"deleted_at": null,
|
||||
"is_anonymous": false,
|
||||
"identities": [
|
||||
{
|
||||
"provider_id": "01676a50-bb56-4c5e-8a61-fb9e9190fb10",
|
||||
"user_id": "01676a50-bb56-4c5e-8a61-fb9e9190fb10",
|
||||
"identity_data": { "sub": "01676a50-bb56-4c5e-8a61-fb9e9190fb10", "email": "[email protected]" },
|
||||
"provider": "email",
|
||||
"last_sign_in_at": "2023-11-22T10:09:32.225444+00:00",
|
||||
"created_at": "2023-11-22T10:09:32.225521+00:00",
|
||||
"updated_at": "2023-11-22T10:09:32.225521+00:00",
|
||||
"email": "[email protected]",
|
||||
"id": "a8961fe8-d51f-4b58-b8bb-a77d6a3c0cbd"
|
||||
}
|
||||
],
|
||||
"profile_fullname": "Alice"
|
||||
},
|
||||
{
|
||||
"instance_id": "00000000-0000-0000-0000-000000000000",
|
||||
"id": "0c256e75-aa40-4f62-8d30-0217ca1c60d9",
|
||||
"aud": "authenticated",
|
||||
"role": "authenticated",
|
||||
"email": "[email protected]",
|
||||
"encrypted_password": "$2a$10$dgxySj.k12gDKhLx7X4x6./J.Nzhz7WQrwh5lkjLKwIwWW4o5GJcW",
|
||||
"email_confirmed_at": "2023-12-18T17:08:57.413Z",
|
||||
"invited_at": null,
|
||||
"confirmation_token": "",
|
||||
"confirmation_sent_at": null,
|
||||
"recovery_token": "",
|
||||
"recovery_sent_at": null,
|
||||
"email_change_token_new": "",
|
||||
"email_change": "",
|
||||
"email_change_sent_at": null,
|
||||
"last_sign_in_at": "2023-12-19T18:22:55.359Z",
|
||||
"raw_app_meta_data": { "provider": "email", "providers": ["email"] },
|
||||
"raw_user_meta_data": {},
|
||||
"is_super_admin": null,
|
||||
"created_at": "2023-12-18T17:08:57.399Z",
|
||||
"updated_at": "2024-01-22T19:48:40.922Z",
|
||||
"phone": null,
|
||||
"phone_confirmed_at": null,
|
||||
"phone_change": "",
|
||||
"phone_change_token": "",
|
||||
"phone_change_sent_at": null,
|
||||
"confirmed_at": "2023-12-18T17:08:57.413Z",
|
||||
"email_change_token_current": "",
|
||||
"email_change_confirm_status": 0,
|
||||
"banned_until": null,
|
||||
"reauthentication_token": "",
|
||||
"reauthentication_sent_at": null,
|
||||
"is_sso_user": false,
|
||||
"deleted_at": null,
|
||||
"is_anonymous": false,
|
||||
"identities": [
|
||||
{
|
||||
"provider_id": "0c256e75-aa40-4f62-8d30-0217ca1c60d9",
|
||||
"user_id": "0c256e75-aa40-4f62-8d30-0217ca1c60d9",
|
||||
"identity_data": { "sub": "0c256e75-aa40-4f62-8d30-0217ca1c60d9", "email": "[email protected]" },
|
||||
"provider": "email",
|
||||
"last_sign_in_at": "2023-12-18T17:08:57.410285+00:00",
|
||||
"created_at": "2023-12-18T17:08:57.410344+00:00",
|
||||
"updated_at": "2023-12-18T17:08:57.410344+00:00",
|
||||
"email": "[email protected]",
|
||||
"id": "65fa8bad-ca49-4676-8b17-ead4cd37fed6"
|
||||
}
|
||||
],
|
||||
"profile_fullname": "John Doe"
|
||||
},
|
||||
{
|
||||
"instance_id": "00000000-0000-0000-0000-000000000000",
|
||||
"id": "7ac00503-8519-43c8-a5ea-b79aeca900b1",
|
||||
"aud": "authenticated",
|
||||
"role": "authenticated",
|
||||
"email": "[email protected]",
|
||||
"encrypted_password": "$2a$10$n8vBI6.pyE0W/RO9DcJDseLKF/CRwsU4X4Lc2MaQogt8pQgnJavTa",
|
||||
"email_confirmed_at": "2023-12-16T14:04:38.311Z",
|
||||
"invited_at": null,
|
||||
"confirmation_token": "",
|
||||
"confirmation_sent_at": null,
|
||||
"recovery_token": "",
|
||||
"recovery_sent_at": null,
|
||||
"email_change_token_new": "",
|
||||
"email_change": "",
|
||||
"email_change_sent_at": null,
|
||||
"last_sign_in_at": "2025-10-12T19:35:13.256Z",
|
||||
"raw_app_meta_data": { "provider": "email", "providers": ["email"] },
|
||||
"raw_user_meta_data": {},
|
||||
"is_super_admin": null,
|
||||
"created_at": "2023-12-16T14:04:38.281Z",
|
||||
"updated_at": "2025-10-15T09:45:29.267Z",
|
||||
"phone": null,
|
||||
"phone_confirmed_at": null,
|
||||
"phone_change": "",
|
||||
"phone_change_token": "",
|
||||
"phone_change_sent_at": null,
|
||||
"confirmed_at": "2023-12-16T14:04:38.311Z",
|
||||
"email_change_token_current": "",
|
||||
"email_change_confirm_status": 0,
|
||||
"banned_until": null,
|
||||
"reauthentication_token": "",
|
||||
"reauthentication_sent_at": null,
|
||||
"is_sso_user": false,
|
||||
"deleted_at": null,
|
||||
"is_anonymous": false,
|
||||
"identities": [
|
||||
{
|
||||
"provider_id": "7ac00503-8519-43c8-a5ea-b79aeca900b1",
|
||||
"user_id": "7ac00503-8519-43c8-a5ea-b79aeca900b1",
|
||||
"identity_data": { "sub": "7ac00503-8519-43c8-a5ea-b79aeca900b1", "email": "[email protected]" },
|
||||
"provider": "email",
|
||||
"last_sign_in_at": "2023-12-16T14:04:38.302264+00:00",
|
||||
"created_at": "2023-12-16T14:04:38.302326+00:00",
|
||||
"updated_at": "2023-12-16T14:04:38.302326+00:00",
|
||||
"email": "[email protected]",
|
||||
"id": "e790ab09-9c5c-4fb4-aa6b-78a5abe8cd56"
|
||||
}
|
||||
],
|
||||
"profile_fullname": "Elon Gates"
|
||||
}
|
||||
]
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"name": "shared",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"tsconfig": "workspace:*"
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"extends": "tsconfig/base.json"
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "tsconfig",
|
||||
"name": "@cio/tsconfig",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"license": "MIT",
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "@cio/utils",
|
||||
"version": "1.0.0",
|
||||
"exports": {
|
||||
"./plans": "./src/plans/index.ts",
|
||||
"./senja": "./src/senja/index.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@cio/tsconfig": "workspace:*"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
export * from './constants';
|
||||
export * from './utils';
|
||||
|
||||
import * as PLANS from './data.json';
|
||||
|
||||
export { PLANS };
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"extends": "tsconfig/base.json",
|
||||
"compilerOptions": {
|
||||
"resolveJsonModule": true
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user