spark-server/internal/transport/http/router.go
DESKTOP-L8OUL9F\gfl0034 753c276496 feat: PopAdmin 拉取管理、签到能量 API 与图片 150KiB 硬上限
管理端按用户查询开启通讯录/相册/媒体拉取;服务端写入路径自动压图;新增 /v1/sign 与 /v1/energy。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-11-02 12:44:06 +08:00

320 lines
8.8 KiB
Go

package httpx
import (
"net/http"
"github.com/gin-gonic/gin"
"spark-server/internal/module/square/entity"
"spark-server/internal/pkg/errs"
"spark-server/internal/pkg/i18n"
"spark-server/internal/pkg/reply"
"spark-server/internal/pkg/reqctx"
authhandler "spark-server/internal/transport/http/handler/auth"
clienthandler "spark-server/internal/transport/http/handler/client"
convhandler "spark-server/internal/transport/http/handler/conversation"
energyhandler "spark-server/internal/transport/http/handler/energy"
favhandler "spark-server/internal/transport/http/handler/favorite"
filehandler "spark-server/internal/transport/http/handler/file"
friendhandler "spark-server/internal/transport/http/handler/friend"
grouphandler "spark-server/internal/transport/http/handler/group"
msghandler "spark-server/internal/transport/http/handler/message"
metahandler "spark-server/internal/transport/http/handler/meta"
momenthandler "spark-server/internal/transport/http/handler/moment"
musichandler "spark-server/internal/transport/http/handler/music"
smshandler "spark-server/internal/transport/http/handler/sms"
squarehandler "spark-server/internal/transport/http/handler/square"
userhandler "spark-server/internal/transport/http/handler/user"
"spark-server/internal/transport/http/respond"
)
func registerRoutes(r *gin.Engine, deps *EngineDeps) {
registerDocs(r)
registerHealth(r, deps.Health)
registerAdminRoutes(r, deps)
registerClientPopAliases(r, deps)
v1 := r.Group("/v1")
registerMetaRoutes(v1)
registerAuthRoutes(v1, deps)
registerSMSRoutes(v1, deps)
registerClientRoutes(v1, deps)
registerUserRoutes(v1, deps)
registerFriendRoutes(v1, deps)
registerGroupRoutes(v1, deps)
registerFileRoutes(v1, deps)
registerFavoriteRoutes(v1, deps)
registerMomentRoutes(v1, deps)
registerSquareRoutes(v1, deps)
registerMusicRoutes(v1, deps)
registerSignEnergyRoutes(v1, deps)
registerConversationRoutes(v1, deps)
registerMessageRoutes(v1, deps)
}
func registerSignEnergyRoutes(v1 *gin.RouterGroup, deps *EngineDeps) {
if deps.Energy == nil {
return
}
h := energyhandler.New(deps.Energy)
sg := v1.Group("/sign")
sg.GET("/calendar", h.Calendar)
sg.POST("", h.CheckIn)
sg.GET("/makeup", h.MakeupCheck)
sg.POST("/makeup", h.Makeup)
eg := v1.Group("/energy")
eg.GET("", h.Balance)
eg.GET("/logs", h.Logs)
}
func registerHealth(r *gin.Engine, h Health) {
r.GET("/healthz", func(c *gin.Context) {
JSON(c, gin.H{"status": "ok"})
})
r.GET("/readyz", func(c *gin.Context) {
if h == nil {
JSON(c, gin.H{"status": "ok", "ready": true})
return
}
ok, data := h.Ready(c.Request.Context())
if ok {
JSON(c, data)
return
}
lang := reqctx.Lang(c.Request.Context())
c.JSON(http.StatusServiceUnavailable, reply.Stamp(c.Request.Context(), reply.FailData(
errs.ErrAvailable.Code,
i18n.ErrorMsg(lang, errs.ErrAvailable.Code),
data,
)))
})
}
func registerMetaRoutes(v1 *gin.RouterGroup) {
h := metahandler.New()
v1.GET("/meta/enums", h.Enums)
}
func registerAuthRoutes(v1 *gin.RouterGroup, deps *EngineDeps) {
g := v1.Group("/auth")
if deps.Login == nil {
return
}
h := authhandler.New(deps.Login)
g.POST("/login", h.Login)
g.POST("/password-login", h.PasswordLogin)
g.POST("/token/refresh", h.Refresh)
g.POST("/logout", h.Logout)
if deps.Client != nil {
ch := clienthandler.New(deps.Client)
g.POST("/password", ch.SetPassword)
}
}
func registerClientRoutes(v1 *gin.RouterGroup, deps *EngineDeps) {
if deps.Client == nil {
return
}
h := clienthandler.New(deps.Client)
v1.GET("/legal/agreements", h.LegalAgreements)
v1.POST("/feedback", h.SubmitFeedback)
v1.GET("/subscriptions/plans", h.SubscriptionPlans)
v1.GET("/developer-apps", h.DeveloperApps)
}
func registerClientPopAliases(r *gin.Engine, deps *EngineDeps) {
if deps == nil || deps.Client == nil {
return
}
h := clienthandler.New(deps.Client)
for _, prefix := range []string{"/api/client/pop", "/api/client/spark"} {
g := r.Group(prefix)
g.GET("/developer-apps", h.DeveloperApps)
}
}
func registerSMSRoutes(v1 *gin.RouterGroup, deps *EngineDeps) {
if deps.SMS == nil {
return
}
h := smshandler.New(deps.SMS)
g := v1.Group("/sms")
g.POST("/codes", h.SendCode)
}
func registerUserRoutes(v1 *gin.RouterGroup, deps *EngineDeps) {
if deps.Users == nil {
return
}
h := userhandler.New(deps.Users)
g := v1.Group("/users")
g.GET("/me", h.Me)
g.PATCH("/me", h.PatchMe)
g.DELETE("/me", h.DeleteMe)
}
func registerFriendRoutes(v1 *gin.RouterGroup, deps *EngineDeps) {
if deps.Friends == nil {
return
}
h := friendhandler.New(deps.Friends)
g := v1.Group("/friends")
g.GET("/lookup", h.Lookup)
g.GET("/requests", h.ListRequests)
g.POST("/requests", h.Apply)
g.POST("/requests/reject", h.Reject)
g.GET("", h.List)
g.POST("", h.Accept)
g.GET("/:uid", h.Get)
g.DELETE("/:uid", h.Delete)
g.PUT("/:uid/remark", h.Remark)
g.PUT("/:uid/pin", h.Pin)
g.DELETE("/:uid/pin", h.Unpin)
g.PUT("/:uid/block", h.Block)
g.DELETE("/:uid/block", h.Unblock)
g.POST("/:uid/reports", h.Report)
f := v1.Group("/follows")
f.GET("/:uid", h.GetFollow)
f.PUT("/:uid", h.Follow)
f.DELETE("/:uid", h.Unfollow)
}
func registerGroupRoutes(v1 *gin.RouterGroup, deps *EngineDeps) {
if deps.Groups == nil {
return
}
h := grouphandler.New(deps.Groups)
g := v1.Group("/groups")
g.POST("", h.Create)
g.GET("", h.List)
g.GET("/:id/members", h.ListMembers)
g.POST("/:id/members", h.Invite)
g.PATCH("/:id/members/:uid", h.UpdateMember)
g.DELETE("/:id/members/:uid", h.RemoveMember)
g.POST("/:id/transfer", h.Transfer)
g.GET("/:id", h.Get)
g.PATCH("/:id", h.Update)
g.DELETE("/:id", h.Dissolve)
}
func registerFileRoutes(v1 *gin.RouterGroup, deps *EngineDeps) {
if deps.Files == nil {
return
}
h := filehandler.New(deps.Files)
g := v1.Group("/files")
g.POST("", h.Create)
g.POST("/batch", h.CreateBatch)
g.POST("/downloads", h.Download)
g.POST("/downloads/batch", h.DownloadBatch)
}
func registerFavoriteRoutes(v1 *gin.RouterGroup, deps *EngineDeps) {
if deps.Favorites == nil {
return
}
h := favhandler.New(deps.Favorites)
g := v1.Group("/favorites")
g.GET("", h.List)
g.POST("", h.Create)
g.DELETE("/:id", h.Delete)
}
func registerMomentRoutes(v1 *gin.RouterGroup, deps *EngineDeps) {
if deps.Moments == nil {
return
}
h := momenthandler.New(deps.Moments)
g := v1.Group("/moments")
g.GET("", h.Feed)
g.POST("", h.Publish)
g.GET("/unread", h.Unread)
g.PUT("/read", h.Read)
g.GET("/notices", h.ListNotices)
g.POST("/notices/read", h.ReadNotices)
g.GET("/settings", h.GetSettings)
g.PATCH("/settings", h.PatchSettings)
g.PUT("/settings/hides/:uid", h.PutHide)
g.DELETE("/settings/hides/:uid", h.DeleteHide)
g.GET("/users/:uid", h.Album)
g.GET("/:id", h.Get)
g.DELETE("/:id", h.Delete)
g.PUT("/:id/like", h.Like)
g.DELETE("/:id/like", h.Unlike)
g.POST("/:id/comments", h.CreateComment)
g.DELETE("/:id/comments/:cid", h.DeleteComment)
}
func registerSquareRoutes(v1 *gin.RouterGroup, deps *EngineDeps) {
if deps.Square == nil {
return
}
for _, ch := range []string{"square", "squarenovel", "squaresteps", "squarehealth"} {
registerSquareChannelRoutes(v1, deps, ch)
}
}
func registerSquareChannelRoutes(v1 *gin.RouterGroup, deps *EngineDeps, channel string) {
h := squarehandler.New(deps.Square, entity.Channel(channel))
g := v1.Group("/" + channel)
g.GET("/categories", h.Categories)
g.GET("/posts", h.Feed)
g.POST("/posts", h.Publish)
g.GET("/posts/:id", h.Get)
g.DELETE("/posts/:id", h.Delete)
g.PUT("/posts/:id/like", h.Like)
g.DELETE("/posts/:id/like", h.Unlike)
g.POST("/posts/:id/comments", h.CreateComment)
g.DELETE("/posts/:id/comments/:cid", h.DeleteComment)
g.GET("/users/:uid/posts", h.UserPosts)
g.GET("/notices", h.ListNotices)
g.GET("/notices/unread", h.NoticeUnread)
g.POST("/notices/read", h.ReadNotices)
}
func registerMusicRoutes(v1 *gin.RouterGroup, deps *EngineDeps) {
if deps.Music == nil {
return
}
h := musichandler.New(deps.Music)
g := v1.Group("/music")
// 客户端可读:无需登录(列表为运营配置的公开曲目元数据)
g.GET("/playlist", h.Playlist)
g.GET("/playlist/grouped", h.PlaylistGrouped)
g.GET("/tracks/:id", h.GetTrack)
g.GET("/categories", h.Categories)
g.GET("/settings", h.Settings)
}
func registerConversationRoutes(v1 *gin.RouterGroup, deps *EngineDeps) {
if deps.Sync == nil {
return
}
h := convhandler.New(deps.Sync)
g := v1.Group("/conversations")
g.GET("", h.Inbox)
}
func registerMessageRoutes(v1 *gin.RouterGroup, deps *EngineDeps) {
if deps.Messages == nil {
return
}
h := msghandler.New(deps.Messages)
g := v1.Group("/messages")
g.GET("", h.History)
g.POST("", h.Send)
g.POST("/:id/recall", h.Recall)
g.DELETE("/:id", h.Delete)
}
func JSON(c *gin.Context, data any) {
respond.JSON(c, data)
}
func JSONError(c *gin.Context, err error) {
respond.JSONError(c, err)
}
func BindJSON(c *gin.Context, dst any) error {
return respond.BindJSON(c, dst)
}