This commit is contained in:
2026-05-19 14:16:43 +05:00
parent 894415e3ac
commit 42549eb116
4 changed files with 423 additions and 39 deletions
@@ -6,6 +6,7 @@ import (
"strconv" "strconv"
"api_yal/internal/logger" "api_yal/internal/logger"
"api_yal/internal/middleware"
"api_yal/internal/models" "api_yal/internal/models"
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
@@ -24,21 +25,22 @@ func NewFeedbackHandler(service FeedbackService) *FeedbackHandler {
// CreateFeedback создает новый отзыв // CreateFeedback создает новый отзыв
func (h *FeedbackHandler) CreateFeedback(w http.ResponseWriter, r *http.Request) { func (h *FeedbackHandler) CreateFeedback(w http.ResponseWriter, r *http.Request) {
var feedback models.Feedback var req CreateFeedbackRequest
if err := json.NewDecoder(r.Body).Decode(&feedback); err != nil { if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "Invalid request body", http.StatusBadRequest) http.Error(w, "Invalid request body", http.StatusBadRequest)
return return
} }
if err := h.service.Create(r.Context(), &feedback); err != nil { response, err := h.service.Create(r.Context(), &req)
if err != nil {
logger.Get().Error("Failed to create feedback", zap.Error(err)) logger.Get().Error("Failed to create feedback", zap.Error(err))
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusBadRequest)
return return
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusCreated) w.WriteHeader(http.StatusCreated)
json.NewEncoder(w).Encode(feedback) json.NewEncoder(w).Encode(response)
} }
// GetFeedbackByID возвращает отзыв по ID // GetFeedbackByID возвращает отзыв по ID
@@ -50,7 +52,7 @@ func (h *FeedbackHandler) GetFeedbackByID(w http.ResponseWriter, r *http.Request
return return
} }
feedback, err := h.service.GetByID(r.Context(), uint(id)) response, err := h.service.GetByID(r.Context(), uint(id))
if err != nil { if err != nil {
logger.Get().Error("Failed to get feedback", zap.Error(err)) logger.Get().Error("Failed to get feedback", zap.Error(err))
http.Error(w, err.Error(), http.StatusNotFound) http.Error(w, err.Error(), http.StatusNotFound)
@@ -58,7 +60,7 @@ func (h *FeedbackHandler) GetFeedbackByID(w http.ResponseWriter, r *http.Request
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(feedback) json.NewEncoder(w).Encode(response)
} }
// UpdateFeedback обновляет существующий отзыв // UpdateFeedback обновляет существующий отзыв
@@ -70,21 +72,21 @@ func (h *FeedbackHandler) UpdateFeedback(w http.ResponseWriter, r *http.Request)
return return
} }
var feedback models.Feedback var req UpdateFeedbackRequest
if err := json.NewDecoder(r.Body).Decode(&feedback); err != nil { if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "Invalid request body", http.StatusBadRequest) http.Error(w, "Invalid request body", http.StatusBadRequest)
return return
} }
feedback.ID = uint(id)
if err := h.service.Update(r.Context(), &feedback); err != nil { response, err := h.service.Update(r.Context(), uint(id), &req)
if err != nil {
logger.Get().Error("Failed to update feedback", zap.Error(err)) logger.Get().Error("Failed to update feedback", zap.Error(err))
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusBadRequest)
return return
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(feedback) json.NewEncoder(w).Encode(response)
} }
// DeleteFeedback удаляет отзыв // DeleteFeedback удаляет отзыв
@@ -98,7 +100,7 @@ func (h *FeedbackHandler) DeleteFeedback(w http.ResponseWriter, r *http.Request)
if err := h.service.Delete(r.Context(), uint(id)); err != nil { if err := h.service.Delete(r.Context(), uint(id)); err != nil {
logger.Get().Error("Failed to delete feedback", zap.Error(err)) logger.Get().Error("Failed to delete feedback", zap.Error(err))
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusBadRequest)
return return
} }
@@ -120,7 +122,7 @@ func (h *FeedbackHandler) ListFeedbacks(w http.ResponseWriter, r *http.Request)
pageSize = 100 pageSize = 100
} }
feedbacks, total, err := h.service.List(r.Context(), page, pageSize) response, err := h.service.List(r.Context(), page, pageSize)
if err != nil { if err != nil {
logger.Get().Error("Failed to list feedbacks", zap.Error(err)) logger.Get().Error("Failed to list feedbacks", zap.Error(err))
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
@@ -128,15 +130,16 @@ func (h *FeedbackHandler) ListFeedbacks(w http.ResponseWriter, r *http.Request)
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
w.Header().Set("X-Total-Count", strconv.FormatInt(total, 10)) json.NewEncoder(w).Encode(response)
json.NewEncoder(w).Encode(feedbacks)
} }
// GetMyFeedbacks возвращает отзывы текущего пользователя // GetMyFeedbacks возвращает отзывы текущего пользователя
func (h *FeedbackHandler) GetMyFeedbacks(w http.ResponseWriter, r *http.Request) { func (h *FeedbackHandler) GetMyFeedbacks(w http.ResponseWriter, r *http.Request) {
// Здесь нужно получить ownerID из JWT токена userID, ok := middleware.GetUserID(r.Context())
// Для примера используем заглушку if !ok {
ownerID := uint(1) // TODO: Get from context http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
page, _ := strconv.Atoi(r.URL.Query().Get("page")) page, _ := strconv.Atoi(r.URL.Query().Get("page"))
pageSize, _ := strconv.Atoi(r.URL.Query().Get("page_size")) pageSize, _ := strconv.Atoi(r.URL.Query().Get("page_size"))
@@ -147,8 +150,11 @@ func (h *FeedbackHandler) GetMyFeedbacks(w http.ResponseWriter, r *http.Request)
if pageSize <= 0 { if pageSize <= 0 {
pageSize = 10 pageSize = 10
} }
if pageSize > 100 {
pageSize = 100
}
feedbacks, err := h.service.ListByOwner(r.Context(), ownerID, page, pageSize) response, err := h.service.ListByOwner(r.Context(), userID, page, pageSize)
if err != nil { if err != nil {
logger.Get().Error("Failed to get user feedbacks", zap.Error(err)) logger.Get().Error("Failed to get user feedbacks", zap.Error(err))
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
@@ -156,7 +162,7 @@ func (h *FeedbackHandler) GetMyFeedbacks(w http.ResponseWriter, r *http.Request)
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(feedbacks) json.NewEncoder(w).Encode(response)
} }
// GetFeedbacksByObject возвращает отзывы по объекту // GetFeedbacksByObject возвращает отзывы по объекту
@@ -171,7 +177,17 @@ func (h *FeedbackHandler) GetFeedbacksByObject(w http.ResponseWriter, r *http.Re
page, _ := strconv.Atoi(r.URL.Query().Get("page")) page, _ := strconv.Atoi(r.URL.Query().Get("page"))
pageSize, _ := strconv.Atoi(r.URL.Query().Get("page_size")) pageSize, _ := strconv.Atoi(r.URL.Query().Get("page_size"))
feedbacks, err := h.service.ListByObject(r.Context(), uint(objectID), page, pageSize) if page <= 0 {
page = 1
}
if pageSize <= 0 {
pageSize = 10
}
if pageSize > 100 {
pageSize = 100
}
response, err := h.service.ListByObject(r.Context(), uint(objectID), page, pageSize)
if err != nil { if err != nil {
logger.Get().Error("Failed to get object feedbacks", zap.Error(err)) logger.Get().Error("Failed to get object feedbacks", zap.Error(err))
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
@@ -179,7 +195,7 @@ func (h *FeedbackHandler) GetFeedbacksByObject(w http.ResponseWriter, r *http.Re
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(feedbacks) json.NewEncoder(w).Encode(response)
} }
// GetFeedbacksByPlatform возвращает отзывы по платформе // GetFeedbacksByPlatform возвращает отзывы по платформе
@@ -190,7 +206,17 @@ func (h *FeedbackHandler) GetFeedbacksByPlatform(w http.ResponseWriter, r *http.
page, _ := strconv.Atoi(r.URL.Query().Get("page")) page, _ := strconv.Atoi(r.URL.Query().Get("page"))
pageSize, _ := strconv.Atoi(r.URL.Query().Get("page_size")) pageSize, _ := strconv.Atoi(r.URL.Query().Get("page_size"))
feedbacks, err := h.service.ListByPlatform(r.Context(), platform, page, pageSize) if page <= 0 {
page = 1
}
if pageSize <= 0 {
pageSize = 10
}
if pageSize > 100 {
pageSize = 100
}
response, err := h.service.ListByPlatform(r.Context(), platform, page, pageSize)
if err != nil { if err != nil {
logger.Get().Error("Failed to get platform feedbacks", zap.Error(err)) logger.Get().Error("Failed to get platform feedbacks", zap.Error(err))
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
@@ -198,7 +224,7 @@ func (h *FeedbackHandler) GetFeedbacksByPlatform(w http.ResponseWriter, r *http.
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(feedbacks) json.NewEncoder(w).Encode(response)
} }
// SearchFeedbacks ищет отзывы по тексту // SearchFeedbacks ищет отзывы по тексту
@@ -212,7 +238,17 @@ func (h *FeedbackHandler) SearchFeedbacks(w http.ResponseWriter, r *http.Request
page, _ := strconv.Atoi(r.URL.Query().Get("page")) page, _ := strconv.Atoi(r.URL.Query().Get("page"))
pageSize, _ := strconv.Atoi(r.URL.Query().Get("page_size")) pageSize, _ := strconv.Atoi(r.URL.Query().Get("page_size"))
feedbacks, err := h.service.Search(r.Context(), query, page, pageSize) if page <= 0 {
page = 1
}
if pageSize <= 0 {
pageSize = 10
}
if pageSize > 100 {
pageSize = 100
}
response, err := h.service.Search(r.Context(), query, page, pageSize)
if err != nil { if err != nil {
logger.Get().Error("Failed to search feedbacks", zap.Error(err)) logger.Get().Error("Failed to search feedbacks", zap.Error(err))
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
@@ -220,7 +256,20 @@ func (h *FeedbackHandler) SearchFeedbacks(w http.ResponseWriter, r *http.Request
} }
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(feedbacks) json.NewEncoder(w).Encode(response)
}
// GetFeedbackStats возвращает статистику по отзывам
func (h *FeedbackHandler) GetFeedbackStats(w http.ResponseWriter, r *http.Request) {
stats, err := h.service.GetStats(r.Context())
if err != nil {
logger.Get().Error("Failed to get feedback stats", zap.Error(err))
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(stats)
} }
// GetFeedbackComments возвращает комментарии к отзыву // GetFeedbackComments возвращает комментарии к отзыву
@@ -235,15 +284,33 @@ func (h *FeedbackHandler) GetFeedbackComments(w http.ResponseWriter, r *http.Req
page, _ := strconv.Atoi(r.URL.Query().Get("page")) page, _ := strconv.Atoi(r.URL.Query().Get("page"))
pageSize, _ := strconv.Atoi(r.URL.Query().Get("page_size")) pageSize, _ := strconv.Atoi(r.URL.Query().Get("page_size"))
comments, err := h.service.GetComments(r.Context(), uint(id), page, pageSize) if page <= 0 {
page = 1
}
if pageSize <= 0 {
pageSize = 10
}
if pageSize > 100 {
pageSize = 100
}
comments, total, err := h.service.GetComments(r.Context(), uint(id), page, pageSize)
if err != nil { if err != nil {
logger.Get().Error("Failed to get comments", zap.Error(err)) logger.Get().Error("Failed to get comments", zap.Error(err))
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusInternalServerError)
return return
} }
response := map[string]interface{}{
"items": comments,
"total": total,
"page": page,
"page_size": pageSize,
"total_pages": int((total + int64(pageSize) - 1) / int64(pageSize)),
}
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(comments) json.NewEncoder(w).Encode(response)
} }
// AddComment добавляет комментарий к отзыву // AddComment добавляет комментарий к отзыву
@@ -255,15 +322,18 @@ func (h *FeedbackHandler) AddComment(w http.ResponseWriter, r *http.Request) {
return return
} }
var comment models.Comment var req struct {
if err := json.NewDecoder(r.Body).Decode(&comment); err != nil { Text string `json:"text" binding:"required"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "Invalid request body", http.StatusBadRequest) http.Error(w, "Invalid request body", http.StatusBadRequest)
return return
} }
if err := h.service.AddComment(r.Context(), uint(id), &comment); err != nil { comment, err := h.service.AddComment(r.Context(), uint(id), req.Text)
if err != nil {
logger.Get().Error("Failed to add comment", zap.Error(err)) logger.Get().Error("Failed to add comment", zap.Error(err))
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusBadRequest)
return return
} }
@@ -282,7 +352,7 @@ func (h *FeedbackHandler) UpdateComment(w http.ResponseWriter, r *http.Request)
} }
var req struct { var req struct {
Text string `json:"text"` Text string `json:"text" binding:"required"`
} }
if err := json.NewDecoder(r.Body).Decode(&req); err != nil { if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "Invalid request body", http.StatusBadRequest) http.Error(w, "Invalid request body", http.StatusBadRequest)
@@ -291,7 +361,7 @@ func (h *FeedbackHandler) UpdateComment(w http.ResponseWriter, r *http.Request)
if err := h.service.UpdateComment(r.Context(), uint(commentID), req.Text); err != nil { if err := h.service.UpdateComment(r.Context(), uint(commentID), req.Text); err != nil {
logger.Get().Error("Failed to update comment", zap.Error(err)) logger.Get().Error("Failed to update comment", zap.Error(err))
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusBadRequest)
return return
} }
@@ -310,7 +380,7 @@ func (h *FeedbackHandler) DeleteComment(w http.ResponseWriter, r *http.Request)
if err := h.service.DeleteComment(r.Context(), uint(commentID)); err != nil { if err := h.service.DeleteComment(r.Context(), uint(commentID)); err != nil {
logger.Get().Error("Failed to delete comment", zap.Error(err)) logger.Get().Error("Failed to delete comment", zap.Error(err))
http.Error(w, err.Error(), http.StatusInternalServerError) http.Error(w, err.Error(), http.StatusBadRequest)
return return
} }
@@ -580,3 +580,170 @@ func (s *feedbackServiceImpl) isValidPlatform(platform models.PlatformType) bool
} }
return false return false
} }
// Добавьте в конец файла service.go:
// AddComment добавляет комментарий к отзыву
func (s *feedbackServiceImpl) AddComment(ctx context.Context, feedbackID uint, text string) (*models.Comment, error) {
if feedbackID == 0 {
return nil, errors.New("invalid feedback ID")
}
if strings.TrimSpace(text) == "" {
return nil, errors.New("comment text cannot be empty")
}
if len(text) > 1000 {
return nil, errors.New("comment text cannot exceed 1000 characters")
}
// Проверяем существование отзыва
_, err := s.feedbackRepository.GetByID(feedbackID)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, fmt.Errorf("feedback with ID %d not found", feedbackID)
}
return nil, fmt.Errorf("failed to get feedback: %w", err)
}
// Получаем userID из контекста
userID, ok := ctx.Value(middleware.UserIDKey).(uint)
if !ok {
return nil, errors.New("unauthorized")
}
comment := &models.Comment{
FeedbackID: feedbackID,
UserID: userID,
Text: text,
}
if err := s.feedbackRepository.CreateComment(comment); err != nil {
return nil, fmt.Errorf("failed to create comment: %w", err)
}
// Обновляем счетчик комментариев
if err := s.updateCommentCount(feedbackID); err != nil {
// Логируем ошибку, но не возвращаем, так как комментарий уже создан
_ = err
}
return comment, nil
}
// GetComments возвращает комментарии к отзыву
func (s *feedbackServiceImpl) GetComments(ctx context.Context, feedbackID uint, page, pageSize int) ([]models.Comment, int64, error) {
if feedbackID == 0 {
return nil, 0, errors.New("invalid feedback ID")
}
// Проверяем существование отзыва
_, err := s.feedbackRepository.GetByID(feedbackID)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, 0, fmt.Errorf("feedback with ID %d not found", feedbackID)
}
return nil, 0, fmt.Errorf("failed to get feedback: %w", err)
}
offset, limit := s.normalizePagination(page, pageSize)
comments, err := s.feedbackRepository.GetComments(feedbackID, offset, limit)
if err != nil {
return nil, 0, fmt.Errorf("failed to get comments: %w", err)
}
total, err := s.feedbackRepository.GetCommentCount(feedbackID)
if err != nil {
return nil, 0, fmt.Errorf("failed to count comments: %w", err)
}
return comments, int64(total), nil
}
// UpdateComment обновляет комментарий
func (s *feedbackServiceImpl) UpdateComment(ctx context.Context, commentID uint, text string) error {
if commentID == 0 {
return errors.New("invalid comment ID")
}
if strings.TrimSpace(text) == "" {
return errors.New("comment text cannot be empty")
}
if len(text) > 1000 {
return errors.New("comment text cannot exceed 1000 characters")
}
comment, err := s.feedbackRepository.GetCommentByID(commentID)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return fmt.Errorf("comment with ID %d not found", commentID)
}
return fmt.Errorf("failed to get comment: %w", err)
}
// Проверяем, что текущий пользователь является владельцем
userID, ok := ctx.Value(middleware.UserIDKey).(uint)
if !ok {
return errors.New("unauthorized")
}
if comment.UserID != userID {
return errors.New("unauthorized: cannot update comment owned by another user")
}
comment.Text = text
if err := s.feedbackRepository.UpdateComment(comment); err != nil {
return fmt.Errorf("failed to update comment: %w", err)
}
return nil
}
// DeleteComment удаляет комментарий
func (s *feedbackServiceImpl) DeleteComment(ctx context.Context, commentID uint) error {
if commentID == 0 {
return errors.New("invalid comment ID")
}
comment, err := s.feedbackRepository.GetCommentByID(commentID)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return fmt.Errorf("comment with ID %d not found", commentID)
}
return fmt.Errorf("failed to get comment: %w", err)
}
// Проверяем, что текущий пользователь является владельцем
userID, ok := ctx.Value(middleware.UserIDKey).(uint)
if !ok {
return errors.New("unauthorized")
}
if comment.UserID != userID {
return errors.New("unauthorized: cannot delete comment owned by another user")
}
if err := s.feedbackRepository.DeleteComment(commentID); err != nil {
return fmt.Errorf("failed to delete comment: %w", err)
}
// Обновляем счетчик комментариев
if err := s.updateCommentCount(comment.FeedbackID); err != nil {
// Логируем ошибку, но не возвращаем
_ = err
}
return nil
}
// updateCommentCount обновляет счетчик комментариев у отзыва
func (s *feedbackServiceImpl) updateCommentCount(feedbackID uint) error {
count, err := s.feedbackRepository.GetCommentCount(feedbackID)
if err != nil {
return err
}
return s.feedbackRepository.UpdateCommentCount(feedbackID, count)
}
@@ -5,6 +5,7 @@ import (
) )
// FeedbackRepository интерфейс для операций с моделью Feedback // FeedbackRepository интерфейс для операций с моделью Feedback
//
//go:generate mockgen -destination=mocks/feedback_repository.go -package=mocks . FeedbackRepository //go:generate mockgen -destination=mocks/feedback_repository.go -package=mocks . FeedbackRepository
type FeedbackRepository interface { type FeedbackRepository interface {
// Create создает новый отзыв // Create создает новый отзыв
@@ -51,4 +52,26 @@ type FeedbackRepository interface {
// Search находит отзывы по тексту // Search находит отзывы по тексту
Search(query string, offset, limit int) ([]models.Feedback, error) Search(query string, offset, limit int) ([]models.Feedback, error)
// Добавьте в интерфейс FeedbackRepository:
// Comment methods
CreateComment(comment *models.Comment) error
GetCommentByID(id uint) (*models.Comment, error)
UpdateComment(comment *models.Comment) error
DeleteComment(id uint) error
// Additional methods for stats
GetAverageScore() (float64, error)
GetPlatformStats() (map[models.PlatformType]int, error)
GetScoreDistribution() (map[int]int, error)
// Count methods
CountByOwner(ownerID uint) (int64, error)
CountByObject(objectID uint) (int64, error)
CountByPlatform(platform models.PlatformType) (int64, error)
CountBySearch(query string) (int64, error)
// GetObject by ID (general method)
GetObjectByID(id uint) (*models.Object, error)
} }
@@ -157,3 +157,127 @@ func (r *feedbackRepositoryImpl) getObjectByID(id uint) (*models.Object, error)
} }
return &object, nil return &object, nil
} }
// CreateComment создает новый комментарий
func (r *feedbackRepositoryImpl) CreateComment(comment *models.Comment) error {
return r.db.Create(comment).Error
}
// GetCommentByID возвращает комментарий по ID
func (r *feedbackRepositoryImpl) GetCommentByID(id uint) (*models.Comment, error) {
var comment models.Comment
err := r.db.First(&comment, id).Error
if err != nil {
return nil, err
}
return &comment, nil
}
// UpdateComment обновляет комментарий
func (r *feedbackRepositoryImpl) UpdateComment(comment *models.Comment) error {
return r.db.Save(comment).Error
}
// DeleteComment удаляет комментарий
func (r *feedbackRepositoryImpl) DeleteComment(id uint) error {
return r.db.Delete(&models.Comment{}, id).Error
}
// GetAverageScore возвращает средний балл отзывов
func (r *feedbackRepositoryImpl) GetAverageScore() (float64, error) {
var avg float64
err := r.db.Model(&models.Feedback{}).Select("COALESCE(AVG(score), 0)").Scan(&avg).Error
return avg, err
}
// GetPlatformStats возвращает статистику по платформам
func (r *feedbackRepositoryImpl) GetPlatformStats() (map[models.PlatformType]int, error) {
type Result struct {
Platform models.PlatformType
Count int
}
var results []Result
err := r.db.Model(&models.Feedback{}).
Select("platform, COUNT(*) as count").
Group("platform").
Scan(&results).Error
if err != nil {
return nil, err
}
stats := make(map[models.PlatformType]int)
for _, r := range results {
stats[r.Platform] = r.Count
}
return stats, nil
}
// GetScoreDistribution возвращает распределение оценок
func (r *feedbackRepositoryImpl) GetScoreDistribution() (map[int]int, error) {
type Result struct {
Score int
Count int
}
var results []Result
err := r.db.Model(&models.Feedback{}).
Select("score, COUNT(*) as count").
Group("score").
Scan(&results).Error
if err != nil {
return nil, err
}
distribution := make(map[int]int)
for i := 1; i <= 5; i++ {
distribution[i] = 0
}
for _, r := range results {
distribution[r.Score] = r.Count
}
return distribution, nil
}
// CountByOwner возвращает количество отзывов владельца
func (r *feedbackRepositoryImpl) CountByOwner(ownerID uint) (int64, error) {
var count int64
err := r.db.Model(&models.Feedback{}).Where("owner_id = ?", ownerID).Count(&count).Error
return count, err
}
// CountByObject возвращает количество отзывов объекта
func (r *feedbackRepositoryImpl) CountByObject(objectID uint) (int64, error) {
var count int64
err := r.db.Model(&models.Feedback{}).Where("object_id = ?", objectID).Count(&count).Error
return count, err
}
// CountByPlatform возвращает количество отзывов платформы
func (r *feedbackRepositoryImpl) CountByPlatform(platform models.PlatformType) (int64, error) {
var count int64
err := r.db.Model(&models.Feedback{}).Where("platform = ?", platform).Count(&count).Error
return count, err
}
// CountBySearch возвращает количество отзывов по поисковому запросу
func (r *feedbackRepositoryImpl) CountBySearch(query string) (int64, error) {
var count int64
err := r.db.Model(&models.Feedback{}).Where("text LIKE ?", "%"+query+"%").Count(&count).Error
return count, err
}
// GetObjectByID возвращает объект по ID
func (r *feedbackRepositoryImpl) GetObjectByID(id uint) (*models.Object, error) {
var object models.Object
err := r.db.First(&object, id).Error
if err != nil {
return nil, err
}
return &object, nil
}