|
|
|
@ -15,6 +15,7 @@ import ( |
|
|
|
|
|
|
|
"github.com/youruser/base/internal/config" |
|
|
|
"github.com/youruser/base/internal/middleware" |
|
|
|
"github.com/youruser/base/internal/storage" |
|
|
|
"github.com/youruser/base/model" |
|
|
|
|
|
|
|
"gorm.io/driver/mysql" |
|
|
|
@ -50,6 +51,8 @@ type ServiceContext struct { |
|
|
|
DB *gorm.DB |
|
|
|
// Casbin enforcer
|
|
|
|
Enforcer *casbin.Enforcer |
|
|
|
// 文件存储
|
|
|
|
Storage storage.Storage |
|
|
|
} |
|
|
|
|
|
|
|
func NewServiceContext(c config.Config) *ServiceContext { |
|
|
|
@ -61,7 +64,7 @@ func NewServiceContext(c config.Config) *ServiceContext { |
|
|
|
} |
|
|
|
|
|
|
|
// 自动迁移表
|
|
|
|
err = db.AutoMigrate(&model.User{}, &model.Profile{}) |
|
|
|
err = db.AutoMigrate(&model.User{}, &model.Profile{}, &model.File{}, &model.Menu{}, &model.Role{}, &model.RoleMenu{}, &model.Organization{}, &model.UserOrganization{}) |
|
|
|
if err != nil { |
|
|
|
panic("Failed to migrate database: " + err.Error()) |
|
|
|
} |
|
|
|
@ -75,6 +78,18 @@ func NewServiceContext(c config.Config) *ServiceContext { |
|
|
|
// 种子 Casbin 策略
|
|
|
|
seedCasbinPolicies(enforcer) |
|
|
|
|
|
|
|
// 种子角色、菜单、角色-菜单关联
|
|
|
|
seedRoles(db) |
|
|
|
seedMenus(db) |
|
|
|
seedRoleMenus(db) |
|
|
|
|
|
|
|
// 初始化存储
|
|
|
|
store, err := storage.NewStorage(c.Storage) |
|
|
|
if err != nil { |
|
|
|
panic("Failed to initialize storage: " + err.Error()) |
|
|
|
} |
|
|
|
log.Printf("[Storage] Initialized with type: %s", c.Storage.Type) |
|
|
|
|
|
|
|
return &ServiceContext{ |
|
|
|
Config: c, |
|
|
|
Cors: middleware.NewCorsMiddleware().Handle, |
|
|
|
@ -83,6 +98,7 @@ func NewServiceContext(c config.Config) *ServiceContext { |
|
|
|
Authz: middleware.NewAuthzMiddleware(enforcer).Handle, |
|
|
|
DB: db, |
|
|
|
Enforcer: enforcer, |
|
|
|
Storage: store, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -193,6 +209,50 @@ func seedCasbinPolicies(enforcer *casbin.Enforcer) { |
|
|
|
|
|
|
|
// super_admin: 用户删除
|
|
|
|
{"super_admin", "/api/v1/user/:id", "DELETE"}, |
|
|
|
|
|
|
|
// user: 文件管理
|
|
|
|
{"user", "/api/v1/file/upload", "POST"}, |
|
|
|
{"user", "/api/v1/files", "GET"}, |
|
|
|
{"user", "/api/v1/file/:id", "GET"}, |
|
|
|
{"user", "/api/v1/file/:id/url", "GET"}, |
|
|
|
{"user", "/api/v1/file/:id", "PUT"}, |
|
|
|
|
|
|
|
// super_admin: 文件删除
|
|
|
|
{"super_admin", "/api/v1/file/:id", "DELETE"}, |
|
|
|
|
|
|
|
// user: 个人机构相关
|
|
|
|
{"user", "/api/v1/profile/orgs", "GET"}, |
|
|
|
{"user", "/api/v1/profile/current-org", "PUT"}, |
|
|
|
|
|
|
|
// admin: 菜单管理(读取)
|
|
|
|
{"admin", "/api/v1/menus", "GET"}, |
|
|
|
|
|
|
|
// super_admin: 菜单管理(增删改)
|
|
|
|
{"super_admin", "/api/v1/menu", "POST"}, |
|
|
|
{"super_admin", "/api/v1/menu/:id", "PUT"}, |
|
|
|
{"super_admin", "/api/v1/menu/:id", "DELETE"}, |
|
|
|
|
|
|
|
// admin: 角色管理(读取)
|
|
|
|
{"admin", "/api/v1/roles", "GET"}, |
|
|
|
{"admin", "/api/v1/role/:id/menus", "GET"}, |
|
|
|
|
|
|
|
// super_admin: 角色管理(增删改)
|
|
|
|
{"super_admin", "/api/v1/role", "POST"}, |
|
|
|
{"super_admin", "/api/v1/role/:id", "PUT"}, |
|
|
|
{"super_admin", "/api/v1/role/:id", "DELETE"}, |
|
|
|
{"super_admin", "/api/v1/role/:id/menus", "PUT"}, |
|
|
|
|
|
|
|
// admin: 机构管理
|
|
|
|
{"admin", "/api/v1/organizations", "GET"}, |
|
|
|
{"admin", "/api/v1/organization", "POST"}, |
|
|
|
{"admin", "/api/v1/organization/:id", "PUT"}, |
|
|
|
{"admin", "/api/v1/organization/:id/members", "GET"}, |
|
|
|
{"admin", "/api/v1/organization/:id/member", "POST"}, |
|
|
|
{"admin", "/api/v1/organization/:id/member/:userId", "PUT"}, |
|
|
|
{"admin", "/api/v1/organization/:id/member/:userId", "DELETE"}, |
|
|
|
|
|
|
|
// super_admin: 机构删除
|
|
|
|
{"super_admin", "/api/v1/organization/:id", "DELETE"}, |
|
|
|
} |
|
|
|
|
|
|
|
for _, p := range policies { |
|
|
|
@ -204,3 +264,94 @@ func seedCasbinPolicies(enforcer *casbin.Enforcer) { |
|
|
|
enforcer.SavePolicy() |
|
|
|
log.Println("[Casbin] Policies seeded successfully") |
|
|
|
} |
|
|
|
|
|
|
|
// seedRoles 种子系统角色(幂等)
|
|
|
|
func seedRoles(db *gorm.DB) { |
|
|
|
roles := []model.Role{ |
|
|
|
{Name: "超级管理员", Code: model.RoleSuperAdmin, Description: "系统超级管理员", IsSystem: true, SortOrder: 1, Status: 1}, |
|
|
|
{Name: "管理员", Code: model.RoleAdmin, Description: "系统管理员", IsSystem: true, SortOrder: 2, Status: 1}, |
|
|
|
{Name: "普通用户", Code: model.RoleUser, Description: "普通用户", IsSystem: true, SortOrder: 3, Status: 1}, |
|
|
|
{Name: "访客", Code: model.RoleGuest, Description: "访客", IsSystem: true, SortOrder: 4, Status: 1}, |
|
|
|
} |
|
|
|
|
|
|
|
for _, r := range roles { |
|
|
|
var existing model.Role |
|
|
|
if err := db.Where("code = ?", r.Code).First(&existing).Error; err != nil { |
|
|
|
db.Create(&r) |
|
|
|
} |
|
|
|
} |
|
|
|
log.Println("[Seed] Roles seeded successfully") |
|
|
|
} |
|
|
|
|
|
|
|
// seedMenus 种子默认菜单(幂等)
|
|
|
|
func seedMenus(db *gorm.DB) { |
|
|
|
menus := []model.Menu{ |
|
|
|
{Name: "我的", Path: "/my", Icon: "User", Type: "default", SortOrder: 1, Visible: true, Status: 1}, |
|
|
|
{Name: "仪表盘", Path: "/dashboard", Icon: "LayoutDashboard", Type: "config", SortOrder: 2, Visible: true, Status: 1}, |
|
|
|
{Name: "用户管理", Path: "/users", Icon: "Users", Type: "config", SortOrder: 3, Visible: true, Status: 1}, |
|
|
|
{Name: "文件管理", Path: "/files", Icon: "FolderOpen", Type: "config", SortOrder: 4, Visible: true, Status: 1}, |
|
|
|
{Name: "角色管理", Path: "/roles", Icon: "Shield", Type: "config", SortOrder: 5, Visible: true, Status: 1}, |
|
|
|
{Name: "菜单管理", Path: "/menus", Icon: "Menu", Type: "config", SortOrder: 6, Visible: true, Status: 1}, |
|
|
|
{Name: "机构管理", Path: "/organizations", Icon: "Building2", Type: "config", SortOrder: 7, Visible: true, Status: 1}, |
|
|
|
{Name: "设置", Path: "/settings", Icon: "Settings", Type: "default", SortOrder: 8, Visible: true, Status: 1}, |
|
|
|
} |
|
|
|
|
|
|
|
for _, m := range menus { |
|
|
|
var existing model.Menu |
|
|
|
if err := db.Where("path = ?", m.Path).First(&existing).Error; err != nil { |
|
|
|
db.Create(&m) |
|
|
|
} |
|
|
|
} |
|
|
|
log.Println("[Seed] Menus seeded successfully") |
|
|
|
} |
|
|
|
|
|
|
|
// seedRoleMenus 种子角色-菜单关联(幂等)
|
|
|
|
func seedRoleMenus(db *gorm.DB) { |
|
|
|
// 获取所有角色
|
|
|
|
var roles []model.Role |
|
|
|
db.Find(&roles) |
|
|
|
|
|
|
|
// 获取所有菜单
|
|
|
|
var menus []model.Menu |
|
|
|
db.Find(&menus) |
|
|
|
|
|
|
|
if len(roles) == 0 || len(menus) == 0 { |
|
|
|
return |
|
|
|
} |
|
|
|
|
|
|
|
// 构建菜单分类
|
|
|
|
var allMenuIds []int64 |
|
|
|
var defaultMenuIds []int64 |
|
|
|
for _, m := range menus { |
|
|
|
allMenuIds = append(allMenuIds, m.Id) |
|
|
|
if m.Type == "default" { |
|
|
|
defaultMenuIds = append(defaultMenuIds, m.Id) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
for _, r := range roles { |
|
|
|
// 检查角色是否已有菜单关联
|
|
|
|
var count int64 |
|
|
|
db.Model(&model.RoleMenu{}).Where("role_id = ?", r.Id).Count(&count) |
|
|
|
if count > 0 { |
|
|
|
continue |
|
|
|
} |
|
|
|
|
|
|
|
var menuIds []int64 |
|
|
|
switch r.Code { |
|
|
|
case model.RoleSuperAdmin, model.RoleAdmin: |
|
|
|
menuIds = allMenuIds |
|
|
|
case model.RoleUser, model.RoleGuest: |
|
|
|
menuIds = defaultMenuIds |
|
|
|
} |
|
|
|
|
|
|
|
if len(menuIds) > 0 { |
|
|
|
records := make([]model.RoleMenu, 0, len(menuIds)) |
|
|
|
for _, menuId := range menuIds { |
|
|
|
records = append(records, model.RoleMenu{RoleId: r.Id, MenuId: menuId}) |
|
|
|
} |
|
|
|
db.Create(&records) |
|
|
|
} |
|
|
|
} |
|
|
|
log.Println("[Seed] RoleMenus seeded successfully") |
|
|
|
} |
|
|
|
|