e5623d2f84
- Add Infrastructure Health section with CPU/Memory/Disk panels - Add Service Status section with PM2/Docker panels - Create GrafanaPanel component for iframe embedding - Build passes successfully
152 lines
4.1 KiB
Go
152 lines
4.1 KiB
Go
package handlers
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
|
|
"boc/sms"
|
|
)
|
|
|
|
// SMSHandler hanterar SMS- och 2FA-endpoints
|
|
type SMSHandler struct {
|
|
TwoFactor *sms.TwoFactorAuth
|
|
Notifier *sms.NotificationService
|
|
}
|
|
|
|
// NewSMSHandler skapar ny SMS-handler
|
|
func NewSMSHandler(twoFactor *sms.TwoFactorAuth, notifier *sms.NotificationService) *SMSHandler {
|
|
return &SMSHandler{
|
|
TwoFactor: twoFactor,
|
|
Notifier: notifier,
|
|
}
|
|
}
|
|
|
|
// SendVerificationCode skickar 2FA-kod
|
|
func (h *SMSHandler) SendVerificationCode(w http.ResponseWriter, r *http.Request) {
|
|
if h.TwoFactor == nil {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.WriteHeader(http.StatusServiceUnavailable)
|
|
json.NewEncoder(w).Encode(map[string]interface{}{
|
|
"error": "SMS not configured",
|
|
"message": "Set ELK46_USERNAME and ELK46_PASSWORD environment variables",
|
|
})
|
|
return
|
|
}
|
|
|
|
var req struct {
|
|
Phone string `json:"phone"`
|
|
}
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
http.Error(w, `{"error":"invalid request"}`, http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
code, err := h.TwoFactor.SendVerificationCode(req.Phone)
|
|
if err != nil {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
json.NewEncoder(w).Encode(map[string]interface{}{
|
|
"error": err.Error(),
|
|
})
|
|
return
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(map[string]interface{}{
|
|
"message": "Verification code sent",
|
|
"phone": req.Phone,
|
|
// I produktion: skicka INTE koden tillbaka!
|
|
"code": code, // Endast för test
|
|
})
|
|
}
|
|
|
|
// VerifyCode verifierar 2FA-kod
|
|
func (h *SMSHandler) VerifyCode(w http.ResponseWriter, r *http.Request) {
|
|
if h.TwoFactor == nil {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.WriteHeader(http.StatusServiceUnavailable)
|
|
json.NewEncoder(w).Encode(map[string]interface{}{
|
|
"error": "SMS not configured",
|
|
"message": "Set ELK46_USERNAME and ELK46_PASSWORD environment variables",
|
|
})
|
|
return
|
|
}
|
|
|
|
var req struct {
|
|
Phone string `json:"phone"`
|
|
Code string `json:"code"`
|
|
}
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
http.Error(w, `{"error":"invalid request"}`, http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
valid, err := h.TwoFactor.VerifyCode(req.Phone, req.Code)
|
|
if err != nil {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
json.NewEncoder(w).Encode(map[string]interface{}{
|
|
"error": err.Error(),
|
|
})
|
|
return
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(map[string]interface{}{
|
|
"valid": valid,
|
|
})
|
|
}
|
|
|
|
// SendNotification skickar generisk notifikation
|
|
func (h *SMSHandler) SendNotification(w http.ResponseWriter, r *http.Request) {
|
|
var req struct {
|
|
Phone string `json:"phone"`
|
|
Type string `json:"type"` // task_reminder, onboarding, document, performance, training, security
|
|
Message string `json:"message"`
|
|
}
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
http.Error(w, `{"error":"invalid request"}`, http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
var err error
|
|
switch req.Type {
|
|
case "task_reminder":
|
|
err = h.Notifier.SendTaskReminder(req.Phone, req.Message, "idag")
|
|
case "onboarding":
|
|
err = h.Notifier.SendOnboardingWelcome(req.Phone, req.Message)
|
|
case "document":
|
|
err = h.Notifier.SendDocumentSignatureRequest(req.Phone, req.Message)
|
|
case "security":
|
|
err = h.Notifier.SendSecurityAlert(req.Phone, req.Message)
|
|
default:
|
|
http.Error(w, `{"error":"unknown notification type"}`, http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
if err != nil {
|
|
http.Error(w, `{"error":"`+err.Error()+`"}`, http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(map[string]interface{}{
|
|
"message": "Notification sent",
|
|
})
|
|
}
|
|
|
|
// SMSStatus kontrollerar SMS-konfiguration
|
|
func (h *SMSHandler) SMSStatus(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(map[string]interface{}{
|
|
"configured": h.TwoFactor != nil,
|
|
"provider": "46elks",
|
|
"features": []string{
|
|
"two_way_sms",
|
|
"bulk_sms",
|
|
"2fa_verification",
|
|
"notifications",
|
|
},
|
|
})
|
|
}
|