From 18a801a82e37639d02d177ec32b76ed50ae657bc Mon Sep 17 00:00:00 2001 From: esteban Date: Sun, 16 Aug 2026 13:25:18 -0500 Subject: [PATCH] cached results and queries, add users and auth for admin --- .env.example | 9 + .gitea/workflows/deploy.yaml | 1 + .../migration.sql | 25 +++ .../migration.sql | 5 + prisma/schema.prisma | 19 ++- src/components/Header.astro | 28 ++-- src/components/admin/AdminDashboard.vue | 3 +- src/components/admin/SearchableCombobox.vue | 3 +- src/components/admin/VoluntarioDetail.vue | 3 +- src/components/admin/VoluntariosTable.vue | 5 +- src/lib/adminCache.ts | 63 +++++++ src/middleware.ts | 45 ++++- src/pages/[locale]/admin/login.astro | 156 ++++++++++++++++++ src/pages/api/admin/auth/login.ts | 64 +++++++ src/pages/api/admin/auth/logout.ts | 16 ++ src/pages/api/admin/voluntarios.ts | 2 + src/pages/api/admin/voluntarios/[numero].ts | 2 + src/pages/api/admin/voluntarios/distinct.ts | 2 + src/pages/api/admin/voluntarios/options.ts | 2 + src/pages/api/admin/voluntarios/stats.ts | 2 + src/pages/api/lib/auth.ts | 129 +++++++++++++++ src/pages/api/lib/email.ts | 5 + 22 files changed, 568 insertions(+), 21 deletions(-) create mode 100644 prisma/migrations/20260816105155_add_admin_auth/migration.sql create mode 100644 prisma/migrations/20260816122101_add_admin_username/migration.sql create mode 100644 src/lib/adminCache.ts create mode 100644 src/pages/[locale]/admin/login.astro create mode 100644 src/pages/api/admin/auth/login.ts create mode 100644 src/pages/api/admin/auth/logout.ts create mode 100644 src/pages/api/lib/auth.ts diff --git a/.env.example b/.env.example index 1162174..c366ac7 100644 --- a/.env.example +++ b/.env.example @@ -12,3 +12,12 @@ SUPABASE_URL="http://localhost:8000" SUPABASE_ANON_KEY="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJhbm9uIiwKICAgICJpc3MiOiAic3VwYWJhc2UtZGVtbyIsCiAgICAiaWF0IjogMTY0MTc2OTIwMCwKICAgICJleHAiOiAxNzk5NTM1NjAwCn0.dc_X5iR_VP_qT0zsiyj_I_OZ2T9FtRU2BBNWN8Bu4GE" SUPABASE_SERVICE_ROLE_KEY="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJzZXJ2aWNlX3JvbGUiLAogICAgImlzcyI6ICJzdXBhYmFzZS1kZW1vIiwKICAgICJpYXQiOiAxNjQxNzY5MjAwLAogICAgImV4cCI6IDE3OTk1MzU2MDAKfQ.DaYlNEoUrrEn2Ig7tqibS-PHK5vgusbcbo7X36XVt4Q" POSTGRES_PASSWORD=postgres + +# Admin auth — API key (para consumo externo de /api/admin/*) +ADMIN_API_KEY="CHANGE_ME_admin_api_key" + +# Admin auth — credenciales del seed (solo se usan en scripts/seed-admin.ts) +ADMIN_EMAIL="admin@example.com" +ADMIN_USERNAME="admin" +ADMIN_PASSWORD="CHANGE_ME_password" +ADMIN_NOMBRE="Admin" diff --git a/.gitea/workflows/deploy.yaml b/.gitea/workflows/deploy.yaml index 9636a0e..5837b36 100644 --- a/.gitea/workflows/deploy.yaml +++ b/.gitea/workflows/deploy.yaml @@ -63,6 +63,7 @@ jobs: TURNSTILE_SECRET_KEY="${{ secrets.TURNSTILE_SECRET_KEY }}" CLOUDFLARE_API_TOKEN="${{ secrets.CLOUDFLARE_API_TOKEN }}" CLOUDFLARE_ACCOUNT_ID="${{ secrets.CLOUDFLARE_ACCOUNT_ID }}" + ADMIN_API_KEY="${{ secrets.ADMIN_API_KEY }}" ENVEOF pm2 reload ecosystem.config.cjs --only ${{ env.APP_NAME }} --update-env || \ pm2 start ecosystem.config.cjs --only ${{ env.APP_NAME }} --update-env diff --git a/prisma/migrations/20260816105155_add_admin_auth/migration.sql b/prisma/migrations/20260816105155_add_admin_auth/migration.sql new file mode 100644 index 0000000..3cfa438 --- /dev/null +++ b/prisma/migrations/20260816105155_add_admin_auth/migration.sql @@ -0,0 +1,25 @@ +-- AlterTable +ALTER TABLE "admins" ALTER COLUMN "auth_user_id" DROP NOT NULL; + +-- AlterTable +ALTER TABLE "admins" ADD COLUMN "password_hash" TEXT; + +-- CreateTable +CREATE TABLE "sessions" ( + "id" UUID NOT NULL, + "token_hash" TEXT NOT NULL, + "admin_id" UUID NOT NULL, + "expires_at" TIMESTAMPTZ NOT NULL, + "created_at" TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + + CONSTRAINT "sessions_pkey" PRIMARY KEY ("id") +); + +-- CreateIndex +CREATE UNIQUE INDEX "sessions_token_hash_key" ON "sessions"("token_hash"); + +-- CreateIndex +CREATE INDEX "sessions_admin_id_idx" ON "sessions"("admin_id"); + +-- AddForeignKey +ALTER TABLE "sessions" ADD CONSTRAINT "sessions_admin_id_fkey" FOREIGN KEY ("admin_id") REFERENCES "admins"("id") ON DELETE CASCADE ON UPDATE CASCADE; diff --git a/prisma/migrations/20260816122101_add_admin_username/migration.sql b/prisma/migrations/20260816122101_add_admin_username/migration.sql new file mode 100644 index 0000000..6fd773d --- /dev/null +++ b/prisma/migrations/20260816122101_add_admin_username/migration.sql @@ -0,0 +1,5 @@ +-- AlterTable +ALTER TABLE "admins" ADD COLUMN "username" TEXT; + +-- CreateIndex +CREATE UNIQUE INDEX "admins_username_key" ON "admins"("username"); diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 6358ffc..95a8873 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -130,14 +130,31 @@ model FormVersion { model Admin { id String @id @default(uuid()) @db.Uuid - auth_user_id String @unique @db.Uuid + auth_user_id String? @unique @db.Uuid email String @unique + username String? @unique nombre String + password_hash String? rol String @default("coordinador") activo Boolean @default(true) ultimo_acceso DateTime? @db.Timestamptz created_at DateTime @default(now()) @db.Timestamptz + sessions Session[] + @@index([email]) @@map("admins") } + +model Session { + id String @id @default(uuid()) @db.Uuid + token_hash String @unique + admin_id String @db.Uuid + expires_at DateTime @db.Timestamptz + created_at DateTime @default(now()) @db.Timestamptz + + admin Admin @relation(fields: [admin_id], references: [id], onDelete: Cascade) + + @@index([admin_id]) + @@map("sessions") +} diff --git a/src/components/Header.astro b/src/components/Header.astro index 679de8a..da02ec4 100644 --- a/src/components/Header.astro +++ b/src/components/Header.astro @@ -159,12 +159,14 @@ function translatePath(newLocale: string) { } {isAdmin && (
  • - - Acceder - +
    + +
  • )} @@ -215,12 +217,14 @@ function translatePath(newLocale: string) { {isAdmin && ( )}