diff --git a/internal/apps/mysql/service.go b/internal/apps/mysql/service.go index 78e5d61ad0..1a38770caa 100644 --- a/internal/apps/mysql/service.go +++ b/internal/apps/mysql/service.go @@ -3,6 +3,7 @@ package mysql import ( "fmt" "net/http" + "os" "regexp" "github.com/spf13/cast" @@ -80,11 +81,16 @@ func (s *Service) Load(w http.ResponseWriter, r *http.Request) { return } - raw, err := shell.Execf(`mysqladmin -u root -p "%s" extended-status`, rootPassword) + if err = os.Setenv("MYSQL_PWD", rootPassword); err != nil { + service.Error(w, http.StatusInternalServerError, "设置环境变量失败") + return + } + raw, err := shell.Execf(`mysqladmin -u root extended-status`) if err != nil { service.Error(w, http.StatusInternalServerError, "获取负载失败") return } + _ = os.Unsetenv("MYSQL_PWD") var load []map[string]string expressions := []struct { diff --git a/internal/data/safe.go b/internal/data/safe.go index 26cd66a7f8..608bb03677 100644 --- a/internal/data/safe.go +++ b/internal/data/safe.go @@ -7,7 +7,6 @@ import ( "github.com/spf13/cast" "github.com/TheTNB/panel/internal/biz" - "github.com/TheTNB/panel/pkg/io" "github.com/TheTNB/panel/pkg/os" "github.com/TheTNB/panel/pkg/shell" "github.com/TheTNB/panel/pkg/systemctl" @@ -61,59 +60,32 @@ func (r *safeRepo) UpdateSSH(port uint, status bool) error { } func (r *safeRepo) GetPingStatus() (bool, error) { - if os.IsRHEL() { - out, err := shell.Execf(`firewall-cmd --list-all`) - if err != nil { - return true, errors.New(out) - } - - if !strings.Contains(out, `rule protocol value="icmp" drop`) { - return true, nil - } else { - return false, nil - } - } else { - config, err := io.Read("/etc/ufw/before.rules") - if err != nil { - return true, err - } - if strings.Contains(config, "-A ufw-before-input -p icmp --icmp-type echo-request -j ACCEPT") { - return true, nil - } else { - return false, nil - } + out, err := shell.Execf(`firewall-cmd --list-all`) + if err != nil { + return true, errors.New(out) } + + if !strings.Contains(out, `rule protocol value="icmp" drop`) { + return true, nil + } + + return false, nil } func (r *safeRepo) UpdatePingStatus(status bool) error { - var out string var err error - if os.IsRHEL() { - if status { - out, err = shell.Execf(`firewall-cmd --permanent --remove-rich-rule='rule protocol value=icmp drop'`) - } else { - out, err = shell.Execf(`firewall-cmd --permanent --add-rich-rule='rule protocol value=icmp drop'`) - } + if status { + _, err = shell.Execf(`firewall-cmd --permanent --remove-rich-rule='rule protocol value=icmp drop'`) } else { - if status { - out, err = shell.Execf(`sed -i 's/-A ufw-before-input -p icmp --icmp-type echo-request -j DROP/-A ufw-before-input -p icmp --icmp-type echo-request -j ACCEPT/g' /etc/ufw/before.rules`) - } else { - out, err = shell.Execf(`sed -i 's/-A ufw-before-input -p icmp --icmp-type echo-request -j ACCEPT/-A ufw-before-input -p icmp --icmp-type echo-request -j DROP/g' /etc/ufw/before.rules`) - } + _, err = shell.Execf(`firewall-cmd --permanent --add-rich-rule='rule protocol value=icmp drop'`) } - if err != nil { - return errors.New(out) - } - - if os.IsRHEL() { - out, err = shell.Execf(`firewall-cmd --reload`) - } else { - out, err = shell.Execf(`ufw reload`) + return err } + _, err = shell.Execf(`firewall-cmd --reload`) if err != nil { - return errors.New(out) + return err } return nil diff --git a/internal/data/setting.go b/internal/data/setting.go index ee02de45d2..89c32104cf 100644 --- a/internal/data/setting.go +++ b/internal/data/setting.go @@ -44,10 +44,13 @@ func (r *settingRepo) Get(key biz.SettingKey, defaultValue ...string) (string, e func (r *settingRepo) Set(key biz.SettingKey, value string) error { setting := new(biz.Setting) - if err := app.Orm.Where("key = ?", key).FirstOrInit(setting).Error; err != nil { - return err + if err := app.Orm.Where("key = ?", key).First(setting).Error; err != nil { + if !errors.Is(err, gorm.ErrRecordNotFound) { + return err + } } + setting.Key = key setting.Value = value return app.Orm.Save(setting).Error } @@ -278,6 +281,7 @@ func (r *settingRepo) UpdatePanel(version, url, checksum string) error { _, _ = shell.Execf("systemctl daemon-reload") _ = io.Remove("/tmp/panel-storage.zip") + _ = io.Remove(filepath.Join(app.Root, "panel/config.example.yml")) return nil } diff --git a/internal/data/ssh.go b/internal/data/ssh.go index 165ba55ecd..24a521da66 100644 --- a/internal/data/ssh.go +++ b/internal/data/ssh.go @@ -40,7 +40,7 @@ func (r *sshRepo) UpdateInfo(req *request.SSHUpdateInfo) error { if err := r.settingRepo.Set(biz.SettingKeySshHost, req.Host); err != nil { return err } - if err := r.settingRepo.Set(biz.SettingKeySshPort, req.Port); err != nil { + if err := r.settingRepo.Set(biz.SettingKeySshPort, cast.ToString(req.Port)); err != nil { return err } if err := r.settingRepo.Set(biz.SettingKeySshUser, req.User); err != nil { diff --git a/internal/data/website.go b/internal/data/website.go index 77af5cbb1a..5ee96fa71e 100644 --- a/internal/data/website.go +++ b/internal/data/website.go @@ -178,7 +178,7 @@ func (r *websiteRepo) Create(req *request.WebsiteCreate) (*biz.Website, error) { Name: req.Name, Status: true, Path: req.Path, - PHP: cast.ToInt(req.PHP), + PHP: req.PHP, SSL: false, } if err := app.Orm.Create(w).Error; err != nil { @@ -250,7 +250,7 @@ server # ssl标记位结束 # php标记位开始 - include enable-php-%s.conf; + include enable-php-%d.conf; # php标记位结束 # 错误页配置,可自行设置 diff --git a/internal/http/request/ssh.go b/internal/http/request/ssh.go index b49c8cbeb1..be274c4e6d 100644 --- a/internal/http/request/ssh.go +++ b/internal/http/request/ssh.go @@ -2,7 +2,7 @@ package request type SSHUpdateInfo struct { Host string `json:"host" form:"host"` - Port string `json:"port" form:"port"` + Port int `json:"port" form:"port"` User string `json:"user" form:"user"` Password string `json:"password" form:"password"` } diff --git a/internal/http/request/website.go b/internal/http/request/website.go index bde171aa26..a04042a938 100644 --- a/internal/http/request/website.go +++ b/internal/http/request/website.go @@ -10,7 +10,7 @@ type WebsiteCreate struct { Domains []string `form:"domains" json:"domains"` Ports []uint `form:"ports" json:"ports"` Path string `form:"path" json:"path"` - PHP string `form:"php" json:"php"` + PHP int `form:"php" json:"php"` DB bool `form:"db" json:"db"` DBType string `form:"db_type" json:"db_type"` DBName string `form:"db_name" json:"db_name"` diff --git a/internal/route/http.go b/internal/route/http.go index 51224a24d8..8ccabf91f3 100644 --- a/internal/route/http.go +++ b/internal/route/http.go @@ -166,48 +166,48 @@ func Http(r chi.Router) { container := service.NewContainerService() r.Get("/", container.List) r.Get("/search", container.Search) - r.Post("/create", container.Create) - r.Post("/remove", container.Remove) - r.Post("/start", container.Start) - r.Post("/stop", container.Stop) - r.Post("/restart", container.Restart) - r.Post("/pause", container.Pause) - r.Post("/unpause", container.Unpause) - r.Get("/inspect", container.Inspect) - r.Post("/kill", container.Kill) - r.Post("/rename", container.Rename) - r.Get("/stats", container.Stats) - r.Get("/exist", container.Exist) - r.Get("/logs", container.Logs) + r.Post("/", container.Create) + r.Delete("/{id}", container.Remove) + r.Post("/{id}/start", container.Start) + r.Post("/{id}/stop", container.Stop) + r.Post("/{id}/restart", container.Restart) + r.Post("/{id}/pause", container.Pause) + r.Post("/{id}/unpause", container.Unpause) + r.Get("/{id}/inspect", container.Inspect) + r.Post("/{id}/kill", container.Kill) + r.Post("/{id}/rename", container.Rename) + r.Get("/{id}/stats", container.Stats) + r.Get("/{id}/exist", container.Exist) + r.Get("/{id}/logs", container.Logs) r.Post("/prune", container.Prune) }) r.Route("/network", func(r chi.Router) { containerNetwork := service.NewContainerNetworkService() - r.Get("/list", containerNetwork.List) - r.Post("/create", containerNetwork.Create) - r.Post("/remove", containerNetwork.Remove) - r.Get("/exist", containerNetwork.Exist) - r.Get("/inspect", containerNetwork.Inspect) - r.Post("/connect", containerNetwork.Connect) - r.Post("/disconnect", containerNetwork.Disconnect) + r.Get("/", containerNetwork.List) + r.Post("/", containerNetwork.Create) + r.Delete("/{id}", containerNetwork.Remove) + r.Get("/{id}/exist", containerNetwork.Exist) + r.Get("/{id}/inspect", containerNetwork.Inspect) + r.Post("/{network}/connect", containerNetwork.Connect) + r.Post("/{network}/disconnect", containerNetwork.Disconnect) r.Post("/prune", containerNetwork.Prune) }) r.Route("/image", func(r chi.Router) { containerImage := service.NewContainerImageService() - r.Get("/list", containerImage.List) - r.Get("/exist", containerImage.Exist) - r.Post("/pull", containerImage.Pull) - r.Post("/remove", containerImage.Remove) - r.Get("/inspect", containerImage.Inspect) + r.Get("/", containerImage.List) + r.Get("/{id}/exist", containerImage.Exist) + r.Post("/", containerImage.Pull) + r.Delete("/{id}", containerImage.Remove) + r.Get("/{id}", containerImage.Inspect) r.Post("/prune", containerImage.Prune) }) r.Route("/volume", func(r chi.Router) { containerVolume := service.NewContainerVolumeService() - r.Get("/list", containerVolume.List) - r.Post("/create", containerVolume.Create) - r.Get("/exist", containerVolume.Exist) - r.Post("/remove", containerVolume.Remove) - r.Get("/inspect", containerVolume.Inspect) + r.Get("/", containerVolume.List) + r.Post("/", containerVolume.Create) + r.Get("/{id}/exist", containerVolume.Exist) + r.Delete("/{id}", containerVolume.Remove) + r.Get("/{id}", containerVolume.Inspect) r.Post("/prune", containerVolume.Prune) }) }) @@ -219,7 +219,7 @@ func Http(r chi.Router) { r.Get("/content", file.Content) r.Post("/save", file.Save) r.Post("/delete", file.Delete) - r.Post("/upload", file.Upload) + r.Post("/upload", file.Upload) // TODO fix r.Post("/move", file.Move) r.Post("/copy", file.Copy) r.Get("/download", file.Download) diff --git a/internal/service/cli.go b/internal/service/cli.go index 44b4028667..540ed7bf47 100644 --- a/internal/service/cli.go +++ b/internal/service/cli.go @@ -6,7 +6,6 @@ import ( "fmt" "path/filepath" - "github.com/go-rat/utils/env" "github.com/go-rat/utils/hash" "github.com/goccy/go-yaml" "github.com/gookit/color" @@ -61,30 +60,11 @@ func (s *CliService) Update(ctx context.Context, cmd *cli.Command) error { return fmt.Errorf("获取最新版本失败:%v", err) } - // TODO 需要修改接口直接把arch传过去 - var ver, url, checksum string - if env.IsX86() { - for _, v := range panel.Downloads { - if v.Arch == "amd64" { - ver = panel.Version - url = v.URL - checksum = v.Checksum - break - } - } - } else if env.IsArm() { - for _, v := range panel.Downloads { - if v.Arch == "arm64" { - ver = panel.Version - url = v.URL - checksum = v.Checksum - break - } - - } - } else { - return errors.New("不支持的架构") + download := str.FirstElement(panel.Downloads) + if download == nil { + return fmt.Errorf("下载地址为空") } + ver, url, checksum := panel.Version, download.URL, download.Checksum return s.setting.UpdatePanel(ver, url, checksum) } diff --git a/internal/service/info.go b/internal/service/info.go index 51f9a69891..4b8d0df5f5 100644 --- a/internal/service/info.go +++ b/internal/service/info.go @@ -7,7 +7,6 @@ import ( "strings" "github.com/go-rat/chix" - "github.com/go-rat/utils/env" "github.com/hashicorp/go-version" "github.com/spf13/cast" @@ -17,6 +16,7 @@ import ( "github.com/TheTNB/panel/pkg/api" "github.com/TheTNB/panel/pkg/db" "github.com/TheTNB/panel/pkg/shell" + "github.com/TheTNB/panel/pkg/str" "github.com/TheTNB/panel/pkg/tools" "github.com/TheTNB/panel/pkg/types" ) @@ -285,31 +285,12 @@ func (s *InfoService) Update(w http.ResponseWriter, r *http.Request) { return } - // TODO 需要修改接口直接把arch传过去 - var ver, url, checksum string - if env.IsX86() { - for _, v := range panel.Downloads { - if v.Arch == "amd64" { - ver = panel.Version - url = v.URL - checksum = v.Checksum - break - } - } - } else if env.IsArm() { - for _, v := range panel.Downloads { - if v.Arch == "arm64" { - ver = panel.Version - url = v.URL - checksum = v.Checksum - break - } - - } - } else { - Error(w, http.StatusInternalServerError, "不支持的架构") + download := str.FirstElement(panel.Downloads) + if download == nil { + Error(w, http.StatusInternalServerError, "获取下载链接失败") return } + ver, url, checksum := panel.Version, download.URL, download.Checksum types.Status = types.StatusUpgrade if err = s.settingRepo.UpdatePanel(ver, url, checksum); err != nil { diff --git a/internal/service/ssh.go b/internal/service/ssh.go index 863bc00c85..e0c0d8f698 100644 --- a/internal/service/ssh.go +++ b/internal/service/ssh.go @@ -59,9 +59,6 @@ func (s *SSHService) Session(w http.ResponseWriter, r *http.Request) { upGrader := websocket.Upgrader{ ReadBufferSize: 4096, WriteBufferSize: 4096, - CheckOrigin: func(r *http.Request) bool { - return true - }, } ws, err := upGrader.Upgrade(w, r, nil) diff --git a/pkg/api/version.go b/pkg/api/version.go index 67625183bd..d563e13b6e 100644 --- a/pkg/api/version.go +++ b/pkg/api/version.go @@ -2,20 +2,25 @@ package api import ( "fmt" + "slices" "time" + + "github.com/go-rat/utils/env" ) +type VersionDownload struct { + URL string `json:"url"` + Arch string `json:"arch"` + Checksum string `json:"checksum"` +} + type Version struct { - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` - Type string `json:"type"` - Version string `json:"version"` - Description string `json:"description"` - Downloads []struct { - URL string `json:"url"` - Arch string `json:"arch"` - Checksum string `json:"checksum"` - } `json:"downloads"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + Type string `json:"type"` + Version string `json:"version"` + Description string `json:"description"` + Downloads []VersionDownload `json:"downloads"` } type Versions []Version @@ -35,6 +40,14 @@ func (r *API) LatestVersion() (*Version, error) { return nil, err } + arch := "amd64" + if env.IsArm() { + arch = "arm64" + } + slices.DeleteFunc(version.Downloads, func(item VersionDownload) bool { + return item.Arch != arch + }) + return version, nil } diff --git a/storage/README.md b/storage/README.md deleted file mode 100644 index 47cabd95a8..0000000000 --- a/storage/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# storage - -storage 目录存放应用运行时产生的文件,如上传的文件、缓存文件等。 \ No newline at end of file diff --git a/storage/sessions/.gitkeep b/storage/sessions/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/web/src/api/panel/cert/index.ts b/web/src/api/panel/cert/index.ts index 85cb627076..5df8f64ac4 100644 --- a/web/src/api/panel/cert/index.ts +++ b/web/src/api/panel/cert/index.ts @@ -9,18 +9,18 @@ export default { dnsProviders: (): Promise> => request.get('/cert/dnsProviders'), // 证书算法列表 algorithms: (): Promise> => request.get('/cert/algorithms'), - // ACME 用户列表 - users: (page: number, limit: number): Promise> => - request.get('/cert/users', { params: { page, limit } }), - // ACME 用户详情 - userInfo: (id: number): Promise> => request.get(`/cert/users/${id}`), - // ACME 用户添加 - userAdd: (data: any): Promise> => request.post('/cert/users', data), - // ACME 用户更新 - userUpdate: (id: number, data: any): Promise> => - request.put(`/cert/users/${id}`, data), - // ACME 用户删除 - userDelete: (id: number): Promise> => request.delete(`/cert/users/${id}`), + // ACME 账号列表 + accounts: (page: number, limit: number): Promise> => + request.get('/cert/account', { params: { page, limit } }), + // ACME 账号详情 + accountInfo: (id: number): Promise> => request.get(`/cert/account/${id}`), + // ACME 账号添加 + accountAdd: (data: any): Promise> => request.post('/cert/account', data), + // ACME 账号更新 + accountUpdate: (id: number, data: any): Promise> => + request.put(`/cert/account/${id}`, data), + // ACME 账号删除 + accountDelete: (id: number): Promise> => request.delete(`/cert/account/${id}`), // DNS 记录列表 dns: (page: number, limit: number): Promise> => request.get('/cert/dns', { params: { page, limit } }), @@ -35,23 +35,26 @@ export default { dnsDelete: (id: number): Promise> => request.delete(`/cert/dns/${id}`), // 证书列表 certs: (page: number, limit: number): Promise> => - request.get('/cert/certs', { params: { page, limit } }), + request.get('/cert/cert', { params: { page, limit } }), // 证书详情 - certInfo: (id: number): Promise> => request.get(`/cert/certs/${id}`), + certInfo: (id: number): Promise> => request.get(`/cert/cert/${id}`), // 证书添加 - certAdd: (data: any): Promise> => request.post('/cert/certs', data), + certAdd: (data: any): Promise> => request.post('/cert/cert', data), // 证书更新 certUpdate: (id: number, data: any): Promise> => - request.put(`/cert/certs/${id}`, data), + request.put(`/cert/cert/${id}`, data), // 证书删除 - certDelete: (id: number): Promise> => request.delete(`/cert/certs/${id}`), + certDelete: (id: number): Promise> => request.delete(`/cert/cert/${id}`), // 签发 - obtain: (id: number): Promise> => request.post(`/cert/obtain`, { id }), + obtain: (id: number): Promise> => + request.post(`/cert/cert/${id}/obtain`, { id }), // 续签 - renew: (id: number): Promise> => request.post(`/cert/renew`, { id }), + renew: (id: number): Promise> => + request.post(`/cert/cert/${id}/renew`, { id }), // 获取 DNS 记录 - manualDNS: (id: number): Promise> => request.post(`/cert/manualDNS`, { id }), + manualDNS: (id: number): Promise> => + request.post(`/cert/cert/${id}/manualDNS`, { id }), // 部署 deploy: (id: number, website_id: number): Promise> => - request.post(`/cert/deploy`, { id, website_id }) + request.post(`/cert/cert/${id}/deploy`, { id, website_id }) } diff --git a/web/src/api/panel/container/index.ts b/web/src/api/panel/container/index.ts index 90a61529bf..3f4ab2bfb5 100644 --- a/web/src/api/panel/container/index.ts +++ b/web/src/api/panel/container/index.ts @@ -5,103 +5,101 @@ import { request } from '@/utils' export default { // 获取容器列表 containerList: (page: number, limit: number): Promise> => - request.get('/container/list', { params: { page, limit } }), + request.get('/container/container', { params: { page, limit } }), // 添加容器 containerCreate: (config: any): Promise> => - request.post('/container/create', config), + request.post('/container/container', config), // 删除容器 containerRemove: (id: string): Promise> => - request.post(`/container/remove`, { id }), + request.delete(`/container/container/${id}`), // 启动容器 containerStart: (id: string): Promise> => - request.post(`/container/start`, { id }), + request.post(`/container/container/${id}/start`), // 停止容器 containerStop: (id: string): Promise> => - request.post(`/container/stop`, { id }), + request.post(`/container/container/${id}/stop`), // 重启容器 containerRestart: (id: string): Promise> => - request.post(`/container/restart`, { id }), + request.post(`/container/container/${id}/restart`), // 暂停容器 containerPause: (id: string): Promise> => - request.post(`/container/pause`, { id }), + request.post(`/container/container/${id}/pause`), // 恢复容器 containerUnpause: (id: string): Promise> => - request.post(`/container/unpause`, { id }), + request.post(`/container/container/${id}/unpause`), // 获取容器详情 containerDetail: (id: string): Promise> => - request.get(`/container/detail`, { params: { id } }), + request.get(`/container/container/${id}/detail`), // 杀死容器 containerKill: (id: string): Promise> => - request.post(`/container/kill`, { id }), + request.post(`/container/container/${id}/kill`), // 重命名容器 containerRename: (id: string, name: string): Promise> => - request.post(`/container/rename`, { id, name }), + request.post(`/container/container/${id}/rename`, { name }), // 获取容器状态 containerStats: (id: string): Promise> => - request.get(`/container/stats`, { params: { id } }), + request.get(`/container/container/${id}/stats`), // 检查容器是否存在 containerExist: (id: string): Promise> => - request.get(`/container/exist`, { params: { id } }), + request.get(`/container/container/${id}/exist`), // 获取容器日志 containerLogs: (id: string): Promise> => - request.get(`/container/logs`, { params: { id } }), + request.get(`/container/container/${id}/logs`), // 清理容器 - containerPrune: (): Promise> => request.post(`/container/prune`), + containerPrune: (): Promise> => request.post(`/container/container/prune`), // 获取网络列表 networkList: (page: number, limit: number): Promise> => - request.get(`/container/network/list`, { params: { page, limit } }), + request.get(`/container/network`, { params: { page, limit } }), // 创建网络 networkCreate: (config: any): Promise> => - request.post(`/container/network/create`, config), + request.post(`/container/network`, config), // 删除网络 networkRemove: (id: string): Promise> => - request.post(`/container/network/remove`, { id }), + request.delete(`/container/network/${id}`), // 检查网络是否存在 networkExist: (id: string): Promise> => - request.get(`/container/network/exist`, { params: { id } }), + request.get(`/container/network/${id}/exist`), // 获取网络详情 networkInspect: (id: string): Promise> => - request.get(`/container/network/inspect`, { params: { id } }), + request.get(`/container/network/${id}/inspect`), // 连接容器到网络 - networkConnect: (config: any): Promise> => - request.post(`/container/network/connect`, config), + networkConnect: (network: string, container: string): Promise> => + request.post(`/container/network/${network}/connect`, container), // 断开容器到网络的连接 - networkDisconnect: (config: any): Promise> => - request.post(`/container/network/disconnect`, config), + networkDisconnect: (network: string, container: string): Promise> => + request.post(`/container/network/${network}/disconnect`, container), // 清理网络 networkPrune: (): Promise> => request.post(`/container/network/prune`), // 获取镜像列表 imageList: (page: number, limit: number): Promise> => - request.get(`/container/image/list`, { params: { page, limit } }), + request.get(`/container/image`, { params: { page, limit } }), // 检查镜像是否存在 imageExist: (id: string): Promise> => - request.get(`/container/image/exist`, { params: { id } }), + request.get(`/container/image/${id}/exist`), // 拉取镜像 - imagePull: (config: any): Promise> => - request.post(`/container/image/pull`, config), + imagePull: (config: any): Promise> => request.post(`/container/image`, config), // 删除镜像 imageRemove: (id: string): Promise> => - request.post(`/container/image/remove`, { id }), + request.delete(`/container/image/${id}`), // 获取镜像详情 - imageInspect: (id: string): Promise> => - request.get(`/container/image/inspect`, { params: { id } }), + imageInspect: (id: string): Promise> => request.get(`/container/image/${id}`), // 清理镜像 imagePrune: (): Promise> => request.post(`/container/image/prune`), // 获取卷列表 volumeList: (page: number, limit: number): Promise> => - request.get(`/container/volume/list`, { params: { page, limit } }), + request.get(`/container/volume`, { params: { page, limit } }), // 创建卷 volumeCreate: (config: any): Promise> => - request.post(`/container/volume/create`, config), + request.post(`/container/volume`, config), // 检查卷是否存在 volumeExist: (id: string): Promise> => - request.get(`/container/volume/exist`, { params: { id } }), + request.get(`/container/volume/${id}/exist`), // 删除卷 volumeRemove: (id: string): Promise> => - request.post(`/container/volume/remove`, { id }), + request.delete(`/container/volume/${id}`), // 获取卷详情 volumeInspect: (id: string): Promise> => - request.get(`/container/volume/inspect`, { params: { id } }), + request.get(`/container/volume/${id}`), // 清理卷 volumePrune: (): Promise> => request.post(`/container/volume/prune`) } diff --git a/web/src/api/panel/file/index.ts b/web/src/api/panel/file/index.ts index da6486906c..7360961e13 100644 --- a/web/src/api/panel/file/index.ts +++ b/web/src/api/panel/file/index.ts @@ -44,11 +44,11 @@ export default { group: string ): Promise> => request.post('/file/permission', { path, mode, owner, group }), // 压缩文件 - archive: (paths: string[], file: string): Promise> => - request.post('/file/archive', { paths, file }), + compress: (paths: string[], file: string): Promise> => + request.post('/file/compress', { paths, file }), // 解压文件 - unArchive: (file: string, path: string): Promise> => - request.post('/file/unArchive', { file, path }), + unCompress: (file: string, path: string): Promise> => + request.post('/file/unCompress', { file, path }), // 搜索文件 search: (keyword: string): Promise> => request.post('/file/search', { keyword }), diff --git a/web/src/api/panel/monitor/index.ts b/web/src/api/panel/monitor/index.ts index 20b8066be3..c87f643ffe 100644 --- a/web/src/api/panel/monitor/index.ts +++ b/web/src/api/panel/monitor/index.ts @@ -4,16 +4,13 @@ import { request } from '@/utils' export default { // 开关 - switch: (monitor: boolean): Promise> => - request.post('/monitor/switch', { monitor }), + setting: (): Promise> => request.get('/monitor/setting'), // 保存天数 - saveDays: (days: number): Promise> => - request.post('/monitor/saveDays', { days }), + updateSetting: (enabled: boolean, days: number): Promise> => + request.post('/monitor/setting', { enabled, days }), // 清空监控记录 clear: (): Promise> => request.post('/monitor/clear'), // 监控记录 list: (start: number, end: number): Promise> => - request.get('/monitor/list', { params: { start, end } }), - // 开关和天数 - switchAndDays: (): Promise> => request.get('/monitor/switchAndDays') + request.get('/monitor/list', { params: { start, end } }) } diff --git a/web/src/api/panel/safe/index.ts b/web/src/api/panel/safe/index.ts index 0fa568c6da..d2958ea4a6 100644 --- a/web/src/api/panel/safe/index.ts +++ b/web/src/api/panel/safe/index.ts @@ -4,32 +4,27 @@ import { request } from '@/utils' export default { // 获取防火墙状态 - firewallStatus: (): Promise> => request.get('/safe/firewallStatus'), + firewallStatus: (): Promise> => request.get('/firewall/status'), // 设置防火墙状态 setFirewallStatus: (status: boolean): Promise> => - request.post('/safe/firewallStatus', { status }), + request.post('/firewall/status', { status }), // 获取防火墙规则 firewallRules: (page: number, limit: number): Promise> => - request.get('/safe/firewallRules', { params: { page, limit } }), + request.get('/firewall/rule', { params: { page, limit } }), // 添加防火墙规则 - addFirewallRule: (port: string, protocol: string): Promise> => - request.post('/safe/firewallRules', { port, protocol }), + addFirewallRule: (port: number, protocol: string): Promise> => + request.post('/firewall/rule', { port, protocol }), // 删除防火墙规则 - deleteFirewallRule: (port: string, protocol: string): Promise> => - request.delete('/safe/firewallRules', { data: { port, protocol } }), - // 获取SSH状态 - sshStatus: (): Promise> => request.get('/safe/sshStatus'), - // 设置SSH状态 - setSshStatus: (status: boolean): Promise> => - request.post('/safe/sshStatus', { status }), - // 获取SSH端口 - sshPort: (): Promise> => request.get('/safe/sshPort'), - // 设置SSH端口 - setSshPort: (port: number): Promise> => - request.post('/safe/sshPort', { port }), + deleteFirewallRule: (port: number, protocol: string): Promise> => + request.delete('/firewall/rule', { data: { port, protocol } }), + // 获取SSH + ssh: (): Promise> => request.get('/safe/ssh'), + // 设置SSH + setSsh: (status: boolean, port: number): Promise> => + request.post('/safe/ssh', { status, port }), // 获取Ping状态 - pingStatus: (): Promise> => request.get('/safe/pingStatus'), + pingStatus: (): Promise> => request.get('/safe/ping'), // 设置Ping状态 setPingStatus: (status: boolean): Promise> => - request.post('/safe/pingStatus', { status }) + request.post('/safe/ping', { status }) } diff --git a/web/src/i18n/en.json b/web/src/i18n/en.json index 784dd50c13..55bd9a17bf 100644 --- a/web/src/i18n/en.json +++ b/web/src/i18n/en.json @@ -83,23 +83,6 @@ "success": "Update successful" } }, - "eggs": { - "count": { - "gt10": "What are you doing, ouch!", - "gt4": "Are you awesome, Brother Kun?", - "gt0": "If you look at it one more time, it will explode." - } - }, - "about": { - "title": "About the panel", - "tnb": "The TNB development team wishes everyone a happy Dragon Boat Festival in 2024! Never downtime!", - "specialThanks": "Special thanks to the following supporters and {supporter}!", - "links": { - "group": "group", - "channel": "channel", - "supporter": "" - } - }, "apps": { "title": "Quick App" } diff --git a/web/src/i18n/zh_CN.json b/web/src/i18n/zh_CN.json index 58e7ed9e51..3be11426a9 100644 --- a/web/src/i18n/zh_CN.json +++ b/web/src/i18n/zh_CN.json @@ -83,23 +83,6 @@ "success": "当前已是最新版本" } }, - "eggs": { - "count": { - "gt10": "你干嘛,哎呦!", - "gt4": "厉不厉害你坤哥", - "gt0": "在多一眼看一眼就会爆炸" - } - }, - "about": { - "title": "关于面板", - "tnb": "树新蜂开发组祝大家 2024 端午安康!永不宕机!", - "specialThanks": "特别感谢以下支持者和 {supporter}!", - "links": { - "group": "群", - "channel": "频道", - "supporter": "" - } - }, "apps": { "title": "快捷应用" } diff --git a/web/src/utils/file/index.ts b/web/src/utils/file/index.ts index 92f923520d..835dd9663e 100644 --- a/web/src/utils/file/index.ts +++ b/web/src/utils/file/index.ts @@ -286,7 +286,7 @@ const getFilename = (path: string) => { return parts.pop()! } -const isArchive = (name: string) => { +const isCompress = (name: string) => { const ext = getExt(name) return ['zip', 'rar', '7z', 'tar', 'gz'].includes(ext) } @@ -323,7 +323,7 @@ export { getExt, getFilename, getIconByExt, - isArchive, + isCompress, languageByPath, lastDirectory } diff --git a/web/src/views/cert/UserView.vue b/web/src/views/cert/AccountView.vue similarity index 68% rename from web/src/views/cert/UserView.vue rename to web/src/views/cert/AccountView.vue index 84d609097b..adbc8cb399 100644 --- a/web/src/views/cert/UserView.vue +++ b/web/src/views/cert/AccountView.vue @@ -10,31 +10,31 @@ import { } from 'naive-ui' import cert from '@/api/panel/cert' -import type { User } from '@/views/cert/types' +import type { Account } from '@/views/cert/types' let messageReactive: MessageReactive | null = null -const addUserModel = ref({ +const addAccountModel = ref({ hmac_encoded: '', email: '', kid: '', key_type: 'P256', ca: 'letsencrypt' }) -const updateUserModel = ref({ +const updateAccountModel = ref({ hmac_encoded: '', email: '', kid: '', key_type: 'P256', ca: 'letsencrypt' }) -const addUserModal = ref(false) -const updateUserModal = ref(false) -const updateUser = ref() +const addAccountModal = ref(false) +const updateAccountModal = ref(false) +const updateAccount = ref() const caProviders = ref([]) const algorithms = ref([]) -const userColumns: any = [ +const accountColumns: any = [ { title: '邮箱', key: 'email', resizable: true, ellipsis: { tooltip: true } }, { title: 'CA', @@ -86,13 +86,13 @@ const userColumns: any = [ size: 'small', type: 'primary', onClick: () => { - updateUser.value = row.id - updateUserModel.value.email = row.email - updateUserModel.value.hmac_encoded = row.hmac_encoded - updateUserModel.value.kid = row.kid - updateUserModel.value.key_type = row.key_type - updateUserModel.value.ca = row.ca - updateUserModal.value = true + updateAccount.value = row.id + updateAccountModel.value.email = row.email + updateAccountModel.value.hmac_encoded = row.hmac_encoded + updateAccountModel.value.kid = row.kid + updateAccountModel.value.key_type = row.key_type + updateAccountModel.value.ca = row.ca + updateAccountModal.value = true } }, { @@ -103,9 +103,9 @@ const userColumns: any = [ NPopconfirm, { onPositiveClick: async () => { - await cert.userDelete(row.id) + await cert.accountDelete(row.id) window.$message.success('删除成功') - onUserPageChange(1) + onAccountPageChange(1) } }, { @@ -131,9 +131,9 @@ const userColumns: any = [ } } ] -const userData = ref([] as User[]) +const accountData = ref([] as Account[]) -const userPagination = reactive({ +const accountPagination = reactive({ page: 1, pageCount: 1, pageSize: 10, @@ -143,51 +143,51 @@ const userPagination = reactive({ pageSizes: [10, 20, 50, 100] }) -const onUserPageChange = (page: number) => { - userPagination.page = page - getUserList(page, userPagination.pageSize).then((res) => { - userData.value = res.items - userPagination.itemCount = res.total - userPagination.pageCount = res.total / userPagination.pageSize + 1 +const onAccountPageChange = (page: number) => { + accountPagination.page = page + getAccountList(page, accountPagination.pageSize).then((res) => { + accountData.value = res.items + accountPagination.itemCount = res.total + accountPagination.pageCount = res.total / accountPagination.pageSize + 1 }) } -const onUserPageSizeChange = (pageSize: number) => { - userPagination.pageSize = pageSize - onUserPageChange(1) +const onAccountPageSizeChange = (pageSize: number) => { + accountPagination.pageSize = pageSize + onAccountPageChange(1) } -const getUserList = async (page: number, limit: number) => { - const { data } = await cert.users(page, limit) +const getAccountList = async (page: number, limit: number) => { + const { data } = await cert.accounts(page, limit) return data } -const handleAddUser = async () => { +const handleAddAccount = async () => { messageReactive = window.$message.loading('正在向 CA 注册账号,请耐心等待', { duration: 0 }) - await cert.userAdd(addUserModel.value) + await cert.accountAdd(addAccountModel.value) messageReactive.destroy() window.$message.success('添加成功') - addUserModal.value = false - onUserPageChange(1) - addUserModel.value.email = '' - addUserModel.value.hmac_encoded = '' - addUserModel.value.kid = '' + addAccountModal.value = false + onAccountPageChange(1) + addAccountModel.value.email = '' + addAccountModel.value.hmac_encoded = '' + addAccountModel.value.kid = '' } -const handleUpdateUser = async () => { +const handleUpdateAccount = async () => { messageReactive = window.$message.loading('正在向 CA 注册账号,请耐心等待', { duration: 0 }) - await cert.userUpdate(updateUser.value, updateUserModel.value) + await cert.accountUpdate(updateAccount.value, updateAccountModel.value) messageReactive.destroy() window.$message.success('更新成功') - updateUserModal.value = false - onUserPageChange(1) - updateUserModel.value.email = '' - updateUserModel.value.hmac_encoded = '' - updateUserModel.value.kid = '' + updateAccountModal.value = false + onAccountPageChange(1) + updateAccountModel.value.email = '' + updateAccountModel.value.hmac_encoded = '' + updateAccountModel.value.kid = '' } onMounted(() => { @@ -207,7 +207,7 @@ onMounted(() => { }) } }) - onUserPageChange(1) + onAccountPageChange(1) }) @@ -215,7 +215,7 @@ onMounted(() => { - 添加账号 + 添加账号 { remote :loading="false" :scroll-x="1200" - :columns="userColumns" - :data="userData" + :columns="accountColumns" + :data="accountData" :row-key="(row: any) => row.id" - :pagination="userPagination" - @update:page="onUserPageChange" - @update:page-size="onUserPageSizeChange" + :pagination="accountPagination" + @update:page="onAccountPageChange" + @update:page-size="onAccountPageSizeChange" /> { 境内无法使用 Google CA,其他 CA 视网络情况而定,建议使用 Let's Encrypt - + { { { { - 提交 + 提交 { 境内无法使用 Google CA,其他 CA 视网络情况而定,建议使用 Let's Encrypt - + { { { { - 提交 + 提交 diff --git a/web/src/views/cert/CertView.vue b/web/src/views/cert/CertView.vue index c16428bdcd..1c5c576bbc 100644 --- a/web/src/views/cert/CertView.vue +++ b/web/src/views/cert/CertView.vue @@ -11,7 +11,7 @@ const addCertModel = ref({ domains: [], dns_id: 0, type: 'P256', - user_id: null, + account_id: null, website_id: 0, auto_renew: true }) @@ -19,7 +19,7 @@ const updateCertModel = ref({ domains: [], dns_id: 0, type: 'P256', - user_id: null, + account_id: null, website_id: 0, auto_renew: true }) @@ -40,7 +40,7 @@ const deployCertModel = ref({ const algorithms = ref([]) const websites = ref([]) const dns = ref([]) -const users = ref([]) +const accounts = ref([]) const certColumns: any = [ { @@ -94,7 +94,7 @@ const certColumns: any = [ }, { title: '关联账号', - key: 'user_id', + key: 'account_id', width: 200, resizable: true, ellipsis: { tooltip: true }, @@ -102,11 +102,11 @@ const certColumns: any = [ return h( NTag, { - type: row.user == null ? 'error' : 'success', + type: row.account == null ? 'error' : 'success', bordered: false }, { - default: () => (row.user?.email == null ? '无' : row.user.email) + default: () => (row.account?.email == null ? '无' : row.account.email) } ) } @@ -314,7 +314,7 @@ const certColumns: any = [ updateCertModel.value.domains = row.domains updateCertModel.value.dns_id = row.dns_id updateCertModel.value.type = row.type - updateCertModel.value.user_id = row.user_id + updateCertModel.value.account_id = row.account_id updateCertModel.value.website_id = row.website_id updateCertModel.value.auto_renew = row.auto_renew updateCertModal.value = true @@ -395,7 +395,7 @@ const handleAddCert = async () => { addCertModel.value.domains = [] addCertModel.value.dns_id = 0 addCertModel.value.type = 'P256' - addCertModel.value.user_id = 0 + addCertModel.value.account_id = 0 addCertModel.value.website_id = 0 addCertModel.value.auto_renew = true await getAsyncData() @@ -409,7 +409,7 @@ const handleUpdateCert = async () => { updateCertModel.value.domains = [] updateCertModel.value.dns_id = 0 updateCertModel.value.type = 'P256' - updateCertModel.value.user_id = 0 + updateCertModel.value.account_id = 0 updateCertModel.value.website_id = 0 updateCertModel.value.auto_renew = true await getAsyncData() @@ -459,10 +459,10 @@ const getAsyncData = async () => { }) } - const { data: userData } = await cert.users(1, 10000) - users.value = [] - for (const item of userData.items) { - users.value.push({ + const { data: accountData } = await cert.accounts(1, 10000) + accounts.value = [] + for (const item of accountData.items) { + accounts.value.push({ label: item.email, value: item.id }) @@ -539,15 +539,15 @@ onMounted(() => { :options="websites" /> - + - + { :options="websites" /> - + - + +import AccountView from '@/views/cert/AccountView.vue' import CertView from '@/views/cert/CertView.vue' -import DNSView from '@/views/cert/DNSView.vue' -import UserView from '@/views/cert/UserView.vue' +import DnsView from '@/views/cert/DnsView.vue' const currentTab = ref('cert') @@ -10,13 +10,13 @@ const currentTab = ref('cert') - + - + - + diff --git a/web/src/views/cert/types.ts b/web/src/views/cert/types.ts index ff041386c0..bd5a72a270 100644 --- a/web/src/views/cert/types.ts +++ b/web/src/views/cert/types.ts @@ -1,6 +1,6 @@ export interface Cert { id: number - user_id: number + account_id: number website_id: number dns_id: number type: string @@ -13,7 +13,7 @@ export interface Cert { updated_at: string website: Website dns: DNS - user: User + account: Account } export interface Website { @@ -43,7 +43,7 @@ export interface DNS { updated_at: string } -export interface User { +export interface Account { id: number email: string ca: string diff --git a/web/src/views/file/ArchiveModal.vue b/web/src/views/file/CompressModal.vue similarity index 96% rename from web/src/views/file/ArchiveModal.vue rename to web/src/views/file/CompressModal.vue index 11a9474dfe..288ee2988b 100644 --- a/web/src/views/file/ArchiveModal.vue +++ b/web/src/views/file/CompressModal.vue @@ -1,7 +1,7 @@ @@ -22,17 +22,17 @@ const permission = ref(false) v-model:path="path" v-model:selected="selected" v-model:marked="marked" - v-model:archive="archive" + v-model:compress="compress" v-model:permission="permission" /> - + diff --git a/web/src/views/file/ListTable.vue b/web/src/views/file/ListTable.vue index 6be09264f6..e5c8da040e 100644 --- a/web/src/views/file/ListTable.vue +++ b/web/src/views/file/ListTable.vue @@ -6,7 +6,7 @@ import type { RowData } from 'naive-ui/es/data-table/src/interface' import file from '@/api/panel/file' import TheIcon from '@/components/custom/TheIcon.vue' import EventBus from '@/utils/event' -import { checkName, checkPath, getExt, getFilename, getIconByExt, isArchive } from '@/utils/file' +import { checkName, checkPath, getExt, getFilename, getIconByExt, isCompress } from '@/utils/file' import EditModal from '@/views/file/EditModal.vue' import type { Marked } from '@/views/file/types' @@ -14,7 +14,7 @@ const loading = ref(false) const path = defineModel('path', { type: String, required: true }) const selected = defineModel('selected', { type: Array, default: () => [] }) const marked = defineModel('marked', { type: Array, default: () => [] }) -const archive = defineModel('archive', { type: Boolean, required: true }) +const compress = defineModel('compress', { type: Boolean, required: true }) const permission = defineModel('permission', { type: Boolean, required: true }) const editorModal = ref(false) const editorFile = ref('') @@ -24,8 +24,8 @@ const renameModel = ref({ source: '', target: '' }) -const unArchiveModal = ref(false) -const unArchiveModel = ref({ +const unCompressModal = ref(false) +const unCompressModel = ref({ path: '', file: '' }) @@ -125,7 +125,7 @@ const columns: DataTableColumns = [ onClick: () => { if (row.dir) { selected.value = [row.full] - archive.value = true + compress.value = true } else { window.open('/api/panel/file/download?path=' + encodeURIComponent(row.full)) } @@ -189,8 +189,8 @@ const columns: DataTableColumns = [ { label: '复制', value: 'copy' }, { label: '移动', value: 'move' }, { label: '权限', value: 'permission' }, - { label: '压缩', value: 'archive' }, - { label: '解压', value: 'unarchive', disabled: !isArchive(row.name) } + { label: '压缩', value: 'compress' }, + { label: '解压', value: 'uncompress', disabled: !isCompress(row.name) } ], onUpdateValue: (value) => { switch (value) { @@ -218,14 +218,14 @@ const columns: DataTableColumns = [ selected.value = [row.full] permission.value = true break - case 'archive': + case 'compress': selected.value = [row.full] - archive.value = true + compress.value = true break - case 'unarchive': - unArchiveModel.value.file = row.full - unArchiveModel.value.path = path.value - unArchiveModal.value = true + case 'uncompress': + unCompressModel.value.file = row.full + unCompressModel.value.path = path.value + unCompressModal.value = true break } } @@ -306,11 +306,11 @@ const handleRename = () => { }) } -const handleUnArchive = () => { +const handleUnCompress = () => { // 移除首位的 / 去检测 if ( - !unArchiveModel.value.path.startsWith('/') || - !checkPath(unArchiveModel.value.path.slice(1)) + !unCompressModel.value.path.startsWith('/') || + !checkPath(unCompressModel.value.path.slice(1)) ) { window.$message.error('路径不合法') return @@ -319,11 +319,11 @@ const handleUnArchive = () => { duration: 0 }) file - .unArchive(unArchiveModel.value.file, unArchiveModel.value.path) + .unCompress(unCompressModel.value.file, unCompressModel.value.path) .then(() => { message?.destroy() window.$message.success('解压成功') - unArchiveModal.value = false + unCompressModal.value = false EventBus.emit('file:refresh') }) .catch(() => { @@ -391,9 +391,9 @@ onUnmounted(() => { { - + - 解压 + 解压 diff --git a/web/src/views/file/ToolBar.vue b/web/src/views/file/ToolBar.vue index 987a827e85..ccc7d0ee2b 100644 --- a/web/src/views/file/ToolBar.vue +++ b/web/src/views/file/ToolBar.vue @@ -10,7 +10,7 @@ import type { Marked } from '@/views/file/types' const path = defineModel('path', { type: String, required: true }) const selected = defineModel('selected', { type: Array, default: () => [] }) const marked = defineModel('marked', { type: Array, default: () => [] }) -const archive = defineModel('archive', { type: Boolean, required: true }) +const compress = defineModel('compress', { type: Boolean, required: true }) const permission = defineModel('permission', { type: Boolean, required: true }) const upload = ref(false) @@ -126,7 +126,7 @@ const bulkDelete = () => { 复制 移动 - 压缩 + 压缩 权限