upd rules and log viewer
This commit is contained in:
parent
d1c51e2d4a
commit
66b740abed
|
|
@ -2,7 +2,11 @@
|
|||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(powershell.exe -ExecutionPolicy Bypass -File scripts/Process-MailRules.ps1)",
|
||||
"Bash(powershell.exe -ExecutionPolicy Bypass -File scripts/Process-MailRules.ps1 -DryRun)"
|
||||
"Bash(powershell.exe -ExecutionPolicy Bypass -File scripts/Process-MailRules.ps1 -DryRun)",
|
||||
"Bash(powershell.exe -Command \"Get-ChildItem ''C:\\\\Users\\\\d-chrka\\\\Documents\\\\projects\\\\mail-organizer\\\\logs\\\\protocols\\\\'' -Filter ''run_*.json'' | Select-Object Name\")",
|
||||
"Bash(powershell.exe -File:*)",
|
||||
"Bash(node -e:*)",
|
||||
"Bash(node:*)"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,8 +52,7 @@
|
|||
"match": {
|
||||
"from": "*@datacenter-group.com",
|
||||
"subject": "Wartungsbericht*",
|
||||
"hasAttachment": true,
|
||||
"unreadOnly": false
|
||||
"hasAttachment": true
|
||||
},
|
||||
|
||||
"actions": {
|
||||
|
|
@ -70,6 +69,23 @@
|
|||
"moveToFolder": "archive"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "feldmann-fi-rechnung-loeschen",
|
||||
"enabled": true,
|
||||
"name": "Feldmann FI-Rechnung Erinnerungen loeschen",
|
||||
"description": "Automatische Erinnerungen von M. Feldmann zu FI Rechnungen in den Papierkorb verschieben",
|
||||
|
||||
"match": {
|
||||
"subject": "M. Feldmann: Bitte denken Sie an FI Rechnung*"
|
||||
},
|
||||
|
||||
"actions": {
|
||||
"onSuccess": {
|
||||
"markAsRead": true,
|
||||
"moveToFolder": "deleteditems"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,167 @@
|
|||
param(
|
||||
[Parameter(Mandatory)][string]$JsonData,
|
||||
[Parameter(Mandatory)][string]$OutputPath
|
||||
)
|
||||
|
||||
# Escape for safe embedding in JS string literal
|
||||
$escaped = $JsonData -replace '\\', '\\\\' -replace "'", "\\\'" -replace "`r`n", '\n' -replace "`n", '\n'
|
||||
|
||||
$html = @'
|
||||
<!DOCTYPE html>
|
||||
<html lang="de"><head><meta charset="UTF-8"><title>Mail-Organizer Protokoll</title>
|
||||
<style>
|
||||
*{box-sizing:border-box;margin:0;padding:0}
|
||||
body{font-family:Segoe UI,system-ui,sans-serif;background:#f5f5f5;color:#333;padding:24px;max-width:1100px;margin:0 auto}
|
||||
h1{font-size:1.3em;margin-bottom:4px}
|
||||
.sub{color:#666;font-size:.85em;margin-bottom:20px}
|
||||
.ctl{display:flex;gap:12px;align-items:center;margin-bottom:16px;flex-wrap:wrap}
|
||||
.ctl label{font-weight:600;font-size:.82em}
|
||||
select{padding:5px 10px;border:1px solid #ccc;border-radius:4px;font-size:.82em;background:#fff}
|
||||
.sbar{display:flex;gap:16px;background:#fff;border:1px solid #ddd;border-radius:6px;padding:14px 18px;margin-bottom:16px;flex-wrap:wrap;align-items:center}
|
||||
.sbar .it{font-size:.85em}.sbar .it strong{font-size:1.1em}
|
||||
.b{display:inline-block;padding:2px 8px;border-radius:10px;font-size:.72em;font-weight:600;color:#fff;vertical-align:middle}
|
||||
.bok{background:#107c10}.ber{background:#d13438}.bwa{background:#ca5010}.bdr{background:#8764b8}.bin{background:#0078d4}
|
||||
.rc{background:#fff;border:1px solid #ddd;border-radius:6px;margin-bottom:8px;overflow:hidden}
|
||||
.rh{padding:11px 16px;cursor:pointer;display:flex;justify-content:space-between;align-items:center;user-select:none}
|
||||
.rh:hover{background:#fafafa}.rh h3{font-size:.9em;font-weight:600}.rh .tg{display:flex;gap:5px}
|
||||
.rb{display:none;border-top:1px solid #eee}.rb.open{display:block}
|
||||
.mr{padding:9px 16px;border-bottom:1px solid #f0f0f0;font-size:.83em}.mr:last-child{border-bottom:none}
|
||||
.ms{font-weight:600}.mm{color:#888;font-size:.92em;margin-top:1px}
|
||||
.ac{margin-top:5px;display:flex;flex-wrap:wrap;gap:5px}
|
||||
.at{display:inline-block;padding:2px 7px;border-radius:3px;font-size:.78em}
|
||||
.at.ok{background:#dff6dd;color:#107c10}.at.error{background:#fde7e9;color:#d13438}
|
||||
.at.dryrun{background:#eee0f5;color:#8764b8}.at.warn{background:#fff4ce;color:#ca5010}
|
||||
.nm{padding:12px 16px;color:#aaa;font-size:.83em;font-style:italic}
|
||||
.em{color:#d13438;font-size:.83em;padding:8px 16px}
|
||||
a.sl{color:#0078d4;text-decoration:none}a.sl:hover{text-decoration:underline}
|
||||
.err-box{background:#fde7e9;color:#d13438;border:1px solid #d13438;border-radius:6px;padding:16px;margin:20px 0;font-size:.9em}
|
||||
</style></head><body>
|
||||
<h1>Mail-Organizer Protokoll</h1>
|
||||
<div class="sub" id="gen"></div>
|
||||
<div class="ctl"><label>Lauf:</label><select id="rs"></select><label>Status:</label>
|
||||
<select id="fl"><option value="all">Alle</option><option value="ok">Nur OK</option><option value="error">Nur Fehler</option><option value="dryrun">Nur DryRun</option></select></div>
|
||||
<div id="o"></div>
|
||||
<script>
|
||||
var DATA;
|
||||
try {
|
||||
DATA = JSON.parse('
|
||||
'@
|
||||
|
||||
$html += $escaped
|
||||
|
||||
$html += @'
|
||||
');
|
||||
} catch(ex) {
|
||||
document.getElementById('o').innerHTML = '<div class="err-box"><strong>Fehler beim Laden der Protokolldaten:</strong><br>' + ex.message + '</div>';
|
||||
}
|
||||
|
||||
if (DATA && DATA.length) {
|
||||
var sel = document.getElementById('rs');
|
||||
var flt = document.getElementById('fl');
|
||||
var out = document.getElementById('o');
|
||||
|
||||
document.getElementById('gen').textContent = 'Generiert: ' + new Date().toLocaleString('de-DE');
|
||||
|
||||
DATA.sort(function(a,b) { return b.timestamp.localeCompare(a.timestamp); });
|
||||
for (var i = 0; i < DATA.length; i++) {
|
||||
var r = DATA[i];
|
||||
var opt = document.createElement('option');
|
||||
opt.value = i;
|
||||
var d = r.dryRun ? ' [DRY RUN]' : '';
|
||||
var e = r.summary.errors > 0 ? ' \u26A0 ' + r.summary.errors + ' Fehler' : '';
|
||||
opt.textContent = r.timestamp + d + ' \u2014 ' + r.summary.processed + ' Mail(s)' + e;
|
||||
sel.appendChild(opt);
|
||||
}
|
||||
|
||||
sel.addEventListener('change', render);
|
||||
flt.addEventListener('change', render);
|
||||
render();
|
||||
}
|
||||
|
||||
function render() {
|
||||
var r = DATA[sel.value];
|
||||
if (!r) return;
|
||||
var f = flt.value;
|
||||
var h = '<div class="sbar">';
|
||||
h += '<div class="it">' + (r.dryRun ? '<span class="b bdr">DRY RUN</span> ' : '') + '<strong>' + esc(r.timestamp) + '</strong></div>';
|
||||
h += '<div class="it">Mailbox: <strong>' + esc(r.mailbox) + '</strong></div>';
|
||||
h += '<div class="it">Verarbeitet: <strong>' + r.summary.processed + '</strong></div>';
|
||||
h += '<div class="it">Alerts: <strong>' + r.summary.alerts + '</strong></div>';
|
||||
h += '<div class="it">' + (r.summary.errors > 0 ? '<span class="b ber">' + r.summary.errors + ' Fehler</span>' : '<span class="b bok">Fehlerfrei</span>') + '</div>';
|
||||
h += '</div>';
|
||||
var rules = r.rules || [];
|
||||
for (var ri = 0; ri < rules.length; ri++) {
|
||||
var rule = rules[ri];
|
||||
var mails = fm(rule.mails || [], f);
|
||||
var total = (rule.mails || []).length;
|
||||
var errs = 0;
|
||||
for (var ei = 0; ei < (rule.mails||[]).length; ei++) { if ((rule.mails||[])[ei].status === 'error') errs++; }
|
||||
var badge = rule.error ? '<span class="b ber">API-Fehler</span>' : errs > 0 ? '<span class="b bwa">' + errs + '/' + total + ' Fehler</span>' : total > 0 ? '<span class="b bok">' + total + ' OK</span>' : '<span class="b bin">0 Mails</span>';
|
||||
h += '<div class="rc"><div class="rh" onclick="tgl(this)"><h3>' + esc(rule.ruleName) + '</h3>';
|
||||
h += '<div class="tg"><span class="b bin">' + total + '</span>' + badge + '</div></div>';
|
||||
h += '<div class="rb' + (total > 0 || rule.error ? ' open' : '') + '">';
|
||||
if (rule.error) h += '<div class="em">' + esc(rule.error) + '</div>';
|
||||
if (mails.length === 0 && !rule.error) h += '<div class="nm">' + (f !== 'all' ? 'Keine Mails mit Filter "' + f + '"' : 'Keine passenden E-Mails') + '</div>';
|
||||
for (var mi = 0; mi < mails.length; mi++) {
|
||||
var m = mails[mi];
|
||||
var dt = m.received ? new Date(m.received).toLocaleString('de-DE') : '';
|
||||
h += '<div class="mr"><div class="ms">' + esc(m.subject) + '</div>';
|
||||
h += '<div class="mm">' + esc(m.from) + ' · ' + dt + '</div>';
|
||||
h += '<div class="ac">' + acHtml(m.actions) + '</div></div>';
|
||||
}
|
||||
h += '</div></div>';
|
||||
}
|
||||
out.innerHTML = h;
|
||||
}
|
||||
|
||||
function fm(mails, f) {
|
||||
if (f === 'all') return mails;
|
||||
var res = [];
|
||||
for (var i = 0; i < mails.length; i++) {
|
||||
var m = mails[i];
|
||||
if (f === 'error' && m.status === 'error') res.push(m);
|
||||
if (f === 'ok' && m.status === 'ok') res.push(m);
|
||||
if (f === 'dryrun') { for (var j=0;j<(m.actions||[]).length;j++) { if(m.actions[j].status==='dryrun'){res.push(m);break;} } }
|
||||
}
|
||||
return f === 'all' ? mails : res;
|
||||
}
|
||||
|
||||
function acHtml(actions) {
|
||||
if (!actions || !actions.length) return '<span style="color:#aaa;font-size:.78em">Keine Aktionen</span>';
|
||||
var parts = [];
|
||||
for (var i = 0; i < actions.length; i++) {
|
||||
var a = actions[i], l = a.action, d = '';
|
||||
if (a.action === 'uploadToSharePoint') {
|
||||
l = 'SharePoint';
|
||||
if (a.files && a.files.length) {
|
||||
var fparts = [];
|
||||
for (var fi = 0; fi < a.files.length; fi++) {
|
||||
var ff = a.files[fi];
|
||||
var name = typeof ff === 'string' ? ff : (ff.name || '');
|
||||
var url = (typeof ff === 'object' && ff !== null) ? ff.url : null;
|
||||
fparts.push(url ? '<a class="sl" href="' + esc(url) + '" target="_blank">' + esc(name) + '</a>' : esc(name));
|
||||
}
|
||||
d = fparts.join(', ');
|
||||
} else if (a.target) d = a.target;
|
||||
} else if (a.action === 'saveAttachments') {
|
||||
l = 'Anhaenge'; d = a.files ? a.files + ' Datei(en)' : '';
|
||||
} else if (a.action === 'onSuccess') {
|
||||
l = 'Erfolg'; d = (a.details || []).join(', ');
|
||||
} else if (a.action === 'alert') {
|
||||
l = 'Alert'; d = a.to || '';
|
||||
}
|
||||
if (a.error) d = a.error;
|
||||
if (a.message) d = a.message;
|
||||
parts.push('<span class="at ' + (a.status || 'ok') + '">' + esc(l) + (d ? ': ' + d : '') + '</span>');
|
||||
}
|
||||
return parts.join('');
|
||||
}
|
||||
|
||||
function tgl(el) { var b = el.nextElementSibling; b.className = b.className.indexOf('open') >= 0 ? 'rb' : 'rb open'; }
|
||||
function esc(s) { if (!s) return ''; var d = document.createElement('div'); d.textContent = s; return d.innerHTML; }
|
||||
</script></body></html>
|
||||
'@
|
||||
|
||||
# Write without BOM
|
||||
$utf8NoBom = New-Object System.Text.UTF8Encoding $false
|
||||
[System.IO.File]::WriteAllText($OutputPath, $html, $utf8NoBom)
|
||||
|
|
@ -116,7 +116,7 @@ function Get-MailMessages {
|
|||
)
|
||||
|
||||
$user = $Settings.MailboxUser
|
||||
$endpoint = "/users/$user/messages?`$top=$Top&`$orderby=receivedDateTime desc"
|
||||
$endpoint = "/users/$user/mailFolders/inbox/messages?`$top=$Top&`$orderby=receivedDateTime desc"
|
||||
$endpoint += "&`$select=id,subject,from,receivedDateTime,categories,hasAttachments,isRead,body"
|
||||
|
||||
if ($UnreadOnly) {
|
||||
|
|
|
|||
|
|
@ -457,4 +457,16 @@ $protocolFile = Join-Path $protocolDir "run_$($runTimestamp.ToString('yyyy-MM-dd
|
|||
$protocol | ConvertTo-Json -Depth 10 | Set-Content -Path $protocolFile -Encoding UTF8
|
||||
Write-Log "Protokoll geschrieben: $protocolFile" -Level Info
|
||||
|
||||
# --- HTML-Gesamtprotokoll generieren ---
|
||||
$allProtocols = @()
|
||||
Get-ChildItem -Path $protocolDir -Filter "run_*.json" | Sort-Object Name -Descending | ForEach-Object {
|
||||
$content = Get-Content $_.FullName -Raw -Encoding UTF8
|
||||
$allProtocols += $content
|
||||
}
|
||||
$jsonArray = "[" + ($allProtocols -join ",") + "]"
|
||||
|
||||
$htmlFile = Join-Path (Split-Path $protocolDir -Parent) "protocol.html"
|
||||
& (Join-Path $scriptRoot "Generate-ProtocolHtml.ps1") -JsonData $jsonArray -OutputPath $htmlFile
|
||||
Write-Log "HTML-Protokoll aktualisiert: $htmlFile" -Level Info
|
||||
|
||||
Write-Log "=== Fertig: $totalProcessed E-Mail(s) verarbeitet, $totalAlerts Alert(s), $totalErrors Fehler ==="
|
||||
|
|
|
|||
Loading…
Reference in New Issue