diff --git a/assets/groups.example.csv b/assets/groups.example.csv deleted file mode 100644 index ec7870c0..00000000 --- a/assets/groups.example.csv +++ /dev/null @@ -1,4 +0,0 @@ -name -Group A -Group B -Group C \ No newline at end of file diff --git a/migrations/0015_shiny_black_knight.sql b/migrations/0015_shiny_black_knight.sql new file mode 100644 index 00000000..269ca6c1 --- /dev/null +++ b/migrations/0015_shiny_black_knight.sql @@ -0,0 +1,26 @@ +CREATE TABLE IF NOT EXISTS "questions_to_group_categories" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "question_id" uuid NOT NULL, + "group_category_id" uuid, + "created_at" timestamp DEFAULT now() NOT NULL, + "updated_at" timestamp DEFAULT now() NOT NULL +); +--> statement-breakpoint +ALTER TABLE "registrations" ADD COLUMN "group_id" uuid;--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "registrations" ADD CONSTRAINT "registrations_group_id_groups_id_fk" FOREIGN KEY ("group_id") REFERENCES "groups"("id") ON DELETE no action ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "questions_to_group_categories" ADD CONSTRAINT "questions_to_group_categories_question_id_forum_questions_id_fk" FOREIGN KEY ("question_id") REFERENCES "forum_questions"("id") ON DELETE no action ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; +--> statement-breakpoint +DO $$ BEGIN + ALTER TABLE "questions_to_group_categories" ADD CONSTRAINT "questions_to_group_categories_group_category_id_group_categories_id_fk" FOREIGN KEY ("group_category_id") REFERENCES "group_categories"("id") ON DELETE no action ON UPDATE no action; +EXCEPTION + WHEN duplicate_object THEN null; +END $$; diff --git a/migrations/0016_ambitious_rictor.sql b/migrations/0016_ambitious_rictor.sql new file mode 100644 index 00000000..87a9aae3 --- /dev/null +++ b/migrations/0016_ambitious_rictor.sql @@ -0,0 +1,4 @@ +ALTER TABLE "group_categories" ADD COLUMN "user_can_create" boolean DEFAULT false NOT NULL;--> statement-breakpoint +ALTER TABLE "group_categories" ADD COLUMN "user_can_view" boolean DEFAULT false NOT NULL;--> statement-breakpoint +ALTER TABLE "groups" ADD COLUMN "secret" varchar(256);--> statement-breakpoint +ALTER TABLE "groups" ADD CONSTRAINT "groups_secret_unique" UNIQUE("secret"); \ No newline at end of file diff --git a/migrations/0017_jazzy_revanche.sql b/migrations/0017_jazzy_revanche.sql new file mode 100644 index 00000000..c53a96cb --- /dev/null +++ b/migrations/0017_jazzy_revanche.sql @@ -0,0 +1 @@ +ALTER TABLE "registration_fields" ADD COLUMN "display_on_group_registration" boolean DEFAULT false; \ No newline at end of file diff --git a/migrations/0018_abandoned_mongoose.sql b/migrations/0018_abandoned_mongoose.sql new file mode 100644 index 00000000..924b5f21 --- /dev/null +++ b/migrations/0018_abandoned_mongoose.sql @@ -0,0 +1,11 @@ +CREATE TABLE IF NOT EXISTS "alerts" ( + "id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL, + "title" varchar(256) NOT NULL, + "description" varchar(1024), + "link" varchar(256), + "start_at" timestamp, + "end_at" timestamp, + "active" boolean DEFAULT false, + "created_at" timestamp DEFAULT now() NOT NULL, + "updated_at" timestamp DEFAULT now() NOT NULL +); diff --git a/migrations/0019_nifty_wallow.sql b/migrations/0019_nifty_wallow.sql new file mode 100644 index 00000000..8f5e6a4a --- /dev/null +++ b/migrations/0019_nifty_wallow.sql @@ -0,0 +1,2 @@ +ALTER TABLE "registration_fields" RENAME COLUMN "display_on_group_registration" TO "for_group";--> statement-breakpoint +ALTER TABLE "registration_fields" ADD COLUMN "for_user" boolean DEFAULT true; \ No newline at end of file diff --git a/migrations/meta/0015_snapshot.json b/migrations/meta/0015_snapshot.json new file mode 100644 index 00000000..9485f110 --- /dev/null +++ b/migrations/meta/0015_snapshot.json @@ -0,0 +1,1527 @@ +{ + "id": "52b7a687-9af1-4d59-8443-195f60d1d1f5", + "prevId": "2bbf7b5d-a98a-4170-8e2c-df6dcbab7133", + "version": "5", + "dialect": "pg", + "tables": { + "comments": { + "name": "comments", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "question_option_id": { + "name": "question_option_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "value": { + "name": "value", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "comments_user_id_users_id_fk": { + "name": "comments_user_id_users_id_fk", + "tableFrom": "comments", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "comments_question_option_id_question_options_id_fk": { + "name": "comments_question_option_id_question_options_id_fk", + "tableFrom": "comments", + "tableTo": "question_options", + "columnsFrom": [ + "question_option_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "cycles": { + "name": "cycles", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "event_id": { + "name": "event_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "start_at": { + "name": "start_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "end_at": { + "name": "end_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false, + "default": "'UPCOMING'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "cycles_event_id_events_id_fk": { + "name": "cycles_event_id_events_id_fk", + "tableFrom": "cycles", + "tableTo": "events", + "columnsFrom": [ + "event_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "events": { + "name": "events", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "link": { + "name": "link", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "registration_description": { + "name": "registration_description", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "image_url": { + "name": "image_url", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "event_display_rank": { + "name": "event_display_rank", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "federated_credentials": { + "name": "federated_credentials", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "subject": { + "name": "subject", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "federated_credentials_user_id_users_id_fk": { + "name": "federated_credentials_user_id_users_id_fk", + "tableFrom": "federated_credentials", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "provider_subject_idx": { + "name": "provider_subject_idx", + "nullsNotDistinct": false, + "columns": [ + "provider", + "subject" + ] + } + } + }, + "forum_questions": { + "name": "forum_questions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "cycle_id": { + "name": "cycle_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "question_title": { + "name": "question_title", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "question_sub_title": { + "name": "question_sub_title", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "forum_questions_cycle_id_cycles_id_fk": { + "name": "forum_questions_cycle_id_cycles_id_fk", + "tableFrom": "forum_questions", + "tableTo": "cycles", + "columnsFrom": [ + "cycle_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "group_categories": { + "name": "group_categories", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "event_id": { + "name": "event_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "group_categories_event_id_events_id_fk": { + "name": "group_categories_event_id_events_id_fk", + "tableFrom": "group_categories", + "tableTo": "events", + "columnsFrom": [ + "event_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "groups": { + "name": "groups", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "group_category_id": { + "name": "group_category_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "groups_group_category_id_group_categories_id_fk": { + "name": "groups_group_category_id_group_categories_id_fk", + "tableFrom": "groups", + "tableTo": "group_categories", + "columnsFrom": [ + "group_category_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "users": { + "name": "users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "username": { + "name": "username", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "first_name": { + "name": "first_name", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "last_name": { + "name": "last_name", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "email": { + "name": "email", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "telegram": { + "name": "telegram", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "users_username_unique": { + "name": "users_username_unique", + "nullsNotDistinct": false, + "columns": [ + "username" + ] + }, + "users_email_unique": { + "name": "users_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + }, + "users_telegram_unique": { + "name": "users_telegram_unique", + "nullsNotDistinct": false, + "columns": [ + "telegram" + ] + } + } + }, + "registrations": { + "name": "registrations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "event_id": { + "name": "event_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "group_id": { + "name": "group_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "varchar", + "primaryKey": false, + "notNull": false, + "default": "'DRAFT'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "registrations_user_id_users_id_fk": { + "name": "registrations_user_id_users_id_fk", + "tableFrom": "registrations", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "registrations_event_id_events_id_fk": { + "name": "registrations_event_id_events_id_fk", + "tableFrom": "registrations", + "tableTo": "events", + "columnsFrom": [ + "event_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "registrations_group_id_groups_id_fk": { + "name": "registrations_group_id_groups_id_fk", + "tableFrom": "registrations", + "tableTo": "groups", + "columnsFrom": [ + "group_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "registration_field_options": { + "name": "registration_field_options", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "registration_field_id": { + "name": "registration_field_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "registration_field_options_registration_field_id_registration_fields_id_fk": { + "name": "registration_field_options_registration_field_id_registration_fields_id_fk", + "tableFrom": "registration_field_options", + "tableTo": "registration_fields", + "columnsFrom": [ + "registration_field_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "question_options": { + "name": "question_options", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "registration_id": { + "name": "registration_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "question_id": { + "name": "question_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "option_title": { + "name": "option_title", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "option_sub_title": { + "name": "option_sub_title", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "accepted": { + "name": "accepted", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "vote_score": { + "name": "vote_score", + "type": "numeric", + "primaryKey": false, + "notNull": true, + "default": "'0.0'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "question_options_user_id_users_id_fk": { + "name": "question_options_user_id_users_id_fk", + "tableFrom": "question_options", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "question_options_registration_id_registrations_id_fk": { + "name": "question_options_registration_id_registrations_id_fk", + "tableFrom": "question_options", + "tableTo": "registrations", + "columnsFrom": [ + "registration_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "question_options_question_id_forum_questions_id_fk": { + "name": "question_options_question_id_forum_questions_id_fk", + "tableFrom": "question_options", + "tableTo": "forum_questions", + "columnsFrom": [ + "question_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "votes": { + "name": "votes", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "option_id": { + "name": "option_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "question_id": { + "name": "question_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "num_of_votes": { + "name": "num_of_votes", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "votes_user_id_users_id_fk": { + "name": "votes_user_id_users_id_fk", + "tableFrom": "votes", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "votes_option_id_question_options_id_fk": { + "name": "votes_option_id_question_options_id_fk", + "tableFrom": "votes", + "tableTo": "question_options", + "columnsFrom": [ + "option_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "votes_question_id_forum_questions_id_fk": { + "name": "votes_question_id_forum_questions_id_fk", + "tableFrom": "votes", + "tableTo": "forum_questions", + "columnsFrom": [ + "question_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "registration_fields": { + "name": "registration_fields", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "event_id": { + "name": "event_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "varchar", + "primaryKey": false, + "notNull": true, + "default": "'TEXT'" + }, + "required": { + "name": "required", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "question_id": { + "name": "question_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "question_option_type": { + "name": "question_option_type", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "fields_display_rank": { + "name": "fields_display_rank", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "character_limit": { + "name": "character_limit", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "registration_fields_event_id_events_id_fk": { + "name": "registration_fields_event_id_events_id_fk", + "tableFrom": "registration_fields", + "tableTo": "events", + "columnsFrom": [ + "event_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "registration_fields_question_id_forum_questions_id_fk": { + "name": "registration_fields_question_id_forum_questions_id_fk", + "tableFrom": "registration_fields", + "tableTo": "forum_questions", + "columnsFrom": [ + "question_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "registration_data": { + "name": "registration_data", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "registration_id": { + "name": "registration_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "registration_field_id": { + "name": "registration_field_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "registration_data_registration_id_registrations_id_fk": { + "name": "registration_data_registration_id_registrations_id_fk", + "tableFrom": "registration_data", + "tableTo": "registrations", + "columnsFrom": [ + "registration_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "registration_data_registration_field_id_registration_fields_id_fk": { + "name": "registration_data_registration_field_id_registration_fields_id_fk", + "tableFrom": "registration_data", + "tableTo": "registration_fields", + "columnsFrom": [ + "registration_field_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "users_to_groups": { + "name": "users_to_groups", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "group_id": { + "name": "group_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "group_category_id": { + "name": "group_category_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "users_to_groups_user_id_users_id_fk": { + "name": "users_to_groups_user_id_users_id_fk", + "tableFrom": "users_to_groups", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "users_to_groups_group_id_groups_id_fk": { + "name": "users_to_groups_group_id_groups_id_fk", + "tableFrom": "users_to_groups", + "tableTo": "groups", + "columnsFrom": [ + "group_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "users_to_groups_group_category_id_group_categories_id_fk": { + "name": "users_to_groups_group_category_id_group_categories_id_fk", + "tableFrom": "users_to_groups", + "tableTo": "group_categories", + "columnsFrom": [ + "group_category_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "user_attributes": { + "name": "user_attributes", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "attribute_key": { + "name": "attribute_key", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "attribute_value": { + "name": "attribute_value", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "user_attributes_user_id_users_id_fk": { + "name": "user_attributes_user_id_users_id_fk", + "tableFrom": "user_attributes", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "likes": { + "name": "likes", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "comment_id": { + "name": "comment_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "likes_user_id_users_id_fk": { + "name": "likes_user_id_users_id_fk", + "tableFrom": "likes", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "likes_comment_id_comments_id_fk": { + "name": "likes_comment_id_comments_id_fk", + "tableFrom": "likes", + "tableTo": "comments", + "columnsFrom": [ + "comment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "notification_types": { + "name": "notification_types", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "value": { + "name": "value", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "notification_types_value_unique": { + "name": "notification_types_value_unique", + "nullsNotDistinct": false, + "columns": [ + "value" + ] + } + } + }, + "users_to_notifications": { + "name": "users_to_notifications", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "notification_type_id": { + "name": "notification_type_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "active": { + "name": "active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "users_to_notifications_user_id_users_id_fk": { + "name": "users_to_notifications_user_id_users_id_fk", + "tableFrom": "users_to_notifications", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "users_to_notifications_notification_type_id_notification_types_id_fk": { + "name": "users_to_notifications_notification_type_id_notification_types_id_fk", + "tableFrom": "users_to_notifications", + "tableTo": "notification_types", + "columnsFrom": [ + "notification_type_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "questions_to_group_categories": { + "name": "questions_to_group_categories", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "question_id": { + "name": "question_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "group_category_id": { + "name": "group_category_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "questions_to_group_categories_question_id_forum_questions_id_fk": { + "name": "questions_to_group_categories_question_id_forum_questions_id_fk", + "tableFrom": "questions_to_group_categories", + "tableTo": "forum_questions", + "columnsFrom": [ + "question_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "questions_to_group_categories_group_category_id_group_categories_id_fk": { + "name": "questions_to_group_categories_group_category_id_group_categories_id_fk", + "tableFrom": "questions_to_group_categories", + "tableTo": "group_categories", + "columnsFrom": [ + "group_category_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": {}, + "schemas": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/migrations/meta/0016_snapshot.json b/migrations/meta/0016_snapshot.json new file mode 100644 index 00000000..a084a595 --- /dev/null +++ b/migrations/meta/0016_snapshot.json @@ -0,0 +1,1555 @@ +{ + "id": "3bca2de9-9a2c-46ce-87c8-226969d43ec7", + "prevId": "52b7a687-9af1-4d59-8443-195f60d1d1f5", + "version": "5", + "dialect": "pg", + "tables": { + "comments": { + "name": "comments", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "question_option_id": { + "name": "question_option_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "value": { + "name": "value", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "comments_user_id_users_id_fk": { + "name": "comments_user_id_users_id_fk", + "tableFrom": "comments", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "comments_question_option_id_question_options_id_fk": { + "name": "comments_question_option_id_question_options_id_fk", + "tableFrom": "comments", + "tableTo": "question_options", + "columnsFrom": [ + "question_option_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "cycles": { + "name": "cycles", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "event_id": { + "name": "event_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "start_at": { + "name": "start_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "end_at": { + "name": "end_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false, + "default": "'UPCOMING'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "cycles_event_id_events_id_fk": { + "name": "cycles_event_id_events_id_fk", + "tableFrom": "cycles", + "tableTo": "events", + "columnsFrom": [ + "event_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "events": { + "name": "events", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "link": { + "name": "link", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "registration_description": { + "name": "registration_description", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "image_url": { + "name": "image_url", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "event_display_rank": { + "name": "event_display_rank", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "federated_credentials": { + "name": "federated_credentials", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "subject": { + "name": "subject", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "federated_credentials_user_id_users_id_fk": { + "name": "federated_credentials_user_id_users_id_fk", + "tableFrom": "federated_credentials", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "provider_subject_idx": { + "name": "provider_subject_idx", + "nullsNotDistinct": false, + "columns": [ + "provider", + "subject" + ] + } + } + }, + "forum_questions": { + "name": "forum_questions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "cycle_id": { + "name": "cycle_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "question_title": { + "name": "question_title", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "question_sub_title": { + "name": "question_sub_title", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "forum_questions_cycle_id_cycles_id_fk": { + "name": "forum_questions_cycle_id_cycles_id_fk", + "tableFrom": "forum_questions", + "tableTo": "cycles", + "columnsFrom": [ + "cycle_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "group_categories": { + "name": "group_categories", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "event_id": { + "name": "event_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "user_can_create": { + "name": "user_can_create", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "user_can_view": { + "name": "user_can_view", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "group_categories_event_id_events_id_fk": { + "name": "group_categories_event_id_events_id_fk", + "tableFrom": "group_categories", + "tableTo": "events", + "columnsFrom": [ + "event_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "groups": { + "name": "groups", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "secret": { + "name": "secret", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "group_category_id": { + "name": "group_category_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "groups_group_category_id_group_categories_id_fk": { + "name": "groups_group_category_id_group_categories_id_fk", + "tableFrom": "groups", + "tableTo": "group_categories", + "columnsFrom": [ + "group_category_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "groups_secret_unique": { + "name": "groups_secret_unique", + "nullsNotDistinct": false, + "columns": [ + "secret" + ] + } + } + }, + "users": { + "name": "users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "username": { + "name": "username", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "first_name": { + "name": "first_name", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "last_name": { + "name": "last_name", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "email": { + "name": "email", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "telegram": { + "name": "telegram", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "users_username_unique": { + "name": "users_username_unique", + "nullsNotDistinct": false, + "columns": [ + "username" + ] + }, + "users_email_unique": { + "name": "users_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + }, + "users_telegram_unique": { + "name": "users_telegram_unique", + "nullsNotDistinct": false, + "columns": [ + "telegram" + ] + } + } + }, + "registrations": { + "name": "registrations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "event_id": { + "name": "event_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "group_id": { + "name": "group_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "varchar", + "primaryKey": false, + "notNull": false, + "default": "'DRAFT'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "registrations_user_id_users_id_fk": { + "name": "registrations_user_id_users_id_fk", + "tableFrom": "registrations", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "registrations_event_id_events_id_fk": { + "name": "registrations_event_id_events_id_fk", + "tableFrom": "registrations", + "tableTo": "events", + "columnsFrom": [ + "event_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "registrations_group_id_groups_id_fk": { + "name": "registrations_group_id_groups_id_fk", + "tableFrom": "registrations", + "tableTo": "groups", + "columnsFrom": [ + "group_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "registration_field_options": { + "name": "registration_field_options", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "registration_field_id": { + "name": "registration_field_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "registration_field_options_registration_field_id_registration_fields_id_fk": { + "name": "registration_field_options_registration_field_id_registration_fields_id_fk", + "tableFrom": "registration_field_options", + "tableTo": "registration_fields", + "columnsFrom": [ + "registration_field_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "question_options": { + "name": "question_options", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "registration_id": { + "name": "registration_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "question_id": { + "name": "question_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "option_title": { + "name": "option_title", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "option_sub_title": { + "name": "option_sub_title", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "accepted": { + "name": "accepted", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "vote_score": { + "name": "vote_score", + "type": "numeric", + "primaryKey": false, + "notNull": true, + "default": "'0.0'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "question_options_user_id_users_id_fk": { + "name": "question_options_user_id_users_id_fk", + "tableFrom": "question_options", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "question_options_registration_id_registrations_id_fk": { + "name": "question_options_registration_id_registrations_id_fk", + "tableFrom": "question_options", + "tableTo": "registrations", + "columnsFrom": [ + "registration_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "question_options_question_id_forum_questions_id_fk": { + "name": "question_options_question_id_forum_questions_id_fk", + "tableFrom": "question_options", + "tableTo": "forum_questions", + "columnsFrom": [ + "question_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "votes": { + "name": "votes", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "option_id": { + "name": "option_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "question_id": { + "name": "question_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "num_of_votes": { + "name": "num_of_votes", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "votes_user_id_users_id_fk": { + "name": "votes_user_id_users_id_fk", + "tableFrom": "votes", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "votes_option_id_question_options_id_fk": { + "name": "votes_option_id_question_options_id_fk", + "tableFrom": "votes", + "tableTo": "question_options", + "columnsFrom": [ + "option_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "votes_question_id_forum_questions_id_fk": { + "name": "votes_question_id_forum_questions_id_fk", + "tableFrom": "votes", + "tableTo": "forum_questions", + "columnsFrom": [ + "question_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "registration_fields": { + "name": "registration_fields", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "event_id": { + "name": "event_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "varchar", + "primaryKey": false, + "notNull": true, + "default": "'TEXT'" + }, + "required": { + "name": "required", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "question_id": { + "name": "question_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "question_option_type": { + "name": "question_option_type", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "fields_display_rank": { + "name": "fields_display_rank", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "character_limit": { + "name": "character_limit", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "registration_fields_event_id_events_id_fk": { + "name": "registration_fields_event_id_events_id_fk", + "tableFrom": "registration_fields", + "tableTo": "events", + "columnsFrom": [ + "event_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "registration_fields_question_id_forum_questions_id_fk": { + "name": "registration_fields_question_id_forum_questions_id_fk", + "tableFrom": "registration_fields", + "tableTo": "forum_questions", + "columnsFrom": [ + "question_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "registration_data": { + "name": "registration_data", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "registration_id": { + "name": "registration_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "registration_field_id": { + "name": "registration_field_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "registration_data_registration_id_registrations_id_fk": { + "name": "registration_data_registration_id_registrations_id_fk", + "tableFrom": "registration_data", + "tableTo": "registrations", + "columnsFrom": [ + "registration_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "registration_data_registration_field_id_registration_fields_id_fk": { + "name": "registration_data_registration_field_id_registration_fields_id_fk", + "tableFrom": "registration_data", + "tableTo": "registration_fields", + "columnsFrom": [ + "registration_field_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "users_to_groups": { + "name": "users_to_groups", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "group_id": { + "name": "group_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "group_category_id": { + "name": "group_category_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "users_to_groups_user_id_users_id_fk": { + "name": "users_to_groups_user_id_users_id_fk", + "tableFrom": "users_to_groups", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "users_to_groups_group_id_groups_id_fk": { + "name": "users_to_groups_group_id_groups_id_fk", + "tableFrom": "users_to_groups", + "tableTo": "groups", + "columnsFrom": [ + "group_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "users_to_groups_group_category_id_group_categories_id_fk": { + "name": "users_to_groups_group_category_id_group_categories_id_fk", + "tableFrom": "users_to_groups", + "tableTo": "group_categories", + "columnsFrom": [ + "group_category_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "user_attributes": { + "name": "user_attributes", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "attribute_key": { + "name": "attribute_key", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "attribute_value": { + "name": "attribute_value", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "user_attributes_user_id_users_id_fk": { + "name": "user_attributes_user_id_users_id_fk", + "tableFrom": "user_attributes", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "likes": { + "name": "likes", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "comment_id": { + "name": "comment_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "likes_user_id_users_id_fk": { + "name": "likes_user_id_users_id_fk", + "tableFrom": "likes", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "likes_comment_id_comments_id_fk": { + "name": "likes_comment_id_comments_id_fk", + "tableFrom": "likes", + "tableTo": "comments", + "columnsFrom": [ + "comment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "notification_types": { + "name": "notification_types", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "value": { + "name": "value", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "notification_types_value_unique": { + "name": "notification_types_value_unique", + "nullsNotDistinct": false, + "columns": [ + "value" + ] + } + } + }, + "users_to_notifications": { + "name": "users_to_notifications", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "notification_type_id": { + "name": "notification_type_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "active": { + "name": "active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "users_to_notifications_user_id_users_id_fk": { + "name": "users_to_notifications_user_id_users_id_fk", + "tableFrom": "users_to_notifications", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "users_to_notifications_notification_type_id_notification_types_id_fk": { + "name": "users_to_notifications_notification_type_id_notification_types_id_fk", + "tableFrom": "users_to_notifications", + "tableTo": "notification_types", + "columnsFrom": [ + "notification_type_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "questions_to_group_categories": { + "name": "questions_to_group_categories", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "question_id": { + "name": "question_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "group_category_id": { + "name": "group_category_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "questions_to_group_categories_question_id_forum_questions_id_fk": { + "name": "questions_to_group_categories_question_id_forum_questions_id_fk", + "tableFrom": "questions_to_group_categories", + "tableTo": "forum_questions", + "columnsFrom": [ + "question_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "questions_to_group_categories_group_category_id_group_categories_id_fk": { + "name": "questions_to_group_categories_group_category_id_group_categories_id_fk", + "tableFrom": "questions_to_group_categories", + "tableTo": "group_categories", + "columnsFrom": [ + "group_category_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": {}, + "schemas": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/migrations/meta/0017_snapshot.json b/migrations/meta/0017_snapshot.json new file mode 100644 index 00000000..91aeb18f --- /dev/null +++ b/migrations/meta/0017_snapshot.json @@ -0,0 +1,1562 @@ +{ + "id": "0d20d2de-c589-4e94-a0b1-fbd54238e209", + "prevId": "3bca2de9-9a2c-46ce-87c8-226969d43ec7", + "version": "5", + "dialect": "pg", + "tables": { + "comments": { + "name": "comments", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "question_option_id": { + "name": "question_option_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "value": { + "name": "value", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "comments_user_id_users_id_fk": { + "name": "comments_user_id_users_id_fk", + "tableFrom": "comments", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "comments_question_option_id_question_options_id_fk": { + "name": "comments_question_option_id_question_options_id_fk", + "tableFrom": "comments", + "tableTo": "question_options", + "columnsFrom": [ + "question_option_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "cycles": { + "name": "cycles", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "event_id": { + "name": "event_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "start_at": { + "name": "start_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "end_at": { + "name": "end_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false, + "default": "'UPCOMING'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "cycles_event_id_events_id_fk": { + "name": "cycles_event_id_events_id_fk", + "tableFrom": "cycles", + "tableTo": "events", + "columnsFrom": [ + "event_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "events": { + "name": "events", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "link": { + "name": "link", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "registration_description": { + "name": "registration_description", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "image_url": { + "name": "image_url", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "event_display_rank": { + "name": "event_display_rank", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "federated_credentials": { + "name": "federated_credentials", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "subject": { + "name": "subject", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "federated_credentials_user_id_users_id_fk": { + "name": "federated_credentials_user_id_users_id_fk", + "tableFrom": "federated_credentials", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "provider_subject_idx": { + "name": "provider_subject_idx", + "nullsNotDistinct": false, + "columns": [ + "provider", + "subject" + ] + } + } + }, + "forum_questions": { + "name": "forum_questions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "cycle_id": { + "name": "cycle_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "question_title": { + "name": "question_title", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "question_sub_title": { + "name": "question_sub_title", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "forum_questions_cycle_id_cycles_id_fk": { + "name": "forum_questions_cycle_id_cycles_id_fk", + "tableFrom": "forum_questions", + "tableTo": "cycles", + "columnsFrom": [ + "cycle_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "group_categories": { + "name": "group_categories", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "event_id": { + "name": "event_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "user_can_create": { + "name": "user_can_create", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "user_can_view": { + "name": "user_can_view", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "group_categories_event_id_events_id_fk": { + "name": "group_categories_event_id_events_id_fk", + "tableFrom": "group_categories", + "tableTo": "events", + "columnsFrom": [ + "event_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "groups": { + "name": "groups", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "secret": { + "name": "secret", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "group_category_id": { + "name": "group_category_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "groups_group_category_id_group_categories_id_fk": { + "name": "groups_group_category_id_group_categories_id_fk", + "tableFrom": "groups", + "tableTo": "group_categories", + "columnsFrom": [ + "group_category_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "groups_secret_unique": { + "name": "groups_secret_unique", + "nullsNotDistinct": false, + "columns": [ + "secret" + ] + } + } + }, + "users": { + "name": "users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "username": { + "name": "username", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "first_name": { + "name": "first_name", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "last_name": { + "name": "last_name", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "email": { + "name": "email", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "telegram": { + "name": "telegram", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "users_username_unique": { + "name": "users_username_unique", + "nullsNotDistinct": false, + "columns": [ + "username" + ] + }, + "users_email_unique": { + "name": "users_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + }, + "users_telegram_unique": { + "name": "users_telegram_unique", + "nullsNotDistinct": false, + "columns": [ + "telegram" + ] + } + } + }, + "registrations": { + "name": "registrations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "event_id": { + "name": "event_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "group_id": { + "name": "group_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "varchar", + "primaryKey": false, + "notNull": false, + "default": "'DRAFT'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "registrations_user_id_users_id_fk": { + "name": "registrations_user_id_users_id_fk", + "tableFrom": "registrations", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "registrations_event_id_events_id_fk": { + "name": "registrations_event_id_events_id_fk", + "tableFrom": "registrations", + "tableTo": "events", + "columnsFrom": [ + "event_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "registrations_group_id_groups_id_fk": { + "name": "registrations_group_id_groups_id_fk", + "tableFrom": "registrations", + "tableTo": "groups", + "columnsFrom": [ + "group_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "registration_field_options": { + "name": "registration_field_options", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "registration_field_id": { + "name": "registration_field_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "registration_field_options_registration_field_id_registration_fields_id_fk": { + "name": "registration_field_options_registration_field_id_registration_fields_id_fk", + "tableFrom": "registration_field_options", + "tableTo": "registration_fields", + "columnsFrom": [ + "registration_field_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "question_options": { + "name": "question_options", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "registration_id": { + "name": "registration_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "question_id": { + "name": "question_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "option_title": { + "name": "option_title", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "option_sub_title": { + "name": "option_sub_title", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "accepted": { + "name": "accepted", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "vote_score": { + "name": "vote_score", + "type": "numeric", + "primaryKey": false, + "notNull": true, + "default": "'0.0'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "question_options_user_id_users_id_fk": { + "name": "question_options_user_id_users_id_fk", + "tableFrom": "question_options", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "question_options_registration_id_registrations_id_fk": { + "name": "question_options_registration_id_registrations_id_fk", + "tableFrom": "question_options", + "tableTo": "registrations", + "columnsFrom": [ + "registration_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "question_options_question_id_forum_questions_id_fk": { + "name": "question_options_question_id_forum_questions_id_fk", + "tableFrom": "question_options", + "tableTo": "forum_questions", + "columnsFrom": [ + "question_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "votes": { + "name": "votes", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "option_id": { + "name": "option_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "question_id": { + "name": "question_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "num_of_votes": { + "name": "num_of_votes", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "votes_user_id_users_id_fk": { + "name": "votes_user_id_users_id_fk", + "tableFrom": "votes", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "votes_option_id_question_options_id_fk": { + "name": "votes_option_id_question_options_id_fk", + "tableFrom": "votes", + "tableTo": "question_options", + "columnsFrom": [ + "option_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "votes_question_id_forum_questions_id_fk": { + "name": "votes_question_id_forum_questions_id_fk", + "tableFrom": "votes", + "tableTo": "forum_questions", + "columnsFrom": [ + "question_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "registration_fields": { + "name": "registration_fields", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "event_id": { + "name": "event_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "varchar", + "primaryKey": false, + "notNull": true, + "default": "'TEXT'" + }, + "required": { + "name": "required", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "question_id": { + "name": "question_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "question_option_type": { + "name": "question_option_type", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "fields_display_rank": { + "name": "fields_display_rank", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "character_limit": { + "name": "character_limit", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "display_on_group_registration": { + "name": "display_on_group_registration", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "registration_fields_event_id_events_id_fk": { + "name": "registration_fields_event_id_events_id_fk", + "tableFrom": "registration_fields", + "tableTo": "events", + "columnsFrom": [ + "event_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "registration_fields_question_id_forum_questions_id_fk": { + "name": "registration_fields_question_id_forum_questions_id_fk", + "tableFrom": "registration_fields", + "tableTo": "forum_questions", + "columnsFrom": [ + "question_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "registration_data": { + "name": "registration_data", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "registration_id": { + "name": "registration_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "registration_field_id": { + "name": "registration_field_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "registration_data_registration_id_registrations_id_fk": { + "name": "registration_data_registration_id_registrations_id_fk", + "tableFrom": "registration_data", + "tableTo": "registrations", + "columnsFrom": [ + "registration_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "registration_data_registration_field_id_registration_fields_id_fk": { + "name": "registration_data_registration_field_id_registration_fields_id_fk", + "tableFrom": "registration_data", + "tableTo": "registration_fields", + "columnsFrom": [ + "registration_field_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "users_to_groups": { + "name": "users_to_groups", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "group_id": { + "name": "group_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "group_category_id": { + "name": "group_category_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "users_to_groups_user_id_users_id_fk": { + "name": "users_to_groups_user_id_users_id_fk", + "tableFrom": "users_to_groups", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "users_to_groups_group_id_groups_id_fk": { + "name": "users_to_groups_group_id_groups_id_fk", + "tableFrom": "users_to_groups", + "tableTo": "groups", + "columnsFrom": [ + "group_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "users_to_groups_group_category_id_group_categories_id_fk": { + "name": "users_to_groups_group_category_id_group_categories_id_fk", + "tableFrom": "users_to_groups", + "tableTo": "group_categories", + "columnsFrom": [ + "group_category_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "user_attributes": { + "name": "user_attributes", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "attribute_key": { + "name": "attribute_key", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "attribute_value": { + "name": "attribute_value", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "user_attributes_user_id_users_id_fk": { + "name": "user_attributes_user_id_users_id_fk", + "tableFrom": "user_attributes", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "likes": { + "name": "likes", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "comment_id": { + "name": "comment_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "likes_user_id_users_id_fk": { + "name": "likes_user_id_users_id_fk", + "tableFrom": "likes", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "likes_comment_id_comments_id_fk": { + "name": "likes_comment_id_comments_id_fk", + "tableFrom": "likes", + "tableTo": "comments", + "columnsFrom": [ + "comment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "notification_types": { + "name": "notification_types", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "value": { + "name": "value", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "notification_types_value_unique": { + "name": "notification_types_value_unique", + "nullsNotDistinct": false, + "columns": [ + "value" + ] + } + } + }, + "users_to_notifications": { + "name": "users_to_notifications", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "notification_type_id": { + "name": "notification_type_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "active": { + "name": "active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "users_to_notifications_user_id_users_id_fk": { + "name": "users_to_notifications_user_id_users_id_fk", + "tableFrom": "users_to_notifications", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "users_to_notifications_notification_type_id_notification_types_id_fk": { + "name": "users_to_notifications_notification_type_id_notification_types_id_fk", + "tableFrom": "users_to_notifications", + "tableTo": "notification_types", + "columnsFrom": [ + "notification_type_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "questions_to_group_categories": { + "name": "questions_to_group_categories", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "question_id": { + "name": "question_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "group_category_id": { + "name": "group_category_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "questions_to_group_categories_question_id_forum_questions_id_fk": { + "name": "questions_to_group_categories_question_id_forum_questions_id_fk", + "tableFrom": "questions_to_group_categories", + "tableTo": "forum_questions", + "columnsFrom": [ + "question_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "questions_to_group_categories_group_category_id_group_categories_id_fk": { + "name": "questions_to_group_categories_group_category_id_group_categories_id_fk", + "tableFrom": "questions_to_group_categories", + "tableTo": "group_categories", + "columnsFrom": [ + "group_category_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": {}, + "schemas": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/migrations/meta/0018_snapshot.json b/migrations/meta/0018_snapshot.json new file mode 100644 index 00000000..8ae39496 --- /dev/null +++ b/migrations/meta/0018_snapshot.json @@ -0,0 +1,1630 @@ +{ + "id": "9e82519c-4853-44bf-ac83-165a4e51c435", + "prevId": "0d20d2de-c589-4e94-a0b1-fbd54238e209", + "version": "5", + "dialect": "pg", + "tables": { + "alerts": { + "name": "alerts", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "title": { + "name": "title", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "varchar(1024)", + "primaryKey": false, + "notNull": false + }, + "link": { + "name": "link", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "start_at": { + "name": "start_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "end_at": { + "name": "end_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "active": { + "name": "active", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "comments": { + "name": "comments", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "question_option_id": { + "name": "question_option_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "value": { + "name": "value", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "comments_user_id_users_id_fk": { + "name": "comments_user_id_users_id_fk", + "tableFrom": "comments", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "comments_question_option_id_question_options_id_fk": { + "name": "comments_question_option_id_question_options_id_fk", + "tableFrom": "comments", + "tableTo": "question_options", + "columnsFrom": [ + "question_option_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "cycles": { + "name": "cycles", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "event_id": { + "name": "event_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "start_at": { + "name": "start_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "end_at": { + "name": "end_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false, + "default": "'UPCOMING'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "cycles_event_id_events_id_fk": { + "name": "cycles_event_id_events_id_fk", + "tableFrom": "cycles", + "tableTo": "events", + "columnsFrom": [ + "event_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "events": { + "name": "events", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "link": { + "name": "link", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "registration_description": { + "name": "registration_description", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "image_url": { + "name": "image_url", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "event_display_rank": { + "name": "event_display_rank", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "federated_credentials": { + "name": "federated_credentials", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "subject": { + "name": "subject", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "federated_credentials_user_id_users_id_fk": { + "name": "federated_credentials_user_id_users_id_fk", + "tableFrom": "federated_credentials", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "provider_subject_idx": { + "name": "provider_subject_idx", + "nullsNotDistinct": false, + "columns": [ + "provider", + "subject" + ] + } + } + }, + "forum_questions": { + "name": "forum_questions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "cycle_id": { + "name": "cycle_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "question_title": { + "name": "question_title", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "question_sub_title": { + "name": "question_sub_title", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "forum_questions_cycle_id_cycles_id_fk": { + "name": "forum_questions_cycle_id_cycles_id_fk", + "tableFrom": "forum_questions", + "tableTo": "cycles", + "columnsFrom": [ + "cycle_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "group_categories": { + "name": "group_categories", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "event_id": { + "name": "event_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "user_can_create": { + "name": "user_can_create", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "user_can_view": { + "name": "user_can_view", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "group_categories_event_id_events_id_fk": { + "name": "group_categories_event_id_events_id_fk", + "tableFrom": "group_categories", + "tableTo": "events", + "columnsFrom": [ + "event_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "groups": { + "name": "groups", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "secret": { + "name": "secret", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "group_category_id": { + "name": "group_category_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "groups_group_category_id_group_categories_id_fk": { + "name": "groups_group_category_id_group_categories_id_fk", + "tableFrom": "groups", + "tableTo": "group_categories", + "columnsFrom": [ + "group_category_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "groups_secret_unique": { + "name": "groups_secret_unique", + "nullsNotDistinct": false, + "columns": [ + "secret" + ] + } + } + }, + "users": { + "name": "users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "username": { + "name": "username", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "first_name": { + "name": "first_name", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "last_name": { + "name": "last_name", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "email": { + "name": "email", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "telegram": { + "name": "telegram", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "users_username_unique": { + "name": "users_username_unique", + "nullsNotDistinct": false, + "columns": [ + "username" + ] + }, + "users_email_unique": { + "name": "users_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + }, + "users_telegram_unique": { + "name": "users_telegram_unique", + "nullsNotDistinct": false, + "columns": [ + "telegram" + ] + } + } + }, + "registrations": { + "name": "registrations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "event_id": { + "name": "event_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "group_id": { + "name": "group_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "varchar", + "primaryKey": false, + "notNull": false, + "default": "'DRAFT'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "registrations_user_id_users_id_fk": { + "name": "registrations_user_id_users_id_fk", + "tableFrom": "registrations", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "registrations_event_id_events_id_fk": { + "name": "registrations_event_id_events_id_fk", + "tableFrom": "registrations", + "tableTo": "events", + "columnsFrom": [ + "event_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "registrations_group_id_groups_id_fk": { + "name": "registrations_group_id_groups_id_fk", + "tableFrom": "registrations", + "tableTo": "groups", + "columnsFrom": [ + "group_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "registration_field_options": { + "name": "registration_field_options", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "registration_field_id": { + "name": "registration_field_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "registration_field_options_registration_field_id_registration_fields_id_fk": { + "name": "registration_field_options_registration_field_id_registration_fields_id_fk", + "tableFrom": "registration_field_options", + "tableTo": "registration_fields", + "columnsFrom": [ + "registration_field_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "question_options": { + "name": "question_options", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "registration_id": { + "name": "registration_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "question_id": { + "name": "question_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "option_title": { + "name": "option_title", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "option_sub_title": { + "name": "option_sub_title", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "accepted": { + "name": "accepted", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "vote_score": { + "name": "vote_score", + "type": "numeric", + "primaryKey": false, + "notNull": true, + "default": "'0.0'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "question_options_user_id_users_id_fk": { + "name": "question_options_user_id_users_id_fk", + "tableFrom": "question_options", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "question_options_registration_id_registrations_id_fk": { + "name": "question_options_registration_id_registrations_id_fk", + "tableFrom": "question_options", + "tableTo": "registrations", + "columnsFrom": [ + "registration_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "question_options_question_id_forum_questions_id_fk": { + "name": "question_options_question_id_forum_questions_id_fk", + "tableFrom": "question_options", + "tableTo": "forum_questions", + "columnsFrom": [ + "question_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "votes": { + "name": "votes", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "option_id": { + "name": "option_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "question_id": { + "name": "question_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "num_of_votes": { + "name": "num_of_votes", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "votes_user_id_users_id_fk": { + "name": "votes_user_id_users_id_fk", + "tableFrom": "votes", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "votes_option_id_question_options_id_fk": { + "name": "votes_option_id_question_options_id_fk", + "tableFrom": "votes", + "tableTo": "question_options", + "columnsFrom": [ + "option_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "votes_question_id_forum_questions_id_fk": { + "name": "votes_question_id_forum_questions_id_fk", + "tableFrom": "votes", + "tableTo": "forum_questions", + "columnsFrom": [ + "question_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "registration_fields": { + "name": "registration_fields", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "event_id": { + "name": "event_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "varchar", + "primaryKey": false, + "notNull": true, + "default": "'TEXT'" + }, + "required": { + "name": "required", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "question_id": { + "name": "question_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "question_option_type": { + "name": "question_option_type", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "fields_display_rank": { + "name": "fields_display_rank", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "character_limit": { + "name": "character_limit", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "display_on_group_registration": { + "name": "display_on_group_registration", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "registration_fields_event_id_events_id_fk": { + "name": "registration_fields_event_id_events_id_fk", + "tableFrom": "registration_fields", + "tableTo": "events", + "columnsFrom": [ + "event_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "registration_fields_question_id_forum_questions_id_fk": { + "name": "registration_fields_question_id_forum_questions_id_fk", + "tableFrom": "registration_fields", + "tableTo": "forum_questions", + "columnsFrom": [ + "question_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "registration_data": { + "name": "registration_data", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "registration_id": { + "name": "registration_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "registration_field_id": { + "name": "registration_field_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "registration_data_registration_id_registrations_id_fk": { + "name": "registration_data_registration_id_registrations_id_fk", + "tableFrom": "registration_data", + "tableTo": "registrations", + "columnsFrom": [ + "registration_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "registration_data_registration_field_id_registration_fields_id_fk": { + "name": "registration_data_registration_field_id_registration_fields_id_fk", + "tableFrom": "registration_data", + "tableTo": "registration_fields", + "columnsFrom": [ + "registration_field_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "users_to_groups": { + "name": "users_to_groups", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "group_id": { + "name": "group_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "group_category_id": { + "name": "group_category_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "users_to_groups_user_id_users_id_fk": { + "name": "users_to_groups_user_id_users_id_fk", + "tableFrom": "users_to_groups", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "users_to_groups_group_id_groups_id_fk": { + "name": "users_to_groups_group_id_groups_id_fk", + "tableFrom": "users_to_groups", + "tableTo": "groups", + "columnsFrom": [ + "group_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "users_to_groups_group_category_id_group_categories_id_fk": { + "name": "users_to_groups_group_category_id_group_categories_id_fk", + "tableFrom": "users_to_groups", + "tableTo": "group_categories", + "columnsFrom": [ + "group_category_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "user_attributes": { + "name": "user_attributes", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "attribute_key": { + "name": "attribute_key", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "attribute_value": { + "name": "attribute_value", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "user_attributes_user_id_users_id_fk": { + "name": "user_attributes_user_id_users_id_fk", + "tableFrom": "user_attributes", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "likes": { + "name": "likes", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "comment_id": { + "name": "comment_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "likes_user_id_users_id_fk": { + "name": "likes_user_id_users_id_fk", + "tableFrom": "likes", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "likes_comment_id_comments_id_fk": { + "name": "likes_comment_id_comments_id_fk", + "tableFrom": "likes", + "tableTo": "comments", + "columnsFrom": [ + "comment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "notification_types": { + "name": "notification_types", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "value": { + "name": "value", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "notification_types_value_unique": { + "name": "notification_types_value_unique", + "nullsNotDistinct": false, + "columns": [ + "value" + ] + } + } + }, + "users_to_notifications": { + "name": "users_to_notifications", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "notification_type_id": { + "name": "notification_type_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "active": { + "name": "active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "users_to_notifications_user_id_users_id_fk": { + "name": "users_to_notifications_user_id_users_id_fk", + "tableFrom": "users_to_notifications", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "users_to_notifications_notification_type_id_notification_types_id_fk": { + "name": "users_to_notifications_notification_type_id_notification_types_id_fk", + "tableFrom": "users_to_notifications", + "tableTo": "notification_types", + "columnsFrom": [ + "notification_type_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "questions_to_group_categories": { + "name": "questions_to_group_categories", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "question_id": { + "name": "question_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "group_category_id": { + "name": "group_category_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "questions_to_group_categories_question_id_forum_questions_id_fk": { + "name": "questions_to_group_categories_question_id_forum_questions_id_fk", + "tableFrom": "questions_to_group_categories", + "tableTo": "forum_questions", + "columnsFrom": [ + "question_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "questions_to_group_categories_group_category_id_group_categories_id_fk": { + "name": "questions_to_group_categories_group_category_id_group_categories_id_fk", + "tableFrom": "questions_to_group_categories", + "tableTo": "group_categories", + "columnsFrom": [ + "group_category_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": {}, + "schemas": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/migrations/meta/0019_snapshot.json b/migrations/meta/0019_snapshot.json new file mode 100644 index 00000000..406b19f9 --- /dev/null +++ b/migrations/meta/0019_snapshot.json @@ -0,0 +1,1637 @@ +{ + "id": "9c2a63ef-990b-4651-b9b2-b6e490f83942", + "prevId": "9e82519c-4853-44bf-ac83-165a4e51c435", + "version": "5", + "dialect": "pg", + "tables": { + "alerts": { + "name": "alerts", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "title": { + "name": "title", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "varchar(1024)", + "primaryKey": false, + "notNull": false + }, + "link": { + "name": "link", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "start_at": { + "name": "start_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "end_at": { + "name": "end_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "active": { + "name": "active", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "comments": { + "name": "comments", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "question_option_id": { + "name": "question_option_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "value": { + "name": "value", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "comments_user_id_users_id_fk": { + "name": "comments_user_id_users_id_fk", + "tableFrom": "comments", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "comments_question_option_id_question_options_id_fk": { + "name": "comments_question_option_id_question_options_id_fk", + "tableFrom": "comments", + "tableTo": "question_options", + "columnsFrom": [ + "question_option_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "cycles": { + "name": "cycles", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "event_id": { + "name": "event_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "start_at": { + "name": "start_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "end_at": { + "name": "end_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "varchar(20)", + "primaryKey": false, + "notNull": false, + "default": "'UPCOMING'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "cycles_event_id_events_id_fk": { + "name": "cycles_event_id_events_id_fk", + "tableFrom": "cycles", + "tableTo": "events", + "columnsFrom": [ + "event_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "events": { + "name": "events", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "link": { + "name": "link", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "registration_description": { + "name": "registration_description", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "image_url": { + "name": "image_url", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "event_display_rank": { + "name": "event_display_rank", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "federated_credentials": { + "name": "federated_credentials", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "subject": { + "name": "subject", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "federated_credentials_user_id_users_id_fk": { + "name": "federated_credentials_user_id_users_id_fk", + "tableFrom": "federated_credentials", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "provider_subject_idx": { + "name": "provider_subject_idx", + "nullsNotDistinct": false, + "columns": [ + "provider", + "subject" + ] + } + } + }, + "forum_questions": { + "name": "forum_questions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "cycle_id": { + "name": "cycle_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "question_title": { + "name": "question_title", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "question_sub_title": { + "name": "question_sub_title", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "forum_questions_cycle_id_cycles_id_fk": { + "name": "forum_questions_cycle_id_cycles_id_fk", + "tableFrom": "forum_questions", + "tableTo": "cycles", + "columnsFrom": [ + "cycle_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "group_categories": { + "name": "group_categories", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "event_id": { + "name": "event_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "user_can_create": { + "name": "user_can_create", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "user_can_view": { + "name": "user_can_view", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "group_categories_event_id_events_id_fk": { + "name": "group_categories_event_id_events_id_fk", + "tableFrom": "group_categories", + "tableTo": "events", + "columnsFrom": [ + "event_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "groups": { + "name": "groups", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "secret": { + "name": "secret", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "group_category_id": { + "name": "group_category_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "groups_group_category_id_group_categories_id_fk": { + "name": "groups_group_category_id_group_categories_id_fk", + "tableFrom": "groups", + "tableTo": "group_categories", + "columnsFrom": [ + "group_category_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "groups_secret_unique": { + "name": "groups_secret_unique", + "nullsNotDistinct": false, + "columns": [ + "secret" + ] + } + } + }, + "users": { + "name": "users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "username": { + "name": "username", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "first_name": { + "name": "first_name", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "last_name": { + "name": "last_name", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "email": { + "name": "email", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "telegram": { + "name": "telegram", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "users_username_unique": { + "name": "users_username_unique", + "nullsNotDistinct": false, + "columns": [ + "username" + ] + }, + "users_email_unique": { + "name": "users_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + }, + "users_telegram_unique": { + "name": "users_telegram_unique", + "nullsNotDistinct": false, + "columns": [ + "telegram" + ] + } + } + }, + "registrations": { + "name": "registrations", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "event_id": { + "name": "event_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "group_id": { + "name": "group_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "varchar", + "primaryKey": false, + "notNull": false, + "default": "'DRAFT'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "registrations_user_id_users_id_fk": { + "name": "registrations_user_id_users_id_fk", + "tableFrom": "registrations", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "registrations_event_id_events_id_fk": { + "name": "registrations_event_id_events_id_fk", + "tableFrom": "registrations", + "tableTo": "events", + "columnsFrom": [ + "event_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "registrations_group_id_groups_id_fk": { + "name": "registrations_group_id_groups_id_fk", + "tableFrom": "registrations", + "tableTo": "groups", + "columnsFrom": [ + "group_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "registration_field_options": { + "name": "registration_field_options", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "registration_field_id": { + "name": "registration_field_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "registration_field_options_registration_field_id_registration_fields_id_fk": { + "name": "registration_field_options_registration_field_id_registration_fields_id_fk", + "tableFrom": "registration_field_options", + "tableTo": "registration_fields", + "columnsFrom": [ + "registration_field_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "question_options": { + "name": "question_options", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "registration_id": { + "name": "registration_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "question_id": { + "name": "question_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "option_title": { + "name": "option_title", + "type": "varchar(256)", + "primaryKey": false, + "notNull": true + }, + "option_sub_title": { + "name": "option_sub_title", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "accepted": { + "name": "accepted", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "vote_score": { + "name": "vote_score", + "type": "numeric", + "primaryKey": false, + "notNull": true, + "default": "'0.0'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "question_options_user_id_users_id_fk": { + "name": "question_options_user_id_users_id_fk", + "tableFrom": "question_options", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "question_options_registration_id_registrations_id_fk": { + "name": "question_options_registration_id_registrations_id_fk", + "tableFrom": "question_options", + "tableTo": "registrations", + "columnsFrom": [ + "registration_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "question_options_question_id_forum_questions_id_fk": { + "name": "question_options_question_id_forum_questions_id_fk", + "tableFrom": "question_options", + "tableTo": "forum_questions", + "columnsFrom": [ + "question_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "votes": { + "name": "votes", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "option_id": { + "name": "option_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "question_id": { + "name": "question_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "num_of_votes": { + "name": "num_of_votes", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "votes_user_id_users_id_fk": { + "name": "votes_user_id_users_id_fk", + "tableFrom": "votes", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "votes_option_id_question_options_id_fk": { + "name": "votes_option_id_question_options_id_fk", + "tableFrom": "votes", + "tableTo": "question_options", + "columnsFrom": [ + "option_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "votes_question_id_forum_questions_id_fk": { + "name": "votes_question_id_forum_questions_id_fk", + "tableFrom": "votes", + "tableTo": "forum_questions", + "columnsFrom": [ + "question_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "registration_fields": { + "name": "registration_fields", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "event_id": { + "name": "event_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "varchar", + "primaryKey": false, + "notNull": true, + "default": "'TEXT'" + }, + "required": { + "name": "required", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "question_id": { + "name": "question_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "question_option_type": { + "name": "question_option_type", + "type": "varchar", + "primaryKey": false, + "notNull": false + }, + "fields_display_rank": { + "name": "fields_display_rank", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "character_limit": { + "name": "character_limit", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "for_group": { + "name": "for_group", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "for_user": { + "name": "for_user", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "registration_fields_event_id_events_id_fk": { + "name": "registration_fields_event_id_events_id_fk", + "tableFrom": "registration_fields", + "tableTo": "events", + "columnsFrom": [ + "event_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "registration_fields_question_id_forum_questions_id_fk": { + "name": "registration_fields_question_id_forum_questions_id_fk", + "tableFrom": "registration_fields", + "tableTo": "forum_questions", + "columnsFrom": [ + "question_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "registration_data": { + "name": "registration_data", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "registration_id": { + "name": "registration_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "registration_field_id": { + "name": "registration_field_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "registration_data_registration_id_registrations_id_fk": { + "name": "registration_data_registration_id_registrations_id_fk", + "tableFrom": "registration_data", + "tableTo": "registrations", + "columnsFrom": [ + "registration_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "registration_data_registration_field_id_registration_fields_id_fk": { + "name": "registration_data_registration_field_id_registration_fields_id_fk", + "tableFrom": "registration_data", + "tableTo": "registration_fields", + "columnsFrom": [ + "registration_field_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "users_to_groups": { + "name": "users_to_groups", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "group_id": { + "name": "group_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "group_category_id": { + "name": "group_category_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "users_to_groups_user_id_users_id_fk": { + "name": "users_to_groups_user_id_users_id_fk", + "tableFrom": "users_to_groups", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "users_to_groups_group_id_groups_id_fk": { + "name": "users_to_groups_group_id_groups_id_fk", + "tableFrom": "users_to_groups", + "tableTo": "groups", + "columnsFrom": [ + "group_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "users_to_groups_group_category_id_group_categories_id_fk": { + "name": "users_to_groups_group_category_id_group_categories_id_fk", + "tableFrom": "users_to_groups", + "tableTo": "group_categories", + "columnsFrom": [ + "group_category_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "user_attributes": { + "name": "user_attributes", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "attribute_key": { + "name": "attribute_key", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "attribute_value": { + "name": "attribute_value", + "type": "varchar", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "user_attributes_user_id_users_id_fk": { + "name": "user_attributes_user_id_users_id_fk", + "tableFrom": "user_attributes", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "likes": { + "name": "likes", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "comment_id": { + "name": "comment_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "likes_user_id_users_id_fk": { + "name": "likes_user_id_users_id_fk", + "tableFrom": "likes", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "likes_comment_id_comments_id_fk": { + "name": "likes_comment_id_comments_id_fk", + "tableFrom": "likes", + "tableTo": "comments", + "columnsFrom": [ + "comment_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "notification_types": { + "name": "notification_types", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "value": { + "name": "value", + "type": "varchar(256)", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "notification_types_value_unique": { + "name": "notification_types_value_unique", + "nullsNotDistinct": false, + "columns": [ + "value" + ] + } + } + }, + "users_to_notifications": { + "name": "users_to_notifications", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "notification_type_id": { + "name": "notification_type_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "active": { + "name": "active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "users_to_notifications_user_id_users_id_fk": { + "name": "users_to_notifications_user_id_users_id_fk", + "tableFrom": "users_to_notifications", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "users_to_notifications_notification_type_id_notification_types_id_fk": { + "name": "users_to_notifications_notification_type_id_notification_types_id_fk", + "tableFrom": "users_to_notifications", + "tableTo": "notification_types", + "columnsFrom": [ + "notification_type_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "questions_to_group_categories": { + "name": "questions_to_group_categories", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "question_id": { + "name": "question_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "group_category_id": { + "name": "group_category_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "questions_to_group_categories_question_id_forum_questions_id_fk": { + "name": "questions_to_group_categories_question_id_forum_questions_id_fk", + "tableFrom": "questions_to_group_categories", + "tableTo": "forum_questions", + "columnsFrom": [ + "question_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + }, + "questions_to_group_categories_group_category_id_group_categories_id_fk": { + "name": "questions_to_group_categories_group_category_id_group_categories_id_fk", + "tableFrom": "questions_to_group_categories", + "tableTo": "group_categories", + "columnsFrom": [ + "group_category_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": {}, + "schemas": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/migrations/meta/_journal.json b/migrations/meta/_journal.json index 8c821548..29a0acb2 100644 --- a/migrations/meta/_journal.json +++ b/migrations/meta/_journal.json @@ -106,6 +106,41 @@ "when": 1712178506955, "tag": "0014_foamy_monster_badoon", "breakpoints": true + }, + { + "idx": 15, + "version": "5", + "when": 1712769381020, + "tag": "0015_shiny_black_knight", + "breakpoints": true + }, + { + "idx": 16, + "version": "5", + "when": 1712848852970, + "tag": "0016_ambitious_rictor", + "breakpoints": true + }, + { + "idx": 17, + "version": "5", + "when": 1713192184507, + "tag": "0017_jazzy_revanche", + "breakpoints": true + }, + { + "idx": 18, + "version": "5", + "when": 1713278183377, + "tag": "0018_abandoned_mongoose", + "breakpoints": true + }, + { + "idx": 19, + "version": "5", + "when": 1713387423686, + "tag": "0019_nifty_wallow", + "breakpoints": true } ] } \ No newline at end of file diff --git a/package.json b/package.json index 77122ab6..c2f73c65 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "forum", - "version": "2.4.0", + "version": "2.5.0", "description": "", "main": "dist/index.js", "scripts": { diff --git a/scripts/db/insertCustomGroups.ts b/scripts/db/insertCustomGroups.ts deleted file mode 100644 index fc2eb5e3..00000000 --- a/scripts/db/insertCustomGroups.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { createDbPool } from '../../src/utils/db/createDbPool'; -import * as fs from 'fs'; -import csvParser from 'csv-parser'; -import { insertCustomGroups } from '../../src/utils/db/insertCustomGroups'; - -const DEFAULT_DB_CONNECTION_URL = 'postgresql://postgres:secretpassword@localhost:5432'; -const CSV_FILE_PATH = 'assets/groups.csv'; - -async function main() { - console.log(process.env.DB_CONNECTION_URL); - const dbConnectionUrl = process.env.DB_CONNECTION_URL ?? DEFAULT_DB_CONNECTION_URL; - const { dbPool, connection } = createDbPool(dbConnectionUrl, { max: 1 }); - - try { - const names: string[] = []; - try { - const stream = fs.createReadStream(CSV_FILE_PATH); - await new Promise((resolve, reject) => { - stream - .pipe(csvParser()) - .on('data', (row) => { - if (row.name) { - names.push(row.name.trim()); - } - }) - .on('end', () => { - console.log('Number of names:', names.length); - console.log('Names:', names); - resolve(); - }) - .on('error', (error) => { - reject(new Error(`Error reading CSV file: ${error}`)); - }); - }); - } catch (error) { - throw new Error(`Error processing CSV file: ${error}`); - } - - await insertCustomGroups(dbPool, names); - console.log('Inserted groups into the database'); - } catch (error) { - console.error('Error processing groups:', error); - } finally { - await connection.end(); - } -} - -main() - .then(() => process.exit(0)) - .catch((error) => { - console.error('Error seeding database:', error); - process.exit(1); - }); diff --git a/src/db/alerts.ts b/src/db/alerts.ts new file mode 100644 index 00000000..5ed0c07d --- /dev/null +++ b/src/db/alerts.ts @@ -0,0 +1,15 @@ +import { boolean, pgTable, timestamp, uuid, varchar } from 'drizzle-orm/pg-core'; + +export const alerts = pgTable('alerts', { + id: uuid('id').primaryKey().defaultRandom(), + title: varchar('title', { length: 256 }).notNull(), + description: varchar('description', { length: 1024 }), + link: varchar('link', { length: 256 }), + startAt: timestamp('start_at'), + endAt: timestamp('end_at'), + active: boolean('active').default(false), + createdAt: timestamp('created_at').notNull().defaultNow(), + updatedAt: timestamp('updated_at').notNull().defaultNow(), +}); + +export type Alert = typeof alerts.$inferSelect; diff --git a/src/db/forumQuestions.ts b/src/db/forumQuestions.ts index bbc6d39e..c9602aba 100644 --- a/src/db/forumQuestions.ts +++ b/src/db/forumQuestions.ts @@ -2,6 +2,7 @@ import { pgTable, timestamp, uuid, varchar } from 'drizzle-orm/pg-core'; import { cycles } from './cycles'; import { relations } from 'drizzle-orm'; import { questionOptions } from './questionOptions'; +import { questionsToGroupCategories } from './questionsToGroupCategories'; export const forumQuestions = pgTable('forum_questions', { id: uuid('id').primaryKey().defaultRandom(), @@ -20,6 +21,7 @@ export const forumQuestionsRelations = relations(forumQuestions, ({ one, many }) references: [cycles.id], }), questionOptions: many(questionOptions), + questionsToGroupCategories: many(questionsToGroupCategories), })); export type ForumQuestion = typeof forumQuestions.$inferSelect; diff --git a/src/db/groupCategories.ts b/src/db/groupCategories.ts index 32369144..5e5bbc73 100644 --- a/src/db/groupCategories.ts +++ b/src/db/groupCategories.ts @@ -1,13 +1,16 @@ -import { pgTable, timestamp, uuid, varchar } from 'drizzle-orm/pg-core'; +import { pgTable, timestamp, uuid, varchar, boolean } from 'drizzle-orm/pg-core'; import { events } from './events'; import { groups } from './groups'; import { usersToGroups } from './usersToGroups'; import { relations } from 'drizzle-orm'; +import { questionsToGroupCategories } from './questionsToGroupCategories'; export const groupCategories = pgTable('group_categories', { id: uuid('id').primaryKey().defaultRandom(), name: varchar('name'), eventId: uuid('event_id').references(() => events.id), + userCanCreate: boolean('user_can_create').notNull().default(false), + userCanView: boolean('user_can_view').notNull().default(false), createdAt: timestamp('created_at').notNull().defaultNow(), updatedAt: timestamp('updated_at').notNull().defaultNow(), }); @@ -19,6 +22,7 @@ export const groupCategoriesRelations = relations(groupCategories, ({ one, many }), group: many(groups), usersToGroup: many(usersToGroups), + questionsToGroupCategories: many(questionsToGroupCategories), })); export type GroupCategory = typeof groupCategories.$inferSelect; diff --git a/src/db/groups.ts b/src/db/groups.ts index fd4e469b..708dbb0a 100644 --- a/src/db/groups.ts +++ b/src/db/groups.ts @@ -2,11 +2,13 @@ import { relations } from 'drizzle-orm'; import { pgTable, timestamp, uuid, varchar } from 'drizzle-orm/pg-core'; import { usersToGroups } from './usersToGroups'; import { groupCategories } from './groupCategories'; +import { registrations } from './registrations'; export const groups = pgTable('groups', { id: uuid('id').primaryKey().defaultRandom(), name: varchar('name', { length: 256 }).notNull(), description: varchar('description', { length: 256 }), + secret: varchar('secret', { length: 256 }).unique(), groupCategoryId: uuid('group_category_id').references(() => groupCategories.id), createdAt: timestamp('created_at').notNull().defaultNow(), updatedAt: timestamp('updated_at').notNull().defaultNow(), @@ -17,6 +19,7 @@ export const groupsRelations = relations(groups, ({ one, many }) => ({ fields: [groups.groupCategoryId], references: [groupCategories.id], }), + registrations: many(registrations), usersToGroups: many(usersToGroups), })); diff --git a/src/db/index.ts b/src/db/index.ts index 654193d3..c45e57b0 100644 --- a/src/db/index.ts +++ b/src/db/index.ts @@ -17,3 +17,5 @@ export * from './likes'; export * from './notificationTypes'; export * from './usersToNotifications'; export * from './groupCategories'; +export * from './questionsToGroupCategories'; +export * from './alerts'; diff --git a/src/db/questionsToGroupCategories.ts b/src/db/questionsToGroupCategories.ts new file mode 100644 index 00000000..c2abfb90 --- /dev/null +++ b/src/db/questionsToGroupCategories.ts @@ -0,0 +1,30 @@ +import { pgTable, timestamp, uuid } from 'drizzle-orm/pg-core'; +import { relations } from 'drizzle-orm'; +import { groupCategories } from './groupCategories'; +import { forumQuestions } from './forumQuestions'; + +export const questionsToGroupCategories = pgTable('questions_to_group_categories', { + id: uuid('id').primaryKey().defaultRandom(), + questionId: uuid('question_id') + .notNull() + .references(() => forumQuestions.id), + groupCategoryId: uuid('group_category_id').references(() => groupCategories.id), // Must be nullable (for now) because affiliation does not have a group category id. + createdAt: timestamp('created_at').notNull().defaultNow(), + updatedAt: timestamp('updated_at').notNull().defaultNow(), +}); + +export const questionsToGroupCategoriesRelations = relations( + questionsToGroupCategories, + ({ one }) => ({ + question: one(forumQuestions, { + fields: [questionsToGroupCategories.questionId], + references: [forumQuestions.id], + }), + groupCategory: one(groupCategories, { + fields: [questionsToGroupCategories.groupCategoryId], + references: [groupCategories.id], + }), + }), +); + +export type QuestionsToGroupCategories = typeof questionsToGroupCategories.$inferSelect; diff --git a/src/db/registrationFields.ts b/src/db/registrationFields.ts index d38633cb..1446fb45 100644 --- a/src/db/registrationFields.ts +++ b/src/db/registrationFields.ts @@ -17,6 +17,8 @@ export const registrationFields = pgTable('registration_fields', { questionOptionType: varchar('question_option_type'), fieldDisplayRank: integer('fields_display_rank'), characterLimit: integer('character_limit').default(0), + forGroup: boolean('for_group').default(false), + forUser: boolean('for_user').default(true), createdAt: timestamp('created_at').notNull().defaultNow(), updatedAt: timestamp('updated_at').notNull().defaultNow(), }); diff --git a/src/db/registrations.ts b/src/db/registrations.ts index 26107c41..143242f8 100644 --- a/src/db/registrations.ts +++ b/src/db/registrations.ts @@ -3,6 +3,7 @@ import { pgTable, timestamp, uuid, varchar } from 'drizzle-orm/pg-core'; import { events } from './events'; import { registrationData } from './registrationData'; import { users } from './users'; +import { groups } from './groups'; export const registrations = pgTable('registrations', { id: uuid('id').primaryKey().defaultRandom(), @@ -12,6 +13,7 @@ export const registrations = pgTable('registrations', { eventId: uuid('event_id') .references(() => events.id) .notNull(), + groupId: uuid('group_id').references(() => groups.id), // CAN BE: DRAFT, APPROVED, REJECTED AND MORE status: varchar('status').default('DRAFT'), createdAt: timestamp('created_at').notNull().defaultNow(), @@ -27,6 +29,10 @@ export const registrationsRelations = relations(registrations, ({ one, many }) = fields: [registrations.eventId], references: [events.id], }), + group: one(groups, { + fields: [registrations.groupId], + references: [groups.id], + }), registrationData: many(registrationData), })); diff --git a/src/handlers/alerts.ts b/src/handlers/alerts.ts new file mode 100644 index 00000000..f09d226a --- /dev/null +++ b/src/handlers/alerts.ts @@ -0,0 +1,22 @@ +import { PostgresJsDatabase } from 'drizzle-orm/postgres-js'; +import type { Request, Response } from 'express'; +import * as db from '../db'; +import { and, eq, gte, lte, or } from 'drizzle-orm'; + +export function getActiveAlerts(dbPool: PostgresJsDatabase) { + return async function (req: Request, res: Response) { + try { + const alerts = await dbPool.query.alerts.findMany({ + where: or( + eq(db.alerts.active, true), + and(lte(db.alerts.startAt, new Date()), gte(db.alerts.endAt, new Date())), + ), + }); + + return res.json({ data: alerts }); + } catch (e) { + console.error(`[ERROR] ${JSON.stringify(e)}`); + return res.sendStatus(500); + } + }; +} diff --git a/src/handlers/events.ts b/src/handlers/events.ts index d55f0718..d0575f0b 100644 --- a/src/handlers/events.ts +++ b/src/handlers/events.ts @@ -2,9 +2,6 @@ import { and, eq } from 'drizzle-orm'; import { PostgresJsDatabase } from 'drizzle-orm/postgres-js'; import type { Request, Response } from 'express'; import * as db from '../db'; -import { insertRegistrationSchema } from '../types'; -import { validateRequiredRegistrationFields } from '../services/registrationFields'; -import { saveEventRegistration } from '../services/registrations'; export function getEventCyclesHandler(dbPool: PostgresJsDatabase) { return async function (req: Request, res: Response) { @@ -69,84 +66,21 @@ export function getEventRegistrationFieldsHandler(dbPool: PostgresJsDatabase eq(fields.id, eventId), + where: eq(db.events.id, eventId), }); return res.json({ data: event?.registrationFields }); }; } -export function getEventRegistrationDataHandler(dbPool: PostgresJsDatabase) { - return async function (req: Request, res: Response) { - const eventId = req.params.eventId; - const userId = req.session.userId; - if (!userId) { - return res.status(400).json({ errors: ['userId is required'] }); - } - - if (!eventId) { - return res.status(400).json({ errors: ['eventId is required'] }); - } - - try { - const event = await dbPool.query.events.findFirst({ - with: { - registrations: { - with: { - registrationData: true, - }, - where: (fields, { eq }) => eq(fields.userId, userId), - }, - }, - where: (fields, { eq }) => eq(fields.id, eventId), - }); - - const out = event?.registrations.map((registration) => registration.registrationData).flat(); - - return res.json({ data: out }); - } catch (e) { - return res.status(500).json({ errors: ['Failed to get registration data'] }); - } - }; -} - -export function saveEventRegistrationHandler(dbPool: PostgresJsDatabase) { - return async function (req: Request, res: Response) { - // parse input - const eventId = req.params.eventId; - const userId = req.session.userId; - req.body.userId = userId; - req.body.eventId = eventId; - const body = insertRegistrationSchema.safeParse(req.body); - - if (!body.success) { - return res.status(400).json({ errors: body.error.issues }); - } - - const missingRequiredFields = await validateRequiredRegistrationFields(dbPool, body.data); - - if (missingRequiredFields.length > 0) { - return res.status(400).json({ errors: missingRequiredFields }); - } - - try { - const out = await saveEventRegistration(dbPool, body.data, userId); - return res.json({ data: out }); - } catch (e) { - console.log('error saving registration ' + e); - return res.sendStatus(500); - } - }; -} - -export function getEventRegistrationHandler(dbPool: PostgresJsDatabase) { +export function getEventRegistrationsHandler(dbPool: PostgresJsDatabase) { return async function (req: Request, res: Response) { // parse input const eventId = req.params.eventId ?? ''; const userId = req.session.userId; try { - const out = await dbPool.query.registrations.findFirst({ + const out = await dbPool.query.registrations.findMany({ where: and(eq(db.registrations.userId, userId), eq(db.registrations.eventId, eventId)), }); diff --git a/src/handlers/groupCategories.ts b/src/handlers/groupCategories.ts new file mode 100644 index 00000000..fd806b33 --- /dev/null +++ b/src/handlers/groupCategories.ts @@ -0,0 +1,68 @@ +import { PostgresJsDatabase } from 'drizzle-orm/postgres-js'; +import type { Request, Response } from 'express'; +import * as db from '../db'; +import { and, eq } from 'drizzle-orm'; +import { canViewGroupsInGroupCategory } from '../services/groupCategories'; + +export function getGroupCategoriesHandler(dbPool: PostgresJsDatabase) { + return async function (req: Request, res: Response) { + const groupCategories = await dbPool.query.groupCategories.findMany(); + return res.json({ data: groupCategories }); + }; +} + +export function getGroupCategoryHandler(dbPool: PostgresJsDatabase) { + return async function (req: Request, res: Response) { + const groupCategoryId = req.params.id; + + if (!groupCategoryId) { + return res.status(400).json({ error: 'Group Category ID is required' }); + } + + const groupCategory = await dbPool.query.groupCategories.findFirst({ + where: and(eq(db.groupCategories.id, groupCategoryId)), + }); + + return res.json({ data: groupCategory }); + }; +} + +export function getGroupCategoriesGroupsHandler(dbPool: PostgresJsDatabase) { + return async function (req: Request, res: Response) { + const groupCategoryName = req.params.name; + + if (!groupCategoryName) { + return res.status(400).json({ error: 'Group Category Name is required' }); + } + + const groupCategory = await dbPool.query.groupCategories.findFirst({ + where: eq(db.groupCategories.name, groupCategoryName), + }); + + if (!groupCategory) { + return res.status(404).json({ error: 'Group Category not found' }); + } + + const canView = await canViewGroupsInGroupCategory(dbPool, groupCategory.id); + + if (!canView) { + return res + .status(403) + .json({ error: 'You do not have permission to view this group category' }); + } + + const groups = await dbPool.query.groups.findMany({ + where: eq(db.groups.groupCategoryId, groupCategory.id), + columns: { + createdAt: true, + description: true, + groupCategoryId: true, + id: true, + name: true, + updatedAt: true, + }, + }); + + return res.json({ data: groups }); + }; +} diff --git a/src/handlers/groups.ts b/src/handlers/groups.ts index 42bcb8dd..0cc79a9e 100644 --- a/src/handlers/groups.ts +++ b/src/handlers/groups.ts @@ -1,14 +1,61 @@ import { PostgresJsDatabase } from 'drizzle-orm/postgres-js'; import type { Request, Response } from 'express'; import * as db from '../db'; -/** - * Retrieves all groups from the database. - * @param dbPool The database connection pool. - * @returns An asynchronous function that handles the HTTP request and response. - */ -export function getGroupsHandler(dbPool: PostgresJsDatabase) { +import { eq } from 'drizzle-orm'; +import { insertGroupsSchema } from '../types/groups'; +import { canCreateGroupInGroupCategory } from '../services/groupCategories'; +import { createSecretGroup } from '../services/groups'; +import { upsertUsersToGroups } from '../services/usersToGroups'; + +export function getGroupRegistrationsHandler(dbPool: PostgresJsDatabase) { return async function (req: Request, res: Response) { - const groups = await dbPool.query.groups.findMany(); - return res.json({ data: groups }); + const groupId = req.params.id; + + if (!groupId) { + return res.status(400).json({ error: 'Group ID is required' }); + } + + const registrations = await dbPool.query.registrations.findMany({ + where: eq(db.registrations.groupId, groupId), + }); + + return res.json({ data: registrations }); + }; +} + +export function createGroupHandler(dbPool: PostgresJsDatabase) { + return async function (req: Request, res: Response) { + const userId = req.session.userId; + const body = insertGroupsSchema.safeParse(req.body); + + if (!body.success) { + return res.status(400).json({ errors: body.error.errors }); + } + + try { + const canCreateGroup = await canCreateGroupInGroupCategory( + dbPool, + body.data.groupCategoryId!, + ); + + if (!canCreateGroup) { + return res + .status(403) + .json({ error: 'You do not have permission to create a group in this category' }); + } + + const newGroupRows = await createSecretGroup(dbPool, body.data); + + if (!newGroupRows || !newGroupRows[0]) { + return res.status(500).json({ error: 'An error occurred while creating the group' }); + } + + // assign user to new group + await upsertUsersToGroups(dbPool, userId, [newGroupRows[0].id]); + + return res.json({ data: newGroupRows[0] }); + } catch (error) { + return res.status(500).json({ error: 'An error occurred while creating the group' }); + } }; } diff --git a/src/handlers/registrations.ts b/src/handlers/registrations.ts new file mode 100644 index 00000000..c0904170 --- /dev/null +++ b/src/handlers/registrations.ts @@ -0,0 +1,136 @@ +import { PostgresJsDatabase } from 'drizzle-orm/postgres-js'; +import type { Request, Response } from 'express'; +import * as db from '../db'; +import { insertRegistrationSchema } from '../types'; +import { validateRequiredRegistrationFields } from '../services/registrationFields'; +import { + saveRegistration, + updateRegistration, + validateCreateRegistrationPermissions, + validateUpdateRegistrationPermissions, +} from '../services/registrations'; +import { and, eq } from 'drizzle-orm'; + +export function getRegistrationDataHandler(dbPool: PostgresJsDatabase) { + return async function (req: Request, res: Response) { + const registrationId = req.params.id; + const userId = req.session.userId; + if (!userId) { + return res.status(400).json({ errors: ['userId is required'] }); + } + + if (!registrationId) { + return res.status(400).json({ errors: ['registrationId is required'] }); + } + + try { + const registration = await dbPool.query.registrations.findFirst({ + with: { + registrationData: true, + }, + where: and(eq(db.registrations.userId, userId), eq(db.registrations.id, registrationId)), + }); + + const out = [...(registration?.registrationData ?? [])]; + + return res.json({ data: out }); + } catch (e) { + return res.status(500).json({ errors: ['Failed to get registration data'] }); + } + }; +} + +export function saveRegistrationHandler(dbPool: PostgresJsDatabase) { + return async function (req: Request, res: Response) { + const userId = req.session.userId; + req.body.userId = userId; + const body = insertRegistrationSchema.safeParse(req.body); + + if (!body.success) { + return res.status(400).json({ errors: body.error.issues }); + } + + const missingRequiredFields = await validateRequiredRegistrationFields({ + dbPool, + data: body.data, + forGroup: !!body.data.groupId, + forUser: !body.data.groupId, + }); + + if (missingRequiredFields.length > 0) { + return res.status(400).json({ errors: missingRequiredFields }); + } + + const canRegisterGroup = await validateCreateRegistrationPermissions({ + dbPool, + userId, + eventId: body.data.eventId, + groupId: body.data.groupId, + }); + + if (!canRegisterGroup) { + return res.status(400).json({ errors: ['Cannot register for this group'] }); + } + + try { + const out = await saveRegistration(dbPool, body.data, userId); + return res.json({ data: out }); + } catch (e) { + console.log('error saving registration ' + e); + return res.sendStatus(500); + } + }; +} + +export function updateRegistrationHandler(dbPool: PostgresJsDatabase) { + return async function (req: Request, res: Response) { + const registrationId = req.params.id; + + if (!registrationId) { + return res.status(400).json({ errors: ['registrationId is required'] }); + } + + const userId = req.session.userId; + req.body.userId = userId; + const body = insertRegistrationSchema.safeParse(req.body); + + if (!body.success) { + return res.status(400).json({ errors: body.error.issues }); + } + + const missingRequiredFields = await validateRequiredRegistrationFields({ + dbPool, + data: body.data, + forGroup: !!body.data.groupId, + forUser: !body.data.groupId, + }); + + if (missingRequiredFields.length > 0) { + return res.status(400).json({ errors: missingRequiredFields }); + } + + const canUpdateRegistration = await validateUpdateRegistrationPermissions({ + dbPool, + registrationId, + userId, + groupId: body.data.groupId, + }); + + if (!canUpdateRegistration) { + return res.status(400).json({ errors: ['Cannot update this registration'] }); + } + + try { + const out = await updateRegistration({ + data: body.data, + dbPool, + registrationId, + userId, + }); + return res.json({ data: out }); + } catch (e) { + console.log('error saving registration ' + e); + return res.sendStatus(500); + } + }; +} diff --git a/src/handlers/users.ts b/src/handlers/users.ts index ec149464..bcd28504 100644 --- a/src/handlers/users.ts +++ b/src/handlers/users.ts @@ -95,7 +95,11 @@ export function getUserGroupsHandler(dbPool: PostgresJsDatabase) { try { const query = await dbPool.query.usersToGroups.findMany({ with: { - group: true, + group: { + with: { + groupCategory: true, + }, + }, }, where: eq(db.usersToGroups.userId, userId), }); diff --git a/src/handlers/usersToGroups.ts b/src/handlers/usersToGroups.ts new file mode 100644 index 00000000..02ce05e7 --- /dev/null +++ b/src/handlers/usersToGroups.ts @@ -0,0 +1,54 @@ +import { PostgresJsDatabase } from 'drizzle-orm/postgres-js'; +import type { Request, Response } from 'express'; +import * as db from '../db'; +import { joinGroupsSchema } from '../types/usersToGroups'; +import { getSecretGroup } from '../services/groups'; +import { upsertUsersToGroups } from '../services/usersToGroups'; +import { eq } from 'drizzle-orm'; + +export function joinGroupsHandler(dbPool: PostgresJsDatabase) { + return async (req: Request, res: Response) => { + const userId = req.session.userId; + const body = joinGroupsSchema.safeParse(req.body); + + // does not have secret nor id + if (!body.success) { + return res.status(400).json({ errors: body.error.errors }); + } + + try { + // public group + if ('groupId' in body.data) { + const group = await dbPool.query.groups.findFirst({ + where: eq(db.groups.id, body.data.groupId), + }); + + if (!group) { + return res.status(404).json({ error: 'Group not found' }); + } + + if (group.secret) { + return res.status(400).json({ error: 'Group is secret' }); + } + + const userToGroup = await upsertUsersToGroups(dbPool, userId, [body.data.groupId]); + + return res.json({ data: userToGroup }); + } + + // secret group + const secretGroup = await getSecretGroup(dbPool, body.data.secret); + + if (!secretGroup) { + return res.status(404).json({ error: 'Group not found' }); + } + + const userToGroup = await upsertUsersToGroups(dbPool, userId, [secretGroup.id]); + + return res.json({ data: userToGroup }); + } catch (e) { + console.error(e); + return res.status(500).json({ error: 'An error occurred while joining the group' }); + } + }; +} diff --git a/src/routers/alerts.ts b/src/routers/alerts.ts new file mode 100644 index 00000000..3b8737a9 --- /dev/null +++ b/src/routers/alerts.ts @@ -0,0 +1,11 @@ +import type { PostgresJsDatabase } from 'drizzle-orm/postgres-js'; +import { default as express } from 'express'; +import type * as db from '../db'; +import { getActiveAlerts } from '../handlers/alerts'; +import { isLoggedIn } from '../middleware/isLoggedIn'; +const router = express.Router(); + +export function alertsRouter({ dbPool }: { dbPool: PostgresJsDatabase }) { + router.get('/', isLoggedIn(dbPool), getActiveAlerts(dbPool)); + return router; +} diff --git a/src/routers/api.ts b/src/routers/api.ts index cfdd6fba..b8441be8 100644 --- a/src/routers/api.ts +++ b/src/routers/api.ts @@ -12,6 +12,10 @@ import { groupsRouter } from './groups'; import { commentsRouter } from './comments'; import { optionsRouter } from './options'; import { votesRouter } from './votes'; +import { registrationsRouter } from './registrations'; +import { usersToGroupsRouter } from './usersToGroups'; +import { groupCategoriesRouter } from './groupCategories'; +import { alertsRouter } from './alerts'; const router = express.Router(); @@ -54,6 +58,10 @@ export function apiRouter({ router.use('/groups', groupsRouter({ dbPool })); router.use('/comments', commentsRouter({ dbPool })); router.use('/options', optionsRouter({ dbPool })); + router.use('/group-categories', groupCategoriesRouter({ dbPool })); + router.use('/registrations', registrationsRouter({ dbPool })); + router.use('/users-to-groups', usersToGroupsRouter({ dbPool })); + router.use('/alerts', alertsRouter({ dbPool })); return router; } diff --git a/src/routers/events.ts b/src/routers/events.ts index 5bdf4667..978b245d 100644 --- a/src/routers/events.ts +++ b/src/routers/events.ts @@ -5,11 +5,9 @@ import { isLoggedIn } from '../middleware/isLoggedIn'; import { getEventCyclesHandler, getEventHandler, - getEventRegistrationDataHandler, getEventRegistrationFieldsHandler, - getEventRegistrationHandler, + getEventRegistrationsHandler, getEventsHandler, - saveEventRegistrationHandler, } from '../handlers/events'; const router = express.Router(); @@ -21,13 +19,7 @@ export function eventsRouter({ dbPool }: { dbPool: PostgresJsDatabase isLoggedIn(dbPool), getEventRegistrationFieldsHandler(dbPool), ); - router.get( - '/:eventId/registration-data', - isLoggedIn(dbPool), - getEventRegistrationDataHandler(dbPool), - ); router.get('/:eventId/cycles', isLoggedIn(dbPool), getEventCyclesHandler(dbPool)); - router.post('/:eventId/registration', isLoggedIn(dbPool), saveEventRegistrationHandler(dbPool)); - router.get('/:eventId/registration', isLoggedIn(dbPool), getEventRegistrationHandler(dbPool)); + router.get('/:eventId/registrations', isLoggedIn(dbPool), getEventRegistrationsHandler(dbPool)); return router; } diff --git a/src/routers/groupCategories.ts b/src/routers/groupCategories.ts new file mode 100644 index 00000000..71422b98 --- /dev/null +++ b/src/routers/groupCategories.ts @@ -0,0 +1,19 @@ +import type { PostgresJsDatabase } from 'drizzle-orm/postgres-js'; +import { default as express } from 'express'; +import type * as db from '../db'; +import { isLoggedIn } from '../middleware/isLoggedIn'; +import { + getGroupCategoriesGroupsHandler, + getGroupCategoriesHandler, + getGroupCategoryHandler, +} from '../handlers/groupCategories'; + +const router = express.Router(); + +export function groupCategoriesRouter({ dbPool }: { dbPool: PostgresJsDatabase }) { + router.get('/', isLoggedIn(dbPool), getGroupCategoriesHandler(dbPool)); + router.get('/:id', isLoggedIn(dbPool), getGroupCategoryHandler(dbPool)); + router.get('/:name/groups', isLoggedIn(dbPool), getGroupCategoriesGroupsHandler(dbPool)); + + return router; +} diff --git a/src/routers/groups.ts b/src/routers/groups.ts index 26358955..4e158dbb 100644 --- a/src/routers/groups.ts +++ b/src/routers/groups.ts @@ -2,10 +2,12 @@ import type { PostgresJsDatabase } from 'drizzle-orm/postgres-js'; import { default as express } from 'express'; import type * as db from '../db'; import { isLoggedIn } from '../middleware/isLoggedIn'; -import { getGroupsHandler } from '../handlers/groups'; +import { createGroupHandler, getGroupRegistrationsHandler } from '../handlers/groups'; const router = express.Router(); export function groupsRouter({ dbPool }: { dbPool: PostgresJsDatabase }) { - router.get('/', isLoggedIn(dbPool), getGroupsHandler(dbPool)); + router.post('/', isLoggedIn(dbPool), createGroupHandler(dbPool)); + router.get('/:id/registrations', isLoggedIn(dbPool), getGroupRegistrationsHandler(dbPool)); + return router; } diff --git a/src/routers/registrations.ts b/src/routers/registrations.ts new file mode 100644 index 00000000..7eaea8d8 --- /dev/null +++ b/src/routers/registrations.ts @@ -0,0 +1,19 @@ +import type { PostgresJsDatabase } from 'drizzle-orm/postgres-js'; +import { default as express } from 'express'; +import type * as db from '../db'; +import { isLoggedIn } from '../middleware/isLoggedIn'; +import { + getRegistrationDataHandler, + saveRegistrationHandler, + updateRegistrationHandler, +} from '../handlers/registrations'; + +const router = express.Router(); + +export function registrationsRouter({ dbPool }: { dbPool: PostgresJsDatabase }) { + router.post('/', isLoggedIn(dbPool), saveRegistrationHandler(dbPool)); + router.put('/:id', isLoggedIn(dbPool), updateRegistrationHandler(dbPool)); + router.get('/:id/registration-data', isLoggedIn(dbPool), getRegistrationDataHandler(dbPool)); + + return router; +} diff --git a/src/routers/usersToGroups.ts b/src/routers/usersToGroups.ts new file mode 100644 index 00000000..25fd87b9 --- /dev/null +++ b/src/routers/usersToGroups.ts @@ -0,0 +1,12 @@ +import type { PostgresJsDatabase } from 'drizzle-orm/postgres-js'; +import { default as express } from 'express'; +import type * as db from '../db'; +import { isLoggedIn } from '../middleware/isLoggedIn'; +import { joinGroupsHandler } from '../handlers/usersToGroups'; + +const router = express.Router(); + +export function usersToGroupsRouter({ dbPool }: { dbPool: PostgresJsDatabase }) { + router.post('/', isLoggedIn(dbPool), joinGroupsHandler(dbPool)); + return router; +} diff --git a/src/services/groupCategories.spec.ts b/src/services/groupCategories.spec.ts new file mode 100644 index 00000000..a74ad8aa --- /dev/null +++ b/src/services/groupCategories.spec.ts @@ -0,0 +1,90 @@ +import { PostgresJsDatabase } from 'drizzle-orm/postgres-js'; +import postgres from 'postgres'; +import * as db from '../db'; +import { createDbPool } from '../utils/db/createDbPool'; +import { runMigrations } from '../utils/db/runMigrations'; +import { cleanup, seed } from '../utils/db/seed'; +import { canCreateGroupInGroupCategory, canViewGroupsInGroupCategory } from './groupCategories'; +import { eq } from 'drizzle-orm'; + +const DB_CONNECTION_URL = 'postgresql://postgres:secretpassword@localhost:5432'; + +describe('service: groupCategories', () => { + let dbPool: PostgresJsDatabase; + let dbConnection: postgres.Sql>; + let groupCategory: db.GroupCategory | undefined; + + beforeAll(async () => { + const initDb = createDbPool(DB_CONNECTION_URL, { max: 1 }); + await runMigrations(DB_CONNECTION_URL); + dbPool = initDb.dbPool; + dbConnection = initDb.connection; + // seed + const { groupCategories } = await seed(dbPool); + + groupCategory = groupCategories[0]; + }); + + describe('check if user can create group in category:', function () { + test('default:', async function () { + if (!groupCategory) { + throw new Error('Group category not found'); + } + + const canCreate = await canCreateGroupInGroupCategory(dbPool, groupCategory.id); + + expect(canCreate).toBe(false); + }); + + test('userCanCreate: true', async function () { + if (!groupCategory) { + throw new Error('Group category not found'); + } + + await dbPool + .update(db.groupCategories) + .set({ userCanCreate: true }) + .where(eq(db.groupCategories.id, groupCategory.id)); + + const canCreate = await canCreateGroupInGroupCategory(dbPool, groupCategory.id); + + expect(canCreate).toBe(true); + }); + }); + + describe('check if user can view group category', function () { + test('userCanView: false', async function () { + if (!groupCategory) { + throw new Error('Group category not found'); + } + + await dbPool + .update(db.groupCategories) + .set({ userCanView: false }) + .where(eq(db.groupCategories.id, groupCategory.id)); + + const canView = await canViewGroupsInGroupCategory(dbPool, groupCategory.id); + + expect(canView).toBe(false); + }); + test('userCanView: true', async function () { + if (!groupCategory) { + throw new Error('Group category not found'); + } + + await dbPool + .update(db.groupCategories) + .set({ userCanView: true }) + .where(eq(db.groupCategories.id, groupCategory.id)); + + const canView = await canViewGroupsInGroupCategory(dbPool, groupCategory.id); + + expect(canView).toBe(true); + }); + }); + + afterAll(async () => { + await cleanup(dbPool); + await dbConnection.end(); + }); +}); diff --git a/src/services/groupCategories.ts b/src/services/groupCategories.ts new file mode 100644 index 00000000..39b3a60f --- /dev/null +++ b/src/services/groupCategories.ts @@ -0,0 +1,32 @@ +import type { PostgresJsDatabase } from 'drizzle-orm/postgres-js'; +import * as db from '../db'; + +export async function canCreateGroupInGroupCategory( + dbPool: PostgresJsDatabase, + groupCategoryId: string, +) { + const groupCategory = await dbPool.query.groupCategories.findFirst({ + where: (fields, { eq }) => eq(fields.id, groupCategoryId), + }); + + if (!groupCategory) { + return false; + } + + return groupCategory.userCanCreate; +} + +export async function canViewGroupsInGroupCategory( + dbPool: PostgresJsDatabase, + groupCategoryId: string, +) { + const groupCategory = await dbPool.query.groupCategories.findFirst({ + where: (fields, { eq }) => eq(fields.id, groupCategoryId), + }); + + if (!groupCategory) { + return false; + } + + return groupCategory.userCanView; +} diff --git a/src/services/groups.spec.ts b/src/services/groups.spec.ts new file mode 100644 index 00000000..49fca9b1 --- /dev/null +++ b/src/services/groups.spec.ts @@ -0,0 +1,65 @@ +import { PostgresJsDatabase } from 'drizzle-orm/postgres-js'; +import postgres from 'postgres'; +import * as db from '../db'; +import { createDbPool } from '../utils/db/createDbPool'; +import { runMigrations } from '../utils/db/runMigrations'; +import { cleanup } from '../utils/db/seed'; +import { createSecretGroup, generateSecret, getSecretGroup } from './groups'; + +const DB_CONNECTION_URL = 'postgresql://postgres:secretpassword@localhost:5432'; + +describe('service: groups', () => { + let dbPool: PostgresJsDatabase; + let dbConnection: postgres.Sql>; + + beforeAll(async () => { + const initDb = createDbPool(DB_CONNECTION_URL, { max: 1 }); + await runMigrations(DB_CONNECTION_URL); + dbPool = initDb.dbPool; + dbConnection = initDb.connection; + }); + + test('generate secret:', async function () { + const secret = generateSecret(); + expect(secret).toHaveLength(12); + }); + + test('generate multiple secrets:', async function () { + const secrets = Array.from({ length: 10 }, () => generateSecret()); + + expect(secrets).toHaveLength(10); + expect(secrets).toEqual(expect.arrayContaining(secrets)); + // none should be the same + expect(new Set(secrets).size).toBe(secrets.length); + }); + + test('create a group:', async function () { + const rows = await createSecretGroup(dbPool, { + name: 'Test Group', + description: 'Test Description', + }); + + expect(rows).toHaveLength(1); + expect(rows[0]?.name).toBe('Test Group'); + expect(rows[0]?.description).toBe('Test Description'); + // secret should be generated + expect(rows[0]?.secret).toHaveLength(12); + }); + + test('get a group:', async function () { + const rows = await createSecretGroup(dbPool, { + name: 'Test Group', + description: 'Test Description', + }); + + const group = await getSecretGroup(dbPool, rows[0]?.secret ?? ''); + + expect(group?.name).toBe('Test Group'); + expect(group?.description).toBe('Test Description'); + }); + + afterAll(async () => { + await cleanup(dbPool); + await dbConnection.end(); + }); +}); diff --git a/src/services/groups.ts b/src/services/groups.ts index af813271..7dc52ff5 100644 --- a/src/services/groups.ts +++ b/src/services/groups.ts @@ -1,70 +1,34 @@ import type { PostgresJsDatabase } from 'drizzle-orm/postgres-js'; import * as db from '../db'; -import type { Request, Response } from 'express'; -import { eq } from 'drizzle-orm'; +import { z } from 'zod'; +import { insertGroupsSchema } from '../types/groups'; +import { randomBytes } from 'crypto'; -/** - * Retrieves groups by a specified group Category ID. - * @param dbPool The database connection pool. - * @returns An asynchronous function that handles the HTTP request and response. - */ -export function getGroupsByCategoryId(dbPool: PostgresJsDatabase) { - return async function (req: Request, res: Response) { - const groupCategoryId = req.params.groupCategoryId; - if (!groupCategoryId) { - return res.status(400).json({ error: 'groupCategoryId parameter is missing' }); - } - try { - const groupByCategoryId = await dbPool.query.groups.findMany({ - where: eq(db.groups.groupCategoryId, groupCategoryId), - }); - return res.json({ data: groupByCategoryId }); - } catch (e) { - console.error('error getting groups by Category id ' + JSON.stringify(e)); - return res.status(500).json({ error: 'internal server error' }); - } - }; -} - -/** - * Retrieves groups associated with a specific user filtered by a group Category ID. - * @param dbPool The database connection pool. - * @returns An asynchronous function that handles the HTTP request and response. - */ -export function getGroupsPerUserByCategoryId(dbPool: PostgresJsDatabase) { - return async function (req: Request, res: Response) { - const paramsUserId = req.params.userId; - const userId = req.session.userId; - const groupCategoryId = req.params.groupCategoryId; +export function createSecretGroup( + dbPool: PostgresJsDatabase, + body: z.infer, +) { + const secret = generateSecret(); - if (paramsUserId !== userId) { - return res.status(403).json({ errors: ['forbidden'] }); - } - if (!groupCategoryId) { - return res.status(400).json({ error: 'groupCategoryId parameter is missing' }); - } + const rows = dbPool + .insert(db.groups) + .values({ + ...body, + secret, + }) + .returning(); - try { - // Fetch all groups associated with the user - const userGroups = await dbPool.query.usersToGroups.findMany({ - with: { - group: true, - }, - where: eq(db.usersToGroups.userId, userId), - }); + return rows; +} - // Filter groups by groupCategoryId - const groupsWithCategoryId = userGroups.filter( - (group) => group.group.groupCategoryId === groupCategoryId, - ); +export function getSecretGroup(dbPool: PostgresJsDatabase, secret: string) { + const group = dbPool.query.groups.findFirst({ + where: (fields, { eq }) => eq(fields.secret, secret), + }); - // Extract the group objects - const out = groupsWithCategoryId.map((r) => r.group); + return group; +} - return res.json({ data: out }); - } catch (e) { - console.log('error getting groups per user by Category id ' + JSON.stringify(e)); - return res.status(500).json({ error: 'internal server error' }); - } - }; +export function generateSecret(): string { + return randomBytes(6).toString('hex'); } diff --git a/src/services/registrationData.spec.ts b/src/services/registrationData.spec.ts index 37b296db..08207e7f 100644 --- a/src/services/registrationData.spec.ts +++ b/src/services/registrationData.spec.ts @@ -11,7 +11,7 @@ import { fetchRegistrationFields, filterRegistrationData, } from './registrationData'; -import { saveEventRegistration } from './registrations'; +import { saveRegistration } from './registrations'; import { isNotNull } from 'drizzle-orm'; const DB_CONNECTION_URL = 'postgresql://postgres:secretpassword@localhost:5432'; @@ -65,7 +65,7 @@ describe('service: registrationData', () => { .update(db.registrationFields) .set({ questionId: forumQuestion?.id ?? '' }) .where(isNotNull(db.registrationFields.questionOptionType)); - registration = await saveEventRegistration(dbPool, testRegistration, testRegistration.userId); + registration = await saveRegistration(dbPool, testRegistration, testRegistration.userId); }); test('should update existing records', async () => { diff --git a/src/services/registrationFields.spec.ts b/src/services/registrationFields.spec.ts new file mode 100644 index 00000000..1f0bf772 --- /dev/null +++ b/src/services/registrationFields.spec.ts @@ -0,0 +1,132 @@ +import { PostgresJsDatabase } from 'drizzle-orm/postgres-js'; +import postgres from 'postgres'; +import { z } from 'zod'; +import * as db from '../db'; +import { insertRegistrationSchema } from '../types'; +import { createDbPool } from '../utils/db/createDbPool'; +import { runMigrations } from '../utils/db/runMigrations'; +import { cleanup, seed } from '../utils/db/seed'; +import { validateRequiredRegistrationFields } from './registrationFields'; + +const DB_CONNECTION_URL = 'postgresql://postgres:secretpassword@localhost:5432'; + +describe('service: registrationFields', () => { + let dbPool: PostgresJsDatabase; + let dbConnection: postgres.Sql>; + let requiredByGroupRegistrationField: db.RegistrationField | undefined; + let requiredByUserRegistrationField: db.RegistrationField | undefined; + let testRegistration: z.infer; + + beforeAll(async () => { + const initDb = createDbPool(DB_CONNECTION_URL, { max: 1 }); + await runMigrations(DB_CONNECTION_URL); + dbPool = initDb.dbPool; + dbConnection = initDb.connection; + // seed + const { events, users, registrationFields } = await seed(dbPool); + + // required by group + requiredByGroupRegistrationField = registrationFields[0]; + // required by user + requiredByUserRegistrationField = registrationFields[1]; + + testRegistration = { + userId: users[0]?.id ?? '', + eventId: events[0]?.id ?? '', + status: 'DRAFT', + registrationData: [ + { + registrationFieldId: registrationFields[0]?.id ?? '', + value: 'title', + }, + { + registrationFieldId: registrationFields[1]?.id ?? '', + value: 'sub title', + }, + { + registrationFieldId: registrationFields[2]?.id ?? '', + value: 'other', + }, + ], + }; + }); + + describe('should return an empty array if all required fields are filled', function () { + test('for user', async () => { + const missingRequiredFields = await validateRequiredRegistrationFields({ + dbPool, + data: { + ...testRegistration, + registrationData: testRegistration.registrationData.filter( + (data) => data.registrationFieldId !== requiredByGroupRegistrationField?.id, + ), + }, + forGroup: false, + forUser: true, + }); + expect(missingRequiredFields).toEqual([]); + }); + test('for group', async () => { + const missingRequiredFields = await validateRequiredRegistrationFields({ + dbPool, + data: { + ...testRegistration, + registrationData: testRegistration.registrationData.filter( + (data) => data.registrationFieldId !== requiredByUserRegistrationField?.id, + ), + }, + forGroup: true, + forUser: false, + }); + expect(missingRequiredFields).toEqual([]); + }); + }); + + describe('should return an array of missing required fields', function () { + test('for user', async () => { + const missingRequiredFields = await validateRequiredRegistrationFields({ + dbPool, + data: { + ...testRegistration, + registrationData: testRegistration.registrationData.filter( + (data) => data.registrationFieldId !== requiredByUserRegistrationField?.id, + ), + }, + forGroup: false, + forUser: true, + }); + + expect(missingRequiredFields).toEqual([ + { + field: requiredByUserRegistrationField?.name, + message: 'missing required field', + }, + ]); + }); + test('for group', async () => { + const missingRequiredFields = await validateRequiredRegistrationFields({ + dbPool, + data: { + ...testRegistration, + registrationData: testRegistration.registrationData.filter( + (data) => data.registrationFieldId !== requiredByGroupRegistrationField?.id, + ), + }, + forGroup: true, + forUser: false, + }); + + expect(missingRequiredFields).toEqual([ + { + field: requiredByGroupRegistrationField?.name, + message: 'missing required field', + }, + ]); + }); + }); + + afterAll(async () => { + await cleanup(dbPool); + await dbConnection.end(); + }); +}); diff --git a/src/services/registrationFields.ts b/src/services/registrationFields.ts index c65c3283..1bccc1a4 100644 --- a/src/services/registrationFields.ts +++ b/src/services/registrationFields.ts @@ -1,33 +1,61 @@ import { PostgresJsDatabase } from 'drizzle-orm/postgres-js'; import * as db from '../db'; +import { and, eq } from 'drizzle-orm'; -export async function validateRequiredRegistrationFields( - dbPool: PostgresJsDatabase, +export async function validateRequiredRegistrationFields({ + data, + dbPool, + forGroup, + forUser, +}: { + dbPool: PostgresJsDatabase; data: { eventId: string; registrationData: { registrationFieldId: string; value: string; }[]; - }, -) { + }; + forUser: boolean; + forGroup: boolean; +}) { // check if all required fields are filled const event = await dbPool.query.events.findFirst({ with: { - registrationFields: true, + registrationFields: { + where: and( + eq(db.registrationFields.forUser, forUser), + eq(db.registrationFields.forGroup, forGroup), + eq(db.registrationFields.required, true), + ), + }, }, - where: (event, { eq }) => eq(event.id, data.eventId), + where: eq(db.events.id, data.eventId), }); - const requiredFields = event?.registrationFields.filter((field) => field.required); + const requiredFields = event?.registrationFields; if (!requiredFields) { return []; } // loop through required fields and check if they are filled - const missingFields = requiredFields.filter( - (field) => !data.registrationData.some((data) => data.registrationFieldId === field.id), - ); + const missingFields = requiredFields.filter((field) => { + const registrationField = data.registrationData.find( + (data) => data.registrationFieldId === field.id, + ); + + // if field is not found in registration data, it is missing + if (!registrationField) { + return true; + } + + // if field is found but value is empty, it is missing + if (!registrationField.value) { + return true; + } + + return false; + }); return missingFields.map((field) => ({ field: field.name, diff --git a/src/services/registrations.spec.ts b/src/services/registrations.spec.ts index 5eb70ffe..c0e46cad 100644 --- a/src/services/registrations.spec.ts +++ b/src/services/registrations.spec.ts @@ -3,7 +3,7 @@ import * as db from '../db'; import { createDbPool } from '../utils/db/createDbPool'; import postgres from 'postgres'; import { runMigrations } from '../utils/db/runMigrations'; -import { saveEventRegistration } from './registrations'; +import { saveRegistration } from './registrations'; import { z } from 'zod'; import { insertRegistrationSchema } from '../types'; import { cleanup, seed } from '../utils/db/seed'; @@ -37,7 +37,7 @@ describe('service: registrations', () => { }); test('send registration data', async function () { // Call the saveRegistration function - const response = await saveEventRegistration(dbPool, testData, testData.userId); + const response = await saveRegistration(dbPool, testData, testData.userId); // Check if response is defined expect(response).toBeDefined(); // Check property existence and types @@ -66,7 +66,7 @@ describe('service: registrations', () => { }, ]; // Call the saveRegistration function - const response = await saveEventRegistration(dbPool, testData, testData.userId); + const response = await saveRegistration(dbPool, testData, testData.userId); // Check if response is defined expect(response).toBeDefined(); // Check property existence and types diff --git a/src/services/registrations.ts b/src/services/registrations.ts index dd1d1d08..f58a3c39 100644 --- a/src/services/registrations.ts +++ b/src/services/registrations.ts @@ -1,6 +1,5 @@ -import { eq } from 'drizzle-orm'; import type { PostgresJsDatabase } from 'drizzle-orm/postgres-js'; -import { and } from 'drizzle-orm'; +import { and, eq } from 'drizzle-orm'; import { z } from 'zod'; import { insertRegistrationSchema } from '../types'; import * as db from '../db'; @@ -9,15 +8,81 @@ import { upsertQuestionOptionFromRegistrationData, } from './registrationData'; -export async function saveEventRegistration( +export async function validateCreateRegistrationPermissions({ + dbPool, + userId, + groupId, + eventId, +}: { + dbPool: PostgresJsDatabase; + userId: string; + eventId: string; + groupId?: string | null; +}) { + if (groupId) { + const userGroup = dbPool.query.usersToGroups.findFirst({ + where: and(eq(db.usersToGroups.userId, userId), eq(db.usersToGroups.groupId, groupId)), + }); + + if (!userGroup) { + return false; + } + + // limit one registration per group per event + const existingRegistration = await dbPool.query.registrations.findFirst({ + where: and(eq(db.registrations.eventId, eventId), eq(db.registrations.groupId, groupId)), + }); + + if (existingRegistration) { + return false; + } + } + + return true; +} + +export async function validateUpdateRegistrationPermissions({ + dbPool, + registrationId, + userId, + groupId, +}: { + dbPool: PostgresJsDatabase; + userId: string; + registrationId: string; + groupId?: string | null; +}) { + const existingRegistration = await dbPool.query.registrations.findFirst({ + where: and(eq(db.registrations.userId, userId), eq(db.registrations.id, registrationId)), + }); + + if (!existingRegistration) { + return false; + } + + if (existingRegistration.userId !== userId) { + return false; + } + + if (groupId) { + const userGroup = dbPool.query.usersToGroups.findFirst({ + where: and(eq(db.usersToGroups.userId, userId), eq(db.usersToGroups.groupId, groupId)), + }); + + if (!userGroup) { + return false; + } + } + + return true; +} + +export async function saveRegistration( dbPool: PostgresJsDatabase, data: z.infer, userId: string, ) { - const existingRegistration = await dbPool.query.registrations.findFirst({ - where: and(eq(db.registrations.userId, userId), eq(db.registrations.eventId, data.eventId)), - }); - const newRegistration = await upsertRegistration(dbPool, existingRegistration, data); + const newRegistration = await createRegistrationInDB(dbPool, data); if (!newRegistration) { throw new Error('failed to save registration'); } @@ -43,33 +108,84 @@ export async function saveEventRegistration( } } -async function upsertRegistration( +export async function updateRegistration({ + data, + dbPool, + registrationId, + userId, +}: { + dbPool: PostgresJsDatabase; + data: z.infer; + registrationId: string; + userId: string; +}) { + const existingRegistration = await dbPool.query.registrations.findFirst({ + where: and(eq(db.registrations.userId, userId), eq(db.registrations.id, registrationId)), + }); + + if (!existingRegistration) { + throw new Error('registration not found'); + } + + const updatedRegistration = await updateRegistrationInDB(dbPool, existingRegistration, data); + + if (!updatedRegistration) { + throw new Error('failed to save registration'); + } + + const updatedRegistrationData = await upsertRegistrationData({ + dbPool, + registrationId: updatedRegistration.id, + + registrationData: data.registrationData, + }); + + try { + await upsertQuestionOptionFromRegistrationData(dbPool, userId, updatedRegistrationData); + + const out = { + ...updatedRegistration, + registrationData: updatedRegistrationData, + }; + + return out; + } catch (error) { + console.error('Error in updateQuestionOptions: ', error); + throw new Error('Failed to update question options'); + } +} + +async function createRegistrationInDB( dbPool: PostgresJsDatabase, - registration: db.Registration | undefined, body: z.infer, ) { - if (registration) { - const updatedRegistration = await dbPool - .update(db.registrations) - .set({ - userId: body.userId, - eventId: body.eventId, - status: body.status, - updatedAt: new Date(), - }) - .where(eq(db.registrations.id, registration.id)) - .returning(); - return updatedRegistration[0]; - } else { - // insert to registration table - const newRegistration = await dbPool - .insert(db.registrations) - .values({ - userId: body.userId, - eventId: body.eventId, - status: body.status, - }) - .returning(); - return newRegistration[0]; - } + // insert to registration table + const newRegistration = await dbPool + .insert(db.registrations) + .values({ + userId: body.userId, + groupId: body.groupId, + eventId: body.eventId, + status: body.status, + }) + .returning(); + return newRegistration[0]; +} + +async function updateRegistrationInDB( + dbPool: PostgresJsDatabase, + registration: db.Registration, + body: z.infer, +) { + const updatedRegistration = await dbPool + .update(db.registrations) + .set({ + eventId: body.eventId, + groupId: body.groupId, + status: body.status, + updatedAt: new Date(), + }) + .where(eq(db.registrations.id, registration.id)) + .returning(); + return updatedRegistration[0]; } diff --git a/src/services/statistics.spec.ts b/src/services/statistics.spec.ts index 4e333dd5..3fdf6c94 100644 --- a/src/services/statistics.spec.ts +++ b/src/services/statistics.spec.ts @@ -84,7 +84,7 @@ describe('service: statistics', () => { expect(optionStat?.distinctUsers).toEqual(2); expect(optionStat?.allocatedHearts).toEqual(8); expect(optionStat?.quadraticScore).toEqual('4'); - expect(optionStat?.distinctGroups).toEqual(1); + expect(optionStat?.distinctGroups).toEqual(2); const listOfGroupNames = optionStat?.listOfGroupNames; // Check if the array is not empty expect(listOfGroupNames).toBeDefined(); diff --git a/src/services/usersToGroups.spec.ts b/src/services/usersToGroups.spec.ts index 8a394081..0d38b648 100644 --- a/src/services/usersToGroups.spec.ts +++ b/src/services/usersToGroups.spec.ts @@ -1,7 +1,7 @@ import { PostgresJsDatabase } from 'drizzle-orm/postgres-js'; import * as db from '../db'; import { upsertUsersToGroups } from './usersToGroups'; -import { eq } from 'drizzle-orm'; +import { eq, and } from 'drizzle-orm'; import { createDbPool } from '../utils/db/createDbPool'; import postgres from 'postgres'; import { runMigrations } from '../utils/db/runMigrations'; @@ -25,7 +25,6 @@ describe('service: usersToGroups', function () { defaultGroups = groups; // insert users without group assignment await dbPool.insert(db.users).values({ username: 'NewUser', email: 'SomeEmail' }); - await dbPool.insert(db.users).values({ username: 'NewUser1', email: 'SomeEmail1' }); }); test('can save initial groups', async function () { @@ -45,30 +44,46 @@ describe('service: usersToGroups', function () { expect(newUserGroup?.userId).toBe(newUser?.id); }); - test('can save initial groups when label is null', async function () { + test('can save another group for the same user with a different category id', async function () { // Get the newly inserted user - const newUser1 = await dbPool.query.users.findFirst({ - where: eq(db.users.username, 'NewUser1'), + const newUser = await dbPool.query.users.findFirst({ + where: eq(db.users.username, 'NewUser'), }); - await upsertUsersToGroups(dbPool, newUser1?.id ?? '', [defaultGroups[3]?.id ?? '']); + await upsertUsersToGroups(dbPool, newUser?.id ?? '', [defaultGroups[2]?.id ?? '']); // Find the userToGroup relationship for the newUser and the chosen group const newUserGroup = await dbPool.query.usersToGroups.findFirst({ - where: eq(db.usersToGroups.userId, newUser1?.id ?? ''), + where: and( + eq(db.usersToGroups.userId, newUser?.id ?? ''), + eq(db.usersToGroups.groupId, defaultGroups[2]?.id ?? ''), + ), }); expect(newUserGroup).toBeDefined(); - expect(newUserGroup?.userId).toBe(newUser1?.id); + expect(newUserGroup?.userId).toBe(newUser?.id); + expect(newUserGroup?.groupId).toBe(defaultGroups[2]?.id); }); test('can overwrite old user groups', async function () { - await upsertUsersToGroups(dbPool, user?.id ?? '', [defaultGroups[2]?.id ?? '']); - const group = await dbPool.query.usersToGroups.findFirst({ - where: eq(db.usersToGroups.groupId, defaultGroups[2]?.id ?? ''), + const newUser = await dbPool.query.users.findFirst({ + where: eq(db.users.username, 'NewUser'), }); - expect(group?.userId).toBeDefined; - expect(group?.userId).toBe(user?.id); + + await upsertUsersToGroups(dbPool, newUser?.id ?? '', [defaultGroups[1]?.id ?? '']); + + // Find the userToGroup relationship for the newUser and the chosen group + const newUserGroup = await dbPool.query.usersToGroups.findFirst({ + where: and( + eq(db.usersToGroups.userId, newUser?.id ?? ''), + eq(db.usersToGroups.groupId, defaultGroups[1]?.id ?? ''), + ), + }); + + expect(newUserGroup).toBeDefined(); + expect(newUserGroup?.userId).toBe(newUser?.id); + expect(newUserGroup?.groupId).toBe(defaultGroups[1]?.id); + expect(newUserGroup?.groupId).not.toBe(defaultGroups[2]?.id); }); test('handles non-existent group IDs', async function () { diff --git a/src/services/usersToGroups.ts b/src/services/usersToGroups.ts index 15b97e56..566a632c 100644 --- a/src/services/usersToGroups.ts +++ b/src/services/usersToGroups.ts @@ -1,6 +1,6 @@ import { PostgresJsDatabase } from 'drizzle-orm/postgres-js'; import * as db from '../db'; -import { eq, and, isNull } from 'drizzle-orm'; +import { eq, and } from 'drizzle-orm'; /** * Upserts the user-to-groups associations in the database for a given user. @@ -26,34 +26,32 @@ export async function upsertUsersToGroups( continue; } - const groupCategoryId = group.groupCategoryId ?? null; + // get group category id + const groupCategoryId = group.groupCategoryId; - if (groupCategoryId === null) { - await overwriteUsersToGroups(dbPool, userId, groupId); - } else { - const existingAssociation = await dbPool.query.usersToGroups.findFirst({ - where: and( - eq(db.usersToGroups.userId, userId), - eq(db.usersToGroups.groupCategoryId, groupCategoryId!), - ), - }); + // get all groups associated with a user by group category + const existingAssociation = await dbPool.query.usersToGroups.findFirst({ + where: and( + eq(db.usersToGroups.userId, userId), + eq(db.usersToGroups.groupCategoryId, groupCategoryId!), + ), + }); - if (existingAssociation) { - await dbPool - .update(db.usersToGroups) - .set({ userId, groupId, groupCategoryId, updatedAt: new Date() }) - .where( - and( - eq(db.usersToGroups.userId, userId), - eq(db.usersToGroups.groupCategoryId, groupCategoryId!), - ), - ); - } else { - await dbPool - .insert(db.usersToGroups) - .values({ userId, groupId, groupCategoryId }) - .returning(); - } + if (existingAssociation) { + await dbPool + .update(db.usersToGroups) + .set({ userId, groupId, groupCategoryId, updatedAt: new Date() }) + .where( + and( + eq(db.usersToGroups.userId, userId), + eq(db.usersToGroups.groupCategoryId, groupCategoryId!), + ), + ); + } else { + await dbPool + .insert(db.usersToGroups) + .values({ userId, groupId, groupCategoryId }) + .returning(); } } @@ -66,28 +64,3 @@ export async function upsertUsersToGroups( return null; } } - -// Handle cases where Category ID is zero. This function and its references will be deleted once we require -// group Category ids to be mandatory in the group table. -export async function overwriteUsersToGroups( - dbPool: PostgresJsDatabase, - userId: string, - newGroupId: string, -): Promise { - // delete all groups with Category id zero that previously existed - try { - await dbPool - .delete(db.usersToGroups) - .where(and(eq(db.usersToGroups.userId, userId), isNull(db.usersToGroups.groupCategoryId))); - } catch (e) { - console.log('error deleting user groups ' + JSON.stringify(e)); - return null; - } - // save the new ones - const newUsersToGroups = await dbPool - .insert(db.usersToGroups) - .values({ userId, groupId: newGroupId }) - .returning(); - - return newUsersToGroups; -} diff --git a/src/services/votes.spec.ts b/src/services/votes.spec.ts index 2aee4b92..2246027f 100644 --- a/src/services/votes.spec.ts +++ b/src/services/votes.spec.ts @@ -9,6 +9,7 @@ import { z } from 'zod'; import { saveVote, queryVoteData, + queryGroupCategories, numOfVotesDictionary, groupsDictionary, calculatePluralScore, @@ -29,6 +30,10 @@ describe('service: votes', () => { let questionOption: db.QuestionOption | undefined; let otherQuestionOption: db.QuestionOption | undefined; let forumQuestion: db.ForumQuestion | undefined; + let otherForumQuestion: db.ForumQuestion | undefined; + let groupCategory: db.GroupCategory | undefined; + let otherGroupCategory: db.GroupCategory | undefined; + let unrelatedGroupCategory: db.GroupCategory | undefined; let user: db.User | undefined; let secondUser: db.User | undefined; let thirdUser: db.User | undefined; @@ -38,11 +43,15 @@ describe('service: votes', () => { dbPool = initDb.dbPool; dbConnection = initDb.connection; // seed - const { users, questionOptions, forumQuestions, cycles } = await seed(dbPool); + const { users, questionOptions, forumQuestions, cycles, groupCategories } = await seed(dbPool); // Insert registration fields for the user questionOption = questionOptions[0]; otherQuestionOption = questionOptions[1]; forumQuestion = forumQuestions[0]; + otherForumQuestion = forumQuestions[1]; + groupCategory = groupCategories[0]; + otherGroupCategory = groupCategories[1]; + unrelatedGroupCategory = groupCategories[2]; user = users[0]; secondUser = users[1]; thirdUser = users[2]; @@ -182,11 +191,60 @@ describe('service: votes', () => { expect(thirdUser!.id in result).toBe(false); }); + test('that query group categories returns the correct amount of group category ids', async () => { + // Get vote data required for groups + const groupCategoriesIdArray = await queryGroupCategories(dbPool, forumQuestion!.id); + expect(groupCategoriesIdArray).toBeDefined(); + expect(groupCategoriesIdArray.length).toBe(2); + expect(Array.isArray(groupCategoriesIdArray)).toBe(true); + groupCategoriesIdArray.forEach((categoryId) => { + expect(typeof categoryId).toBe('string'); + }); + }); + + test('that query group categories returns an empty array if their are no group categories specified for a specific question', async () => { + const groupCategoriesIdArray = await queryGroupCategories(dbPool, otherForumQuestion!.id); + expect(groupCategoriesIdArray).toBeDefined(); + expect(groupCategoriesIdArray.length).toBe(0); + expect(Array.isArray(groupCategoriesIdArray)).toBe(true); + expect(groupCategoriesIdArray).toEqual([]); + }); + test('only return groups for users who voted for the option', async () => { + const voteArray = await queryVoteData(dbPool, questionOption?.id ?? ''); + const votesDictionary = await numOfVotesDictionary(voteArray); + const groups = await groupsDictionary(dbPool, votesDictionary, [groupCategory!.id]); + + expect(groups).toBeDefined(); + expect(groups['unexpectedKey']).toBeUndefined(); + expect(typeof groups).toBe('object'); + expect(Object.keys(groups).length).toEqual(1); + expect(groups[Object.keys(groups)[0]!]!.length).toEqual(2); + }); + + test('only return groups for users who voted for the option with two elidgible group categories', async () => { + const voteArray = await queryVoteData(dbPool, questionOption?.id ?? ''); + const votesDictionary = await numOfVotesDictionary(voteArray); + const groups = await groupsDictionary(dbPool, votesDictionary, [ + groupCategory!.id, + otherGroupCategory!.id, + ]); + + expect(groups).toBeDefined(); + expect(groups['unexpectedKey']).toBeUndefined(); + expect(typeof groups).toBe('object'); + expect(Object.keys(groups).length).toEqual(2); + expect(groups[Object.keys(groups)[0]!]!.length).toEqual(2); + }); + + test('only return baseline groups for users who voted for the option as non of the users is in the additional group category', async () => { // Get vote data required for groups const voteArray = await queryVoteData(dbPool, questionOption?.id ?? ''); const votesDictionary = await numOfVotesDictionary(voteArray); - const groups = await groupsDictionary(dbPool, votesDictionary); + const groups = await groupsDictionary(dbPool, votesDictionary, [ + groupCategory!.id, + unrelatedGroupCategory!.id, + ]); expect(groups).toBeDefined(); expect(groups['unexpectedKey']).toBeUndefined(); diff --git a/src/services/votes.ts b/src/services/votes.ts index 1e068f8a..10a148c9 100644 --- a/src/services/votes.ts +++ b/src/services/votes.ts @@ -78,13 +78,38 @@ export function numOfVotesDictionary(voteArray: Array<{ userId: string; numOfVot return numOfVotesDictionary; } +export async function queryGroupCategories( + dbPool: PostgresJsDatabase, + questionId: string, +): Promise { + const groupCategories = await dbPool + .select({ + groupCategoryId: db.questionsToGroupCategories.groupCategoryId, + }) + .from(db.questionsToGroupCategories) + .where(eq(db.questionsToGroupCategories.questionId, questionId)); + + // Need to due this adjustment because currently groupCategoryId is nullable in the datatable definition. + const groupCategoryIds: string[] = groupCategories.map((category) => category.groupCategoryId!); + + if (groupCategoryIds.length === 0) { + console.error('Group Category ID is Missing'); + return []; + } + + return groupCategoryIds; +} + /** * Queries group data and creates group dictionary based on user IDs and option ID. - * @param {PostgresJsDatabase} dbPool - The database connection pool. + * @param {Record} numOfVotesDictionary - Dictionary of user IDs and their respective number of votes. + * @param {Array} groupCategoryIds - Array of group category IDs. + * @returns {Promise>} - Dictionary of group IDs and their corresponding user IDs. */ export async function groupsDictionary( dbPool: PostgresJsDatabase, numOfVotesDictionary: Record, + groupCategories: Array, ) { const groupArray = await dbPool.execute<{ groupId: string; userIds: string[] }>( sql.raw(` @@ -93,6 +118,7 @@ export async function groupsDictionary( WHERE user_id IN (${Object.keys(numOfVotesDictionary) .map((id) => `'${id}'`) .join(', ')}) + AND group_category_id IN (${groupCategories.map((category) => `'${category}'`).join(', ')}) GROUP BY group_id `), ); @@ -171,8 +197,19 @@ export async function updateVoteScore( // Transform data const votesDictionary = await numOfVotesDictionary(voteArray); + // Query question Id + const queryQuestionId = await dbPool + .select({ + questionId: db.questionOptions.questionId, + }) + .from(db.questionOptions) + .where(eq(db.questionOptions.id, optionId)); + + // Query group categories + const groupCategories = await queryGroupCategories(dbPool, queryQuestionId[0]!.questionId); + // Query group data - const groupArray = await groupsDictionary(dbPool, votesDictionary); + const groupArray = await groupsDictionary(dbPool, votesDictionary, groupCategories ?? []); // Perform plural voting calculation const score = await calculatePluralScore(groupArray, votesDictionary); diff --git a/src/types/groups.ts b/src/types/groups.ts new file mode 100644 index 00000000..4e897fa0 --- /dev/null +++ b/src/types/groups.ts @@ -0,0 +1,12 @@ +import { createInsertSchema } from 'drizzle-zod'; +import { groups } from '../db'; +import { z } from 'zod'; + +export const insertGroupsSchema = createInsertSchema(groups, { + groupCategoryId: z.string().trim().min(1), +}).omit({ + createdAt: true, + updatedAt: true, + secret: true, + id: true, +}); diff --git a/src/types/usersToGroups.ts b/src/types/usersToGroups.ts new file mode 100644 index 00000000..146c789f --- /dev/null +++ b/src/types/usersToGroups.ts @@ -0,0 +1,11 @@ +import { z } from 'zod'; + +export const joinSecretGroupsSchema = z.object({ + secret: z.string().min(1), +}); + +export const joinPublicGroupsSchema = z.object({ + groupId: z.string().min(1), +}); + +export const joinGroupsSchema = z.union([joinSecretGroupsSchema, joinPublicGroupsSchema]); diff --git a/src/utils/db/insertCustomGroups.ts b/src/utils/db/insertCustomGroups.ts deleted file mode 100644 index 11375549..00000000 --- a/src/utils/db/insertCustomGroups.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { PostgresJsDatabase } from 'drizzle-orm/postgres-js'; -import * as db from '../../db'; - -/** - * Inserts groups into the 'groups' table based on data from a CSV file, after - * first deleting all existing data from the table. - * @param {PostgresJsDatabase} dbPool - The database connection pool. - * @param {string[]} groups - a list of groups to insert into the database. - * @returns {Promise} A promise that resolves when the insertion is complete. - * @throws {Error} If there is an error during file reading, database operations, or deletion of existing data. - */ -async function insertCustomGroups(dbPool: PostgresJsDatabase, groups: string[]) { - await dbPool.delete(db.groups); - await dbPool.insert(db.groups).values(groups.map((name) => ({ name }))); -} - -export { insertCustomGroups }; diff --git a/src/utils/db/seed.ts b/src/utils/db/seed.ts index 2c462274..70e3c218 100644 --- a/src/utils/db/seed.ts +++ b/src/utils/db/seed.ts @@ -6,16 +6,33 @@ async function seed(dbPool: PostgresJsDatabase) { const events = await createEvent(dbPool); const cycles = await createCycle(dbPool, events[0]?.id); const registrationFields = await createRegistrationFields(dbPool, events[0]?.id); + const registrationFieldOptions = await createRegistrationFieldOptions( + dbPool, + registrationFields[3]?.id, + ); const forumQuestions = await createForumQuestions(dbPool, cycles[0]?.id); const questionOptions = await createQuestionOptions(dbPool, forumQuestions[0]?.id); const groupCategories = await createGroupCategories(dbPool, events[0]?.id); - const groups = await createGroups(dbPool, groupCategories[0]?.id, groupCategories[1]?.id); + const groups = await createGroups( + dbPool, + groupCategories[0]?.id, + groupCategories[1]?.id, + groupCategories[2]?.id, + groupCategories[3]?.id, + ); const users = await createUsers(dbPool); const usersToGroups = await createUsersToGroups( dbPool, users.map((u) => u.id!), groups.map((g) => g.id!), + groupCategories[0]!.id, + groupCategories[1]!.id, + ); + const questionsToGroupCategories = await createQuestionsToGroupCategories( + dbPool, + forumQuestions[0]!.id, groupCategories[0]?.id, + groupCategories[1]?.id, ); return { @@ -28,6 +45,8 @@ async function seed(dbPool: PostgresJsDatabase) { users, usersToGroups, registrationFields, + questionsToGroupCategories, + registrationFieldOptions, }; } @@ -37,11 +56,13 @@ async function cleanup(dbPool: PostgresJsDatabase) { await dbPool.delete(db.federatedCredentials); await dbPool.delete(db.questionOptions); await dbPool.delete(db.registrationData); + await dbPool.delete(db.registrationFieldOptions); await dbPool.delete(db.registrationFields); await dbPool.delete(db.registrations); await dbPool.delete(db.usersToGroups); await dbPool.delete(db.users); await dbPool.delete(db.groups); + await dbPool.delete(db.questionsToGroupCategories); await dbPool.delete(db.groupCategories); await dbPool.delete(db.forumQuestions); await dbPool.delete(db.cycles); @@ -71,6 +92,8 @@ async function createRegistrationFields(dbPool: PostgresJsDatabase, e required: true, eventId, questionOptionType: 'TITLE', + forUser: false, + forGroup: true, }, { name: 'proposal description', @@ -78,6 +101,8 @@ async function createRegistrationFields(dbPool: PostgresJsDatabase, e required: true, eventId, questionOptionType: 'SUBTITLE', + forUser: true, + forGroup: false, }, { name: 'other field', @@ -85,6 +110,36 @@ async function createRegistrationFields(dbPool: PostgresJsDatabase, e required: false, eventId, }, + { + name: 'select field', + type: 'SELECT', + required: false, + eventId, + forUser: true, + }, + ]) + .returning(); +} + +async function createRegistrationFieldOptions( + dbPool: PostgresJsDatabase, + registrationFieldId?: string, +) { + if (registrationFieldId === undefined) { + throw new Error('Registration Field ID is undefined.'); + } + + return dbPool + .insert(db.registrationFieldOptions) + .values([ + { + registrationFieldId, + value: 'Option A', + }, + { + registrationFieldId, + value: 'Option B', + }, ]) .returning(); } @@ -114,10 +169,16 @@ async function createForumQuestions(dbPool: PostgresJsDatabase, cycle return dbPool .insert(db.forumQuestions) - .values({ - cycleId, - questionTitle: "What's your favorite movie?", - }) + .values([ + { + cycleId, + questionTitle: "What's your favorite movie?", + }, + { + cycleId, + questionTitle: 'What is your favorit fruit?', + }, + ]) .returning(); } @@ -148,12 +209,24 @@ async function createGroupCategories(dbPool: PostgresJsDatabase, even .insert(db.groupCategories) .values([ { - name: 'Category A', + name: 'affiliation', + eventId: eventId, + userCanView: true, + }, + { + name: 'category A', + eventId: eventId, + userCanView: true, + }, + { + name: 'category B', eventId: eventId, + userCanView: true, }, { - name: 'Category B', + name: 'secrets', eventId: eventId, + userCanCreate: true, }, ]) .returning(); @@ -161,26 +234,33 @@ async function createGroupCategories(dbPool: PostgresJsDatabase, even async function createGroups( dbPool: PostgresJsDatabase, - groupIdOne?: string, - groupIdTwo?: string, + baselineCategory?: string, + categoryOne?: string, + categoryTwo?: string, + secretCategory?: string, ) { return dbPool .insert(db.groups) .values([ { name: randCompanyName(), - groupCategoryId: groupIdOne, + groupCategoryId: baselineCategory, + }, + { + name: randCompanyName(), + groupCategoryId: categoryOne, }, { name: randCompanyName(), - groupCategoryId: groupIdOne, + groupCategoryId: categoryOne, }, { name: randCompanyName(), - groupCategoryId: groupIdTwo, + groupCategoryId: categoryTwo, }, { name: randCompanyName(), + groupCategoryId: secretCategory, }, ]) .returning(); @@ -198,15 +278,47 @@ async function createUsersToGroups( dbPool: PostgresJsDatabase, userIds: string[], groupIds: string[], - groupCategoryId: string | undefined, + baselineGroupCategory: string | undefined, + otherGroupCategory: string | undefined, ) { // assign users to groups const usersToGroups = userIds.map((userId, index) => ({ userId, - groupId: index < 2 ? groupIds[0]! : groupIds[1]!, - groupCategoryId, + groupId: index < 2 ? groupIds[1]! : groupIds[2]!, + groupCategoryId: otherGroupCategory, })); + + // Add baseline group for each user (i.e. each user must be assigned to at least one group at all times) + userIds.forEach((userId) => { + usersToGroups.push({ + userId, + groupId: groupIds[0]!, + groupCategoryId: baselineGroupCategory, + }); + }); + return dbPool.insert(db.usersToGroups).values(usersToGroups).returning(); } +async function createQuestionsToGroupCategories( + dbPool: PostgresJsDatabase, + questionId: string, + groupCategoryIdOne?: string, + groupCategoryIdTwo?: string, +) { + return dbPool + .insert(db.questionsToGroupCategories) + .values([ + { + questionId: questionId, + groupCategoryId: groupCategoryIdOne, + }, + { + questionId: questionId, + groupCategoryId: groupCategoryIdTwo, + }, + ]) + .returning(); +} + export { seed, cleanup };