- Backend: Email producer (LavinMQ), EmailService interface - Backend: CRUD API for email_templates and email_settings - Backend: avatar_url field in users table + UpdateMyProfile support - Backend: StorageService for pre-signed URLs - NestJS: Email consumer with Nodemailer and Handlebars - Frontend: Email Templates admin pages (list/edit) - Frontend: Updated profileApi.uploadAvatar with pre-signed URL flow - Frontend: New /post-job public page (company registration + job creation wizard) - Migrations: 027_create_email_system.sql, 028_add_avatar_url_to_users.sql
86 lines
2.2 KiB
Go
86 lines
2.2 KiB
Go
package handlers
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
|
|
"github.com/rede5/gohorsejobs/backend/internal/api/middleware"
|
|
"github.com/rede5/gohorsejobs/backend/internal/services"
|
|
)
|
|
|
|
type SettingsHandler struct {
|
|
settingsService *services.SettingsService
|
|
}
|
|
|
|
func NewSettingsHandler(s *services.SettingsService) *SettingsHandler {
|
|
return &SettingsHandler{settingsService: s}
|
|
}
|
|
|
|
// GetSettings retrieves a setting by key.
|
|
// Public for 'theme', restricted for others.
|
|
func (h *SettingsHandler) GetSettings(w http.ResponseWriter, r *http.Request) {
|
|
key := r.PathValue("key")
|
|
if key == "" {
|
|
http.Error(w, "Key is required", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
// Security Check
|
|
if key != "theme" {
|
|
// Require Admin
|
|
roles := middleware.ExtractRoles(r.Context().Value(middleware.ContextRoles))
|
|
isAdmin := false
|
|
for _, role := range roles {
|
|
if role == "ADMIN" || role == "SUPERADMIN" || role == "admin" || role == "superadmin" {
|
|
isAdmin = true
|
|
break
|
|
}
|
|
}
|
|
if !isAdmin {
|
|
http.Error(w, "Forbidden: Access restricted", http.StatusForbidden)
|
|
return
|
|
}
|
|
}
|
|
|
|
val, err := h.settingsService.GetSettings(r.Context(), key)
|
|
if err != nil {
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
if val == nil {
|
|
// Return empty object for theme instead of 404 to avoid errors in frontend
|
|
if key == "theme" {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.Write([]byte("{}"))
|
|
return
|
|
}
|
|
http.Error(w, "Setting not found", http.StatusNotFound)
|
|
return
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.Write(val)
|
|
}
|
|
|
|
// SaveSettings saves a setting. Admin only.
|
|
func (h *SettingsHandler) SaveSettings(w http.ResponseWriter, r *http.Request) {
|
|
key := r.PathValue("key")
|
|
if key == "" {
|
|
http.Error(w, "Key is required", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
var req interface{}
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
|
http.Error(w, "Invalid value", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
if err := h.settingsService.SaveSettings(r.Context(), key, req); err != nil {
|
|
http.Error(w, err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
w.WriteHeader(http.StatusOK)
|
|
json.NewEncoder(w).Encode(map[string]string{"message": "Setting saved"})
|
|
}
|