create and moove into new directories for BegushiyBashkir and
yalarbacreate and moove into new directories for BegushiyBashkir and yalarbacreate and moove into new directories for BegushiyBashkir and yalarbacreate and moove into new directories for BegushiyBashkir and yalarbacreate and moove into new directories for BegushiyBashkir and yalarbacreate and moove into new directories for BegushiyBashkir and yalarbacreate and moove into new directories for BegushiyBashkir and yalarbacreate and moove into new directories for BegushiyBashkir and yalarbacreate and moove into new directories for BegushiyBashkir and yalarba
This commit is contained in:
@@ -0,0 +1,432 @@
|
||||
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) {
|
||||
h.logger.Debug("Start GetNews Method")
|
||||
|
||||
limit, _ := strconv.Atoi(r.URL.Query().Get("limit"))
|
||||
offset, _ := strconv.Atoi(r.URL.Query().Get("offset"))
|
||||
category := r.URL.Query().Get("category")
|
||||
|
||||
h.logger.Debug("GetNews parameters",
|
||||
zap.Int("limit", limit),
|
||||
zap.Int("offset", offset),
|
||||
zap.String("category", 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
|
||||
}
|
||||
|
||||
h.logger.Debug("Successfully retrieved news",
|
||||
zap.Int("count", len(news)),
|
||||
zap.Int("total", int(total)),
|
||||
)
|
||||
|
||||
h.logger.Debug("End GetNews Method")
|
||||
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) {
|
||||
h.logger.Debug("Start GetNewsByID Method")
|
||||
|
||||
idStr := chi.URLParam(r, "id")
|
||||
h.logger.Debug("GetNewsByID parameters", zap.String("id", idStr))
|
||||
|
||||
id, err := strconv.ParseUint(idStr, 10, 32)
|
||||
if err != nil {
|
||||
h.logger.Warn("Invalid news ID", zap.String("id", idStr), zap.Error(err))
|
||||
utils.RespondWithError(w, http.StatusBadRequest, "Invalid news ID")
|
||||
return
|
||||
}
|
||||
|
||||
news, err := h.newsService.GetNewsByID(uint(id))
|
||||
if err != nil {
|
||||
h.logger.Warn("News not found", zap.Uint("id", uint(id)), zap.Error(err))
|
||||
utils.RespondWithError(w, http.StatusNotFound, "News not found")
|
||||
return
|
||||
}
|
||||
|
||||
h.logger.Debug("Successfully retrieved news by ID", zap.Uint("id", uint(id)))
|
||||
h.logger.Debug("End GetNewsByID Method")
|
||||
utils.RespondWithJSON(w, http.StatusOK, news)
|
||||
}
|
||||
|
||||
// CreateNews создает новую новость
|
||||
func (h *NewsHandler) CreateNews(w http.ResponseWriter, r *http.Request) {
|
||||
h.logger.Debug("Start CreateNews Method")
|
||||
|
||||
userID, ok := r.Context().Value(middleware.UserIDKey).(uint)
|
||||
h.logger.Debug("CreateNews user context", zap.Uint("userID", userID), zap.Bool("ok", ok))
|
||||
|
||||
if !ok {
|
||||
h.logger.Warn("Failed to get userID from context in CreateNews",
|
||||
zap.String("path", r.URL.Path),
|
||||
zap.String("method", r.Method),
|
||||
zap.String("remote_addr", r.RemoteAddr),
|
||||
)
|
||||
utils.RespondWithError(w, http.StatusUnauthorized, "Unauthorized")
|
||||
return
|
||||
}
|
||||
|
||||
var req models.CreateNewsRequest
|
||||
if err := utils.DecodeJSONBody(w, r, &req); err != nil {
|
||||
h.logger.Warn("Invalid request body in CreateNews", zap.Error(err))
|
||||
utils.RespondWithError(w, http.StatusBadRequest, "Invalid request body")
|
||||
return
|
||||
}
|
||||
|
||||
h.logger.Debug("CreateNews request data",
|
||||
zap.String("title", req.Title),
|
||||
zap.String("category", string(req.Category)),
|
||||
)
|
||||
|
||||
if err := h.validator.Struct(req); err != nil {
|
||||
h.logger.Warn("Validation failed in CreateNews", zap.Error(err))
|
||||
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
|
||||
}
|
||||
|
||||
h.logger.Info("Successfully created news",
|
||||
zap.Uint("newsID", news.ID),
|
||||
zap.Uint("userID", userID),
|
||||
)
|
||||
h.logger.Debug("End CreateNews Method")
|
||||
utils.RespondWithJSON(w, http.StatusCreated, news)
|
||||
}
|
||||
|
||||
// UpdateNews обновляет новость
|
||||
func (h *NewsHandler) UpdateNews(w http.ResponseWriter, r *http.Request) {
|
||||
h.logger.Debug("Start UpdateNews Method")
|
||||
|
||||
userID, ok := r.Context().Value(middleware.UserIDKey).(uint)
|
||||
h.logger.Debug("UpdateNews user context", zap.Uint("userID", userID), zap.Bool("ok", ok))
|
||||
|
||||
if !ok {
|
||||
h.logger.Warn("Failed to get userID from context in UpdateNews")
|
||||
utils.RespondWithError(w, http.StatusUnauthorized, "Unauthorized")
|
||||
return
|
||||
}
|
||||
|
||||
idStr := chi.URLParam(r, "id")
|
||||
h.logger.Debug("UpdateNews parameters", zap.String("id", idStr))
|
||||
|
||||
id, err := strconv.ParseUint(idStr, 10, 32)
|
||||
if err != nil {
|
||||
h.logger.Warn("Invalid news ID in UpdateNews", zap.String("id", idStr), zap.Error(err))
|
||||
utils.RespondWithError(w, http.StatusBadRequest, "Invalid news ID")
|
||||
return
|
||||
}
|
||||
|
||||
var req models.UpdateNewsRequest
|
||||
if err := utils.DecodeJSONBody(w, r, &req); err != nil {
|
||||
h.logger.Warn("Invalid request body in UpdateNews", zap.Error(err))
|
||||
utils.RespondWithError(w, http.StatusBadRequest, "Invalid request body")
|
||||
return
|
||||
}
|
||||
|
||||
h.logger.Debug("UpdateNews request data",
|
||||
zap.String("title", req.Title),
|
||||
zap.String("category", string(req.Category)),
|
||||
)
|
||||
|
||||
if err := h.validator.Struct(req); err != nil {
|
||||
h.logger.Warn("Validation failed in UpdateNews", zap.Error(err))
|
||||
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" {
|
||||
h.logger.Warn("Access denied in UpdateNews",
|
||||
zap.Uint("userID", userID),
|
||||
zap.Uint("newsID", uint(id)),
|
||||
)
|
||||
utils.RespondWithError(w, http.StatusForbidden, "Access denied")
|
||||
return
|
||||
}
|
||||
h.logger.Error("Failed to update news", zap.Error(err))
|
||||
utils.RespondWithError(w, http.StatusInternalServerError, "Failed to update news")
|
||||
return
|
||||
}
|
||||
|
||||
h.logger.Info("Successfully updated news",
|
||||
zap.Uint("newsID", uint(id)),
|
||||
zap.Uint("userID", userID),
|
||||
)
|
||||
h.logger.Debug("End UpdateNews Method")
|
||||
utils.RespondWithJSON(w, http.StatusOK, news)
|
||||
}
|
||||
|
||||
// DeleteNews удаляет новость
|
||||
func (h *NewsHandler) DeleteNews(w http.ResponseWriter, r *http.Request) {
|
||||
h.logger.Debug("Start DeleteNews Method")
|
||||
|
||||
userID, ok := r.Context().Value(middleware.UserIDKey).(uint)
|
||||
h.logger.Debug("DeleteNews user context", zap.Uint("userID", userID), zap.Bool("ok", ok))
|
||||
|
||||
if !ok {
|
||||
h.logger.Warn("Failed to get userID from context in DeleteNews")
|
||||
utils.RespondWithError(w, http.StatusUnauthorized, "Unauthorized")
|
||||
return
|
||||
}
|
||||
|
||||
idStr := chi.URLParam(r, "id")
|
||||
h.logger.Debug("DeleteNews parameters", zap.String("id", idStr))
|
||||
|
||||
id, err := strconv.ParseUint(idStr, 10, 32)
|
||||
if err != nil {
|
||||
h.logger.Warn("Invalid news ID in DeleteNews", zap.String("id", idStr), zap.Error(err))
|
||||
utils.RespondWithError(w, http.StatusBadRequest, "Invalid news ID")
|
||||
return
|
||||
}
|
||||
|
||||
err = h.newsService.DeleteNews(uint(id), userID)
|
||||
if err != nil {
|
||||
if err.Error() == "access denied" {
|
||||
h.logger.Warn("Access denied in DeleteNews",
|
||||
zap.Uint("userID", userID),
|
||||
zap.Uint("newsID", uint(id)),
|
||||
)
|
||||
utils.RespondWithError(w, http.StatusForbidden, "Access denied")
|
||||
return
|
||||
}
|
||||
h.logger.Error("Failed to delete news", zap.Error(err))
|
||||
utils.RespondWithError(w, http.StatusInternalServerError, "Failed to delete news")
|
||||
return
|
||||
}
|
||||
|
||||
h.logger.Info("Successfully deleted news",
|
||||
zap.Uint("newsID", uint(id)),
|
||||
zap.Uint("userID", userID),
|
||||
)
|
||||
h.logger.Debug("End DeleteNews Method")
|
||||
utils.RespondWithJSON(w, http.StatusOK, map[string]string{"message": "News deleted successfully"})
|
||||
}
|
||||
|
||||
// CreateComment создает комментарий к новости
|
||||
func (h *NewsHandler) CreateComment(w http.ResponseWriter, r *http.Request) {
|
||||
h.logger.Debug("Start CreateComment Method")
|
||||
|
||||
userID, ok := r.Context().Value(middleware.UserIDKey).(uint)
|
||||
h.logger.Debug("CreateComment user context", zap.Uint("userID", userID), zap.Bool("ok", ok))
|
||||
|
||||
if !ok {
|
||||
h.logger.Warn("Failed to get userID from context in CreateComment")
|
||||
utils.RespondWithError(w, http.StatusUnauthorized, "Unauthorized")
|
||||
return
|
||||
}
|
||||
|
||||
newsIDStr := chi.URLParam(r, "id")
|
||||
h.logger.Debug("CreateComment parameters", zap.String("newsID", newsIDStr))
|
||||
|
||||
newsID, err := strconv.ParseUint(newsIDStr, 10, 32)
|
||||
if err != nil {
|
||||
h.logger.Warn("Invalid news ID in CreateComment", zap.String("newsID", newsIDStr), zap.Error(err))
|
||||
utils.RespondWithError(w, http.StatusBadRequest, "Invalid news ID")
|
||||
return
|
||||
}
|
||||
|
||||
var req models.CreateCommentRequest
|
||||
if err := utils.DecodeJSONBody(w, r, &req); err != nil {
|
||||
h.logger.Warn("Invalid request body in CreateComment", zap.Error(err))
|
||||
utils.RespondWithError(w, http.StatusBadRequest, "Invalid request body")
|
||||
return
|
||||
}
|
||||
|
||||
h.logger.Debug("CreateComment request data",
|
||||
zap.String("content", req.Content),
|
||||
)
|
||||
|
||||
if err := h.validator.Struct(req); err != nil {
|
||||
h.logger.Warn("Validation failed in CreateComment", zap.Error(err))
|
||||
utils.RespondWithError(w, http.StatusBadRequest, "Validation failed: "+err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
comment, err := h.newsService.CreateComment(uint(newsID), req, userID)
|
||||
if err != nil {
|
||||
h.logger.Error("Failed to create comment", zap.Error(err))
|
||||
utils.RespondWithError(w, http.StatusInternalServerError, "Failed to create comment")
|
||||
return
|
||||
}
|
||||
|
||||
h.logger.Info("Successfully created comment",
|
||||
zap.Uint("commentID", comment.ID),
|
||||
zap.Uint("newsID", uint(newsID)),
|
||||
zap.Uint("userID", userID),
|
||||
)
|
||||
h.logger.Debug("End CreateComment Method")
|
||||
utils.RespondWithJSON(w, http.StatusCreated, comment)
|
||||
}
|
||||
|
||||
// GetComments возвращает комментарии к новости
|
||||
func (h *NewsHandler) GetComments(w http.ResponseWriter, r *http.Request) {
|
||||
h.logger.Debug("Start GetComments Method")
|
||||
|
||||
newsIDStr := chi.URLParam(r, "id")
|
||||
h.logger.Debug("GetComments parameters", zap.String("newsID", newsIDStr))
|
||||
|
||||
newsID, err := strconv.ParseUint(newsIDStr, 10, 32)
|
||||
if err != nil {
|
||||
h.logger.Warn("Invalid news ID in GetComments", zap.String("newsID", newsIDStr), zap.Error(err))
|
||||
utils.RespondWithError(w, http.StatusBadRequest, "Invalid news ID")
|
||||
return
|
||||
}
|
||||
|
||||
comments, err := h.newsService.GetCommentsByNewsID(uint(newsID))
|
||||
if err != nil {
|
||||
h.logger.Error("Failed to get comments", zap.Error(err))
|
||||
utils.RespondWithError(w, http.StatusInternalServerError, "Failed to get comments")
|
||||
return
|
||||
}
|
||||
|
||||
h.logger.Debug("Successfully retrieved comments",
|
||||
zap.Uint("newsID", uint(newsID)),
|
||||
zap.Int("count", len(comments)),
|
||||
)
|
||||
h.logger.Debug("End GetComments Method")
|
||||
utils.RespondWithJSON(w, http.StatusOK, comments)
|
||||
}
|
||||
|
||||
// DeleteComment удаляет комментарий
|
||||
func (h *NewsHandler) DeleteComment(w http.ResponseWriter, r *http.Request) {
|
||||
h.logger.Debug("Start DeleteComment Method")
|
||||
|
||||
userID, ok := r.Context().Value(middleware.UserIDKey).(uint)
|
||||
h.logger.Debug("DeleteComment user context", zap.Uint("userID", userID), zap.Bool("ok", ok))
|
||||
|
||||
if !ok {
|
||||
h.logger.Warn("Failed to get userID from context in DeleteComment")
|
||||
utils.RespondWithError(w, http.StatusUnauthorized, "Unauthorized")
|
||||
return
|
||||
}
|
||||
|
||||
commentIDStr := chi.URLParam(r, "commentId")
|
||||
h.logger.Debug("DeleteComment parameters", zap.String("commentID", commentIDStr))
|
||||
|
||||
commentID, err := strconv.ParseUint(commentIDStr, 10, 32)
|
||||
if err != nil {
|
||||
h.logger.Warn("Invalid comment ID in DeleteComment", zap.String("commentID", commentIDStr), zap.Error(err))
|
||||
utils.RespondWithError(w, http.StatusBadRequest, "Invalid comment ID")
|
||||
return
|
||||
}
|
||||
|
||||
err = h.newsService.DeleteComment(uint(commentID), userID)
|
||||
if err != nil {
|
||||
if err.Error() == "access denied" {
|
||||
h.logger.Warn("Access denied in DeleteComment",
|
||||
zap.Uint("userID", userID),
|
||||
zap.Uint("commentID", uint(commentID)),
|
||||
)
|
||||
utils.RespondWithError(w, http.StatusForbidden, "Access denied")
|
||||
return
|
||||
}
|
||||
h.logger.Error("Failed to delete comment", zap.Error(err))
|
||||
utils.RespondWithError(w, http.StatusInternalServerError, "Failed to delete comment")
|
||||
return
|
||||
}
|
||||
|
||||
h.logger.Info("Successfully deleted comment",
|
||||
zap.Uint("commentID", uint(commentID)),
|
||||
zap.Uint("userID", userID),
|
||||
)
|
||||
h.logger.Debug("End DeleteComment Method")
|
||||
utils.RespondWithJSON(w, http.StatusOK, map[string]string{"message": "Comment deleted successfully"})
|
||||
}
|
||||
|
||||
// GetUserNews возвращает новости конкретного пользователя
|
||||
func (h *NewsHandler) GetUserNews(w http.ResponseWriter, r *http.Request) {
|
||||
h.logger.Debug("Start GetUserNews Method")
|
||||
|
||||
userID, ok := r.Context().Value(middleware.UserIDKey).(uint)
|
||||
h.logger.Debug("GetUserNews user context", zap.Uint("userID", userID), zap.Bool("ok", ok))
|
||||
|
||||
if !ok {
|
||||
h.logger.Warn("Failed to get userID from context in GetUserNews")
|
||||
utils.RespondWithError(w, http.StatusUnauthorized, "Unauthorized")
|
||||
return
|
||||
}
|
||||
|
||||
limit, _ := strconv.Atoi(r.URL.Query().Get("limit"))
|
||||
offset, _ := strconv.Atoi(r.URL.Query().Get("offset"))
|
||||
|
||||
h.logger.Debug("GetUserNews parameters",
|
||||
zap.Int("limit", limit),
|
||||
zap.Int("offset", offset),
|
||||
)
|
||||
|
||||
if limit == 0 {
|
||||
limit = 10
|
||||
}
|
||||
|
||||
news, total, err := h.newsService.GetUserNews(userID, limit, offset)
|
||||
if err != nil {
|
||||
h.logger.Error("Failed to get user news", zap.Error(err))
|
||||
utils.RespondWithError(w, http.StatusInternalServerError, "Failed to get user news")
|
||||
return
|
||||
}
|
||||
|
||||
h.logger.Debug("Successfully retrieved user news",
|
||||
zap.Uint("userID", userID),
|
||||
zap.Int("count", len(news)),
|
||||
zap.Int("total", int(total)),
|
||||
)
|
||||
h.logger.Debug("End GetUserNews Method")
|
||||
utils.RespondWithJSON(w, http.StatusOK, map[string]interface{}{
|
||||
"news": news,
|
||||
"total": total,
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user