package system import ( "errors" "kra/pkg/database/migration" "gorm.io/gorm" ) // Migrations returns schema steps owned by the built-in system module. // Administrators, menus, APIs, and policies are created only by SeedSystem // during the explicit first-install flow. func Migrations() []migration.Step { return []migration.Step{ { ID: "202608200002_system_schema", Migrate: func(db *gorm.DB) error { return migration.CreateMissingTables(db, &userPO{}, &authorityPO{}, &menuPO{}, &userAuthorityPO{}, &authorityMenuPO{}, &menuParameterPO{}, &apiPO{}, &ignoredAPIPO{}, &authorityAPIPO{}, &casbinRulePO{}, &menuButtonPO{}, &authorityButtonPO{}, &departmentPO{}, &positionPO{}, &userDepartmentPO{}, &userPositionPO{}, &authorityDepartmentPO{}, &dictionaryPO{}, &dictionaryDetailPO{}, ¶meterPO{}, &apiTokenPO{}, &jwtBlacklistPO{}, &SecurityConfigPO{}, &versionPO{}, &exportTemplatePO{}, &exportConditionPO{}, &exportJoinPO{}, &operationPO{}, &loginLogPO{}, &DataAccessLogPO{}, &errorRecordPO{}, &mediaPO{}, &categoryPO{}, &uploadSessionPO{}, &uploadChunkPO{}, &announcementPO{}, ) }, }, {ID: "202608210002_communication_surface", Migrate: ensureCommunicationSurface}, {ID: "202608210003_communication_test_surface", Migrate: ensureCommunicationTestSurface}, } } func ensureCommunicationSurface(db *gorm.DB) error { if db == nil || !db.Migrator().HasTable(&menuPO{}) || !db.Migrator().HasTable(&apiPO{}) { return nil } return db.Transaction(func(tx *gorm.DB) error { var parent menuPO if err := tx.Where("name = ?", "extensions").First(&parent).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil } return err } menu := menuPO{ MenuLevel: 1, ParentID: parent.ID, Path: "integrationConfig", Name: "integrationConfig", Component: "view/systemTools/integration/config.vue", Title: "通信集成", Icon: "connection", Sort: 8, } var current menuPO err := tx.Where("name = ?", menu.Name).First(¤t).Error switch { case errors.Is(err, gorm.ErrRecordNotFound): if err = tx.Create(&menu).Error; err != nil { return err } case err != nil: return err default: if err = tx.Model(¤t).Updates(map[string]any{ "menu_level": menu.MenuLevel, "parent_id": menu.ParentID, "path": menu.Path, "component": menu.Component, "title": menu.Title, "icon": menu.Icon, "sort": menu.Sort, }).Error; err != nil { return err } menu.ID = current.ID } apis := []apiPO{ {Path: "/integration/configs/:kind", Method: "GET", APIGroup: "集成配置", Description: "按类型获取集成配置"}, {Path: "/integration/configs/:kind/:provider", Method: "GET", APIGroup: "集成配置", Description: "获取指定集成配置"}, {Path: "/integration/configs/:kind/:provider", Method: "PUT", APIGroup: "集成配置", Description: "保存集成配置"}, {Path: "/integration/configs/:kind/:provider/test", Method: "POST", APIGroup: "集成配置", Description: "测试通信集成连接"}, {Path: "/integration/configs/:kind/:provider", Method: "DELETE", APIGroup: "集成配置", Description: "删除集成配置"}, } for _, api := range apis { if err := tx.Where("path = ? AND method = ?", api.Path, api.Method).FirstOrCreate(&api).Error; err != nil { return err } } if !tx.Migrator().HasTable(&authorityPO{}) || !tx.Migrator().HasTable(&authorityMenuPO{}) || !tx.Migrator().HasTable(&casbinRulePO{}) { return nil } var authority authorityPO if err := tx.Where("authority_id = ?", 888).First(&authority).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil } return err } var linkCount int64 if err := tx.Model(&authorityMenuPO{}).Where("sys_authority_authority_id = ? AND sys_base_menu_id = ?", authority.AuthorityID, menu.ID).Count(&linkCount).Error; err != nil { return err } if linkCount == 0 { if err := tx.Create(&authorityMenuPO{SysAuthorityAuthorityID: authority.AuthorityID, SysBaseMenuID: menu.ID}).Error; err != nil { return err } } for _, api := range apis { exists, err := policyExists(tx, authority.AuthorityID, api.Path, api.Method) if err != nil { return err } if !exists { rule := newPolicyRule(authority.AuthorityID, api.Path, api.Method) if err := tx.Create(&rule).Error; err != nil { return err } } } return nil }) } func ensureCommunicationTestSurface(db *gorm.DB) error { if db == nil || !db.Migrator().HasTable(&menuPO{}) || !db.Migrator().HasTable(&apiPO{}) { return nil } return db.Transaction(func(tx *gorm.DB) error { var existingMenus int64 if err := tx.Model(&menuPO{}).Where("name IN ?", []string{"extensions", "integrationConfig"}).Count(&existingMenus).Error; err != nil { return err } if existingMenus == 0 { return nil } api := apiPO{ Path: "/integration/configs/:kind/:provider/test", Method: "POST", APIGroup: "集成配置", Description: "测试通信集成连接", } if err := tx.Where("path = ? AND method = ?", api.Path, api.Method).FirstOrCreate(&api).Error; err != nil { return err } if !tx.Migrator().HasTable(&authorityPO{}) || !tx.Migrator().HasTable(&casbinRulePO{}) { return nil } var authority authorityPO if err := tx.Where("authority_id = ?", 888).First(&authority).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil } return err } exists, err := policyExists(tx, authority.AuthorityID, api.Path, api.Method) if err != nil { return err } if exists { return nil } rule := newPolicyRule(authority.AuthorityID, api.Path, api.Method) return tx.Create(&rule).Error }) }