package document_scraper import ( "errors" "tm/pkg/logger" "tm/pkg/response" "github.com/labstack/echo/v4" ) // Handler handles HTTP requests for the document scraper API type Handler struct { service Service logger logger.Logger } // NewHandler creates a new document scraper handler func NewHandler(service Service, logger logger.Logger) *Handler { return &Handler{ service: service, logger: logger, } } // ListPendingTenders retrieves tenders that need document scraping // @Summary List pending tenders for document scraping // @Description Retrieve tenders that have not yet been scraped for documents. Each item includes contract_folder_id, notice_publication_id, document_url, title, and description. Optionally filter by created_at range (Unix timestamps in seconds). By default only tenders with active deadlines are returned; set include_expired=true to include expired tenders. // @Tags Document-Scraper // @Produce json // @Param limit query int false "Number of items per page (default: 20, max: 100)" // @Param offset query int false "Number of items to skip (default: 0)" // @Param created_at_from query int64 false "Filter by created_at lower bound (Unix timestamp, seconds)" // @Param created_at_to query int64 false "Filter by created_at upper bound (Unix timestamp, seconds)" // @Param include_expired query bool false "When true, include tenders whose deadline has passed (default: false)" // @Success 200 {object} response.APIResponse{data=DocumentScraperListResponse} "List of pending tenders" // @Failure 400 {object} response.APIResponse "Invalid query parameters" // @Failure 401 {object} response.APIResponse "Invalid or missing API key" // @Failure 500 {object} response.APIResponse "Internal server error" // @Security ApiKeyAuth // @Router /api/v1/scraper/tenders [get] func (h *Handler) ListPendingTenders(c echo.Context) error { form, err := response.Parse[DocumentScraperListRequest](c) if err != nil { return response.ValidationError(c, "Invalid request data", err.Error()) } tenders, meta, err := h.service.ListPendingTenders(c.Request().Context(), *form) if err != nil { if errors.Is(err, ErrInvalidDateRange) { return response.BadRequest(c, "Invalid date range", err.Error()) } return response.InternalServerError(c, "Failed to list pending tenders") } return response.SuccessWithMeta(c, tenders, meta, "Pending tenders retrieved successfully") } // GetTenderByNoticeID retrieves a specific tender by its notice publication ID // @Summary Get tender by notice ID for document scraping // @Description Retrieve a specific tender by its notice publication ID (contract_folder_id, notice_publication_id, document_url, title, description). // @Tags Document-Scraper // @Produce json // @Param notice_id path string true "Notice Publication ID" // @Success 200 {object} response.APIResponse{data=DocumentScraperTenderResponse} "Tender details" // @Failure 400 {object} response.APIResponse "Invalid notice ID" // @Failure 401 {object} response.APIResponse "Invalid or missing API key" // @Failure 404 {object} response.APIResponse "Tender not found" // @Failure 500 {object} response.APIResponse "Internal server error" // @Security ApiKeyAuth // @Router /api/v1/scraper/tenders/{notice_id} [get] func (h *Handler) GetTenderByNoticeID(c echo.Context) error { noticeID := c.Param("notice_id") if noticeID == "" { return response.BadRequest(c, "Notice ID is required", "notice_id parameter cannot be empty") } tender, err := h.service.GetTenderByNoticeID(c.Request().Context(), noticeID) if err != nil { if err.Error() == "tender not found" { return response.NotFound(c, "Tender not found") } return response.InternalServerError(c, "Failed to get tender") } return response.Success(c, tender, "Tender retrieved successfully") }