初始提交:姜十三论坛 Jiang13 Forum
轻量自用论坛,Go 单二进制 + React SPA 内嵌 + SQLite。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
46
model/db.go
Normal file
46
model/db.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"gorm.io/driver/sqlite"
|
||||
"gorm.io/gorm"
|
||||
"gorm.io/gorm/logger"
|
||||
)
|
||||
|
||||
var DB *gorm.DB
|
||||
|
||||
// InitDB 初始化 SQLite 并自动迁移
|
||||
func InitDB(dbPath string) error {
|
||||
dir := filepath.Dir(dbPath)
|
||||
if err := os.MkdirAll(dir, 0755); err != nil {
|
||||
return fmt.Errorf("创建数据库目录失败: %w", err)
|
||||
}
|
||||
|
||||
db, err := gorm.Open(sqlite.Open(dbPath), &gorm.Config{
|
||||
Logger: logger.Default.LogMode(logger.Warn),
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("连接 SQLite 失败: %w", err)
|
||||
}
|
||||
|
||||
sqlDB, err := db.DB()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sqlDB.SetMaxOpenConns(1)
|
||||
|
||||
if err := db.AutoMigrate(
|
||||
&User{}, &Board{}, &Post{}, &Comment{},
|
||||
&PostLike{}, &PostFavorite{},
|
||||
); err != nil {
|
||||
return fmt.Errorf("自动迁移失败: %w", err)
|
||||
}
|
||||
|
||||
DB = db
|
||||
log.Println("[model] SQLite 数据库初始化完成:", dbPath)
|
||||
return nil
|
||||
}
|
||||
101
model/models.go
Normal file
101
model/models.go
Normal file
@@ -0,0 +1,101 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// Role 用户角色
|
||||
type Role string
|
||||
|
||||
const (
|
||||
RoleUser Role = "user"
|
||||
RoleAdmin Role = "admin"
|
||||
)
|
||||
|
||||
// User 用户表
|
||||
type User struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
Username string `gorm:"uniqueIndex;size:64;not null" json:"username"`
|
||||
Password string `gorm:"size:128;not null" json:"-"`
|
||||
Nickname string `gorm:"size:64" json:"nickname"`
|
||||
Avatar string `gorm:"size:256" json:"avatar"`
|
||||
Role Role `gorm:"size:16;default:user" json:"role"`
|
||||
Banned bool `gorm:"default:false" json:"banned"`
|
||||
BannedAt *time.Time `json:"banned_at,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
||||
}
|
||||
|
||||
// Board 论坛板块
|
||||
type Board struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
Name string `gorm:"size:64;not null" json:"name"`
|
||||
Description string `gorm:"size:512" json:"description"`
|
||||
SortOrder int `gorm:"default:0" json:"sort_order"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
||||
}
|
||||
|
||||
// Post 帖子
|
||||
type Post struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
BoardID uint `gorm:"index;not null" json:"board_id"`
|
||||
UserID uint `gorm:"index;not null" json:"user_id"`
|
||||
Title string `gorm:"size:256;not null" json:"title"`
|
||||
Content string `gorm:"type:text;not null" json:"content"`
|
||||
Tags string `gorm:"size:256" json:"tags"`
|
||||
Pinned bool `gorm:"default:false" json:"pinned"`
|
||||
LikeCount int `gorm:"default:0" json:"like_count"`
|
||||
ViewCount int `gorm:"default:0" json:"view_count"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
||||
|
||||
Board Board `gorm:"foreignKey:BoardID" json:"board,omitempty"`
|
||||
User User `gorm:"foreignKey:UserID" json:"user,omitempty"`
|
||||
Comments []Comment `gorm:"foreignKey:PostID" json:"comments,omitempty"`
|
||||
}
|
||||
|
||||
// Comment 楼层评论
|
||||
type Comment struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
PostID uint `gorm:"index;not null" json:"post_id"`
|
||||
UserID uint `gorm:"index" json:"user_id"` // 0 表示游客
|
||||
Floor int `gorm:"not null" json:"floor"`
|
||||
Content string `gorm:"type:text;not null" json:"content"`
|
||||
ReplyTo *uint `gorm:"index" json:"reply_to,omitempty"`
|
||||
GuestNick string `gorm:"size:64" json:"guest_nick,omitempty"`
|
||||
GuestEmail string `gorm:"size:128" json:"guest_email,omitempty"`
|
||||
GuestURL string `gorm:"size:256" json:"guest_url,omitempty"`
|
||||
IsPrivate bool `gorm:"default:false" json:"is_private"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
||||
|
||||
User User `gorm:"foreignKey:UserID" json:"user,omitempty"`
|
||||
Post Post `gorm:"foreignKey:PostID" json:"post,omitempty"`
|
||||
ReplyTarget *Comment `gorm:"-" json:"reply_target,omitempty"`
|
||||
ContentHidden bool `gorm:"-" json:"content_hidden"`
|
||||
}
|
||||
|
||||
// PostLike 帖子点赞
|
||||
type PostLike struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
PostID uint `gorm:"uniqueIndex:idx_post_user;not null" json:"post_id"`
|
||||
UserID uint `gorm:"uniqueIndex:idx_post_user;not null" json:"user_id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
}
|
||||
|
||||
// PostFavorite 帖子收藏
|
||||
type PostFavorite struct {
|
||||
ID uint `gorm:"primaryKey" json:"id"`
|
||||
PostID uint `gorm:"uniqueIndex:idx_fav_post_user;not null" json:"post_id"`
|
||||
UserID uint `gorm:"uniqueIndex:idx_fav_post_user;not null" json:"user_id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
|
||||
Post Post `gorm:"foreignKey:PostID" json:"post,omitempty"`
|
||||
}
|
||||
Reference in New Issue
Block a user