158 lines
12 KiB
HTML
158 lines
12 KiB
HTML
{{define "title"}}Logs - Email Server{{end}}
|
|
|
|
{{define "extra_css"}}
|
|
<style>
|
|
.log-entry { border-left: 4px solid var(--bs-border-color); padding: 0.75rem; margin-bottom: 0.5rem; background-color: var(--bs-body-bg); border-radius: 0.375rem; }
|
|
.log-email { border-left-color: #0d6efd; }
|
|
.log-auth { border-left-color: #198754; }
|
|
.log-success { border-left-color: #198754; }
|
|
.log-failed { border-left-color: #dc3545; }
|
|
.log-partial { border-left-color: #fd7e14; }
|
|
</style>
|
|
{{end}}
|
|
|
|
{{define "content"}}
|
|
<div class="container-fluid">
|
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
|
<h2><i class="bi bi-journal-text me-2"></i>Emails Log</h2>
|
|
<div class="btn-group">
|
|
<a href="/pymta-manager/logs?type=all" class="btn {{if eq .filter_type "all"}}btn-primary{{else}}btn-outline-primary{{end}}"><i class="bi bi-list-ul me-1"></i>All Logs</a>
|
|
<a href="/pymta-manager/logs?type=emails" class="btn {{if eq .filter_type "emails"}}btn-primary{{else}}btn-outline-primary{{end}}"><i class="bi bi-envelope me-1"></i>Email Logs</a>
|
|
<a href="/pymta-manager/logs?type=auth" class="btn {{if eq .filter_type "auth"}}btn-primary{{else}}btn-outline-primary{{end}}"><i class="bi bi-shield-lock me-1"></i>Auth Logs</a>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="row">
|
|
<div class="col-12">
|
|
<div class="card">
|
|
<div class="card-header d-flex justify-content-between align-items-center">
|
|
<h5 class="mb-0"><i class="bi bi-list-ul me-2"></i>Recent Activity</h5>
|
|
<button class="btn btn-outline-secondary btn-sm" onclick="location.reload()"><i class="bi bi-arrow-clockwise me-1"></i>Refresh</button>
|
|
</div>
|
|
<div class="card-body">
|
|
{{if .logs}}
|
|
{{if eq .filter_type "all"}}
|
|
{{range .logs}}
|
|
{{if eq .type "email"}}
|
|
{{$log := .data}}
|
|
{{$overall := emailOverallStatus .recipients}}
|
|
<div class="log-entry log-email log-{{if eq $overall "relayed"}}success{{else if eq $overall "partial"}}partial{{else}}failed{{end}}">
|
|
<div class="d-flex justify-content-between align-items-start mb-2">
|
|
<div>
|
|
<span class="badge bg-primary me-2">EMAIL</span>
|
|
<strong>{{$log.MailFrom}}</strong>
|
|
{{if $log.ToAddress}} → <span class="text-primary">To:</span> {{$log.ToAddress}}{{end}}
|
|
{{if $log.DKIMSigned}}<span class="badge bg-success ms-2"><i class="bi bi-shield-check me-1"></i>DKIM</span>{{end}}
|
|
</div>
|
|
<small class="text-muted">{{strftime "%Y-%m-%d %H:%M:%S" $log.Timestamp}}</small>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-md-6"><strong>Status:</strong> {{if eq $overall "relayed"}}<span class="text-success">Sent Successfully</span>{{else if eq $overall "partial"}}<span class="text-warning">Partial Fail</span>{{else}}<span class="text-danger">Failed</span>{{end}}</div>
|
|
<div class="col-md-6"><strong>Message ID:</strong> <code>{{$log.MessageID}}</code></div>
|
|
</div>
|
|
{{if $log.Subject}}<div class="mt-2"><strong>Subject:</strong> {{$log.Subject}}</div>{{end}}
|
|
<div class="mt-2"><a href="/pymta-manager/msg/content/{{$log.ID}}" class="btn btn-sm btn-primary"><i class="bi bi-envelope-open-text"></i> View Message Details</a></div>
|
|
</div>
|
|
{{else}}
|
|
{{$log := .data}}
|
|
<div class="log-entry log-auth log-{{if $log.Success}}success{{else}}failed{{end}}">
|
|
<div class="d-flex justify-content-between align-items-start mb-2">
|
|
<div>
|
|
<span class="badge bg-success me-2">AUTH</span>
|
|
<strong>{{$log.Identifier}}</strong>
|
|
<span class="badge {{if $log.Success}}bg-success{{else}}bg-danger{{end}} ms-2">{{if $log.Success}}Success{{else}}Failed{{end}}</span>
|
|
</div>
|
|
<small class="text-muted">{{formatDatetime $log.CreatedAt}}</small>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-md-6"><strong>Type:</strong> {{upper $log.AuthType}}</div>
|
|
<div class="col-md-6"><strong>IP:</strong> <code>{{if $log.IPAddress}}{{$log.IPAddress}}{{else}}N/A{{end}}</code></div>
|
|
</div>
|
|
{{if $log.Message}}<div class="mt-2"><strong>Message:</strong> {{$log.Message}}</div>{{end}}
|
|
</div>
|
|
{{end}}
|
|
{{end}}
|
|
{{else if eq .filter_type "emails"}}
|
|
{{$recMap := .recipient_logs_map}}
|
|
{{range .logs}}
|
|
{{$log := .}}
|
|
{{$recs := index $recMap .ID}}
|
|
{{$overall := emailOverallStatus $recs}}
|
|
<div class="log-entry log-email log-{{$overall}}">
|
|
<div class="d-flex justify-content-between align-items-start mb-2">
|
|
<div>
|
|
<strong>{{.MailFrom}}</strong>
|
|
{{if .ToAddress}} → <span class="text-primary">To:</span> {{.ToAddress}}{{end}}
|
|
{{if .CcAddresses}}<br><span class="ms-4 text-info">CC:</span> {{.CcAddresses}}{{end}}
|
|
{{if .BccAddresses}}<br><span class="ms-4 text-warning">BCC:</span> {{.BccAddresses}}{{end}}
|
|
{{if .DKIMSigned}}<span class="badge bg-success ms-2"><i class="bi bi-shield-check me-1"></i>DKIM</span>{{end}}
|
|
</div>
|
|
<small class="text-muted">{{strftime "%Y-%m-%d %H:%M:%S" .Timestamp}}</small>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-md-3"><strong>Status:</strong> {{if eq $overall "relayed"}}<span class="text-success">Sent</span>{{else if eq $overall "partial"}}<span class="text-warning">Partial Fail</span>{{else}}<span class="text-danger">Failed</span>{{end}}</div>
|
|
<div class="col-md-3"><strong>Peer:</strong> <code>{{.PeerIP}}</code></div>
|
|
<div class="col-md-6"><strong>Message ID:</strong> <code>{{.MessageID}}</code></div>
|
|
</div>
|
|
{{if $recs}}
|
|
<div class="mt-2">
|
|
<strong>Recipient Delivery Results:</strong>
|
|
<ul class="list-group">
|
|
{{range $recs}}
|
|
<li class="list-group-item d-flex justify-content-between align-items-center">
|
|
<span><strong>{{upper .RecipientType}}:</strong> {{.Recipient}} {{if eq .Status "success"}}<span class="badge bg-success ms-2">Delivered</span>{{else}}<span class="badge bg-danger ms-2">Failed</span>{{end}}</span>
|
|
{{if or .ErrorCode .ErrorMessage}}<span class="text-danger ms-2">{{.ErrorCode}} {{.ErrorMessage}}</span>{{end}}
|
|
</li>
|
|
{{end}}
|
|
</ul>
|
|
</div>
|
|
{{end}}
|
|
{{if .Subject}}<div class="mt-2"><strong>Subject:</strong> {{.Subject}}</div>{{end}}
|
|
<div class="mt-2"><a href="/pymta-manager/msg/content/{{.ID}}" class="btn btn-outline-info btn-sm"><i class="bi bi-file-earmark-text me-1"></i> View Full Message</a></div>
|
|
</div>
|
|
{{end}}
|
|
{{else}}
|
|
{{range .logs}}
|
|
<div class="log-entry log-auth log-{{if .Success}}success{{else}}failed{{end}}">
|
|
<div class="d-flex justify-content-between align-items-start mb-2">
|
|
<div>
|
|
<strong>{{.Identifier}}</strong>
|
|
<span class="badge {{if .Success}}bg-success{{else}}bg-danger{{end}} ms-2">{{if .Success}}Success{{else}}Failed{{end}}</span>
|
|
</div>
|
|
<small class="text-muted">{{formatDatetime .CreatedAt}}</small>
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-md-4"><strong>Type:</strong> {{upper .AuthType}}</div>
|
|
<div class="col-md-4"><strong>IP:</strong> <code>{{if .IPAddress}}{{.IPAddress}}{{else}}N/A{{end}}</code></div>
|
|
<div class="col-md-4"><strong>Result:</strong> {{if .Success}}<span class="text-success">Authenticated</span>{{else}}<span class="text-danger">Rejected</span>{{end}}</div>
|
|
</div>
|
|
{{if .Message}}<div class="mt-2"><strong>Details:</strong> {{.Message}}</div>{{end}}
|
|
</div>
|
|
{{end}}
|
|
{{end}}
|
|
|
|
{{if or .has_prev .has_next}}
|
|
<nav aria-label="Log pagination" class="mt-4">
|
|
<ul class="pagination justify-content-center">
|
|
{{if .has_prev}}<li class="page-item"><a class="page-link" href="/pymta-manager/logs?type={{.filter_type}}&page={{sub .page 1}}"><i class="bi bi-chevron-left"></i> Previous</a></li>{{end}}
|
|
<li class="page-item active"><span class="page-link">Page {{.page}}</span></li>
|
|
{{if .has_next}}<li class="page-item"><a class="page-link" href="/pymta-manager/logs?type={{.filter_type}}&page={{add .page 1}}">Next <i class="bi bi-chevron-right"></i></a></li>{{end}}
|
|
</ul>
|
|
</nav>
|
|
{{end}}
|
|
{{else}}
|
|
<div class="text-center py-5"><i class="bi bi-journal-text text-muted" style="font-size: 4rem;"></i><h4 class="text-muted mt-3">No Logs Found</h4></div>
|
|
{{end}}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{{end}}
|
|
|
|
{{define "extra_js"}}
|
|
<script>
|
|
setInterval(function() { if (document.visibilityState === 'visible') { location.reload(); } }, 30000);
|
|
</script>
|
|
{{end}}
|