feat: add SproutWorkCollect apps
This commit is contained in:
145
SproutWorkCollect-Backend-Golang/internal/handler/public.go
Normal file
145
SproutWorkCollect-Backend-Golang/internal/handler/public.go
Normal file
@@ -0,0 +1,145 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"sproutworkcollect-backend/internal/service"
|
||||
)
|
||||
|
||||
// PublicHandler handles all publicly accessible API endpoints.
|
||||
type PublicHandler struct {
|
||||
workSvc *service.WorkService
|
||||
settingsSvc *service.SettingsService
|
||||
rateLimiter *service.RateLimiter
|
||||
}
|
||||
|
||||
// NewPublicHandler wires up a PublicHandler with its dependencies.
|
||||
func NewPublicHandler(
|
||||
workSvc *service.WorkService,
|
||||
settingsSvc *service.SettingsService,
|
||||
rateLimiter *service.RateLimiter,
|
||||
) *PublicHandler {
|
||||
return &PublicHandler{
|
||||
workSvc: workSvc,
|
||||
settingsSvc: settingsSvc,
|
||||
rateLimiter: rateLimiter,
|
||||
}
|
||||
}
|
||||
|
||||
// GetSettings handles GET /api/settings
|
||||
func (h *PublicHandler) GetSettings(c *gin.Context) {
|
||||
settings, err := h.settingsSvc.Load()
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, settings)
|
||||
}
|
||||
|
||||
// GetWorks handles GET /api/works
|
||||
func (h *PublicHandler) GetWorks(c *gin.Context) {
|
||||
works, err := h.workSvc.LoadAllWorks()
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"success": false, "message": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
responses := make([]any, len(works))
|
||||
for i, w := range works {
|
||||
responses[i] = h.workSvc.BuildResponse(w)
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"success": true,
|
||||
"data": responses,
|
||||
"total": len(responses),
|
||||
})
|
||||
}
|
||||
|
||||
// GetWorkDetail handles GET /api/works/:work_id
|
||||
func (h *PublicHandler) GetWorkDetail(c *gin.Context) {
|
||||
workID := c.Param("work_id")
|
||||
|
||||
work, err := h.workSvc.LoadWork(workID)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"success": false, "message": "作品不存在"})
|
||||
return
|
||||
}
|
||||
|
||||
fp := service.Fingerprint(c.ClientIP(), c.GetHeader("User-Agent"))
|
||||
if h.rateLimiter.CanPerform(fp, "view", workID) {
|
||||
_ = h.workSvc.UpdateStats(workID, "view")
|
||||
// Reload to return the updated view count.
|
||||
if fresh, err2 := h.workSvc.LoadWork(workID); err2 == nil {
|
||||
work = fresh
|
||||
}
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"success": true,
|
||||
"data": h.workSvc.BuildResponse(work),
|
||||
})
|
||||
}
|
||||
|
||||
// SearchWorks handles GET /api/search?q=...&category=...
|
||||
func (h *PublicHandler) SearchWorks(c *gin.Context) {
|
||||
works, err := h.workSvc.SearchWorks(c.Query("q"), c.Query("category"))
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"success": false, "message": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
responses := make([]any, len(works))
|
||||
for i, w := range works {
|
||||
responses[i] = h.workSvc.BuildResponse(w)
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"success": true,
|
||||
"data": responses,
|
||||
"total": len(responses),
|
||||
})
|
||||
}
|
||||
|
||||
// GetCategories handles GET /api/categories
|
||||
func (h *PublicHandler) GetCategories(c *gin.Context) {
|
||||
cats, err := h.workSvc.AllCategories()
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"success": false, "message": err.Error()})
|
||||
return
|
||||
}
|
||||
c.JSON(http.StatusOK, gin.H{"success": true, "data": cats})
|
||||
}
|
||||
|
||||
// LikeWork handles POST /api/like/:work_id
|
||||
func (h *PublicHandler) LikeWork(c *gin.Context) {
|
||||
workID := c.Param("work_id")
|
||||
|
||||
if _, err := h.workSvc.LoadWork(workID); err != nil {
|
||||
c.JSON(http.StatusNotFound, gin.H{"success": false, "message": "作品不存在"})
|
||||
return
|
||||
}
|
||||
|
||||
fp := service.Fingerprint(c.ClientIP(), c.GetHeader("User-Agent"))
|
||||
if !h.rateLimiter.CanPerform(fp, "like", workID) {
|
||||
c.JSON(http.StatusTooManyRequests, gin.H{
|
||||
"success": false,
|
||||
"message": "操作太频繁,请稍后再试",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.workSvc.UpdateStats(workID, "like"); err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"success": false, "message": "点赞失败"})
|
||||
return
|
||||
}
|
||||
|
||||
work, _ := h.workSvc.LoadWork(workID)
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"success": true,
|
||||
"message": "点赞成功",
|
||||
"likes": work.Likes,
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user