package handlers import ( "api_bb/internal/models" "api_bb/internal/service" "api_bb/pkg/logger" "api_bb/pkg/utils" "net/http" "strconv" "github.com/go-chi/chi/v5" "github.com/go-playground/validator/v10" "go.uber.org/zap" ) type NewsHandler struct { newsService service.NewsService logger logger.Interface validator *validator.Validate } func NewNewsHandler(newsService service.NewsService, log logger.Interface) *NewsHandler { return &NewsHandler{ newsService: newsService, logger: log, validator: validator.New(), } } // GetNews возвращает список новостей с пагинацией и фильтрацией func (h *NewsHandler) GetNews(w http.ResponseWriter, r *http.Request) { limit, _ := strconv.Atoi(r.URL.Query().Get("limit")) offset, _ := strconv.Atoi(r.URL.Query().Get("offset")) category := r.URL.Query().Get("category") if limit == 0 { limit = 10 } if limit > 50 { limit = 50 } news, total, err := h.newsService.GetAllNews(limit, offset, category) if err != nil { h.logger.Error("Failed to get news", zap.Error(err)) utils.RespondWithError(w, http.StatusInternalServerError, "Failed to get news") return } utils.RespondWithJSON(w, http.StatusOK, map[string]interface{}{ "news": news, "total": total, "limit": limit, "offset": offset, }) } // GetNewsByID возвращает конкретную новость func (h *NewsHandler) GetNewsByID(w http.ResponseWriter, r *http.Request) { idStr := chi.URLParam(r, "id") id, err := strconv.ParseUint(idStr, 10, 32) if err != nil { utils.RespondWithError(w, http.StatusBadRequest, "Invalid news ID") return } news, err := h.newsService.GetNewsByID(uint(id)) if err != nil { utils.RespondWithError(w, http.StatusNotFound, "News not found") return } utils.RespondWithJSON(w, http.StatusOK, news) } // CreateNews создает новую новость func (h *NewsHandler) CreateNews(w http.ResponseWriter, r *http.Request) { userID, ok := r.Context().Value("userID").(uint) if !ok { utils.RespondWithError(w, http.StatusUnauthorized, "Unauthorized") return } var req models.CreateNewsRequest if err := utils.DecodeJSONBody(w, r, &req); err != nil { utils.RespondWithError(w, http.StatusBadRequest, "Invalid request body") return } if err := h.validator.Struct(req); err != nil { utils.RespondWithError(w, http.StatusBadRequest, "Validation failed: "+err.Error()) return } news, err := h.newsService.CreateNews(req, userID) if err != nil { h.logger.Error("Failed to create news", zap.Error(err)) utils.RespondWithError(w, http.StatusInternalServerError, "Failed to create news") return } utils.RespondWithJSON(w, http.StatusCreated, news) } // UpdateNews обновляет новость func (h *NewsHandler) UpdateNews(w http.ResponseWriter, r *http.Request) { userID, ok := r.Context().Value("userID").(uint) if !ok { utils.RespondWithError(w, http.StatusUnauthorized, "Unauthorized") return } idStr := chi.URLParam(r, "id") id, err := strconv.ParseUint(idStr, 10, 32) if err != nil { utils.RespondWithError(w, http.StatusBadRequest, "Invalid news ID") return } var req models.UpdateNewsRequest if err := utils.DecodeJSONBody(w, r, &req); err != nil { utils.RespondWithError(w, http.StatusBadRequest, "Invalid request body") return } if err := h.validator.Struct(req); err != nil { utils.RespondWithError(w, http.StatusBadRequest, "Validation failed: "+err.Error()) return } news, err := h.newsService.UpdateNews(uint(id), req, userID) if err != nil { if err.Error() == "access denied" { utils.RespondWithError(w, http.StatusForbidden, "Access denied") return } utils.RespondWithError(w, http.StatusInternalServerError, "Failed to update news") return } utils.RespondWithJSON(w, http.StatusOK, news) } // DeleteNews удаляет новость func (h *NewsHandler) DeleteNews(w http.ResponseWriter, r *http.Request) { userID, ok := r.Context().Value("userID").(uint) if !ok { utils.RespondWithError(w, http.StatusUnauthorized, "Unauthorized") return } idStr := chi.URLParam(r, "id") id, err := strconv.ParseUint(idStr, 10, 32) if err != nil { utils.RespondWithError(w, http.StatusBadRequest, "Invalid news ID") return } err = h.newsService.DeleteNews(uint(id), userID) if err != nil { if err.Error() == "access denied" { utils.RespondWithError(w, http.StatusForbidden, "Access denied") return } utils.RespondWithError(w, http.StatusInternalServerError, "Failed to delete news") return } utils.RespondWithJSON(w, http.StatusOK, map[string]string{"message": "News deleted successfully"}) } // CreateComment создает комментарий к новости func (h *NewsHandler) CreateComment(w http.ResponseWriter, r *http.Request) { userID, ok := r.Context().Value("userID").(uint) if !ok { utils.RespondWithError(w, http.StatusUnauthorized, "Unauthorized") return } newsIDStr := chi.URLParam(r, "id") newsID, err := strconv.ParseUint(newsIDStr, 10, 32) if err != nil { utils.RespondWithError(w, http.StatusBadRequest, "Invalid news ID") return } var req models.CreateCommentRequest if err := utils.DecodeJSONBody(w, r, &req); err != nil { utils.RespondWithError(w, http.StatusBadRequest, "Invalid request body") return } if err := h.validator.Struct(req); err != nil { utils.RespondWithError(w, http.StatusBadRequest, "Validation failed: "+err.Error()) return } comment, err := h.newsService.CreateComment(uint(newsID), req, userID) if err != nil { utils.RespondWithError(w, http.StatusInternalServerError, "Failed to create comment") return } utils.RespondWithJSON(w, http.StatusCreated, comment) } // GetComments возвращает комментарии к новости func (h *NewsHandler) GetComments(w http.ResponseWriter, r *http.Request) { newsIDStr := chi.URLParam(r, "id") newsID, err := strconv.ParseUint(newsIDStr, 10, 32) if err != nil { utils.RespondWithError(w, http.StatusBadRequest, "Invalid news ID") return } comments, err := h.newsService.GetCommentsByNewsID(uint(newsID)) if err != nil { utils.RespondWithError(w, http.StatusInternalServerError, "Failed to get comments") return } utils.RespondWithJSON(w, http.StatusOK, comments) } // DeleteComment удаляет комментарий func (h *NewsHandler) DeleteComment(w http.ResponseWriter, r *http.Request) { userID, ok := r.Context().Value("userID").(uint) if !ok { utils.RespondWithError(w, http.StatusUnauthorized, "Unauthorized") return } commentIDStr := chi.URLParam(r, "commentId") commentID, err := strconv.ParseUint(commentIDStr, 10, 32) if err != nil { utils.RespondWithError(w, http.StatusBadRequest, "Invalid comment ID") return } err = h.newsService.DeleteComment(uint(commentID), userID) if err != nil { if err.Error() == "access denied" { utils.RespondWithError(w, http.StatusForbidden, "Access denied") return } utils.RespondWithError(w, http.StatusInternalServerError, "Failed to delete comment") return } utils.RespondWithJSON(w, http.StatusOK, map[string]string{"message": "Comment deleted successfully"}) } // GetUserNews возвращает новости конкретного пользователя func (h *NewsHandler) GetUserNews(w http.ResponseWriter, r *http.Request) { userID, ok := r.Context().Value("userID").(uint) if !ok { utils.RespondWithError(w, http.StatusUnauthorized, "Unauthorized") return } limit, _ := strconv.Atoi(r.URL.Query().Get("limit")) offset, _ := strconv.Atoi(r.URL.Query().Get("offset")) if limit == 0 { limit = 10 } news, total, err := h.newsService.GetUserNews(userID, limit, offset) if err != nil { utils.RespondWithError(w, http.StatusInternalServerError, "Failed to get user news") return } utils.RespondWithJSON(w, http.StatusOK, map[string]interface{}{ "news": news, "total": total, }) }