emilsoftware-utilities 2.0.0-dev.31 → 2.0.0-dev.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/accessi-module/Console/console.js +19 -39
- package/dist/accessi-module/Console/console.js.map +1 -1
- package/dist/accessi-module/Console/generated/model/authenticatedUserPayloadDto.d.ts +1 -1
- package/dist/accessi-module/Console/generated/model/authenticatedUserPayloadDto.js.map +1 -1
- package/dist/accessi-module/Console/generated/model/publicRegisterRequest.d.ts +0 -4
- package/dist/accessi-module/Console/generated/model/publicRegisterRequest.js.map +1 -1
- package/dist/accessi-module/Console/generated/model/registerRequest.d.ts +2 -6
- package/dist/accessi-module/Console/generated/model/registerRequest.js.map +1 -1
- package/dist/accessi-module/Console/generated/model/userDto.d.ts +3 -29
- package/dist/accessi-module/Console/generated/model/userDto.js.map +1 -1
- package/dist/accessi-module/Console/wiki.js +2 -2
- package/dist/accessi-module/Console/wiki.js.map +1 -1
- package/dist/accessi-module/Controllers/ConfiguratorController.js +2 -2
- package/dist/accessi-module/Controllers/ConfiguratorController.js.map +1 -1
- package/dist/accessi-module/Dtos/AuthenticatedUserPayloadDto.d.ts +1 -1
- package/dist/accessi-module/Dtos/AuthenticatedUserPayloadDto.js +1 -1
- package/dist/accessi-module/Dtos/AuthenticatedUserPayloadDto.js.map +1 -1
- package/dist/accessi-module/Dtos/PublicRegisterRequest.d.ts +1 -1
- package/dist/accessi-module/Dtos/PublicRegisterRequest.js +1 -1
- package/dist/accessi-module/Dtos/PublicRegisterRequest.js.map +1 -1
- package/dist/accessi-module/Dtos/RegisterRequest.d.ts +1 -3
- package/dist/accessi-module/Dtos/RegisterRequest.js +2 -22
- package/dist/accessi-module/Dtos/RegisterRequest.js.map +1 -1
- package/dist/accessi-module/Dtos/UserDto.d.ts +2 -15
- package/dist/accessi-module/Dtos/UserDto.js +4 -97
- package/dist/accessi-module/Dtos/UserDto.js.map +1 -1
- package/dist/accessi-module/Services/UserService/UserService.d.ts +1 -2
- package/dist/accessi-module/Services/UserService/UserService.js +19 -108
- package/dist/accessi-module/Services/UserService/UserService.js.map +1 -1
- package/dist/accessi-module/database-updates/AccessiDatabaseUpdater.js +16 -0
- package/dist/accessi-module/database-updates/AccessiDatabaseUpdater.js.map +1 -1
- package/dist/accessi-module/database-updates/accessiSchema.d.ts +12 -1
- package/dist/accessi-module/database-updates/accessiSchema.js +18 -9
- package/dist/accessi-module/database-updates/accessiSchema.js.map +1 -1
- package/dist/accessi-module/security/accessControl.d.ts +2 -2
- package/dist/accessi-module/security/accessControl.js +2 -2
- package/dist/accessi-module/security/accessControl.js.map +1 -1
- package/dist/accessi-module/security/authenticatedToken.d.ts +1 -1
- package/dist/accessi-module/security/authenticatedToken.js +2 -2
- package/dist/accessi-module/security/authenticatedToken.js.map +1 -1
- package/dist/emilsoftware-utilities-2.0.0-dev.32.tgz +0 -0
- package/package.json +1 -1
- package/dist/emilsoftware-utilities-2.0.0-dev.31.tgz +0 -0
|
@@ -1141,8 +1141,8 @@ POST /api/accessi/auth/confirm-reset-password/{token}
|
|
|
1141
1141
|
" body: JSON.stringify({ email, flagSuper: true }), // ignorato o negato",
|
|
1142
1142
|
"});"
|
|
1143
1143
|
].join("\n"), "Privilegi dal client"),
|
|
1144
|
-
note("info", `
|
|
1145
|
-
note("info", `Gruppi menu e NOMECAMPO`, `Ogni gruppo menu puo dichiarare NOMECAMPO
|
|
1144
|
+
note("info", `Campi di dominio`, `UTENTI_CONFIG contiene solo i flag di dominio Accessi: FLGSUPER, FLGADMIN, FLG2FATT (2FA), FLGPWDLESS (passwordless) e FLGPASSWORD (login locale). I flag applicativi legacy (FLGMOP, FLGPIANA, FLGADDETTI, FLGOSPITI, FLGPIANARFID, FLGCONTA, FLGCUBI, FLGCICLPASS, FLGDIPENDENTI, FLGINVENTARI) e le colonne applicative (CAUMOV, NUMMAC, RAGSOCCLI) sono stati rimossi dallo schema: i backend devono gestirli in tabelle proprie. ENABLEIA resta per l'assistente IA.`),
|
|
1145
|
+
note("info", `Gruppi menu e NOMECAMPO`, `Ogni gruppo menu puo dichiarare NOMECAMPO. get-groups-with-menus e get-menus espongono nomeCampo. Dopo la pulizia dello schema NOMECAMPO non deve piu puntare a colonne applicative rimosse.`),
|
|
1146
1146
|
note("info", `Campi estesi`, `extensionFieldsOptions allega colonne di tabelle applicative al profilo (per esempio la ragione sociale). Le colonne sono in whitelist: non costruirle mai da input HTTP.`)
|
|
1147
1147
|
]
|
|
1148
1148
|
},
|
|
@@ -1907,7 +1907,7 @@ function roleAssignmentEditor(roles, assignedRoles, groups) {
|
|
|
1907
1907
|
const assigned = (assignedRoles ?? []).some((current) => current.codiceRuolo === role.codiceRuolo);
|
|
1908
1908
|
const groupedMenus = groups.map((group) => ({ group, entries: group.menus.map((menu) => ({ menu, assignment: roleMenus.find((item) => item.codiceMenu === menu.codiceMenu) })).filter((entry) => entry.assignment) })).filter((entry) => entry.entries.length > 0);
|
|
1909
1909
|
const missingMenus = roleMenus.filter((item) => !catalogMenus.has(item.codiceMenu));
|
|
1910
|
-
return `<article class="role-assignment-card"><div class="role-assignment-heading"><label class="check"><input type="checkbox" name="role" value="${escapeHtml(role.codiceRuolo)}" ${assigned ? "checked" : ""}><span><strong>${escapeHtml(role.descrizioneRuolo)}</strong><small>Codice ruolo: ${escapeHtml(role.codiceRuolo)}</small></span></label><span class="role-menu-count">${roleMenus.length} menu</span></div><div class="role-permission-groups">${groupedMenus.map(({ group, entries }) => `<section class="role-permission-group"><div class="role-permission-group-heading"><strong>${escapeHtml(group.descrizioneGruppo)}</strong>${groupMetadata(group)}</div>${entries.map(({ menu, assignment }) => `<div class="role-permission-entry ${menu.enabled === false ? "is-disabled" : ""}"><div><strong>${escapeHtml(menu.descrizioneMenu)}</strong>${menuMetadata(menu)}</div><span class="permission-level">${escapeHtml(rolePermissionLevel(assignment?.tipoAbilitazione))}</span></div>`).join("")}</section>`).join("") || '<p class="form-help">Questo ruolo non contiene menu attivi nel catalogo.</p>'}${missingMenus.length ? `<section class="role-permission-group missing-role-menus"><strong>Menu non pi\
|
|
1910
|
+
return `<article class="role-assignment-card"><div class="role-assignment-heading"><label class="check"><input type="checkbox" name="role" value="${escapeHtml(role.codiceRuolo)}" ${assigned ? "checked" : ""}><span><strong>${escapeHtml(role.descrizioneRuolo)}</strong><small>Codice ruolo: ${escapeHtml(role.codiceRuolo)}</small></span></label><span class="role-menu-count">${roleMenus.length} menu</span></div><div class="role-permission-groups">${groupedMenus.map(({ group, entries }) => `<section class="role-permission-group"><div class="role-permission-group-heading"><strong>${escapeHtml(group.descrizioneGruppo)}</strong>${groupMetadata(group)}</div>${entries.map(({ menu, assignment }) => `<div class="role-permission-entry ${menu.enabled === false ? "is-disabled" : ""}"><div><strong>${escapeHtml(menu.descrizioneMenu)}</strong>${menuMetadata(menu)}</div><span class="permission-level">${escapeHtml(rolePermissionLevel(assignment?.tipoAbilitazione))}</span></div>`).join("")}</section>`).join("") || '<p class="form-help">Questo ruolo non contiene menu attivi nel catalogo.</p>'}${missingMenus.length ? `<section class="role-permission-group missing-role-menus"><strong>Menu non pi\xC3\xB9 presenti nel catalogo</strong>${missingMenus.map((menu) => `<div class="role-permission-entry"><div><strong>${escapeHtml(menu.codiceMenu)}</strong><p class="entity-note">Il menu \xC3\xA8 ancora associato al ruolo ma non \xC3\xA8 disponibile nel catalogo corrente.</p></div><span class="permission-level">${escapeHtml(rolePermissionLevel(menu.tipoAbilitazione))}</span></div>`).join("")}</section>` : ""}</div></article>`;
|
|
1911
1911
|
}).join("")}</div><button>Salva ruoli</button></form>`;
|
|
1912
1912
|
}
|
|
1913
1913
|
function roleOverview(role, groups) {
|
|
@@ -1917,7 +1917,7 @@ function roleOverview(role, groups) {
|
|
|
1917
1917
|
const tree = groups.map((group) => ({ group, entries: group.menus.filter((menu) => assignments.has(menu.codiceMenu)) })).filter((node) => node.entries.length > 0);
|
|
1918
1918
|
const orphans = roleMenus.filter((item) => !knownMenus.has(item.codiceMenu));
|
|
1919
1919
|
const groupNodes = tree.map(({ group, entries }) => `<li class="role-tree-group ${group.enabled === false ? "is-disabled" : ""}"><div class="role-tree-group-head"><strong>${escapeHtml(group.descrizioneGruppo)}</strong><span class="role-tree-count">${entries.length}</span></div><ul class="role-tree-menus">${entries.map((menu) => `<li class="role-tree-menu ${menu.enabled === false ? "is-disabled" : ""}"><span class="role-tree-menu-name">${escapeHtml(menu.descrizioneMenu)}</span><span class="permission-level">${escapeHtml(rolePermissionLevel(assignments.get(menu.codiceMenu)?.tipoAbilitazione))}</span></li>`).join("")}</ul></li>`).join("");
|
|
1920
|
-
const orphanNode = orphans.length ? `<li class="role-tree-group is-orphan"><div class="role-tree-group-head"><strong>Menu non pi\
|
|
1920
|
+
const orphanNode = orphans.length ? `<li class="role-tree-group is-orphan"><div class="role-tree-group-head"><strong>Menu non pi\xC3\xB9 nel catalogo</strong><span class="role-tree-count">${orphans.length}</span></div><ul class="role-tree-menus">${orphans.map((item) => `<li class="role-tree-menu"><span class="role-tree-menu-name"><code>${escapeHtml(item.codiceMenu)}</code></span><span class="permission-level">${escapeHtml(rolePermissionLevel(item.tipoAbilitazione))}</span></li>`).join("")}</ul></li>` : "";
|
|
1921
1921
|
return `<article class="role-card">
|
|
1922
1922
|
<div class="role-card-head">
|
|
1923
1923
|
<div class="role-card-title">
|
|
@@ -2044,11 +2044,11 @@ function federatedIdentityFields(providers) {
|
|
|
2044
2044
|
<label>Nota ${helpDot("sso-note")}<input name="note"><span class="form-help">Nota interna, non inviata al provider.</span></label>`;
|
|
2045
2045
|
}
|
|
2046
2046
|
function federatedIdentitySection(identities, providers) {
|
|
2047
|
-
return `<section class="user-editor-section sso-identity-section" data-user-panel="sso" role="tabpanel" aria-labelledby="user-tab-sso"><div class="section-heading"><div><p class="eyebrow">Autenticazione esterna</p><h3>Identit\
|
|
2047
|
+
return `<section class="user-editor-section sso-identity-section" data-user-panel="sso" role="tabpanel" aria-labelledby="user-tab-sso"><div class="section-heading"><div><p class="eyebrow">Autenticazione esterna</p><h3>Identit\xC3\xA0 SSO</h3></div><span class="muted">Collegamenti verificati dal backend</span></div><p class="form-help">Disabilita conserva lo storico; elimina rimuove il collegamento (l'utente resta).</p><div class="sso-identity-list">${identities.map((identity) => `<article class="sso-identity-item ${identity.active ? "" : "is-disabled"}"><div class="sso-identity-data"><strong>${escapeHtml(identity.provider)}</strong><dl class="entity-metadata"><div><dt>Subject</dt><dd>${escapeHtml(identity.subject)}</dd></div><div><dt>Stato</dt><dd>${identity.active ? "Abilitata" : "Disabilitata"}</dd></div></dl>${identity.note ? `<p class="entity-note"><strong>Nota</strong>${escapeHtml(identity.note)}</p>` : ""}</div><div class="sso-identity-actions"><button type="button" class="secondary" data-identity-toggle="${escapeHtml(identity.identityKey)}" data-active="${String(!identity.active)}">${identity.active ? "Disabilita" : "Abilita"}</button><button type="button" class="icon-button danger-button" data-identity-delete="${escapeHtml(identity.identityKey)}" aria-label="Elimina definitivamente il collegamento SSO ${escapeHtml(identity.provider)}" title="Elimina definitivamente il collegamento SSO"><span aria-hidden="true">🗑</span></button></div></article>`).join("") || '<p class="muted">Nessun collegamento SSO.</p>'}</div>${providers.some((provider) => provider.active) ? `<form id="link-sso" class="sso-link-form">${federatedIdentityFields(providers)}<button>Collega SSO verificato</button></form>` : '<p class="form-help">Non ci sono provider SSO attivi. Censiscine uno nella sezione SSO prima di creare collegamenti.</p>'}</section>`;
|
|
2048
2048
|
}
|
|
2049
2049
|
function userDetailTabs(hasSso) {
|
|
2050
2050
|
const tabs = [
|
|
2051
|
-
...hasSso ? [{ id: "sso", label: "Identit\
|
|
2051
|
+
...hasSso ? [{ id: "sso", label: "Identit\xC3\xA0 SSO" }] : [],
|
|
2052
2052
|
{ id: "profile", label: "Profilo e accesso" },
|
|
2053
2053
|
{ id: "roles", label: "Ruoli" },
|
|
2054
2054
|
{ id: "grants", label: "Grant diretti" }
|
|
@@ -2105,7 +2105,7 @@ function pageNumbers(current, total) {
|
|
|
2105
2105
|
return result2;
|
|
2106
2106
|
}
|
|
2107
2107
|
function pagerMarkup(totalPages) {
|
|
2108
|
-
const context = `<span class="pager-context">${usersTotal} utent${usersTotal === 1 ? "e" : "i"}${totalPages > 1 ? ` \xB7 pagina ${usersPage + 1} di ${totalPages}` : ""}</span>`;
|
|
2108
|
+
const context = `<span class="pager-context">${usersTotal} utent${usersTotal === 1 ? "e" : "i"}${totalPages > 1 ? ` \xC2\xB7 pagina ${usersPage + 1} di ${totalPages}` : ""}</span>`;
|
|
2109
2109
|
if (totalPages <= 1) {
|
|
2110
2110
|
return `<nav class="pager" aria-label="Paginazione utenti">${context}</nav>`;
|
|
2111
2111
|
}
|
|
@@ -2280,35 +2280,20 @@ async function showUsers() {
|
|
|
2280
2280
|
function authenticationPolicyFields(user) {
|
|
2281
2281
|
return `<fieldset><legend>Verifica dell'accesso (opzionale)</legend>
|
|
2282
2282
|
<label class="check"><input name="flagDueFattori" type="checkbox" ${user.flagDueFattori ? "checked" : ""}> Richiedi un codice via email (2FA) ${helpDot("user-2fa")}</label>
|
|
2283
|
-
<p class="form-help">Se attiva, il codice \
|
|
2283
|
+
<p class="form-help">Se attiva, il codice \xC3\xA8 richiesto dopo password o SSO.</p>
|
|
2284
2284
|
<label class="check"><input name="passwordlessLoginEnabled" type="checkbox" ${user.passwordlessLoginEnabled ? "checked" : ""} ${user.flagDueFattori ? "" : "disabled"}> Consenti accesso con il solo codice email ${helpDot("user-passwordless")}</label>
|
|
2285
2285
|
<p class="form-help">Accesso senza password (richiede il codice email).</p>
|
|
2286
2286
|
</fieldset>`;
|
|
2287
2287
|
}
|
|
2288
|
-
var APPLICATION_FLAGS = [
|
|
2289
|
-
["flagMop", "MOP"],
|
|
2290
|
-
["flagPiana", "Piana"],
|
|
2291
|
-
["flagAddetti", "Addetti"],
|
|
2292
|
-
["flagOspiti", "Ospiti"],
|
|
2293
|
-
["flagPianaRfid", "Piana RFID"],
|
|
2294
|
-
["flagConta", "Contabilit\xE0"],
|
|
2295
|
-
["flagCubi", "Cubi"],
|
|
2296
|
-
["flagCicliPass", "Cicli passivi"],
|
|
2297
|
-
["flagDipendenti", "Gestione dipendenti"],
|
|
2298
|
-
["flagInventari", "Gestione inventari"]
|
|
2299
|
-
];
|
|
2300
2288
|
function applicationFlagFields(user) {
|
|
2301
2289
|
const record = user;
|
|
2302
|
-
const checks = APPLICATION_FLAGS.map(([key, label]) => `<label class="check"><input name="${key}" type="checkbox" ${record[key] ? "checked" : ""}> ${label}</label>`).join("");
|
|
2303
2290
|
return `<fieldset><legend>Abilitazioni applicative</legend>
|
|
2304
|
-
${checks}
|
|
2305
|
-
<label>Codice causale <input name="caumov" value="${escapeHtml(String(record.caumov ?? ""))}"></label>
|
|
2306
2291
|
<label class="check"><input name="enableIa" type="checkbox" ${record.enableIa ? "checked" : ""}> Assistente IA (ENABLEIA)</label>
|
|
2307
2292
|
</fieldset>`;
|
|
2308
2293
|
}
|
|
2309
2294
|
function showLocalUserForm() {
|
|
2310
2295
|
render(`<button id="back">Indietro</button><h2>Nuovo utente locale</h2><p class="muted">Viene inviata l'e-mail per impostare la password.</p>
|
|
2311
|
-
<form id="local-user"><label>Email ${helpDot("user-email")}<input name="email" type="email" required><span class="form-help">Identificativo di accesso; ricever\
|
|
2296
|
+
<form id="local-user"><label>Email ${helpDot("user-email")}<input name="email" type="email" required><span class="form-help">Identificativo di accesso; ricever\xC3\xA0 l'email per la password.</span></label><label>Nome ${helpDot("user-name")}<input name="nome"></label><label>Cognome ${helpDot("user-name")}<input name="cognome"></label><button>Crea utente</button></form>`);
|
|
2312
2297
|
byId("back").onclick = () => show("users");
|
|
2313
2298
|
const localUserForm = document.getElementById("local-user");
|
|
2314
2299
|
if (localUserForm) localUserForm.onsubmit = (event) => {
|
|
@@ -2325,7 +2310,7 @@ async function showSsoUserForm() {
|
|
|
2325
2310
|
if (!providers.some((provider) => provider.active)) {
|
|
2326
2311
|
throw new Error("Prima di creare un utente SSO, censisci e abilita almeno un provider SSO.");
|
|
2327
2312
|
}
|
|
2328
|
-
render(`<button id="back">Indietro</button><h2>Nuovo utente SSO</h2><p class="muted">Salva solo collegamenti gi\
|
|
2313
|
+
render(`<button id="back">Indietro</button><h2>Nuovo utente SSO</h2><p class="muted">Salva solo collegamenti gi\xC3\xA0 verificati dal backend.</p>
|
|
2329
2314
|
<form id="sso-user"><label>Email ${helpDot("user-email")}<input name="email" type="email" required><span class="form-help">Email di contatto e identificativo Accessi dell'utente.</span></label><label>Nome ${helpDot("user-name")}<input name="nome"></label><label>Cognome ${helpDot("user-name")}<input name="cognome"></label>${federatedIdentityFields(providers)}<label class="check"><input name="passwordLoginEnabled" type="checkbox"> Abilita anche la password locale ${helpDot("user-password-login")}</label><span class="form-help">Se disattivato, l'utente accede solo via SSO.</span><button>Crea utente SSO</button></form>`);
|
|
2330
2315
|
byId("back").onclick = () => show("ssoUsers");
|
|
2331
2316
|
const ssoUserForm = document.getElementById("sso-user");
|
|
@@ -2348,10 +2333,10 @@ async function showSsoUserForm() {
|
|
|
2348
2333
|
};
|
|
2349
2334
|
}
|
|
2350
2335
|
async function showSsoProviders() {
|
|
2351
|
-
if (!federatedAuthenticationAvailable) throw new Error("SSO non \
|
|
2336
|
+
if (!federatedAuthenticationAvailable) throw new Error("SSO non \xC3\xA8 abilitato in questa istanza Accessi.");
|
|
2352
2337
|
const providerList = result(await getFederatedProviders());
|
|
2353
2338
|
render(`<div class="toolbar"><button id="new-provider">Nuovo provider</button><button id="reload-providers" class="secondary">Aggiorna</button></div>
|
|
2354
|
-
<h2>Provider SSO</h2><p class="muted">La validazione di token, issuer e segreti resta nel backend. Un provider si elimina solo se nessuna identit\
|
|
2339
|
+
<h2>Provider SSO</h2><p class="muted">La validazione di token, issuer e segreti resta nel backend. Un provider si elimina solo se nessuna identit\xC3\xA0 \xC3\xA8 collegata.</p>
|
|
2355
2340
|
<div class="menu-table-wrap"><table><thead><tr><th>Provider</th><th>Descrizione</th><th>Stato</th><th></th></tr></thead><tbody>${providerList.map((provider) => `<tr class="${provider.active ? "" : "is-disabled"}"><td><code>${escapeHtml(provider.provider)}</code></td><td>${escapeHtml(provider.description)}</td><td>${provider.active ? "Attivo" : "Disabilitato"}</td><td class="row-actions"><button data-provider="${escapeHtml(provider.provider)}">Gestisci</button></td></tr>`).join("") || '<tr><td colspan="4" class="muted">Nessun provider censito.</td></tr>'}</tbody></table></div>`);
|
|
2356
2341
|
byId("new-provider").onclick = () => showProviderForm();
|
|
2357
2342
|
byId("reload-providers").onclick = () => handleAction(showSsoProviders);
|
|
@@ -2360,11 +2345,11 @@ async function showSsoProviders() {
|
|
|
2360
2345
|
});
|
|
2361
2346
|
}
|
|
2362
2347
|
async function showSsoUsers() {
|
|
2363
|
-
if (!federatedAuthenticationAvailable) throw new Error("SSO non \
|
|
2348
|
+
if (!federatedAuthenticationAvailable) throw new Error("SSO non \xC3\xA8 abilitato in questa istanza Accessi.");
|
|
2364
2349
|
const users = await loadUsers();
|
|
2365
2350
|
render(`<div class="toolbar"><button id="new-sso">Nuovo utente SSO</button><button id="reload-sso-users" class="secondary">Aggiorna</button></div>
|
|
2366
|
-
<h2>Utenti e identit\
|
|
2367
|
-
<div class="menu-table-wrap"><table><thead><tr><th>Utente</th><th>Accesso</th><th></th></tr></thead><tbody>${users.map(({ utente }) => `<tr><td>${escapeHtml(utente.email)}</td><td>${utente.passwordLoginEnabled === false ? "solo SSO" : "password e SSO"}</td><td class="row-actions"><button data-sso-user="${utente.codiceUtente}">Gestisci identit\
|
|
2351
|
+
<h2>Utenti e identit\xC3\xA0 SSO</h2><p class="muted">Gestisci i collegamenti provider/subject gi\xC3\xA0 verificati dal backend.</p>
|
|
2352
|
+
<div class="menu-table-wrap"><table><thead><tr><th>Utente</th><th>Accesso</th><th></th></tr></thead><tbody>${users.map(({ utente }) => `<tr><td>${escapeHtml(utente.email)}</td><td>${utente.passwordLoginEnabled === false ? "solo SSO" : "password e SSO"}</td><td class="row-actions"><button data-sso-user="${utente.codiceUtente}">Gestisci identit\xC3\xA0</button></td></tr>`).join("") || '<tr><td colspan="3" class="muted">Nessun utente.</td></tr>'}</tbody></table></div>`);
|
|
2368
2353
|
byId("new-sso").onclick = () => handleAction(showSsoUserForm);
|
|
2369
2354
|
byId("reload-sso-users").onclick = () => handleAction(showSsoUsers);
|
|
2370
2355
|
document.querySelectorAll("[data-sso-user]").forEach((button) => {
|
|
@@ -2443,7 +2428,7 @@ async function showUser(rawCode) {
|
|
|
2443
2428
|
const defaultUserTab = federatedAuthenticationAvailable ? "sso" : "profile";
|
|
2444
2429
|
render(`<div class="user-action-bar"><button id="back" type="button" class="secondary">Indietro</button><label class="inline-field">Stato registrazione ${helpDot("user-state")}<select id="user-state">${registrationStateOptions(user.statoRegistrazione)}</select></label><button id="save-state" type="button" class="secondary">Aggiorna stato</button><button id="disable-user" type="button" class="danger-button">Imposta stato eliminato</button>${helpDot("user-delete")}</div><div class="page-header"><div><p class="eyebrow">Utente ${codiceUtente}</p><h2>${escapeHtml(user.email)}</h2></div><span class="muted">Gestione profilo, ruoli e autorizzazioni</span></div>${userDetailTabs(federatedAuthenticationAvailable)}<div class="user-editor">
|
|
2445
2430
|
${identitySection}
|
|
2446
|
-
<form id="profile" data-user-panel="profile" role="tabpanel" aria-labelledby="user-tab-profile"><h3>Profilo e accesso</h3><label>Nome ${helpDot("user-name")}<input name="nome" value="${escapeHtml(user.nome)}"></label><label>Cognome ${helpDot("user-name")}<input name="cognome" value="${escapeHtml(user.cognome)}"></label><label>Email ${helpDot("user-email")}<input name="email" type="email" value="${escapeHtml(user.email)}" required><span class="form-help">Identificativo di accesso e recapito.</span></label>${federatedAuthenticationAvailable ? `<label class="check"><input name="passwordLoginEnabled" type="checkbox" ${user.passwordLoginEnabled !== false ? "checked" : ""}> Login con password ${helpDot("user-password-login")}</label><span class="form-help">Se disabilitato, il login con email e password restituisce un errore esplicito; restano valide le identit\
|
|
2431
|
+
<form id="profile" data-user-panel="profile" role="tabpanel" aria-labelledby="user-tab-profile"><h3>Profilo e accesso</h3><label>Nome ${helpDot("user-name")}<input name="nome" value="${escapeHtml(user.nome)}"></label><label>Cognome ${helpDot("user-name")}<input name="cognome" value="${escapeHtml(user.cognome)}"></label><label>Email ${helpDot("user-email")}<input name="email" type="email" value="${escapeHtml(user.email)}" required><span class="form-help">Identificativo di accesso e recapito.</span></label>${federatedAuthenticationAvailable ? `<label class="check"><input name="passwordLoginEnabled" type="checkbox" ${user.passwordLoginEnabled !== false ? "checked" : ""}> Login con password ${helpDot("user-password-login")}</label><span class="form-help">Se disabilitato, il login con email e password restituisce un errore esplicito; restano valide le identit\xC3\xA0 SSO attive.</span>` : ""}${authenticationPolicyFields(user)}${applicationFlagFields(user)}<button>Salva</button></form>
|
|
2447
2432
|
${roleAssignmentEditor(allRoles, userGrants.ruoli, menuGroups)}
|
|
2448
2433
|
${directGrantEditor(menuGroups, userGrants.abilitazioni)}
|
|
2449
2434
|
</div>`);
|
|
@@ -2475,9 +2460,6 @@ async function showUser(rawCode) {
|
|
|
2475
2460
|
handleAction(async () => {
|
|
2476
2461
|
const values = formValues(eventForm(event));
|
|
2477
2462
|
const fields = new FormData(eventForm(event));
|
|
2478
|
-
const applicationFlags = Object.fromEntries(
|
|
2479
|
-
APPLICATION_FLAGS.map(([key]) => [key, fields.has(key)])
|
|
2480
|
-
);
|
|
2481
2463
|
await updateUtente(codiceUtente, {
|
|
2482
2464
|
codiceUtente,
|
|
2483
2465
|
email: values.email ?? "",
|
|
@@ -2485,9 +2467,7 @@ async function showUser(rawCode) {
|
|
|
2485
2467
|
cognome: values.cognome || void 0,
|
|
2486
2468
|
flagDueFattori: fields.has("flagDueFattori"),
|
|
2487
2469
|
passwordlessLoginEnabled: fields.has("passwordlessLoginEnabled"),
|
|
2488
|
-
caumov: values.caumov || void 0,
|
|
2489
2470
|
enableIa: fields.has("enableIa"),
|
|
2490
|
-
...applicationFlags,
|
|
2491
2471
|
...federatedAuthenticationAvailable ? { passwordLoginEnabled: fields.has("passwordLoginEnabled") } : {}
|
|
2492
2472
|
});
|
|
2493
2473
|
if (codiceUtente === currentUser?.codiceUtente && (fields.has("flagDueFattori") !== Boolean(user.flagDueFattori) || fields.has("passwordlessLoginEnabled") !== Boolean(user.passwordlessLoginEnabled))) {
|
|
@@ -2543,7 +2523,7 @@ async function showUser(rawCode) {
|
|
|
2543
2523
|
});
|
|
2544
2524
|
document.querySelectorAll("[data-identity-delete]").forEach((button) => {
|
|
2545
2525
|
button.onclick = () => handleAction(async () => {
|
|
2546
|
-
if (!window.confirm("Eliminare definitivamente questo collegamento SSO? L\
|
|
2526
|
+
if (!window.confirm("Eliminare definitivamente questo collegamento SSO? L\xE2\u20AC\u2122utente Accessi non verr\xC3\xA0 eliminato.")) return;
|
|
2547
2527
|
await deleteFederatedIdentityPermanently(codiceUtente, button.dataset.identityDelete ?? "");
|
|
2548
2528
|
showNotice("Collegamento SSO eliminato definitivamente.");
|
|
2549
2529
|
await showUser(String(codiceUtente));
|
|
@@ -2679,7 +2659,7 @@ async function showMenuItems() {
|
|
|
2679
2659
|
async function showMenuTypes() {
|
|
2680
2660
|
const menuTypes = result(await getMenuTypes());
|
|
2681
2661
|
render(`<div class="toolbar"><button id="new-menu-type">Nuovo tipo menu</button><button id="reload-menu-types" class="secondary">Aggiorna</button></div>
|
|
2682
|
-
<h2>Tipi menu</h2><p class="form-help">Classificano i menu (es. amministrazione, operativit\
|
|
2662
|
+
<h2>Tipi menu</h2><p class="form-help">Classificano i menu (es. amministrazione, operativit\xC3\xA0). Un tipo si elimina solo se non \xC3\xA8 usato da alcun menu.</p>
|
|
2683
2663
|
${menuTypeTable(menuTypes)}`);
|
|
2684
2664
|
byId("new-menu-type").onclick = () => showMenuTypeForm();
|
|
2685
2665
|
byId("reload-menu-types").onclick = () => handleAction(showMenuTypes);
|
|
@@ -2897,7 +2877,7 @@ async function showServiceTokens(includeRevoked = false) {
|
|
|
2897
2877
|
});
|
|
2898
2878
|
}
|
|
2899
2879
|
function showServiceTokenForm() {
|
|
2900
|
-
render(`<button id="back" type="button" class="secondary">Indietro</button><h2>Nuovo token di servizio</h2><form id="token-form"><label>Descrizione ${helpDot("token-label")}<input name="label" required maxlength="100"><span class="form-help">Identifica l'integrazione, ad esempio "IA - produzione".</span></label><label>Scope ${helpDot("token-scopes")}<input name="scopes" placeholder="ia, chat"><span class="form-help">Separati da virgola (lettere, numeri, ':', '_', '-'). Definiscono cosa pu\
|
|
2880
|
+
render(`<button id="back" type="button" class="secondary">Indietro</button><h2>Nuovo token di servizio</h2><form id="token-form"><label>Descrizione ${helpDot("token-label")}<input name="label" required maxlength="100"><span class="form-help">Identifica l'integrazione, ad esempio "IA - produzione".</span></label><label>Scope ${helpDot("token-scopes")}<input name="scopes" placeholder="ia, chat"><span class="form-help">Separati da virgola (lettere, numeri, ':', '_', '-'). Definiscono cosa pu\xC3\xB2 fare il token.</span></label><label>Durata in giorni ${helpDot("token-ttl")}<input name="ttlDays" type="number" min="1" step="1"><span class="form-help">Opzionale. Lascia vuoto per un token senza scadenza.</span></label><button>Crea token</button></form>`);
|
|
2901
2881
|
byId("back").onclick = () => void show("tokens");
|
|
2902
2882
|
const form = document.getElementById("token-form");
|
|
2903
2883
|
if (form) form.onsubmit = (event) => {
|