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
}
}