package handlers import ( "encoding/json" "net/http" "github.com/rede5/gohorsejobs/backend/internal/models" "github.com/rede5/gohorsejobs/backend/internal/services" ) type TicketHandler struct { service *services.TicketService } func NewTicketHandler(service *services.TicketService) *TicketHandler { return &TicketHandler{service: service} } // CreateTicket func (h *TicketHandler) CreateTicket(w http.ResponseWriter, r *http.Request) { userID := getUserIDFromContext(r) if userID == "" { http.Error(w, "Unauthorized", http.StatusUnauthorized) return } var req models.CreateTicketRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { http.Error(w, "Invalid request", http.StatusBadRequest) return } if req.Subject == "" { http.Error(w, "Subject is required", http.StatusBadRequest) return } ticket, err := h.service.CreateTicket(r.Context(), userID, req.Subject, req.Category, req.Priority) 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(ticket) } // GetTickets (List user tickets) func (h *TicketHandler) GetTickets(w http.ResponseWriter, r *http.Request) { userID := getUserIDFromContext(r) if userID == "" { http.Error(w, "Unauthorized", http.StatusUnauthorized) return } tickets, err := h.service.ListTickets(r.Context(), userID) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(tickets) } // GetTicketByID (and messages) func (h *TicketHandler) GetTicketByID(w http.ResponseWriter, r *http.Request) { userID := getUserIDFromContext(r) if userID == "" { http.Error(w, "Unauthorized", http.StatusUnauthorized) return } id := r.PathValue("id") if id == "" { http.Error(w, "Invalid ticket ID", http.StatusBadRequest) return } ticket, messages, err := h.service.GetTicket(r.Context(), id, userID, false) if err != nil { http.Error(w, err.Error(), http.StatusNotFound) return } type Response struct { Ticket *models.Ticket `json:"ticket"` Messages []models.TicketMessage `json:"messages"` } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(Response{Ticket: ticket, Messages: messages}) } // AddTicketMessage func (h *TicketHandler) AddTicketMessage(w http.ResponseWriter, r *http.Request) { userID := getUserIDFromContext(r) if userID == "" { http.Error(w, "Unauthorized", http.StatusUnauthorized) return } id := r.PathValue("id") if id == "" { http.Error(w, "Invalid ticket ID", http.StatusBadRequest) return } var req models.AddTicketMessageRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { http.Error(w, "Invalid request", http.StatusBadRequest) return } if req.Message == "" { http.Error(w, "Message is required", http.StatusBadRequest) return } msg, err := h.service.AddMessage(r.Context(), id, userID, req.Message, false) 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(msg) } // UpdateTicket (Status/Priority) // NOTE: hml UpdateTicket requires isAdmin flag. User can only add messages or close? // hml UpdateTicket: verify ownership OR admin. func (h *TicketHandler) UpdateTicket(w http.ResponseWriter, r *http.Request) { userID := getUserIDFromContext(r) if userID == "" { http.Error(w, "Unauthorized", http.StatusUnauthorized) return } id := r.PathValue("id") if id == "" { http.Error(w, "Invalid ticket ID", http.StatusBadRequest) return } var req struct { Status *string `json:"status"` Priority *string `json:"priority"` } if err := json.NewDecoder(r.Body).Decode(&req); err != nil { http.Error(w, "Invalid request", http.StatusBadRequest) return } // Assuming User is NOT admin for this general handler. Admin routes separate? // But hml UpdateTicket allows owner update. isAdmin := false // TODO: Extract from context role ticket, err := h.service.UpdateTicket(r.Context(), id, userID, req.Status, req.Priority, isAdmin) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(ticket) } // Helper COPY (To avoid import cycle if utils not available, or just keeping package local) // Ideally this should be in a shared middleware/utils package /* func getUserIDFromContext(r *http.Request) string { if userID, ok := r.Context().Value("userID").(string); ok && userID != "" { return userID } if userID := r.Header.Get("X-User-ID"); userID != "" { return userID } return "" } */