Files
SproutGate/sproutgate-backend/main.go
2026-03-20 20:42:33 +08:00

100 lines
3.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package main
import (
"log"
"net/http"
"os"
"time"
"github.com/gin-contrib/cors"
"github.com/gin-gonic/gin"
"sproutgate-backend/internal/handlers"
"sproutgate-backend/internal/storage"
)
func main() {
dataDir := os.Getenv("DATA_DIR")
store, err := storage.NewStore(dataDir)
if err != nil {
log.Fatalf("failed to init storage: %v", err)
}
router := gin.Default()
router.Use(cors.New(cors.Config{
AllowOrigins: []string{"*"},
AllowMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"},
AllowHeaders: []string{"Origin", "Content-Type", "Authorization", "X-Admin-Token", "X-Visit-Ip", "X-Visit-Location", "X-Auth-Client", "X-Auth-Client-Name"},
MaxAge: 12 * time.Hour,
}))
handler := handlers.NewHandler(store)
apiIntro := gin.H{
"name": "SproutGate API",
"title": "萌芽账户认证中心",
"description": "统一认证、用户资料、每日签到、公开用户主页与管理端等 JSON HTTP 接口。",
"version": "0.1.0",
"links": gin.H{
"apiDocs": "GET /api/docs — Markdown 接口说明(本仓库 API_DOCS.md",
"health": "GET /api/health",
},
"routePrefixes": []string{
"/api/auth — 登录、注册、邮箱验证、令牌校验、当前用户、资料、签到、辅助邮箱;可选 X-Auth-Client 记录应用接入",
"/api/public — 公开用户资料、注册策略(是否强制邀请码)",
"/api/admin — 用户 CRUD、签到与注册/邀请码配置(请求头 X-Admin-Token 或 Query token",
},
}
router.GET("/", func(c *gin.Context) {
c.JSON(http.StatusOK, apiIntro)
})
router.GET("/api", func(c *gin.Context) {
c.JSON(http.StatusOK, apiIntro)
})
router.GET("/api/health", func(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{
"status": "ok",
"dataDir": store.DataDir(),
})
})
router.GET("/api/docs", func(c *gin.Context) {
c.File("API_DOCS.md")
})
router.POST("/api/auth/login", handler.Login)
router.POST("/api/auth/register", handler.Register)
router.POST("/api/auth/verify-email", handler.VerifyEmail)
router.POST("/api/auth/forgot-password", handler.ForgotPassword)
router.POST("/api/auth/reset-password", handler.ResetPassword)
router.POST("/api/auth/secondary-email/request", handler.RequestSecondaryEmail)
router.POST("/api/auth/secondary-email/verify", handler.VerifySecondaryEmail)
router.POST("/api/auth/verify", handler.Verify)
router.GET("/api/auth/me", handler.Me)
router.POST("/api/auth/check-in", handler.CheckIn)
router.PUT("/api/auth/profile", handler.UpdateProfile)
router.GET("/api/public/users/:account", handler.GetPublicUser)
router.GET("/api/public/registration-policy", handler.GetPublicRegistrationPolicy)
admin := router.Group("/api/admin")
admin.Use(handler.AdminMiddleware())
admin.GET("/users", handler.ListUsers)
admin.POST("/users", handler.CreateUser)
admin.PUT("/users/:account", handler.UpdateUser)
admin.DELETE("/users/:account", handler.DeleteUser)
admin.GET("/check-in/config", handler.GetCheckInConfig)
admin.PUT("/check-in/config", handler.UpdateCheckInConfig)
admin.GET("/registration", handler.GetAdminRegistration)
admin.PUT("/registration", handler.PutAdminRegistrationPolicy)
admin.POST("/registration/invites", handler.PostAdminInvite)
admin.DELETE("/registration/invites/:code", handler.DeleteAdminInvite)
port := os.Getenv("PORT")
if port == "" {
port = "8080"
}
if err := router.Run(":" + port); err != nil {
log.Fatalf("server stopped: %v", err)
}
}