2026-07-14 11:14:18 +02:00
|
|
|
|
//======================================================
|
|
|
|
|
|
// File: openapi.ts
|
2026-07-14 15:09:07 +02:00
|
|
|
|
// Script per la gestione dello schema di configurazione
|
2026-07-14 11:14:18 +02:00
|
|
|
|
// di swagger.
|
|
|
|
|
|
// @author: "villari.andrea@libero.it"
|
|
|
|
|
|
// @version: "1.0.0 2026-07-14"
|
|
|
|
|
|
//======================================================
|
|
|
|
|
|
|
|
|
|
|
|
const errorSchema = {
|
|
|
|
|
|
type: "object",
|
|
|
|
|
|
properties: {
|
|
|
|
|
|
error: { type: "string" },
|
|
|
|
|
|
fields: {
|
|
|
|
|
|
type: "object",
|
|
|
|
|
|
additionalProperties: { type: "string" },
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
} as const;
|
|
|
|
|
|
|
|
|
|
|
|
const utenteSchema = {
|
|
|
|
|
|
type: "object",
|
|
|
|
|
|
properties: {
|
|
|
|
|
|
id: { type: "integer" },
|
|
|
|
|
|
nome: { type: "string" },
|
|
|
|
|
|
cognome: { type: "string" },
|
|
|
|
|
|
email: { type: "string", format: "email" },
|
|
|
|
|
|
ruolo: { type: "string", enum: ["Dipendente", "Referente Academy"] },
|
|
|
|
|
|
},
|
|
|
|
|
|
} as const;
|
|
|
|
|
|
|
|
|
|
|
|
const corsoSchema = {
|
|
|
|
|
|
type: "object",
|
|
|
|
|
|
properties: {
|
|
|
|
|
|
id: { type: "integer" },
|
|
|
|
|
|
titolo: { type: "string" },
|
|
|
|
|
|
descrizione: { type: "string", nullable: true },
|
|
|
|
|
|
categoria: { type: "string" },
|
|
|
|
|
|
durataOre: { type: "integer", minimum: 1 },
|
|
|
|
|
|
obbligatorio: { type: "boolean" },
|
|
|
|
|
|
attivo: { type: "boolean" },
|
|
|
|
|
|
},
|
|
|
|
|
|
} as const;
|
|
|
|
|
|
|
|
|
|
|
|
const assegnazioneSchema = {
|
|
|
|
|
|
type: "object",
|
|
|
|
|
|
properties: {
|
|
|
|
|
|
id: { type: "integer" },
|
|
|
|
|
|
corsoId: { type: "integer" },
|
|
|
|
|
|
dipendenteId: { type: "integer" },
|
|
|
|
|
|
dataAssegnazione: { type: "string", format: "date" },
|
|
|
|
|
|
dataScadenza: { type: "string", format: "date" },
|
|
|
|
|
|
stato: {
|
|
|
|
|
|
type: "string",
|
|
|
|
|
|
enum: ["Assegnato", "Completato", "Scaduto", "Annullato"],
|
|
|
|
|
|
},
|
|
|
|
|
|
dataCompletamento: { type: "string", format: "date", nullable: true },
|
|
|
|
|
|
corso: {
|
|
|
|
|
|
type: "object",
|
|
|
|
|
|
properties: {
|
|
|
|
|
|
id: { type: "integer" },
|
|
|
|
|
|
titolo: { type: "string" },
|
|
|
|
|
|
categoria: { type: "string" },
|
|
|
|
|
|
durataOre: { type: "integer" },
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
dipendente: {
|
|
|
|
|
|
type: "object",
|
|
|
|
|
|
properties: {
|
|
|
|
|
|
id: { type: "integer" },
|
|
|
|
|
|
nome: { type: "string" },
|
|
|
|
|
|
cognome: { type: "string" },
|
|
|
|
|
|
email: { type: "string", format: "email" },
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
} as const;
|
|
|
|
|
|
|
|
|
|
|
|
const statisticaSchema = {
|
|
|
|
|
|
type: "object",
|
|
|
|
|
|
properties: {
|
|
|
|
|
|
mese: { type: "string", example: "2026-05" },
|
|
|
|
|
|
categoria: { type: "string", example: "Sicurezza" },
|
|
|
|
|
|
numeroAssegnazioni: { type: "integer", example: 18 },
|
|
|
|
|
|
numeroCompletamenti: { type: "integer", example: 12 },
|
|
|
|
|
|
percentualeCompletamento: { type: "number", example: 66.67 },
|
|
|
|
|
|
},
|
|
|
|
|
|
} as const;
|
|
|
|
|
|
|
|
|
|
|
|
const idParam = {
|
|
|
|
|
|
name: "id",
|
|
|
|
|
|
in: "path",
|
|
|
|
|
|
required: true,
|
|
|
|
|
|
schema: { type: "integer", minimum: 1 },
|
|
|
|
|
|
} as const;
|
|
|
|
|
|
|
|
|
|
|
|
const responses = {
|
|
|
|
|
|
unauthorized: {
|
|
|
|
|
|
description: "Autenticazione richiesta",
|
|
|
|
|
|
content: { "application/json": { schema: errorSchema } },
|
|
|
|
|
|
},
|
|
|
|
|
|
forbidden: {
|
|
|
|
|
|
description: "Operazione non consentita per il ruolo corrente",
|
|
|
|
|
|
content: { "application/json": { schema: errorSchema } },
|
|
|
|
|
|
},
|
|
|
|
|
|
notFound: {
|
|
|
|
|
|
description: "Risorsa non trovata",
|
|
|
|
|
|
content: { "application/json": { schema: errorSchema } },
|
|
|
|
|
|
},
|
|
|
|
|
|
validationError: {
|
|
|
|
|
|
description: "Validazione fallita",
|
|
|
|
|
|
content: { "application/json": { schema: errorSchema } },
|
|
|
|
|
|
},
|
|
|
|
|
|
} as const;
|
|
|
|
|
|
|
|
|
|
|
|
export const openApiSpec = {
|
|
|
|
|
|
openapi: "3.0.3",
|
|
|
|
|
|
info: {
|
|
|
|
|
|
title: "Esame ITS 24-26 – Academy API",
|
|
|
|
|
|
version: "1.0.0",
|
|
|
|
|
|
description: [
|
|
|
|
|
|
"API REST per la gestione dell'Academy aziendale (corsi, assegnazioni, statistiche).",
|
|
|
|
|
|
"",
|
|
|
|
|
|
"### Autenticazione",
|
|
|
|
|
|
"Le API protette usano sessioni Auth.js tramite cookie HTTP-only.",
|
|
|
|
|
|
"1. `GET /api/auth/csrf` per ottenere il token CSRF",
|
|
|
|
|
|
"2. `POST /api/auth/callback/credentials` con `email`, `password`, `csrfToken`",
|
|
|
|
|
|
"3. Le richieste successive inviano automaticamente il cookie di sessione",
|
|
|
|
|
|
"",
|
|
|
|
|
|
"### Utenti di test",
|
|
|
|
|
|
"| Email | Password | Ruolo |",
|
|
|
|
|
|
"|-------|----------|-------|",
|
|
|
|
|
|
"| admin@academy.it | Password123! | Referente Academy |",
|
|
|
|
|
|
"| maria.bianchi@academy.it | Password123! | Dipendente |",
|
|
|
|
|
|
].join("\n"),
|
|
|
|
|
|
},
|
|
|
|
|
|
servers: [{ url: "/", description: "Server corrente" }],
|
|
|
|
|
|
tags: [
|
|
|
|
|
|
{ name: "Sistema", description: "Health check e documentazione" },
|
|
|
|
|
|
{ name: "Autenticazione", description: "Login e sessione" },
|
|
|
|
|
|
{ name: "Profilo", description: "Utente autenticato" },
|
|
|
|
|
|
{ name: "Utenti", description: "Gestione utenti (Referente Academy)" },
|
|
|
|
|
|
{ name: "Corsi", description: "Catalogo corsi Academy" },
|
|
|
|
|
|
{ name: "Assegnazioni", description: "Assegnazioni corsi ai dipendenti" },
|
|
|
|
|
|
{ name: "Statistiche", description: "Riepiloghi formativi" },
|
|
|
|
|
|
],
|
|
|
|
|
|
components: {
|
|
|
|
|
|
securitySchemes: {
|
|
|
|
|
|
cookieAuth: {
|
|
|
|
|
|
type: "apiKey",
|
|
|
|
|
|
in: "cookie",
|
|
|
|
|
|
name: "authjs.session-token",
|
|
|
|
|
|
description:
|
|
|
|
|
|
"Cookie di sessione Auth.js. In produzione può essere __Secure-authjs.session-token.",
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
schemas: {
|
|
|
|
|
|
Error: errorSchema,
|
|
|
|
|
|
Utente: utenteSchema,
|
|
|
|
|
|
Corso: corsoSchema,
|
|
|
|
|
|
AssegnazioneCorso: assegnazioneSchema,
|
|
|
|
|
|
StatisticaAcademy: statisticaSchema,
|
|
|
|
|
|
UtenteCreate: {
|
|
|
|
|
|
type: "object",
|
|
|
|
|
|
required: ["nome", "cognome", "email", "password", "ruolo"],
|
|
|
|
|
|
properties: {
|
|
|
|
|
|
nome: { type: "string" },
|
|
|
|
|
|
cognome: { type: "string" },
|
|
|
|
|
|
email: { type: "string", format: "email" },
|
|
|
|
|
|
password: { type: "string", minLength: 8 },
|
|
|
|
|
|
ruolo: { type: "string", enum: ["Dipendente", "Referente Academy"] },
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
CorsoCreate: {
|
|
|
|
|
|
type: "object",
|
|
|
|
|
|
required: ["titolo", "categoria", "durataOre"],
|
|
|
|
|
|
properties: {
|
|
|
|
|
|
titolo: { type: "string" },
|
|
|
|
|
|
descrizione: { type: "string", nullable: true },
|
|
|
|
|
|
categoria: { type: "string" },
|
|
|
|
|
|
durataOre: { type: "integer", minimum: 1 },
|
|
|
|
|
|
obbligatorio: { type: "boolean", default: false },
|
|
|
|
|
|
attivo: { type: "boolean", default: true },
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
AssegnazioneCreate: {
|
|
|
|
|
|
type: "object",
|
|
|
|
|
|
required: ["corsoId", "dipendenteId", "dataAssegnazione", "dataScadenza"],
|
|
|
|
|
|
properties: {
|
|
|
|
|
|
corsoId: { type: "integer" },
|
|
|
|
|
|
dipendenteId: { type: "integer" },
|
|
|
|
|
|
dataAssegnazione: { type: "string", format: "date" },
|
|
|
|
|
|
dataScadenza: { type: "string", format: "date" },
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
AssegnazioneCompleta: {
|
|
|
|
|
|
type: "object",
|
|
|
|
|
|
properties: {
|
|
|
|
|
|
dataCompletamento: {
|
|
|
|
|
|
type: "string",
|
|
|
|
|
|
format: "date",
|
|
|
|
|
|
description: "Se omessa, viene usata la data odierna",
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
paths: {
|
|
|
|
|
|
"/api/health": {
|
|
|
|
|
|
get: {
|
|
|
|
|
|
tags: ["Sistema"],
|
|
|
|
|
|
summary: "Health check",
|
|
|
|
|
|
responses: {
|
|
|
|
|
|
200: {
|
|
|
|
|
|
description: "Servizio attivo",
|
|
|
|
|
|
content: {
|
|
|
|
|
|
"application/json": {
|
|
|
|
|
|
schema: {
|
|
|
|
|
|
type: "object",
|
|
|
|
|
|
properties: { status: { type: "string", example: "ok" } },
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
"/api/auth/csrf": {
|
|
|
|
|
|
get: {
|
|
|
|
|
|
tags: ["Autenticazione"],
|
|
|
|
|
|
summary: "Ottieni token CSRF per il login",
|
|
|
|
|
|
responses: {
|
|
|
|
|
|
200: {
|
|
|
|
|
|
description: "Token CSRF",
|
|
|
|
|
|
content: {
|
|
|
|
|
|
"application/json": {
|
|
|
|
|
|
schema: {
|
|
|
|
|
|
type: "object",
|
|
|
|
|
|
properties: { csrfToken: { type: "string" } },
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
"/api/auth/callback/credentials": {
|
|
|
|
|
|
post: {
|
|
|
|
|
|
tags: ["Autenticazione"],
|
|
|
|
|
|
summary: "Login con email e password",
|
|
|
|
|
|
requestBody: {
|
|
|
|
|
|
required: true,
|
|
|
|
|
|
content: {
|
|
|
|
|
|
"application/x-www-form-urlencoded": {
|
|
|
|
|
|
schema: {
|
|
|
|
|
|
type: "object",
|
|
|
|
|
|
required: ["csrfToken", "email", "password"],
|
|
|
|
|
|
properties: {
|
|
|
|
|
|
csrfToken: { type: "string" },
|
|
|
|
|
|
email: { type: "string", format: "email" },
|
|
|
|
|
|
password: { type: "string" },
|
|
|
|
|
|
redirect: { type: "string", example: "false" },
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
responses: {
|
|
|
|
|
|
200: { description: "Login riuscito, cookie di sessione impostato" },
|
|
|
|
|
|
401: { description: "Credenziali non valide" },
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
"/api/auth/signout": {
|
|
|
|
|
|
post: {
|
|
|
|
|
|
tags: ["Autenticazione"],
|
|
|
|
|
|
summary: "Logout",
|
|
|
|
|
|
security: [{ cookieAuth: [] }],
|
|
|
|
|
|
responses: {
|
|
|
|
|
|
200: { description: "Logout effettuato" },
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
"/api/me": {
|
|
|
|
|
|
get: {
|
|
|
|
|
|
tags: ["Profilo"],
|
|
|
|
|
|
summary: "Profilo utente autenticato",
|
|
|
|
|
|
security: [{ cookieAuth: [] }],
|
|
|
|
|
|
responses: {
|
|
|
|
|
|
200: {
|
|
|
|
|
|
description: "Profilo corrente",
|
|
|
|
|
|
content: { "application/json": { schema: utenteSchema } },
|
|
|
|
|
|
},
|
|
|
|
|
|
401: responses.unauthorized,
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
"/api/utenti": {
|
|
|
|
|
|
get: {
|
|
|
|
|
|
tags: ["Utenti"],
|
|
|
|
|
|
summary: "Elenco utenti",
|
|
|
|
|
|
security: [{ cookieAuth: [] }],
|
|
|
|
|
|
parameters: [
|
|
|
|
|
|
{
|
|
|
|
|
|
name: "ruolo",
|
|
|
|
|
|
in: "query",
|
|
|
|
|
|
schema: { type: "string", enum: ["Dipendente", "Referente Academy"] },
|
|
|
|
|
|
description: "Filtra per ruolo (es. Dipendente per l'elenco dipendenti)",
|
|
|
|
|
|
},
|
|
|
|
|
|
],
|
|
|
|
|
|
responses: {
|
|
|
|
|
|
200: {
|
|
|
|
|
|
description: "Lista utenti",
|
|
|
|
|
|
content: {
|
|
|
|
|
|
"application/json": {
|
|
|
|
|
|
schema: { type: "array", items: utenteSchema },
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
401: responses.unauthorized,
|
|
|
|
|
|
403: responses.forbidden,
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
post: {
|
|
|
|
|
|
tags: ["Utenti"],
|
|
|
|
|
|
summary: "Crea utente",
|
|
|
|
|
|
security: [{ cookieAuth: [] }],
|
|
|
|
|
|
requestBody: {
|
|
|
|
|
|
required: true,
|
|
|
|
|
|
content: {
|
|
|
|
|
|
"application/json": {
|
|
|
|
|
|
schema: { $ref: "#/components/schemas/UtenteCreate" },
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
responses: {
|
|
|
|
|
|
201: {
|
|
|
|
|
|
description: "Utente creato",
|
|
|
|
|
|
content: { "application/json": { schema: utenteSchema } },
|
|
|
|
|
|
},
|
|
|
|
|
|
400: responses.validationError,
|
|
|
|
|
|
403: responses.forbidden,
|
|
|
|
|
|
409: { description: "Email già registrata" },
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
2026-07-14 16:03:16 +02:00
|
|
|
|
"/api/utenti/login": {
|
|
|
|
|
|
post: {
|
|
|
|
|
|
tags: ["Utenti"],
|
|
|
|
|
|
summary: "Login utente",
|
|
|
|
|
|
description:
|
|
|
|
|
|
"Autentica l'utente con email e password. Imposta il cookie di sessione.",
|
|
|
|
|
|
requestBody: {
|
|
|
|
|
|
required: true,
|
|
|
|
|
|
content: {
|
|
|
|
|
|
"application/json": {
|
|
|
|
|
|
schema: {
|
|
|
|
|
|
type: "object",
|
|
|
|
|
|
required: ["email", "password"],
|
|
|
|
|
|
properties: {
|
|
|
|
|
|
email: { type: "string", format: "email" },
|
|
|
|
|
|
password: { type: "string" },
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
responses: {
|
|
|
|
|
|
200: {
|
|
|
|
|
|
description: "Login riuscito",
|
|
|
|
|
|
content: { "application/json": { schema: utenteSchema } },
|
|
|
|
|
|
},
|
|
|
|
|
|
400: responses.validationError,
|
|
|
|
|
|
401: { description: "Credenziali non valide" },
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
"/api/utenti/register": {
|
|
|
|
|
|
post: {
|
|
|
|
|
|
tags: ["Utenti"],
|
|
|
|
|
|
summary: "Registra utente",
|
|
|
|
|
|
description:
|
|
|
|
|
|
"Crea un nuovo utente (Dipendente o Referente Academy). Richiede autenticazione Referente Academy.",
|
|
|
|
|
|
security: [{ cookieAuth: [] }],
|
|
|
|
|
|
requestBody: {
|
|
|
|
|
|
required: true,
|
|
|
|
|
|
content: {
|
|
|
|
|
|
"application/json": {
|
|
|
|
|
|
schema: { $ref: "#/components/schemas/UtenteCreate" },
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
responses: {
|
|
|
|
|
|
201: {
|
|
|
|
|
|
description: "Utente registrato",
|
|
|
|
|
|
content: { "application/json": { schema: utenteSchema } },
|
|
|
|
|
|
},
|
|
|
|
|
|
400: responses.validationError,
|
|
|
|
|
|
403: responses.forbidden,
|
|
|
|
|
|
409: { description: "Email già registrata" },
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
2026-07-14 11:14:18 +02:00
|
|
|
|
"/api/utenti/{id}": {
|
|
|
|
|
|
get: {
|
|
|
|
|
|
tags: ["Utenti"],
|
|
|
|
|
|
summary: "Dettaglio utente",
|
|
|
|
|
|
security: [{ cookieAuth: [] }],
|
|
|
|
|
|
parameters: [idParam],
|
|
|
|
|
|
responses: {
|
|
|
|
|
|
200: {
|
|
|
|
|
|
description: "Utente trovato",
|
|
|
|
|
|
content: { "application/json": { schema: utenteSchema } },
|
|
|
|
|
|
},
|
|
|
|
|
|
404: responses.notFound,
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
put: {
|
|
|
|
|
|
tags: ["Utenti"],
|
|
|
|
|
|
summary: "Aggiorna utente",
|
|
|
|
|
|
security: [{ cookieAuth: [] }],
|
|
|
|
|
|
parameters: [idParam],
|
|
|
|
|
|
requestBody: {
|
|
|
|
|
|
required: true,
|
|
|
|
|
|
content: {
|
|
|
|
|
|
"application/json": {
|
|
|
|
|
|
schema: { $ref: "#/components/schemas/UtenteCreate" },
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
responses: {
|
|
|
|
|
|
200: {
|
|
|
|
|
|
description: "Utente aggiornato",
|
|
|
|
|
|
content: { "application/json": { schema: utenteSchema } },
|
|
|
|
|
|
},
|
|
|
|
|
|
400: responses.validationError,
|
|
|
|
|
|
404: responses.notFound,
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
delete: {
|
|
|
|
|
|
tags: ["Utenti"],
|
|
|
|
|
|
summary: "Elimina utente",
|
|
|
|
|
|
security: [{ cookieAuth: [] }],
|
|
|
|
|
|
parameters: [idParam],
|
|
|
|
|
|
responses: {
|
|
|
|
|
|
204: { description: "Utente eliminato" },
|
|
|
|
|
|
400: { description: "Impossibile eliminare il proprio account" },
|
|
|
|
|
|
404: responses.notFound,
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
"/api/corsi": {
|
|
|
|
|
|
get: {
|
|
|
|
|
|
tags: ["Corsi"],
|
|
|
|
|
|
summary: "Elenco corsi",
|
|
|
|
|
|
security: [{ cookieAuth: [] }],
|
|
|
|
|
|
parameters: [
|
|
|
|
|
|
{ name: "categoria", in: "query", schema: { type: "string" } },
|
|
|
|
|
|
{ name: "attivo", in: "query", schema: { type: "boolean" } },
|
|
|
|
|
|
],
|
|
|
|
|
|
responses: {
|
|
|
|
|
|
200: {
|
|
|
|
|
|
description: "Lista corsi",
|
|
|
|
|
|
content: {
|
|
|
|
|
|
"application/json": {
|
|
|
|
|
|
schema: { type: "array", items: corsoSchema },
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
post: {
|
|
|
|
|
|
tags: ["Corsi"],
|
|
|
|
|
|
summary: "Crea corso",
|
|
|
|
|
|
security: [{ cookieAuth: [] }],
|
|
|
|
|
|
requestBody: {
|
|
|
|
|
|
required: true,
|
|
|
|
|
|
content: {
|
|
|
|
|
|
"application/json": {
|
|
|
|
|
|
schema: { $ref: "#/components/schemas/CorsoCreate" },
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
responses: {
|
|
|
|
|
|
201: {
|
|
|
|
|
|
description: "Corso creato",
|
|
|
|
|
|
content: { "application/json": { schema: corsoSchema } },
|
|
|
|
|
|
},
|
|
|
|
|
|
403: responses.forbidden,
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
"/api/corsi/{id}": {
|
|
|
|
|
|
get: {
|
|
|
|
|
|
tags: ["Corsi"],
|
|
|
|
|
|
summary: "Dettaglio corso",
|
|
|
|
|
|
security: [{ cookieAuth: [] }],
|
|
|
|
|
|
parameters: [idParam],
|
|
|
|
|
|
responses: {
|
|
|
|
|
|
200: {
|
|
|
|
|
|
description: "Corso trovato",
|
|
|
|
|
|
content: { "application/json": { schema: corsoSchema } },
|
|
|
|
|
|
},
|
|
|
|
|
|
404: responses.notFound,
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
put: {
|
|
|
|
|
|
tags: ["Corsi"],
|
|
|
|
|
|
summary: "Modifica corso",
|
|
|
|
|
|
security: [{ cookieAuth: [] }],
|
|
|
|
|
|
parameters: [idParam],
|
|
|
|
|
|
requestBody: {
|
|
|
|
|
|
required: true,
|
|
|
|
|
|
content: {
|
|
|
|
|
|
"application/json": {
|
|
|
|
|
|
schema: { $ref: "#/components/schemas/CorsoCreate" },
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
responses: {
|
|
|
|
|
|
200: {
|
|
|
|
|
|
description: "Corso aggiornato",
|
|
|
|
|
|
content: { "application/json": { schema: corsoSchema } },
|
|
|
|
|
|
},
|
|
|
|
|
|
403: responses.forbidden,
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
delete: {
|
|
|
|
|
|
tags: ["Corsi"],
|
|
|
|
|
|
summary: "Elimina corso",
|
|
|
|
|
|
security: [{ cookieAuth: [] }],
|
|
|
|
|
|
parameters: [idParam],
|
|
|
|
|
|
responses: {
|
|
|
|
|
|
204: { description: "Corso eliminato" },
|
|
|
|
|
|
409: { description: "Corso con assegnazioni collegate" },
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
"/api/corsi/{id}/disattiva": {
|
|
|
|
|
|
put: {
|
|
|
|
|
|
tags: ["Corsi"],
|
|
|
|
|
|
summary: "Disattiva corso",
|
|
|
|
|
|
security: [{ cookieAuth: [] }],
|
|
|
|
|
|
parameters: [idParam],
|
|
|
|
|
|
responses: {
|
|
|
|
|
|
200: {
|
|
|
|
|
|
description: "Corso disattivato",
|
|
|
|
|
|
content: { "application/json": { schema: corsoSchema } },
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
"/api/assegnazioni-corsi": {
|
|
|
|
|
|
get: {
|
|
|
|
|
|
tags: ["Assegnazioni"],
|
|
|
|
|
|
summary: "Elenco assegnazioni",
|
|
|
|
|
|
security: [{ cookieAuth: [] }],
|
|
|
|
|
|
parameters: [
|
|
|
|
|
|
{
|
|
|
|
|
|
name: "stato",
|
|
|
|
|
|
in: "query",
|
|
|
|
|
|
schema: {
|
|
|
|
|
|
type: "string",
|
|
|
|
|
|
enum: ["Assegnato", "Completato", "Scaduto", "Annullato"],
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
{ name: "categoria", in: "query", schema: { type: "string" } },
|
|
|
|
|
|
{ name: "corsoId", in: "query", schema: { type: "integer" } },
|
|
|
|
|
|
{
|
|
|
|
|
|
name: "dipendenteId",
|
|
|
|
|
|
in: "query",
|
|
|
|
|
|
schema: { type: "integer" },
|
|
|
|
|
|
description: "Solo Referente Academy",
|
|
|
|
|
|
},
|
|
|
|
|
|
],
|
|
|
|
|
|
responses: {
|
|
|
|
|
|
200: {
|
|
|
|
|
|
description: "Lista assegnazioni",
|
|
|
|
|
|
content: {
|
|
|
|
|
|
"application/json": {
|
|
|
|
|
|
schema: { type: "array", items: assegnazioneSchema },
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
post: {
|
|
|
|
|
|
tags: ["Assegnazioni"],
|
|
|
|
|
|
summary: "Assegna corso a dipendente",
|
|
|
|
|
|
security: [{ cookieAuth: [] }],
|
|
|
|
|
|
requestBody: {
|
|
|
|
|
|
required: true,
|
|
|
|
|
|
content: {
|
|
|
|
|
|
"application/json": {
|
|
|
|
|
|
schema: { $ref: "#/components/schemas/AssegnazioneCreate" },
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
responses: {
|
|
|
|
|
|
201: {
|
|
|
|
|
|
description: "Assegnazione creata",
|
|
|
|
|
|
content: { "application/json": { schema: assegnazioneSchema } },
|
|
|
|
|
|
},
|
|
|
|
|
|
403: responses.forbidden,
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
"/api/assegnazioni-corsi/{id}": {
|
|
|
|
|
|
get: {
|
|
|
|
|
|
tags: ["Assegnazioni"],
|
|
|
|
|
|
summary: "Dettaglio assegnazione",
|
|
|
|
|
|
security: [{ cookieAuth: [] }],
|
|
|
|
|
|
parameters: [idParam],
|
|
|
|
|
|
responses: {
|
|
|
|
|
|
200: {
|
|
|
|
|
|
description: "Assegnazione trovata",
|
|
|
|
|
|
content: { "application/json": { schema: assegnazioneSchema } },
|
|
|
|
|
|
},
|
|
|
|
|
|
403: responses.forbidden,
|
|
|
|
|
|
404: responses.notFound,
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
put: {
|
|
|
|
|
|
tags: ["Assegnazioni"],
|
|
|
|
|
|
summary: "Modifica assegnazione",
|
|
|
|
|
|
security: [{ cookieAuth: [] }],
|
|
|
|
|
|
parameters: [idParam],
|
|
|
|
|
|
requestBody: {
|
|
|
|
|
|
required: true,
|
|
|
|
|
|
content: {
|
|
|
|
|
|
"application/json": {
|
|
|
|
|
|
schema: {
|
|
|
|
|
|
type: "object",
|
|
|
|
|
|
properties: {
|
|
|
|
|
|
corsoId: { type: "integer" },
|
|
|
|
|
|
dipendenteId: { type: "integer" },
|
|
|
|
|
|
dataAssegnazione: { type: "string", format: "date" },
|
|
|
|
|
|
dataScadenza: { type: "string", format: "date" },
|
|
|
|
|
|
stato: {
|
|
|
|
|
|
type: "string",
|
|
|
|
|
|
enum: ["Assegnato", "Completato", "Scaduto", "Annullato"],
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
}
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
responses: {
|
|
|
|
|
|
200: {
|
|
|
|
|
|
description: "Assegnazione aggiornata",
|
|
|
|
|
|
content: { "application/json": { schema: assegnazioneSchema } },
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
delete: {
|
|
|
|
|
|
tags: ["Assegnazioni"],
|
|
|
|
|
|
summary: "Elimina assegnazione",
|
|
|
|
|
|
security: [{ cookieAuth: [] }],
|
|
|
|
|
|
parameters: [idParam],
|
|
|
|
|
|
responses: {
|
|
|
|
|
|
204: { description: "Assegnazione eliminata" },
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
"/api/assegnazioni-corsi/{id}/completa": {
|
|
|
|
|
|
put: {
|
|
|
|
|
|
tags: ["Assegnazioni"],
|
|
|
|
|
|
summary: "Segna assegnazione come completata",
|
|
|
|
|
|
description: "Solo il dipendente titolare può completare la propria assegnazione.",
|
|
|
|
|
|
security: [{ cookieAuth: [] }],
|
|
|
|
|
|
parameters: [idParam],
|
|
|
|
|
|
requestBody: {
|
|
|
|
|
|
content: {
|
|
|
|
|
|
"application/json": {
|
|
|
|
|
|
schema: { $ref: "#/components/schemas/AssegnazioneCompleta" },
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
responses: {
|
|
|
|
|
|
200: {
|
|
|
|
|
|
description: "Assegnazione completata",
|
|
|
|
|
|
content: { "application/json": { schema: assegnazioneSchema } },
|
|
|
|
|
|
},
|
|
|
|
|
|
403: responses.forbidden,
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
"/api/assegnazioni-corsi/{id}/annulla": {
|
|
|
|
|
|
put: {
|
|
|
|
|
|
tags: ["Assegnazioni"],
|
|
|
|
|
|
summary: "Annulla assegnazione",
|
|
|
|
|
|
security: [{ cookieAuth: [] }],
|
|
|
|
|
|
parameters: [idParam],
|
|
|
|
|
|
responses: {
|
|
|
|
|
|
200: {
|
|
|
|
|
|
description: "Assegnazione annullata",
|
|
|
|
|
|
content: { "application/json": { schema: assegnazioneSchema } },
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
"/api/statistiche/academy": {
|
|
|
|
|
|
get: {
|
|
|
|
|
|
tags: ["Statistiche"],
|
|
|
|
|
|
summary: "Riepilogo formazione per mese e categoria",
|
|
|
|
|
|
security: [{ cookieAuth: [] }],
|
|
|
|
|
|
parameters: [
|
|
|
|
|
|
{
|
|
|
|
|
|
name: "mese",
|
|
|
|
|
|
in: "query",
|
|
|
|
|
|
schema: { type: "string", example: "2026-05" },
|
|
|
|
|
|
description: "Filtra per mese (YYYY-MM)",
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
name: "daMese",
|
|
|
|
|
|
in: "query",
|
|
|
|
|
|
schema: { type: "string", example: "2026-01" },
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
name: "aMese",
|
|
|
|
|
|
in: "query",
|
|
|
|
|
|
schema: { type: "string", example: "2026-12" },
|
|
|
|
|
|
},
|
|
|
|
|
|
{ name: "categoria", in: "query", schema: { type: "string" } },
|
|
|
|
|
|
{ name: "dipendenteId", in: "query", schema: { type: "integer" } },
|
|
|
|
|
|
],
|
|
|
|
|
|
responses: {
|
|
|
|
|
|
200: {
|
|
|
|
|
|
description: "Statistiche aggregate",
|
|
|
|
|
|
content: {
|
|
|
|
|
|
"application/json": {
|
|
|
|
|
|
schema: {
|
|
|
|
|
|
type: "array",
|
|
|
|
|
|
items: { $ref: "#/components/schemas/StatisticaAcademy" },
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
403: responses.forbidden,
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
} as const;
|