package handlers import ( "encoding/json" "net/http" "strings" "github.com/rede5/gohorsejobs/backend/internal/api/middleware" "github.com/rede5/gohorsejobs/backend/internal/dto" "github.com/rede5/gohorsejobs/backend/internal/models" ) type JobAlertServiceInterface interface { CreateAlert(req dto.CreateJobAlertRequest, userID *string) (*models.JobAlert, error) ConfirmAlert(token string) (*models.JobAlert, error) GetAlertsByUser(userID string) ([]models.JobAlert, error) DeleteAlert(id string, userID string) error ToggleAlert(id string, userID string, active bool) error } type JobAlertHandler struct { Service JobAlertServiceInterface } func NewJobAlertHandler(service JobAlertServiceInterface) *JobAlertHandler { return &JobAlertHandler{Service: service} } func (h *JobAlertHandler) CreateAlert(w http.ResponseWriter, r *http.Request) { var req dto.CreateJobAlertRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } var userID *string if uid, ok := r.Context().Value(middleware.ContextUserID).(string); ok && uid != "" { userID = &uid } alert, err := h.Service.CreateAlert(req, userID) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusCreated) json.NewEncoder(w).Encode(alert) } func (h *JobAlertHandler) ConfirmAlert(w http.ResponseWriter, r *http.Request) { token := r.URL.Query().Get("token") if token == "" { http.Error(w, "Token is required", http.StatusBadRequest) return } alert, err := h.Service.ConfirmAlert(token) if err != nil { http.Error(w, "Invalid or expired token", http.StatusNotFound) return } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(alert) } func (h *JobAlertHandler) GetMyAlerts(w http.ResponseWriter, r *http.Request) { userID, ok := r.Context().Value(middleware.ContextUserID).(string) if !ok || userID == "" { http.Error(w, "Unauthorized", http.StatusUnauthorized) return } alerts, err := h.Service.GetAlertsByUser(userID) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(alerts) } func (h *JobAlertHandler) DeleteAlert(w http.ResponseWriter, r *http.Request) { userID, ok := r.Context().Value(middleware.ContextUserID).(string) if !ok || userID == "" { http.Error(w, "Unauthorized", http.StatusUnauthorized) return } id := strings.TrimPrefix(r.URL.Path, "/api/v1/alerts/") err := h.Service.DeleteAlert(id, userID) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.WriteHeader(http.StatusNoContent) } func (h *JobAlertHandler) ToggleAlert(w http.ResponseWriter, r *http.Request) { userID, ok := r.Context().Value(middleware.ContextUserID).(string) if !ok || userID == "" { http.Error(w, "Unauthorized", http.StatusUnauthorized) return } id := strings.TrimPrefix(r.URL.Path, "/api/v1/alerts/") var req struct { Active bool `json:"active"` } if err := json.NewDecoder(r.Body).Decode(&req); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } err := h.Service.ToggleAlert(id, userID, req.Active) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.WriteHeader(http.StatusOK) }