diff --git a/app/console/commands/panel.go b/app/console/commands/panel.go index e2bbbe8886..eb65d90dc5 100644 --- a/app/console/commands/panel.go +++ b/app/console/commands/panel.go @@ -4,11 +4,10 @@ import ( "os" "github.com/gookit/color" - "github.com/spf13/cast" - "github.com/goravel/framework/contracts/console" "github.com/goravel/framework/contracts/console/command" "github.com/goravel/framework/facades" + "github.com/spf13/cast" "panel/app/models" "panel/app/services" @@ -73,12 +72,19 @@ func (receiver *Panel) Handle(ctx console.Context) error { color.Greenln("初始化成功") case "update": + var task models.Task + err := facades.Orm().Query().Where("status", models.TaskStatusRunning).OrWhere("status", models.TaskStatusWaiting).FirstOrFail(&task) + if err == nil { + color.Redln("当前有任务正在执行,禁止更新") + return nil + } + input := arg1 proxy := false if input == "y" || input == "Y" || input == "yes" || input == "Yes" { proxy = true } - err := tools.UpdatePanel(cast.ToBool(proxy)) + err = tools.UpdatePanel(cast.ToBool(proxy)) if err != nil { color.Redln("更新失败: " + err.Error()) return nil diff --git a/app/http/controllers/cron_controller.go b/app/http/controllers/cron_controller.go index 30a6c5a05d..7309079b36 100644 --- a/app/http/controllers/cron_controller.go +++ b/app/http/controllers/cron_controller.go @@ -53,7 +53,7 @@ func (r *CronController) Add(ctx http.Context) { return } if validator.Fails() { - Error(ctx, http.StatusBadRequest, validator.Errors().All()) + Error(ctx, http.StatusBadRequest, validator.Errors().One()) return } @@ -129,7 +129,7 @@ func (r *CronController) Update(ctx http.Context) { return } if validator.Fails() { - Error(ctx, http.StatusBadRequest, validator.Errors().All()) + Error(ctx, http.StatusBadRequest, validator.Errors().One()) return } diff --git a/app/http/controllers/info_controller.go b/app/http/controllers/info_controller.go index 043715a1c8..2a41c46a83 100644 --- a/app/http/controllers/info_controller.go +++ b/app/http/controllers/info_controller.go @@ -163,8 +163,15 @@ func (c *InfoController) CheckUpdate(ctx http.Context) { } func (c *InfoController) Update(ctx http.Context) { + var task models.Task + err := facades.Orm().Query().Where("status", models.TaskStatusRunning).OrWhere("status", models.TaskStatusWaiting).FirstOrFail(&task) + if err == nil { + Error(ctx, http.StatusInternalServerError, "当前有任务正在执行,禁止更新") + return + } + proxy := ctx.Request().InputBool("proxy") - err := tools.UpdatePanel(proxy) + err = tools.UpdatePanel(proxy) if err != nil { facades.Log().Error("[面板][InfoController] 更新面板失败 ", err.Error()) Error(ctx, http.StatusInternalServerError, "更新失败: "+err.Error()) diff --git a/app/http/controllers/plugins/mysql57/mysql57_controller.go b/app/http/controllers/plugins/mysql57/mysql57_controller.go index a42ee2cc0a..aea71f0134 100644 --- a/app/http/controllers/plugins/mysql57/mysql57_controller.go +++ b/app/http/controllers/plugins/mysql57/mysql57_controller.go @@ -1,6 +1,7 @@ package mysql57 import ( + "database/sql" "fmt" "os" "path/filepath" @@ -11,8 +12,6 @@ import ( "github.com/goravel/framework/facades" "github.com/goravel/framework/support/carbon" "github.com/spf13/cast" - "golang.org/x/exp/slices" - "panel/app/http/controllers" "panel/app/models" "panel/app/services" @@ -35,7 +34,7 @@ func (c *Mysql57Controller) Status(ctx http.Context) { return } - status := tools.ExecShell("systemctl status mysql | grep Active | grep -v grep | awk '{print $2}'") + status := tools.ExecShell("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'") if len(status) == 0 { controllers.Error(ctx, http.StatusInternalServerError, "获取MySQL状态失败") return @@ -54,8 +53,8 @@ func (c *Mysql57Controller) Reload(ctx http.Context) { return } - tools.ExecShell("systemctl reload mysql") - status := tools.ExecShell("systemctl status mysql | grep Active | grep -v grep | awk '{print $2}'") + tools.ExecShell("systemctl reload mysqld") + status := tools.ExecShell("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'") if len(status) == 0 { controllers.Error(ctx, http.StatusInternalServerError, "获取MySQL状态失败") return @@ -74,8 +73,8 @@ func (c *Mysql57Controller) Restart(ctx http.Context) { return } - tools.ExecShell("systemctl restart mysql") - status := tools.ExecShell("systemctl status mysql | grep Active | grep -v grep | awk '{print $2}'") + tools.ExecShell("systemctl restart mysqld") + status := tools.ExecShell("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'") if len(status) == 0 { controllers.Error(ctx, http.StatusInternalServerError, "获取MySQL状态失败") return @@ -94,8 +93,8 @@ func (c *Mysql57Controller) Start(ctx http.Context) { return } - tools.ExecShell("systemctl start mysql") - status := tools.ExecShell("systemctl status mysql | grep Active | grep -v grep | awk '{print $2}'") + tools.ExecShell("systemctl start mysqld") + status := tools.ExecShell("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'") if len(status) == 0 { controllers.Error(ctx, http.StatusInternalServerError, "获取MySQL状态失败") return @@ -114,8 +113,8 @@ func (c *Mysql57Controller) Stop(ctx http.Context) { return } - tools.ExecShell("systemctl stop mysql") - status := tools.ExecShell("systemctl status mysql | grep Active | grep -v grep | awk '{print $2}'") + tools.ExecShell("systemctl stop mysqld") + status := tools.ExecShell("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'") if len(status) == 0 { controllers.Error(ctx, http.StatusInternalServerError, "获取MySQL状态失败") return @@ -135,7 +134,7 @@ func (c *Mysql57Controller) GetConfig(ctx http.Context) { } // 获取配置 - config := tools.ReadFile("mysql57") + config := tools.ReadFile("/www/server/mysql/conf/my.cnf") if len(config) == 0 { controllers.Error(ctx, http.StatusInternalServerError, "获取MySQL配置失败") return @@ -156,7 +155,7 @@ func (c *Mysql57Controller) SaveConfig(ctx http.Context) { return } - if !tools.WriteFile("mysql57", config, 0644) { + if !tools.WriteFile("/www/server/mysql/conf/my.cnf", config, 0644) { controllers.Error(ctx, http.StatusInternalServerError, "写入MySQL配置失败") return } @@ -197,24 +196,24 @@ func (c *Mysql57Controller) Load(ctx http.Context) { regex string name string }{ - {`Uptime\s+\|\s+(\d+)\s+\|`, "总查询次数"}, - {`Queries\s+\|\s+(\d+)\s+\|`, "总连接次数"}, - {`Connections\s+\|\s+(\d+)\s+\|`, "每秒事务"}, - {`Com_commit\s+\|\s+(\d+)\s+\|`, "每秒回滚"}, - {`Com_rollback\s+\|\s+(\d+)\s+\|`, "发送"}, - {`Bytes_sent\s+\|\s+(\d+)\s+\|`, "接收"}, - {`Bytes_received\s+\|\s+(\d+)\s+\|`, "活动连接数"}, - {`Threads_connected\s+\|\s+(\d+)\s+\|`, "峰值连接数"}, - {`Max_used_connections\s+\|\s+(\d+)\s+\|`, "索引命中率"}, - {`Key_read_requests\s+\|\s+(\d+)\s+\|`, "Innodb索引命中率"}, - {`Innodb_buffer_pool_reads\s+\|\s+(\d+)\s+\|`, "创建临时表到磁盘"}, - {`Created_tmp_disk_tables\s+\|\s+(\d+)\s+\|`, "已打开的表"}, - {`Open_tables\s+\|\s+(\d+)\s+\|`, "没有使用索引的量"}, - {`Select_full_join\s+\|\s+(\d+)\s+\|`, "没有索引的JOIN量"}, - {`Select_full_range_join\s+\|\s+(\d+)\s+\|`, "没有索引的子查询量"}, - {`Select_range_check\s+\|\s+(\d+)\s+\|`, "排序后的合并次数"}, - {`Sort_merge_passes\s+\|\s+(\d+)\s+\|`, "锁表次数"}, - {`Table_locks_waited\s+\|\s+(\d+)\s+\|`, ""}, + {`Uptime\s+\|\s+(\d+)\s+\|`, "运行时间"}, + {`Queries\s+\|\s+(\d+)\s+\|`, "总查询次数"}, + {`Connections\s+\|\s+(\d+)\s+\|`, "总连接次数"}, + {`Com_commit\s+\|\s+(\d+)\s+\|`, "每秒事务"}, + {`Com_rollback\s+\|\s+(\d+)\s+\|`, "每秒回滚"}, + {`Bytes_sent\s+\|\s+(\d+)\s+\|`, "发送"}, + {`Bytes_received\s+\|\s+(\d+)\s+\|`, "接收"}, + {`Threads_connected\s+\|\s+(\d+)\s+\|`, "活动连接数"}, + {`Max_used_connections\s+\|\s+(\d+)\s+\|`, "峰值连接数"}, + {`Key_read_requests\s+\|\s+(\d+)\s+\|`, "索引命中率"}, + {`Innodb_buffer_pool_reads\s+\|\s+(\d+)\s+\|`, "Innodb索引命中率"}, + {`Created_tmp_disk_tables\s+\|\s+(\d+)\s+\|`, "创建临时表到磁盘"}, + {`Open_tables\s+\|\s+(\d+)\s+\|`, "已打开的表"}, + {`Select_full_join\s+\|\s+(\d+)\s+\|`, "没有使用索引的量"}, + {`Select_full_range_join\s+\|\s+(\d+)\s+\|`, "没有索引的JOIN量"}, + {`Select_range_check\s+\|\s+(\d+)\s+\|`, "没有索引的子查询量"}, + {`Sort_merge_passes\s+\|\s+(\d+)\s+\|`, "排序后的合并次数"}, + {`Table_locks_waited\s+\|\s+(\d+)\s+\|`, "锁表次数"}, } for i, expression := range expressions { @@ -234,7 +233,7 @@ func (c *Mysql57Controller) Load(ctx http.Context) { readRequests := cast.ToFloat64(data[9]["value"]) reads := cast.ToFloat64(data[10]["value"]) data[9]["value"] = fmt.Sprintf("%.2f%%", readRequests/(reads+readRequests)*100) - // Innodb索引命中率 + // Innodb 索引命中率 bufferPoolReads := cast.ToFloat64(data[11]["value"]) bufferPoolReadRequests := cast.ToFloat64(data[12]["value"]) data[10]["value"] = fmt.Sprintf("%.2f%%", bufferPoolReadRequests/(bufferPoolReads+bufferPoolReadRequests)*100) @@ -303,7 +302,7 @@ func (c *Mysql57Controller) SetRootPassword(ctx http.Context) { return } - status := tools.ExecShell("systemctl status mysql | grep Active | grep -v grep | awk '{print $2}'") + status := tools.ExecShell("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'") if len(status) == 0 { controllers.Error(ctx, http.StatusInternalServerError, "获取MySQL状态失败") return @@ -341,29 +340,45 @@ func (c *Mysql57Controller) DatabaseList(ctx http.Context) { return } - out := tools.ExecShell("mysql -uroot -p" + c.setting.Get(models.SettingKeyMysqlRootPassword) + " -e \"show databases;\"") - databases := strings.Split(out, "\n") + rootPassword := c.setting.Get(models.SettingKeyMysqlRootPassword) + type database struct { + Name string `json:"name"` + } - databases = databases[1 : len(databases)-1] - systemDatabases := []string{"information_schema", "mysql", "performance_schema", "sys"} + db, err := sql.Open("mysql", "root:"+rootPassword+"@unix(/tmp/mysql.sock)/") + if err != nil { + facades.Log().Error("[MySQL57] 连接数据库失败" + err.Error()) + controllers.Error(ctx, http.StatusInternalServerError, "连接数据库失败") + return + } + defer db.Close() - var userDatabases []string - for _, db := range databases { - if !slices.Contains(systemDatabases, db) { - userDatabases = append(userDatabases, db) - } + rows, err := db.Query("SHOW DATABASES") + if err != nil { + facades.Log().Error("[MySQL57] 获取数据库列表失败" + err.Error()) + controllers.Error(ctx, http.StatusInternalServerError, "获取数据库列表失败") + return } + defer rows.Close() - type Database struct { - Name string + var databases []database + for rows.Next() { + var d database + err := rows.Scan(&d.Name) + if err != nil { + continue + } + + databases = append(databases, d) } - var dbStructs []Database - for _, db := range userDatabases { - dbStructs = append(dbStructs, Database{Name: db}) + if err := rows.Err(); err != nil { + facades.Log().Error("[MySQL57] 获取数据库列表失败" + err.Error()) + controllers.Error(ctx, http.StatusInternalServerError, "获取数据库列表失败") + return } - controllers.Success(ctx, dbStructs) + controllers.Success(ctx, databases) } // AddDatabase 添加数据库 @@ -375,14 +390,14 @@ func (c *Mysql57Controller) AddDatabase(ctx http.Context) { validator, err := ctx.Request().Validate(map[string]string{ "database": "required|min_len:1|max_len:255|regex:^[a-zA-Z][a-zA-Z0-9_]+$", "user": "required|min_len:1|max_len:255|regex:^[a-zA-Z][a-zA-Z0-9_]+$", - "password": "required|min_len:8|max_len:255|regex:^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*(_|[^\\w])).+$", + "password": "required|min_len:8|max_len:255", }) if err != nil { controllers.Error(ctx, http.StatusBadRequest, err.Error()) return } if validator.Fails() { - controllers.Error(ctx, http.StatusBadRequest, validator.Errors().All()) + controllers.Error(ctx, http.StatusBadRequest, validator.Errors().One()) return } @@ -413,7 +428,7 @@ func (c *Mysql57Controller) DeleteDatabase(ctx http.Context) { return } if validator.Fails() { - controllers.Error(ctx, http.StatusBadRequest, validator.Errors().All()) + controllers.Error(ctx, http.StatusBadRequest, validator.Errors().One()) return } @@ -458,6 +473,38 @@ func (c *Mysql57Controller) BackupList(ctx http.Context) { controllers.Success(ctx, backupFiles) } +// UploadBackup 上传备份 +func (c *Mysql57Controller) UploadBackup(ctx http.Context) { + if !controllers.Check(ctx, "mysql57") { + return + } + + // TODO 框架 Bug ? 下面会 panic + controllers.Error(ctx, http.StatusBadRequest, "暂不支持") + return + + file, err := ctx.Request().File("file") + if err != nil { + controllers.Error(ctx, http.StatusBadRequest, "上传文件失败") + return + } + + backupPath := c.setting.Get(models.SettingKeyBackupPath) + "/mysql" + if !tools.Exists(backupPath) { + tools.Mkdir(backupPath, 0644) + } + + name := file.GetClientOriginalName() + extension := file.GetClientOriginalExtension() + _, err = file.Store(backupPath + "/" + name + "." + extension) + if err != nil { + controllers.Error(ctx, http.StatusBadRequest, "上传文件失败") + return + } + + controllers.Success(ctx, "上传文件成功") +} + // CreateBackup 创建备份 func (c *Mysql57Controller) CreateBackup(ctx http.Context) { if !controllers.Check(ctx, "mysql57") { @@ -472,14 +519,14 @@ func (c *Mysql57Controller) CreateBackup(ctx http.Context) { return } if validator.Fails() { - controllers.Error(ctx, http.StatusBadRequest, validator.Errors().All()) + controllers.Error(ctx, http.StatusBadRequest, validator.Errors().One()) return } backupPath := c.setting.Get(models.SettingKeyBackupPath) + "/mysql" rootPassword := c.setting.Get(models.SettingKeyMysqlRootPassword) database := ctx.Request().Input("database") - backupFile := backupPath + "/" + database + "_" + carbon.Now().ToShortDateTimeString() + ".sql" + backupFile := database + "_" + carbon.Now().ToShortDateTimeString() + ".sql" if !tools.Exists(backupPath) { tools.Mkdir(backupPath, 0644) } @@ -490,9 +537,9 @@ func (c *Mysql57Controller) CreateBackup(ctx http.Context) { return } - tools.ExecShell("mysqldump -uroot " + database + " > " + backupFile) - tools.ExecShell("zip -c " + backupFile + ".zip " + backupFile) - tools.RemoveFile(backupFile) + tools.ExecShell("mysqldump -uroot " + database + " > " + backupPath + "/" + backupFile) + tools.ExecShell("cd " + backupPath + " && zip -r " + backupPath + "/" + backupFile + ".zip " + backupFile) + tools.RemoveFile(backupPath + "/" + backupFile) _ = os.Unsetenv("MYSQL_PWD") controllers.Success(ctx, "备份成功") @@ -512,7 +559,7 @@ func (c *Mysql57Controller) DeleteBackup(ctx http.Context) { return } if validator.Fails() { - controllers.Error(ctx, http.StatusBadRequest, validator.Errors().All()) + controllers.Error(ctx, http.StatusBadRequest, validator.Errors().One()) return } @@ -538,7 +585,7 @@ func (c *Mysql57Controller) RestoreBackup(ctx http.Context) { return } if validator.Fails() { - controllers.Error(ctx, http.StatusBadRequest, validator.Errors().All()) + controllers.Error(ctx, http.StatusBadRequest, validator.Errors().One()) return } @@ -602,36 +649,66 @@ func (c *Mysql57Controller) UserList(ctx http.Context) { return } - type User struct { - Username string `json:"username"` - Host string `json:"host"` - Privileges string `json:"privileges"` + type user struct { + User string `json:"user"` + Host string `json:"host"` + Grants []string `json:"grants"` } rootPassword := c.setting.Get(models.SettingKeyMysqlRootPassword) - out := tools.ExecShell("mysql -uroot -p" + rootPassword + " -e 'select user,host from mysql.user'") - rawUsers := strings.Split(out, "\n") - users := make([]User, 0) - for _, rawUser := range rawUsers { - user := strings.Split(rawUser, "\t") - if user[0] == "root" || user[0] == "mysql.sys" || user[0] == "mysql.infoschema" || user[0] == "mysql.session" { + db, err := sql.Open("mysql", "root:"+rootPassword+"@unix(/tmp/mysql.sock)/") + if err != nil { + facades.Log().Error("[MYSQL57] 连接数据库失败:" + err.Error()) + controllers.Error(ctx, http.StatusInternalServerError, "连接数据库失败") + } + defer db.Close() + + rows, err := db.Query("SELECT user, host FROM mysql.user") + if err != nil { + facades.Log().Error("[MYSQL57] 查询数据库失败:" + err.Error()) + controllers.Error(ctx, http.StatusInternalServerError, "查询数据库失败") + } + defer rows.Close() + + var userGrants []user + + for rows.Next() { + var u user + err := rows.Scan(&u.User, &u.Host) + if err != nil { + continue + } + + // 查询用户权限 + grantsRows, err := db.Query(fmt.Sprintf("SHOW GRANTS FOR '%s'@'%s'", u.User, u.Host)) + if err != nil { continue } + defer grantsRows.Close() - out := tools.ExecShell("mysql -uroot -p" + rootPassword + " -e 'show grants for " + user[0] + "@" + user[1] + "'") - rawPrivileges := strings.Split(out, "\n") - privileges := make([]string, 0) - for _, rawPrivilege := range rawPrivileges { - if rawPrivilege == "" { + for grantsRows.Next() { + var grant string + err := grantsRows.Scan(&grant) + if err != nil { continue } - privilege := rawPrivilege[6:strings.Index(rawPrivilege, " TO")] - privileges = append(privileges, privilege) + + u.Grants = append(u.Grants, grant) } - users = append(users, User{Username: user[0], Host: user[1], Privileges: strings.Join(privileges, " | ")}) + + if err := grantsRows.Err(); err != nil { + continue + } + + userGrants = append(userGrants, u) + } + + if err := rows.Err(); err != nil { + controllers.Error(ctx, http.StatusInternalServerError, "获取用户列表失败") + return } - controllers.Success(ctx, users) + controllers.Success(ctx, userGrants) } // AddUser 添加用户 @@ -643,14 +720,14 @@ func (c *Mysql57Controller) AddUser(ctx http.Context) { validator, err := ctx.Request().Validate(map[string]string{ "database": "required|min_len:1|max_len:255|regex:^[a-zA-Z][a-zA-Z0-9_]+$", "user": "required|min_len:1|max_len:255|regex:^[a-zA-Z][a-zA-Z0-9_]+$", - "password": "required|min_len:8|max_len:255|regex:^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*(_|[^\\w])).+$", + "password": "required|min_len:8|max_len:255", }) if err != nil { controllers.Error(ctx, http.StatusBadRequest, err.Error()) return } if validator.Fails() { - controllers.Error(ctx, http.StatusBadRequest, validator.Errors().All()) + controllers.Error(ctx, http.StatusBadRequest, validator.Errors().One()) return } @@ -679,7 +756,7 @@ func (c *Mysql57Controller) DeleteUser(ctx http.Context) { return } if validator.Fails() { - controllers.Error(ctx, http.StatusBadRequest, validator.Errors().All()) + controllers.Error(ctx, http.StatusBadRequest, validator.Errors().One()) return } @@ -698,14 +775,14 @@ func (c *Mysql57Controller) SetUserPassword(ctx http.Context) { validator, err := ctx.Request().Validate(map[string]string{ "user": "required|min_len:1|max_len:255|regex:^[a-zA-Z][a-zA-Z0-9_]+$", - "password": "required|min_len:8|max_len:255|regex:^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*(_|[^\\w])).+$", + "password": "required|min_len:8|max_len:255", }) if err != nil { controllers.Error(ctx, http.StatusBadRequest, err.Error()) return } if validator.Fails() { - controllers.Error(ctx, http.StatusBadRequest, validator.Errors().All()) + controllers.Error(ctx, http.StatusBadRequest, validator.Errors().One()) return } @@ -733,7 +810,7 @@ func (c *Mysql57Controller) SetUserPrivileges(ctx http.Context) { return } if validator.Fails() { - controllers.Error(ctx, http.StatusBadRequest, validator.Errors().All()) + controllers.Error(ctx, http.StatusBadRequest, validator.Errors().One()) return } diff --git a/app/http/controllers/plugins/mysql80/mysql80_controller.go b/app/http/controllers/plugins/mysql80/mysql80_controller.go index fd25a964f6..618cc2bfca 100644 --- a/app/http/controllers/plugins/mysql80/mysql80_controller.go +++ b/app/http/controllers/plugins/mysql80/mysql80_controller.go @@ -1,6 +1,7 @@ package mysql80 import ( + "database/sql" "fmt" "os" "path/filepath" @@ -11,8 +12,6 @@ import ( "github.com/goravel/framework/facades" "github.com/goravel/framework/support/carbon" "github.com/spf13/cast" - "golang.org/x/exp/slices" - "panel/app/http/controllers" "panel/app/models" "panel/app/services" @@ -35,7 +34,7 @@ func (c *Mysql80Controller) Status(ctx http.Context) { return } - status := tools.ExecShell("systemctl status mysql | grep Active | grep -v grep | awk '{print $2}'") + status := tools.ExecShell("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'") if len(status) == 0 { controllers.Error(ctx, http.StatusInternalServerError, "获取MySQL状态失败") return @@ -54,8 +53,8 @@ func (c *Mysql80Controller) Reload(ctx http.Context) { return } - tools.ExecShell("systemctl reload mysql") - status := tools.ExecShell("systemctl status mysql | grep Active | grep -v grep | awk '{print $2}'") + tools.ExecShell("systemctl reload mysqld") + status := tools.ExecShell("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'") if len(status) == 0 { controllers.Error(ctx, http.StatusInternalServerError, "获取MySQL状态失败") return @@ -74,8 +73,8 @@ func (c *Mysql80Controller) Restart(ctx http.Context) { return } - tools.ExecShell("systemctl restart mysql") - status := tools.ExecShell("systemctl status mysql | grep Active | grep -v grep | awk '{print $2}'") + tools.ExecShell("systemctl restart mysqld") + status := tools.ExecShell("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'") if len(status) == 0 { controllers.Error(ctx, http.StatusInternalServerError, "获取MySQL状态失败") return @@ -94,8 +93,8 @@ func (c *Mysql80Controller) Start(ctx http.Context) { return } - tools.ExecShell("systemctl start mysql") - status := tools.ExecShell("systemctl status mysql | grep Active | grep -v grep | awk '{print $2}'") + tools.ExecShell("systemctl start mysqld") + status := tools.ExecShell("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'") if len(status) == 0 { controllers.Error(ctx, http.StatusInternalServerError, "获取MySQL状态失败") return @@ -114,8 +113,8 @@ func (c *Mysql80Controller) Stop(ctx http.Context) { return } - tools.ExecShell("systemctl stop mysql") - status := tools.ExecShell("systemctl status mysql | grep Active | grep -v grep | awk '{print $2}'") + tools.ExecShell("systemctl stop mysqld") + status := tools.ExecShell("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'") if len(status) == 0 { controllers.Error(ctx, http.StatusInternalServerError, "获取MySQL状态失败") return @@ -135,7 +134,7 @@ func (c *Mysql80Controller) GetConfig(ctx http.Context) { } // 获取配置 - config := tools.ReadFile("mysql80") + config := tools.ReadFile("/www/server/mysql/conf/my.cnf") if len(config) == 0 { controllers.Error(ctx, http.StatusInternalServerError, "获取MySQL配置失败") return @@ -156,7 +155,7 @@ func (c *Mysql80Controller) SaveConfig(ctx http.Context) { return } - if !tools.WriteFile("mysql80", config, 0644) { + if !tools.WriteFile("/www/server/mysql/conf/my.cnf", config, 0644) { controllers.Error(ctx, http.StatusInternalServerError, "写入MySQL配置失败") return } @@ -197,24 +196,24 @@ func (c *Mysql80Controller) Load(ctx http.Context) { regex string name string }{ - {`Uptime\s+\|\s+(\d+)\s+\|`, "总查询次数"}, - {`Queries\s+\|\s+(\d+)\s+\|`, "总连接次数"}, - {`Connections\s+\|\s+(\d+)\s+\|`, "每秒事务"}, - {`Com_commit\s+\|\s+(\d+)\s+\|`, "每秒回滚"}, - {`Com_rollback\s+\|\s+(\d+)\s+\|`, "发送"}, - {`Bytes_sent\s+\|\s+(\d+)\s+\|`, "接收"}, - {`Bytes_received\s+\|\s+(\d+)\s+\|`, "活动连接数"}, - {`Threads_connected\s+\|\s+(\d+)\s+\|`, "峰值连接数"}, - {`Max_used_connections\s+\|\s+(\d+)\s+\|`, "索引命中率"}, - {`Key_read_requests\s+\|\s+(\d+)\s+\|`, "Innodb索引命中率"}, - {`Innodb_buffer_pool_reads\s+\|\s+(\d+)\s+\|`, "创建临时表到磁盘"}, - {`Created_tmp_disk_tables\s+\|\s+(\d+)\s+\|`, "已打开的表"}, - {`Open_tables\s+\|\s+(\d+)\s+\|`, "没有使用索引的量"}, - {`Select_full_join\s+\|\s+(\d+)\s+\|`, "没有索引的JOIN量"}, - {`Select_full_range_join\s+\|\s+(\d+)\s+\|`, "没有索引的子查询量"}, - {`Select_range_check\s+\|\s+(\d+)\s+\|`, "排序后的合并次数"}, - {`Sort_merge_passes\s+\|\s+(\d+)\s+\|`, "锁表次数"}, - {`Table_locks_waited\s+\|\s+(\d+)\s+\|`, ""}, + {`Uptime\s+\|\s+(\d+)\s+\|`, "运行时间"}, + {`Queries\s+\|\s+(\d+)\s+\|`, "总查询次数"}, + {`Connections\s+\|\s+(\d+)\s+\|`, "总连接次数"}, + {`Com_commit\s+\|\s+(\d+)\s+\|`, "每秒事务"}, + {`Com_rollback\s+\|\s+(\d+)\s+\|`, "每秒回滚"}, + {`Bytes_sent\s+\|\s+(\d+)\s+\|`, "发送"}, + {`Bytes_received\s+\|\s+(\d+)\s+\|`, "接收"}, + {`Threads_connected\s+\|\s+(\d+)\s+\|`, "活动连接数"}, + {`Max_used_connections\s+\|\s+(\d+)\s+\|`, "峰值连接数"}, + {`Key_read_requests\s+\|\s+(\d+)\s+\|`, "索引命中率"}, + {`Innodb_buffer_pool_reads\s+\|\s+(\d+)\s+\|`, "Innodb索引命中率"}, + {`Created_tmp_disk_tables\s+\|\s+(\d+)\s+\|`, "创建临时表到磁盘"}, + {`Open_tables\s+\|\s+(\d+)\s+\|`, "已打开的表"}, + {`Select_full_join\s+\|\s+(\d+)\s+\|`, "没有使用索引的量"}, + {`Select_full_range_join\s+\|\s+(\d+)\s+\|`, "没有索引的JOIN量"}, + {`Select_range_check\s+\|\s+(\d+)\s+\|`, "没有索引的子查询量"}, + {`Sort_merge_passes\s+\|\s+(\d+)\s+\|`, "排序后的合并次数"}, + {`Table_locks_waited\s+\|\s+(\d+)\s+\|`, "锁表次数"}, } for i, expression := range expressions { @@ -234,7 +233,7 @@ func (c *Mysql80Controller) Load(ctx http.Context) { readRequests := cast.ToFloat64(data[9]["value"]) reads := cast.ToFloat64(data[10]["value"]) data[9]["value"] = fmt.Sprintf("%.2f%%", readRequests/(reads+readRequests)*100) - // Innodb索引命中率 + // Innodb 索引命中率 bufferPoolReads := cast.ToFloat64(data[11]["value"]) bufferPoolReadRequests := cast.ToFloat64(data[12]["value"]) data[10]["value"] = fmt.Sprintf("%.2f%%", bufferPoolReadRequests/(bufferPoolReads+bufferPoolReadRequests)*100) @@ -303,7 +302,7 @@ func (c *Mysql80Controller) SetRootPassword(ctx http.Context) { return } - status := tools.ExecShell("systemctl status mysql | grep Active | grep -v grep | awk '{print $2}'") + status := tools.ExecShell("systemctl status mysqld | grep Active | grep -v grep | awk '{print $2}'") if len(status) == 0 { controllers.Error(ctx, http.StatusInternalServerError, "获取MySQL状态失败") return @@ -341,29 +340,45 @@ func (c *Mysql80Controller) DatabaseList(ctx http.Context) { return } - out := tools.ExecShell("mysql -uroot -p" + c.setting.Get(models.SettingKeyMysqlRootPassword) + " -e \"show databases;\"") - databases := strings.Split(out, "\n") + rootPassword := c.setting.Get(models.SettingKeyMysqlRootPassword) + type database struct { + Name string `json:"name"` + } - databases = databases[1 : len(databases)-1] - systemDatabases := []string{"information_schema", "mysql", "performance_schema", "sys"} + db, err := sql.Open("mysql", "root:"+rootPassword+"@unix(/tmp/mysql.sock)/") + if err != nil { + facades.Log().Error("[MySQL80] 连接数据库失败" + err.Error()) + controllers.Error(ctx, http.StatusInternalServerError, "连接数据库失败") + return + } + defer db.Close() - var userDatabases []string - for _, db := range databases { - if !slices.Contains(systemDatabases, db) { - userDatabases = append(userDatabases, db) - } + rows, err := db.Query("SHOW DATABASES") + if err != nil { + facades.Log().Error("[MySQL80] 获取数据库列表失败" + err.Error()) + controllers.Error(ctx, http.StatusInternalServerError, "获取数据库列表失败") + return } + defer rows.Close() - type Database struct { - Name string + var databases []database + for rows.Next() { + var d database + err := rows.Scan(&d.Name) + if err != nil { + continue + } + + databases = append(databases, d) } - var dbStructs []Database - for _, db := range userDatabases { - dbStructs = append(dbStructs, Database{Name: db}) + if err := rows.Err(); err != nil { + facades.Log().Error("[MySQL80] 获取数据库列表失败" + err.Error()) + controllers.Error(ctx, http.StatusInternalServerError, "获取数据库列表失败") + return } - controllers.Success(ctx, dbStructs) + controllers.Success(ctx, databases) } // AddDatabase 添加数据库 @@ -375,14 +390,14 @@ func (c *Mysql80Controller) AddDatabase(ctx http.Context) { validator, err := ctx.Request().Validate(map[string]string{ "database": "required|min_len:1|max_len:255|regex:^[a-zA-Z][a-zA-Z0-9_]+$", "user": "required|min_len:1|max_len:255|regex:^[a-zA-Z][a-zA-Z0-9_]+$", - "password": "required|min_len:8|max_len:255|regex:^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*(_|[^\\w])).+$", + "password": "required|min_len:8|max_len:255", }) if err != nil { controllers.Error(ctx, http.StatusBadRequest, err.Error()) return } if validator.Fails() { - controllers.Error(ctx, http.StatusBadRequest, validator.Errors().All()) + controllers.Error(ctx, http.StatusBadRequest, validator.Errors().One()) return } @@ -413,7 +428,7 @@ func (c *Mysql80Controller) DeleteDatabase(ctx http.Context) { return } if validator.Fails() { - controllers.Error(ctx, http.StatusBadRequest, validator.Errors().All()) + controllers.Error(ctx, http.StatusBadRequest, validator.Errors().One()) return } @@ -458,6 +473,38 @@ func (c *Mysql80Controller) BackupList(ctx http.Context) { controllers.Success(ctx, backupFiles) } +// UploadBackup 上传备份 +func (c *Mysql80Controller) UploadBackup(ctx http.Context) { + if !controllers.Check(ctx, "mysql80") { + return + } + + // TODO 框架 Bug ? 下面会 panic + controllers.Error(ctx, http.StatusBadRequest, "暂不支持") + return + + file, err := ctx.Request().File("file") + if err != nil { + controllers.Error(ctx, http.StatusBadRequest, "上传文件失败") + return + } + + backupPath := c.setting.Get(models.SettingKeyBackupPath) + "/mysql" + if !tools.Exists(backupPath) { + tools.Mkdir(backupPath, 0644) + } + + name := file.GetClientOriginalName() + extension := file.GetClientOriginalExtension() + _, err = file.Store(backupPath + "/" + name + "." + extension) + if err != nil { + controllers.Error(ctx, http.StatusBadRequest, "上传文件失败") + return + } + + controllers.Success(ctx, "上传文件成功") +} + // CreateBackup 创建备份 func (c *Mysql80Controller) CreateBackup(ctx http.Context) { if !controllers.Check(ctx, "mysql80") { @@ -472,14 +519,14 @@ func (c *Mysql80Controller) CreateBackup(ctx http.Context) { return } if validator.Fails() { - controllers.Error(ctx, http.StatusBadRequest, validator.Errors().All()) + controllers.Error(ctx, http.StatusBadRequest, validator.Errors().One()) return } backupPath := c.setting.Get(models.SettingKeyBackupPath) + "/mysql" rootPassword := c.setting.Get(models.SettingKeyMysqlRootPassword) database := ctx.Request().Input("database") - backupFile := backupPath + "/" + database + "_" + carbon.Now().ToShortDateTimeString() + ".sql" + backupFile := database + "_" + carbon.Now().ToShortDateTimeString() + ".sql" if !tools.Exists(backupPath) { tools.Mkdir(backupPath, 0644) } @@ -490,9 +537,9 @@ func (c *Mysql80Controller) CreateBackup(ctx http.Context) { return } - tools.ExecShell("mysqldump -uroot " + database + " > " + backupFile) - tools.ExecShell("zip -c " + backupFile + ".zip " + backupFile) - tools.RemoveFile(backupFile) + tools.ExecShell("mysqldump -uroot " + database + " > " + backupPath + "/" + backupFile) + tools.ExecShell("cd " + backupPath + " && zip -r " + backupPath + "/" + backupFile + ".zip " + backupFile) + tools.RemoveFile(backupPath + "/" + backupFile) _ = os.Unsetenv("MYSQL_PWD") controllers.Success(ctx, "备份成功") @@ -512,7 +559,7 @@ func (c *Mysql80Controller) DeleteBackup(ctx http.Context) { return } if validator.Fails() { - controllers.Error(ctx, http.StatusBadRequest, validator.Errors().All()) + controllers.Error(ctx, http.StatusBadRequest, validator.Errors().One()) return } @@ -538,7 +585,7 @@ func (c *Mysql80Controller) RestoreBackup(ctx http.Context) { return } if validator.Fails() { - controllers.Error(ctx, http.StatusBadRequest, validator.Errors().All()) + controllers.Error(ctx, http.StatusBadRequest, validator.Errors().One()) return } @@ -553,7 +600,7 @@ func (c *Mysql80Controller) RestoreBackup(ctx http.Context) { err = os.Setenv("MYSQL_PWD", rootPassword) if err != nil { - facades.Log().Error("[MySQL80] 设置环境变量 MYSQL_PWD 失败:" + err.Error()) + facades.Log().Error("[MYSQL80] 设置环境变量 MYSQL_PWD 失败:" + err.Error()) controllers.Error(ctx, http.StatusInternalServerError, "还原失败") return } @@ -602,36 +649,66 @@ func (c *Mysql80Controller) UserList(ctx http.Context) { return } - type User struct { - Username string `json:"username"` - Host string `json:"host"` - Privileges string `json:"privileges"` + type user struct { + User string `json:"user"` + Host string `json:"host"` + Grants []string `json:"grants"` } rootPassword := c.setting.Get(models.SettingKeyMysqlRootPassword) - out := tools.ExecShell("mysql -uroot -p" + rootPassword + " -e 'select user,host from mysql.user'") - rawUsers := strings.Split(out, "\n") - users := make([]User, 0) - for _, rawUser := range rawUsers { - user := strings.Split(rawUser, "\t") - if user[0] == "root" || user[0] == "mysql.sys" || user[0] == "mysql.infoschema" || user[0] == "mysql.session" { + db, err := sql.Open("mysql", "root:"+rootPassword+"@unix(/tmp/mysql.sock)/") + if err != nil { + facades.Log().Error("[MYSQL80] 连接数据库失败:" + err.Error()) + controllers.Error(ctx, http.StatusInternalServerError, "连接数据库失败") + } + defer db.Close() + + rows, err := db.Query("SELECT user, host FROM mysql.user") + if err != nil { + facades.Log().Error("[MYSQL80] 查询数据库失败:" + err.Error()) + controllers.Error(ctx, http.StatusInternalServerError, "查询数据库失败") + } + defer rows.Close() + + var userGrants []user + + for rows.Next() { + var u user + err := rows.Scan(&u.User, &u.Host) + if err != nil { + continue + } + + // 查询用户权限 + grantsRows, err := db.Query(fmt.Sprintf("SHOW GRANTS FOR '%s'@'%s'", u.User, u.Host)) + if err != nil { continue } + defer grantsRows.Close() - out := tools.ExecShell("mysql -uroot -p" + rootPassword + " -e 'show grants for " + user[0] + "@" + user[1] + "'") - rawPrivileges := strings.Split(out, "\n") - privileges := make([]string, 0) - for _, rawPrivilege := range rawPrivileges { - if rawPrivilege == "" { + for grantsRows.Next() { + var grant string + err := grantsRows.Scan(&grant) + if err != nil { continue } - privilege := rawPrivilege[6:strings.Index(rawPrivilege, " TO")] - privileges = append(privileges, privilege) + + u.Grants = append(u.Grants, grant) } - users = append(users, User{Username: user[0], Host: user[1], Privileges: strings.Join(privileges, " | ")}) + + if err := grantsRows.Err(); err != nil { + continue + } + + userGrants = append(userGrants, u) + } + + if err := rows.Err(); err != nil { + controllers.Error(ctx, http.StatusInternalServerError, "获取用户列表失败") + return } - controllers.Success(ctx, users) + controllers.Success(ctx, userGrants) } // AddUser 添加用户 @@ -643,14 +720,14 @@ func (c *Mysql80Controller) AddUser(ctx http.Context) { validator, err := ctx.Request().Validate(map[string]string{ "database": "required|min_len:1|max_len:255|regex:^[a-zA-Z][a-zA-Z0-9_]+$", "user": "required|min_len:1|max_len:255|regex:^[a-zA-Z][a-zA-Z0-9_]+$", - "password": "required|min_len:8|max_len:255|regex:^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*(_|[^\\w])).+$", + "password": "required|min_len:8|max_len:255", }) if err != nil { controllers.Error(ctx, http.StatusBadRequest, err.Error()) return } if validator.Fails() { - controllers.Error(ctx, http.StatusBadRequest, validator.Errors().All()) + controllers.Error(ctx, http.StatusBadRequest, validator.Errors().One()) return } @@ -679,7 +756,7 @@ func (c *Mysql80Controller) DeleteUser(ctx http.Context) { return } if validator.Fails() { - controllers.Error(ctx, http.StatusBadRequest, validator.Errors().All()) + controllers.Error(ctx, http.StatusBadRequest, validator.Errors().One()) return } @@ -698,14 +775,14 @@ func (c *Mysql80Controller) SetUserPassword(ctx http.Context) { validator, err := ctx.Request().Validate(map[string]string{ "user": "required|min_len:1|max_len:255|regex:^[a-zA-Z][a-zA-Z0-9_]+$", - "password": "required|min_len:8|max_len:255|regex:^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*(_|[^\\w])).+$", + "password": "required|min_len:8|max_len:255", }) if err != nil { controllers.Error(ctx, http.StatusBadRequest, err.Error()) return } if validator.Fails() { - controllers.Error(ctx, http.StatusBadRequest, validator.Errors().All()) + controllers.Error(ctx, http.StatusBadRequest, validator.Errors().One()) return } @@ -733,7 +810,7 @@ func (c *Mysql80Controller) SetUserPrivileges(ctx http.Context) { return } if validator.Fails() { - controllers.Error(ctx, http.StatusBadRequest, validator.Errors().All()) + controllers.Error(ctx, http.StatusBadRequest, validator.Errors().One()) return } diff --git a/app/http/controllers/plugins/php74/php74_controller.go b/app/http/controllers/plugins/php74/php74_controller.go index c9aea7d551..8247718055 100644 --- a/app/http/controllers/plugins/php74/php74_controller.go +++ b/app/http/controllers/plugins/php74/php74_controller.go @@ -154,7 +154,7 @@ func (c *Php74Controller) Load(ctx http.Context) { } client := req.C().SetTimeout(10 * time.Second) - resp, err := client.R().Get("http://127.0.0.1/phpfpm_" + c.version + "_status") + resp, err := client.R().Get("http://127.0.0.1/phpfpm_status/" + c.version) if err != nil || !resp.IsSuccessState() { facades.Log().Error("获取PHP-" + c.version + "运行状态失败") controllers.Error(ctx, http.StatusInternalServerError, "[PHP-"+c.version+"] 获取运行状态失败") @@ -258,7 +258,7 @@ func (c *Php74Controller) InstallExtension(ctx http.Context) { var task models.Task task.Name = "安装PHP-" + c.version + "扩展-" + item.Name task.Status = models.TaskStatusWaiting - task.Shell = "bash /www/panel/scripts/php_extensions/" + item.Slug + ".sh install " + c.version + ">> /tmp/" + item.Slug + ".log 2>&1" + task.Shell = `bash '/www/panel/scripts/php_extensions/` + item.Slug + `.sh' install ` + c.version + ` >> /tmp/` + item.Slug + `.log 2>&1` task.Log = "/tmp/" + item.Slug + ".log" if err := facades.Orm().Query().Create(&task); err != nil { facades.Log().Error("[PHP-" + c.version + "] 创建安装拓展任务失败:" + err.Error()) @@ -298,7 +298,7 @@ func (c *Php74Controller) UninstallExtension(ctx http.Context) { var task models.Task task.Name = "卸载PHP-" + c.version + "扩展-" + item.Name task.Status = models.TaskStatusWaiting - task.Shell = "bash /www/panel/scripts/php_extensions/" + item.Slug + ".sh uninstall " + c.version + ">> /tmp/" + item.Slug + ".log 2>&1" + task.Shell = `bash '/www/panel/scripts/php_extensions/` + item.Slug + `.sh' uninstall ` + c.version + ` >> /tmp/` + item.Slug + `.log 2>&1` task.Log = "/tmp/" + item.Slug + ".log" if err := facades.Orm().Query().Create(&task); err != nil { facades.Log().Error("[PHP-" + c.version + "] 创建卸载拓展任务失败:" + err.Error()) @@ -361,7 +361,7 @@ func (c *Php74Controller) GetExtensions() []Extension { for _, item := range rawExtensionList { if !strings.Contains(item, "[") && item != "" { for i := range extensions { - if extensions[i].Name == item { + if extensions[i].Slug == item { extensions[i].Installed = true } } diff --git a/app/http/controllers/plugins/php80/php80_controller.go b/app/http/controllers/plugins/php80/php80_controller.go index eb270c8b38..72f969944a 100644 --- a/app/http/controllers/plugins/php80/php80_controller.go +++ b/app/http/controllers/plugins/php80/php80_controller.go @@ -154,7 +154,7 @@ func (c *Php80Controller) Load(ctx http.Context) { } client := req.C().SetTimeout(10 * time.Second) - resp, err := client.R().Get("http://127.0.0.1/phpfpm_" + c.version + "_status") + resp, err := client.R().Get("http://127.0.0.1/phpfpm_status/" + c.version) if err != nil || !resp.IsSuccessState() { facades.Log().Error("获取PHP-" + c.version + "运行状态失败") controllers.Error(ctx, http.StatusInternalServerError, "[PHP-"+c.version+"] 获取运行状态失败") @@ -258,7 +258,7 @@ func (c *Php80Controller) InstallExtension(ctx http.Context) { var task models.Task task.Name = "安装PHP-" + c.version + "扩展-" + item.Name task.Status = models.TaskStatusWaiting - task.Shell = "bash /www/panel/scripts/php_extensions/" + item.Slug + ".sh install " + c.version + ">> /tmp/" + item.Slug + ".log 2>&1" + task.Shell = `bash '/www/panel/scripts/php_extensions/` + item.Slug + `.sh' install ` + c.version + ` >> /tmp/` + item.Slug + `.log 2>&1` task.Log = "/tmp/" + item.Slug + ".log" if err := facades.Orm().Query().Create(&task); err != nil { facades.Log().Error("[PHP-" + c.version + "] 创建安装拓展任务失败:" + err.Error()) @@ -298,7 +298,7 @@ func (c *Php80Controller) UninstallExtension(ctx http.Context) { var task models.Task task.Name = "卸载PHP-" + c.version + "扩展-" + item.Name task.Status = models.TaskStatusWaiting - task.Shell = "bash /www/panel/scripts/php_extensions/" + item.Slug + ".sh uninstall " + c.version + ">> /tmp/" + item.Slug + ".log 2>&1" + task.Shell = `bash '/www/panel/scripts/php_extensions/` + item.Slug + `.sh' uninstall ` + c.version + ` >> /tmp/` + item.Slug + `.log 2>&1` task.Log = "/tmp/" + item.Slug + ".log" if err := facades.Orm().Query().Create(&task); err != nil { facades.Log().Error("[PHP-" + c.version + "] 创建卸载拓展任务失败:" + err.Error()) @@ -361,7 +361,7 @@ func (c *Php80Controller) GetExtensions() []Extension { for _, item := range rawExtensionList { if !strings.Contains(item, "[") && item != "" { for i := range extensions { - if extensions[i].Name == item { + if extensions[i].Slug == item { extensions[i].Installed = true } } diff --git a/app/http/controllers/website_controller.go b/app/http/controllers/website_controller.go index b1c808db68..8cf31dd1e2 100644 --- a/app/http/controllers/website_controller.go +++ b/app/http/controllers/website_controller.go @@ -64,7 +64,7 @@ func (c *WebsiteController) Add(ctx http.Context) { return } if validator.Fails() { - Error(ctx, http.StatusBadRequest, validator.Errors().All()) + Error(ctx, http.StatusBadRequest, validator.Errors().One()) return } @@ -372,9 +372,8 @@ func (c *WebsiteController) SaveConfig(ctx http.Context) { website.Php = ctx.Request().InputInt("php") phpConfigOld := tools.Cut(raw, "# php标记位开始", "# php标记位结束") phpConfig := ` - include enable-php` + strconv.Itoa(website.Php) + `.conf; - -` + include enable-php-` + strconv.Itoa(website.Php) + `.conf; + ` if len(strings.TrimSpace(phpConfigOld)) != 0 { raw = strings.Replace(raw, phpConfigOld, phpConfig, -1) } diff --git a/config/filesystems.go b/config/filesystems.go index 8e974dd22b..97d397ffff 100644 --- a/config/filesystems.go +++ b/config/filesystems.go @@ -24,7 +24,7 @@ func init() { "disks": map[string]any{ "local": map[string]any{ "driver": "local", - "root": "/", + "root": "storage/app", "url": "http://localhost/", }, }, diff --git a/config/panel.go b/config/panel.go index b355970d79..c19d48902e 100644 --- a/config/panel.go +++ b/config/panel.go @@ -8,6 +8,6 @@ func init() { config := facades.Config() config.Add("panel", map[string]any{ "name": "耗子面板", - "version": "v2.0.9", + "version": "v2.0.10", }) } diff --git a/go.mod b/go.mod index 8baa6ca7ee..185603075c 100644 --- a/go.mod +++ b/go.mod @@ -5,8 +5,8 @@ go 1.18 require ( github.com/gertd/go-pluralize v0.2.1 github.com/gin-contrib/static v0.0.1 - github.com/gookit/color v1.5.3 - github.com/goravel/framework v1.12.1-0.20230717105343-6ce864794883 + github.com/gookit/color v1.5.4 + github.com/goravel/framework v1.12.1-0.20230721095426-6f24ecdaf6a7 github.com/iancoleman/strcase v0.2.0 github.com/imroc/req/v3 v3.37.2 github.com/mojocn/base64Captcha v1.3.5 diff --git a/go.sum b/go.sum index 0edafc8512..1b8405259f 100644 --- a/go.sum +++ b/go.sum @@ -85,6 +85,7 @@ github.com/aws/aws-sdk-go v1.37.16 h1:Q4YOP2s00NpB9wfmTDZArdcLRuG9ijbnoAwTW3ivle github.com/aws/aws-sdk-go v1.37.16/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA= +github.com/brianvoe/gofakeit/v6 v6.23.0 h1:pgVhyWpYq4e0GEVCh2gdZnS/nBX+8SnyTBliHg5xjks= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= github.com/bytedance/sonic v1.9.2 h1:GDaNjuWSGu09guE9Oql0MSTNhNCLlWwO8y/xM5BzcbM= github.com/bytedance/sonic v1.9.2/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= @@ -169,8 +170,6 @@ github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= github.com/glebarez/go-sqlite v1.21.2 h1:3a6LFC4sKahUunAmynQKLZceZCOzUthkRkEAl9gAXWo= github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k= -github.com/glebarez/sqlite v1.8.0 h1:02X12E2I/4C1n+v90yTqrjRa8yuo7c3KeHI3FRznCvc= -github.com/glebarez/sqlite v1.8.0/go.mod h1:bpET16h1za2KOOMb8+jCp6UBP/iahDpfPQqSaYLTLx8= github.com/glebarez/sqlite v1.9.0 h1:Aj6bPA12ZEx5GbSF6XADmCkYXlljPNUY+Zf1EQxynXs= github.com/glebarez/sqlite v1.9.0/go.mod h1:YBYCoyupOao60lzp1MVBLEjZfgkq0tdB1voAQ09K9zw= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= @@ -345,8 +344,8 @@ github.com/googleapis/gax-go/v2 v2.8.0 h1:UBtEZqx1bjXtOQ5BVTkuYghXrr3N4V123VKJK6 github.com/googleapis/gax-go/v2 v2.8.0/go.mod h1:4orTrqY6hXxxaUL4LHIPl6lGo8vAE38/qKbhSAKP6QI= github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g= github.com/gookit/color v1.5.2/go.mod h1:w8h4bGiHeeBpvQVePTutdbERIUf3oJE5lZ8HM0UgXyg= -github.com/gookit/color v1.5.3 h1:twfIhZs4QLCtimkP7MOxlF3A0U/5cDPseRT9M/+2SCE= -github.com/gookit/color v1.5.3/go.mod h1:NUzwzeehUfl7GIb36pqId+UGmRfQcU/WiiyTTeNjHtE= +github.com/gookit/color v1.5.4 h1:FZmqs7XOyGgCAxmWyPslpiok1k05wmY3SJTytgvYFs0= +github.com/gookit/color v1.5.4/go.mod h1:pZJOeOS8DM43rXbp4AZo1n9zCU2qjpcRko0b6/QJi9w= github.com/gookit/filter v1.1.4 h1:SXd6PEumiP/0jtF2crQRaz1wmKwHbW9xg5Ds6/ZP16w= github.com/gookit/filter v1.1.4/go.mod h1:0CEPQvudso375RitQf9X8HerUg9cz8N7c/yn6b1RMzM= github.com/gookit/goutil v0.5.12/go.mod h1:6vhWm/bSYXGE8poqFbFz6IGM7jV2r6qVhyK567SX/AI= @@ -358,10 +357,8 @@ github.com/goravel/file-rotatelogs v0.0.0-20211215053220-2ab31dd9575c h1:obhFK91 github.com/goravel/file-rotatelogs v0.0.0-20211215053220-2ab31dd9575c/go.mod h1:YSWsLXlG16u5CWFaXNZHhEQD10+NwF3xfgDV816OwLE= github.com/goravel/file-rotatelogs/v2 v2.4.1 h1:ogkeIFcTHSBRUBpZYiyJbpul8hkVXxHPuDbOaP78O1M= github.com/goravel/file-rotatelogs/v2 v2.4.1/go.mod h1:euk9qr52WrzM8ICs1hecFcR4CZ/ZZOPdacHfvHgbOf0= -github.com/goravel/framework v1.12.1-0.20230710102458-737cce0f687c h1:KPggCIxAZghopvPXC0g0jCmFNbC+r5EawjHCcbfBOhQ= -github.com/goravel/framework v1.12.1-0.20230710102458-737cce0f687c/go.mod h1:SBsBTY8KTqSDipGPEZXnRRC1mWzKmL55Eo1P5aHNDgY= -github.com/goravel/framework v1.12.1-0.20230717105343-6ce864794883 h1:8+87CCYqt5O6GqAYmGWz/W6SXGKp6xyn+McMbtWgyug= -github.com/goravel/framework v1.12.1-0.20230717105343-6ce864794883/go.mod h1:quBqUHAyZutEs/TFfm9b/caI+BtyF82njGhNIL1QJM0= +github.com/goravel/framework v1.12.1-0.20230721095426-6f24ecdaf6a7 h1:2rkC/6M7tLx/Ya1TulO2GjtVRIGXTmpp0XppzZRloYA= +github.com/goravel/framework v1.12.1-0.20230721095426-6f24ecdaf6a7/go.mod h1:1lxwtCXMkotSmt0YWRg/s7EnMUFfmne9L1a50X9J0fA= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= diff --git a/pkg/tools/tools.go b/pkg/tools/tools.go index 4e77e5b157..7aba572ae8 100644 --- a/pkg/tools/tools.go +++ b/pkg/tools/tools.go @@ -10,14 +10,12 @@ import ( "time" "github.com/gookit/color" - "github.com/goravel/framework/facades" "github.com/shirou/gopsutil/cpu" "github.com/shirou/gopsutil/disk" "github.com/shirou/gopsutil/host" "github.com/shirou/gopsutil/load" "github.com/shirou/gopsutil/mem" "github.com/shirou/gopsutil/net" - "panel/app/models" ) // MonitoringInfo 监控信息 @@ -119,12 +117,6 @@ func GetLatestPanelVersion() (PanelInfo, error) { // UpdatePanel 更新面板 func UpdatePanel(proxy bool) error { - var task models.Task - err := facades.Orm().Query().Where("status", models.TaskStatusRunning).OrWhere("status", models.TaskStatusWaiting).FirstOrFail(&task) - if err == nil { - return errors.New("面板有任务正在执行,禁止更新") - } - panelInfo, err := GetLatestPanelVersion() if err != nil { return err diff --git a/public/panel/views/plugins/mysql57.html b/public/panel/views/plugins/mysql57.html new file mode 100644 index 0000000000..29d377d933 --- /dev/null +++ b/public/panel/views/plugins/mysql57.html @@ -0,0 +1,558 @@ + +
当前状态:获取中+
面板仅集成了部分常用功能,如需更多功能,建议安装 + phpMyAdmin 使用。 ++ +
此处修改的是MySQL主配置文件,如果你不了解各参数的含义,请不要随意修改!+ +
+ 提示:Ctrl+F 搜索关键字,Ctrl+S 保存,Ctrl+H 查找替换! +
+ 获取中... ++
+ 获取中... ++
当前状态:获取中+
面板仅集成了部分常用功能,如需更多功能,建议安装 + phpMyAdmin 使用。 ++ +
此处修改的是MySQL主配置文件,如果你不了解各参数的含义,请不要随意修改!+ +
+ 提示:Ctrl+F 搜索关键字,Ctrl+S 保存,Ctrl+H 查找替换! +
+ 获取中... ++
+ 获取中... ++
当前状态:获取中+
此处修改的是PHP主配置文件,如果你不了解各参数的含义,请不要随意修改!+ +
+ 提示:Ctrl+F 搜索关键字,Ctrl+S 保存,Ctrl+H 查找替换! +
+ 获取中... ++
+ 获取中... ++
当前状态:获取中+
此处修改的是PHP主配置文件,如果你不了解各参数的含义,请不要随意修改!+ +
+ 提示:Ctrl+F 搜索关键字,Ctrl+S 保存,Ctrl+H 查找替换! +
+ 获取中... ++
+ 获取中... ++