diff --git a/.dev.vars.example b/.dev.vars.example index 10fd9c7c..21d4cb98 100644 --- a/.dev.vars.example +++ b/.dev.vars.example @@ -9,5 +9,6 @@ STRIPE_KEY="" MERCADOPAGO_KEY="" RESEND_API_KEY="" SUPABASE_JWT_DECODER"" +SUPABASE_JWT_ENCODER="" ENFORCED_JWT_TOKEN="" diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 561b5631..05f01d1a 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -118,6 +118,7 @@ module.exports = { // Incredible Plugin. // Rules URL: https://the-guild.dev/graphql/eslint/rules "@graphql-eslint/unique-fragment-name": "error", + "@graphql-eslint/no-deprecated": "warn", "@graphql-eslint/selection-set-depth": [ "error", { diff --git a/.github/workflows/deploy_db_model.yml b/.github/workflows/deploy_db_model.yml index 955a030d..8d37232d 100644 --- a/.github/workflows/deploy_db_model.yml +++ b/.github/workflows/deploy_db_model.yml @@ -21,7 +21,7 @@ jobs: - name: ⬢ Setup Node uses: actions/setup-node@v3 with: - node-version: 18 + node-version: 22 - name: 📦 Download Cached Package Dependencies uses: actions/cache@v3 env: diff --git a/.github/workflows/deploy_dev.yml b/.github/workflows/deploy_dev.yml index e7fcb5f8..09e269c6 100644 --- a/.github/workflows/deploy_dev.yml +++ b/.github/workflows/deploy_dev.yml @@ -18,7 +18,7 @@ jobs: - name: ⬢ Setup Node uses: actions/setup-node@v3 with: - node-version: 18 + node-version: 22 - name: 📦 Download Cached Package Dependencies uses: actions/cache@v3 env: diff --git a/.github/workflows/deploy_prod.yml b/.github/workflows/deploy_prod.yml index 0fa7a897..0836c67a 100644 --- a/.github/workflows/deploy_prod.yml +++ b/.github/workflows/deploy_prod.yml @@ -21,7 +21,7 @@ jobs: - name: ⬢ Setup Node uses: actions/setup-node@v3 with: - node-version: 18 + node-version: 22 - name: 📦 Download Cached Package Dependencies uses: actions/cache@v3 env: diff --git a/.github/workflows/deploy_staging.yml b/.github/workflows/deploy_staging.yml index 399b8a69..349460a5 100644 --- a/.github/workflows/deploy_staging.yml +++ b/.github/workflows/deploy_staging.yml @@ -21,7 +21,7 @@ jobs: - name: ⬢ Setup Node uses: actions/setup-node@v3 with: - node-version: 18 + node-version: 22 - name: 📦 Download Cached Package Dependencies uses: actions/cache@v3 env: diff --git a/.github/workflows/integration_tests.yml b/.github/workflows/integration_tests.yml index 5a4bdbfb..c855271c 100644 --- a/.github/workflows/integration_tests.yml +++ b/.github/workflows/integration_tests.yml @@ -30,7 +30,7 @@ jobs: - name: ⬢ Setup Node uses: actions/setup-node@v3 with: - node-version: 18 + node-version: 22 - name: 📦 Download Cached Package Dependencies uses: actions/cache@v3 diff --git a/.github/workflows/lint_and_typecheck.yml b/.github/workflows/lint_and_typecheck.yml index 343cef1b..2b9c4fb4 100644 --- a/.github/workflows/lint_and_typecheck.yml +++ b/.github/workflows/lint_and_typecheck.yml @@ -21,7 +21,7 @@ jobs: - name: ⬢ Setup Node uses: actions/setup-node@v3 with: - node-version: 18 + node-version: 22 - name: 📦 Download Cached Package Dependencies uses: actions/cache@v3 diff --git a/drizzle/migrations/0020_elite_electro.sql b/drizzle/migrations/0020_elite_electro.sql new file mode 100644 index 00000000..1212af0e --- /dev/null +++ b/drizzle/migrations/0020_elite_electro.sql @@ -0,0 +1 @@ +ALTER TABLE "users" ADD COLUMN "isRetoolEnabled" boolean DEFAULT false NOT NULL; \ No newline at end of file diff --git a/drizzle/migrations/meta/0020_snapshot.json b/drizzle/migrations/meta/0020_snapshot.json new file mode 100644 index 00000000..08767d41 --- /dev/null +++ b/drizzle/migrations/meta/0020_snapshot.json @@ -0,0 +1,2631 @@ +{ + "id": "3981ddc0-a5ca-4af2-b233-b5c4f617cd12", + "prevId": "dcedf1be-2b76-42a8-95da-1702fb9aeb42", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.allowed_currencies": { + "name": "allowed_currencies", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "currency": { + "name": "currency", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "payment_methods": { + "name": "payment_methods", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "allowed_currencies_currency_unique": { + "name": "allowed_currencies_currency_unique", + "nullsNotDistinct": false, + "columns": ["currency"] + } + } + }, + "public.communities": { + "name": "communities", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "logo_image_sanity_ref": { + "name": "logo_image_sanity_ref", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "banner_image_sanity_ref": { + "name": "banner_image_sanity_ref", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "payment_success_redirect_url": { + "name": "payment_success_redirect_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "payment_cancel_redirect_url": { + "name": "payment_cancel_redirect_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'inactive'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "communities_slug_unique": { + "name": "communities_slug_unique", + "nullsNotDistinct": false, + "columns": ["slug"] + } + } + }, + "public.companies": { + "name": "companies", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "domain": { + "name": "domain", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "logo": { + "name": "logo", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "website": { + "name": "website", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'draft'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.confirmation_token": { + "name": "confirmation_token", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "source_id": { + "name": "source_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "uuid", + "primaryKey": false, + "notNull": true, + "default": "gen_random_uuid()" + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'pending'" + }, + "valid_until": { + "name": "valid_until", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "confirmation_date": { + "name": "confirmation_date", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "confirmation_token_user_id_users_id_fk": { + "name": "confirmation_token_user_id_users_id_fk", + "tableFrom": "confirmation_token", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "confirmation_token_token_unique": { + "name": "confirmation_token_token_unique", + "nullsNotDistinct": false, + "columns": ["token"] + } + } + }, + "public.events": { + "name": "events", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'inactive'" + }, + "visibility": { + "name": "visibility", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'unlisted'" + }, + "start_date_time": { + "name": "start_date_time", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "end_date_time": { + "name": "end_date_time", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "timezone": { + "name": "timezone", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "geo_latitude": { + "name": "geo_latitude", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "geo_longitude": { + "name": "geo_longitude", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "geo_address_json": { + "name": "geo_address_json", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "address_descriptive_name": { + "name": "address_descriptive_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "address": { + "name": "address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "meeting_url": { + "name": "meeting_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sanity_event_id": { + "name": "sanity_event_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "banner_image_sanity_ref": { + "name": "banner_image_sanity_ref", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "events_name_unique": { + "name": "events_name_unique", + "nullsNotDistinct": false, + "columns": ["name"] + } + } + }, + "public.events_communities": { + "name": "events_communities", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": false, + "notNull": true, + "default": "gen_random_uuid()" + }, + "event_id": { + "name": "event_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "community_id": { + "name": "community_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "payment_success_redirect_url": { + "name": "payment_success_redirect_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "payment_cancel_redirect_url": { + "name": "payment_cancel_redirect_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "events_communities_event_id_events_id_fk": { + "name": "events_communities_event_id_events_id_fk", + "tableFrom": "events_communities", + "tableTo": "events", + "columnsFrom": ["event_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "events_communities_community_id_communities_id_fk": { + "name": "events_communities_community_id_communities_id_fk", + "tableFrom": "events_communities", + "tableTo": "communities", + "columnsFrom": ["community_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "events_communities_event_id_community_id_pk": { + "name": "events_communities_event_id_community_id_pk", + "columns": ["event_id", "community_id"] + } + }, + "uniqueConstraints": { + "events_communities_id_unique": { + "name": "events_communities_id_unique", + "nullsNotDistinct": false, + "columns": ["id"] + } + } + }, + "public.events_tags": { + "name": "events_tags", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": false, + "notNull": true, + "default": "gen_random_uuid()" + }, + "event_id": { + "name": "event_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "tag_id": { + "name": "tag_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "events_tags_event_id_events_id_fk": { + "name": "events_tags_event_id_events_id_fk", + "tableFrom": "events_tags", + "tableTo": "events", + "columnsFrom": ["event_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "events_tags_tag_id_tags_id_fk": { + "name": "events_tags_tag_id_tags_id_fk", + "tableFrom": "events_tags", + "tableTo": "tags", + "columnsFrom": ["tag_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "events_tags_event_id_tag_id_pk": { + "name": "events_tags_event_id_tag_id_pk", + "columns": ["event_id", "tag_id"] + } + }, + "uniqueConstraints": { + "events_tags_id_unique": { + "name": "events_tags_id_unique", + "nullsNotDistinct": false, + "columns": ["id"] + } + } + }, + "public.events_users": { + "name": "events_users", + "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 + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'member'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "events_users_event_id_events_id_fk": { + "name": "events_users_event_id_events_id_fk", + "tableFrom": "events_users", + "tableTo": "events", + "columnsFrom": ["event_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "events_users_user_id_users_id_fk": { + "name": "events_users_user_id_users_id_fk", + "tableFrom": "events_users", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.payments_logs": { + "name": "payments_logs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "external_id": { + "name": "external_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "external_product_reference": { + "name": "external_product_reference", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "platform": { + "name": "platform", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "transaction_amount": { + "name": "transaction_amount", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "external_creation_date": { + "name": "external_creation_date", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "currency_id": { + "name": "currency_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "original_response_blob": { + "name": "original_response_blob", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "payments_logs_external_id_platform_unique": { + "name": "payments_logs_external_id_platform_unique", + "nullsNotDistinct": false, + "columns": ["external_id", "platform"] + } + } + }, + "public.prices": { + "name": "prices", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "price": { + "name": "price", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "currency_id": { + "name": "currency_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "prices_currency_id_allowed_currencies_id_fk": { + "name": "prices_currency_id_allowed_currencies_id_fk", + "tableFrom": "prices", + "tableTo": "allowed_currencies", + "columnsFrom": ["currency_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.purchase_orders": { + "name": "purchase_orders", + "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 + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "idempotency_uuid_key": { + "name": "idempotency_uuid_key", + "type": "uuid", + "primaryKey": false, + "notNull": true, + "default": "gen_random_uuid()" + }, + "payment_platform": { + "name": "payment_platform", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "total_price": { + "name": "total_price", + "type": "numeric", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'open'" + }, + "currency_id": { + "name": "currency_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "payment_platform_payment_link": { + "name": "payment_platform_payment_link", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "payment_platform_expiration_date": { + "name": "payment_platform_expiration_date", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "payment_platform_reference_id": { + "name": "payment_platform_reference_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "payment_platform_status": { + "name": "payment_platform_status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "payment_platform_metadata": { + "name": "payment_platform_metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "purchase_order_payment_status": { + "name": "purchase_order_payment_status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'unpaid'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "purchase_orders_user_id_users_id_fk": { + "name": "purchase_orders_user_id_users_id_fk", + "tableFrom": "purchase_orders", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "purchase_orders_currency_id_allowed_currencies_id_fk": { + "name": "purchase_orders_currency_id_allowed_currencies_id_fk", + "tableFrom": "purchase_orders", + "tableTo": "allowed_currencies", + "columnsFrom": ["currency_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "purchase_orders_idempotency_uuid_key_unique": { + "name": "purchase_orders_idempotency_uuid_key_unique", + "nullsNotDistinct": false, + "columns": ["idempotency_uuid_key"] + } + } + }, + "public.salaries": { + "name": "salaries", + "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 + }, + "amount": { + "name": "amount", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "company_id": { + "name": "company_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "currency_code": { + "name": "currency_code", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "work_seniority_and_role_id": { + "name": "work_seniority_and_role_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "work_email_id": { + "name": "work_email_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "years_of_experience": { + "name": "years_of_experience", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "gender": { + "name": "gender", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "gender_other_text": { + "name": "gender_other_text", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "country_code": { + "name": "country_code", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type_of_employment": { + "name": "type_of_employment", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "work_metodology": { + "name": "work_metodology", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "salaries_user_id_users_id_fk": { + "name": "salaries_user_id_users_id_fk", + "tableFrom": "salaries", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "salaries_company_id_companies_id_fk": { + "name": "salaries_company_id_companies_id_fk", + "tableFrom": "salaries", + "tableTo": "companies", + "columnsFrom": ["company_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "salaries_work_seniority_and_role_id_work_seniority_and_role_id_fk": { + "name": "salaries_work_seniority_and_role_id_work_seniority_and_role_id_fk", + "tableFrom": "salaries", + "tableTo": "work_seniority_and_role", + "columnsFrom": ["work_seniority_and_role_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "salaries_work_email_id_work_email_id_fk": { + "name": "salaries_work_email_id_work_email_id_fk", + "tableFrom": "salaries", + "tableTo": "work_email", + "columnsFrom": ["work_email_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.schedule": { + "name": "schedule", + "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 + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "start_at": { + "name": "start_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": true + }, + "end_at": { + "name": "end_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "schedule_event_id_events_id_fk": { + "name": "schedule_event_id_events_id_fk", + "tableFrom": "schedule", + "tableTo": "events", + "columnsFrom": ["event_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "schedule_id_unique": { + "name": "schedule_id_unique", + "nullsNotDistinct": false, + "columns": ["id"] + } + } + }, + "public.sessions": { + "name": "sessions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "schedule_id": { + "name": "schedule_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "start_at": { + "name": "start_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": true + }, + "end_at": { + "name": "end_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "sessions_schedule_id_schedule_id_fk": { + "name": "sessions_schedule_id_schedule_id_fk", + "tableFrom": "sessions", + "tableTo": "schedule", + "columnsFrom": ["schedule_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "sessions_id_unique": { + "name": "sessions_id_unique", + "nullsNotDistinct": false, + "columns": ["id"] + } + } + }, + "public.session_to_speakers": { + "name": "session_to_speakers", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "session_id": { + "name": "session_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "speaker_id": { + "name": "speaker_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "session_to_speakers_session_id_sessions_id_fk": { + "name": "session_to_speakers_session_id_sessions_id_fk", + "tableFrom": "session_to_speakers", + "tableTo": "sessions", + "columnsFrom": ["session_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "session_to_speakers_speaker_id_speakers_id_fk": { + "name": "session_to_speakers_speaker_id_speakers_id_fk", + "tableFrom": "session_to_speakers", + "tableTo": "speakers", + "columnsFrom": ["speaker_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "session_to_speakers_id_unique": { + "name": "session_to_speakers_id_unique", + "nullsNotDistinct": false, + "columns": ["id"] + } + } + }, + "public.speakers": { + "name": "speakers", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "bio": { + "name": "bio", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "avatar": { + "name": "avatar", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "event_id": { + "name": "event_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "company": { + "name": "company", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "social_links": { + "name": "social_links", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "ARRAY[]::text[]" + }, + "created_at": { + "name": "created_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "speakers_event_id_events_id_fk": { + "name": "speakers_event_id_events_id_fk", + "tableFrom": "speakers", + "tableTo": "events", + "columnsFrom": ["event_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "speakers_id_unique": { + "name": "speakers_id_unique", + "nullsNotDistinct": false, + "columns": ["id"] + } + } + }, + "public.tags": { + "name": "tags", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "tags_name_unique": { + "name": "tags_name_unique", + "nullsNotDistinct": false, + "columns": ["name"] + } + } + }, + "public.tags_communities": { + "name": "tags_communities", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": false, + "notNull": true, + "default": "gen_random_uuid()" + }, + "tag_id": { + "name": "tag_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "community_id": { + "name": "community_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "tags_communities_tag_id_tags_id_fk": { + "name": "tags_communities_tag_id_tags_id_fk", + "tableFrom": "tags_communities", + "tableTo": "tags", + "columnsFrom": ["tag_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "tags_communities_community_id_communities_id_fk": { + "name": "tags_communities_community_id_communities_id_fk", + "tableFrom": "tags_communities", + "tableTo": "communities", + "columnsFrom": ["community_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "tags_communities_tag_id_community_id_pk": { + "name": "tags_communities_tag_id_community_id_pk", + "columns": ["tag_id", "community_id"] + } + }, + "uniqueConstraints": { + "tags_communities_id_unique": { + "name": "tags_communities_id_unique", + "nullsNotDistinct": false, + "columns": ["id"] + } + } + }, + "public.teams": { + "name": "teams", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "event_id": { + "name": "event_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "limit": { + "name": "limit", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 5 + }, + "team_status": { + "name": "team_status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'waiting_resolution'" + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "teams_event_id_events_id_fk": { + "name": "teams_event_id_events_id_fk", + "tableFrom": "teams", + "tableTo": "events", + "columnsFrom": ["event_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.tickets_prices": { + "name": "tickets_prices", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "ticket_id": { + "name": "ticket_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "price_id": { + "name": "price_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "tickets_prices_ticket_id_tickets_id_fk": { + "name": "tickets_prices_ticket_id_tickets_id_fk", + "tableFrom": "tickets_prices", + "tableTo": "tickets", + "columnsFrom": ["ticket_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "tickets_prices_price_id_prices_id_fk": { + "name": "tickets_prices_price_id_prices_id_fk", + "tableFrom": "tickets_prices", + "tableTo": "prices", + "columnsFrom": ["price_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.tickets": { + "name": "tickets", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'inactive'" + }, + "tags": { + "name": "tags", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "ARRAY[]::text[]" + }, + "external_link": { + "name": "external_link", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "max_tickets_per_user": { + "name": "max_tickets_per_user", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "image_link": { + "name": "image_link", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "visibility": { + "name": "visibility", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'unlisted'" + }, + "start_date_time": { + "name": "start_date_time", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "end_date_time": { + "name": "end_date_time", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "requires_approval": { + "name": "requires_approval", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "quantity": { + "name": "quantity", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "is_unlimited": { + "name": "is_unlimited", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "is_free": { + "name": "is_free", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "event_id": { + "name": "event_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "stripe_product_id": { + "name": "stripe_product_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mercado_pago_product_id": { + "name": "mercado_pago_product_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "tickets_event_id_events_id_fk": { + "name": "tickets_event_id_events_id_fk", + "tableFrom": "tickets", + "tableTo": "events", + "columnsFrom": ["event_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "tickets_name_unique": { + "name": "tickets_name_unique", + "nullsNotDistinct": false, + "columns": ["name"] + } + } + }, + "public.users": { + "name": "users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "externalId": { + "name": "externalId", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "lastName": { + "name": "lastName", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "bio": { + "name": "bio", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "''" + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "gender": { + "name": "gender", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "pronouns": { + "name": "pronouns", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'inactive'" + }, + "gender_other_text": { + "name": "gender_other_text", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "isSuperAdmin": { + "name": "isSuperAdmin", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "isRetoolEnabled": { + "name": "isRetoolEnabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "emailVerified": { + "name": "emailVerified", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "imageUrl": { + "name": "imageUrl", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "publicMetadata": { + "name": "publicMetadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "users_email_unique": { + "name": "users_email_unique", + "nullsNotDistinct": false, + "columns": ["email"] + }, + "users_username_unique": { + "name": "users_username_unique", + "nullsNotDistinct": false, + "columns": ["username"] + } + } + }, + "public.users_communities": { + "name": "users_communities", + "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 + }, + "community_id": { + "name": "community_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'member'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "users_communities_user_id_users_id_fk": { + "name": "users_communities_user_id_users_id_fk", + "tableFrom": "users_communities", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "users_communities_community_id_communities_id_fk": { + "name": "users_communities_community_id_communities_id_fk", + "tableFrom": "users_communities", + "tableTo": "communities", + "columnsFrom": ["community_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.users_tags": { + "name": "users_tags", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": false, + "notNull": true, + "default": "gen_random_uuid()" + }, + "tag_id": { + "name": "tag_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "users_tags_tag_id_tags_id_fk": { + "name": "users_tags_tag_id_tags_id_fk", + "tableFrom": "users_tags", + "tableTo": "tags", + "columnsFrom": ["tag_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "users_tags_user_id_users_id_fk": { + "name": "users_tags_user_id_users_id_fk", + "tableFrom": "users_tags", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "users_tags_tag_id_user_id_pk": { + "name": "users_tags_tag_id_user_id_pk", + "columns": ["tag_id", "user_id"] + } + }, + "uniqueConstraints": { + "users_tags_id_unique": { + "name": "users_tags_id_unique", + "nullsNotDistinct": false, + "columns": ["id"] + } + } + }, + "public.user_teams": { + "name": "user_teams", + "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 + }, + "team_id": { + "name": "team_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'leader'" + }, + "discipline": { + "name": "discipline", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_participation_status": { + "name": "user_participation_status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'waiting_resolution'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_teams_user_id_users_id_fk": { + "name": "user_teams_user_id_users_id_fk", + "tableFrom": "user_teams", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "user_teams_team_id_teams_id_fk": { + "name": "user_teams_team_id_teams_id_fk", + "tableFrom": "user_teams", + "tableTo": "teams", + "columnsFrom": ["team_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.user_tickets": { + "name": "user_tickets", + "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 + }, + "ticket_template_id": { + "name": "ticket_template_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "purchase_order_id": { + "name": "purchase_order_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "approval_status": { + "name": "approval_status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "redemption_status": { + "name": "redemption_status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_tickets_user_id_users_id_fk": { + "name": "user_tickets_user_id_users_id_fk", + "tableFrom": "user_tickets", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "user_tickets_ticket_template_id_tickets_id_fk": { + "name": "user_tickets_ticket_template_id_tickets_id_fk", + "tableFrom": "user_tickets", + "tableTo": "tickets", + "columnsFrom": ["ticket_template_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "user_tickets_purchase_order_id_purchase_orders_id_fk": { + "name": "user_tickets_purchase_order_id_purchase_orders_id_fk", + "tableFrom": "user_tickets", + "tableTo": "purchase_orders", + "columnsFrom": ["purchase_order_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.work_email": { + "name": "work_email", + "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 + }, + "work_email": { + "name": "work_email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "confirmation_token_id": { + "name": "confirmation_token_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'pending'" + }, + "confirmation_date": { + "name": "confirmation_date", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "company_id": { + "name": "company_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "work_email_user_id_users_id_fk": { + "name": "work_email_user_id_users_id_fk", + "tableFrom": "work_email", + "tableTo": "users", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "work_email_confirmation_token_id_confirmation_token_id_fk": { + "name": "work_email_confirmation_token_id_confirmation_token_id_fk", + "tableFrom": "work_email", + "tableTo": "confirmation_token", + "columnsFrom": ["confirmation_token_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "work_email_company_id_companies_id_fk": { + "name": "work_email_company_id_companies_id_fk", + "tableFrom": "work_email", + "tableTo": "companies", + "columnsFrom": ["company_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.work_role": { + "name": "work_role", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.work_seniority": { + "name": "work_seniority", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "public.work_seniority_and_role": { + "name": "work_seniority_and_role", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "work_role_id": { + "name": "work_role_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "work_seniority_id": { + "name": "work_seniority_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp (6)", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "work_seniority_and_role_work_role_id_work_role_id_fk": { + "name": "work_seniority_and_role_work_role_id_work_role_id_fk", + "tableFrom": "work_seniority_and_role", + "tableTo": "work_role", + "columnsFrom": ["work_role_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "work_seniority_and_role_work_seniority_id_work_seniority_id_fk": { + "name": "work_seniority_and_role_work_seniority_id_work_seniority_id_fk", + "tableFrom": "work_seniority_and_role", + "tableTo": "work_seniority", + "columnsFrom": ["work_seniority_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": {}, + "schemas": {}, + "sequences": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} diff --git a/drizzle/migrations/meta/_journal.json b/drizzle/migrations/meta/_journal.json index 4a061a99..c2aaac3d 100644 --- a/drizzle/migrations/meta/_journal.json +++ b/drizzle/migrations/meta/_journal.json @@ -141,6 +141,13 @@ "when": 1722983703830, "tag": "0019_married_starfox", "breakpoints": true + }, + { + "idx": 20, + "version": "7", + "when": 1723328339423, + "tag": "0020_elite_electro", + "breakpoints": true } ] } diff --git a/package-lock.json b/package-lock.json index 998dafa0..53b2f3c4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,6 +21,7 @@ "@pothos/plugin-tracing": "^0.5.8", "@sanity/client": "^6.7.0", "@tsndr/cloudflare-worker-jwt": "^2.5.3", + "@types/jsonwebtoken": "^9.0.6", "@types/react": "^18.2.22", "cookie": "^0.5.0", "dataloader": "^2.2.2", @@ -76,6 +77,7 @@ "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-import": "^2.29.1", "graphql-tag": "^2.12.6", + "jsonwebtoken": "^9.0.2", "prettier": "^3.0.0", "react-email": "2.1.1", "tsx": "^3.13.0", @@ -8102,6 +8104,15 @@ "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, + "node_modules/@types/jsonwebtoken": { + "version": "9.0.6", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.6.tgz", + "integrity": "sha512-/5hndP5dCjloafCXns6SZyESp3Ldq7YjH3zwzwczYnjxIT0Fqzk5ROSYVGfFyczIue7IUEj8hkvLbPoLQ18vQw==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/lodash": { "version": "4.14.198", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.198.tgz", @@ -9806,6 +9817,13 @@ "ieee754": "^1.1.13" } }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "dev": true, + "license": "BSD-3-Clause" + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -11695,6 +11713,16 @@ "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, "node_modules/editorconfig": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-1.0.4.tgz", @@ -15015,6 +15043,65 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jsonwebtoken/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, "node_modules/keyv": { "version": "4.5.3", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.3.tgz", @@ -15215,6 +15302,48 @@ "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==" }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "dev": true, + "license": "MIT" + }, "node_modules/lodash.lowercase": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.lowercase/-/lodash.lowercase-4.3.0.tgz", @@ -15227,6 +15356,13 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "dev": true, + "license": "MIT" + }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", diff --git a/package.json b/package.json index 7bf26b58..9ab2d5ba 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,9 @@ "@react-email/components": "0.0.16", "@total-typescript/ts-reset": "^0.4.2", "@types/cookie": "^0.5.1", + "@types/jsonwebtoken": "^9.0.6", "@types/pg": "^8.11.5", + "@types/react": "^18.2.22", "@typescript-eslint/eslint-plugin": "^5.61.0", "@typescript-eslint/parser": "^5.61.0", "@vitest/coverage-v8": "^0.33.0", @@ -56,6 +58,7 @@ "eslint-import-resolver-typescript": "^3.6.1", "eslint-plugin-import": "^2.29.1", "graphql-tag": "^2.12.6", + "jsonwebtoken": "^9.0.2", "prettier": "^3.0.0", "react-email": "2.1.1", "tsx": "^3.13.0", @@ -85,7 +88,6 @@ "@pothos/plugin-tracing": "^0.5.8", "@sanity/client": "^6.7.0", "@tsndr/cloudflare-worker-jwt": "^2.5.3", - "@types/react": "^18.2.22", "cookie": "^0.5.0", "dataloader": "^2.2.2", "date-fns": "^3.6.0", diff --git a/src/authn/index.ts b/src/authn/index.ts index 5fcc2105..3acb6f8e 100644 --- a/src/authn/index.ts +++ b/src/authn/index.ts @@ -9,7 +9,9 @@ import { updateUserProfileInfo, } from "~/datasources/queries/users"; import { getUsername } from "~/datasources/queries/utils/createUsername"; -import { unauthorizedError } from "~/errors"; +import { applicationError, ServiceErrors, unauthorizedError } from "~/errors"; + +const preventUserUpdate = new Set<"retool">(["retool"]); // Obtener el token de autorización de la solicitud, ya sea del encabezado de // autorización o de la cookie "community-os-access-token" @@ -122,26 +124,39 @@ export const upsertUserFromRequest = async ({ throw unauthorizedError("Token expired", logger); } - const { avatar_url, name, user_name, email_verified, sub, picture } = - payload.user_metadata; - const profileInfo = insertUsersSchema.safeParse({ - email: payload.email.toLowerCase(), - isEmailVerified: email_verified, - imageUrl: avatar_url ? avatar_url : picture ? picture : "", - externalId: sub, - name, - username: user_name ?? getUsername(), - publicMetadata: payload, - }); - - if (profileInfo.success === false) { - logger.error("Could not parse profile info", profileInfo.error); - throw new Error("Could not parse profile info", profileInfo.error); - } + if (payload.audience && preventUserUpdate.has(payload.audience)) { + const userId = payload.user_metadata.sub; + + logger.info(`Preventing update for user ID: ${userId}`); + const user = await findUserByID(DB, userId); + + if (!user) { + throw applicationError("User not found", ServiceErrors.FORBIDDEN, logger); + } - logger.info(`Updating profile Info for user ID: ${sub}`); + return user; + } else { + const { avatar_url, name, user_name, email_verified, sub, picture } = + payload.user_metadata; + const profileInfo = insertUsersSchema.safeParse({ + email: payload.email.toLowerCase(), + isEmailVerified: email_verified, + imageUrl: avatar_url ? avatar_url : picture ? picture : "", + externalId: sub, + name, + username: user_name ?? getUsername(), + publicMetadata: payload, + }); + + if (profileInfo.success === false) { + logger.error("Could not parse profile info", profileInfo.error); + throw new Error("Could not parse profile info", profileInfo.error); + } + + logger.info(`Updating profile Info for user ID: ${sub}`); - return updateUserProfileInfo(DB, profileInfo.data, logger); + return updateUserProfileInfo(DB, profileInfo.data, logger); + } }; export const logPossibleUserIdFromJWT = ( diff --git a/src/authn/types.ts b/src/authn/types.ts index fca6b6c0..fd072fdb 100644 --- a/src/authn/types.ts +++ b/src/authn/types.ts @@ -7,6 +7,7 @@ export type TokenPayload = { sub: string; email: string; phone: string; + audience?: string; app_metadata: { provider: string; providers: string[] }; user_metadata: { avatar_url: string; diff --git a/src/context.ts b/src/context.ts index 6a1e7cca..66573c91 100644 --- a/src/context.ts +++ b/src/context.ts @@ -25,6 +25,8 @@ export const createGraphqlContext = async ({ SANITY_API_VERSION, SANITY_SECRET_TOKEN, SUPABASE_JWT_DECODER, + SUPABASE_JWT_ENCODER, + RETOOL_AUTHENTICATION_TOKEN, STRIPE_KEY, HYPERDRIVE, MERCADOPAGO_KEY, @@ -38,6 +40,14 @@ export const createGraphqlContext = async ({ throw new Error("Missing MAIL_QUEUE"); } + if (!RETOOL_AUTHENTICATION_TOKEN) { + throw new Error("Missing RETOOL_AUTHENTICATION_TOKEN"); + } + + if (!SUPABASE_JWT_ENCODER) { + throw new Error("Missing SUPABASE_JWT_ENCODER"); + } + if (!RPC_SERVICE_EMAIL) { throw new Error("RPC_SERVICE_EMAIL is not defined"); } @@ -134,5 +144,7 @@ export const createGraphqlContext = async ({ GET_MERCADOPAGO_CLIENT, logger, RPC_SERVICE_EMAIL, + RETOOL_AUTHENTICATION_TOKEN, + SUPABASE_JWT_ENCODER, } satisfies Context; }; diff --git a/src/datasources/db/users.ts b/src/datasources/db/users.ts index 8313b1ea..26296e26 100644 --- a/src/datasources/db/users.ts +++ b/src/datasources/db/users.ts @@ -48,6 +48,7 @@ export const usersSchema = pgTable("users", { }).default(UserStatusEnum.inactive), genderOtherText: text("gender_other_text"), isSuperAdmin: boolean("isSuperAdmin").default(false).notNull(), + isRetoolEnabled: boolean("isRetoolEnabled").default(false).notNull(), isEmailVerified: boolean("emailVerified").default(false).notNull(), imageUrl: text("imageUrl"), username: text("username").unique().notNull(), diff --git a/src/generated/schema.gql b/src/generated/schema.gql index dc703124..d2f16f60 100644 --- a/src/generated/schema.gql +++ b/src/generated/schema.gql @@ -363,6 +363,11 @@ type Mutation { """ rejectTeamInvitation(input: RejectTeamInvitationInput!): TeamRef! + """ + Update a user role + """ + retoolToken(input: retoolToken!): TokenRef! @deprecated(reason: "Not enabled") + """ Kickoff the email validation flow. This flow will links an email to a user, create a company if it does not exist, and allows filling data for that email's position """ @@ -962,6 +967,13 @@ enum TicketTemplateVisibility { unlisted } +""" +Representation of a token +""" +type TokenRef { + token: String! +} + enum TypeOfEmployment { freelance fullTime @@ -1111,6 +1123,11 @@ type WorkSeniority { name: String! } +input retoolToken { + authToken: String! + userEmail: String! +} + input updateUserRoleInCommunityInput { communityId: String! role: String! diff --git a/src/generated/types.ts b/src/generated/types.ts index 6b652127..2e6c7ac3 100644 --- a/src/generated/types.ts +++ b/src/generated/types.ts @@ -321,6 +321,11 @@ export type Mutation = { redeemUserTicket: UserTicket; /** Reject the user's invitation to a team */ rejectTeamInvitation: TeamRef; + /** + * Update a user role + * @deprecated Not enabled + */ + retoolToken: TokenRef; /** Kickoff the email validation flow. This flow will links an email to a user, create a company if it does not exist, and allows filling data for that email's position */ startWorkEmailValidation: WorkEmail; /** Update a company */ @@ -421,6 +426,10 @@ export type MutationRejectTeamInvitationArgs = { input: RejectTeamInvitationInput; }; +export type MutationRetoolTokenArgs = { + input: RetoolToken; +}; + export type MutationStartWorkEmailValidationArgs = { email: Scalars["String"]["input"]; }; @@ -977,6 +986,12 @@ export enum TicketTemplateVisibility { Unlisted = "unlisted", } +/** Representation of a token */ +export type TokenRef = { + __typename?: "TokenRef"; + token: Scalars["String"]["output"]; +}; + export enum TypeOfEmployment { Freelance = "freelance", FullTime = "fullTime", @@ -1119,6 +1134,11 @@ export type WorkSeniority = { name: Scalars["String"]["output"]; }; +export type RetoolToken = { + authToken: Scalars["String"]["input"]; + userEmail: Scalars["String"]["input"]; +}; + export type UpdateUserRoleInCommunityInput = { communityId: Scalars["String"]["input"]; role: Scalars["String"]["input"]; diff --git a/src/schema/shared/refs.ts b/src/schema/shared/refs.ts index 019966ea..067da694 100644 --- a/src/schema/shared/refs.ts +++ b/src/schema/shared/refs.ts @@ -96,3 +96,7 @@ export const ConsolidatedPaymentLogEntryRef = builder.objectRef<{ platform: string; currencyId: string; }>("ConsolidatedPaymentLogEntry"); + +export const TokenRef = builder.objectRef<{ + token: string; +}>("TokenRef"); diff --git a/src/schema/user/mutations.ts b/src/schema/user/mutations.ts index 1fcb56be..0e37f920 100644 --- a/src/schema/user/mutations.ts +++ b/src/schema/user/mutations.ts @@ -1,3 +1,4 @@ +import { sign } from "@tsndr/cloudflare-worker-jwt"; import { eq } from "drizzle-orm"; import { GraphQLError } from "graphql"; @@ -6,10 +7,12 @@ import { PronounsEnum, selectUsersSchema, updateUsersSchema, + USER, usersSchema, usersToCommunitiesSchema, } from "~/datasources/db/schema"; -import { UserRef } from "~/schema/shared/refs"; +import { applicationError, ServiceErrors } from "~/errors"; +import { TokenRef, UserRef } from "~/schema/shared/refs"; import { pronounsEnum } from "~/schema/user/types"; import { UserRoleCommunity, @@ -17,6 +20,20 @@ import { isSameUser, } from "~/validations"; +const createMinimalAuthToken = async (user: USER, SECRET: string) => { + const payload = { + audience: "retool", + user_metadata: { + sub: user.id, + }, + exp: Date.now() + 60 * 60 * 24 * 1000 /* 24 hours */, + }; + + const token = await sign(payload, SECRET); + + return token; +}; + const userEditInput = builder.inputType("userEditInput", { fields: (t) => ({ id: t.string({ required: true }), @@ -156,3 +173,62 @@ builder.mutationField("updateUserRoleInCommunity", (t) => }, }), ); + +const retoolToken = builder.inputType("retoolToken", { + fields: (t) => ({ + userEmail: t.string({ required: true }), + authToken: t.string({ required: true }), + }), +}); + +builder.mutationField("retoolToken", (t) => + t.field({ + description: "Update a user role", + type: TokenRef, + deprecationReason: "Not enabled", + nullable: false, + args: { + input: t.arg({ type: retoolToken, required: true }), + }, + resolve: async (root, { input }, ctx) => { + try { + const { userEmail, authToken } = input; + + if (authToken !== ctx.RETOOL_AUTHENTICATION_TOKEN) { + throw new Error("Not authorized"); + } + + const user = await ctx.DB.query.usersSchema.findFirst({ + where: (u, { eq, and }) => + and( + eq(u.email, userEmail), + eq(u.isRetoolEnabled, true), + eq(u.isEmailVerified, true), + eq(u.isSuperAdmin, true), + ), + }); + + if (!user) { + throw new Error("Not authorized"); + } + + const selectedUser = selectUsersSchema.parse(user); + + const token = await createMinimalAuthToken( + selectedUser, + ctx.SUPABASE_JWT_ENCODER, + ); + + return { + token, + }; + } catch (e) { + throw applicationError( + "Not authorized", + ServiceErrors.FORBIDDEN, + ctx.logger, + ); + } + }, + }), +); diff --git a/src/schema/user/tests/token.generated.ts b/src/schema/user/tests/token.generated.ts new file mode 100644 index 00000000..1393ee0d --- /dev/null +++ b/src/schema/user/tests/token.generated.ts @@ -0,0 +1,23 @@ +/* eslint-disable */ +/* @ts-nocheck */ +/* prettier-ignore */ +/* This file is automatically generated using `npm run graphql:types` */ +import type * as Types from '../../../generated/types'; + +import type { JsonObject } from "type-fest"; +import gql from 'graphql-tag'; +export type TokensMutationVariables = Types.Exact<{ + input: Types.RetoolToken; +}>; + + +export type TokensMutation = { __typename?: 'Mutation', retoolToken: { __typename?: 'TokenRef', token: string } }; + + +export const Tokens = gql` + mutation Tokens($input: retoolToken!) { + retoolToken(input: $input) { + token + } +} + `; \ No newline at end of file diff --git a/src/schema/user/tests/token.gql b/src/schema/user/tests/token.gql new file mode 100644 index 00000000..4f88e641 --- /dev/null +++ b/src/schema/user/tests/token.gql @@ -0,0 +1,5 @@ +mutation Tokens($input: retoolToken!) { + retoolToken(input: $input) { + token + } +} diff --git a/src/schema/user/tests/token.test.ts b/src/schema/user/tests/token.test.ts new file mode 100644 index 00000000..3a294df3 --- /dev/null +++ b/src/schema/user/tests/token.test.ts @@ -0,0 +1,72 @@ +import { faker } from "@faker-js/faker"; +import { verify } from "jsonwebtoken"; +import { it, describe, assert } from "vitest"; + +import { executeGraphqlOperation, insertUser } from "~/tests/fixtures"; + +import { + Tokens, + TokensMutation, + TokensMutationVariables, +} from "./token.generated"; + +describe("User", () => { + it("Should create a token", async () => { + const retoolToken = faker.string.alphanumeric(10); + const encoder = faker.string.alphanumeric(10); + const user1 = await insertUser({ + isRetoolEnabled: true, + isSuperAdmin: true, + isEmailVerified: true, + }); + const response = await executeGraphqlOperation< + TokensMutation, + TokensMutationVariables + >( + { + document: Tokens, + variables: { + input: { + authToken: retoolToken, + userEmail: user1.email, + }, + }, + }, + { + RETOOL_AUTHENTICATION_TOKEN: retoolToken, + SUPABASE_JWT_ENCODER: encoder, + }, + ); + + assert.equal(response.errors, undefined); + + const token = response.data?.retoolToken?.token; + + assert.exists(token); + + if (!token) { + throw new Error("Token not found"); + } + + const decodedToken = verify(token, encoder, { + complete: true, + }) as unknown as { + payload: { + audience: string; + user_metadata: { + sub: string; + }; + }; + }; + + assert.exists(token); + + const { user_metadata: userTokenData, audience } = decodedToken.payload; + + assert.equal(userTokenData?.sub, user1.id); + + assert.equal(Object.keys(userTokenData).length, 1); + + assert.equal(audience, "retool"); + }); +}); diff --git a/src/schema/user/types.ts b/src/schema/user/types.ts index 664cd8ac..618a3ccb 100644 --- a/src/schema/user/types.ts +++ b/src/schema/user/types.ts @@ -6,7 +6,7 @@ import { selectCommunitySchema, selectTeamsSchema, } from "~/datasources/db/schema"; -import { CommunityRef, UserRef } from "~/schema/shared/refs"; +import { CommunityRef, TokenRef, UserRef } from "~/schema/shared/refs"; import { TeamRef } from "~/schema/teams/types"; export const pronounsEnum = builder.enumType(PronounsEnum, { @@ -108,3 +108,10 @@ builder.objectType(UserRef, { export const SearchableUserTags = builder.enumType("SearchableUserTags", { values: Object.values(AllowedUserTags), }); + +builder.objectType(TokenRef, { + description: "Representation of a token", + fields: (t) => ({ + token: t.exposeString("token", { nullable: false }), + }), +}); diff --git a/src/tests/fixtures/index.ts b/src/tests/fixtures/index.ts index 49ff2958..5b7bd1cf 100644 --- a/src/tests/fixtures/index.ts +++ b/src/tests/fixtures/index.ts @@ -100,6 +100,7 @@ import { import { defaultLogger } from "~/logging"; import { schema } from "~/schema"; import { getTestDB } from "~/tests/fixtures/databaseHelper"; +import { Context } from "~/types"; const insertUserRequest = insertUsersSchema.deepPartial(); @@ -121,7 +122,10 @@ const CRUDDates = ({ deletedAt: typeof deletedAt !== "undefined" ? deletedAt : faker.date.recent(), }); -const createExecutor = (user?: Awaited>) => +const createExecutor = ( + user?: Awaited> | undefined, + context?: Partial, +) => buildHTTPExecutor({ fetch: createYoga({ schema, @@ -134,6 +138,7 @@ const createExecutor = (user?: Awaited>) => logger: defaultLogger, USER: user ? user : undefined, GET_STRIPE_CLIENT: () => null, + ...(context ?? {}), }; }, plugins: [authZEnvelopPlugin({ rules })], @@ -145,8 +150,9 @@ export const executeGraphqlOperation = < TVariables extends Record = Record, >( params: ExecutionRequest, + context?: Partial, ): Promise> => { - const executor = createExecutor(); + const executor = createExecutor(undefined, context); // @ts-expect-error This is ok. Executor returns a promise with they types passed return executor(params); @@ -158,8 +164,9 @@ export const executeGraphqlOperationAsUser = < >( params: ExecutionRequest, user: Awaited>, + context?: Partial, ): Promise> => { - const executor = createExecutor(user); + const executor = createExecutor(user, context); // @ts-expect-error This error is ok. Executor returns a promise with they types passed return executor(params); @@ -171,13 +178,14 @@ export const executeGraphqlOperationAsSuperAdmin = async < >( params: ExecutionRequest, user?: Awaited>, + context?: Partial, ): Promise> => { if (user && !user.isSuperAdmin) { throw new Error("User passed is not a super admin"); } const superAdmin = user ?? (await insertUser({ isSuperAdmin: true })); - const executor = createExecutor(superAdmin); + const executor = createExecutor(superAdmin, context); // @ts-expect-error This error is ok. Executor returns a promise with they types passed return executor(params); @@ -234,10 +242,11 @@ export const insertUser = async ( externalId: partialInput?.externalId ?? faker.string.uuid(), username: partialInput?.username ?? faker.internet.userName(), bio: partialInput?.bio ?? faker.lorem.paragraph(), - email: partialInput?.email ?? faker.internet.email(), + email: (partialInput?.email ?? faker.internet.email()).toLowerCase(), name: partialInput?.name, isSuperAdmin: partialInput?.isSuperAdmin, isEmailVerified: partialInput?.isEmailVerified, + isRetoolEnabled: partialInput?.isRetoolEnabled, pronouns: partialInput?.pronouns ?? faker.helpers.arrayElement(Object.values(PronounsEnum)), diff --git a/src/types.ts b/src/types.ts index ad70d5c2..01255270 100644 --- a/src/types.ts +++ b/src/types.ts @@ -21,6 +21,8 @@ export type Context = { GOOGLE_PHOTOS_IMPORT_QUEUE: Queue; PURCHASE_CALLBACK_URL: string; RPC_SERVICE_EMAIL: Env["RPC_SERVICE_EMAIL"]; + RETOOL_AUTHENTICATION_TOKEN: string; + SUPABASE_JWT_ENCODER: string; }; export type GraphqlContext = Context & diff --git a/worker-configuration.d.ts b/worker-configuration.d.ts index 6d631a62..8f07b9ac 100644 --- a/worker-configuration.d.ts +++ b/worker-configuration.d.ts @@ -1,5 +1,6 @@ // Generated by Wrangler on Fri Jul 07 2023 08:10:34 GMT-0700 (Pacific Daylight Time) import type WorkerEntrypoint from "./workers/transactional_email_service"; + export interface Env { GRAPHQL_BASE_ENDPOINT: "/"; NEON_URL: string | undefined; @@ -18,6 +19,8 @@ export interface Env { HYPERDRIVE: Hyperdrive; PURCHASE_CALLBACK_URL: string; RPC_SERVICE_EMAIL: Service; + RETOOL_AUTHENTICATION_TOKEN: string; + SUPABASE_JWT_ENCODER: string; } declare global {