base con autenticacion, registro, modulo encuestas
This commit is contained in:
22
apps/api/src/database/drizzle-provider.ts
Normal file
22
apps/api/src/database/drizzle-provider.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { Provider } from '@nestjs/common';
|
||||
import { drizzle, NodePgDatabase } from 'drizzle-orm/node-postgres';
|
||||
import { Pool } from 'pg';
|
||||
import * as schema from './index';
|
||||
import { envs } from 'src/common/config/envs';
|
||||
|
||||
export const DRIZZLE_PROVIDER = 'DRIZZLE_PROVIDER';
|
||||
|
||||
export type DrizzleDatabase = NodePgDatabase<typeof schema>;
|
||||
|
||||
export const DrizzleProvider: Provider = {
|
||||
provide: DRIZZLE_PROVIDER,
|
||||
useFactory: () => {
|
||||
const pool = new Pool({
|
||||
connectionString: envs.dataBaseUrl,
|
||||
ssl:
|
||||
envs.node_env === 'production' ? { rejectUnauthorized: false } : false,
|
||||
});
|
||||
|
||||
return drizzle(pool, { schema }) as DrizzleDatabase;
|
||||
},
|
||||
};
|
||||
10
apps/api/src/database/drizzle.module.ts
Normal file
10
apps/api/src/database/drizzle.module.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { Global, Module } from '@nestjs/common';
|
||||
import { DrizzleProvider } from './drizzle-provider';
|
||||
|
||||
@Global()
|
||||
@Module({
|
||||
imports: [],
|
||||
providers: [DrizzleProvider],
|
||||
exports: [DrizzleProvider],
|
||||
})
|
||||
export class DrizzleModule {}
|
||||
5
apps/api/src/database/index.ts
Normal file
5
apps/api/src/database/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
|
||||
export * from './schema/activity_logs';
|
||||
export * from './schema/auth';
|
||||
export * from './schema/general';
|
||||
export * from './schema/surveys'
|
||||
173
apps/api/src/database/migrations/0000_abnormal_lethal_legion.sql
Normal file
173
apps/api/src/database/migrations/0000_abnormal_lethal_legion.sql
Normal file
@@ -0,0 +1,173 @@
|
||||
CREATE SCHEMA "auth";
|
||||
--> statement-breakpoint
|
||||
CREATE TYPE "auth"."gender" AS ENUM('FEMENINO', 'MASCULINO');--> statement-breakpoint
|
||||
CREATE TYPE "public"."nationality" AS ENUM('VENEZOLANO', 'EXTRANJERO');--> statement-breakpoint
|
||||
CREATE TYPE "auth"."status" AS ENUM('ACTIVE', 'INACTIVE');--> statement-breakpoint
|
||||
CREATE TABLE "activity_logs" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"user_id" integer,
|
||||
"type" text NOT NULL,
|
||||
"description" text NOT NULL,
|
||||
"timestamp" timestamp DEFAULT now(),
|
||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp (3)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "auth"."roles" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"name" text NOT NULL,
|
||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp (3)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "auth"."sessions" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"user_id" integer NOT NULL,
|
||||
"session_token" text NOT NULL,
|
||||
"expires_at" integer NOT NULL,
|
||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp (3)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "auth"."users" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"username" text NOT NULL,
|
||||
"email" text NOT NULL,
|
||||
"fullname" text NOT NULL,
|
||||
"phone" text,
|
||||
"password" text NOT NULL,
|
||||
"is_two_factor_enabled" boolean DEFAULT false NOT NULL,
|
||||
"two_factor_secret" text,
|
||||
"is_email_verified" boolean DEFAULT false NOT NULL,
|
||||
"is_active" boolean DEFAULT true NOT NULL,
|
||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp (3),
|
||||
CONSTRAINT "users_username_unique" UNIQUE("username"),
|
||||
CONSTRAINT "users_email_unique" UNIQUE("email")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "auth"."user_role" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"user_id" integer,
|
||||
"role_id" integer,
|
||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp (3)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "auth"."verificationToken" (
|
||||
"identifier" text NOT NULL,
|
||||
"token" text NOT NULL,
|
||||
"code" integer,
|
||||
"expires" timestamp NOT NULL,
|
||||
"ip_address" text NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "category_type" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"group" varchar(100) NOT NULL,
|
||||
"description" text NOT NULL,
|
||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp (3)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "localities" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"state_id" integer NOT NULL,
|
||||
"municipality_id" integer NOT NULL,
|
||||
"parish_id" integer NOT NULL,
|
||||
"name" text NOT NULL,
|
||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp (3),
|
||||
CONSTRAINT "localities_name_unique" UNIQUE("name")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "municipalities" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"name" text NOT NULL,
|
||||
"state_id" integer NOT NULL,
|
||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp (3)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "parishes" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"name" text NOT NULL,
|
||||
"municipality_id" integer NOT NULL,
|
||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp (3)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "states" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"name" text NOT NULL,
|
||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp (3)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "answers_surveys" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"survey_id" integer,
|
||||
"user_id" integer,
|
||||
"answers" jsonb NOT NULL,
|
||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp (3)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE "surveys" (
|
||||
"id" serial PRIMARY KEY NOT NULL,
|
||||
"title" text NOT NULL,
|
||||
"description" text NOT NULL,
|
||||
"target_audience" varchar(50) NOT NULL,
|
||||
"closing_date" date,
|
||||
"published" boolean NOT NULL,
|
||||
"questions" jsonb NOT NULL,
|
||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||
"updated_at" timestamp (3)
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "activity_logs" ADD CONSTRAINT "activity_logs_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "auth"."users"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "auth"."sessions" ADD CONSTRAINT "sessions_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "auth"."users"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "auth"."user_role" ADD CONSTRAINT "user_role_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "auth"."users"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "auth"."user_role" ADD CONSTRAINT "user_role_role_id_roles_id_fk" FOREIGN KEY ("role_id") REFERENCES "auth"."roles"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "localities" ADD CONSTRAINT "localities_state_id_states_id_fk" FOREIGN KEY ("state_id") REFERENCES "public"."states"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "localities" ADD CONSTRAINT "localities_municipality_id_municipalities_id_fk" FOREIGN KEY ("municipality_id") REFERENCES "public"."municipalities"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "localities" ADD CONSTRAINT "localities_parish_id_parishes_id_fk" FOREIGN KEY ("parish_id") REFERENCES "public"."parishes"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "municipalities" ADD CONSTRAINT "municipalities_state_id_states_id_fk" FOREIGN KEY ("state_id") REFERENCES "public"."states"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "parishes" ADD CONSTRAINT "parishes_municipality_id_municipalities_id_fk" FOREIGN KEY ("municipality_id") REFERENCES "public"."municipalities"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "answers_surveys" ADD CONSTRAINT "answers_surveys_survey_id_surveys_id_fk" FOREIGN KEY ("survey_id") REFERENCES "public"."surveys"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "answers_surveys" ADD CONSTRAINT "answers_surveys_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "auth"."users"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||||
CREATE INDEX "activityLogs_idx" ON "activity_logs" USING btree ("type");--> statement-breakpoint
|
||||
CREATE INDEX "roles_idx" ON "auth"."roles" USING btree ("name");--> statement-breakpoint
|
||||
CREATE INDEX "sessions_idx" ON "auth"."sessions" USING btree ("session_token");--> statement-breakpoint
|
||||
CREATE INDEX "users_idx" ON "auth"."users" USING btree ("username");--> statement-breakpoint
|
||||
CREATE INDEX "user_role_idx" ON "auth"."user_role" USING btree ("user_id");--> statement-breakpoint
|
||||
CREATE INDEX "category_typeIx0" ON "category_type" USING btree ("group");--> statement-breakpoint
|
||||
CREATE INDEX "category_typeIx1" ON "category_type" USING btree ("description");--> statement-breakpoint
|
||||
CREATE UNIQUE INDEX "localities_index_03" ON "localities" USING btree ("state_id","municipality_id","parish_id");--> statement-breakpoint
|
||||
CREATE INDEX "localities_index_00" ON "localities" USING btree ("state_id");--> statement-breakpoint
|
||||
CREATE INDEX "localities_index_01" ON "localities" USING btree ("municipality_id");--> statement-breakpoint
|
||||
CREATE INDEX "localities_index_02" ON "localities" USING btree ("parish_id");--> statement-breakpoint
|
||||
CREATE INDEX "municipalities_index_00" ON "municipalities" USING btree ("id","name","state_id");--> statement-breakpoint
|
||||
CREATE INDEX "parishes_index_00" ON "parishes" USING btree ("id","name","municipality_id");--> statement-breakpoint
|
||||
CREATE INDEX "states_index_00" ON "states" USING btree ("id","name");--> statement-breakpoint
|
||||
CREATE INDEX "answers_index_00" ON "answers_surveys" USING btree ("answers");--> statement-breakpoint
|
||||
CREATE INDEX "answers_index_01" ON "answers_surveys" USING btree ("survey_id");--> statement-breakpoint
|
||||
CREATE INDEX "answers_index_02" ON "answers_surveys" USING btree ("user_id");--> statement-breakpoint
|
||||
CREATE INDEX "surveys_index_00" ON "surveys" USING btree ("title");--> statement-breakpoint
|
||||
CREATE VIEW "auth"."user_access_view" AS (
|
||||
SELECT
|
||||
u.id AS user_id,
|
||||
u.username,
|
||||
u.email,
|
||||
u.fullname,
|
||||
r.id AS role_id,
|
||||
r.name AS role_name
|
||||
FROM
|
||||
auth.users u
|
||||
LEFT JOIN
|
||||
auth.user_role ur ON u.id = ur.user_id
|
||||
LEFT JOIN
|
||||
auth.roles r ON ur.role_id = r.id);--> statement-breakpoint
|
||||
CREATE VIEW "public"."v_surveys" AS (select s.id as survey_id, s.title, s.description, s.created_at, s.closing_date, s.target_audience, as2.user_id from surveys s
|
||||
left join answers_surveys as2 on as2.survey_id = s.id
|
||||
where s.published = true);
|
||||
9
apps/api/src/database/migrations/0001_massive_kylun.sql
Normal file
9
apps/api/src/database/migrations/0001_massive_kylun.sql
Normal file
@@ -0,0 +1,9 @@
|
||||
DROP VIEW "public"."v_surveys";--> statement-breakpoint
|
||||
ALTER TABLE "auth"."users" ADD COLUMN "state" integer;--> statement-breakpoint
|
||||
ALTER TABLE "auth"."users" ADD COLUMN "municipality" integer;--> statement-breakpoint
|
||||
ALTER TABLE "auth"."users" ADD COLUMN "parish" integer;--> statement-breakpoint
|
||||
ALTER TABLE "auth"."users" ADD CONSTRAINT "users_state_states_id_fk" FOREIGN KEY ("state") REFERENCES "public"."states"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "auth"."users" ADD CONSTRAINT "users_municipality_municipalities_id_fk" FOREIGN KEY ("municipality") REFERENCES "public"."municipalities"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
|
||||
ALTER TABLE "auth"."users" ADD CONSTRAINT "users_parish_parishes_id_fk" FOREIGN KEY ("parish") REFERENCES "public"."parishes"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
|
||||
CREATE VIEW "public"."v_surveys" AS (select id as survey_id, title, description, created_at, closing_date, target_audience from surveys
|
||||
where published = true);
|
||||
1306
apps/api/src/database/migrations/meta/0000_snapshot.json
Normal file
1306
apps/api/src/database/migrations/meta/0000_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
1358
apps/api/src/database/migrations/meta/0001_snapshot.json
Normal file
1358
apps/api/src/database/migrations/meta/0001_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
20
apps/api/src/database/migrations/meta/_journal.json
Normal file
20
apps/api/src/database/migrations/meta/_journal.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"version": "7",
|
||||
"dialect": "postgresql",
|
||||
"entries": [
|
||||
{
|
||||
"idx": 0,
|
||||
"version": "7",
|
||||
"when": 1743783835462,
|
||||
"tag": "0000_abnormal_lethal_legion",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 1,
|
||||
"version": "7",
|
||||
"when": 1747665408016,
|
||||
"tag": "0001_massive_kylun",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
32
apps/api/src/database/schema/activity_logs.ts
Normal file
32
apps/api/src/database/schema/activity_logs.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import * as t from 'drizzle-orm/pg-core';
|
||||
import { index, pgTable } from 'drizzle-orm/pg-core';
|
||||
import { sql } from 'drizzle-orm';
|
||||
import { users } from './auth';
|
||||
|
||||
const timestamps = {
|
||||
created_at: t.timestamp('created_at').defaultNow().notNull(),
|
||||
updated_at: t
|
||||
.timestamp('updated_at', { mode: 'date', precision: 3 })
|
||||
.$onUpdate(() => new Date()),
|
||||
};
|
||||
|
||||
// Tabla de Logs de Actividad
|
||||
export const activityLogsSystem = pgTable(
|
||||
'activity_logs',
|
||||
{
|
||||
id: t
|
||||
.uuid('id')
|
||||
.primaryKey()
|
||||
.default(sql`gen_random_uuid()`),
|
||||
userId: t
|
||||
.integer('user_id')
|
||||
.references(() => users.id, { onDelete: 'cascade' }),
|
||||
type: t.text('type').notNull(), // login, failed
|
||||
description: t.text('description').notNull(),
|
||||
timestamp: t.timestamp('timestamp').defaultNow(),
|
||||
...timestamps,
|
||||
},
|
||||
(activityLogs) => ({
|
||||
activityLogsIdx: index('activityLogs_idx').on(activityLogs.type),
|
||||
}),
|
||||
);
|
||||
132
apps/api/src/database/schema/auth.ts
Normal file
132
apps/api/src/database/schema/auth.ts
Normal file
@@ -0,0 +1,132 @@
|
||||
import * as t from 'drizzle-orm/pg-core';
|
||||
import { sql } from 'drizzle-orm';
|
||||
import { authSchema } from './schemas';
|
||||
import { timestamps } from '../timestamps';
|
||||
import { states, municipalities, parishes } from './general';
|
||||
|
||||
|
||||
// Tabla de Usuarios sistema
|
||||
export const users = authSchema.table(
|
||||
'users',
|
||||
{
|
||||
id: t.serial('id').primaryKey(),
|
||||
username: t.text('username').unique().notNull(),
|
||||
email: t.text('email').unique().notNull(),
|
||||
fullname: t.text('fullname').notNull(),
|
||||
phone: t.text('phone'),
|
||||
password: t.text('password').notNull(),
|
||||
state: t.integer('state').references(() => states.id, { onDelete: 'set null' }),
|
||||
municipality: t.integer('municipality').references(() => municipalities.id, { onDelete: 'set null' }),
|
||||
parish: t.integer('parish').references(() => parishes.id, { onDelete: 'set null' }),
|
||||
isTwoFactorEnabled: t
|
||||
.boolean('is_two_factor_enabled')
|
||||
.notNull()
|
||||
.default(false),
|
||||
twoFactorSecret: t.text('two_factor_secret'),
|
||||
isEmailVerified: t.boolean('is_email_verified').notNull().default(false),
|
||||
isActive: t.boolean('is_active').notNull().default(true),
|
||||
...timestamps,
|
||||
},
|
||||
(users) => ({
|
||||
usersIdx: t.index('users_idx').on(users.username),
|
||||
}),
|
||||
);
|
||||
|
||||
|
||||
// Tabla de Roles
|
||||
export const roles = authSchema.table(
|
||||
'roles',
|
||||
{
|
||||
id: t.serial('id').primaryKey(),
|
||||
name: t.text('name').notNull(),
|
||||
...timestamps,
|
||||
},
|
||||
(roles) => ({
|
||||
rolesIdx: t.index('roles_idx').on(roles.name),
|
||||
}),
|
||||
);
|
||||
|
||||
|
||||
|
||||
//tabla User_roles
|
||||
export const usersRole = authSchema.table(
|
||||
'user_role',
|
||||
{
|
||||
id: t.serial('id').primaryKey(),
|
||||
userId: t
|
||||
.integer('user_id')
|
||||
.references(() => users.id, { onDelete: 'cascade' }),
|
||||
roleId: t
|
||||
.integer('role_id')
|
||||
.references(() => roles.id, { onDelete: 'set null' }),
|
||||
...timestamps,
|
||||
},
|
||||
(userRole) => ({
|
||||
userRoleIdx: t.index('user_role_idx').on(userRole.userId),
|
||||
}),
|
||||
);
|
||||
|
||||
export const userAccessView = authSchema.view('user_access_view', {
|
||||
userId: t.integer('userId').notNull(),
|
||||
username: t.text('username').notNull(),
|
||||
email: t.text('email').notNull(),
|
||||
fullname: t.text('email').notNull(),
|
||||
roleId: t.integer('role_id'),
|
||||
roleName: t.text('role_name'),
|
||||
}).as(sql`
|
||||
SELECT
|
||||
u.id AS user_id,
|
||||
u.username,
|
||||
u.email,
|
||||
u.fullname,
|
||||
r.id AS role_id,
|
||||
r.name AS role_name
|
||||
FROM
|
||||
auth.users u
|
||||
LEFT JOIN
|
||||
auth.user_role ur ON u.id = ur.user_id
|
||||
LEFT JOIN
|
||||
auth.roles r ON ur.role_id = r.id`);
|
||||
|
||||
|
||||
// Tabla de Sesiones
|
||||
export const sessions = authSchema.table(
|
||||
'sessions',
|
||||
{
|
||||
id: t
|
||||
.uuid('id')
|
||||
.primaryKey()
|
||||
.default(sql`gen_random_uuid()`),
|
||||
userId: t
|
||||
.integer('user_id')
|
||||
.references(() => users.id, { onDelete: 'cascade' })
|
||||
.notNull(),
|
||||
sessionToken: t.text('session_token').notNull(),
|
||||
expiresAt: t.integer('expires_at').notNull(),
|
||||
...timestamps,
|
||||
},
|
||||
(sessions) => ({
|
||||
sessionsIdx: t.index('sessions_idx').on(sessions.sessionToken),
|
||||
}),
|
||||
);
|
||||
|
||||
|
||||
|
||||
//tabla de tokens de verificación
|
||||
export const verificationTokens = authSchema.table(
|
||||
'verificationToken',
|
||||
{
|
||||
identifier: t.text('identifier').notNull(),
|
||||
token: t.text('token').notNull(),
|
||||
code: t.integer('code'),
|
||||
expires: t.timestamp('expires', { mode: 'date' }).notNull(),
|
||||
ipAddress: t.text('ip_address').notNull(),
|
||||
},
|
||||
(verificationToken) => [
|
||||
{
|
||||
compositePk: t.primaryKey({
|
||||
columns: [verificationToken.identifier, verificationToken.token],
|
||||
}),
|
||||
},
|
||||
],
|
||||
);
|
||||
8
apps/api/src/database/schema/enum.ts
Normal file
8
apps/api/src/database/schema/enum.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { pgEnum } from 'drizzle-orm/pg-core';
|
||||
import { authSchema } from './schemas';
|
||||
export const statusEnum = authSchema.enum('status', ['ACTIVE', 'INACTIVE']);
|
||||
export const genderEnum = authSchema.enum('gender', ['FEMENINO', 'MASCULINO']);
|
||||
export const nationalityEnum = pgEnum('nationality', [
|
||||
'VENEZOLANO',
|
||||
'EXTRANJERO',
|
||||
]);
|
||||
114
apps/api/src/database/schema/general.ts
Normal file
114
apps/api/src/database/schema/general.ts
Normal file
@@ -0,0 +1,114 @@
|
||||
import * as t from 'drizzle-orm/pg-core';
|
||||
import { timestamps } from '../timestamps';
|
||||
|
||||
|
||||
|
||||
//Tabla de Tipo de categorias
|
||||
export const categoryType = t.pgTable(
|
||||
'category_type',
|
||||
{
|
||||
id: t.serial('id').primaryKey(),
|
||||
group: t.varchar('group', { length: 100 }).notNull(), // grupo pertenece
|
||||
description: t.text('description').notNull(), // name
|
||||
...timestamps,
|
||||
},
|
||||
(categoryType) => ({
|
||||
categoryTypeIdx0: t.index('category_typeIx0').on(categoryType.group),
|
||||
categoryTypeIdx1: t.index('category_typeIx1').on(categoryType.description),
|
||||
}),
|
||||
);
|
||||
|
||||
// Tabla States
|
||||
export const states = t.pgTable(
|
||||
'states',
|
||||
{
|
||||
id: t.serial('id').primaryKey(),
|
||||
name: t.text('name').notNull(),
|
||||
...timestamps,
|
||||
},
|
||||
(states) => ({
|
||||
nameIndex: t.index('states_index_00').on(states.id, states.name),
|
||||
}),
|
||||
);
|
||||
|
||||
// Tabla Municipalities
|
||||
export const municipalities = t.pgTable(
|
||||
'municipalities',
|
||||
{
|
||||
id: t.serial('id').primaryKey(),
|
||||
name: t.text('name').notNull(),
|
||||
stateId: t
|
||||
.integer('state_id')
|
||||
.notNull()
|
||||
.references(() => states.id, { onDelete: 'cascade' }),
|
||||
...timestamps,
|
||||
},
|
||||
(municipalities) => ({
|
||||
nameStateIndex: t
|
||||
.index('municipalities_index_00')
|
||||
.on(municipalities.id, municipalities.name, municipalities.stateId),
|
||||
}),
|
||||
);
|
||||
|
||||
// Tabla Parishes
|
||||
export const parishes = t.pgTable(
|
||||
'parishes',
|
||||
{
|
||||
id: t.serial('id').primaryKey(),
|
||||
name: t.text('name').notNull(),
|
||||
municipalityId: t
|
||||
.integer('municipality_id')
|
||||
.notNull()
|
||||
.references(() => municipalities.id, { onDelete: 'cascade' }),
|
||||
...timestamps,
|
||||
},
|
||||
(parishes) => ({
|
||||
parishIndex: t
|
||||
.index('parishes_index_00')
|
||||
.on(parishes.id, parishes.name, parishes.municipalityId),
|
||||
}),
|
||||
);
|
||||
|
||||
// Tabla Localities
|
||||
export const localities = t.pgTable(
|
||||
'localities',
|
||||
{
|
||||
id: t.serial('id').primaryKey(),
|
||||
stateId: t
|
||||
.integer('state_id')
|
||||
.notNull()
|
||||
.references(() => states.id, { onDelete: 'cascade' }),
|
||||
municipalityId: t
|
||||
.integer('municipality_id')
|
||||
.notNull()
|
||||
.references(() => municipalities.id, { onDelete: 'cascade' }),
|
||||
parishId: t
|
||||
.integer('parish_id')
|
||||
.notNull()
|
||||
.references(() => parishes.id, { onDelete: 'cascade' }),
|
||||
name: t.text('name').unique().notNull(),
|
||||
...timestamps,
|
||||
},
|
||||
(localities) => ({
|
||||
uniqueLocalityIndex: t
|
||||
.uniqueIndex('localities_index_03')
|
||||
.on(localities.stateId, localities.municipalityId, localities.parishId),
|
||||
stateIndex: t.index('localities_index_00').on(localities.stateId),
|
||||
municipalityIndex: t
|
||||
.index('localities_index_01')
|
||||
.on(localities.municipalityId),
|
||||
parishIndex: t.index('localities_index_02').on(localities.parishId),
|
||||
}),
|
||||
);
|
||||
|
||||
// // Vista LocalitiesView
|
||||
// export const localitiesView = t.pgView("localities_view", {
|
||||
// id: t.integer("id").notNull(),
|
||||
// stateId: t.integer("state_id"),
|
||||
// state: t.text("state"),
|
||||
// municipalityId: t.integer("municipality_id"),
|
||||
// municipality: t.text("municipality"),
|
||||
// parishId: t.integer("parish_id"),
|
||||
// parish: t.text("parish"),
|
||||
// fullLocation: t.text("full_location"),
|
||||
// });
|
||||
4
apps/api/src/database/schema/schemas.ts
Normal file
4
apps/api/src/database/schema/schemas.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
//schemas
|
||||
import * as t from 'drizzle-orm/pg-core';
|
||||
export const authSchema = t.pgSchema('auth'); //autenticacion y sessiones usuarios
|
||||
|
||||
57
apps/api/src/database/schema/surveys.ts
Normal file
57
apps/api/src/database/schema/surveys.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import * as t from 'drizzle-orm/pg-core';
|
||||
import { eq, lt, gte, ne, sql } from 'drizzle-orm';
|
||||
import { timestamps } from '../timestamps';
|
||||
import { users } from './auth';
|
||||
|
||||
|
||||
// Tabla surveys
|
||||
export const surveys = t.pgTable(
|
||||
'surveys',
|
||||
{
|
||||
id: t.serial('id').primaryKey(),
|
||||
title: t.text('title').notNull(),
|
||||
description: t.text('description').notNull(),
|
||||
targetAudience: t.varchar('target_audience', { length: 50 }).notNull(),
|
||||
closingDate: t.date('closing_date'),
|
||||
published: t.boolean('published').notNull(),
|
||||
questions: t.jsonb('questions').notNull(),
|
||||
...timestamps,
|
||||
},
|
||||
(surveys) => ({
|
||||
surveysIndex: t
|
||||
.index('surveys_index_00')
|
||||
.on(surveys.title),
|
||||
}),
|
||||
);
|
||||
|
||||
export const answersSurveys = t.pgTable(
|
||||
'answers_surveys',
|
||||
{
|
||||
id: t.serial('id').primaryKey(),
|
||||
surveyId: t
|
||||
.integer('survey_id')
|
||||
.references(() => surveys.id, { onDelete: 'cascade' }),
|
||||
userId: t
|
||||
.integer('user_id')
|
||||
.references(() => users.id, { onDelete: 'cascade' }),
|
||||
answers: t.jsonb('answers').notNull(),
|
||||
...timestamps,
|
||||
},
|
||||
(answers) => ({
|
||||
answersIndex: t.index('answers_index_00').on(answers.answers),
|
||||
answersIndex01: t.index('answers_index_01').on(answers.surveyId),
|
||||
answersIndex02: t.index('answers_index_02').on(answers.userId),
|
||||
}),
|
||||
);
|
||||
|
||||
|
||||
|
||||
export const viewSurveys = t.pgView('v_surveys', {
|
||||
surverId: t.integer('survey_id'),
|
||||
title: t.text('title'),
|
||||
description: t.text('description'),
|
||||
created_at: t.timestamp('created_at'),
|
||||
closingDate: t.date('closing_date'),
|
||||
targetAudience: t.varchar('target_audience')
|
||||
}).as(sql`select id as survey_id, title, description, created_at, closing_date, target_audience from surveys
|
||||
where published = true`);
|
||||
24
apps/api/src/database/seeds/admin-role.seed.ts
Normal file
24
apps/api/src/database/seeds/admin-role.seed.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { NodePgDatabase } from 'drizzle-orm/node-postgres';
|
||||
import * as schema from '../index';
|
||||
import { roles, } from '../index';
|
||||
|
||||
|
||||
export async function seedAdminRole(db: NodePgDatabase<typeof schema>) {
|
||||
console.log('Seeding admin role...');
|
||||
|
||||
// Insert roles
|
||||
const roleNames = ['superadmin', 'admin', 'autoridad','manager','user','producers','organization'];
|
||||
|
||||
for (const roleName of roleNames) {
|
||||
try {
|
||||
await db.insert(roles).values({
|
||||
name: roleName
|
||||
}).onConflictDoNothing();
|
||||
console.log(`Role '${roleName}' created or already exists`);
|
||||
} catch (error) {
|
||||
console.error(`Error creating role '${roleName}':`, error);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('roles seeded successfully');
|
||||
}
|
||||
37
apps/api/src/database/seeds/index.ts
Normal file
37
apps/api/src/database/seeds/index.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { drizzle } from 'drizzle-orm/node-postgres';
|
||||
import { Pool } from 'pg';
|
||||
import { envs } from 'src/common/config/envs';
|
||||
import * as schema from '../index';
|
||||
import { seedAdminRole } from './admin-role.seed';
|
||||
import { seedUserAdmin } from './user-admin.seed';
|
||||
import { seedStates } from './states.seed';
|
||||
import { seedMunicipalities } from './municipalities.seed';
|
||||
import { seedParishes } from './parishes.seed';
|
||||
|
||||
|
||||
async function main() {
|
||||
const pool = new Pool({
|
||||
connectionString: envs.dataBaseUrl,
|
||||
ssl:
|
||||
envs.node_env === 'production' ? { rejectUnauthorized: false } : false,
|
||||
});
|
||||
|
||||
const db = drizzle(pool, { schema });
|
||||
|
||||
try {
|
||||
// Run seeds in order
|
||||
await seedStates(db);
|
||||
await seedMunicipalities(db);
|
||||
await seedParishes(db);
|
||||
await seedAdminRole(db);
|
||||
await seedUserAdmin(db)
|
||||
|
||||
console.log('All seeds completed successfully');
|
||||
} catch (error) {
|
||||
console.error('Error seeding database:', error);
|
||||
} finally {
|
||||
await pool.end();
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
25
apps/api/src/database/seeds/municipalities.seed.ts
Normal file
25
apps/api/src/database/seeds/municipalities.seed.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { NodePgDatabase } from 'drizzle-orm/node-postgres';
|
||||
import * as schema from '../index';
|
||||
import { municipalities } from '../schema/general';
|
||||
|
||||
|
||||
export async function seedMunicipalities(db: NodePgDatabase<typeof schema>) {
|
||||
console.log('Seeding public municipalities...');
|
||||
|
||||
// Insert roles
|
||||
const municipalitiesArray = [{name:'municipio1',stateId:1}, {name:'municipio2',stateId:1}, {name:'municipio3',stateId:2}];
|
||||
|
||||
for (const item of municipalitiesArray) {
|
||||
try {
|
||||
await db.insert(municipalities).values({
|
||||
name: item.name,
|
||||
stateId: item.stateId
|
||||
}).onConflictDoNothing();
|
||||
// console.log(`Municipality '${item}' created or already exists`);
|
||||
} catch (error) {
|
||||
console.error(`Error creating municipality '${item.name}':`, error);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('All municipalities seeded successfully');
|
||||
}
|
||||
25
apps/api/src/database/seeds/parishes.seed.ts
Normal file
25
apps/api/src/database/seeds/parishes.seed.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { NodePgDatabase } from 'drizzle-orm/node-postgres';
|
||||
import * as schema from '../index';
|
||||
import { parishes } from '../schema/general';
|
||||
|
||||
|
||||
export async function seedParishes(db: NodePgDatabase<typeof schema>) {
|
||||
console.log('Seeding public parishes...');
|
||||
|
||||
// Insert roles
|
||||
const parishesArray = [{name:'parroquia1',municipalityId:1}, {name:'parroquia2',municipalityId:1}, {name:'parroquia3',municipalityId:2}];
|
||||
|
||||
for (const item of parishesArray) {
|
||||
try {
|
||||
await db.insert(parishes).values({
|
||||
name: item.name,
|
||||
municipalityId: item.municipalityId
|
||||
}).onConflictDoNothing();
|
||||
// console.log(`Parish '${item}' created or already exists`);
|
||||
} catch (error) {
|
||||
console.error(`Error creating parish '${item.name}':`, error);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('All parishes seeded successfully');
|
||||
}
|
||||
24
apps/api/src/database/seeds/states.seed.ts
Normal file
24
apps/api/src/database/seeds/states.seed.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { NodePgDatabase } from 'drizzle-orm/node-postgres';
|
||||
import * as schema from '../index';
|
||||
import { states } from '../schema/general';
|
||||
|
||||
|
||||
export async function seedStates(db: NodePgDatabase<typeof schema>) {
|
||||
console.log('Seeding public state...');
|
||||
|
||||
// Insert roles
|
||||
const statesArray = ['estado1', 'estado2', 'estado3'];
|
||||
|
||||
for (const item of statesArray) {
|
||||
try {
|
||||
await db.insert(states).values({
|
||||
name: item
|
||||
}).onConflictDoNothing();
|
||||
// console.log(`State '${item}' created or already exists`);
|
||||
} catch (error) {
|
||||
console.error(`Error creating state '${item}':`, error);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('All states seeded successfully');
|
||||
}
|
||||
39
apps/api/src/database/seeds/user-admin.seed.ts
Normal file
39
apps/api/src/database/seeds/user-admin.seed.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import { NodePgDatabase } from 'drizzle-orm/node-postgres';
|
||||
import * as schema from '../index';
|
||||
import { users, usersRole } from '../index';
|
||||
|
||||
export async function seedUserAdmin(db: NodePgDatabase<typeof schema>) {
|
||||
|
||||
// Insert admin user
|
||||
try {
|
||||
// Password is already hashed in your SQL, but in a real application you might want to hash it here
|
||||
// const hashedPassword = await hash('your_password', 10);
|
||||
const hashedPassword = '$2b$10$6esl7d/BOINamScuReRoPuYFC8iSJgpk61LHm2X3PCU5hu/St8vHW';
|
||||
|
||||
const [adminUser] = await db.insert(users).values({
|
||||
username: 'superadmin',
|
||||
email: 'admin@zonastart.com',
|
||||
fullname: 'Super Administrador',
|
||||
password: hashedPassword,
|
||||
state: 1,
|
||||
municipality: 1,
|
||||
parish: 1,
|
||||
isTwoFactorEnabled: false,
|
||||
isEmailVerified: true,
|
||||
isActive: true
|
||||
}).returning({ id: users.id }).onConflictDoNothing();
|
||||
|
||||
if (adminUser) {
|
||||
// Assign superadmin role to the user
|
||||
await db.insert(usersRole).values({
|
||||
roleId: 1, // Assuming 'superadmin' has ID 1 based on the insert order
|
||||
userId: adminUser.id
|
||||
}).onConflictDoNothing();
|
||||
console.log('Admin user created and assigned superadmin role');
|
||||
} else {
|
||||
console.log('Admin user already exists, skipping');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error creating admin user:', error);
|
||||
}
|
||||
}
|
||||
8
apps/api/src/database/timestamps.ts
Normal file
8
apps/api/src/database/timestamps.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import * as t from 'drizzle-orm/pg-core';
|
||||
|
||||
export const timestamps = {
|
||||
created_at: t.timestamp('created_at').defaultNow().notNull(),
|
||||
updated_at: t
|
||||
.timestamp('updated_at', { mode: 'date', precision: 3 })
|
||||
.$onUpdate(() => new Date()),
|
||||
};
|
||||
Reference in New Issue
Block a user