This commit is contained in:
@@ -1,9 +1,3 @@
|
|||||||
/*
|
|
||||||
@Time : 2020/6/28 21:48
|
|
||||||
@Author : xuyiqing
|
|
||||||
@File : config.py
|
|
||||||
*/
|
|
||||||
|
|
||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -57,7 +51,7 @@ type Config struct {
|
|||||||
Security SecurityConfig
|
Security SecurityConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
var globalConfig *Config // 新增全局配置变量
|
var globalConfig *Config
|
||||||
|
|
||||||
func LoadConfig(configPath string) (*Config, error) {
|
func LoadConfig(configPath string) (*Config, error) {
|
||||||
// 1. 基础配置
|
// 1. 基础配置
|
||||||
@@ -84,10 +78,9 @@ func LoadConfig(configPath string) (*Config, error) {
|
|||||||
return nil, fmt.Errorf("读取配置文件失败: %w", err)
|
return nil, fmt.Errorf("读取配置文件失败: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
//监控并重新读取配置文件
|
// 监控配置文件变更
|
||||||
viper.WatchConfig()
|
viper.WatchConfig()
|
||||||
viper.OnConfigChange(func(e fsnotify.Event) {
|
viper.OnConfigChange(func(e fsnotify.Event) {
|
||||||
// 配置文件发生变更之后会调用的回调函数
|
|
||||||
fmt.Println("Config file changed:", e.Name)
|
fmt.Println("Config file changed:", e.Name)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,3 @@
|
|||||||
/*
|
|
||||||
@Time : 2020/6/28 21:40
|
|
||||||
@Author : xuyiqing
|
|
||||||
@File : users.py
|
|
||||||
*/
|
|
||||||
|
|
||||||
package admin
|
package admin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
@@ -2,13 +2,15 @@ package controllers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"go_blog/models"
|
"go_blog/models"
|
||||||
|
"go_blog/utils"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 登录
|
// CreateContentHandler 创建内容
|
||||||
func CreateContentHandler(ctx *gin.Context) {
|
func CreateContentHandler(ctx *gin.Context) {
|
||||||
|
|
||||||
var content models.Content
|
var content models.Content
|
||||||
if err := ctx.ShouldBindJSON(&content); err != nil {
|
if err := ctx.ShouldBindJSON(&content); err != nil {
|
||||||
ctx.JSON(400, gin.H{"error": err.Error()})
|
ctx.JSON(400, gin.H{"error": err.Error()})
|
||||||
@@ -22,3 +24,61 @@ func CreateContentHandler(ctx *gin.Context) {
|
|||||||
|
|
||||||
ctx.JSON(201, content)
|
ctx.JSON(201, content)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PageList 分页文章列表
|
||||||
|
func PageList(c *gin.Context) {
|
||||||
|
themeManager, ok := getThemeManager(c)
|
||||||
|
if !ok {
|
||||||
|
c.String(http.StatusInternalServerError, "Theme manager not found")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
db, ok := getDB(c)
|
||||||
|
if !ok {
|
||||||
|
c.String(http.StatusInternalServerError, "DB not found")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var items []models.Content
|
||||||
|
var pager utils.Pager
|
||||||
|
pager.InitPager(c)
|
||||||
|
offset := (pager.Page - 1) * pager.PageSize
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
tpl := themeManager.GetTemplate("index")
|
||||||
|
if tpl == nil {
|
||||||
|
c.String(http.StatusInternalServerError, "Template 'index' not found")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Header("Content-Type", "text/html; charset=utf-8")
|
||||||
|
tpl.Execute(c.Writer, gin.H{
|
||||||
|
"Items": items,
|
||||||
|
"Pager": pager,
|
||||||
|
"Title": "文章列表 - 第 " + strconv.Itoa(pager.Page) + " 页",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateContentPage 创建内容页面
|
||||||
|
func CreateContentPage(c *gin.Context) {
|
||||||
|
themeManager, ok := getThemeManager(c)
|
||||||
|
if !ok {
|
||||||
|
c.String(http.StatusInternalServerError, "Theme manager not found")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
tpl := themeManager.GetTemplate("content")
|
||||||
|
if tpl == nil {
|
||||||
|
c.String(http.StatusInternalServerError, "Template 'content' not found")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Header("Content-Type", "text/html; charset=utf-8")
|
||||||
|
tpl.Execute(c.Writer, gin.H{
|
||||||
|
"Title": "创建新内容",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,50 +6,55 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"gorm.io/gorm" // <-- 确保导入 gorm
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Home(c *gin.Context) {
|
// getThemeManager 从上下文中获取主题管理器
|
||||||
|
func getThemeManager(c *gin.Context) (*utils.ThemeManager, bool) {
|
||||||
tm, exists := c.Get("ThemeManager")
|
tm, exists := c.Get("ThemeManager")
|
||||||
if !exists {
|
if !exists {
|
||||||
c.String(http.StatusInternalServerError, "Theme manager not found in context")
|
return nil, false
|
||||||
return
|
|
||||||
}
|
}
|
||||||
themeManager, ok := tm.(*utils.ThemeManager)
|
themeManager, ok := tm.(*utils.ThemeManager)
|
||||||
|
return themeManager, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// getDB 从上下文中获取数据库实例
|
||||||
|
func getDB(c *gin.Context) (*gorm.DB, bool) {
|
||||||
|
dbInterface, exists := c.Get("DB")
|
||||||
|
if !exists {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
db, ok := dbInterface.(*gorm.DB)
|
||||||
|
return db, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// Home 首页
|
||||||
|
func Home(c *gin.Context) {
|
||||||
|
themeManager, ok := getThemeManager(c)
|
||||||
if !ok {
|
if !ok {
|
||||||
c.String(http.StatusInternalServerError, "Invalid theme manager type in context")
|
c.String(http.StatusInternalServerError, "Theme manager not found")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
db, ok := getDB(c)
|
||||||
|
if !ok {
|
||||||
|
c.String(http.StatusInternalServerError, "DB not found")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var items []models.Content
|
var items []models.Content
|
||||||
// 从 Gin 上下文中获取 DB 实例
|
|
||||||
dbInterface, exists := c.Get("DB")
|
|
||||||
if !exists {
|
|
||||||
c.String(http.StatusInternalServerError, "DB not found in context")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
db, ok := dbInterface.(*gorm.DB)
|
|
||||||
if !ok {
|
|
||||||
c.String(http.StatusInternalServerError, "Invalid DB type in context")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
db.Select("*").Limit(5).Find(&items, "type = ?", "post")
|
db.Select("*").Limit(5).Find(&items, "type = ?", "post")
|
||||||
|
|
||||||
tpl := themeManager.GetTemplate("index") // "index" 是模板的基本名 (例如 index.tmpl -> index)
|
tpl := themeManager.GetTemplate("index")
|
||||||
if tpl == nil {
|
if tpl == nil {
|
||||||
c.String(http.StatusInternalServerError, "Template 'index' not found in current theme: "+themeManager.CurrentTheme())
|
c.String(http.StatusInternalServerError, "Template 'index' not found")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Status(http.StatusOK)
|
|
||||||
c.Header("Content-Type", "text/html; charset=utf-8")
|
c.Header("Content-Type", "text/html; charset=utf-8")
|
||||||
err := tpl.Execute(c.Writer, gin.H{
|
tpl.Execute(c.Writer, gin.H{
|
||||||
"Items": items,
|
"Items": items,
|
||||||
"Title": "首页", // 你可以根据需要传递更多数据
|
"Title": "首页",
|
||||||
})
|
})
|
||||||
if err != nil {
|
|
||||||
// 实际项目中应记录错误
|
|
||||||
c.String(http.StatusInternalServerError, "Error rendering template: "+err.Error())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,23 +2,18 @@ package controllers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"go_blog/models"
|
"go_blog/models"
|
||||||
"go_blog/utils"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"gorm.io/gorm" // <-- 确保导入 gorm
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// ShowPost 显示文章详情
|
||||||
func ShowPost(c *gin.Context) {
|
func ShowPost(c *gin.Context) {
|
||||||
tm, exists := c.Get("ThemeManager")
|
themeManager, ok := getThemeManager(c)
|
||||||
if !exists {
|
|
||||||
c.String(http.StatusInternalServerError, "Theme manager not found")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
themeManager, ok := tm.(*utils.ThemeManager)
|
|
||||||
if !ok {
|
if !ok {
|
||||||
c.String(http.StatusInternalServerError, "Invalid theme manager type")
|
c.String(http.StatusInternalServerError, "Theme manager not found")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,19 +24,13 @@ func ShowPost(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var content = models.Content{Cid: int32(id)}
|
db, ok := getDB(c)
|
||||||
// 从 Gin 上下文中获取 DB 实例
|
|
||||||
dbInterface, exists := c.Get("DB")
|
|
||||||
if !exists {
|
|
||||||
c.String(http.StatusInternalServerError, "DB not found in context")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
db, ok := dbInterface.(*gorm.DB)
|
|
||||||
if !ok {
|
if !ok {
|
||||||
c.String(http.StatusInternalServerError, "Invalid DB type in context")
|
c.String(http.StatusInternalServerError, "DB not found")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var content = models.Content{Cid: int32(id)}
|
||||||
result := db.First(&content)
|
result := db.First(&content)
|
||||||
if result.Error != nil {
|
if result.Error != nil {
|
||||||
if result.Error == gorm.ErrRecordNotFound {
|
if result.Error == gorm.ErrRecordNotFound {
|
||||||
@@ -52,19 +41,12 @@ func ShowPost(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 假设你的主题中有一个名为 "post" 的模板 (post.html 或 post.tmpl)
|
|
||||||
// 注意:当前的 default 主题 (web/themes/default/templates/) 并没有 post.tmpl,你需要添加它。
|
|
||||||
tpl := themeManager.GetTemplate("post")
|
tpl := themeManager.GetTemplate("post")
|
||||||
if tpl == nil {
|
if tpl == nil {
|
||||||
c.String(http.StatusInternalServerError, "Template 'post' not found in current theme: "+themeManager.CurrentTheme()+". Make sure 'post.html' or 'post.tmpl' exists in the theme's templates directory.")
|
c.String(http.StatusInternalServerError, "Template 'post' not found")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Status(http.StatusOK)
|
|
||||||
c.Header("Content-Type", "text/html; charset=utf-8")
|
c.Header("Content-Type", "text/html; charset=utf-8")
|
||||||
// 将整个 content 对象传递给模板。模板内部通过 {{ .Title }} {{ .Text }} 等访问。
|
tpl.Execute(c.Writer, content)
|
||||||
err = tpl.Execute(c.Writer, content)
|
|
||||||
if err != nil {
|
|
||||||
c.String(http.StatusInternalServerError, "Error rendering template: "+err.Error())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
8
main.go
8
main.go
@@ -49,15 +49,15 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 5. 创建Gin实例
|
// 5. 创建Gin实例
|
||||||
// 根据环境设置Gin模式
|
|
||||||
if conf.Env == config.EnvProduction {
|
if conf.Env == config.EnvProduction {
|
||||||
gin.SetMode(gin.ReleaseMode)
|
gin.SetMode(gin.ReleaseMode)
|
||||||
}
|
}
|
||||||
router := gin.Default()
|
router := gin.New()
|
||||||
|
router.Use(gin.Recovery())
|
||||||
themeManager.RegisterStaticRoutes(router)
|
themeManager.RegisterStaticRoutes(router)
|
||||||
|
|
||||||
// 初始化Session存储(使用Cookie)
|
// 初始化Session存储(使用Cookie)
|
||||||
store := cookie.NewStore([]byte("your-session-secret")) // 建议从配置文件读取密钥
|
store := cookie.NewStore([]byte("your-session-secret"))
|
||||||
store.Options(sessions.Options{
|
store.Options(sessions.Options{
|
||||||
Path: "/",
|
Path: "/",
|
||||||
MaxAge: 86400 * 7, // 7天
|
MaxAge: 86400 * 7, // 7天
|
||||||
@@ -66,8 +66,6 @@ func main() {
|
|||||||
// 6. 注册中间件
|
// 6. 注册中间件
|
||||||
router.Use(
|
router.Use(
|
||||||
loggerMiddleware(),
|
loggerMiddleware(),
|
||||||
gin.Logger(),
|
|
||||||
gin.Recovery(),
|
|
||||||
databaseMiddleware(models.DB),
|
databaseMiddleware(models.DB),
|
||||||
configMiddleware(conf),
|
configMiddleware(conf),
|
||||||
themeMiddleware(themeManager),
|
themeMiddleware(themeManager),
|
||||||
|
|||||||
@@ -1,9 +1,3 @@
|
|||||||
/*
|
|
||||||
@Time : 2020/6/28 22:01
|
|
||||||
@Author : xuyiqing
|
|
||||||
@File : users.py
|
|
||||||
*/
|
|
||||||
|
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -43,24 +37,13 @@ func (a *Account) SetPassword(password string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 验证登录帐户密码合法性
|
// IsPasswordEqual 验证密码是否匹配
|
||||||
func (a *Account) CheckPassword() bool {
|
|
||||||
password := a.Password
|
|
||||||
|
|
||||||
aa, err1 := bcrypt.GenerateFromPassword([]byte(a.Password), 12)
|
|
||||||
print(aa, err1)
|
|
||||||
DB.Where("username = ?", a.Username).First(&a)
|
|
||||||
err := bcrypt.CompareHashAndPassword([]byte(a.Password), []byte(password))
|
|
||||||
return err == nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// 验证登录帐户密码合法性
|
|
||||||
func (a *Account) IsPasswordEqual(password string) bool {
|
func (a *Account) IsPasswordEqual(password string) bool {
|
||||||
err := bcrypt.CompareHashAndPassword([]byte(a.Password), []byte(password))
|
err := bcrypt.CompareHashAndPassword([]byte(a.Password), []byte(password))
|
||||||
return err == nil
|
return err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 验证用户民重复
|
// CheckDuplicateUsername 验证用户名是否重复
|
||||||
func (a *Account) CheckDuplicateUsername() bool {
|
func (a *Account) CheckDuplicateUsername() bool {
|
||||||
var count int64
|
var count int64
|
||||||
if DB.Model(&Account{}).Where("username=?", a.Username).Count(&count); count > 0 {
|
if DB.Model(&Account{}).Where("username=?", a.Username).Count(&count); count > 0 {
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
package models
|
|
||||||
|
|
||||||
import "gorm.io/gorm"
|
|
||||||
|
|
||||||
type Article struct {
|
|
||||||
gorm.Model
|
|
||||||
Title string
|
|
||||||
Content string `gorm:"type:text"`
|
|
||||||
AuthorID uint
|
|
||||||
Tags []Tag `gorm:"many2many:article_tags;"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tag represents the tag model
|
|
||||||
type Tag struct {
|
|
||||||
gorm.Model
|
|
||||||
Name string `gorm:"uniqueIndex"` // Ensures tag names are unique
|
|
||||||
Articles []Article `gorm:"many2many:article_tags;"` // Reverse relationship
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
const TableNameContent = "contents"
|
// Content 内容模型(文章/页面)
|
||||||
|
|
||||||
type Content struct {
|
type Content struct {
|
||||||
Cid int32 `gorm:"column:cid;primaryKey;autoIncrement:true" json:"cid"`
|
Cid int32 `gorm:"column:cid;primaryKey;autoIncrement:true" json:"cid"`
|
||||||
Title string `gorm:"column:title" json:"title"`
|
Title string `gorm:"column:title" json:"title"`
|
||||||
@@ -22,7 +21,7 @@ type Content struct {
|
|||||||
Parent int32 `gorm:"column:parent" json:"parent"`
|
Parent int32 `gorm:"column:parent" json:"parent"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TableName Content's table name
|
// TableName 指定表名
|
||||||
func (*Content) TableName() string {
|
func (*Content) TableName() string {
|
||||||
return TableNameContent
|
return "contents"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,3 @@
|
|||||||
/*
|
|
||||||
@Time : 2020/6/28 21:46
|
|
||||||
@Author : xuyiqing
|
|
||||||
@File : init.py
|
|
||||||
*/
|
|
||||||
|
|
||||||
package models
|
package models
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -50,12 +44,8 @@ func InitDatabase(conf *config.Config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DB = db
|
DB = db
|
||||||
// 3. 自动迁移数据模型
|
// 自动迁移数据模型
|
||||||
db.AutoMigrate(&Account{})
|
db.AutoMigrate(&Account{}, &Content{}, &Option{})
|
||||||
db.AutoMigrate(&Content{})
|
|
||||||
// if err := db.AutoMigrate(&models.Article{}, &models.User{}); err != nil {
|
|
||||||
// panic("数据库迁移失败: " + err.Error())
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type BaseModel struct {
|
type BaseModel struct {
|
||||||
|
|||||||
@@ -2,8 +2,7 @@ package models
|
|||||||
|
|
||||||
import "gorm.io/gorm"
|
import "gorm.io/gorm"
|
||||||
|
|
||||||
// Option 对应 typecho_options 数据表
|
// Option 系统配置项模型
|
||||||
// 用于存储系统配置项
|
|
||||||
type Option struct {
|
type Option struct {
|
||||||
Name string `gorm:"column:name;type:varchar(32);primaryKey"` // 配置名称(主键)
|
Name string `gorm:"column:name;type:varchar(32);primaryKey"` // 配置名称(主键)
|
||||||
Value string `gorm:"column:value;type:text"` // 配置值
|
Value string `gorm:"column:value;type:text"` // 配置值
|
||||||
@@ -12,7 +11,7 @@ type Option struct {
|
|||||||
|
|
||||||
// TableName 指定表名
|
// TableName 指定表名
|
||||||
func (Option) TableName() string {
|
func (Option) TableName() string {
|
||||||
return "typecho_options"
|
return "options"
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetOptionValue 根据name和user获取配置值
|
// GetOptionValue 根据name和user获取配置值
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
package models
|
|
||||||
|
|
||||||
type User struct {
|
|
||||||
Name string
|
|
||||||
Gender string
|
|
||||||
Age int
|
|
||||||
Password string
|
|
||||||
PasswordHash []byte
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetUserByID 根据 ID 查询用户
|
|
||||||
func GetUserByID(id uint) (*User, error) {
|
|
||||||
var user User
|
|
||||||
if err := DB.First(&user, id).Error; err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &user, nil
|
|
||||||
}
|
|
||||||
@@ -1,9 +1,3 @@
|
|||||||
/*
|
|
||||||
@Time : 2020/7/15 23:27
|
|
||||||
@Author : xuyiqing
|
|
||||||
@File : util.py
|
|
||||||
*/
|
|
||||||
|
|
||||||
package util
|
package util
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|||||||
@@ -1,23 +1,17 @@
|
|||||||
package routers // Add the package declaration at the top
|
package routers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"go_blog/controllers"
|
"go_blog/controllers"
|
||||||
"go_blog/controllers/admin"
|
"go_blog/controllers/admin"
|
||||||
"go_blog/models"
|
|
||||||
"go_blog/utils"
|
|
||||||
"log"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gin-contrib/sessions"
|
"github.com/gin-contrib/sessions"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"gorm.io/gorm"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// 新增:自定义后台认证中间件(处理页面重定向)
|
// CheckAdminAuth 后台认证中间件(处理页面重定向)
|
||||||
// 自定义后台认证中间件(通过Session判断登录状态)
|
|
||||||
func CheckAdminAuth() gin.HandlerFunc {
|
func CheckAdminAuth() gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
currentPath := c.Request.URL.Path
|
currentPath := c.Request.URL.Path
|
||||||
@@ -43,7 +37,7 @@ func CheckAdminAuth() gin.HandlerFunc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 新增:基于Session的认证中间件
|
// SessionAuthRequired 基于Session的认证中间件
|
||||||
func SessionAuthRequired() gin.HandlerFunc {
|
func SessionAuthRequired() gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
session := sessions.Default(c)
|
session := sessions.Default(c)
|
||||||
@@ -63,97 +57,16 @@ func SessionAuthRequired() gin.HandlerFunc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func RegisterRoutes(r *gin.Engine) {
|
func RegisterRoutes(r *gin.Engine) {
|
||||||
|
// WebSocket 和 SSE 路由
|
||||||
// 注册WebSocket路由
|
|
||||||
r.GET("/events", esSSE)
|
r.GET("/events", esSSE)
|
||||||
|
|
||||||
r.GET("/page", func(c *gin.Context) {
|
|
||||||
tm, exists := c.Get("ThemeManager")
|
|
||||||
if !exists {
|
|
||||||
c.String(http.StatusInternalServerError, "Theme manager not found")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
themeManager, ok := tm.(*utils.ThemeManager)
|
|
||||||
if !ok {
|
|
||||||
c.String(http.StatusInternalServerError, "Invalid theme manager type")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var items []models.Content
|
|
||||||
var pager utils.Pager
|
|
||||||
pager.InitPager(c) // 这会从查询参数中读取 page 和 pageSize
|
|
||||||
offset := (pager.Page - 1) * pager.PageSize
|
|
||||||
|
|
||||||
dbInterface, dbOk := c.Get("DB")
|
|
||||||
if !dbOk {
|
|
||||||
log.Println("未找到键 'DB' 的上下文值")
|
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "内部服务器错误"})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
c.Status(http.StatusOK)
|
|
||||||
c.Header("Content-Type", "text/html; charset=utf-8")
|
|
||||||
err := tpl.Execute(c.Writer, gin.H{
|
|
||||||
"Items": items,
|
|
||||||
"Pager": pager, // 确保你的 index.tmpl 支持 Pager 结构
|
|
||||||
"Title": "文章列表 - 第 " + strconv.Itoa(pager.Page) + " 页",
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
c.String(http.StatusInternalServerError, "Error rendering template: "+err.Error())
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
r.GET("/createcontent", func(c *gin.Context) {
|
|
||||||
tm, exists := c.Get("ThemeManager")
|
|
||||||
if !exists {
|
|
||||||
c.String(http.StatusInternalServerError, "Theme manager not found")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
themeManager, ok := tm.(*utils.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())
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
r.GET("/ws", controllers.WebSocketHandler)
|
r.GET("/ws", controllers.WebSocketHandler)
|
||||||
|
|
||||||
|
// 内容相关路由
|
||||||
r.POST("/content", controllers.CreateContentHandler)
|
r.POST("/content", controllers.CreateContentHandler)
|
||||||
// Frontend routes (dynamic themes)
|
r.GET("/page", controllers.PageList)
|
||||||
|
r.GET("/createcontent", controllers.CreateContentPage)
|
||||||
|
|
||||||
|
// 前端路由(动态主题)
|
||||||
r.GET("/", controllers.Home)
|
r.GET("/", controllers.Home)
|
||||||
r.GET("/post/:id", controllers.ShowPost)
|
r.GET("/post/:id", controllers.ShowPost)
|
||||||
|
|
||||||
@@ -196,22 +109,15 @@ func esSSE(c *gin.Context) {
|
|||||||
w.Header().Set("Connection", "keep-alive")
|
w.Header().Set("Connection", "keep-alive")
|
||||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||||
|
|
||||||
_, ok := w.(http.Flusher)
|
flusher, ok := w.(http.Flusher)
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Panic("server not support") //浏览器不兼容
|
c.String(http.StatusInternalServerError, "server not support SSE")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
// Simulate sending events every second
|
|
||||||
fmt.Fprintf(w, "data: %s\n\n", time.Now().Format(time.Stamp))
|
fmt.Fprintf(w, "data: %s\n\n", time.Now().Format(time.Stamp))
|
||||||
w.(http.Flusher).Flush()
|
flusher.Flush()
|
||||||
time.Sleep(1 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := fmt.Fprintf(w, "event: connecttime\ndata: %s\n\n", "connecttime")
|
|
||||||
if err != nil {
|
|
||||||
print("error", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -200,21 +200,6 @@ func readFile(path string) ([]byte, error) {
|
|||||||
return os.ReadFile(path)
|
return os.ReadFile(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListThemes 获取所有可用主题(目录名)
|
|
||||||
func (m *ThemeManager) ListThemes() ([]string, error) {
|
|
||||||
entries, err := os.ReadDir(m.themesDir)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("读取主题目录失败: %w", err)
|
|
||||||
}
|
|
||||||
var themes []string
|
|
||||||
for _, entry := range entries {
|
|
||||||
if entry.IsDir() {
|
|
||||||
themes = append(themes, entry.Name())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return themes, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAvailableThemes 获取所有可用主题(读取 themesDir 目录下的子目录)
|
// GetAvailableThemes 获取所有可用主题(读取 themesDir 目录下的子目录)
|
||||||
func (m *ThemeManager) GetAvailableThemes() ([]string, error) {
|
func (m *ThemeManager) GetAvailableThemes() ([]string, error) {
|
||||||
entries, err := os.ReadDir(m.themesDir)
|
entries, err := os.ReadDir(m.themesDir)
|
||||||
|
|||||||
Reference in New Issue
Block a user