287 lines
8.0 KiB
Go
287 lines
8.0 KiB
Go
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)
|
|
}
|