feat: rollenbasierte SMTP-Statistik + Service-Aktionen
- handleServiceAction: nur superadmin darf Dienste stoppen/starten - handleSMTPStatus: domain_admin bekommt tenant-gefilterte Stats (Domains, Mailanzahl, Speicher) statt globaler Daemon-Info - Admin-Dashboard: SMTP-Kacheln, Systemauslastung, IP-Allowlist nur für superadmin; domain_admin sieht eigene Domain-Statistik - Dienste-Tab: Aktions-Buttons nur für superadmin sichtbar Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -589,6 +589,35 @@ func (s *Server) handleSearch(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func (s *Server) handleSMTPStatus(w http.ResponseWriter, r *http.Request) {
|
||||
sess := sessionFromCtx(r.Context())
|
||||
tenantID := tenantFromCtx(r.Context())
|
||||
|
||||
// domain_admin: return only their tenant's email statistics (no global daemon info)
|
||||
if sess != nil && !auth.HasRole(sess.Role, userstore.RoleSuperAdmin) {
|
||||
stats, err := s.store.StatsByTenant(r.Context(), tenantID)
|
||||
if err != nil {
|
||||
writeError(w, http.StatusInternalServerError, "failed to read stats")
|
||||
return
|
||||
}
|
||||
domains := []string{}
|
||||
if tenantID != nil && s.tenantStore != nil {
|
||||
if dd, derr := s.tenantStore.ListDomains(r.Context(), *tenantID); derr == nil {
|
||||
for _, d := range dd {
|
||||
domains = append(domains, d.Domain)
|
||||
}
|
||||
}
|
||||
}
|
||||
writeJSON(w, http.StatusOK, map[string]interface{}{
|
||||
"enabled": true,
|
||||
"tenant_only": true,
|
||||
"domains": domains,
|
||||
"total_mails": stats["count"],
|
||||
"total_bytes": stats["total_size"],
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// superadmin: global daemon status
|
||||
if s.smtpDaemon == nil {
|
||||
writeJSON(w, http.StatusOK, map[string]interface{}{"enabled": false, "running": false})
|
||||
return
|
||||
@@ -1047,6 +1076,13 @@ func (s *Server) handleListServices(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
func (s *Server) handleServiceAction(w http.ResponseWriter, r *http.Request) {
|
||||
// Only superadmin may start/stop/restart services
|
||||
sess := sessionFromCtx(r.Context())
|
||||
if sess == nil || !auth.HasRole(sess.Role, userstore.RoleSuperAdmin) {
|
||||
writeError(w, http.StatusForbidden, "superadmin required")
|
||||
return
|
||||
}
|
||||
|
||||
name := r.PathValue("name")
|
||||
if !isAllowedService(name) {
|
||||
writeError(w, http.StatusBadRequest, "unknown service")
|
||||
|
||||
Reference in New Issue
Block a user