commit per adattare il data model alla web app Academy aziendale
This commit is contained in:
parent
d5bd50ef39
commit
3e94fdb6d9
9 changed files with 340 additions and 112 deletions
|
|
@ -1,13 +1,13 @@
|
|||
-- ============================================================
|
||||
-- Schema tabelle – esameits24-26
|
||||
-- Allineato alle API: /utenti,
|
||||
-- Schema tabelle – esameits24-26 (Academy aziendale)
|
||||
-- Allineato alle API: /utenti, /corsi, /assegnazioni-corsi, /statistiche
|
||||
-- ============================================================
|
||||
|
||||
USE `esameits24-26`;
|
||||
|
||||
-- ------------------------------------------------------------
|
||||
-- Tabella UTENTI
|
||||
-- Ruoli: Operatore | Amministratore
|
||||
-- Tabella UTENTE
|
||||
-- Ruoli: Dipendente | Referente Academy
|
||||
-- ------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS utente (
|
||||
UtenteID INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
|
|
@ -15,14 +15,80 @@ CREATE TABLE IF NOT EXISTS utente (
|
|||
Cognome VARCHAR(100) NOT NULL,
|
||||
Email VARCHAR(255) NOT NULL,
|
||||
PasswordHash VARCHAR(255) NOT NULL COMMENT 'Password salvata come hash (es. bcrypt)',
|
||||
Ruolo ENUM("Amministratore", "Operatore") NOT NULL DEFAULT "Operatore",
|
||||
Ruolo ENUM('Dipendente', 'Referente Academy') NOT NULL DEFAULT 'Dipendente',
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
|
||||
PRIMARY KEY (UtenteID),
|
||||
UNIQUE KEY uk_utente_email (Email)
|
||||
UNIQUE KEY uk_utente_email (Email),
|
||||
KEY idx_utente_ruolo (Ruolo)
|
||||
) ENGINE=InnoDB
|
||||
DEFAULT CHARSET=utf8mb4
|
||||
COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- ------------------------------------------------------------
|
||||
-- Tabella CORSO (catalogo Academy)
|
||||
-- ------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS corso (
|
||||
CorsoID INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
Titolo VARCHAR(200) NOT NULL,
|
||||
Descrizione TEXT NULL,
|
||||
Categoria VARCHAR(100) NOT NULL,
|
||||
DurataOre SMALLINT UNSIGNED NOT NULL,
|
||||
Obbligatorio TINYINT(1) NOT NULL DEFAULT 0,
|
||||
Attivo TINYINT(1) NOT NULL DEFAULT 1,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
|
||||
PRIMARY KEY (CorsoID),
|
||||
KEY idx_corso_categoria (Categoria),
|
||||
KEY idx_corso_attivo (Attivo),
|
||||
CONSTRAINT chk_corso_durata_ore CHECK (DurataOre > 0)
|
||||
) ENGINE=InnoDB
|
||||
DEFAULT CHARSET=utf8mb4
|
||||
COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- ------------------------------------------------------------
|
||||
-- Tabella ASSEGNAZIONE_CORSO
|
||||
-- Stati: Assegnato | Completato | Scaduto | Annullato
|
||||
-- ------------------------------------------------------------
|
||||
CREATE TABLE IF NOT EXISTS assegnazione_corso (
|
||||
AssegnazioneID INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
CorsoID INT UNSIGNED NOT NULL,
|
||||
DipendenteID INT UNSIGNED NOT NULL,
|
||||
DataAssegnazione DATE NOT NULL,
|
||||
DataScadenza DATE NOT NULL,
|
||||
Stato ENUM('Assegnato', 'Completato', 'Scaduto', 'Annullato') NOT NULL DEFAULT 'Assegnato',
|
||||
DataCompletamento DATE NULL,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
|
||||
PRIMARY KEY (AssegnazioneID),
|
||||
KEY idx_assegnazione_corso (CorsoID),
|
||||
KEY idx_assegnazione_dipendente (DipendenteID),
|
||||
KEY idx_assegnazione_stato (Stato),
|
||||
KEY idx_assegnazione_data_assegnazione (DataAssegnazione),
|
||||
KEY idx_assegnazione_data_scadenza (DataScadenza),
|
||||
|
||||
CONSTRAINT fk_assegnazione_corso
|
||||
FOREIGN KEY (CorsoID) REFERENCES corso (CorsoID)
|
||||
ON UPDATE CASCADE ON DELETE RESTRICT,
|
||||
|
||||
CONSTRAINT fk_assegnazione_dipendente
|
||||
FOREIGN KEY (DipendenteID) REFERENCES utente (UtenteID)
|
||||
ON UPDATE CASCADE ON DELETE RESTRICT,
|
||||
|
||||
CONSTRAINT chk_assegnazione_scadenza
|
||||
CHECK (DataScadenza >= DataAssegnazione),
|
||||
|
||||
CONSTRAINT chk_assegnazione_completamento
|
||||
CHECK (DataCompletamento IS NULL OR DataCompletamento >= DataAssegnazione),
|
||||
|
||||
CONSTRAINT chk_assegnazione_completato
|
||||
CHECK (
|
||||
(Stato = 'Completato' AND DataCompletamento IS NOT NULL)
|
||||
OR (Stato <> 'Completato' AND DataCompletamento IS NULL)
|
||||
)
|
||||
) ENGINE=InnoDB
|
||||
DEFAULT CHARSET=utf8mb4
|
||||
COLLATE=utf8mb4_unicode_ci;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
-- ============================================================
|
||||
-- Dati iniziali di test – esameits24-26
|
||||
-- Dati iniziali di test – esameits24-26 (Academy aziendale)
|
||||
-- Password per tutti gli utenti: Password123!
|
||||
-- 1 Andrea Villari – admin@example.it (amministratore)
|
||||
-- 2 Maria Bianchi – maria.bianchi@example.it (operatore)
|
||||
-- 3 Luca Conti – luca.conti@example.it (operatore)
|
||||
--
|
||||
-- 1 Andrea Villari – admin@academy.it (Referente Academy)
|
||||
-- 2 Maria Bianchi – maria.bianchi@academy.it (Dipendente)
|
||||
-- 3 Luca Conti – luca.conti@academy.it (Dipendente)
|
||||
-- 4 Elena Rossi – elena.rossi@academy.it (Dipendente)
|
||||
-- ============================================================
|
||||
|
||||
USE `esameits24-26`;
|
||||
|
|
@ -12,6 +14,82 @@ USE `esameits24-26`;
|
|||
-- Utenti
|
||||
-- ------------------------------------------------------------
|
||||
INSERT INTO utente (Nome, Cognome, Email, PasswordHash, Ruolo) VALUES
|
||||
('Andrea', 'Villari', 'admin@example.it', '$2b$10$7Z80qZcDydZCdLrOcaH/VOa9knKWjQVyyg8MtEgBAvgfNMsiLEZze', 'Amministratore'),
|
||||
('Maria', 'Bianchi', 'maria.bianchi@example.it', '$2b$10$7Z80qZcDydZCdLrOcaH/VOa9knKWjQVyyg8MtEgBAvgfNMsiLEZze', 'Operatore'),
|
||||
('Luca', 'Conti', 'luca.conti@example.it', '$2b$10$7Z80qZcDydZCdLrOcaH/VOa9knKWjQVyyg8MtEgBAvgfNMsiLEZze', 'Operatore');
|
||||
('Andrea', 'Villari', 'admin@academy.it', '$2b$10$7Z80qZcDydZCdLrOcaH/VOa9knKWjQVyyg8MtEgBAvgfNMsiLEZze', 'Referente Academy'),
|
||||
('Maria', 'Bianchi', 'maria.bianchi@academy.it', '$2b$10$7Z80qZcDydZCdLrOcaH/VOa9knKWjQVyyg8MtEgBAvgfNMsiLEZze', 'Dipendente'),
|
||||
('Luca', 'Conti', 'luca.conti@academy.it', '$2b$10$7Z80qZcDydZCdLrOcaH/VOa9knKWjQVyyg8MtEgBAvgfNMsiLEZze', 'Dipendente'),
|
||||
('Elena', 'Rossi', 'elena.rossi@academy.it', '$2b$10$7Z80qZcDydZCdLrOcaH/VOa9knKWjQVyyg8MtEgBAvgfNMsiLEZze', 'Dipendente');
|
||||
|
||||
-- ------------------------------------------------------------
|
||||
-- Catalogo corsi
|
||||
-- ------------------------------------------------------------
|
||||
INSERT INTO corso (Titolo, Descrizione, Categoria, DurataOre, Obbligatorio, Attivo) VALUES
|
||||
(
|
||||
'Sicurezza sul lavoro',
|
||||
'Norme base su rischi, DPI e procedure di emergenza in azienda.',
|
||||
'Sicurezza',
|
||||
8,
|
||||
1,
|
||||
1
|
||||
),
|
||||
(
|
||||
'GDPR e privacy',
|
||||
'Trattamento dei dati personali, diritti degli interessati e documentazione privacy.',
|
||||
'Compliance',
|
||||
4,
|
||||
1,
|
||||
1
|
||||
),
|
||||
(
|
||||
'Comunicazione efficace',
|
||||
'Tecniche di ascolto attivo, feedback e gestione dei conflitti nel team.',
|
||||
'Soft Skills',
|
||||
6,
|
||||
0,
|
||||
1
|
||||
),
|
||||
(
|
||||
'Excel avanzato',
|
||||
'Tabelle pivot, funzioni avanzate e automazioni per report aziendali.',
|
||||
'IT',
|
||||
10,
|
||||
0,
|
||||
1
|
||||
),
|
||||
(
|
||||
'Primo soccorso (edizione 2023)',
|
||||
'Corso storico non più disponibile per nuove assegnazioni.',
|
||||
'Sicurezza',
|
||||
4,
|
||||
0,
|
||||
0
|
||||
);
|
||||
|
||||
-- ------------------------------------------------------------
|
||||
-- Assegnazioni corsi
|
||||
-- UtenteID: 2 Maria, 3 Luca, 4 Elena
|
||||
-- CorsoID: 1 Sicurezza, 2 GDPR, 3 Comunicazione, 4 Excel, 5 Primo soccorso
|
||||
-- ------------------------------------------------------------
|
||||
INSERT INTO assegnazione_corso (
|
||||
CorsoID,
|
||||
DipendenteID,
|
||||
DataAssegnazione,
|
||||
DataScadenza,
|
||||
Stato,
|
||||
DataCompletamento
|
||||
) VALUES
|
||||
-- Maria: mix di stati per test filtri e statistiche maggio 2026
|
||||
(1, 2, '2026-05-01', '2026-06-30', 'Assegnato', NULL),
|
||||
(2, 2, '2026-04-10', '2026-05-20', 'Completato', '2026-05-12'),
|
||||
(4, 2, '2026-01-15', '2026-03-01', 'Scaduto', NULL),
|
||||
(3, 2, '2026-03-01', '2026-04-30', 'Annullato', NULL),
|
||||
|
||||
-- Luca: completamenti e corsi in corso
|
||||
(1, 3, '2026-05-05', '2026-06-15', 'Completato', '2026-05-18'),
|
||||
(2, 3, '2026-05-08', '2026-06-30', 'Assegnato', NULL),
|
||||
(3, 3, '2026-02-01', '2026-03-15', 'Scaduto', NULL),
|
||||
|
||||
-- Elena: dati aggiuntivi per riepiloghi per categoria
|
||||
(1, 4, '2026-05-10', '2026-07-01', 'Completato', '2026-05-25'),
|
||||
(2, 4, '2026-05-12', '2026-06-20', 'Completato', '2026-05-28'),
|
||||
(4, 4, '2026-05-15', '2026-07-15', 'Assegnato', NULL),
|
||||
(3, 4, '2026-04-01', '2026-05-10', 'Completato', '2026-05-05');
|
||||
|
|
|
|||
68
scripts/apply-academy-schema.sql
Normal file
68
scripts/apply-academy-schema.sql
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
-- ============================================================
|
||||
-- Migrazione manuale per database già inizializzati
|
||||
-- Eseguire se il volume MySQL esisteva prima dell'aggiornamento schema Academy.
|
||||
-- ============================================================
|
||||
|
||||
USE `esameits24-26`;
|
||||
|
||||
-- Allinea enum ruoli utente (se la tabella esisteva con valori precedenti)
|
||||
ALTER TABLE utente
|
||||
MODIFY Ruolo ENUM('Dipendente', 'Referente Academy') NOT NULL DEFAULT 'Dipendente';
|
||||
|
||||
UPDATE utente SET Ruolo = 'Referente Academy' WHERE Ruolo IN ('Amministratore', 'Refernete Academy');
|
||||
UPDATE utente SET Ruolo = 'Dipendente' WHERE Ruolo = 'Operatore';
|
||||
|
||||
-- Catalogo corsi
|
||||
CREATE TABLE IF NOT EXISTS corso (
|
||||
CorsoID INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
Titolo VARCHAR(200) NOT NULL,
|
||||
Descrizione TEXT NULL,
|
||||
Categoria VARCHAR(100) NOT NULL,
|
||||
DurataOre SMALLINT UNSIGNED NOT NULL,
|
||||
Obbligatorio TINYINT(1) NOT NULL DEFAULT 0,
|
||||
Attivo TINYINT(1) NOT NULL DEFAULT 1,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (CorsoID),
|
||||
KEY idx_corso_categoria (Categoria),
|
||||
KEY idx_corso_attivo (Attivo),
|
||||
CONSTRAINT chk_corso_durata_ore CHECK (DurataOre > 0)
|
||||
) ENGINE=InnoDB
|
||||
DEFAULT CHARSET=utf8mb4
|
||||
COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
-- Assegnazioni corsi
|
||||
CREATE TABLE IF NOT EXISTS assegnazione_corso (
|
||||
AssegnazioneID INT UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
CorsoID INT UNSIGNED NOT NULL,
|
||||
DipendenteID INT UNSIGNED NOT NULL,
|
||||
DataAssegnazione DATE NOT NULL,
|
||||
DataScadenza DATE NOT NULL,
|
||||
Stato ENUM('Assegnato', 'Completato', 'Scaduto', 'Annullato') NOT NULL DEFAULT 'Assegnato',
|
||||
DataCompletamento DATE NULL,
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (AssegnazioneID),
|
||||
KEY idx_assegnazione_corso (CorsoID),
|
||||
KEY idx_assegnazione_dipendente (DipendenteID),
|
||||
KEY idx_assegnazione_stato (Stato),
|
||||
KEY idx_assegnazione_data_assegnazione (DataAssegnazione),
|
||||
KEY idx_assegnazione_data_scadenza (DataScadenza),
|
||||
CONSTRAINT fk_assegnazione_corso
|
||||
FOREIGN KEY (CorsoID) REFERENCES corso (CorsoID)
|
||||
ON UPDATE CASCADE ON DELETE RESTRICT,
|
||||
CONSTRAINT fk_assegnazione_dipendente
|
||||
FOREIGN KEY (DipendenteID) REFERENCES utente (UtenteID)
|
||||
ON UPDATE CASCADE ON DELETE RESTRICT,
|
||||
CONSTRAINT chk_assegnazione_scadenza
|
||||
CHECK (DataScadenza >= DataAssegnazione),
|
||||
CONSTRAINT chk_assegnazione_completamento
|
||||
CHECK (DataCompletamento IS NULL OR DataCompletamento >= DataAssegnazione),
|
||||
CONSTRAINT chk_assegnazione_completato
|
||||
CHECK (
|
||||
(Stato = 'Completato' AND DataCompletamento IS NOT NULL)
|
||||
OR (Stato <> 'Completato' AND DataCompletamento IS NULL)
|
||||
)
|
||||
) ENGINE=InnoDB
|
||||
DEFAULT CHARSET=utf8mb4
|
||||
COLLATE=utf8mb4_unicode_ci;
|
||||
|
|
@ -4,6 +4,7 @@
|
|||
USE `esameits24-26`;
|
||||
|
||||
INSERT IGNORE INTO utente (Nome, Cognome, Email, PasswordHash, Ruolo) VALUES
|
||||
('Andrea', 'Villari', 'admin@example.it', '$2b$10$7Z80qZcDydZCdLrOcaH/VOa9knKWjQVyyg8MtEgBAvgfNMsiLEZze', 'Amministratore'),
|
||||
('Maria', 'Bianchi', 'maria.bianchi@example.it', '$2b$10$7Z80qZcDydZCdLrOcaH/VOa9knKWjQVyyg8MtEgBAvgfNMsiLEZze', 'Operatore'),
|
||||
('Luca', 'Conti', 'luca.conti@example.it', '$2b$10$7Z80qZcDydZCdLrOcaH/VOa9knKWjQVyyg8MtEgBAvgfNMsiLEZze', 'Operatore');
|
||||
('Andrea', 'Villari', 'admin@academy.it', '$2b$10$7Z80qZcDydZCdLrOcaH/VOa9knKWjQVyyg8MtEgBAvgfNMsiLEZze', 'Referente Academy'),
|
||||
('Maria', 'Bianchi', 'maria.bianchi@academy.it', '$2b$10$7Z80qZcDydZCdLrOcaH/VOa9knKWjQVyyg8MtEgBAvgfNMsiLEZze', 'Dipendente'),
|
||||
('Luca', 'Conti', 'luca.conti@academy.it', '$2b$10$7Z80qZcDydZCdLrOcaH/VOa9knKWjQVyyg8MtEgBAvgfNMsiLEZze', 'Dipendente'),
|
||||
('Elena', 'Rossi', 'elena.rossi@academy.it', '$2b$10$7Z80qZcDydZCdLrOcaH/VOa9knKWjQVyyg8MtEgBAvgfNMsiLEZze', 'Dipendente');
|
||||
|
|
|
|||
|
|
@ -17,13 +17,6 @@ export function mapDbError(error: unknown): DbErrorResponse | null {
|
|||
const message = err.sqlMessage ?? err.message ?? "";
|
||||
|
||||
if (err.code === "ER_DUP_ENTRY") {
|
||||
if (message.includes("uk_cliente_email")) {
|
||||
return {
|
||||
status: 409,
|
||||
error: "Email già registrata",
|
||||
fields: { email: "Email già registrata" },
|
||||
};
|
||||
}
|
||||
if (message.includes("uk_utente_email")) {
|
||||
return {
|
||||
status: 409,
|
||||
|
|
@ -31,39 +24,36 @@ export function mapDbError(error: unknown): DbErrorResponse | null {
|
|||
fields: { email: "Email già registrata" },
|
||||
};
|
||||
}
|
||||
if (message.includes("uk_chiaveConsegna")) {
|
||||
return {
|
||||
status: 409,
|
||||
error: "Chiave consegna già registrata",
|
||||
fields: { chiaveConsegna: "Chiave consegna già registrata" },
|
||||
};
|
||||
}
|
||||
return { status: 409, error: "Valore duplicato" };
|
||||
}
|
||||
|
||||
if (err.code === "ER_SIGNAL_EXCEPTION" || err.errno === 1644) {
|
||||
if (message.includes("DataRitiro")) {
|
||||
return {
|
||||
status: 400,
|
||||
error: "Data ritiro non valida",
|
||||
fields: { dataRitiro: "Data ritiro non può essere anteriore alla data odierna" },
|
||||
};
|
||||
}
|
||||
if (message.includes("DataConsegna")) {
|
||||
return {
|
||||
status: 400,
|
||||
error: "Data consegna non valida",
|
||||
fields: { dataConsegna: "Data consegna non può essere anteriore alla data odierna" },
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (err.code === "ER_CHECK_CONSTRAINT_VIOLATED") {
|
||||
if (message.includes("chk_consegna_almeno_una_data")) {
|
||||
if (message.includes("chk_corso_durata_ore")) {
|
||||
return {
|
||||
status: 400,
|
||||
error: "Inserire almeno una data di ritiro o di consegna",
|
||||
fields: { _form: "Inserire almeno una data di ritiro o di consegna" },
|
||||
error: "Durata corso non valida",
|
||||
fields: { durataOre: "La durata prevista deve essere maggiore di zero" },
|
||||
};
|
||||
}
|
||||
if (message.includes("chk_assegnazione_scadenza")) {
|
||||
return {
|
||||
status: 400,
|
||||
error: "Date assegnazione non valide",
|
||||
fields: { dataScadenza: "La data di scadenza non può essere precedente alla data di assegnazione" },
|
||||
};
|
||||
}
|
||||
if (message.includes("chk_assegnazione_completamento")) {
|
||||
return {
|
||||
status: 400,
|
||||
error: "Data completamento non valida",
|
||||
fields: { dataCompletamento: "La data di completamento non può essere precedente alla data di assegnazione" },
|
||||
};
|
||||
}
|
||||
if (message.includes("chk_assegnazione_completato")) {
|
||||
return {
|
||||
status: 400,
|
||||
error: "Stato assegnazione non coerente",
|
||||
fields: { stato: "Lo stato Completato richiede una data di completamento" },
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -71,16 +61,23 @@ export function mapDbError(error: unknown): DbErrorResponse | null {
|
|||
if (err.code === "ER_ROW_IS_REFERENCED_2") {
|
||||
return {
|
||||
status: 409,
|
||||
error: "Impossibile eliminare: esistono riferimenti collegati",
|
||||
error: "Impossibile eliminare: esistono assegnazioni collegate al corso",
|
||||
};
|
||||
}
|
||||
|
||||
if (err.code === "ER_NO_REFERENCED_ROW_2") {
|
||||
if (message.includes("fk_consegna_cliente")) {
|
||||
if (message.includes("fk_assegnazione_corso")) {
|
||||
return {
|
||||
status: 400,
|
||||
error: "Cliente non valido",
|
||||
fields: { clienteId: "Cliente non trovato" },
|
||||
error: "Corso non valido",
|
||||
fields: { corsoId: "Corso non trovato" },
|
||||
};
|
||||
}
|
||||
if (message.includes("fk_assegnazione_dipendente")) {
|
||||
return {
|
||||
status: 400,
|
||||
error: "Dipendente non valido",
|
||||
fields: { dipendenteId: "Dipendente non trovato" },
|
||||
};
|
||||
}
|
||||
return { status: 400, error: "Riferimento non valido" };
|
||||
|
|
|
|||
|
|
@ -1,3 +1,10 @@
|
|||
//====================================================
|
||||
// File: auth.ts
|
||||
// File middleware per gestionre dell'autenticazione
|
||||
// e le autorizzazini dei dipendenti/referenti academy
|
||||
// author: "villari.andrea@libero.it"
|
||||
// version: "1.0.0 2026-07-14"
|
||||
//====================================================
|
||||
import { getSession } from "@auth/express";
|
||||
import type { NextFunction, Request, Response } from "express";
|
||||
import { authConfig } from "../auth/config.js";
|
||||
|
|
@ -18,14 +25,17 @@ export async function requireAuth(req: Request, res: Response, next: NextFunctio
|
|||
next();
|
||||
}
|
||||
|
||||
export function requireAmministratore(req: Request, res: Response, next: NextFunction) {
|
||||
if (req.user?.ruolo !== "Amministratore") {
|
||||
res.status(403).json({ error: "Operazione riservata agli amministratori" });
|
||||
export function requireReferenteAcademy(req: Request, res: Response, next: NextFunction) {
|
||||
if (req.user?.ruolo !== "Referente Academy") {
|
||||
res.status(403).json({ error: "Operazione riservata ai referenti Academy" });
|
||||
return;
|
||||
}
|
||||
next();
|
||||
}
|
||||
|
||||
/** @deprecated Usare requireReferenteAcademy */
|
||||
export const requireAmministratore = requireReferenteAcademy;
|
||||
|
||||
declare global {
|
||||
namespace Express {
|
||||
interface Request {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,15 @@
|
|||
//=============================================
|
||||
// File: index.ts
|
||||
// Script per la gestine degli endpoint /utente
|
||||
// author: "villari.andrea@libero.it"
|
||||
// version: "1.0.0 2026-07-14"
|
||||
//=============================================
|
||||
import bcrypt from "bcryptjs";
|
||||
import { Router } from "express";
|
||||
import type { ResultSetHeader, RowDataPacket } from "mysql2";
|
||||
import pool from "../db/pool.js";
|
||||
import { mapDbError } from "../errors/db.js";
|
||||
import { requireAmministratore, requireAuth } from "../middleware/auth.js";
|
||||
import { requireAuth, requireReferenteAcademy } from "../middleware/auth.js";
|
||||
import type { Ruolo } from "../types/index.js";
|
||||
import { validateBody } from "../validation/middleware.js";
|
||||
import {
|
||||
|
|
@ -41,7 +47,7 @@ async function findUtenteById(id: number): Promise<UtenteRow | undefined> {
|
|||
return rows[0];
|
||||
}
|
||||
|
||||
router.use(requireAuth, requireAmministratore);
|
||||
router.use(requireAuth, requireReferenteAcademy);
|
||||
|
||||
router.get("/", async (_req, res) => {
|
||||
const [rows] = await pool.execute<UtenteRow[]>(
|
||||
|
|
|
|||
|
|
@ -1,8 +1,18 @@
|
|||
import { CONSEGNA_CONSTRAINTS, UTENTE_CONSTRAINTS } from "../validation/constraints.js";
|
||||
//==============================================
|
||||
// File: index.ts
|
||||
// Script con i tipi relativi alle varie entità
|
||||
// author: "villari.andrea@libero.it"
|
||||
// version: "1.0.0 2026-07-14"
|
||||
//==============================================
|
||||
import {
|
||||
ASSEGNAZIONE_CONSTRAINTS,
|
||||
UTENTE_CONSTRAINTS,
|
||||
} from "../validation/constraints.js";
|
||||
|
||||
export type Ruolo = (typeof UTENTE_CONSTRAINTS.ruolo.allowedValues)[number];
|
||||
|
||||
export type StatoConsegna = (typeof CONSEGNA_CONSTRAINTS.stato.allowedValues)[number];
|
||||
export type StatoAssegnazione =
|
||||
(typeof ASSEGNAZIONE_CONSTRAINTS.stato.allowedValues)[number];
|
||||
|
||||
export interface Utente {
|
||||
UtenteID: number;
|
||||
|
|
@ -13,23 +23,22 @@ export interface Utente {
|
|||
Ruolo: Ruolo;
|
||||
}
|
||||
|
||||
export interface Cliente {
|
||||
ClienteID: number;
|
||||
Nome: string;
|
||||
Cognome: string;
|
||||
Via: string;
|
||||
Comune: string;
|
||||
Provincia: string;
|
||||
Telefono: string;
|
||||
Email: string;
|
||||
Note: string | null;
|
||||
export interface Corso {
|
||||
CorsoID: number;
|
||||
Titolo: string;
|
||||
Descrizione: string | null;
|
||||
Categoria: string;
|
||||
DurataOre: number;
|
||||
Obbligatorio: boolean;
|
||||
Attivo: boolean;
|
||||
}
|
||||
|
||||
export interface Consegna {
|
||||
ConsegnaID: number;
|
||||
ClienteID: number;
|
||||
DataRitiro: Date | null;
|
||||
DataConsegna: Date | null;
|
||||
Stato: StatoConsegna;
|
||||
ChiaveConsegna: string;
|
||||
export interface AssegnazioneCorso {
|
||||
AssegnazioneID: number;
|
||||
CorsoID: number;
|
||||
DipendenteID: number;
|
||||
DataAssegnazione: Date;
|
||||
DataScadenza: Date;
|
||||
Stato: StatoAssegnazione;
|
||||
DataCompletamento: Date | null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
// File: constraints.ts
|
||||
// Vincoli derivati da initdb/01_schema.sql.
|
||||
// author: "villari.andrea@libero.it"
|
||||
// version: "1.0.0 2026-06-18"
|
||||
// version: "1.0.0 2026-14-07"
|
||||
//=========================================
|
||||
|
||||
export const UTENTE_CONSTRAINTS = {
|
||||
|
|
@ -10,31 +10,24 @@ export const UTENTE_CONSTRAINTS = {
|
|||
cognome: { maxLength: 100, required: true },
|
||||
email: { maxLength: 255, required: true },
|
||||
password: { minLength: 8, maxLength: 72, required: true },
|
||||
ruolo: {allowedValues: ["Operatore", "Amministratore"],
|
||||
required: true,
|
||||
}
|
||||
} as const;
|
||||
|
||||
export const CLIENTE_CONSTRAINTS = {
|
||||
nome: { maxLength: 100, required: true },
|
||||
cognome: { maxLength: 100, required: true },
|
||||
via: {maxLength: 100, required: true},
|
||||
comune: {maxLength: 100, required: true},
|
||||
provincia: {maxLength: 2, required: true},
|
||||
telefono: { maxLength: 30, required: true },
|
||||
email: { maxLength: 255, required: true },
|
||||
note: { required: false },
|
||||
} as const;
|
||||
|
||||
|
||||
export const CONSEGNA_CONSTRAINTS = {
|
||||
dataRitiro: { required: false },
|
||||
dataConsegna: { required: false },
|
||||
stato: {
|
||||
allowedValues: ["da ritirare", "in consegna", "in giacenza", "in deposito"],
|
||||
ruolo: {
|
||||
allowedValues: ["Dipendente", "Referente Academy"] as const,
|
||||
required: true,
|
||||
},
|
||||
chiaveConsegna: { maxLength: 8, required: true },
|
||||
clienteId: { required: true },
|
||||
} as const;
|
||||
} as const;
|
||||
|
||||
export const CORSO_CONSTRAINTS = {
|
||||
titolo: { maxLength: 200, required: true },
|
||||
descrizione: { maxLength: 65535, required: false },
|
||||
categoria: { maxLength: 100, required: true },
|
||||
durataOre: { min: 1, max: 65535, required: true },
|
||||
obbligatorio: { required: false },
|
||||
attivo: { required: false },
|
||||
} as const;
|
||||
|
||||
export const ASSEGNAZIONE_CONSTRAINTS = {
|
||||
stato: {
|
||||
allowedValues: ["Assegnato", "Completato", "Scaduto", "Annullato"] as const,
|
||||
required: true,
|
||||
},
|
||||
} as const;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue