Files
Mycontent/soul-api/internal/handler/miniprogram_super_articles.go
2026-04-23 18:14:06 +08:00

181 lines
5.2 KiB
Go

package handler
import (
"net/http"
"strconv"
"strings"
"soul-api/internal/database"
"soul-api/internal/model"
"github.com/gin-gonic/gin"
)
type superArticleAuthorRow struct {
ID string `gorm:"column:id"`
Nickname string `gorm:"column:nickname"`
Avatar string `gorm:"column:avatar"`
}
func loadSuperArticleAuthorMap(ids []string) map[string]superArticleAuthorRow {
out := map[string]superArticleAuthorRow{}
if len(ids) == 0 {
return out
}
var rows []superArticleAuthorRow
db := database.DB()
_ = db.Table("users").Select("id", "nickname", "avatar").Where("id IN ?", ids).Find(&rows).Error
for _, r := range rows {
key := strings.TrimSpace(r.ID)
if key == "" {
continue
}
out[key] = r
}
return out
}
// MiniprogramSuperArticleCreate POST /api/miniprogram/super/articles
// 仅超级个体本人可发文章。
func MiniprogramSuperArticleCreate(c *gin.Context) {
var req struct {
UserID string `json:"userId"`
Title string `json:"title"`
Content string `json:"content"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusOK, gin.H{"success": false, "error": "参数错误"})
return
}
req.UserID = strings.TrimSpace(req.UserID)
req.Title = strings.TrimSpace(req.Title)
req.Content = strings.TrimSpace(req.Content)
if req.UserID == "" || req.Title == "" || req.Content == "" {
c.JSON(http.StatusOK, gin.H{"success": false, "error": "标题和正文不能为空"})
return
}
if len([]rune(req.Title)) > 40 {
c.JSON(http.StatusOK, gin.H{"success": false, "error": "标题最多 40 字"})
return
}
if len([]rune(req.Content)) > 5000 {
c.JSON(http.StatusOK, gin.H{"success": false, "error": "正文最多 5000 字"})
return
}
db := database.DB()
if _, ok := miniprogramSuperIndividualPerson(db, req.UserID); !ok {
c.JSON(http.StatusOK, gin.H{"success": false, "error": "仅超级个体可发文章", "forbidden": true})
return
}
row := model.SuperArticle{
UserID: req.UserID,
Title: req.Title,
Content: req.Content,
}
if err := db.Create(&row).Error; err != nil {
c.JSON(http.StatusOK, gin.H{"success": false, "error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"success": true, "data": gin.H{"id": row.ID}})
}
// MiniprogramSuperArticleList GET /api/miniprogram/super/articles?authorUserId=&page=&pageSize=
func MiniprogramSuperArticleList(c *gin.Context) {
authorUserID := strings.TrimSpace(c.Query("authorUserId"))
if authorUserID == "" {
c.JSON(http.StatusOK, gin.H{"success": false, "error": "缺少 authorUserId"})
return
}
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
pageSize, _ := strconv.Atoi(c.DefaultQuery("pageSize", "10"))
if page < 1 {
page = 1
}
if pageSize < 1 || pageSize > 30 {
pageSize = 10
}
db := database.DB()
if _, ok := miniprogramSuperIndividualPerson(db, authorUserID); !ok {
c.JSON(http.StatusOK, gin.H{"success": true, "list": []gin.H{}, "total": 0, "page": page, "pageSize": pageSize})
return
}
var total int64
db.Model(&model.SuperArticle{}).Where("user_id = ?", authorUserID).Count(&total)
var rows []model.SuperArticle
if err := db.Where("user_id = ?", authorUserID).
Order("created_at DESC").
Offset((page - 1) * pageSize).
Limit(pageSize).
Find(&rows).Error; err != nil {
c.JSON(http.StatusOK, gin.H{"success": false, "error": err.Error()})
return
}
authorMap := loadSuperArticleAuthorMap([]string{authorUserID})
author := authorMap[authorUserID]
list := make([]gin.H, 0, len(rows))
for _, r := range rows {
content := strings.TrimSpace(r.Content)
preview := content
if len([]rune(preview)) > 88 {
preview = string([]rune(preview)[:88]) + "..."
}
list = append(list, gin.H{
"id": r.ID,
"userId": r.UserID,
"title": r.Title,
"content": r.Content,
"preview": preview,
"authorNickname": strings.TrimSpace(author.Nickname),
"authorAvatar": strings.TrimSpace(author.Avatar),
"createdAt": r.CreatedAt,
})
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"list": list,
"total": total,
"page": page,
"pageSize": pageSize,
})
}
// MiniprogramSuperArticleDetail GET /api/miniprogram/super/articles/:id
func MiniprogramSuperArticleDetail(c *gin.Context) {
idRaw := strings.TrimSpace(c.Param("id"))
id, err := strconv.ParseUint(idRaw, 10, 64)
if err != nil || id == 0 {
c.JSON(http.StatusOK, gin.H{"success": false, "error": "参数错误"})
return
}
db := database.DB()
var row model.SuperArticle
if err := db.First(&row, id).Error; err != nil {
c.JSON(http.StatusOK, gin.H{"success": false, "error": "文章不存在"})
return
}
if _, ok := miniprogramSuperIndividualPerson(db, row.UserID); !ok {
c.JSON(http.StatusOK, gin.H{"success": false, "error": "文章不可见"})
return
}
authorMap := loadSuperArticleAuthorMap([]string{row.UserID})
author := authorMap[row.UserID]
c.JSON(http.StatusOK, gin.H{
"success": true,
"data": gin.H{
"id": row.ID,
"userId": row.UserID,
"title": row.Title,
"content": row.Content,
"authorNickname": strings.TrimSpace(author.Nickname),
"authorAvatar": strings.TrimSpace(author.Avatar),
"createdAt": row.CreatedAt,
},
})
}