import { MigrationInterface, QueryRunner } from 'typeorm'; function quoteIdentifier(identifier: string): string { return `"${identifier.replaceAll('"', '""')}"`; } export class F62UserSmtpAndActRepresentative1790117400000 implements MigrationInterface { name = 'F62UserSmtpAndActRepresentative1790117400000'; public async up(queryRunner: QueryRunner): Promise { await queryRunner.query(` DO $$ BEGIN IF EXISTS (SELECT 1 FROM users WHERE email IS NULL OR btrim(email)='') THEN RAISE EXCEPTION 'USER_EMAIL_REQUIRED_BEFORE_F62'; END IF; END $$ `); await queryRunner.query(`ALTER TABLE users ALTER COLUMN email SET NOT NULL`); await queryRunner.query(` CREATE TABLE user_smtp_settings ( user_id uuid PRIMARY KEY, mode varchar(16) NOT NULL DEFAULT 'SYSTEM', host varchar(255), port integer, security_mode varchar(24), username varchar(255), password_enc text, from_name varchar(200), from_email varchar(320), reply_to varchar(320), enabled boolean NOT NULL DEFAULT true, updated_by uuid, created_at timestamptz NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at timestamptz NOT NULL DEFAULT CURRENT_TIMESTAMP, CONSTRAINT chk_user_smtp_mode CHECK (mode IN ('SYSTEM','CUSTOM')), CONSTRAINT chk_user_smtp_security CHECK (security_mode IS NULL OR security_mode IN ('NONE','STARTTLS','TLS')), CONSTRAINT chk_user_smtp_port CHECK (port IS NULL OR (port > 0 AND port <= 65535)), CONSTRAINT chk_user_smtp_custom_complete CHECK ( mode='SYSTEM' OR ( LENGTH(TRIM(COALESCE(host,''))) > 0 AND port IS NOT NULL AND security_mode IS NOT NULL AND LENGTH(TRIM(COALESCE(from_email,''))) > 0 ) ), CONSTRAINT fk_user_smtp_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE, CONSTRAINT fk_user_smtp_updated_by FOREIGN KEY (updated_by) REFERENCES users(id) ON DELETE SET NULL ) `); await queryRunner.query(` ALTER TABLE inspection_act_responsibles DROP CONSTRAINT chk_inspection_act_responsibles_details `); await queryRunner.query(` ALTER TABLE inspection_act_responsibles ADD CONSTRAINT chk_inspection_act_responsibles_details CHECK ( ( attendance_status = 'PRESENT' AND LENGTH(TRIM(COALESCE(full_name, ''))) > 0 AND document_type IS NOT NULL AND LENGTH(TRIM(COALESCE(document_number, ''))) > 0 AND LENGTH(TRIM(COALESCE(position, ''))) > 0 AND LENGTH(TRIM(COALESCE(email, ''))) > 0 AND absence_reason IS NULL ) OR ( attendance_status = 'ABSENT' AND LENGTH(TRIM(COALESCE(absence_reason, ''))) >= 10 ) ) `); const appRole = process.env.DB_APP_USER; if (!appRole) throw new Error('Missing required environment variable: DB_APP_USER'); const applicationRole = quoteIdentifier(appRole); await queryRunner.query(`GRANT SELECT, INSERT, UPDATE ON TABLE user_smtp_settings TO ${applicationRole}`); await queryRunner.query(`REVOKE DELETE ON TABLE user_smtp_settings FROM ${applicationRole}`); } public async down(queryRunner: QueryRunner): Promise { await queryRunner.query(` ALTER TABLE inspection_act_responsibles DROP CONSTRAINT chk_inspection_act_responsibles_details `); await queryRunner.query(` ALTER TABLE inspection_act_responsibles ADD CONSTRAINT chk_inspection_act_responsibles_details CHECK ( ( attendance_status = 'PRESENT' AND LENGTH(TRIM(COALESCE(full_name, ''))) > 0 AND document_type IS NOT NULL AND LENGTH(TRIM(COALESCE(document_number, ''))) > 0 AND LENGTH(TRIM(COALESCE(position, ''))) > 0 AND absence_reason IS NULL ) OR ( attendance_status = 'ABSENT' AND LENGTH(TRIM(COALESCE(absence_reason, ''))) >= 10 ) ) `); await queryRunner.query(`DROP TABLE IF EXISTS user_smtp_settings`); await queryRunner.query(`ALTER TABLE users ALTER COLUMN email DROP NOT NULL`); } }