|
|
package model
|
|
|
|
|
|
import (
|
|
|
"fmt"
|
|
|
|
|
|
"github.com/veypi/vbase/internal/config"
|
|
|
"gorm.io/driver/mysql"
|
|
|
"gorm.io/driver/postgres"
|
|
|
"gorm.io/driver/sqlite"
|
|
|
"gorm.io/gorm"
|
|
|
"gorm.io/gorm/logger"
|
|
|
)
|
|
|
|
|
|
var DB *gorm.DB
|
|
|
|
|
|
// InitDB 初始化数据库
|
|
|
func InitDB() error {
|
|
|
cfg := config.C.Database
|
|
|
|
|
|
var dialector gorm.Dialector
|
|
|
switch cfg.Type {
|
|
|
case "mysql":
|
|
|
dialector = mysql.Open(cfg.DSN)
|
|
|
case "postgres":
|
|
|
dialector = postgres.Open(cfg.DSN)
|
|
|
case "sqlite":
|
|
|
dialector = sqlite.Open(cfg.DSN)
|
|
|
default:
|
|
|
return fmt.Errorf("unsupported database type: %s", cfg.Type)
|
|
|
}
|
|
|
|
|
|
var err error
|
|
|
DB, err = gorm.Open(dialector, &gorm.Config{
|
|
|
Logger: logger.Default.LogMode(logger.Info),
|
|
|
})
|
|
|
if err != nil {
|
|
|
return fmt.Errorf("failed to connect database: %w", err)
|
|
|
}
|
|
|
|
|
|
sqlDB, err := DB.DB()
|
|
|
if err != nil {
|
|
|
return err
|
|
|
}
|
|
|
|
|
|
sqlDB.SetMaxOpenConns(cfg.MaxOpenConns)
|
|
|
sqlDB.SetMaxIdleConns(cfg.MaxIdleConns)
|
|
|
sqlDB.SetConnMaxLifetime(cfg.ConnMaxLifetime)
|
|
|
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
// AutoMigrate 自动迁移表结构
|
|
|
func AutoMigrate() error {
|
|
|
return DB.AutoMigrate(
|
|
|
&User{},
|
|
|
&Identity{},
|
|
|
&Session{},
|
|
|
&Org{},
|
|
|
&OrgMember{},
|
|
|
&Policy{},
|
|
|
&Role{},
|
|
|
&OAuthClient{},
|
|
|
&OAuthAuthorization{},
|
|
|
&OAuthToken{},
|
|
|
)
|
|
|
}
|
|
|
|
|
|
// InitSystemData 初始化系统数据
|
|
|
func InitSystemData() error {
|
|
|
return DB.Transaction(func(tx *gorm.DB) error {
|
|
|
// 1. 创建系统策略
|
|
|
if err := initSystemPolicies(tx); err != nil {
|
|
|
return err
|
|
|
}
|
|
|
|
|
|
// 2. 检查是否需要创建初始管理员
|
|
|
var count int64
|
|
|
if err := tx.Model(&User{}).Count(&count).Error; err != nil {
|
|
|
return err
|
|
|
}
|
|
|
|
|
|
if count == 0 {
|
|
|
if err := initAdminUser(tx); err != nil {
|
|
|
return err
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return nil
|
|
|
})
|
|
|
}
|
|
|
|
|
|
// initSystemPolicies 创建系统内置策略
|
|
|
func initSystemPolicies(tx *gorm.DB) error {
|
|
|
policies := []Policy{
|
|
|
{
|
|
|
Code: SysPolicyUserReadOwn,
|
|
|
Name: "读取自己",
|
|
|
Description: "用户读取自己的信息",
|
|
|
Resource: "user",
|
|
|
Action: "read",
|
|
|
Condition: "resource.id == user.id",
|
|
|
Effect: EffectAllow,
|
|
|
IsSystem: true,
|
|
|
},
|
|
|
{
|
|
|
Code: SysPolicyUserUpdateOwn,
|
|
|
Name: "更新自己",
|
|
|
Description: "用户更新自己的信息",
|
|
|
Resource: "user",
|
|
|
Action: "update",
|
|
|
Condition: "resource.id == user.id",
|
|
|
Effect: EffectAllow,
|
|
|
IsSystem: true,
|
|
|
},
|
|
|
{
|
|
|
Code: SysPolicyUserDeleteOwn,
|
|
|
Name: "删除自己",
|
|
|
Description: "用户删除自己的账号",
|
|
|
Resource: "user",
|
|
|
Action: "delete",
|
|
|
Condition: "resource.id == user.id",
|
|
|
Effect: EffectAllow,
|
|
|
IsSystem: true,
|
|
|
},
|
|
|
{
|
|
|
Code: SysPolicyOrgAdmin,
|
|
|
Name: "组织管理员",
|
|
|
Description: "组织所有者拥有所有权限",
|
|
|
Resource: "*",
|
|
|
Action: "*",
|
|
|
Condition: "org.owner_id == user.id",
|
|
|
Effect: EffectAllow,
|
|
|
Priority: 100,
|
|
|
IsSystem: true,
|
|
|
},
|
|
|
{
|
|
|
Code: SysPolicyOrgRead,
|
|
|
Name: "读取组织",
|
|
|
Description: "组织成员可读组织信息",
|
|
|
Resource: "org",
|
|
|
Action: "read",
|
|
|
Condition: "member.org_id == org.id",
|
|
|
Effect: EffectAllow,
|
|
|
IsSystem: true,
|
|
|
},
|
|
|
{
|
|
|
Code: SysPolicyMemberRead,
|
|
|
Name: "读取成员",
|
|
|
Description: "读取组织成员列表",
|
|
|
Resource: "member",
|
|
|
Action: "read",
|
|
|
Condition: "member.org_id == org.id",
|
|
|
Effect: EffectAllow,
|
|
|
IsSystem: true,
|
|
|
},
|
|
|
{
|
|
|
Code: SysPolicyMemberManage,
|
|
|
Name: "管理成员",
|
|
|
Description: "管理组织成员",
|
|
|
Resource: "member",
|
|
|
Action: "*",
|
|
|
Condition: "",
|
|
|
Effect: EffectAllow,
|
|
|
IsSystem: true,
|
|
|
},
|
|
|
{
|
|
|
Code: SysPolicyRoleRead,
|
|
|
Name: "读取角色",
|
|
|
Description: "读取组织角色",
|
|
|
Resource: "role",
|
|
|
Action: "read",
|
|
|
Condition: "resource.org_id == org.id",
|
|
|
Effect: EffectAllow,
|
|
|
IsSystem: true,
|
|
|
},
|
|
|
{
|
|
|
Code: SysPolicyRoleManage,
|
|
|
Name: "管理角色",
|
|
|
Description: "管理组织角色",
|
|
|
Resource: "role",
|
|
|
Action: "*",
|
|
|
Condition: "",
|
|
|
Effect: EffectAllow,
|
|
|
IsSystem: true,
|
|
|
},
|
|
|
{
|
|
|
Code: SysPolicyPolicyRead,
|
|
|
Name: "读取策略",
|
|
|
Description: "读取策略",
|
|
|
Resource: "policy",
|
|
|
Action: "read",
|
|
|
Condition: "",
|
|
|
Effect: EffectAllow,
|
|
|
IsSystem: true,
|
|
|
},
|
|
|
{
|
|
|
Code: SysPolicyPolicyManage,
|
|
|
Name: "管理策略",
|
|
|
Description: "管理策略",
|
|
|
Resource: "policy",
|
|
|
Action: "*",
|
|
|
Condition: "",
|
|
|
Effect: EffectAllow,
|
|
|
IsSystem: true,
|
|
|
},
|
|
|
}
|
|
|
|
|
|
for _, p := range policies {
|
|
|
var existing Policy
|
|
|
if err := tx.Where("code = ?", p.Code).First(&existing).Error; err != nil {
|
|
|
if err == gorm.ErrRecordNotFound {
|
|
|
if err := tx.Create(&p).Error; err != nil {
|
|
|
return err
|
|
|
}
|
|
|
} else {
|
|
|
return err
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
// initAdminUser 创建初始管理员
|
|
|
func initAdminUser(tx *gorm.DB) error {
|
|
|
adminCfg := config.C.App.InitAdmin
|
|
|
|
|
|
// 生成随机密码(如果未配置)
|
|
|
password := adminCfg.Password
|
|
|
if password == "" {
|
|
|
password = generateRandomPassword(16)
|
|
|
fmt.Printf("\n========================================\n")
|
|
|
fmt.Printf("Initial admin user created!\n")
|
|
|
fmt.Printf("Username: %s\n", adminCfg.Username)
|
|
|
fmt.Printf("Password: %s\n", password)
|
|
|
fmt.Printf("Email: %s\n", adminCfg.Email)
|
|
|
fmt.Printf("========================================\n\n")
|
|
|
}
|
|
|
|
|
|
// 密码哈希(这里需要crypto包,后续实现)
|
|
|
// hashedPassword, _ := crypto.HashPassword(password)
|
|
|
|
|
|
admin := &User{
|
|
|
Username: adminCfg.Username,
|
|
|
Password: password, // TODO: hash password
|
|
|
Email: adminCfg.Email,
|
|
|
Nickname: "Administrator",
|
|
|
Status: UserStatusActive,
|
|
|
EmailVerified: true,
|
|
|
PhoneVerified: false,
|
|
|
}
|
|
|
|
|
|
if err := tx.Create(admin).Error; err != nil {
|
|
|
return err
|
|
|
}
|
|
|
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
// generateRandomPassword 生成随机密码
|
|
|
func generateRandomPassword(length int) string {
|
|
|
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*"
|
|
|
result := make([]byte, length)
|
|
|
for i := range result {
|
|
|
result[i] = charset[i%len(charset)]
|
|
|
}
|
|
|
return string(result)
|
|
|
}
|