first commit
This commit is contained in:
306
app/blog/handlers/post_handler.go
Normal file
306
app/blog/handlers/post_handler.go
Normal file
@@ -0,0 +1,306 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"gobeyhan/app/blog/services"
|
||||
"gobeyhan/database/models"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type PostHandler struct {
|
||||
service *services.PostService
|
||||
}
|
||||
|
||||
func NewPostHandler(service *services.PostService) *PostHandler {
|
||||
return &PostHandler{service: service}
|
||||
}
|
||||
|
||||
// GetAllPosts godoc
|
||||
// @Summary Get all active posts
|
||||
// @Description Get paginated list of active posts (public endpoint)
|
||||
// @Tags posts
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param page query int false "Page number" default(1)
|
||||
// @Param limit query int false "Items per page" default(10)
|
||||
// @Success 200 {object} map[string]interface{}
|
||||
// @Router /api/v1/posts [get]
|
||||
func (h *PostHandler) GetAllPosts(c *gin.Context) {
|
||||
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
||||
limit, _ := strconv.Atoi(c.DefaultQuery("limit", "10"))
|
||||
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
if limit < 1 || limit > 100 {
|
||||
limit = 10
|
||||
}
|
||||
|
||||
posts, total, err := h.service.GetAllPosts(page, limit, true)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"data": posts,
|
||||
"total": total,
|
||||
"page": page,
|
||||
"limit": limit,
|
||||
})
|
||||
}
|
||||
|
||||
// GetPostBySlug godoc
|
||||
// @Summary Get post by slug
|
||||
// @Description Get a single post by its slug (public endpoint)
|
||||
// @Tags posts
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param slug path string true "Post Slug"
|
||||
// @Success 200 {object} models.Post
|
||||
// @Router /api/v1/posts/{slug} [get]
|
||||
func (h *PostHandler) GetPostBySlug(c *gin.Context) {
|
||||
slug := c.Param("slug")
|
||||
|
||||
post, err := h.service.GetPostBySlug(slug)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
if post == nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "Post not found"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"data": post})
|
||||
}
|
||||
|
||||
// AdminGetAllPosts godoc
|
||||
// @Summary Get all posts (Admin)
|
||||
// @Description Get paginated list of all posts including inactive
|
||||
// @Tags admin,posts
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Param page query int false "Page number" default(1)
|
||||
// @Param limit query int false "Items per page" default(10)
|
||||
// @Success 200 {object} map[string]interface{}
|
||||
// @Router /api/v1/admin/posts [get]
|
||||
func (h *PostHandler) AdminGetAllPosts(c *gin.Context) {
|
||||
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
||||
limit, _ := strconv.Atoi(c.DefaultQuery("limit", "10"))
|
||||
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
if limit < 1 || limit > 100 {
|
||||
limit = 10
|
||||
}
|
||||
|
||||
posts, total, err := h.service.GetAllPosts(page, limit, false)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"data": posts,
|
||||
"total": total,
|
||||
"page": page,
|
||||
"limit": limit,
|
||||
})
|
||||
}
|
||||
|
||||
// GetPostByID godoc
|
||||
// @Summary Get post by ID (Admin)
|
||||
// @Description Get a single post by ID
|
||||
// @Tags admin,posts
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Param id path int true "Post ID"
|
||||
// @Success 200 {object} models.Post
|
||||
// @Router /api/v1/admin/posts/{id} [get]
|
||||
func (h *PostHandler) GetPostByID(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := strconv.ParseUint(idStr, 10, 64)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid post ID"})
|
||||
return
|
||||
}
|
||||
|
||||
post, err := h.service.GetPostByID(id)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
if post == nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "Post not found"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"data": post})
|
||||
}
|
||||
|
||||
// CreatePost godoc
|
||||
// @Summary Create a new post (Admin)
|
||||
// @Description Create a new post
|
||||
// @Tags admin,posts
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Param post body models.Post true "Post object"
|
||||
// @Success 201 {object} models.Post
|
||||
// @Router /api/v1/admin/posts [post]
|
||||
func (h *PostHandler) CreatePost(c *gin.Context) {
|
||||
var input struct {
|
||||
Title string `json:"title" binding:"required"`
|
||||
UserID *uint64 `json:"user_id"`
|
||||
Content string `json:"content"`
|
||||
Keywords string `json:"keywords"`
|
||||
Image string `json:"image"`
|
||||
Thumb string `json:"thumb"`
|
||||
Video string `json:"video"`
|
||||
Slug string `json:"slug"`
|
||||
IsActive *bool `json:"is_active"`
|
||||
IsFront *bool `json:"is_front"`
|
||||
ParentID *uint64 `json:"parent_id"`
|
||||
Categories []uint64 `json:"categories"`
|
||||
Tags []uint64 `json:"tags"`
|
||||
}
|
||||
|
||||
if err := c.ShouldBindJSON(&input); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
post := &models.Post{
|
||||
Title: input.Title,
|
||||
UserID: input.UserID,
|
||||
Content: input.Content,
|
||||
Keywords: input.Keywords,
|
||||
Image: input.Image,
|
||||
Thumb: input.Thumb,
|
||||
Video: input.Video,
|
||||
Slug: input.Slug,
|
||||
ParentID: input.ParentID,
|
||||
}
|
||||
|
||||
if input.IsActive != nil {
|
||||
post.IsActive = *input.IsActive
|
||||
} else {
|
||||
post.IsActive = true
|
||||
}
|
||||
|
||||
if input.IsFront != nil {
|
||||
post.IsFront = *input.IsFront
|
||||
} else {
|
||||
post.IsFront = true
|
||||
}
|
||||
|
||||
// Create post first
|
||||
if err := h.service.CreatePost(post); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
// Add categories and tags if provided
|
||||
if len(input.Categories) > 0 || len(input.Tags) > 0 {
|
||||
updates := make(map[string]interface{})
|
||||
|
||||
if len(input.Categories) > 0 {
|
||||
var categories []*models.Category
|
||||
for _, catID := range input.Categories {
|
||||
categories = append(categories, &models.Category{ID: catID})
|
||||
}
|
||||
updates["categories"] = categories
|
||||
}
|
||||
|
||||
if len(input.Tags) > 0 {
|
||||
var tags []*models.Tag
|
||||
for _, tagID := range input.Tags {
|
||||
tags = append(tags, &models.Tag{ID: tagID})
|
||||
}
|
||||
updates["tags"] = tags
|
||||
}
|
||||
|
||||
if err := h.service.UpdatePost(post.ID, updates); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch created post with relationships
|
||||
createdPost, _ := h.service.GetPostByID(post.ID)
|
||||
c.JSON(http.StatusCreated, gin.H{"data": createdPost})
|
||||
}
|
||||
|
||||
// UpdatePost godoc
|
||||
// @Summary Update a post (Admin)
|
||||
// @Description Update an existing post
|
||||
// @Tags admin,posts
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Param id path int true "Post ID"
|
||||
// @Param post body models.Post true "Post object"
|
||||
// @Success 200 {object} models.Post
|
||||
// @Router /api/v1/admin/posts/{id} [put]
|
||||
func (h *PostHandler) UpdatePost(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := strconv.ParseUint(idStr, 10, 64)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid post ID"})
|
||||
return
|
||||
}
|
||||
|
||||
var input map[string]interface{}
|
||||
if err := c.ShouldBindJSON(&input); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.service.UpdatePost(id, input); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
// Fetch updated post
|
||||
post, err := h.service.GetPostByID(id)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"data": post})
|
||||
}
|
||||
|
||||
// DeletePost godoc
|
||||
// @Summary Delete a post (Admin)
|
||||
// @Description Delete a post by ID
|
||||
// @Tags admin,posts
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security BearerAuth
|
||||
// @Param id path int true "Post ID"
|
||||
// @Success 200 {object} map[string]string
|
||||
// @Router /api/v1/admin/posts/{id} [delete]
|
||||
func (h *PostHandler) DeletePost(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, err := strconv.ParseUint(idStr, 10, 64)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid post ID"})
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.service.DeletePost(id); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Post deleted successfully"})
|
||||
}
|
||||
Reference in New Issue
Block a user