package handlers import ( "encoding/json" "net/http" "github.com/rede5/gohorsejobs/backend/internal/api/middleware" "github.com/rede5/gohorsejobs/backend/internal/dto" "github.com/rede5/gohorsejobs/backend/internal/models" ) // ApplicationServiceInterface defines the contract for application service type ApplicationServiceInterface interface { CreateApplication(req dto.CreateApplicationRequest) (*models.Application, error) GetApplications(jobID string) ([]models.Application, error) GetApplicationsByCompany(companyID string) ([]models.Application, error) GetApplicationsByUser(userID string) ([]models.ApplicationWithDetails, error) GetApplicationByID(id string) (*models.Application, error) UpdateApplicationStatus(id string, req dto.UpdateApplicationStatusRequest) (*models.Application, error) DeleteApplication(id string) error } type ApplicationHandler struct { Service ApplicationServiceInterface } func NewApplicationHandler(service ApplicationServiceInterface) *ApplicationHandler { return &ApplicationHandler{Service: service} } // CreateApplication submits a new job application // @Summary Create Application // @Description Submit a new job application for a posting // @Tags Applications // @Accept json // @Produce json // @Param application body dto.CreateApplicationRequest true "Application data" // @Success 201 {object} models.Application // @Failure 400 {string} string "Bad Request" // @Failure 500 {string} string "Internal Server Error" // @Router /api/v1/applications [post] func (h *ApplicationHandler) CreateApplication(w http.ResponseWriter, r *http.Request) { var req dto.CreateApplicationRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } // Try to get user ID from context (if authenticated) if userID, ok := r.Context().Value(middleware.ContextUserID).(string); ok && userID != "" { req.UserID = &userID } app, err := h.Service.CreateApplication(req) 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(app) } // GetApplications lists applications for a job // @Summary List Applications // @Description List all applications for a job // @Tags Applications // @Accept json // @Produce json // @Param jobId query string true "Filter applications by job ID" // @Success 200 {array} models.Application // @Failure 400 {string} string "Bad Request" // @Failure 500 {string} string "Internal Server Error" // @Router /api/v1/applications [get] func (h *ApplicationHandler) GetApplications(w http.ResponseWriter, r *http.Request) { // Check for filters jobID := r.URL.Query().Get("jobId") companyID := r.URL.Query().Get("companyId") if jobID == "" && companyID == "" { http.Error(w, "jobId or companyId is required", http.StatusBadRequest) return } var apps []models.Application var err error if companyID != "" { apps, err = h.Service.GetApplicationsByCompany(companyID) } else { apps, err = h.Service.GetApplications(jobID) } if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(apps) } // GetApplicationByID returns a single application by ID // @Summary Get Application // @Description Retrieve a job application by its ID // @Tags Applications // @Accept json // @Produce json // @Param id path string true "Application ID" // @Success 200 {object} models.Application // @Failure 400 {string} string "Bad Request" // @Failure 404 {string} string "Not Found" // @Router /api/v1/applications/{id} [get] func (h *ApplicationHandler) GetApplicationByID(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") app, err := h.Service.GetApplicationByID(id) if err != nil { http.Error(w, err.Error(), http.StatusNotFound) return } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(app) } // UpdateApplicationStatus updates the status of an application // @Summary Update Application Status // @Description Update the status of a job application // @Tags Applications // @Accept json // @Produce json // @Param id path string true "Application ID" // @Param body body dto.UpdateApplicationStatusRequest true "Status update" // @Success 200 {object} models.Application // @Failure 400 {string} string "Bad Request" // @Failure 500 {string} string "Internal Server Error" // @Router /api/v1/applications/{id}/status [put] func (h *ApplicationHandler) UpdateApplicationStatus(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") var req dto.UpdateApplicationStatusRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } app, err := h.Service.UpdateApplicationStatus(id, req) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(app) } // ListUserApplications lists applications for the logged in user func (h *ApplicationHandler) ListUserApplications(w http.ResponseWriter, r *http.Request) { userID, ok := r.Context().Value(middleware.ContextUserID).(string) if !ok { http.Error(w, "Unauthorized", http.StatusUnauthorized) return } apps, err := h.Service.GetApplicationsByUser(userID) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(apps) } // DeleteApplication removes an application // @Summary Delete Application // @Description Remove an application by ID // @Tags Applications // @Accept json // @Produce json // @Param id path string true "Application ID" // @Success 204 {object} nil // @Failure 400 {string} string "Bad Request" // @Failure 500 {string} string "Internal Server Error" // @Router /api/v1/applications/{id} [delete] func (h *ApplicationHandler) DeleteApplication(w http.ResponseWriter, r *http.Request) { id := r.PathValue("id") if err := h.Service.DeleteApplication(id); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } w.WriteHeader(http.StatusNoContent) }