- 新增 internal/version 包维护服务端版本(默认 0.1.0,可用 -ldflags -X 覆盖),GET /api/health 返回 version 字段 - main.go Swagger @version 与常量对齐为 0.1.0,重新生成 docs;api_test 增加版本断言 - 前端 package.json 升至 0.1.0,Vite 注入版本、git 短哈希与构建时间(无 git 自动省略哈希) - 新增 api/version.ts 与 version store,启动时从 health 读取后端版本(失败显示 —) - 页脚左下角显示“前端 vX | 后端 vY | 构建 +hash · 时间”,三语文案补齐
132 lines
4.2 KiB
Go
132 lines
4.2 KiB
Go
// Package api 负责 HTTP 接口路由装配。
|
|
package api
|
|
|
|
import (
|
|
"net/http"
|
|
"path"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
swaggerFiles "github.com/swaggo/files"
|
|
ginSwagger "github.com/swaggo/gin-swagger"
|
|
"gorm.io/gorm"
|
|
|
|
"rill/internal/auth"
|
|
"rill/internal/avatar"
|
|
"rill/internal/config"
|
|
"rill/internal/database"
|
|
"rill/internal/file"
|
|
"rill/internal/nav"
|
|
"rill/internal/note"
|
|
"rill/internal/site"
|
|
"rill/internal/user"
|
|
"rill/internal/usergroup"
|
|
"rill/internal/version"
|
|
"rill/internal/videocategory"
|
|
)
|
|
|
|
// RegisterRoutes 注册 API 路由。health、swagger、auth、站点信息、文件查看、头部导航与视频分类读取公开;notes、个人资料与文件上传删除需登录;站点信息更新、导航维护、视频分类维护、用户与用户组管理仅限管理员。
|
|
func RegisterRoutes(rg *gin.RouterGroup, db *gorm.DB, cfg *config.Config) {
|
|
authn := auth.NewAuthenticator(cfg)
|
|
|
|
rg.GET("/health", health(db))
|
|
|
|
swagger := rg.Group("/swagger")
|
|
{
|
|
swagger.GET("", func(c *gin.Context) {
|
|
c.Redirect(http.StatusFound, path.Join("/", rg.BasePath(), "swagger", "index.html"))
|
|
})
|
|
swagger.GET("/*any", ginSwagger.WrapHandler(swaggerFiles.Handler, ginSwagger.URL("doc.json")))
|
|
}
|
|
|
|
authGroup := rg.Group("/auth")
|
|
{
|
|
authGroup.POST("/register", auth.Register(db))
|
|
authGroup.POST("/login", auth.Login(db, authn))
|
|
}
|
|
|
|
rg.GET("/site", site.Get(db))
|
|
rg.GET("/files/:id", file.View(db, cfg))
|
|
rg.GET("/nav-links", nav.List(db))
|
|
rg.GET("/video-categories", videocategory.List(db))
|
|
|
|
authed := rg.Group("", authn.RequireAuth(db))
|
|
{
|
|
authed.GET("/me", auth.Me())
|
|
authed.PUT("/me", auth.UpdateMe(db))
|
|
authed.PUT("/me/avatar", avatar.Update(db, cfg))
|
|
authed.DELETE("/me/avatar", avatar.Delete(db, cfg))
|
|
authed.POST("/files", file.Upload(db, cfg))
|
|
authed.DELETE("/files/:id", file.Delete(db, cfg))
|
|
|
|
notes := authed.Group("/notes")
|
|
{
|
|
notes.GET("", note.List(db))
|
|
notes.POST("", note.Create(db))
|
|
notes.GET("/:id", note.Get(db))
|
|
notes.PUT("/:id", note.Update(db))
|
|
notes.DELETE("/:id", note.Delete(db))
|
|
}
|
|
}
|
|
|
|
admin := rg.Group("", authn.RequireAuth(db), auth.RequireAdmin())
|
|
{
|
|
admin.PUT("/site", site.Update(db, cfg))
|
|
admin.PUT("/site/logo", site.UploadLogo(db, cfg))
|
|
admin.DELETE("/site/logo", site.DeleteLogo(db, cfg))
|
|
admin.PUT("/site/favicon", site.UploadFavicon(db, cfg))
|
|
admin.DELETE("/site/favicon", site.DeleteFavicon(db, cfg))
|
|
|
|
admin.GET("/nav-links/list", nav.ListAll(db))
|
|
admin.POST("/nav-links", nav.Create(db))
|
|
admin.PUT("/nav-links/:id", nav.Update(db))
|
|
admin.DELETE("/nav-links/:id", nav.Delete(db))
|
|
|
|
admin.GET("/video-categories/list", videocategory.ListAll(db))
|
|
admin.POST("/video-categories", videocategory.Create(db, cfg))
|
|
admin.PUT("/video-categories/:id", videocategory.Update(db, cfg))
|
|
admin.DELETE("/video-categories/:id", videocategory.Delete(db, cfg))
|
|
|
|
users := admin.Group("/users")
|
|
{
|
|
users.GET("", user.List(db))
|
|
users.POST("", user.Create(db))
|
|
users.GET("/:id", user.Get(db))
|
|
users.PUT("/:id", user.Update(db))
|
|
users.DELETE("/:id", user.Delete(db))
|
|
}
|
|
|
|
groups := admin.Group("/user-groups")
|
|
{
|
|
groups.GET("", usergroup.List(db))
|
|
groups.POST("", usergroup.Create(db))
|
|
groups.GET("/:id", usergroup.Get(db))
|
|
groups.PUT("/:id", usergroup.Update(db))
|
|
groups.DELETE("/:id", usergroup.Delete(db))
|
|
}
|
|
}
|
|
}
|
|
|
|
// HealthResponse 健康检查响应。
|
|
type HealthResponse struct {
|
|
Status string `json:"status" example:"ok"`
|
|
Version string `json:"version" example:"0.1.0"`
|
|
Error string `json:"error,omitempty" example:"database unavailable"`
|
|
}
|
|
|
|
// @Summary Health check
|
|
// @Description Check service and database connectivity; returns 503 when the database is unavailable. The version field reports the current server version.
|
|
// @Tags public
|
|
// @Produce json
|
|
// @Success 200 {object} api.HealthResponse
|
|
// @Failure 503 {object} api.HealthResponse
|
|
// @Router /health [get]
|
|
func health(db *gorm.DB) gin.HandlerFunc {
|
|
return func(c *gin.Context) {
|
|
if err := database.Ping(c.Request.Context(), db); err != nil {
|
|
c.JSON(http.StatusServiceUnavailable, HealthResponse{Status: "error", Version: version.Version, Error: "database unavailable"})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, HealthResponse{Status: "ok", Version: version.Version})
|
|
}
|
|
}
|