package http_router import ( "context" "encoding/json" "log/slog" "net/http" "git-molva.ru/Molva/molva-backend/services/api_gateway/internal/constants" rmodel "git-molva.ru/Molva/molva-backend/services/api_gateway/internal/request_model" "github.com/gorilla/mux" ) // TODO: review func (h *handler) setVacancyLogoLinks( ctx context.Context, vacancyList *rmodel.VacancyListGetResponse, ) { const handlerName = "setVacancyLogoLinks" for _, vacancy := range vacancyList.Vacancies { logoLink, err := h.getLogoLinkWithCache(ctx, vacancy.Company.Id) if err != nil { h.logger.Warn("error getting logo link", slog.String("error", err.Error()), slog.String("vacancy_id", vacancy.Id), slog.String("handler", handlerName), ) continue } vacancy.Company.LogoLink = &logoLink } } // @Summary Получить список вакансий для агента // @Description Получение списка вакансий с возможностью фильтрации // @Tags agents // @Accept json // @Produce json // @Param agent_id path string true "ID агента" // @Param distributor_id query string false "ID дистрибьютора" // @Param company_id query string false "ID компании" // @Param region query string false "Регион" // @Param salary_bottom query int false "Минимальная зарплата" // @Param salary_top query int false "Максимальная зарплата" // @Param is_archived query bool false "Архивные вакансии" // @Param status query string false "Статус вакансии" // @Param page query int false "Номер страницы" // @Param page_size query int false "Размер страницы" // @Success 200 {object} rmodel.VacancyListGetResponse "Список вакансий" // @Failure 400 {object} map[string]string "Неверные данные запроса" // @Failure 401 {object} map[string]string "Неавторизованный доступ" // @Failure 500 {object} map[string]string "Внутренняя ошибка сервера" // @Security BearerAuth // @Router /api/v1/agents/{agent_id}/vacancies [get] func (h *handler) getVacancyListAgentHandler(w http.ResponseWriter, r *http.Request) { const handlerName = "getVacancyListAgentHandler" request, err := new(rmodel.VacancyListGetRequest).FromQuery(r.URL.Query()) if err != nil { http.Error(w, constants.ErrBadRequest.Error(), http.StatusBadRequest) h.logger.Error("error parsing request: ", slog.String("error", err.Error()), slog.String("handler", handlerName)) return } result, err := h.agentService.GetVacancyList(r.Context(), request) if err != nil { h.handleAgentError(w, err) h.logger.Error("error getting vacancy list", slog.String("error", err.Error()), slog.String("handler", handlerName), ) return } h.setVacancyLogoLinks(r.Context(), result) w.Header().Set("Content-Type", "application/json") if err := json.NewEncoder(w).Encode(result); err != nil { http.Error(w, constants.ErrInternalServerError.Error(), http.StatusInternalServerError) h.logger.Error("error encoding response", slog.String("error", err.Error()), slog.String("handler", handlerName), ) } } // @Summary Получить список вакансий дистрибьютора // @Description Получение списка вакансий дистрибьютора с возможностью фильтрации // @Tags distributors // @Accept json // @Produce json // @Param distributor_id path string true "ID дистрибьютора" // @Param company_id query string false "ID компании" // @Param region query string false "Регион" // @Param salary_bottom query int false "Минимальная зарплата" // @Param salary_top query int false "Максимальная зарплата" // @Param is_archived query bool false "Архивные вакансии" // @Param status query string false "Статус вакансии" // @Param page query int false "Номер страницы" // @Param page_size query int false "Размер страницы" // @Success 200 {object} rmodel.VacancyListGetResponse "Список вакансий" // @Failure 400 {object} map[string]string "Неверные данные запроса" // @Failure 401 {object} map[string]string "Неавторизованный доступ" // @Failure 500 {object} map[string]string "Внутренняя ошибка сервера" // @Security BearerAuth // @Router /api/v1/distributor/{distributor_id}/vacancies [get] func (h *handler) getVacancyListDistributorHandler(w http.ResponseWriter, r *http.Request) { const handlerName = "getVacancyListDistributorHandler" request, err := new(rmodel.VacancyListGetRequest).FromQuery(r.URL.Query()) if err != nil { http.Error(w, constants.ErrBadRequest.Error(), http.StatusBadRequest) h.logger.Error("error parsing request: ", slog.String("error", err.Error()), slog.String("handler", handlerName)) return } result, err := h.distributorService.GetVacancyList(r.Context(), request) if err != nil { h.handleDistributorError(w, err) h.logger.Error("error getting vacancy list", slog.String("error", err.Error()), slog.String("handler", handlerName), ) return } w.Header().Set("Content-Type", "application/json") if err := json.NewEncoder(w).Encode(result); err != nil { http.Error(w, constants.ErrInternalServerError.Error(), http.StatusInternalServerError) h.logger.Error("error encoding response", slog.String("error", err.Error()), slog.String("handler", handlerName), ) } } // @Summary Создать вакансию // @Description Создание новой вакансии дистрибьютором // @Tags distributors // @Accept json // @Produce json // @Param distributor_id path string true "ID дистрибьютора" // @Param request body rmodel.VacancyCreateRequest true "Данные для создания вакансии" // @Success 201 {object} rmodel.VacancyCreateResponse "Вакансия создана" // @Failure 400 {object} map[string]string "Неверные данные запроса" // @Failure 401 {object} map[string]string "Неавторизованный доступ" // @Failure 500 {object} map[string]string "Внутренняя ошибка сервера" // @Security BearerAuth // @Router /api/v1/distributor/{distributor_id}/vacancies [post] func (h *handler) createVacancyDistributorHandler(w http.ResponseWriter, r *http.Request) { const handlerName = "createVacancyDistributorHandler" var ( vars = mux.Vars(r) distId = vars["distributor_id"] ) var request rmodel.VacancyCreateRequest if err := json.NewDecoder(r.Body).Decode(&request); err != nil { http.Error(w, constants.ErrBadRequest.Error(), http.StatusBadRequest) h.logger.Error("error unmarshalling request: ", slog.String("error", err.Error()), slog.String("handler", handlerName)) return } defer r.Body.Close() result, err := h.distributorService.CreateVacancy(r.Context(), &request) if err != nil { h.handleDistributorError(w, err) h.logger.Error("error creating vacancy", slog.String("error", err.Error()), slog.String("handler", handlerName), ) return } go h.createSetDistributorVacancyEvent( context.Background(), distId, result.Id, request.Name, handlerName, ) w.WriteHeader(http.StatusCreated) w.Header().Set("Content-Type", "application/json") if err := json.NewEncoder(w).Encode(result); err != nil { http.Error(w, constants.ErrInternalServerError.Error(), http.StatusInternalServerError) h.logger.Error("error encoding response", slog.String("error", err.Error()), slog.String("handler", handlerName), ) } } // @Summary Обновить вакансию // @Description Обновление информации о вакансии дистрибьютора // @Tags distributors // @Accept json // @Produce json // @Param distributor_id path string true "ID дистрибьютора" // @Param vacancy_id path string true "ID вакансии" // @Param request body rmodel.VacancyUpdateRequest true "Данные для обновления" // @Success 204 "Вакансия обновлена" // @Failure 400 {object} map[string]string "Неверные данные запроса" // @Failure 401 {object} map[string]string "Неавторизованный доступ" // @Failure 404 {object} map[string]string "Вакансия не найдена" // @Failure 500 {object} map[string]string "Внутренняя ошибка сервера" // @Security BearerAuth // @Router /api/v1/distributor/{distributor_id}/vacancies/{vacancy_id} [patch] func (h *handler) updateVacancyDistributorHandler(w http.ResponseWriter, r *http.Request) { const handlerName = "updateVacancyDistributorHandler" var ( vars = mux.Vars(r) distId = vars["distributor_id"] vacancyId = vars["vacancy_id"] ) var request rmodel.VacancyUpdateRequest if err := json.NewDecoder(r.Body).Decode(&request); err != nil { http.Error(w, constants.ErrBadRequest.Error(), http.StatusBadRequest) h.logger.Error("error unmarshalling request: ", slog.String("error", err.Error()), slog.String("handler", handlerName), ) return } request.Id = vacancyId if _, err := h.distributorService.UpdateVacancy(r.Context(), &request); err != nil { h.handleDistributorError(w, err) h.logger.Error("error updating vacancy", slog.String("error", err.Error()), slog.String("handler", handlerName), ) return } go h.createEditDistributorVacancyEvent( context.Background(), distId, vacancyId, handlerName, ) w.WriteHeader(http.StatusNoContent) } // @Summary Удалить вакансию // @Description Удаление вакансии дистрибьютора // @Tags distributors // @Accept json // @Produce json // @Param distributor_id path string true "ID дистрибьютора" // @Param vacancy_id path string true "ID вакансии" // @Success 204 "Вакансия удалена" // @Failure 400 {object} map[string]string "Неверные данные запроса" // @Failure 401 {object} map[string]string "Неавторизованный доступ" // @Failure 404 {object} map[string]string "Вакансия не найдена" // @Failure 500 {object} map[string]string "Внутренняя ошибка сервера" // @Security BearerAuth // @Router /api/v1/distributor/{distributor_id}/vacancies/{vacancy_id} [delete] func (h *handler) deleteVacancyDistributorHandler(w http.ResponseWriter, r *http.Request) { const handlerName = "deleteDistributorVacancyHandler" var ( vars = mux.Vars(r) distId = vars["distributor_id"] vacancyId = vars["vacancy_id"] ) if _, err := h.distributorService.DeleteVacancy(r.Context(), &rmodel.VacancyDeleteRequest{ Id: vacancyId, }); err != nil { h.handleDistributorError(w, err) h.logger.Error("error deleting vacancy", slog.String("error", err.Error()), slog.String("handler", handlerName), ) return } go func(hdn *handler) { if err := h.feed.CancelEvent(r.Context(), vacancyId, "Вакансия была удалена"); err != nil { h.logger.Error("failed to cancel feed event", slog.String("error", err.Error()), slog.String("handler", handlerName), slog.String("vacancy_id", vacancyId), slog.String("distributor_id", distId)) } }(h) w.WriteHeader(http.StatusNoContent) } // @Summary Отправить вакансию на модерацию // @Description Отправка вакансии дистрибьютора на модерацию // @Tags distributors // @Accept json // @Produce json // @Param distributor_id path string true "ID дистрибьютора" // @Param vacancy_id path string true "ID вакансии" // @Success 200 {object} map[string]string "Вакансия отправлена на модерацию" // @Failure 400 {object} map[string]string "Неверные параметры запроса" // @Failure 500 {object} map[string]string "Внутренняя ошибка сервера" // @Security BearerAuth // @Router /api/v1/distributor/{distributor_id}/vacancies/{vacancy_id}/moderation [post] func (h *handler) sendVacancyToModerationHandler(w http.ResponseWriter, r *http.Request) { const handlerName = "sendVacancyToModerationHandler" var ( vars = mux.Vars(r) distId = vars["distributor_id"] vacancyId = vars["vacancy_id"] ) if _, err := h.distributorService.SendVacancyToModeration(r.Context(), &rmodel.SendVacancyToModerationRequest{ Id: vacancyId, }); err != nil { h.handleDistributorError(w, err) h.logger.Error("error sending vacancy to moderation", slog.String("error", err.Error()), slog.String("handler", handlerName), ) return } go h.createSendVacancyToModerationEvent( context.Background(), distId, vacancyId, handlerName, ) w.WriteHeader(http.StatusNoContent) }