package handler import ( "esforum" "esforum/pkg/util" "net/http" "strconv" "github.com/gin-gonic/gin" ) type threadRequest struct { Title string `json:"title" binding:"required,min=3,max=100"` } type postRequest struct { Title string `json:"title" binding:"required,min=3,max=100"` Content string `json:"content" binding:"required,min=5"` Thread int64 `json:"thread" binding:"required"` } // thread godoc // @Summary Create new thread (only for admins) // @Tags thread // @Produce json // @Param thread body handler.threadRequest true "Thread data in JSON" // @Param Authorization header string true "JWT Bearer token (authorization)" // @Success 200 {object} esforum.Thread "created thread" // @Router /api/thread [post] func (h *Handler) create(c *gin.Context) { var input threadRequest if !util.MatchRole(c, "admin") { util.NewErrorResponse(c, http.StatusForbidden, "no perms") return } if err := c.BindJSON(&input); err != nil { util.NewErrorResponse(c, http.StatusBadRequest, err.Error()) return } thread, err := h.repo.CreateThread(input.Title) if err != nil { util.NewErrorResponse(c, http.StatusBadRequest, err.Error()) return } c.JSON(http.StatusOK, thread) } // thread/delete godoc // @Summary Delete thread by id (only for admins) // @Tags thread // @Produce json // @Param id path int true "id of thread" // @Param Authorization header string true "JWT Bearer token (authorization)" // @Success 200 // @Router /api/thread/{id} [delete] func (h *Handler) delete(c *gin.Context) { id, err := strconv.ParseInt(c.Param("id"), 10, 64) if err != nil { util.NewErrorResponse(c, http.StatusBadRequest, "invalid id format") return } _, err = h.repo.GetThread(id) if err != nil { util.NewErrorResponse(c, http.StatusBadRequest, err.Error()) return } current, exist := c.Get(userCtx) if !exist { util.NewErrorResponse(c, http.StatusUnauthorized, "user not found in context") return } currentUser, err := h.services.AuthorizeById(current.(int64)) if (err != nil) || (currentUser.Access != "admin") { util.NewErrorResponse(c, http.StatusForbidden, "no permissions") return } err = h.repo.DeleteThread(id) if err != nil { util.NewErrorResponse(c, http.StatusInternalServerError, err.Error()) return } c.JSON(http.StatusOK, gin.H{"status": "ok"}) } // createPost godoc // @Summary Create new post // @Tags post // @Produce json // @Param post body handler.postRequest true "Post data in JSON" // @Param Authorization header string true "JWT Bearer token (authorization)" // @Success 200 {object} esforum.Post "created post" // @Router /api/post [post] func (h *Handler) createPost(c *gin.Context) { var input postRequest if err := c.BindJSON(&input); err != nil { util.NewErrorResponse(c, http.StatusBadRequest, err.Error()) return } // Проверяем существование треда _, err := h.repo.GetThread(input.Thread) if err != nil { util.NewErrorResponse(c, http.StatusBadRequest, "thread does not exist") return } post, err := h.repo.CreatePost(input.Title, input.Content, input.Thread) if err != nil { util.NewErrorResponse(c, http.StatusInternalServerError, err.Error()) return } c.JSON(http.StatusOK, post) } // deletePost godoc // @Summary Delete post by id // @Tags post // @Produce json // @Param id path int true "id of post" // @Param Authorization header string true "JWT Bearer token (authorization)" // @Success 200 // @Router /api/post/{id} [delete] func (h *Handler) deletePost(c *gin.Context) { id, err := strconv.ParseInt(c.Param("id"), 10, 64) if err != nil { util.NewErrorResponse(c, http.StatusBadRequest, "invalid id format") return } post, err := h.repo.GetPost(id) if err != nil { util.NewErrorResponse(c, http.StatusBadRequest, err.Error()) return } // Только админ может удалять посты if !util.MatchRole(c, "admin") { util.NewErrorResponse(c, http.StatusForbidden, "no permissions") return } err = h.repo.DeletePost(id) if err != nil { util.NewErrorResponse(c, http.StatusInternalServerError, err.Error()) return } c.JSON(http.StatusOK, gin.H{"status": "ok", "deleted_post_id": post.Id}) } // getThread godoc // @Summary Get thread by id // @Tags thread // @Produce json // @Param id path int true "id of thread" // @Success 200 {object} esforum.Thread // @Router /api/guest/thread/{id} [get] func (h *Handler) getThread(c *gin.Context) { id, err := strconv.ParseInt(c.Param("id"), 10, 64) if err != nil { util.NewErrorResponse(c, http.StatusBadRequest, "invalid id format") return } thread, err := h.repo.GetThread(id) if err != nil { util.NewErrorResponse(c, http.StatusNotFound, "thread not found") return } c.JSON(http.StatusOK, thread) } // getAllThreads godoc // @Summary Get all threads // @Tags thread // @Produce json // @Success 200 {array} esforum.Thread // @Router /api/guest/thread/all [get] func (h *Handler) getAllThreads(c *gin.Context) { // Получаем параметры для пагинации startParam := c.DefaultQuery("start", "0") limitParam := c.DefaultQuery("limit", "20") start, err := strconv.Atoi(startParam) if err != nil || start < 0 { start = 0 } limit, err := strconv.Atoi(limitParam) if err != nil || limit < 1 || limit > 100 { limit = 20 } // Получаем ID всех тредов с учетом пагинации threadIds := h.repo.GetThreads(start, limit) // Получаем общее количество тредов totalThreads := h.repo.GetThreadsCount() // Получаем информацию о каждом треде threads := make([]esforum.Thread, 0, len(threadIds)) for _, threadId := range threadIds { thread, err := h.repo.GetThread(threadId) if err == nil { threads = append(threads, *thread) } } c.JSON(http.StatusOK, gin.H{ "threads": threads, "total": totalThreads, "start": start, "limit": limit, }) } // getThreadPosts godoc // @Summary Get posts in thread // @Tags post // @Produce json // @Param id path int true "id of thread" // @Success 200 {array} esforum.Post // @Router /api/guest/thread/{id}/posts [get] func (h *Handler) getThreadPosts(c *gin.Context) { id, err := strconv.ParseInt(c.Param("id"), 10, 64) if err != nil { util.NewErrorResponse(c, http.StatusBadRequest, "invalid id format") return } // Проверяем существование треда _, err = h.repo.GetThread(id) if err != nil { util.NewErrorResponse(c, http.StatusNotFound, "thread not found") return } // Получаем все посты треда // По умолчанию первые 20 постов postIds := h.repo.FindPostsByThread(id, 0, 20) posts := make([]esforum.Post, 0, len(postIds)) for _, postId := range postIds { post, err := h.repo.GetPost(postId) if err == nil { posts = append(posts, *post) } } c.JSON(http.StatusOK, posts) } // getPost godoc // @Summary Get post by id // @Tags post // @Produce json // @Param id path int true "id of post" // @Success 200 {object} esforum.Post // @Router /api/guest/post/{id} [get] func (h *Handler) getPost(c *gin.Context) { id, err := strconv.ParseInt(c.Param("id"), 10, 64) if err != nil { util.NewErrorResponse(c, http.StatusBadRequest, "invalid id format") return } post, err := h.repo.GetPost(id) if err != nil { util.NewErrorResponse(c, http.StatusNotFound, "post not found") return } c.JSON(http.StatusOK, post) }