Files
tp/main_dc/yalarba/api_yal/internal/domain/rating/handler.go
T
valitovgaziz ba2e3b9545 On branch main
modified:   main_dc/yalarba/api_yal/internal/domain/rating/dto.go
	new file:   main_dc/yalarba/api_yal/internal/domain/rating/handler.go
	new file:   main_dc/yalarba/api_yal/internal/domain/rating/router.go
	new file:   main_dc/yalarba/api_yal/internal/domain/rating/service.go
	modified:   main_dc/yalarba/api_yal/internal/router/router.go
add raing domain without test
2026-05-20 13:23:38 +05:00

463 lines
14 KiB
Go

package rating
import (
"encoding/json"
"net/http"
"strconv"
"api_yal/internal/logger"
"api_yal/internal/middleware"
"api_yal/internal/models"
"github.com/go-chi/chi/v5"
"go.uber.org/zap"
)
type RatingHandler struct {
service RatingService
}
// NewRatingHandler создает новый обработчик рейтингов
func NewRatingHandler(service RatingService) *RatingHandler {
return &RatingHandler{
service: service,
}
}
// CreateRating создает новый рейтинг
// @Summary Create a new rating
// @Tags ratings
// @Accept json
// @Produce json
// @Param request body CreateRatingRequest true "Rating data"
// @Success 201 {object} RatingResponse
// @Router /ratings [post]
func (h *RatingHandler) CreateRating(w http.ResponseWriter, r *http.Request) {
l := logger.Get()
userID, ok := middleware.GetUserID(r.Context())
if !ok {
l.Debug("Unauthorized: user ID not found in context")
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
var req CreateRatingRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
l.Debug("Invalid request body", zap.Error(err))
http.Error(w, "Invalid request body", http.StatusBadRequest)
return
}
rating, err := h.service.CreateRating(r.Context(), userID, &req)
if err != nil {
l.Error("Failed to create rating", zap.Error(err))
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(rating)
}
// GetRatingByID возвращает рейтинг по ID
// @Summary Get rating by ID
// @Tags ratings
// @Produce json
// @Param id path int true "Rating ID"
// @Success 200 {object} RatingResponse
// @Router /ratings/{id} [get]
func (h *RatingHandler) GetRatingByID(w http.ResponseWriter, r *http.Request) {
l := logger.Get()
idStr := chi.URLParam(r, "id")
id, err := strconv.ParseUint(idStr, 10, 32)
if err != nil {
http.Error(w, "Invalid rating ID", http.StatusBadRequest)
return
}
rating, err := h.service.GetRatingByID(r.Context(), uint(id))
if err != nil {
l.Error("Failed to get rating", zap.Error(err))
http.Error(w, err.Error(), http.StatusNotFound)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(rating)
}
// GetRatingByObjectAndPlatform возвращает рейтинг объекта по платформе
// @Summary Get rating by object ID and platform
// @Tags ratings
// @Produce json
// @Param objectID path int true "Object ID"
// @Param platform path string true "Platform (entrepreneur/tourist)"
// @Success 200 {object} RatingResponse
// @Router /ratings/object/{objectID}/platform/{platform} [get]
func (h *RatingHandler) GetRatingByObjectAndPlatform(w http.ResponseWriter, r *http.Request) {
l := logger.Get()
objectIDStr := chi.URLParam(r, "objectID")
objectID, err := strconv.ParseUint(objectIDStr, 10, 32)
if err != nil {
http.Error(w, "Invalid object ID", http.StatusBadRequest)
return
}
platform := models.PlatformType(chi.URLParam(r, "platform"))
if platform != models.PlatformEntrepreneur && platform != models.PlatformTourist {
http.Error(w, "Invalid platform", http.StatusBadRequest)
return
}
rating, err := h.service.GetRatingByObjectAndPlatform(r.Context(), uint(objectID), platform)
if err != nil {
l.Error("Failed to get rating", zap.Error(err))
http.Error(w, err.Error(), http.StatusNotFound)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(rating)
}
// UpdateRating обновляет рейтинг
// @Summary Update rating
// @Tags ratings
// @Accept json
// @Produce json
// @Param id path int true "Rating ID"
// @Param request body UpdateRatingRequest true "Update data"
// @Success 200 {object} RatingResponse
// @Router /ratings/{id} [put]
func (h *RatingHandler) UpdateRating(w http.ResponseWriter, r *http.Request) {
l := logger.Get()
idStr := chi.URLParam(r, "id")
id, err := strconv.ParseUint(idStr, 10, 32)
if err != nil {
http.Error(w, "Invalid rating ID", http.StatusBadRequest)
return
}
var req UpdateRatingRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
l.Debug("Invalid request body", zap.Error(err))
http.Error(w, "Invalid request body", http.StatusBadRequest)
return
}
rating, err := h.service.UpdateRating(r.Context(), uint(id), &req)
if err != nil {
l.Error("Failed to update rating", zap.Error(err))
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(rating)
}
// DeleteRating удаляет рейтинг
// @Summary Delete rating
// @Tags ratings
// @Param id path int true "Rating ID"
// @Success 204 "No Content"
// @Router /ratings/{id} [delete]
func (h *RatingHandler) DeleteRating(w http.ResponseWriter, r *http.Request) {
l := logger.Get()
idStr := chi.URLParam(r, "id")
id, err := strconv.ParseUint(idStr, 10, 32)
if err != nil {
http.Error(w, "Invalid rating ID", http.StatusBadRequest)
return
}
if err := h.service.DeleteRating(r.Context(), uint(id)); err != nil {
l.Error("Failed to delete rating", zap.Error(err))
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusNoContent)
}
// ListRatings возвращает список рейтингов
// @Summary List ratings
// @Tags ratings
// @Produce json
// @Param page query int false "Page number" default(1)
// @Param page_size query int false "Page size" default(20)
// @Param platform query string false "Filter by platform"
// @Param owner_id query int false "Filter by owner ID"
// @Param object_id query int false "Filter by object ID"
// @Success 200 {object} ListRatingsResponse
// @Router /ratings [get]
func (h *RatingHandler) ListRatings(w http.ResponseWriter, r *http.Request) {
l := logger.Get()
req := &ListRatingsRequest{}
// Парсинг query параметров
if pageStr := r.URL.Query().Get("page"); pageStr != "" {
if page, err := strconv.Atoi(pageStr); err == nil && page > 0 {
req.Page = page
}
}
if pageSizeStr := r.URL.Query().Get("page_size"); pageSizeStr != "" {
if pageSize, err := strconv.Atoi(pageSizeStr); err == nil && pageSize > 0 {
req.PageSize = pageSize
}
}
req.Platform = r.URL.Query().Get("platform")
if ownerIDStr := r.URL.Query().Get("owner_id"); ownerIDStr != "" {
if ownerID, err := strconv.ParseUint(ownerIDStr, 10, 32); err == nil {
req.OwnerID = uint(ownerID)
}
}
if objectIDStr := r.URL.Query().Get("object_id"); objectIDStr != "" {
if objectID, err := strconv.ParseUint(objectIDStr, 10, 32); err == nil {
req.ObjectID = uint(objectID)
}
}
var response *ListRatingsResponse
var err error
if req.ObjectID > 0 {
// Получаем все рейтинги объекта
ratings, err := h.service.GetRatingsByObject(r.Context(), req.ObjectID)
if err != nil {
l.Error("Failed to get ratings by object", zap.Error(err))
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
response = &ListRatingsResponse{
Ratings: ratings,
Total: int64(len(ratings)),
Page: 1,
PageSize: len(ratings),
TotalPages: 1,
}
} else if req.OwnerID > 0 {
response, err = h.service.GetRatingsByOwner(r.Context(), req.OwnerID, req)
} else {
response, err = h.service.ListRatings(r.Context(), req)
}
if err != nil {
l.Error("Failed to list ratings", zap.Error(err))
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(response)
}
// Vote голосование за объект
// @Summary Vote for an object
// @Tags ratings
// @Accept json
// @Produce json
// @Param request body VoteRequest true "Vote data"
// @Param targetID path int true "Target object ID"
// @Param platform path string true "Platform"
// @Success 200 {object} RatingResponse
// @Router /ratings/{targetID}/vote/{platform} [post]
func (h *RatingHandler) Vote(w http.ResponseWriter, r *http.Request) {
l := logger.Get()
userID, ok := middleware.GetUserID(r.Context())
if !ok {
l.Debug("Unauthorized: user ID not found in context")
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
targetIDStr := chi.URLParam(r, "targetID")
targetID, err := strconv.ParseUint(targetIDStr, 10, 32)
if err != nil {
http.Error(w, "Invalid target ID", http.StatusBadRequest)
return
}
platform := models.PlatformType(chi.URLParam(r, "platform"))
if platform != models.PlatformEntrepreneur && platform != models.PlatformTourist {
http.Error(w, "Invalid platform", http.StatusBadRequest)
return
}
var req VoteRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
l.Debug("Invalid request body", zap.Error(err))
http.Error(w, "Invalid request body", http.StatusBadRequest)
return
}
rating, err := h.service.Vote(r.Context(), userID, uint(targetID), platform, req.Score)
if err != nil {
l.Error("Failed to vote", zap.Error(err))
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(rating)
}
// GetMyVote возвращает голос текущего пользователя
// @Summary Get current user's vote
// @Tags ratings
// @Produce json
// @Param targetID path int true "Target object ID"
// @Param platform path string true "Platform"
// @Success 200 {object} UserRatingInfoResponse
// @Router /ratings/{targetID}/my-vote/{platform} [get]
func (h *RatingHandler) GetMyVote(w http.ResponseWriter, r *http.Request) {
l := logger.Get()
userID, ok := middleware.GetUserID(r.Context())
if !ok {
l.Debug("Unauthorized: user ID not found in context")
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
targetIDStr := chi.URLParam(r, "targetID")
targetID, err := strconv.ParseUint(targetIDStr, 10, 32)
if err != nil {
http.Error(w, "Invalid target ID", http.StatusBadRequest)
return
}
platform := models.PlatformType(chi.URLParam(r, "platform"))
if platform != models.PlatformEntrepreneur && platform != models.PlatformTourist {
http.Error(w, "Invalid platform", http.StatusBadRequest)
return
}
voteInfo, err := h.service.GetUserVote(r.Context(), userID, uint(targetID), platform)
if err != nil {
l.Error("Failed to get user vote", zap.Error(err))
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(voteInfo)
}
// UpdateMyVote обновляет голос текущего пользователя
// @Summary Update current user's vote
// @Tags ratings
// @Accept json
// @Produce json
// @Param targetID path int true "Target object ID"
// @Param platform path string true "Platform"
// @Param request body VoteRequest true "Vote data"
// @Success 200 {object} RatingResponse
// @Router /ratings/{targetID}/my-vote/{platform} [put]
func (h *RatingHandler) UpdateMyVote(w http.ResponseWriter, r *http.Request) {
l := logger.Get()
userID, ok := middleware.GetUserID(r.Context())
if !ok {
l.Debug("Unauthorized: user ID not found in context")
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
targetIDStr := chi.URLParam(r, "targetID")
targetID, err := strconv.ParseUint(targetIDStr, 10, 32)
if err != nil {
http.Error(w, "Invalid target ID", http.StatusBadRequest)
return
}
platform := models.PlatformType(chi.URLParam(r, "platform"))
if platform != models.PlatformEntrepreneur && platform != models.PlatformTourist {
http.Error(w, "Invalid platform", http.StatusBadRequest)
return
}
var req VoteRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
l.Debug("Invalid request body", zap.Error(err))
http.Error(w, "Invalid request body", http.StatusBadRequest)
return
}
rating, err := h.service.UpdateUserVote(r.Context(), userID, uint(targetID), platform, req.Score)
if err != nil {
l.Error("Failed to update vote", zap.Error(err))
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(rating)
}
// DeleteMyVote удаляет голос текущего пользователя
// @Summary Delete current user's vote
// @Tags ratings
// @Param targetID path int true "Target object ID"
// @Param platform path string true "Platform"
// @Success 204 "No Content"
// @Router /ratings/{targetID}/my-vote/{platform} [delete]
func (h *RatingHandler) DeleteMyVote(w http.ResponseWriter, r *http.Request) {
l := logger.Get()
userID, ok := middleware.GetUserID(r.Context())
if !ok {
l.Debug("Unauthorized: user ID not found in context")
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
targetIDStr := chi.URLParam(r, "targetID")
targetID, err := strconv.ParseUint(targetIDStr, 10, 32)
if err != nil {
http.Error(w, "Invalid target ID", http.StatusBadRequest)
return
}
platform := models.PlatformType(chi.URLParam(r, "platform"))
if platform != models.PlatformEntrepreneur && platform != models.PlatformTourist {
http.Error(w, "Invalid platform", http.StatusBadRequest)
return
}
if err := h.service.DeleteUserVote(r.Context(), userID, uint(targetID), platform); err != nil {
l.Error("Failed to delete vote", zap.Error(err))
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.WriteHeader(http.StatusNoContent)
}
// GetRatingStats возвращает статистику по рейтингам
// @Summary Get rating statistics
// @Tags ratings
// @Produce json
// @Success 200 {object} map[string]interface{}
// @Router /ratings/stats [get]
func (h *RatingHandler) GetRatingStats(w http.ResponseWriter, r *http.Request) {
l := logger.Get()
stats, err := h.service.GetRatingStats(r.Context())
if err != nil {
l.Error("Failed to get rating stats", zap.Error(err))
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(stats)
}