gohorsejobs/backend/internal/api/handlers/settings_handler.go
Tiago Yamamoto 841b1d780c feat: Email System, Avatar Upload, Email Templates UI, and Public Job Posting
- 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
2025-12-26 12:21:34 -03:00

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"})
}