package handlers import ( "math" "net/http" "strconv" "sale/internal/models" "sale/internal/schemas" "sale/internal/utils" "github.com/gin-gonic/gin" ) type ArticleHandler struct{} func NewArticleHandler() *ArticleHandler { return &ArticleHandler{} } func (h *ArticleHandler) List(c *gin.Context) { page, _ := strconv.Atoi(c.DefaultQuery("page", "1")) pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20")) var total int64 utils.DB.Model(&models.Article{}).Where("is_published = ?", true).Count(&total) var articles []models.Article offset := (page - 1) * pageSize utils.DB.Where("is_published = ?", true). Order("is_pinned DESC, sort_order ASC, created_at DESC"). Offset(offset).Limit(pageSize).Find(&articles) totalPages := int(math.Ceil(float64(total) / float64(pageSize))) c.JSON(http.StatusOK, gin.H{ "data": articles, "pagination": gin.H{ "page": page, "page_size": pageSize, "total": total, "total_pages": totalPages, }, }) } func (h *ArticleHandler) GetByID(c *gin.Context) { id, _ := strconv.Atoi(c.Param("id")) var article models.Article if err := utils.DB.Preload("Author").First(&article, id).Error; err != nil { c.JSON(http.StatusNotFound, gin.H{"error": "Article not found"}) return } c.JSON(http.StatusOK, gin.H{"data": article}) } func (h *ArticleHandler) AdminList(c *gin.Context) { page, _ := strconv.Atoi(c.DefaultQuery("page", "1")) pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20")) var total int64 utils.DB.Model(&models.Article{}).Count(&total) var articles []models.Article offset := (page - 1) * pageSize utils.DB.Preload("Author"). Order("is_pinned DESC, sort_order ASC, created_at DESC"). Offset(offset).Limit(pageSize).Find(&articles) totalPages := int(math.Ceil(float64(total) / float64(pageSize))) c.JSON(http.StatusOK, gin.H{ "data": articles, "pagination": gin.H{ "page": page, "page_size": pageSize, "total": total, "total_pages": totalPages, }, }) } func (h *ArticleHandler) Create(c *gin.Context) { userID := c.GetUint("user_id") var req schemas.CreateArticleRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } article := models.Article{ Title: req.Title, Content: req.Content, Summary: req.Summary, CoverImage: req.CoverImage, IsPinned: req.IsPinned, IsPublished: req.IsPublished, SortOrder: req.SortOrder, AuthorID: &userID, } utils.DB.Create(&article) c.JSON(http.StatusCreated, gin.H{"data": article}) } func (h *ArticleHandler) Update(c *gin.Context) { id, _ := strconv.Atoi(c.Param("id")) var article models.Article if err := utils.DB.First(&article, id).Error; err != nil { c.JSON(http.StatusNotFound, gin.H{"error": "Article not found"}) return } var req schemas.UpdateArticleRequest if err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } updates := make(map[string]interface{}) if req.Title != nil { updates["title"] = *req.Title } if req.Content != nil { updates["content"] = *req.Content } if req.Summary != nil { updates["summary"] = *req.Summary } if req.CoverImage != nil { updates["cover_image"] = *req.CoverImage } if req.IsPinned != nil { updates["is_pinned"] = *req.IsPinned } if req.IsPublished != nil { updates["is_published"] = *req.IsPublished } if req.SortOrder != nil { updates["sort_order"] = *req.SortOrder } utils.DB.Model(&article).Updates(updates) c.JSON(http.StatusOK, gin.H{"data": article}) } func (h *ArticleHandler) Delete(c *gin.Context) { id, _ := strconv.Atoi(c.Param("id")) if err := utils.DB.Delete(&models.Article{}, id).Error; err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to delete article"}) return } c.JSON(http.StatusOK, gin.H{"message": "Article deleted successfully"}) } func (h *ArticleHandler) TogglePin(c *gin.Context) { id, _ := strconv.Atoi(c.Param("id")) var article models.Article if err := utils.DB.First(&article, id).Error; err != nil { c.JSON(http.StatusNotFound, gin.H{"error": "Article not found"}) return } utils.DB.Model(&article).Update("is_pinned", !article.IsPinned) c.JSON(http.StatusOK, gin.H{"data": article}) }