Files
backend/internal/router/router.go
lan 21293644b8 Refactor backend APIs to RESTful route patterns.
Align group and conversation handlers/services with path-based endpoints, and unify response/service error handling for related modules.

Made-with: Cursor
2026-03-10 20:52:50 +08:00

333 lines
14 KiB
Go

package router
import (
"github.com/gin-gonic/gin"
"carrot_bbs/internal/handler"
"carrot_bbs/internal/middleware"
"carrot_bbs/internal/service"
)
// Router 路由配置
type Router struct {
engine *gin.Engine
userHandler *handler.UserHandler
postHandler *handler.PostHandler
commentHandler *handler.CommentHandler
messageHandler *handler.MessageHandler
notificationHandler *handler.NotificationHandler
uploadHandler *handler.UploadHandler
pushHandler *handler.PushHandler
systemMessageHandler *handler.SystemMessageHandler
groupHandler *handler.GroupHandler
stickerHandler *handler.StickerHandler
gorseHandler *handler.GorseHandler
voteHandler *handler.VoteHandler
jwtService *service.JWTService
}
// New 创建路由
func New(
userHandler *handler.UserHandler,
postHandler *handler.PostHandler,
commentHandler *handler.CommentHandler,
messageHandler *handler.MessageHandler,
notificationHandler *handler.NotificationHandler,
uploadHandler *handler.UploadHandler,
jwtService *service.JWTService,
pushHandler *handler.PushHandler,
systemMessageHandler *handler.SystemMessageHandler,
groupHandler *handler.GroupHandler,
stickerHandler *handler.StickerHandler,
gorseHandler *handler.GorseHandler,
voteHandler *handler.VoteHandler,
) *Router {
// 设置JWT服务
userHandler.SetJWTService(jwtService)
r := &Router{
engine: gin.Default(),
userHandler: userHandler,
postHandler: postHandler,
commentHandler: commentHandler,
messageHandler: messageHandler,
notificationHandler: notificationHandler,
uploadHandler: uploadHandler,
pushHandler: pushHandler,
systemMessageHandler: systemMessageHandler,
groupHandler: groupHandler,
stickerHandler: stickerHandler,
gorseHandler: gorseHandler,
voteHandler: voteHandler,
jwtService: jwtService,
}
r.setupRoutes()
return r
}
// setupRoutes 设置路由
func (r *Router) setupRoutes() {
// 中间件
r.engine.Use(middleware.CORS())
// 健康检查
r.engine.GET("/health", func(c *gin.Context) {
c.JSON(200, gin.H{"status": "ok"})
})
// API v1
v1 := r.engine.Group("/api/v1")
{
// 认证路由(公开)
auth := v1.Group("/auth")
{
auth.POST("/register", r.userHandler.Register)
auth.POST("/register/send-code", r.userHandler.SendRegisterCode)
auth.POST("/login", r.userHandler.Login)
auth.POST("/password/send-code", r.userHandler.SendPasswordResetCode)
auth.POST("/password/reset", r.userHandler.ResetPassword)
auth.POST("/refresh", r.userHandler.RefreshToken)
}
// 需要认证的路由
authMiddleware := middleware.Auth(r.jwtService)
// 用户路由
users := v1.Group("/users")
{
// 当前用户
users.GET("/me", authMiddleware, r.userHandler.GetCurrentUser)
users.PUT("/me", authMiddleware, r.userHandler.UpdateUser)
users.POST("/me/email/send-code", authMiddleware, r.userHandler.SendEmailVerifyCode)
users.POST("/me/email/verify", authMiddleware, r.userHandler.VerifyEmail)
users.POST("/me/avatar", authMiddleware, r.uploadHandler.UploadAvatar)
users.POST("/me/cover", authMiddleware, r.uploadHandler.UploadCover)
users.POST("/change-password/send-code", authMiddleware, r.userHandler.SendChangePasswordCode)
users.POST("/change-password", authMiddleware, r.userHandler.ChangePassword)
// 搜索用户
users.GET("/search", middleware.OptionalAuth(r.jwtService), r.userHandler.Search)
// 其他用户
users.GET("/:id", middleware.OptionalAuth(r.jwtService), r.userHandler.GetUserByID)
users.POST("/:id/follow", authMiddleware, r.userHandler.FollowUser)
users.DELETE("/:id/follow", authMiddleware, r.userHandler.UnfollowUser)
users.POST("/:id/block", authMiddleware, r.userHandler.BlockUser)
users.DELETE("/:id/block", authMiddleware, r.userHandler.UnblockUser)
users.GET("/:id/block-status", authMiddleware, r.userHandler.GetBlockStatus)
users.GET("/blocks", authMiddleware, r.userHandler.GetBlockedUsers)
users.GET("/:id/following", authMiddleware, r.userHandler.GetFollowingList)
users.GET("/:id/followers", authMiddleware, r.userHandler.GetFollowersList)
// 用户帖子 - 使用 OptionalAuth 获取当前用户点赞/收藏状态
users.GET("/:id/posts", middleware.OptionalAuth(r.jwtService), r.postHandler.GetUserPosts)
users.GET("/:id/favorites", middleware.OptionalAuth(r.jwtService), r.postHandler.GetFavorites)
}
// 认证路由(公开)
authPublic := v1.Group("/auth")
{
authPublic.GET("/check-username", r.userHandler.CheckUsername)
}
// 帖子路由
posts := v1.Group("/posts")
{
// 使用 OptionalAuth 中间件来获取用户登录状态
posts.GET("", middleware.OptionalAuth(r.jwtService), r.postHandler.List)
posts.GET("/search", middleware.OptionalAuth(r.jwtService), r.postHandler.Search)
posts.GET("/:id", middleware.OptionalAuth(r.jwtService), r.postHandler.GetByID)
posts.POST("", authMiddleware, r.postHandler.Create)
posts.PUT("/:id", authMiddleware, r.postHandler.Update)
posts.DELETE("/:id", authMiddleware, r.postHandler.Delete)
// 浏览量记录(可选认证,允许游客浏览)
posts.POST("/:id/view", middleware.OptionalAuth(r.jwtService), r.postHandler.RecordView)
// 点赞
posts.POST("/:id/like", authMiddleware, r.postHandler.Like)
posts.DELETE("/:id/like", authMiddleware, r.postHandler.Unlike)
// 收藏
posts.POST("/:id/favorite", authMiddleware, r.postHandler.Favorite)
posts.DELETE("/:id/favorite", authMiddleware, r.postHandler.Unfavorite)
// 投票相关路由
posts.POST("/vote", authMiddleware, r.voteHandler.CreateVotePost) // 创建投票帖子
posts.GET("/:id/vote", middleware.OptionalAuth(r.jwtService), r.voteHandler.GetVoteResult) // 获取投票结果
posts.POST("/:id/vote", authMiddleware, r.voteHandler.Vote) // 投票
posts.DELETE("/:id/vote", authMiddleware, r.voteHandler.Unvote) // 取消投票
}
// 投票选项路由
voteOptions := v1.Group("/vote-options")
voteOptions.Use(authMiddleware)
{
voteOptions.PUT("/:id", r.voteHandler.UpdateVoteOption) // 更新选项
}
// 评论路由
comments := v1.Group("/comments")
{
comments.GET("/post/:id", middleware.OptionalAuth(r.jwtService), r.commentHandler.GetByPostID)
comments.GET("/:id", middleware.OptionalAuth(r.jwtService), r.commentHandler.GetByID)
comments.POST("", authMiddleware, r.commentHandler.Create)
comments.PUT("/:id", authMiddleware, r.commentHandler.Update)
comments.DELETE("/:id", authMiddleware, r.commentHandler.Delete)
comments.GET("/:id/replies", middleware.OptionalAuth(r.jwtService), r.commentHandler.GetReplies)
comments.GET("/:id/replies/flat", middleware.OptionalAuth(r.jwtService), r.commentHandler.GetRepliesByRootID) // 扁平化分页获取回复
// 评论点赞
comments.POST("/:id/like", authMiddleware, r.commentHandler.Like)
comments.DELETE("/:id/like", authMiddleware, r.commentHandler.Unlike)
}
// 会话路由
conversations := v1.Group("/conversations")
conversations.Use(authMiddleware)
{
// ================================================================
// 新的 RESTful 风格路由(推荐使用)
// ================================================================
conversations.GET("", r.messageHandler.HandleGetConversationList) // 列表
conversations.POST("", r.messageHandler.HandleCreateConversation) // 创建
conversations.GET("/:id", r.messageHandler.HandleGetConversation) // 详情
conversations.GET("/:id/messages", r.messageHandler.HandleGetMessages) // 消息列表
conversations.POST("/:id/messages", r.messageHandler.HandleSendMessage) // 发送消息
conversations.POST("/:id/read", r.messageHandler.HandleMarkRead) // 标记已读
conversations.PUT("/:id/pinned", r.messageHandler.HandleSetConversationPinned) // 置顶设置
conversations.GET("/unread/count", r.messageHandler.GetUnreadCount) // 未读数
conversations.POST("/:id/typing", r.messageHandler.HandleTyping) // 输入状态
conversations.DELETE("/:id/self", r.messageHandler.HandleDeleteConversationForSelf) // 删除会话(仅自己)
}
realtime := v1.Group("/realtime")
realtime.Use(authMiddleware)
{
realtime.GET("/sse", r.messageHandler.HandleSSE)
}
// 消息操作路由
messages := v1.Group("/messages")
messages.Use(authMiddleware)
{
// 撤回/删除消息(统一接口)
messages.POST("/delete_msg", r.messageHandler.HandleDeleteMsg)
}
// 通知路由
notifications := v1.Group("/notifications")
{
notifications.GET("", authMiddleware, r.notificationHandler.GetNotifications)
notifications.POST("/:id/read", authMiddleware, r.notificationHandler.MarkAsRead)
notifications.POST("/read-all", authMiddleware, r.notificationHandler.MarkAllAsRead)
notifications.GET("/unread-count", authMiddleware, r.notificationHandler.GetUnreadCount)
notifications.DELETE("/:id", authMiddleware, r.notificationHandler.DeleteNotification)
notifications.DELETE("", authMiddleware, r.notificationHandler.ClearAllNotifications)
}
// 上传路由
uploads := v1.Group("/uploads")
{
uploads.POST("/images", authMiddleware, r.uploadHandler.UploadImage)
}
// 推送相关路由
if r.pushHandler != nil {
pushGroup := v1.Group("/push")
pushGroup.Use(authMiddleware)
{
pushGroup.POST("/devices", r.pushHandler.RegisterDevice)
pushGroup.GET("/devices", r.pushHandler.GetMyDevices)
pushGroup.DELETE("/devices/:device_id", r.pushHandler.UnregisterDevice)
pushGroup.PUT("/devices/:device_id/token", r.pushHandler.UpdateDeviceToken)
pushGroup.GET("/records", r.pushHandler.GetPushRecords)
}
}
// 系统消息路由
if r.systemMessageHandler != nil {
msgGroup := v1.Group("/messages")
msgGroup.Use(authMiddleware)
{
msgGroup.GET("/system", r.systemMessageHandler.GetSystemMessages)
msgGroup.GET("/system/unread-count", r.systemMessageHandler.GetUnreadCount)
msgGroup.PUT("/system/:id/read", r.systemMessageHandler.MarkAsRead)
msgGroup.PUT("/system/read-all", r.systemMessageHandler.MarkAllAsRead)
}
}
// 群组路由
if r.groupHandler != nil {
groups := v1.Group("/groups")
groups.Use(authMiddleware)
{
// ================================================================
// 新的 RESTful 风格路由(推荐使用)
// ================================================================
// 群组基本操作
groups.GET("", r.groupHandler.HandleGetUserGroups) // 列表
groups.POST("", r.groupHandler.HandleCreateGroup) // 创建
groups.GET("/:id", r.groupHandler.HandleGetGroupInfo) // 详情
groups.GET("/:id/me", r.groupHandler.HandleGetMyMemberInfo) // 当前用户成员信息
groups.DELETE("/:id", r.groupHandler.HandleDissolveGroup) // 解散群组
groups.POST("/:id/transfer", r.groupHandler.HandleTransferOwner) // 转让群主
// 成员管理
groups.POST("/:id/invitations", r.groupHandler.HandleInviteMembers) // 邀请成员
groups.POST("/:id/join-requests", r.groupHandler.HandleJoinGroup) // 申请加群
groups.POST("/:id/join-requests/respond", r.groupHandler.HandleRespondInvite) // 响应加群邀请/申请
groups.POST("/:id/leave", r.groupHandler.HandleSetGroupLeave) // 退群
groups.GET("/:id/members", r.groupHandler.HandleGetGroupMemberList) // 成员列表
groups.POST("/:id/members/kick", r.groupHandler.HandleSetGroupKick) // 踢出成员
groups.PUT("/:id/members/:user_id/admin", r.groupHandler.HandleSetGroupAdmin) // 设置管理员
groups.PUT("/:id/members/me/nickname", r.groupHandler.HandleSetNickname) // 设置群昵称
groups.POST("/:id/members/ban", r.groupHandler.HandleSetGroupBan) // 禁言成员
// 群设置
groups.PUT("/:id/ban", r.groupHandler.HandleSetGroupWholeBan) // 全员禁言
groups.PUT("/:id/join-type", r.groupHandler.HandleSetJoinType) // 加群方式
groups.PUT("/:id/name", r.groupHandler.HandleSetGroupName) // 群名称
groups.PUT("/:id/avatar", r.groupHandler.HandleSetGroupAvatar) // 群头像
// 群公告
groups.POST("/:id/announcements", r.groupHandler.HandleCreateAnnouncement) // 创建公告
groups.GET("/:id/announcements", r.groupHandler.HandleGetAnnouncements) // 公告列表
groups.DELETE("/:id/announcements/:announcement_id", r.groupHandler.HandleDeleteAnnouncement) // 删除公告
// 加群请求处理
groups.POST("/:id/join-requests/handle", r.groupHandler.HandleSetGroupAddRequest) // 处理加群请求
}
}
// 自定义表情路由
if r.stickerHandler != nil {
stickers := v1.Group("/stickers")
stickers.Use(authMiddleware)
{
stickers.GET("", r.stickerHandler.GetStickers)
stickers.POST("", r.stickerHandler.AddSticker)
stickers.DELETE("", r.stickerHandler.DeleteSticker)
stickers.POST("/reorder", r.stickerHandler.ReorderStickers)
stickers.GET("/check", r.stickerHandler.CheckStickerExists)
}
}
// Gorse 管理路由
if r.gorseHandler != nil {
gorseGroup := v1.Group("/gorse")
{
gorseGroup.GET("/status", r.gorseHandler.GetStatus)
gorseGroup.POST("/import", r.gorseHandler.ImportData)
}
}
}
}
// Engine 获取引擎
func (r *Router) Engine() *gin.Engine {
return r.engine
}