mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-12-19 05:49:02 +08:00
feat: PHP 网站增加版本切换 (#1748)
Refs https://github.com/1Panel-dev/1Panel/issues/1586 Refs https://github.com/1Panel-dev/1Panel/issues/1406 Refs https://github.com/1Panel-dev/1Panel/issues/974 Refs https://github.com/1Panel-dev/1Panel/issues/671
This commit is contained in:
parent
da4c264908
commit
3b9f92e03f
18 changed files with 473 additions and 12 deletions
|
|
@ -561,6 +561,28 @@ func (b *BaseApi) UpdatePHPFile(c *gin.Context) {
|
||||||
helper.SuccessWithData(c, nil)
|
helper.SuccessWithData(c, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// @Tags Website PHP
|
||||||
|
// @Summary Update php version
|
||||||
|
// @Description 变更 php 版本
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body request.WebsitePHPVersionReq true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /websites/php/version [post]
|
||||||
|
// @x-panel-log {"bodyKeys":["websiteId"],"paramKeys":[],"BeforeFuntions":[{"input_column":"id","input_value":"websiteId","isList":false,"db":"websites","output_column":"primary_domain","output_value":"domain"}],"formatZH":"php 版本变更 [domain]","formatEN":"php version update [domain]"}
|
||||||
|
func (b *BaseApi) ChangePHPVersion(c *gin.Context) {
|
||||||
|
var req request.WebsitePHPVersionReq
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := websiteService.ChangePHPVersion(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithOutData(c)
|
||||||
|
}
|
||||||
|
|
||||||
// @Tags Website
|
// @Tags Website
|
||||||
// @Summary Get rewrite conf
|
// @Summary Get rewrite conf
|
||||||
// @Description 获取伪静态配置
|
// @Description 获取伪静态配置
|
||||||
|
|
|
||||||
|
|
@ -158,6 +158,12 @@ type WebsitePHPFileUpdate struct {
|
||||||
Content string `json:"content" validate:"required"`
|
Content string `json:"content" validate:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type WebsitePHPVersionReq struct {
|
||||||
|
WebsiteID uint `json:"websiteID" validate:"required"`
|
||||||
|
RuntimeID uint `json:"runtimeID" validate:"required"`
|
||||||
|
RetainConfig bool `json:"retainConfig" validate:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
type WebsiteUpdateDir struct {
|
type WebsiteUpdateDir struct {
|
||||||
ID uint `json:"id" validate:"required"`
|
ID uint `json:"id" validate:"required"`
|
||||||
SiteDir string `json:"siteDir" validate:"required"`
|
SiteDir string `json:"siteDir" validate:"required"`
|
||||||
|
|
|
||||||
|
|
@ -126,7 +126,7 @@ func (a *AppInstallRepo) Create(ctx context.Context, install *model.AppInstall)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AppInstallRepo) Save(ctx context.Context, install *model.AppInstall) error {
|
func (a *AppInstallRepo) Save(ctx context.Context, install *model.AppInstall) error {
|
||||||
return getTx(ctx).Omit(clause.Associations).Save(&install).Error
|
return getTx(ctx).Save(&install).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *AppInstallRepo) DeleteBy(opts ...DBOption) error {
|
func (a *AppInstallRepo) DeleteBy(opts ...DBOption) error {
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,12 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
|
"encoding/json"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/utils/compose"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/utils/env"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
@ -54,20 +57,25 @@ type IWebsiteService interface {
|
||||||
CreateWebsiteDomain(create request.WebsiteDomainCreate) (model.WebsiteDomain, error)
|
CreateWebsiteDomain(create request.WebsiteDomainCreate) (model.WebsiteDomain, error)
|
||||||
GetWebsiteDomain(websiteId uint) ([]model.WebsiteDomain, error)
|
GetWebsiteDomain(websiteId uint) ([]model.WebsiteDomain, error)
|
||||||
DeleteWebsiteDomain(domainId uint) error
|
DeleteWebsiteDomain(domainId uint) error
|
||||||
|
|
||||||
GetNginxConfigByScope(req request.NginxScopeReq) (*response.WebsiteNginxConfig, error)
|
GetNginxConfigByScope(req request.NginxScopeReq) (*response.WebsiteNginxConfig, error)
|
||||||
UpdateNginxConfigByScope(req request.NginxConfigUpdate) error
|
UpdateNginxConfigByScope(req request.NginxConfigUpdate) error
|
||||||
GetWebsiteNginxConfig(websiteId uint, configType string) (response.FileInfo, error)
|
GetWebsiteNginxConfig(websiteId uint, configType string) (response.FileInfo, error)
|
||||||
|
UpdateNginxConfigFile(req request.WebsiteNginxUpdate) error
|
||||||
GetWebsiteHTTPS(websiteId uint) (response.WebsiteHTTPS, error)
|
GetWebsiteHTTPS(websiteId uint) (response.WebsiteHTTPS, error)
|
||||||
OpWebsiteHTTPS(ctx context.Context, req request.WebsiteHTTPSOp) (*response.WebsiteHTTPS, error)
|
OpWebsiteHTTPS(ctx context.Context, req request.WebsiteHTTPSOp) (*response.WebsiteHTTPS, error)
|
||||||
PreInstallCheck(req request.WebsiteInstallCheckReq) ([]response.WebsitePreInstallCheck, error)
|
|
||||||
GetWafConfig(req request.WebsiteWafReq) (response.WebsiteWafConfig, error)
|
|
||||||
UpdateWafConfig(req request.WebsiteWafUpdate) error
|
|
||||||
UpdateNginxConfigFile(req request.WebsiteNginxUpdate) error
|
|
||||||
OpWebsiteLog(req request.WebsiteLogReq) (*response.WebsiteLog, error)
|
OpWebsiteLog(req request.WebsiteLogReq) (*response.WebsiteLog, error)
|
||||||
ChangeDefaultServer(id uint) error
|
ChangeDefaultServer(id uint) error
|
||||||
|
PreInstallCheck(req request.WebsiteInstallCheckReq) ([]response.WebsitePreInstallCheck, error)
|
||||||
|
|
||||||
|
GetWafConfig(req request.WebsiteWafReq) (response.WebsiteWafConfig, error)
|
||||||
|
UpdateWafConfig(req request.WebsiteWafUpdate) error
|
||||||
|
|
||||||
GetPHPConfig(id uint) (*response.PHPConfig, error)
|
GetPHPConfig(id uint) (*response.PHPConfig, error)
|
||||||
UpdatePHPConfig(req request.WebsitePHPConfigUpdate) error
|
UpdatePHPConfig(req request.WebsitePHPConfigUpdate) error
|
||||||
UpdatePHPConfigFile(req request.WebsitePHPFileUpdate) error
|
UpdatePHPConfigFile(req request.WebsitePHPFileUpdate) error
|
||||||
|
ChangePHPVersion(req request.WebsitePHPVersionReq) error
|
||||||
|
|
||||||
GetRewriteConfig(req request.NginxRewriteReq) (*response.NginxRewriteRes, error)
|
GetRewriteConfig(req request.NginxRewriteReq) (*response.NginxRewriteRes, error)
|
||||||
UpdateRewriteConfig(req request.NginxRewriteUpdate) error
|
UpdateRewriteConfig(req request.NginxRewriteUpdate) error
|
||||||
UpdateSiteDir(req request.WebsiteUpdateDir) error
|
UpdateSiteDir(req request.WebsiteUpdateDir) error
|
||||||
|
|
@ -1036,7 +1044,7 @@ func (w WebsiteService) GetPHPConfig(id uint) (*response.PHPConfig, error) {
|
||||||
phpConfigPath := path.Join(appInstall.GetPath(), "conf", "php.ini")
|
phpConfigPath := path.Join(appInstall.GetPath(), "conf", "php.ini")
|
||||||
fileOp := files.NewFileOp()
|
fileOp := files.NewFileOp()
|
||||||
if !fileOp.Stat(phpConfigPath) {
|
if !fileOp.Stat(phpConfigPath) {
|
||||||
return nil, buserr.WithDetail(constant.ErrFileCanNotRead, "php.ini", nil)
|
return nil, buserr.WithMap("ErrFileNotFound", map[string]interface{}{"name": "php.ini"}, nil)
|
||||||
}
|
}
|
||||||
params := make(map[string]string)
|
params := make(map[string]string)
|
||||||
configFile, err := fileOp.OpenFile(phpConfigPath)
|
configFile, err := fileOp.OpenFile(phpConfigPath)
|
||||||
|
|
@ -1090,7 +1098,7 @@ func (w WebsiteService) UpdatePHPConfig(req request.WebsitePHPConfigUpdate) (err
|
||||||
phpConfigPath := path.Join(appInstall.GetPath(), "conf", "php.ini")
|
phpConfigPath := path.Join(appInstall.GetPath(), "conf", "php.ini")
|
||||||
fileOp := files.NewFileOp()
|
fileOp := files.NewFileOp()
|
||||||
if !fileOp.Stat(phpConfigPath) {
|
if !fileOp.Stat(phpConfigPath) {
|
||||||
return buserr.WithDetail(constant.ErrFileCanNotRead, "php.ini", nil)
|
return buserr.WithMap("ErrFileNotFound", map[string]interface{}{"name": "php.ini"}, nil)
|
||||||
}
|
}
|
||||||
configFile, err := fileOp.OpenFile(phpConfigPath)
|
configFile, err := fileOp.OpenFile(phpConfigPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -1182,6 +1190,108 @@ func (w WebsiteService) UpdatePHPConfigFile(req request.WebsitePHPFileUpdate) er
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (w WebsiteService) ChangePHPVersion(req request.WebsitePHPVersionReq) error {
|
||||||
|
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.WebsiteID))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
runtime, err := runtimeRepo.GetFirst(commonRepo.WithByID(req.RuntimeID))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
oldRuntime, err := runtimeRepo.GetFirst(commonRepo.WithByID(req.RuntimeID))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if runtime.Resource == constant.ResourceLocal || oldRuntime.Resource == constant.ResourceLocal {
|
||||||
|
return buserr.New("ErrPHPResource")
|
||||||
|
}
|
||||||
|
appInstall, err := appInstallRepo.GetFirst(commonRepo.WithByID(website.AppInstallID))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
appDetail, err := appDetailRepo.GetFirst(commonRepo.WithByID(runtime.AppDetailID))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
envs := make(map[string]interface{})
|
||||||
|
if err = json.Unmarshal([]byte(appInstall.Env), &envs); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if out, err := compose.Down(appInstall.GetComposePath()); err != nil {
|
||||||
|
if out != "" {
|
||||||
|
return errors.New(out)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
busErr error
|
||||||
|
fileOp = files.NewFileOp()
|
||||||
|
envPath = appInstall.GetEnvPath()
|
||||||
|
composePath = appInstall.GetComposePath()
|
||||||
|
confDir = path.Join(appInstall.GetPath(), "conf")
|
||||||
|
backupConfDir = path.Join(appInstall.GetPath(), "conf_bak")
|
||||||
|
fpmConfDir = path.Join(confDir, "php-fpm.conf")
|
||||||
|
phpDir = path.Join(constant.RuntimeDir, runtime.Type, runtime.Name, "php")
|
||||||
|
oldFmContent, _ = fileOp.GetContent(fpmConfDir)
|
||||||
|
)
|
||||||
|
envParams := make(map[string]string, len(envs))
|
||||||
|
handleMap(envs, envParams)
|
||||||
|
envParams["IMAGE_NAME"] = runtime.Image
|
||||||
|
defer func() {
|
||||||
|
if busErr != nil {
|
||||||
|
envParams["IMAGE_NAME"] = oldRuntime.Image
|
||||||
|
_ = env.Write(envParams, envPath)
|
||||||
|
_ = fileOp.WriteFile(composePath, strings.NewReader(appInstall.DockerCompose), 0775)
|
||||||
|
if fileOp.Stat(backupConfDir) {
|
||||||
|
_ = fileOp.DeleteDir(confDir)
|
||||||
|
_ = fileOp.Rename(backupConfDir, confDir)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
if busErr = env.Write(envParams, envPath); busErr != nil {
|
||||||
|
return busErr
|
||||||
|
}
|
||||||
|
if busErr = fileOp.WriteFile(composePath, strings.NewReader(appDetail.DockerCompose), 0775); busErr != nil {
|
||||||
|
return busErr
|
||||||
|
}
|
||||||
|
if !req.RetainConfig {
|
||||||
|
if busErr = fileOp.Rename(confDir, backupConfDir); busErr != nil {
|
||||||
|
return busErr
|
||||||
|
}
|
||||||
|
_ = fileOp.CreateDir(confDir, 0755)
|
||||||
|
if busErr = fileOp.CopyFile(path.Join(phpDir, "php-fpm.conf"), confDir); busErr != nil {
|
||||||
|
return busErr
|
||||||
|
}
|
||||||
|
if busErr = fileOp.CopyFile(path.Join(phpDir, "php.ini"), confDir); busErr != nil {
|
||||||
|
_ = fileOp.WriteFile(fpmConfDir, bytes.NewReader(oldFmContent), 0775)
|
||||||
|
return busErr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if out, err := compose.Up(appInstall.GetComposePath()); err != nil {
|
||||||
|
if out != "" {
|
||||||
|
busErr = errors.New(out)
|
||||||
|
return busErr
|
||||||
|
}
|
||||||
|
busErr = err
|
||||||
|
return busErr
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = fileOp.DeleteDir(backupConfDir)
|
||||||
|
|
||||||
|
appInstall.AppDetailId = runtime.AppDetailID
|
||||||
|
appInstall.AppId = appDetail.AppId
|
||||||
|
appInstall.Version = appDetail.Version
|
||||||
|
appInstall.DockerCompose = appDetail.DockerCompose
|
||||||
|
|
||||||
|
_ = appInstallRepo.Save(context.Background(), &appInstall)
|
||||||
|
website.RuntimeID = req.RuntimeID
|
||||||
|
return websiteRepo.Save(context.Background(), &website)
|
||||||
|
}
|
||||||
|
|
||||||
func (w WebsiteService) UpdateRewriteConfig(req request.NginxRewriteUpdate) error {
|
func (w WebsiteService) UpdateRewriteConfig(req request.NginxRewriteUpdate) error {
|
||||||
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.WebsiteID))
|
website, err := websiteRepo.GetFirst(commonRepo.WithByID(req.WebsiteID))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,7 @@ ErrAppDelete: 'Other Website use this App'
|
||||||
ErrGroupIsUsed: 'The group is in use and cannot be deleted'
|
ErrGroupIsUsed: 'The group is in use and cannot be deleted'
|
||||||
ErrBackupMatch: 'the backup file does not match the current partial data of the website: {{ .detail}}"'
|
ErrBackupMatch: 'the backup file does not match the current partial data of the website: {{ .detail}}"'
|
||||||
ErrBackupExist: 'the backup file corresponds to a portion of the original data that does not exist: {{ .detail}}"'
|
ErrBackupExist: 'the backup file corresponds to a portion of the original data that does not exist: {{ .detail}}"'
|
||||||
|
ErrPHPResource: 'The local runtime does not support switching!'
|
||||||
|
|
||||||
#ssl
|
#ssl
|
||||||
ErrSSLCannotDelete: "The certificate is being used by the website and cannot be removed"
|
ErrSSLCannotDelete: "The certificate is being used by the website and cannot be removed"
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,7 @@ ErrAppDelete: '其他網站使用此應用,無法刪除'
|
||||||
ErrGroupIsUsed: '分組正在使用中,無法刪除'
|
ErrGroupIsUsed: '分組正在使用中,無法刪除'
|
||||||
ErrBackupMatch: '該備份文件與當前網站部分數據不匹配: {{ .detail}}"'
|
ErrBackupMatch: '該備份文件與當前網站部分數據不匹配: {{ .detail}}"'
|
||||||
ErrBackupExist: '該備份文件對應部分原數據不存在: {{ .detail}}"'
|
ErrBackupExist: '該備份文件對應部分原數據不存在: {{ .detail}}"'
|
||||||
|
ErrPHPResource: '本地運行環境不支持切換!'
|
||||||
|
|
||||||
#ssl
|
#ssl
|
||||||
ErrSSLCannotDelete: "證書正在被網站使用,無法刪除"
|
ErrSSLCannotDelete: "證書正在被網站使用,無法刪除"
|
||||||
|
|
|
||||||
|
|
@ -62,6 +62,7 @@ ErrAppDelete: '其他网站使用此应用,无法删除'
|
||||||
ErrGroupIsUsed: '分组正在使用中,无法删除'
|
ErrGroupIsUsed: '分组正在使用中,无法删除'
|
||||||
ErrBackupMatch: '该备份文件与当前网站部分数据不匹配 {{ .detail}}"'
|
ErrBackupMatch: '该备份文件与当前网站部分数据不匹配 {{ .detail}}"'
|
||||||
ErrBackupExist: '该备份文件对应部分源数据不存在 {{ .detail}}"'
|
ErrBackupExist: '该备份文件对应部分源数据不存在 {{ .detail}}"'
|
||||||
|
ErrPHPResource: '本地运行环境不支持切换!'
|
||||||
|
|
||||||
#ssl
|
#ssl
|
||||||
ErrSSLCannotDelete: "证书正在被网站使用,无法删除"
|
ErrSSLCannotDelete: "证书正在被网站使用,无法删除"
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ func (a *WebsiteRouter) InitWebsiteRouter(Router *gin.RouterGroup) {
|
||||||
groupRouter.GET("/php/config/:id", baseApi.GetWebsitePHPConfig)
|
groupRouter.GET("/php/config/:id", baseApi.GetWebsitePHPConfig)
|
||||||
groupRouter.POST("/php/config", baseApi.UpdateWebsitePHPConfig)
|
groupRouter.POST("/php/config", baseApi.UpdateWebsitePHPConfig)
|
||||||
groupRouter.POST("/php/update", baseApi.UpdatePHPFile)
|
groupRouter.POST("/php/update", baseApi.UpdatePHPFile)
|
||||||
|
groupRouter.POST("/php/version", baseApi.ChangePHPVersion)
|
||||||
|
|
||||||
groupRouter.POST("/rewrite", baseApi.GetRewriteConfig)
|
groupRouter.POST("/rewrite", baseApi.GetRewriteConfig)
|
||||||
groupRouter.POST("/rewrite/update", baseApi.UpdateRewriteConfig)
|
groupRouter.POST("/rewrite/update", baseApi.UpdateRewriteConfig)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
// Code generated by swaggo/swag. DO NOT EDIT.
|
// Package docs GENERATED BY SWAG; DO NOT EDIT
|
||||||
|
// This file was generated by swaggo/swag
|
||||||
package docs
|
package docs
|
||||||
|
|
||||||
import "github.com/swaggo/swag"
|
import "github.com/swaggo/swag"
|
||||||
|
|
@ -10057,6 +10057,57 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/websites/php/version": {
|
||||||
|
"post": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"ApiKeyAuth": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "变更 php 版本",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Website PHP"
|
||||||
|
],
|
||||||
|
"summary": "Update php version",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "request",
|
||||||
|
"name": "request",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/request.WebsitePHPVersionReq"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-panel-log": {
|
||||||
|
"BeforeFuntions": [
|
||||||
|
{
|
||||||
|
"db": "websites",
|
||||||
|
"input_column": "id",
|
||||||
|
"input_value": "websiteId",
|
||||||
|
"isList": false,
|
||||||
|
"output_column": "primary_domain",
|
||||||
|
"output_value": "domain"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"bodyKeys": [
|
||||||
|
"websiteId"
|
||||||
|
],
|
||||||
|
"formatEN": "php version update [domain]",
|
||||||
|
"formatZH": "php 版本变更 [domain]",
|
||||||
|
"paramKeys": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/websites/proxies": {
|
"/websites/proxies": {
|
||||||
"post": {
|
"post": {
|
||||||
"security": [
|
"security": [
|
||||||
|
|
@ -10206,7 +10257,7 @@ const docTemplate = `{
|
||||||
"tags": [
|
"tags": [
|
||||||
"Website"
|
"Website"
|
||||||
],
|
],
|
||||||
"summary": "Get proxy conf",
|
"summary": "Get redirect conf",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"description": "request",
|
"description": "request",
|
||||||
|
|
@ -15587,6 +15638,25 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"request.WebsitePHPVersionReq": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"retainConfig",
|
||||||
|
"runtimeID",
|
||||||
|
"websiteID"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"retainConfig": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"runtimeID": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"websiteID": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"request.WebsiteProxyConfig": {
|
"request.WebsiteProxyConfig": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
|
|
|
||||||
|
|
@ -10050,6 +10050,57 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/websites/php/version": {
|
||||||
|
"post": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"ApiKeyAuth": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "变更 php 版本",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"Website PHP"
|
||||||
|
],
|
||||||
|
"summary": "Update php version",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "request",
|
||||||
|
"name": "request",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/request.WebsitePHPVersionReq"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-panel-log": {
|
||||||
|
"BeforeFuntions": [
|
||||||
|
{
|
||||||
|
"db": "websites",
|
||||||
|
"input_column": "id",
|
||||||
|
"input_value": "websiteId",
|
||||||
|
"isList": false,
|
||||||
|
"output_column": "primary_domain",
|
||||||
|
"output_value": "domain"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"bodyKeys": [
|
||||||
|
"websiteId"
|
||||||
|
],
|
||||||
|
"formatEN": "php version update [domain]",
|
||||||
|
"formatZH": "php 版本变更 [domain]",
|
||||||
|
"paramKeys": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/websites/proxies": {
|
"/websites/proxies": {
|
||||||
"post": {
|
"post": {
|
||||||
"security": [
|
"security": [
|
||||||
|
|
@ -10199,7 +10250,7 @@
|
||||||
"tags": [
|
"tags": [
|
||||||
"Website"
|
"Website"
|
||||||
],
|
],
|
||||||
"summary": "Get proxy conf",
|
"summary": "Get redirect conf",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"description": "request",
|
"description": "request",
|
||||||
|
|
@ -15580,6 +15631,25 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"request.WebsitePHPVersionReq": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"retainConfig",
|
||||||
|
"runtimeID",
|
||||||
|
"websiteID"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"retainConfig": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"runtimeID": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"websiteID": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"request.WebsiteProxyConfig": {
|
"request.WebsiteProxyConfig": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
|
|
|
||||||
|
|
@ -3133,6 +3133,19 @@ definitions:
|
||||||
- id
|
- id
|
||||||
- type
|
- type
|
||||||
type: object
|
type: object
|
||||||
|
request.WebsitePHPVersionReq:
|
||||||
|
properties:
|
||||||
|
retainConfig:
|
||||||
|
type: boolean
|
||||||
|
runtimeID:
|
||||||
|
type: integer
|
||||||
|
websiteID:
|
||||||
|
type: integer
|
||||||
|
required:
|
||||||
|
- retainConfig
|
||||||
|
- runtimeID
|
||||||
|
- websiteID
|
||||||
|
type: object
|
||||||
request.WebsiteProxyConfig:
|
request.WebsiteProxyConfig:
|
||||||
properties:
|
properties:
|
||||||
cache:
|
cache:
|
||||||
|
|
@ -10103,6 +10116,39 @@ paths:
|
||||||
formatEN: Nginx conf update [domain]
|
formatEN: Nginx conf update [domain]
|
||||||
formatZH: php 配置修改 [domain]
|
formatZH: php 配置修改 [domain]
|
||||||
paramKeys: []
|
paramKeys: []
|
||||||
|
/websites/php/version:
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: 变更 php 版本
|
||||||
|
parameters:
|
||||||
|
- description: request
|
||||||
|
in: body
|
||||||
|
name: request
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/request.WebsitePHPVersionReq'
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
security:
|
||||||
|
- ApiKeyAuth: []
|
||||||
|
summary: Update php version
|
||||||
|
tags:
|
||||||
|
- Website PHP
|
||||||
|
x-panel-log:
|
||||||
|
BeforeFuntions:
|
||||||
|
- db: websites
|
||||||
|
input_column: id
|
||||||
|
input_value: websiteId
|
||||||
|
isList: false
|
||||||
|
output_column: primary_domain
|
||||||
|
output_value: domain
|
||||||
|
bodyKeys:
|
||||||
|
- websiteId
|
||||||
|
formatEN: php version update [domain]
|
||||||
|
formatZH: php 版本变更 [domain]
|
||||||
|
paramKeys: []
|
||||||
/websites/proxies:
|
/websites/proxies:
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
|
|
@ -10206,7 +10252,7 @@ paths:
|
||||||
description: OK
|
description: OK
|
||||||
security:
|
security:
|
||||||
- ApiKeyAuth: []
|
- ApiKeyAuth: []
|
||||||
summary: Get proxy conf
|
summary: Get redirect conf
|
||||||
tags:
|
tags:
|
||||||
- Website
|
- Website
|
||||||
/websites/redirect/file:
|
/websites/redirect/file:
|
||||||
|
|
|
||||||
|
|
@ -415,4 +415,10 @@ export namespace Website {
|
||||||
name: string;
|
name: string;
|
||||||
content: string;
|
content: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface PHPVersionChange {
|
||||||
|
websiteID: number;
|
||||||
|
runtimeID: number;
|
||||||
|
retainConfig: boolean;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -226,3 +226,7 @@ export const OperateRedirectConfig = (req: Website.WebsiteReq) => {
|
||||||
export const UpdateRedirectConfigFile = (req: Website.RedirectFileUpdate) => {
|
export const UpdateRedirectConfigFile = (req: Website.RedirectFileUpdate) => {
|
||||||
return http.post<any>(`/websites/redirect/file`, req);
|
return http.post<any>(`/websites/redirect/file`, req);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const ChangePHPVersion = (req: Website.PHPVersionChange) => {
|
||||||
|
return http.post<any>(`/websites/php/version`, req);
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -1460,6 +1460,10 @@ const message = {
|
||||||
notKeep: 'Do not keep',
|
notKeep: 'Do not keep',
|
||||||
redirectRoot: 'Redirect to the homepage',
|
redirectRoot: 'Redirect to the homepage',
|
||||||
redirectHelper: '301 permanent redirection, 302 temporary redirection',
|
redirectHelper: '301 permanent redirection, 302 temporary redirection',
|
||||||
|
changePHPVersionWarn:
|
||||||
|
'Switching the PHP version will delete the original PHP container (the website code that has been mounted will not be lost), continue? ',
|
||||||
|
changeVersion: 'Switch version',
|
||||||
|
retainConfig: 'Whether to keep php-fpm.conf and php.ini files',
|
||||||
},
|
},
|
||||||
php: {
|
php: {
|
||||||
short_open_tag: 'Short tag support',
|
short_open_tag: 'Short tag support',
|
||||||
|
|
|
||||||
|
|
@ -1395,6 +1395,9 @@ const message = {
|
||||||
notKeep: '不保留',
|
notKeep: '不保留',
|
||||||
redirectRoot: '重定向到首頁',
|
redirectRoot: '重定向到首頁',
|
||||||
redirectHelper: '301永久重定向,302臨時重定向',
|
redirectHelper: '301永久重定向,302臨時重定向',
|
||||||
|
changePHPVersionWarn: '切換 PHP 版本會刪除原有的 PHP 容器(不會丟失已經掛載的網站代碼),是否繼續? ',
|
||||||
|
changeVersion: '切換版本',
|
||||||
|
retainConfig: '是否保留 php-fpm.conf 和 php.ini 文件',
|
||||||
},
|
},
|
||||||
php: {
|
php: {
|
||||||
short_open_tag: '短標簽支持',
|
short_open_tag: '短標簽支持',
|
||||||
|
|
|
||||||
|
|
@ -1395,6 +1395,9 @@ const message = {
|
||||||
notKeep: '不保留',
|
notKeep: '不保留',
|
||||||
redirectRoot: '重定向到首页',
|
redirectRoot: '重定向到首页',
|
||||||
redirectHelper: '301永久重定向,302临时重定向',
|
redirectHelper: '301永久重定向,302临时重定向',
|
||||||
|
changePHPVersionWarn: '切换 PHP 版本会删除原有的 PHP 容器(不会丢失已经挂载的网站代码),是否继续?',
|
||||||
|
changeVersion: '切换版本',
|
||||||
|
retainConfig: '是否保留 php-fpm.conf 和 php.ini 文件',
|
||||||
},
|
},
|
||||||
php: {
|
php: {
|
||||||
short_open_tag: '短标签支持',
|
short_open_tag: '短标签支持',
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,9 @@
|
||||||
<el-tab-pane :label="$t('php.uploadMaxSize')" name="2">
|
<el-tab-pane :label="$t('php.uploadMaxSize')" name="2">
|
||||||
<Upload :id="id" v-if="index == '2'"></Upload>
|
<Upload :id="id" v-if="index == '2'"></Upload>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
|
<el-tab-pane :label="$t('runtime.version')" name="3">
|
||||||
|
<Version :id="id" :runtimeID="runtimeID" v-if="index == '3'"></Version>
|
||||||
|
</el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
@ -19,6 +22,7 @@ import { computed, onMounted, ref } from 'vue';
|
||||||
import Config from './config/index.vue';
|
import Config from './config/index.vue';
|
||||||
import Function from './function/index.vue';
|
import Function from './function/index.vue';
|
||||||
import Upload from './upload/index.vue';
|
import Upload from './upload/index.vue';
|
||||||
|
import Version from './version/index.vue';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
id: {
|
id: {
|
||||||
|
|
@ -34,10 +38,12 @@ const id = computed(() => {
|
||||||
const index = ref('0');
|
const index = ref('0');
|
||||||
const configPHP = ref(false);
|
const configPHP = ref(false);
|
||||||
const installId = ref(0);
|
const installId = ref(0);
|
||||||
|
const runtimeID = ref(0);
|
||||||
|
|
||||||
const getWebsiteDetail = async () => {
|
const getWebsiteDetail = async () => {
|
||||||
const res = await GetWebsite(props.id);
|
const res = await GetWebsite(props.id);
|
||||||
if (res.data.type === 'runtime') {
|
if (res.data.type === 'runtime') {
|
||||||
|
runtimeID.value = res.data.runtimeID;
|
||||||
installId.value = res.data.appInstallId;
|
installId.value = res.data.appInstallId;
|
||||||
const runRes = await GetRuntime(res.data.runtimeID);
|
const runRes = await GetRuntime(res.data.runtimeID);
|
||||||
if (runRes.data.resource === 'appstore') {
|
if (runRes.data.resource === 'appstore') {
|
||||||
|
|
|
||||||
107
frontend/src/views/website/website/config/php/version/index.vue
Normal file
107
frontend/src/views/website/website/config/php/version/index.vue
Normal file
|
|
@ -0,0 +1,107 @@
|
||||||
|
<template>
|
||||||
|
<div v-loading="loading">
|
||||||
|
<el-row>
|
||||||
|
<el-col :xs="20" :sm="12" :md="10" :lg="10" :xl="8" :offset="1">
|
||||||
|
<el-form>
|
||||||
|
<el-form-item :label="$t('runtime.version')">
|
||||||
|
<el-select v-model="versionReq.runtimeID" style="width: 100%">
|
||||||
|
<el-option
|
||||||
|
v-for="(item, index) in versions"
|
||||||
|
:key="index"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-checkbox v-model="versionReq.retainConfig" :label="'保留PHP配置文件'" />
|
||||||
|
<span class="input-help">
|
||||||
|
{{ $t('website.retainConfig') }}
|
||||||
|
</span>
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
<el-button type="primary" @click="submit()" :disabled="versionReq.runtimeID === oldRuntimeID">
|
||||||
|
{{ $t('commons.button.save') }}
|
||||||
|
</el-button>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { SearchRuntimes } from '@/api/modules/runtime';
|
||||||
|
import { onMounted, reactive, ref } from 'vue';
|
||||||
|
import { Runtime } from '@/api/interface/runtime';
|
||||||
|
import { Website } from '@/api/interface/website';
|
||||||
|
import { ChangePHPVersion } from '@/api/modules/website';
|
||||||
|
import i18n from '@/lang';
|
||||||
|
import { MsgSuccess } from '@/utils/message';
|
||||||
|
const props = defineProps({
|
||||||
|
id: {
|
||||||
|
type: Number,
|
||||||
|
default: 0,
|
||||||
|
},
|
||||||
|
runtimeID: {
|
||||||
|
type: Number,
|
||||||
|
default: 0,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const runtimeReq = reactive<Runtime.RuntimeReq>({ page: 1, pageSize: 200 });
|
||||||
|
const versionReq = reactive<Website.PHPVersionChange>({
|
||||||
|
websiteID: undefined,
|
||||||
|
runtimeID: undefined,
|
||||||
|
retainConfig: true,
|
||||||
|
});
|
||||||
|
const versions = ref([]);
|
||||||
|
const loading = ref(false);
|
||||||
|
const oldRuntimeID = ref(0);
|
||||||
|
|
||||||
|
const getRuntimes = async () => {
|
||||||
|
try {
|
||||||
|
loading.value = true;
|
||||||
|
const res = await SearchRuntimes(runtimeReq);
|
||||||
|
const items = res.data.items || [];
|
||||||
|
for (const item of items) {
|
||||||
|
versions.value.push({
|
||||||
|
value: item.id,
|
||||||
|
label:
|
||||||
|
item.name +
|
||||||
|
'(' +
|
||||||
|
i18n.global.t('runtime.version') +
|
||||||
|
':' +
|
||||||
|
item.version +
|
||||||
|
+' ' +
|
||||||
|
i18n.global.t('runtime.image') +
|
||||||
|
':' +
|
||||||
|
item.image +
|
||||||
|
')',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (error) {}
|
||||||
|
loading.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const submit = async () => {
|
||||||
|
try {
|
||||||
|
ElMessageBox.confirm(i18n.global.t('website.changePHPVersionWarn'), i18n.global.t('website.changeVersion'), {
|
||||||
|
confirmButtonText: i18n.global.t('commons.button.confirm'),
|
||||||
|
cancelButtonText: i18n.global.t('commons.button.cancel'),
|
||||||
|
}).then(async () => {
|
||||||
|
loading.value = true;
|
||||||
|
try {
|
||||||
|
await ChangePHPVersion(versionReq);
|
||||||
|
MsgSuccess(i18n.global.t('commons.msg.updateSuccess'));
|
||||||
|
} catch (error) {}
|
||||||
|
loading.value = false;
|
||||||
|
});
|
||||||
|
} catch (error) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
versionReq.runtimeID = props.runtimeID;
|
||||||
|
versionReq.websiteID = props.id;
|
||||||
|
oldRuntimeID.value = props.runtimeID;
|
||||||
|
getRuntimes();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
Loading…
Add table
Reference in a new issue