2bab61209c
Go-Modul in go.mod und allen 45 Go-Dateien umbenannt.
119 lines
3.5 KiB
Go
119 lines
3.5 KiB
Go
package api
|
||
|
||
import (
|
||
"encoding/json"
|
||
"net/http"
|
||
|
||
"archivmail/config"
|
||
"archivmail/internal/audit"
|
||
"archivmail/internal/smtpoutconfig"
|
||
)
|
||
|
||
// handleGetSMTPOut returns the current SMTP-Out relay config (password masked).
|
||
// GET /api/admin/smtp-out — superadmin only.
|
||
func (s *Server) handleGetSMTPOut(w http.ResponseWriter, r *http.Request) {
|
||
cfg, err := s.smtpOutStore.Get(r.Context())
|
||
if err != nil {
|
||
writeError(w, http.StatusInternalServerError, err.Error())
|
||
return
|
||
}
|
||
if cfg == nil {
|
||
writeJSON(w, http.StatusOK, map[string]interface{}{"configured": false})
|
||
return
|
||
}
|
||
writeJSON(w, http.StatusOK, map[string]interface{}{"configured": true, "config": cfg})
|
||
}
|
||
|
||
// handleSaveSMTPOut upserts the SMTP-Out relay config and reloads the mailer.
|
||
// PUT /api/admin/smtp-out — superadmin only.
|
||
func (s *Server) handleSaveSMTPOut(w http.ResponseWriter, r *http.Request) {
|
||
var body smtpoutconfig.SMTPOutConfig
|
||
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
|
||
writeError(w, http.StatusBadRequest, "invalid body")
|
||
return
|
||
}
|
||
if body.Port == 0 {
|
||
body.Port = 587
|
||
}
|
||
|
||
sess := sessionFromCtx(r.Context())
|
||
if err := s.smtpOutStore.Save(r.Context(), body, sess.Username); err != nil {
|
||
writeError(w, http.StatusInternalServerError, err.Error())
|
||
return
|
||
}
|
||
|
||
// Reload the mailer at runtime — no restart needed
|
||
if full, err := s.smtpOutStore.GetWithPassword(r.Context()); err == nil && full != nil {
|
||
s.mailer.Reload(config.SMTPOutConfig{
|
||
Host: full.Host,
|
||
Port: full.Port,
|
||
User: full.User,
|
||
Password: full.Password,
|
||
TLS: full.TLS,
|
||
From: full.From,
|
||
})
|
||
}
|
||
|
||
if s.audlog != nil {
|
||
s.audlog.Log(audit.Entry{
|
||
EventType: "smtp_out_config_saved",
|
||
Username: sess.Username,
|
||
IPAddress: s.remoteIP(r),
|
||
Success: true,
|
||
})
|
||
}
|
||
|
||
writeJSON(w, http.StatusOK, map[string]interface{}{"ok": true})
|
||
}
|
||
|
||
// handleDeleteSMTPOut removes the SMTP-Out config and disables the mailer.
|
||
// DELETE /api/admin/smtp-out — superadmin only.
|
||
func (s *Server) handleDeleteSMTPOut(w http.ResponseWriter, r *http.Request) {
|
||
if err := s.smtpOutStore.Delete(r.Context()); err != nil {
|
||
writeError(w, http.StatusInternalServerError, err.Error())
|
||
return
|
||
}
|
||
// Disable mailer
|
||
s.mailer.Reload(config.SMTPOutConfig{})
|
||
|
||
sess := sessionFromCtx(r.Context())
|
||
if s.audlog != nil {
|
||
s.audlog.Log(audit.Entry{
|
||
EventType: "smtp_out_config_deleted",
|
||
Username: sess.Username,
|
||
IPAddress: s.remoteIP(r),
|
||
Success: true,
|
||
})
|
||
}
|
||
writeJSON(w, http.StatusOK, map[string]interface{}{"ok": true})
|
||
}
|
||
|
||
// handleTestSMTPOut sends a test email to the logged-in admin.
|
||
// POST /api/admin/smtp-out/test — superadmin only.
|
||
func (s *Server) handleTestSMTPOut(w http.ResponseWriter, r *http.Request) {
|
||
if !s.mailer.IsConfigured() {
|
||
writeError(w, http.StatusServiceUnavailable, "SMTP-Out nicht konfiguriert")
|
||
return
|
||
}
|
||
|
||
sess := sessionFromCtx(r.Context())
|
||
u, err := s.users.GetByUsername(sess.Username)
|
||
if err != nil || u.Email == "" {
|
||
writeError(w, http.StatusBadRequest, "Keine E-Mail-Adresse für diesen Account")
|
||
return
|
||
}
|
||
|
||
html := `<p>Dies ist eine Test-E-Mail von <strong>archivmail</strong>.<br>Der SMTP-Relay ist korrekt konfiguriert.</p>`
|
||
txt := "Dies ist eine Test-E-Mail von archivmail. Der SMTP-Relay ist korrekt konfiguriert."
|
||
|
||
if err := s.mailer.Send(u.Email, "archivmail – SMTP-Test", html, txt); err != nil {
|
||
writeError(w, http.StatusBadGateway, "Versand fehlgeschlagen: "+err.Error())
|
||
return
|
||
}
|
||
|
||
writeJSON(w, http.StatusOK, map[string]interface{}{
|
||
"ok": true,
|
||
"sent_to": u.Email,
|
||
})
|
||
}
|