Files
Fuchs_Intranet/Fuchs/wwwroot/web/fis.admin.de.js
T
Stefan c812d94d99 Improve audit logging, error handling, and metadata encoding
- Ensure all email/SMS send attempts are audit-logged, including API errors, exceptions, invalid addresses, and disabled service cases; logs now include raw API responses or exception details for better diagnostics.
- Fix audit log parameter builder to never pass NULL for NOT NULL columns (`config`, `DateSent`).
- Add unit tests covering all send paths and audit log correctness.
- Percent-encode non-ASCII/control chars in `DocumentMetadataBuilder` for safe HTTP header metadata; add tests.
- Simplify admin test mail dialog JS and improve success handler robustness.
- Set `charset=utf-8` in admin controller JSON responses for OCORE consistency.
- Update minified JS to match new admin dialog logic.
2026-07-16 16:03:58 +02:00

331 lines
13 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
let $adt = {
mdl: 'Administration'
, sub_info: 'System'
, sub_status: 'Status & Konnektivität'
, sub_tests: 'Tests'
// startup checks widget (non-refreshable)
, startup: 'Startup-Prüfungen'
, startup_notrun: 'Die Startup-Prüfungen sind deaktiviert oder wurden noch nicht ausgeführt (Fuchs:StartupChecks:Enabled).'
, startup_on: 'Host'
, startup_at: 'Ausgeführt (UTC)'
, chk_ok: 'OK'
, chk_fail: 'Fehler'
, chk_skipped: 'übersprungen'
, chk_KeyVault: 'Azure Key Vault'
, chk_Database: 'SQL-Datenbank'
, chk_MFR: 'MFR (ERP)'
, chk_PdfLicense: 'Spire.PDF-Lizenz'
, chk_Mailer: 'E-Mail (Startup-Probe)'
// system info
, host: 'Host / Server'
, machine: 'Hostname'
, os: 'Betriebssystem'
, framework: 'Framework'
, env: 'Umgebung'
, testdep: 'Test-Deployment'
, pid: 'Prozess-ID'
, uptime: 'Laufzeit'
, since: 'Start (UTC)'
, hours: 'Std.'
// status cards
, db: 'SQL-Datenbank'
, mail: 'E-Mail-Dienst'
, blob: 'Azure Blob Storage'
, mfr: 'MFR (ERP)'
, kv: 'Azure Key Vault'
// labels
, server: 'Server'
, catalog: 'Datenbank'
, login: 'Login'
, mailer: 'Mailer aktiv'
, baseurl: 'Base-URL'
, account: 'Account'
, serverid: 'Server-ID'
, token: 'Token hinterlegt'
, override: 'OverrideRecipient'
, overrideActive: 'Umleitung aktiv'
, enabled: 'Aktiviert'
, configured: 'Konfiguriert'
, invContainer: 'Rechnungs-Container'
, remContainer: 'Mahnungs-Container'
, host_l: 'Host'
, creds: 'Zugangsdaten hinterlegt'
, sync: 'Sync aktiv'
, vault: 'Vault-URI'
, appname: 'App-Präfix'
, seccount: 'Verwaltete Secrets'
, clientreg: 'Client registriert'
, duration: 'Dauer'
, checked: 'Geprüft'
, detail: 'Detail'
// status values
, st_ok: 'OK'
, st_error: 'Fehler'
, st_disabled: 'Deaktiviert'
, st_unconfigured: 'Nicht konfiguriert'
, st_checking: 'Prüfe…'
// actions
, refresh: 'Aktualisieren'
, refreshAll: 'Alle prüfen'
, yes: 'Ja'
, no: 'Nein'
// test email
, testmail: 'Test-E-Mail'
, testmail_btn: 'Test-E-Mail senden'
, tm_to: 'Empfänger'
, tm_subject: 'Betreff'
, tm_body: 'Nachricht'
, tm_hint: 'Der Versand nutzt die normale E-Mail-Pipeline; bei gesetztem OverrideRecipient wird die Nachricht dorthin umgeleitet.'
, tm_sent: 'Test-E-Mail übergeben.'
, tm_failed: 'Test-E-Mail konnte nicht gesendet werden.'
, tm_default_subject: 'Fuchs Intranet Test-E-Mail'
, tm_default_body: 'Dies ist eine Test-E-Mail aus dem Administrationsbereich des Fuchs Intranet.'
, loadfail: 'Der Systemstatus konnte nicht geladen werden.'
};
let $adm = {
init2: function () {
// No external libraries needed — go straight to render.
$ocms.getScript([], function () { $adm.init3(); });
},
init3: function () {
$fis.cf(true);
$fis.lf(true);
$('#activemodule').text($adt.mdl);
$adm.topbar();
let frm = $$.dc('admfrm', $('#contentframe')).ldng(1);
$adm.load(frm);
},
topbar: function () {
return $('#topbar').ocmsmenu([
{ lbl: $adt.refreshAll, id: 'adm_refresh_all', ico: 'glyphicon glyphicon-refresh', fnc: function () { $adm.init3(); } }
]);
},
load: function (frm) {
$ocms.postXT({
url: $ocms.url('admin/status'), success: function (r) {
frm.empty();
$adm.render(frm, r.info || {}, r.probes || []);
}, error: function () {
frm.empty();
$$.dc('adm_err', frm).text($adt.loadfail);
}, complete: function () { frm.ldng(0); }
});
},
render: function (frm, info, probes) {
let pmap = {};
$.each(probes, function (i, p) { pmap[p.component] = p; });
$$.dc('adm_sec', frm).text($adt.sub_info);
$adm.sysCard(frm, info);
$adm.startupCard(frm, info.startupChecks);
$$.dc('adm_sec', frm).text($adt.sub_status);
let grid = $$.dc('adm_grid', frm);
$adm.dbCard(grid, info.database || {}, pmap.database);
$adm.mailCard(grid, info.email || {});
$adm.blobCard(grid, info.blob || {}, pmap.blob);
$adm.mfrCard(grid, info.mfr || {}, pmap.mfr);
$adm.kvCard(grid, info.keyVault || {}, pmap.keyvault);
},
/* ── generic building blocks ─────────────────────────────────────────── */
kvTable: function (parent, rows) {
let t = $$.tbl().addClass('adm_kv');
$.each(rows || [], function (i, r) {
if (!r) { return true; }
let tr = $$.tr(t);
$$.td(tr).addClass('k').text(r[0] == null ? '' : String(r[0]));
let v = $$.td(tr).addClass('v');
if (r[1] instanceof jQuery) { v.append(r[1]); } else { v.text(r[1] == null ? '' : String(r[1])); }
});
if (parent instanceof jQuery) { parent.append(t); }
return t;
},
yesNo: function (b) {
return $$.sc('adm_bool adm_bool_' + (b ? 'y' : 'n'), b ? $adt.yes : $adt.no);
},
setPill: function (pill, probe) {
probe = probe || {};
let st = probe.status || 'unconfigured';
let lbl = {
ok: $adt.st_ok, error: $adt.st_error, disabled: $adt.st_disabled,
unconfigured: $adt.st_unconfigured, checking: $adt.st_checking
}[st] || st;
pill.attr('class', 'adm_pill adm_pill_' + st).text(lbl);
return pill;
},
/* Connectivity card with a live status pill + per-card refresh button. */
probeCard: function (grid, title, component, cfgRows, probe) {
let card = $$.dc('adm_card', grid);
let hd = $$.dc('adm_card_hd', card);
$$.s(title).appendTo(hd);
let pill = $$.sc('adm_pill').appendTo(hd);
let rbtn = $$.bbtn($adt.refresh, 'adm_btn').appendTo(hd);
let bd = $$.dc('adm_card_bd', card);
$adm.kvTable(bd, cfgRows);
let pf = $$.dc('adm_probe', bd);
let msg = $$.dc('adm_probe_msg', pf);
let met = $$.dc('adm_probe_metrics', pf);
let det = $$.dc('adm_probe_det', pf);
let dur = $$.dc('adm_probe_dur', pf);
let apply = function (p) {
p = p || {};
$adm.setPill(pill, p);
msg.text(p.message || '');
met.empty();
$.each(p.metrics || [], function (i, m) {
let row = $$.dc('adm_metric', met);
$$.sc('adm_metric_k').text(m.label || '').appendTo(row);
$$.sc('adm_metric_v').text(m.value == null ? '' : String(m.value)).appendTo(row);
});
det.text(p.detail || '');
dur.text(p.durationMs != null ? (p.durationMs + ' ms') : '');
};
apply(probe);
rbtn.click(function () {
$adm.setPill(pill, { status: 'checking' });
msg.text(''); met.empty(); det.text(''); dur.text('');
$ocms.postXT({
url: $ocms.url('admin/probe/' + component), success: function (r) {
apply(r.probe);
}, error: function () {
$adm.setPill(pill, { status: 'error' });
msg.text($adt.st_error);
}
});
});
return card;
},
/* ── individual cards ────────────────────────────────────────────────── */
sysCard: function (frm, info) {
let card = $$.dc('adm_card adm_card_wide', frm);
let hd = $$.dc('adm_card_hd', card);
$$.s($adt.host).appendTo(hd);
let env = $$.sc('adm_env').text(info.environment || '');
if (info.isTestDeployment === true) { env.aC('adm_env_test'); }
env.appendTo(hd);
let bd = $$.dc('adm_card_bd', card);
$adm.kvTable(bd, [
[$adt.machine, info.machineName],
[$adt.os, info.osDescription],
[$adt.framework, info.frameworkDescription],
[$adt.env, info.environment],
[$adt.testdep, $adm.yesNo(info.isTestDeployment === true)],
[$adt.pid, info.processId],
[$adt.since, info.processStartUtc ? fdt(info.processStartUtc) : ''],
[$adt.uptime, (info.uptimeHours != null ? (info.uptimeHours + ' ' + $adt.hours) : '')]
]);
},
/* Non-refreshable widget: the one-shot startup self-test result captured at boot. */
startupCard: function (frm, sc) {
let card = $$.dc('adm_card adm_card_wide', frm);
let hd = $$.dc('adm_card_hd', card);
$$.s($adt.startup).appendTo(hd);
let bd = $$.dc('adm_card_bd', card);
if (!sc || sc.ran !== true) {
$adm.setPill($$.sc('adm_pill').appendTo(hd), { status: 'disabled' });
$$.dc('adm_note', bd).text($adt.startup_notrun);
return;
}
let items = sc.items || [];
let anyFail = false;
$.each(items, function (i, it) { if (it.enabled === true && it.ok !== true) { anyFail = true; } });
$adm.setPill($$.sc('adm_pill').appendTo(hd), { status: anyFail ? 'error' : 'ok' });
$adm.kvTable(bd, [
[$adt.startup_on, sc.machineName],
[$adt.startup_at, sc.completedUtc ? fdt(sc.completedUtc) : '']
]);
let list = $$.dc('adm_checks', bd);
$.each(items, function (i, it) {
let row = $$.dc('adm_check', list);
$$.sc('adm_check_k').text($adt['chk_' + it.name] || it.name).appendTo(row);
let stt = it.enabled !== true ? 'skipped' : (it.ok === true ? 'ok' : 'fail');
let lbl = { ok: $adt.chk_ok, fail: $adt.chk_fail, skipped: $adt.chk_skipped }[stt];
$$.sc('adm_check_v adm_check_' + stt).text(lbl).appendTo(row);
});
},
dbCard: function (grid, d, probe) {
$adm.probeCard(grid, $adt.db, 'database', [
[$adt.configured, $adm.yesNo(d.configured === true)],
[$adt.server, d.server],
[$adt.catalog, d.catalog],
[$adt.login, d.userId]
], probe);
},
mailCard: function (grid, e) {
let card = $$.dc('adm_card', grid);
let hd = $$.dc('adm_card_hd', card);
$$.s($adt.mail).appendTo(hd);
$adm.setPill($$.sc('adm_pill').appendTo(hd), { status: e.mailerEnabled === true ? 'ok' : 'disabled' });
let bd = $$.dc('adm_card_bd', card);
let rows = [
[$adt.mailer, $adm.yesNo(e.mailerEnabled === true)],
[$adt.baseurl, e.baseUrl],
[$adt.account, e.accountId],
[$adt.serverid, e.serverId],
[$adt.token, $adm.yesNo(e.tokenConfigured === true)],
[$adt.overrideActive, $adm.yesNo(e.overrideActive === true)]
];
if (e.overrideActive === true) { rows.push([$adt.override, e.overrideRecipient]); }
$adm.kvTable(bd, rows);
let ft = $$.dc('adm_card_ft', card);
$$.bbtn($adt.testmail_btn, 'adm_btn adm_btn_primary').appendTo(ft).click($adm.testMailDlg);
},
blobCard: function (grid, b, probe) {
$adm.probeCard(grid, $adt.blob, 'blob', [
[$adt.enabled, $adm.yesNo(b.enabled === true)],
[$adt.configured, $adm.yesNo(b.configured === true)],
[$adt.invContainer, b.invoiceContainer],
[$adt.remContainer, b.reminderContainer]
], probe);
},
mfrCard: function (grid, m, probe) {
$adm.probeCard(grid, $adt.mfr, 'mfr', [
[$adt.host_l, m.host],
[$adt.creds, $adm.yesNo(m.credentialsConfigured === true)],
[$adt.sync, $adm.yesNo(m.syncEnabled === true)]
], probe);
},
kvCard: function (grid, k, probe) {
$adm.probeCard(grid, $adt.kv, 'keyvault', [
[$adt.vault, k.vaultUri],
[$adt.appname, k.appName],
[$adt.seccount, k.managedSecretCount],
[$adt.clientreg, $adm.yesNo(k.clientRegistered === true)]
], probe);
},
/* ── test email ──────────────────────────────────────────────────────── */
testMailDlg: function () {
$ocms.dlgform([
{ name: 'to', label: $adt.tm_to, type: 'email', required: true, value: ($ocms.auth.email || '') },
{ name: 'subject', label: $adt.tm_subject, type: 'string', required: true, value: $adt.tm_default_subject },
{ name: 'body', label: $adt.tm_body, type: 'text', required: true, value: $adt.tm_default_body }
], {
title: $adt.testmail,
button: $adt.testmail_btn,
size: [420, 560],
addcontent: $$.dc('adm_note').text($adt.tm_hint),
url: $ocms.url('admin/testmail'),
typedvalues: true,
/* Runs inside jQuery's success dispatch — it must never throw, or postXT's
`complete` (which clears the page loading indicator) is skipped. */
success: function (r) {
let res = (r && r.result) || {};
alert(res.message || (res.sent === true ? $adt.tm_sent : $adt.tm_failed));
}
});
}
};
let $$adm = { init2: $adm.init2, auth: {} };
export default $$adm;