96e372a699
del fmt upused import
289 lines
8.3 KiB
Go
289 lines
8.3 KiB
Go
package handlers
|
|
|
|
import (
|
|
"api_bb/internal/models"
|
|
"api_bb/internal/service"
|
|
"api_bb/pkg/logger"
|
|
"api_bb/pkg/middleware"
|
|
"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.LoggerInterface
|
|
validator *validator.Validate
|
|
}
|
|
|
|
func NewNewsHandler(newsService service.NewsService, log logger.LoggerInterface) *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) {
|
|
logger.Get().Debug("Start CreateNews Method")
|
|
userID, ok := r.Context().Value(middleware.UserIDKey).(uint)
|
|
logger.Get().Info("userID", zap.Uint("userID", userID))
|
|
if !ok {
|
|
h.logger.Warn("Failed to get userID from context in CreateReview",
|
|
zap.String("path", r.URL.Path),
|
|
zap.String("method", r.Method),
|
|
zap.String("remote_addr", r.RemoteAddr),
|
|
zap.Uint("userID", userID),
|
|
)
|
|
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(middleware.UserIDKey).(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
|
|
}
|
|
|
|
logger.Get().Debug("End CreateNews Method")
|
|
utils.RespondWithJSON(w, http.StatusOK, news)
|
|
}
|
|
|
|
// DeleteNews удаляет новость
|
|
func (h *NewsHandler) DeleteNews(w http.ResponseWriter, r *http.Request) {
|
|
userID, ok := r.Context().Value(middleware.UserIDKey).(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(middleware.UserIDKey).(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(middleware.UserIDKey).(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(middleware.UserIDKey).(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,
|
|
})
|
|
}
|