- Added new job analysis result repository and database migration system - Expanded job creation to support Glassdoor as a new provider alongside LinkedIn - Added CV analysis service launch configuration in VS Code - Updated Makefile with new commands for scraper service and migrations - Improved environment loading in cron analyzer to support local development - Added error handling for unsupported job providers - Integrated job analysis results
148 lines
5.2 KiB
Go
148 lines
5.2 KiB
Go
package http
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"log/slog"
|
|
"net/http"
|
|
"strconv"
|
|
|
|
"github.com/jobs-scraper/shared/ports"
|
|
"github.com/jobs-scraper/shared/repo"
|
|
"github.com/jobs-scraper/shared/utils"
|
|
|
|
"github.com/gorilla/mux"
|
|
)
|
|
|
|
// JobHandler handles HTTP requests related to jobs
|
|
type JobHandler struct {
|
|
jobCommands *ports.JobCommands
|
|
jobAnalysisResultRepo *repo.JobAnalysisResultRepository
|
|
}
|
|
|
|
// NewJobHandler creates a new instance of JobHandler
|
|
func NewJobHandler(jobCommands *ports.JobCommands, jobAnalysisResultRepo *repo.JobAnalysisResultRepository) *JobHandler {
|
|
return &JobHandler{
|
|
jobCommands: jobCommands,
|
|
jobAnalysisResultRepo: jobAnalysisResultRepo,
|
|
}
|
|
}
|
|
|
|
// RegisterRoutes registers all routes to the router
|
|
func (h *JobHandler) RegisterRoutes(router *mux.Router) {
|
|
jobs := router.PathPrefix("/jobs").Subrouter()
|
|
|
|
//jobs.Use(AuthMiddleware)
|
|
|
|
jobs.HandleFunc("", utils.Make(h.CreateJob)).Methods("POST")
|
|
jobs.HandleFunc("/analysis", utils.Make(h.GetAllAnalysisResults)).Methods("GET")
|
|
jobs.HandleFunc("/{id}/analysis", utils.Make(h.GetJobAnalysisResult)).Methods("GET")
|
|
jobs.HandleFunc("/analysis/top-matches", utils.Make(h.GetTopMatches)).Methods("GET")
|
|
}
|
|
|
|
// CreateJob handles the creation of a new job
|
|
// @Summary Create a new job
|
|
// @Description Creates a new job with the provided specifications
|
|
// @Tags jobs
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param job body ports.CreateJobCommand true "Job creation data"
|
|
// @Success 201 {object} map[string]string "Successfully created job"
|
|
// @Failure 400 {object} map[string]string "Invalid request data"
|
|
// @Failure 500 {object} map[string]string "Internal server error"
|
|
// @Router /jobs [post]
|
|
func (h *JobHandler) CreateJob(w http.ResponseWriter, r *http.Request) error {
|
|
var cmd ports.CreateJobCommand
|
|
if err := json.NewDecoder(r.Body).Decode(&cmd); err != nil {
|
|
slog.Error(err.Error())
|
|
return utils.NewAPIError(http.StatusBadRequest, utils.InvalidJSON())
|
|
}
|
|
|
|
err := h.jobCommands.CreateJob.Handle(cmd)
|
|
if err != nil {
|
|
slog.Error(err.Error())
|
|
return utils.NewAPIError(http.StatusInternalServerError, err)
|
|
}
|
|
|
|
utils.WriteJSON(w, http.StatusCreated, map[string]string{"message": "Success"})
|
|
return nil
|
|
}
|
|
|
|
// GetAllAnalysisResults handles retrieving all job analysis results
|
|
// @Summary Get all job analysis results
|
|
// @Description Retrieves all job analysis results from the database
|
|
// @Tags jobs
|
|
// @Produce json
|
|
// @Success 200 {array} domain.JobAnalysisResult "List of job analysis results"
|
|
// @Failure 500 {object} map[string]string "Internal server error"
|
|
// @Router /jobs/analysis [get]
|
|
func (h *JobHandler) GetAllAnalysisResults(w http.ResponseWriter, r *http.Request) error {
|
|
results, err := h.jobAnalysisResultRepo.GetAllAnalysisResults()
|
|
if err != nil {
|
|
slog.Error("Failed to get analysis results", "error", err)
|
|
return utils.NewAPIError(http.StatusInternalServerError, err)
|
|
}
|
|
|
|
utils.WriteJSON(w, http.StatusOK, results)
|
|
return nil
|
|
}
|
|
|
|
// GetJobAnalysisResult handles retrieving analysis result for a specific job
|
|
// @Summary Get job analysis result by job ID
|
|
// @Description Retrieves the analysis result for a specific job
|
|
// @Tags jobs
|
|
// @Produce json
|
|
// @Param id path int true "Job ID"
|
|
// @Success 200 {object} domain.JobAnalysisResult "Job analysis result"
|
|
// @Failure 400 {object} map[string]string "Invalid job ID"
|
|
// @Failure 404 {object} map[string]string "Analysis result not found"
|
|
// @Failure 500 {object} map[string]string "Internal server error"
|
|
// @Router /jobs/{id}/analysis [get]
|
|
func (h *JobHandler) GetJobAnalysisResult(w http.ResponseWriter, r *http.Request) error {
|
|
vars := mux.Vars(r)
|
|
jobID, err := strconv.ParseInt(vars["id"], 10, 64)
|
|
if err != nil {
|
|
return utils.NewAPIError(http.StatusBadRequest, fmt.Errorf("invalid job ID"))
|
|
}
|
|
|
|
result, err := h.jobAnalysisResultRepo.GetAnalysisResultByJobID(jobID)
|
|
if err != nil {
|
|
slog.Error("Failed to get analysis result", "jobID", jobID, "error", err)
|
|
return utils.NewAPIError(http.StatusNotFound, fmt.Errorf("analysis result not found"))
|
|
}
|
|
|
|
utils.WriteJSON(w, http.StatusOK, result)
|
|
return nil
|
|
}
|
|
|
|
// GetTopMatches handles retrieving top matching jobs based on analysis score
|
|
// @Summary Get top matching jobs
|
|
// @Description Retrieves jobs with high analysis match scores
|
|
// @Tags jobs
|
|
// @Produce json
|
|
// @Param min_score query int false "Minimum match score (default: 70)"
|
|
// @Success 200 {array} domain.JobAnalysisResult "List of top matching job analysis results"
|
|
// @Failure 400 {object} map[string]string "Invalid minimum score"
|
|
// @Failure 500 {object} map[string]string "Internal server error"
|
|
// @Router /jobs/analysis/top-matches [get]
|
|
func (h *JobHandler) GetTopMatches(w http.ResponseWriter, r *http.Request) error {
|
|
minScoreStr := r.URL.Query().Get("min_score")
|
|
minScore := 70 // default minimum score
|
|
|
|
if minScoreStr != "" {
|
|
var err error
|
|
minScore, err = strconv.Atoi(minScoreStr)
|
|
if err != nil {
|
|
return utils.NewAPIError(http.StatusBadRequest, fmt.Errorf("invalid minimum score"))
|
|
}
|
|
}
|
|
|
|
results, err := h.jobAnalysisResultRepo.GetAnalysisResultsByMatchScore(minScore)
|
|
if err != nil {
|
|
slog.Error("Failed to get top matches", "minScore", minScore, "error", err)
|
|
return utils.NewAPIError(http.StatusInternalServerError, err)
|
|
}
|
|
|
|
utils.WriteJSON(w, http.StatusOK, results)
|
|
return nil
|
|
}
|