Files
go_blog/routers/router.go

218 lines
6.6 KiB
Go
Raw Normal View History

2025-04-01 17:59:10 +08:00
package routers // Add the package declaration at the top
import (
2025-04-15 16:47:00 +08:00
"fmt"
2025-04-09 16:56:05 +08:00
"go_blog/controllers"
2025-04-15 16:47:00 +08:00
"go_blog/models"
"go_blog/serializers"
2025-05-27 19:01:05 +08:00
"go_blog/themes" // <-- 确保导入 themes 包
2025-04-15 16:47:00 +08:00
"log"
2025-04-01 17:59:10 +08:00
"net/http"
2025-05-27 19:01:05 +08:00
"strconv"
2025-05-22 13:56:57 +08:00
"time"
2025-04-01 17:59:10 +08:00
2025-06-13 08:59:01 +08:00
"github.com/gin-contrib/sessions"
2025-04-01 17:59:10 +08:00
"github.com/gin-gonic/gin"
2025-05-21 20:38:25 +08:00
"gorm.io/gorm"
2025-04-01 17:59:10 +08:00
)
2025-06-09 17:59:19 +08:00
// 新增:自定义后台认证中间件(处理页面重定向)
2025-06-13 08:59:01 +08:00
// 自定义后台认证中间件通过Session判断登录状态
2025-06-09 17:59:19 +08:00
func CheckAdminAuth() gin.HandlerFunc {
2025-06-18 18:34:08 +08:00
return func(c *gin.Context) {
currentPath := c.Request.URL.Path
session := sessions.Default(c) // 获取当前请求的Session
userID := session.Get("user_id") // 从Session中获取用户ID
loggedIn := userID != nil && userID != ""
// 已登录状态访问登录/注册页:重定向到后台首页
if (currentPath == "/admin/login" || currentPath == "/admin/register") && loggedIn {
c.Redirect(http.StatusFound, "/admin/index")
c.Abort()
return
}
// 未登录状态访问非登录/注册页:重定向到登录页
if (currentPath != "/admin/login" && currentPath != "/admin/register") && !loggedIn {
c.Redirect(http.StatusFound, "/admin/login")
c.Abort()
return
}
c.Next()
}
2025-06-13 08:59:01 +08:00
}
2025-06-09 17:59:19 +08:00
2025-06-13 08:59:01 +08:00
// 新增基于Session的认证中间件
func SessionAuthRequired() gin.HandlerFunc {
return func(c *gin.Context) {
session := sessions.Default(c)
userID := session.Get("user_id")
if userID == nil {
// 未登录,重定向到登录页
2025-06-09 17:59:19 +08:00
c.Redirect(http.StatusFound, "/admin/login")
c.Abort()
return
}
2025-06-13 08:59:01 +08:00
// 可选根据userID查询用户信息并注入上下文
// user, err := models.GetAccountByID(userID.(uint))
// if err != nil { ... }
// c.Set("user", user)
2025-06-09 17:59:19 +08:00
c.Next()
}
}
2025-04-01 17:59:10 +08:00
func RegisterRoutes(r *gin.Engine) {
2025-04-15 16:47:00 +08:00
// 注册WebSocket路由
r.GET("/events", esSSE)
r.GET("/page", func(c *gin.Context) {
2025-05-27 19:01:05 +08:00
tm, exists := c.Get("ThemeManager")
if !exists {
c.String(http.StatusInternalServerError, "Theme manager not found")
return
}
themeManager, ok := tm.(*themes.ThemeManager)
if !ok {
c.String(http.StatusInternalServerError, "Invalid theme manager type")
return
}
2025-04-15 16:47:00 +08:00
var items []models.Content
var pager serializers.Pager
2025-05-27 19:01:05 +08:00
pager.InitPager(c) // 这会从查询参数中读取 page 和 pageSize
2025-04-15 16:47:00 +08:00
offset := (pager.Page - 1) * pager.PageSize
2025-05-27 19:01:05 +08:00
dbInterface, dbOk := c.Get("DB")
if !dbOk {
2025-05-21 20:38:25 +08:00
log.Println("未找到键 'DB' 的上下文值")
c.JSON(http.StatusInternalServerError, gin.H{"error": "内部服务器错误"})
return
}
2025-05-27 19:01:05 +08:00
db, typeOk := dbInterface.(*gorm.DB)
if !typeOk {
log.Println("无法将 DB 转换为 *gorm.DB 类型")
c.JSON(http.StatusInternalServerError, gin.H{"error": "内部服务器错误"})
return
}
db.Select("*").Offset(offset).Limit(pager.PageSize).Find(&items, "type = ?", "post")
var totalCount int64
db.Model(&models.Content{}).Where("type = ?", "post").Count(&totalCount)
pager.Total = int(totalCount) // 确保 Pager 结构体中的 Total 类型匹配
tpl := themeManager.GetTemplate("index") // 假设分页列表也使用 index 模板
if tpl == nil {
c.String(http.StatusInternalServerError, "Template 'index' not found in current theme: "+themeManager.CurrentTheme())
return
}
2025-05-21 20:38:25 +08:00
2025-05-27 19:01:05 +08:00
c.Status(http.StatusOK)
c.Header("Content-Type", "text/html; charset=utf-8")
err := tpl.Execute(c.Writer, gin.H{
2025-04-15 16:47:00 +08:00
"Items": items,
2025-05-27 19:01:05 +08:00
"Pager": pager, // 确保你的 index.tmpl 支持 Pager 结构
"Title": "文章列表 - 第 " + strconv.Itoa(pager.Page) + " 页",
2025-04-15 16:47:00 +08:00
})
2025-05-27 19:01:05 +08:00
if err != nil {
c.String(http.StatusInternalServerError, "Error rendering template: "+err.Error())
}
2025-04-15 16:47:00 +08:00
})
2025-05-27 19:01:05 +08:00
2025-04-15 16:47:00 +08:00
r.GET("/createcontent", func(c *gin.Context) {
2025-05-27 19:01:05 +08:00
tm, exists := c.Get("ThemeManager")
if !exists {
c.String(http.StatusInternalServerError, "Theme manager not found")
return
}
themeManager, ok := tm.(*themes.ThemeManager)
if !ok {
c.String(http.StatusInternalServerError, "Invalid theme manager type")
return
}
// 假设你的主题中有一个名为 "content" 的模板 (content.html 或 content.tmpl)
// 注意:当前的 default 主题并没有 content.tmpl你需要添加它。
// 如果这个页面是后台页面,它可能不需要主题化,或者使用一个固定的后台模板。
tpl := themeManager.GetTemplate("content")
if tpl == nil {
c.String(http.StatusInternalServerError, "Template 'content' not found in current theme: "+themeManager.CurrentTheme()+". Make sure 'content.html' or 'content.tmpl' exists.")
return
}
c.Status(http.StatusOK)
c.Header("Content-Type", "text/html; charset=utf-8")
err := tpl.Execute(c.Writer, gin.H{
"Title": "创建新内容",
})
if err != nil {
c.String(http.StatusInternalServerError, "Error rendering template: "+err.Error())
}
2025-04-15 16:47:00 +08:00
})
r.GET("/ws", controllers.WebSocketHandler)
r.POST("/content", controllers.CreateContentHandler)
2025-04-01 17:59:10 +08:00
// Frontend routes (dynamic themes)
2025-04-09 16:56:05 +08:00
r.GET("/", controllers.Home)
r.GET("/post/:id", controllers.ShowPost)
2025-04-01 17:59:10 +08:00
2025-06-09 17:59:19 +08:00
admin := r.Group("/admin")
2025-06-13 08:59:01 +08:00
admin.Use(CheckAdminAuth())
2025-05-27 19:01:05 +08:00
{
2025-06-09 17:59:19 +08:00
// 无需认证的公开路由(登录/注册)
2025-06-13 08:59:01 +08:00
// 新增:处理 /admin 根路径跳转
admin.GET("/", func(c *gin.Context) {
// 由于 CheckAdminAuth 中间件已处理未登录场景,此处用户必定已登录
c.Redirect(http.StatusFound, "/admin/index")
})
2025-06-09 17:59:19 +08:00
admin.GET("/login", controllers.ShowLoginPage)
admin.GET("/register", controllers.ShowRegisterPage)
admin.POST("/login", controllers.UsersLoginHandler)
admin.POST("/register", controllers.UsersRegisterHandler)
2025-06-13 08:59:01 +08:00
// 需要认证的路由组
authAdmin := admin.Group("", SessionAuthRequired())
2025-06-09 17:59:19 +08:00
{
2025-06-13 08:59:01 +08:00
authAdmin.GET("/index", controllers.ShowAdminIndexPage)
authAdmin.GET("/themes", controllers.ListThemes)
authAdmin.POST("/themes/switch", controllers.SwitchTheme)
2025-06-09 17:59:19 +08:00
authAdmin.POST("/setinfo", controllers.UsersSetInfoHandler)
authAdmin.POST("/setpwd", controllers.UsersSetPwdHandler)
2025-06-13 08:59:01 +08:00
admin.GET("/logout", controllers.UsersLogoutHandler) // 添加退出路由
2025-06-09 17:59:19 +08:00
}
2025-05-27 19:01:05 +08:00
}
2025-04-01 17:59:10 +08:00
// Static files for themes
r.StaticFS("/themes", http.Dir("web/themes"))
}
2025-04-15 16:47:00 +08:00
func esSSE(c *gin.Context) {
w := c.Writer
w.Header().Set("Content-Type", "text/event-stream")
w.Header().Set("Cache-Control", "no-cache")
w.Header().Set("Connection", "keep-alive")
w.Header().Set("Access-Control-Allow-Origin", "*")
_, ok := w.(http.Flusher)
if !ok {
log.Panic("server not support") //浏览器不兼容
}
2025-05-22 13:56:57 +08:00
for {
// Simulate sending events every second
fmt.Fprintf(w, "data: %s\n\n", time.Now().Format(time.Stamp))
w.(http.Flusher).Flush()
time.Sleep(1 * time.Second)
}
2025-06-09 17:59:19 +08:00
_, err := fmt.Fprintf(w, "event: connecttime\ndata: %s\n\n", "connecttime")
if err != nil {
2025-04-15 16:47:00 +08:00
print("error", err)
return
}
}