diff --git a/app/http/controllers/plugins/postgresql15/postgresql15_controller.go b/app/http/controllers/plugins/postgresql15/postgresql15_controller.go new file mode 100644 index 00000000..80be6779 --- /dev/null +++ b/app/http/controllers/plugins/postgresql15/postgresql15_controller.go @@ -0,0 +1,624 @@ +package postgresql15 + +import ( + "strings" + + "github.com/goravel/framework/contracts/http" + "github.com/goravel/framework/facades" + "github.com/goravel/framework/support/carbon" + + "panel/app/http/controllers" + "panel/app/models" + "panel/app/services" + "panel/pkg/tools" +) + +type Postgresql15Controller struct { + setting services.Setting + backup services.Backup +} + +type Info struct { + Name string `json:"name"` + Value string `json:"value"` +} + +func NewPostgresql15Controller() *Postgresql15Controller { + return &Postgresql15Controller{ + setting: services.NewSettingImpl(), + backup: services.NewBackupImpl(), + } +} + +// Status 获取运行状态 +func (c *Postgresql15Controller) Status(ctx http.Context) { + if !controllers.Check(ctx, "postgresql15") { + return + } + + status := tools.ExecShell("systemctl status postgresql | grep Active | grep -v grep | awk '{print $2}'") + if len(status) == 0 { + controllers.Error(ctx, http.StatusInternalServerError, "获取PostgreSQL状态失败") + return + } + + if status == "active" { + controllers.Success(ctx, true) + } else { + controllers.Success(ctx, false) + } +} + +// Reload 重载配置 +func (c *Postgresql15Controller) Reload(ctx http.Context) { + if !controllers.Check(ctx, "postgresql15") { + return + } + + tools.ExecShell("systemctl reload postgresql") + status := tools.ExecShell("systemctl status postgresql | grep Active | grep -v grep | awk '{print $2}'") + if len(status) == 0 { + controllers.Error(ctx, http.StatusInternalServerError, "获取PostgreSQL状态失败") + return + } + + if status == "active" { + controllers.Success(ctx, true) + } else { + controllers.Success(ctx, false) + } +} + +// Restart 重启服务 +func (c *Postgresql15Controller) Restart(ctx http.Context) { + if !controllers.Check(ctx, "postgresql15") { + return + } + + tools.ExecShell("systemctl restart postgresql") + status := tools.ExecShell("systemctl status postgresql | grep Active | grep -v grep | awk '{print $2}'") + if len(status) == 0 { + controllers.Error(ctx, http.StatusInternalServerError, "获取PostgreSQL状态失败") + return + } + + if status == "active" { + controllers.Success(ctx, true) + } else { + controllers.Success(ctx, false) + } +} + +// Start 启动服务 +func (c *Postgresql15Controller) Start(ctx http.Context) { + if !controllers.Check(ctx, "postgresql15") { + return + } + + tools.ExecShell("systemctl start postgresql") + status := tools.ExecShell("systemctl status postgresql | grep Active | grep -v grep | awk '{print $2}'") + if len(status) == 0 { + controllers.Error(ctx, http.StatusInternalServerError, "获取PostgreSQL状态失败") + return + } + + if status == "active" { + controllers.Success(ctx, true) + } else { + controllers.Success(ctx, false) + } +} + +// Stop 停止服务 +func (c *Postgresql15Controller) Stop(ctx http.Context) { + if !controllers.Check(ctx, "postgresql15") { + return + } + + tools.ExecShell("systemctl stop postgresql") + status := tools.ExecShell("systemctl status postgresql | grep Active | grep -v grep | awk '{print $2}'") + if len(status) == 0 { + controllers.Error(ctx, http.StatusInternalServerError, "获取PostgreSQL状态失败") + return + } + + if status != "active" { + controllers.Success(ctx, true) + } else { + controllers.Success(ctx, false) + } +} + +// GetConfig 获取配置 +func (c *Postgresql15Controller) GetConfig(ctx http.Context) { + if !controllers.Check(ctx, "postgresql15") { + return + } + + // 获取配置 + config := tools.ReadFile("/www/server/postgresql/data/postgresql.conf") + if len(config) == 0 { + controllers.Error(ctx, http.StatusInternalServerError, "获取PostgreSQL配置失败") + return + } + + controllers.Success(ctx, config) +} + +// GetUserConfig 获取用户配置 +func (c *Postgresql15Controller) GetUserConfig(ctx http.Context) { + if !controllers.Check(ctx, "postgresql15") { + return + } + + // 获取配置 + config := tools.ReadFile("/www/server/postgresql/data/pg_hba.conf") + if len(config) == 0 { + controllers.Error(ctx, http.StatusInternalServerError, "获取PostgreSQL配置失败") + return + } + + controllers.Success(ctx, config) +} + +// SaveConfig 保存配置 +func (c *Postgresql15Controller) SaveConfig(ctx http.Context) { + if !controllers.Check(ctx, "postgresql15") { + return + } + + config := ctx.Request().Input("config") + if len(config) == 0 { + controllers.Error(ctx, http.StatusBadRequest, "配置不能为空") + return + } + + if !tools.WriteFile("/www/server/postgresql/data/postgresql.conf", config, 0644) { + controllers.Error(ctx, http.StatusInternalServerError, "写入PostgreSQL配置失败") + return + } + + c.Restart(ctx) +} + +// SaveUserConfig 保存用户配置 +func (c *Postgresql15Controller) SaveUserConfig(ctx http.Context) { + if !controllers.Check(ctx, "postgresql15") { + return + } + + config := ctx.Request().Input("config") + if len(config) == 0 { + controllers.Error(ctx, http.StatusBadRequest, "配置不能为空") + return + } + + if !tools.WriteFile("/www/server/postgresql/data/pg_hba.conf", config, 0644) { + controllers.Error(ctx, http.StatusInternalServerError, "写入PostgreSQL配置失败") + return + } + + c.Restart(ctx) +} + +// Load 获取负载 +func (c *Postgresql15Controller) Load(ctx http.Context) { + if !controllers.Check(ctx, "postgresql15") { + return + } + + status := tools.ExecShell("systemctl status postgresql | grep Active | grep -v grep | awk '{print $2}'") + if status != "active" { + controllers.Error(ctx, http.StatusInternalServerError, "PostgreSQL 已停止运行") + return + } + + data := []Info{ + {"启动时间", carbon.Parse(tools.ExecShell(`echo "select pg_postmaster_start_time();" | su - postgres -c "psql" | sed -n 3p | cut -d'.' -f1`)).ToDateTimeString()}, + {"进程 PID", tools.ExecShell(`echo "select pg_backend_pid();" | su - postgres -c "psql" | sed -n 3p`)}, + {"进程数", tools.ExecShell(`ps aux | grep postgres | grep -v grep | wc -l`)}, + {"总连接数", tools.ExecShell(`echo "SELECT count(*) FROM pg_stat_activity WHERE NOT pid=pg_backend_pid();" | su - postgres -c "psql" | sed -n 3p`)}, + {"空间占用", tools.ExecShell(`echo "select pg_size_pretty(pg_database_size('postgres'));" | su - postgres -c "psql" | sed -n 3p`)}, + } + + controllers.Success(ctx, data) +} + +// Log 获取日志 +func (c *Postgresql15Controller) Log(ctx http.Context) { + if !controllers.Check(ctx, "postgresql15") { + return + } + + log := tools.ExecShell("tail -n 100 /www/server/postgresql/logs/postgresql-" + carbon.Now().ToDateString() + ".log") + controllers.Success(ctx, log) +} + +// ClearLog 清空日志 +func (c *Postgresql15Controller) ClearLog(ctx http.Context) { + if !controllers.Check(ctx, "postgresql15") { + return + } + + tools.ExecShell("echo '' > /www/server/postgresql/logs/postgresql-" + carbon.Now().ToDateString() + ".log") + controllers.Success(ctx, nil) +} + +// DatabaseList 获取数据库列表 +func (c *Postgresql15Controller) DatabaseList(ctx http.Context) { + if !controllers.Check(ctx, "postgresql15") { + return + } + + status := tools.ExecShell("systemctl status postgresql | grep Active | grep -v grep | awk '{print $2}'") + if status != "active" { + controllers.Error(ctx, http.StatusInternalServerError, "PostgreSQL 已停止运行") + return + } + + raw := tools.ExecShell(`echo "\l" | su - postgres -c "psql"`) + databases := strings.Split(raw, "\n") + databases = databases[3 : len(databases)-1] + + type database struct { + Name string `json:"name"` + Owner string `json:"owner"` + Encoding string `json:"encoding"` + } + + var databaseList []database + for _, db := range databases { + parts := strings.Split(db, "|") + if len(parts) != 8 || len(strings.TrimSpace(parts[0])) == 0 { + continue + } + + databaseList = append(databaseList, database{ + Name: strings.TrimSpace(parts[0]), + Owner: strings.TrimSpace(parts[1]), + Encoding: strings.TrimSpace(parts[2]), + }) + } + + page := ctx.Request().QueryInt("page", 1) + limit := ctx.Request().QueryInt("limit", 10) + startIndex := (page - 1) * limit + endIndex := page * limit + if startIndex > len(databaseList) { + controllers.Success(ctx, http.Json{ + "total": 0, + "items": []database{}, + }) + return + } + if endIndex > len(databaseList) { + endIndex = len(databaseList) + } + pagedDatabases := databaseList[startIndex:endIndex] + + controllers.Success(ctx, http.Json{ + "total": len(databaseList), + "items": pagedDatabases, + }) +} + +// AddDatabase 添加数据库 +func (c *Postgresql15Controller) AddDatabase(ctx http.Context) { + if !controllers.Check(ctx, "postgresql15") { + return + } + + 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", + }) + if err != nil { + controllers.Error(ctx, http.StatusBadRequest, err.Error()) + return + } + if validator.Fails() { + controllers.Error(ctx, http.StatusBadRequest, validator.Errors().One()) + return + } + + database := ctx.Request().Input("database") + user := ctx.Request().Input("user") + password := ctx.Request().Input("password") + + tools.ExecShell(`echo "CREATE DATABASE ` + database + `;" | su - postgres -c "psql"`) + tools.ExecShell(`echo "CREATE USER ` + user + ` WITH PASSWORD '` + password + `';" | su - postgres -c "psql"`) + tools.ExecShell(`echo "GRANT ALL PRIVILEGES ON DATABASE ` + database + ` TO ` + user + `;" | su - postgres -c "psql"`) + + userConfig := "host " + database + " " + user + " 127.0.0.1/32 scram-sha-256" + tools.ExecShell(`echo "` + userConfig + `" >> /www/server/postgresql/data/pg_hba.conf`) + + c.Reload(ctx) +} + +// DeleteDatabase 删除数据库 +func (c *Postgresql15Controller) DeleteDatabase(ctx http.Context) { + if !controllers.Check(ctx, "postgresql15") { + return + } + + validator, err := ctx.Request().Validate(map[string]string{ + "database": "required|min_len:1|max_len:255|regex:^[a-zA-Z][a-zA-Z0-9_]+$|not_in:postgres,template0,template1", + }) + if err != nil { + controllers.Error(ctx, http.StatusBadRequest, err.Error()) + return + } + if validator.Fails() { + controllers.Error(ctx, http.StatusBadRequest, validator.Errors().One()) + return + } + + database := ctx.Request().Input("database") + tools.ExecShell(`echo "DROP DATABASE ` + database + `;" | su - postgres -c "psql"`) + + controllers.Success(ctx, nil) +} + +// BackupList 获取备份列表 +func (c *Postgresql15Controller) BackupList(ctx http.Context) { + if !controllers.Check(ctx, "postgresql15") { + return + } + + backupList, err := c.backup.PostgresqlList() + if err != nil { + facades.Log().Error("[PostgreSQL] 获取备份列表失败:" + err.Error()) + controllers.Error(ctx, http.StatusInternalServerError, "获取备份列表失败") + return + } + + controllers.Success(ctx, backupList) +} + +// UploadBackup 上传备份 +func (c *Postgresql15Controller) UploadBackup(ctx http.Context) { + if !controllers.Check(ctx, "postgresql15") { + return + } + + file, err := ctx.Request().File("file") + if err != nil { + controllers.Error(ctx, http.StatusBadRequest, "上传文件失败") + return + } + + backupPath := c.setting.Get(models.SettingKeyBackupPath) + "/postgresql" + if !tools.Exists(backupPath) { + tools.Mkdir(backupPath, 0644) + } + + name := file.GetClientOriginalName() + _, err = file.StoreAs(backupPath, name) + if err != nil { + controllers.Error(ctx, http.StatusBadRequest, "上传文件失败") + return + } + + controllers.Success(ctx, nil) +} + +// CreateBackup 创建备份 +func (c *Postgresql15Controller) CreateBackup(ctx http.Context) { + if !controllers.Check(ctx, "postgresql15") { + return + } + + validator, err := ctx.Request().Validate(map[string]string{ + "database": "required|min_len:1|max_len:255|regex:^[a-zA-Z][a-zA-Z0-9_]+$|not_in:information_schema,mysql,performance_schema,sys", + }) + if err != nil { + controllers.Error(ctx, http.StatusBadRequest, err.Error()) + return + } + if validator.Fails() { + controllers.Error(ctx, http.StatusBadRequest, validator.Errors().One()) + return + } + + database := ctx.Request().Input("database") + err = c.backup.PostgresqlBackup(database) + if err != nil { + facades.Log().Error("[PostgreSQL] 创建备份失败:" + err.Error()) + controllers.Error(ctx, http.StatusInternalServerError, "创建备份失败") + return + } + + controllers.Success(ctx, nil) +} + +// DeleteBackup 删除备份 +func (c *Postgresql15Controller) DeleteBackup(ctx http.Context) { + if !controllers.Check(ctx, "postgresql15") { + return + } + + validator, err := ctx.Request().Validate(map[string]string{ + "name": "required|min_len:1|max_len:255", + }) + if err != nil { + controllers.Error(ctx, http.StatusBadRequest, err.Error()) + return + } + if validator.Fails() { + controllers.Error(ctx, http.StatusBadRequest, validator.Errors().One()) + return + } + + backupPath := c.setting.Get(models.SettingKeyBackupPath) + "/postgresql" + fileName := ctx.Request().Input("name") + tools.RemoveFile(backupPath + "/" + fileName) + + controllers.Success(ctx, nil) +} + +// RestoreBackup 还原备份 +func (c *Postgresql15Controller) RestoreBackup(ctx http.Context) { + if !controllers.Check(ctx, "postgresql15") { + return + } + + validator, err := ctx.Request().Validate(map[string]string{ + "name": "required|min_len:1|max_len:255", + "database": "required|min_len:1|max_len:255|regex:^[a-zA-Z][a-zA-Z0-9_]+$|not_in:information_schema,mysql,performance_schema,sys", + }) + if err != nil { + controllers.Error(ctx, http.StatusBadRequest, err.Error()) + return + } + if validator.Fails() { + controllers.Error(ctx, http.StatusBadRequest, validator.Errors().One()) + return + } + + err = c.backup.PostgresqlRestore(ctx.Request().Input("database"), ctx.Request().Input("name")) + if err != nil { + facades.Log().Error("[PostgreSQL] 还原失败:" + err.Error()) + controllers.Error(ctx, http.StatusInternalServerError, "还原失败: "+err.Error()) + return + } + + controllers.Success(ctx, nil) +} + +// UserList 用户列表 +func (c *Postgresql15Controller) UserList(ctx http.Context) { + if !controllers.Check(ctx, "postgresql15") { + return + } + + type user struct { + User string `json:"user"` + Role string `json:"role"` + } + + raw := tools.ExecShell(`echo "\du" | su - postgres -c "psql"`) + users := strings.Split(raw, "\n") + if len(users) < 4 { + controllers.Error(ctx, http.StatusInternalServerError, "用户列表为空") + return + } + users = users[3:] + + var userList []user + for _, u := range users { + userInfo := strings.Split(u, "|") + if len(userInfo) != 3 { + continue + } + + userList = append(userList, user{ + User: strings.TrimSpace(userInfo[0]), + Role: strings.TrimSpace(userInfo[1]), + }) + } + + page := ctx.Request().QueryInt("page", 1) + limit := ctx.Request().QueryInt("limit", 10) + startIndex := (page - 1) * limit + endIndex := page * limit + if startIndex > len(userList) { + controllers.Success(ctx, http.Json{ + "total": 0, + "items": []user{}, + }) + return + } + if endIndex > len(userList) { + endIndex = len(userList) + } + pagedUsers := userList[startIndex:endIndex] + + controllers.Success(ctx, http.Json{ + "total": len(userList), + "items": pagedUsers, + }) +} + +// AddUser 添加用户 +func (c *Postgresql15Controller) AddUser(ctx http.Context) { + if !controllers.Check(ctx, "postgresql15") { + return + } + + 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", + }) + if err != nil { + controllers.Error(ctx, http.StatusBadRequest, err.Error()) + return + } + if validator.Fails() { + controllers.Error(ctx, http.StatusBadRequest, validator.Errors().One()) + return + } + + user := ctx.Request().Input("user") + password := ctx.Request().Input("password") + database := ctx.Request().Input("database") + tools.ExecShell(`echo "CREATE USER ` + user + ` WITH PASSWORD '` + password + `';" | su - postgres -c "psql"`) + tools.ExecShell(`echo "GRANT ALL PRIVILEGES ON DATABASE ` + database + ` TO ` + user + `;" | su - postgres -c "psql"`) + + userConfig := "host " + database + " " + user + " 127.0.0.1/32 scram-sha-256" + tools.ExecShell(`echo "` + userConfig + `" >> /www/server/postgresql/data/pg_hba.conf`) + + c.Reload(ctx) +} + +// DeleteUser 删除用户 +func (c *Postgresql15Controller) DeleteUser(ctx http.Context) { + if !controllers.Check(ctx, "postgresql15") { + return + } + + validator, err := ctx.Request().Validate(map[string]string{ + "user": "required|min_len:1|max_len:255|regex:^[a-zA-Z][a-zA-Z0-9_]+$", + }) + if err != nil { + controllers.Error(ctx, http.StatusBadRequest, err.Error()) + return + } + if validator.Fails() { + controllers.Error(ctx, http.StatusBadRequest, validator.Errors().One()) + return + } + + user := ctx.Request().Input("user") + tools.ExecShell(`echo "DROP USER ` + user + `;" | su - postgres -c "psql"`) + tools.ExecShell(`sed -i '/` + user + `/d' /www/server/postgresql/data/pg_hba.conf`) + + c.Reload(ctx) +} + +// SetUserPassword 设置用户密码 +func (c *Postgresql15Controller) SetUserPassword(ctx http.Context) { + if !controllers.Check(ctx, "postgresql15") { + return + } + + 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", + }) + if err != nil { + controllers.Error(ctx, http.StatusBadRequest, err.Error()) + return + } + if validator.Fails() { + controllers.Error(ctx, http.StatusBadRequest, validator.Errors().One()) + return + } + + user := ctx.Request().Input("user") + password := ctx.Request().Input("password") + tools.ExecShell(`echo "ALTER USER ` + user + ` WITH PASSWORD '` + password + `';" | su - postgres -c "psql"`) + + controllers.Success(ctx, nil) +} diff --git a/app/plugins/postgresql15/postgresql15.go b/app/plugins/postgresql15/postgresql15.go new file mode 100644 index 00000000..3e4fe271 --- /dev/null +++ b/app/plugins/postgresql15/postgresql15.go @@ -0,0 +1,13 @@ +package postgresql15 + +var ( + Name = "PostgreSQL-15" + Description = "PostgreSQL 是开源的对象 - 关系数据库数据库管理系统,在类似 BSD 许可与 MIT 许可的 PostgreSQL 许可下发行。" + Slug = "postgresql15" + Version = "15.3" + Requires = []string{} + Excludes = []string{} + Install = `bash /www/panel/scripts/postgresql/install.sh 15` + Uninstall = `bash /www/panel/scripts/postgresql/uninstall.sh 15` + Update = `bash /www/panel/scripts/postgresql/update.sh 15` +) diff --git a/app/services/backup.go b/app/services/backup.go index 96537bb5..05936fc1 100644 --- a/app/services/backup.go +++ b/app/services/backup.go @@ -20,6 +20,9 @@ type Backup interface { MysqlList() ([]BackupFile, error) MysqlBackup(database string) error MysqlRestore(database string, backupFile string) error + PostgresqlList() ([]BackupFile, error) + PostgresqlBackup(database string) error + PostgresqlRestore(database string, backupFile string) error } type BackupFile struct { @@ -212,3 +215,92 @@ func (s *BackupImpl) MysqlRestore(database string, backupFile string) error { return nil } + +// PostgresqlList PostgreSQL备份列表 +func (s *BackupImpl) PostgresqlList() ([]BackupFile, error) { + backupPath := s.setting.Get(models.SettingKeyBackupPath) + if len(backupPath) == 0 { + return []BackupFile{}, nil + } + + backupPath += "/postgresql" + if !tools.Exists(backupPath) { + tools.Mkdir(backupPath, 0644) + } + + files, err := os.ReadDir(backupPath) + if err != nil { + return []BackupFile{}, err + } + var backupList []BackupFile + for _, file := range files { + info, err := file.Info() + if err != nil { + continue + } + backupList = append(backupList, BackupFile{ + Name: file.Name(), + Size: tools.FormatBytes(float64(info.Size())), + }) + } + + return backupList, nil +} + +// PostgresqlBackup PostgreSQL备份 +func (s *BackupImpl) PostgresqlBackup(database string) error { + backupPath := s.setting.Get(models.SettingKeyBackupPath) + "/postgresql" + backupFile := database + "_" + carbon.Now().ToShortDateTimeString() + ".sql" + if !tools.Exists(backupPath) { + tools.Mkdir(backupPath, 0644) + } + + tools.ExecShell(`su - postgres -c "pg_dump ` + database + `" > ` + backupPath + "/" + backupFile) + tools.ExecShell("cd " + backupPath + " && zip -r " + backupPath + "/" + backupFile + ".zip " + backupFile) + tools.RemoveFile(backupPath + "/" + backupFile) + + return nil +} + +// PostgresqlRestore PostgreSQL恢复 +func (s *BackupImpl) PostgresqlRestore(database string, backupFile string) error { + backupPath := s.setting.Get(models.SettingKeyBackupPath) + "/postgresql" + ext := filepath.Ext(backupFile) + backupFile = backupPath + "/" + backupFile + if !tools.Exists(backupFile) { + return errors.New("备份文件不存在") + } + + switch ext { + case ".zip": + tools.ExecShell("unzip -o " + backupFile + " -d " + backupPath) + backupFile = strings.TrimSuffix(backupFile, ext) + case ".gz": + if strings.HasSuffix(backupFile, ".tar.gz") { + // 解压.tar.gz文件 + tools.ExecShell("tar -zxvf " + backupFile + " -C " + backupPath) + backupFile = strings.TrimSuffix(backupFile, ".tar.gz") + } else { + // 解压.gz文件 + tools.ExecShell("gzip -d " + backupFile) + backupFile = strings.TrimSuffix(backupFile, ext) + } + case ".bz2": + tools.ExecShell("bzip2 -d " + backupFile) + backupFile = strings.TrimSuffix(backupFile, ext) + case ".tar": + tools.ExecShell("tar -xvf " + backupFile + " -C " + backupPath) + backupFile = strings.TrimSuffix(backupFile, ext) + case ".rar": + tools.ExecShell("unrar x " + backupFile + " " + backupPath) + backupFile = strings.TrimSuffix(backupFile, ext) + } + + if !tools.Exists(backupFile) { + return errors.New("自动解压失败,请手动解压") + } + + tools.ExecShell(`su - postgres -c "psql ` + database + `" < ` + backupFile) + + return nil +} diff --git a/app/services/plugin.go b/app/services/plugin.go index 9d8d38c7..9ecca2da 100644 --- a/app/services/plugin.go +++ b/app/services/plugin.go @@ -14,6 +14,7 @@ import ( "panel/app/plugins/php81" "panel/app/plugins/php82" "panel/app/plugins/phpmyadmin" + "panel/app/plugins/postgresql15" "panel/app/plugins/pureftpd" "panel/app/plugins/redis" "panel/app/plugins/s3fs" @@ -94,6 +95,17 @@ func (r *PluginImpl) All() []PanelPlugin { Uninstall: mysql80.Uninstall, Update: mysql80.Update, }) + p = append(p, PanelPlugin{ + Name: postgresql15.Name, + Description: postgresql15.Description, + Slug: postgresql15.Slug, + Version: postgresql15.Version, + Requires: postgresql15.Requires, + Excludes: postgresql15.Excludes, + Install: postgresql15.Install, + Uninstall: postgresql15.Uninstall, + Update: postgresql15.Update, + }) p = append(p, PanelPlugin{ Name: php74.Name, Description: php74.Description, diff --git a/public/panel/adminui/src/modules/view.js b/public/panel/adminui/src/modules/view.js index def1b26c..5df974b5 100644 --- a/public/panel/adminui/src/modules/view.js +++ b/public/panel/adminui/src/modules/view.js @@ -37,7 +37,7 @@ layui.define(['laytpl', 'layer'], function (exports) { }) //跳转到登入页 - location.hash = '/user/login' + location.hash = '/login' } //Ajax请求 diff --git a/public/panel/views/plugins/postgresql15.html b/public/panel/views/plugins/postgresql15.html new file mode 100644 index 00000000..abcc5c4f --- /dev/null +++ b/public/panel/views/plugins/postgresql15.html @@ -0,0 +1,524 @@ + +
+ 当前状态:获取中+
面板仅集成了部分常用功能,如需更多功能,请使用 + pgAdmin 客户端。 ++ +
此处修改的是PostgreSQL主配置文件,如果你不了解各参数的含义,请不要随意修改!+ +
+ 提示:Ctrl+F 搜索关键字,Ctrl+S 保存,Ctrl+H 查找替换! +
此处修改的是PostgreSQL用户配置文件,如果你不了解各参数的含义,请不要随意修改!+ +
+ 提示:Ctrl+F 搜索关键字,Ctrl+S 保存,Ctrl+H 查找替换! +
+ 获取中... ++