mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2026-10-11 08:00:31 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
887db0aff7 | ||
|
|
4a974b7e0a | ||
|
|
fb286d2def | ||
|
|
89cb9e6693 | ||
|
|
927def4472 | ||
|
|
84fcd31704 | ||
|
|
005e5cc01f | ||
|
|
2896409b3a | ||
|
|
791641f3e1 | ||
|
|
79f266bbda | ||
|
|
c9edaf0d1d | ||
|
|
ac5f73c687 | ||
|
|
cc0667429a | ||
|
|
92a5d6faeb | ||
|
|
1111b6b494 | ||
|
|
be5a7c99e1 | ||
|
|
d6a963c087 | ||
|
|
af753bdffe | ||
|
|
59b025353f | ||
|
|
355a6b0205 | ||
|
|
7de80e9d5a | ||
|
|
4c6d8cd20c | ||
|
|
31da89d63a | ||
|
|
e044ca7d12 | ||
|
|
7c037b68cd | ||
|
|
9080824a59 | ||
|
|
11f4bc2c89 | ||
|
|
a64ddd1eb8 | ||
|
|
2fdaecfafe | ||
|
|
6d1fe20736 | ||
|
|
f61bc047cd | ||
|
|
4f52580938 | ||
|
|
281d0cf880 | ||
|
|
fdf9215d43 | ||
|
|
8c182e907d | ||
|
|
e55af04568 | ||
|
|
2462ffdbab | ||
|
|
bfeb57e24f | ||
|
|
9bb28cda27 | ||
|
|
42e522abe1 | ||
|
|
fb5c3429e5 | ||
|
|
0fe1fd3c7b | ||
|
|
bdcca7f380 | ||
|
|
796d47d60e | ||
|
|
a9a45ce5ac | ||
|
|
d04121c551 | ||
|
|
dd06ff73e6 | ||
|
|
24b3501f38 | ||
|
|
ed11c0a4a6 | ||
|
|
7591a716f4 | ||
|
|
ce44ccdedb | ||
|
|
521fca93bd | ||
|
|
d6a0dc0125 | ||
|
|
0a483383b4 | ||
|
|
6c99e04aee | ||
|
|
e120bb0612 | ||
|
|
92a11863a7 | ||
|
|
2091fdbe5d | ||
|
|
b518463c90 | ||
|
|
94fbb265fa | ||
|
|
daefd650a5 | ||
|
|
4994cc39f1 | ||
|
|
2dec0bfb3c | ||
|
|
eb56b918a6 | ||
|
|
35098ce79c | ||
|
|
5a3a123be7 | ||
|
|
a94e78d31e | ||
|
|
5527ef73ad | ||
|
|
f1ed976c17 | ||
|
|
471bbb5c43 | ||
|
|
4ae8e580b9 | ||
|
|
ffb0e72a5b | ||
|
|
7f9793e4bb | ||
|
|
c332d0284b | ||
|
|
8b3d84d667 | ||
|
|
f009e6414a | ||
|
|
e36cbb0eb7 | ||
|
|
2fbddf3f30 | ||
|
|
8927b59bae | ||
|
|
90c7f9cc2c | ||
|
|
83ca72e153 | ||
|
|
9571d82932 | ||
|
|
c54451c733 | ||
|
|
e52ddd3f39 | ||
|
|
c488507d96 | ||
|
|
db5853df7d | ||
|
|
eb2e533d14 |
@@ -25,7 +25,7 @@ body:
|
||||
required: true
|
||||
attributes:
|
||||
label: "1Panel 版本"
|
||||
description: "可通过系统右上角下拉菜单中的`关于`选项,或查看安装目录中的 version 文件获取。"
|
||||
description: "登录 1Panel Web 控制台,在页面右下角查看当前版本。"
|
||||
- type: markdown
|
||||
id: details
|
||||
attributes:
|
||||
|
||||
@@ -14,7 +14,7 @@ body:
|
||||
required: true
|
||||
attributes:
|
||||
label: "1Panel 版本"
|
||||
description: "可通过系统右上角下拉菜单中的`关于`选项,或查看安装目录中的 version 文件获取。"
|
||||
description: "登录 1Panel Web 控制台,在页面右下角查看当前版本。"
|
||||
- type: markdown
|
||||
id: details
|
||||
attributes:
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
on: pull_request
|
||||
|
||||
name: 1Panel 通用 PR 处理
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
generic_handler:
|
||||
name: 为 PR 添加标签
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions-ecosystem/action-add-labels@v1
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUBTOKEN }}
|
||||
labels: ${{ github.base_ref }}
|
||||
@@ -0,0 +1,17 @@
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'pr@**'
|
||||
- 'repr@**'
|
||||
|
||||
name: 针对特定分支名自动创建 PR
|
||||
|
||||
jobs:
|
||||
generic_handler:
|
||||
name: 自动创建 PR
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Create pull request
|
||||
uses: jumpserver/action-generic-handler@master
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUBTOKEN }}
|
||||
@@ -0,0 +1,16 @@
|
||||
name: Issue Close Check
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: [closed]
|
||||
|
||||
jobs:
|
||||
issue-close-remove-labels:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Remove labels
|
||||
uses: actions-cool/issues-helper@v2
|
||||
if: ${{ !github.event.issue.pull_request }}
|
||||
with:
|
||||
actions: 'remove-labels'
|
||||
labels: '状态:待处理'
|
||||
@@ -0,0 +1,38 @@
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
|
||||
name: Add issues workflow labels
|
||||
|
||||
jobs:
|
||||
add-label-if-is-author:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ (github.event.issue.user.id == github.event.comment.user.id) && (!github.event.issue.pull_request) }}
|
||||
steps:
|
||||
- name: Add require handle label
|
||||
uses: actions-cool/issues-helper@v2
|
||||
with:
|
||||
actions: 'add-labels'
|
||||
labels: '状态:待处理'
|
||||
|
||||
- name: Remove require reply label
|
||||
uses: actions-cool/issues-helper@v2
|
||||
with:
|
||||
actions: 'remove-labels'
|
||||
labels: '状态:待用户反馈'
|
||||
|
||||
add-label-if-not-author:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ (github.event.issue.user.id != github.event.comment.user.id) && (!github.event.issue.pull_request) && (github.event.issue.state == 'open') }}
|
||||
steps:
|
||||
- name: Add require replay label
|
||||
uses: actions-cool/issues-helper@v2
|
||||
with:
|
||||
actions: 'add-labels'
|
||||
labels: '状态:待用户反馈'
|
||||
|
||||
- name: Remove require handle label
|
||||
uses: actions-cool/issues-helper@v2
|
||||
with:
|
||||
actions: 'remove-labels'
|
||||
labels: '状态:待处理'
|
||||
@@ -0,0 +1,16 @@
|
||||
name: Issue Open Check
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: [opened]
|
||||
|
||||
jobs:
|
||||
issue-open-add-labels:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Add labels
|
||||
uses: actions-cool/issues-helper@v2
|
||||
if: ${{ !github.event.issue.pull_request }}
|
||||
with:
|
||||
actions: 'add-labels'
|
||||
labels: '状态:待处理'
|
||||
@@ -0,0 +1,17 @@
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 1 * * *"
|
||||
|
||||
name: Check recent handle issues
|
||||
|
||||
jobs:
|
||||
check-recent-issues-not-handle:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check recent issues and send msg
|
||||
uses: jumpserver/action-issues-alert@master
|
||||
with:
|
||||
hook: ${{ secrets.WECHAT_GROUP_WEB_HOOK }}
|
||||
type: recent
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -0,0 +1,17 @@
|
||||
on:
|
||||
schedule:
|
||||
- cron: "0 9 * * 1-5"
|
||||
|
||||
name: Check untimely handle issues
|
||||
|
||||
jobs:
|
||||
check-untimely-handle-issues:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check untimely issues and send msg
|
||||
uses: jumpserver/action-issues-alert@master
|
||||
with:
|
||||
hook: ${{ secrets.WECHAT_GROUP_WEB_HOOK }}
|
||||
type: untimely
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -22,5 +22,4 @@ cmd/server/__debug_bin
|
||||
cmd/server/web/assets
|
||||
cmd/server/web/monacoeditorwork
|
||||
cmd/server/web/index.html
|
||||
cmd/server/web/favicon.png
|
||||
frontend/auto-imports.d.ts
|
||||
|
||||
@@ -16,7 +16,7 @@ build_web:
|
||||
|
||||
build_bin:
|
||||
cd $(SERVER_PATH) \
|
||||
&& CGO_ENABLED=1 GOOS=$(GOOS) GOARCH=$(GOARCH) $(GOBUILD) -trimpath -ldflags '-s -w --extldflags "-static -fpic"' -o $(BUILD_PATH)/$(APP_NAME) $(MAIN)
|
||||
&& CGO_ENABLED=1 GOOS=$(GOOS) GOARCH=$(GOARCH) $(GOBUILD) -trimpath -ldflags '-s -w --extldflags "-static -fpic"' -tags osusergo -o $(BUILD_PATH)/$(APP_NAME) $(MAIN)
|
||||
|
||||
build_linux_on_mac:
|
||||
cd $(SERVER_PATH) \
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
reviewers:
|
||||
- zhengkunwang223
|
||||
- ssongliu
|
||||
- wanghe-fit2cloud
|
||||
- wangdan-fit2cloud
|
||||
|
||||
approvers:
|
||||
- zhengkunwang223
|
||||
- ssongliu
|
||||
- wanghe-fit2cloud
|
||||
- wangdan-fit2cloud
|
||||
@@ -11,8 +11,8 @@
|
||||
|
||||
1Panel 是一个现代化、开源的 Linux 服务器运维管理面板。1Panel 的功能和优势包括:
|
||||
|
||||
- **快速建站**:深度集成 Wordpress 和 Halo,域名绑定、SSL 证书配置等一键搞定;
|
||||
- **高效管理**:通过 Web 端轻松管理 Linux 服务器,包括主机监控、文件管理、数据库管理、容器管理及常用应用软件管理;
|
||||
- **快速建站**:深度集成 Wordpress 和 [Halo](https://github.com/halo-dev/halo/),域名绑定、SSL 证书配置等一键搞定;
|
||||
- **高效管理**:通过 Web 端轻松管理 Linux 服务器,包括应用管理、主机监控、文件管理、数据库管理、容器管理等;
|
||||
- **安全可靠**:最小漏洞暴露面,提供防火墙和安全审计等功能;
|
||||
- **一键备份**:支持一键备份和恢复,备份数据云端存储,永不丢失。
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
**一键安装**
|
||||
|
||||
以 root 用户执行如下命令一键安装 1Panel:
|
||||
执行如下命令一键安装 1Panel:
|
||||
|
||||
```sh
|
||||
curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_start.sh && sudo bash quick_start.sh
|
||||
@@ -39,7 +39,7 @@ curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_
|
||||
**学习资料**
|
||||
|
||||
- [在线文档](https://1panel.cn/docs/)
|
||||
- [入门视频](https://1panel.cn/video.html)
|
||||
- [教学视频](https://space.bilibili.com/510493147/channel/collectiondetail?sid=1199760)
|
||||
|
||||
## 社区
|
||||
|
||||
@@ -56,6 +56,10 @@ curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_
|
||||
- 邮箱:support@fit2cloud.com
|
||||
- 电话:400-052-0755
|
||||
|
||||
## Star History
|
||||
|
||||
[](https://star-history.com/#1Panel-dev/1Panel&Date)
|
||||
|
||||
## License
|
||||
|
||||
Copyright (c) 2014-2023 飞致云 FIT2CLOUD, All rights reserved.
|
||||
|
||||
@@ -128,3 +128,18 @@ func (b *BaseApi) GetAppTags(c *gin.Context) {
|
||||
}
|
||||
helper.SuccessWithData(c, tags)
|
||||
}
|
||||
|
||||
// @Tags App
|
||||
// @Summary Get app list update
|
||||
// @Description 获取应用更新版本
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /apps/checkupdate [get]
|
||||
func (b *BaseApi) GetAppListUpdate(c *gin.Context) {
|
||||
res, err := appService.GetAppUpdate()
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, res)
|
||||
}
|
||||
|
||||
@@ -167,6 +167,15 @@ func (b *BaseApi) InitUserInfo(c *gin.Context) {
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
// @Tags Auth
|
||||
// @Summary Check System isDemo
|
||||
// @Description 判断是否为demo环境
|
||||
// @Success 200
|
||||
// @Router /auth/demo [get]
|
||||
func (b *BaseApi) CheckIsDemo(c *gin.Context) {
|
||||
helper.SuccessWithData(c, global.CONF.System.IsDemo)
|
||||
}
|
||||
|
||||
func saveLoginLogs(c *gin.Context, err error) {
|
||||
var logs model.LoginLog
|
||||
if err != nil {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
@@ -27,6 +29,23 @@ func (b *BaseApi) CreateBackup(c *gin.Context) {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
if len(req.Credential) != 0 {
|
||||
credential, err := base64.StdEncoding.DecodeString(req.Credential)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
req.Credential = string(credential)
|
||||
}
|
||||
if len(req.AccessKey) != 0 {
|
||||
accessKey, err := base64.StdEncoding.DecodeString(req.AccessKey)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
req.AccessKey = string(accessKey)
|
||||
}
|
||||
|
||||
if err := backupService.Create(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
@@ -52,6 +71,23 @@ func (b *BaseApi) ListBuckets(c *gin.Context) {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
if len(req.Credential) != 0 {
|
||||
credential, err := base64.StdEncoding.DecodeString(req.Credential)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
req.Credential = string(credential)
|
||||
}
|
||||
if len(req.AccessKey) != 0 {
|
||||
accessKey, err := base64.StdEncoding.DecodeString(req.AccessKey)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
req.AccessKey = string(accessKey)
|
||||
}
|
||||
|
||||
buckets, err := backupService.GetBuckets(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
@@ -139,7 +175,7 @@ func (b *BaseApi) DownloadRecord(c *gin.Context) {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
c.File(filePath)
|
||||
helper.SuccessWithData(c, filePath)
|
||||
}
|
||||
|
||||
// @Tags Backup Account
|
||||
@@ -188,6 +224,23 @@ func (b *BaseApi) UpdateBackup(c *gin.Context) {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
if len(req.Credential) != 0 {
|
||||
credential, err := base64.StdEncoding.DecodeString(req.Credential)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
req.Credential = string(credential)
|
||||
}
|
||||
if len(req.AccessKey) != 0 {
|
||||
accessKey, err := base64.StdEncoding.DecodeString(req.AccessKey)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
req.AccessKey = string(accessKey)
|
||||
}
|
||||
|
||||
if err := backupService.Update(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
|
||||
@@ -198,7 +198,7 @@ func (b *BaseApi) TargetDownload(c *gin.Context) {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
}
|
||||
c.File(filePath)
|
||||
helper.SuccessWithData(c, filePath)
|
||||
}
|
||||
|
||||
// @Tags Cronjob
|
||||
|
||||
@@ -2,6 +2,7 @@ package v1
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
@@ -29,6 +30,15 @@ func (b *BaseApi) CreateMysql(c *gin.Context) {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
if len(req.Password) != 0 {
|
||||
password, err := base64.StdEncoding.DecodeString(req.Password)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
req.Password = string(password)
|
||||
}
|
||||
|
||||
if _, err := mysqlService.Create(context.Background(), req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
@@ -81,6 +91,15 @@ func (b *BaseApi) ChangeMysqlPassword(c *gin.Context) {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
if len(req.Value) != 0 {
|
||||
value, err := base64.StdEncoding.DecodeString(req.Value)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
req.Value = string(value)
|
||||
}
|
||||
|
||||
if err := mysqlService.ChangePassword(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
|
||||
@@ -2,6 +2,7 @@ package v1
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
@@ -106,6 +107,15 @@ func (b *BaseApi) ChangeRedisPassword(c *gin.Context) {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
if len(req.Value) != 0 {
|
||||
value, err := base64.StdEncoding.DecodeString(req.Value)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
req.Value = string(value)
|
||||
}
|
||||
|
||||
if err := redisService.ChangePassword(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
|
||||
+129
-5
@@ -3,6 +3,14 @@ package v1
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
|
||||
@@ -10,14 +18,10 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||
websocket2 "github.com/1Panel-dev/1Panel/backend/utils/websocket"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gorilla/websocket"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// @Tags File
|
||||
@@ -441,6 +445,28 @@ func (b *BaseApi) Download(c *gin.Context) {
|
||||
c.File(filePath)
|
||||
}
|
||||
|
||||
// @Tags File
|
||||
// @Summary Download file with path
|
||||
// @Description 下载指定文件
|
||||
// @Accept json
|
||||
// @Param request body request.FilePath true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /files/download/bypath [post]
|
||||
// @x-panel-log {"bodyKeys":["path"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"下载文件 [path]","formatEN":"Download file [path]"}
|
||||
func (b *BaseApi) DownloadFile(c *gin.Context) {
|
||||
var req dto.FilePath
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
if err := global.VALID.Struct(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
c.File(req.Path)
|
||||
}
|
||||
|
||||
// @Tags File
|
||||
// @Summary Load file size
|
||||
// @Description 获取文件夹大小
|
||||
@@ -492,6 +518,104 @@ func (b *BaseApi) LoadFromFile(c *gin.Context) {
|
||||
helper.SuccessWithData(c, string(content))
|
||||
}
|
||||
|
||||
func mergeChunks(fileName string, fileDir string, dstDir string, chunkCount int) error {
|
||||
targetFile, err := os.Create(filepath.Join(dstDir, fileName))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer targetFile.Close()
|
||||
|
||||
for i := 0; i < chunkCount; i++ {
|
||||
chunkPath := filepath.Join(fileDir, fmt.Sprintf("%s.%d", fileName, i))
|
||||
chunkData, err := ioutil.ReadFile(chunkPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = targetFile.Write(chunkData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return files.NewFileOp().DeleteDir(fileDir)
|
||||
}
|
||||
|
||||
// @Tags File
|
||||
// @Summary ChunkUpload file
|
||||
// @Description 分片上传文件
|
||||
// @Param file formData file true "request"
|
||||
// @Success 200
|
||||
// @Security ApiKeyAuth
|
||||
// @Router /files/chunkupload [post]
|
||||
// @x-panel-log {"bodyKeys":["path"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"上传文件 [path]","formatEN":"Upload file [path]"}
|
||||
func (b *BaseApi) UploadChunkFiles(c *gin.Context) {
|
||||
fileForm, err := c.FormFile("chunk")
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
uploadFile, err := fileForm.Open()
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
|
||||
chunkIndex, err := strconv.Atoi(c.PostForm("chunkIndex"))
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
|
||||
chunkCount, err := strconv.Atoi(c.PostForm("chunkCount"))
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
|
||||
fileOp := files.NewFileOp()
|
||||
if err := fileOp.CreateDir("uploads", 0755); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
//fileID := uuid.New().String()
|
||||
filename := c.PostForm("filename")
|
||||
fileDir := filepath.Join(global.CONF.System.DataDir, "upload", filename)
|
||||
|
||||
_ = os.MkdirAll(fileDir, 0755)
|
||||
filePath := filepath.Join(fileDir, filename)
|
||||
|
||||
emptyFile, err := os.Create(filePath)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
emptyFile.Close()
|
||||
|
||||
chunkData, err := ioutil.ReadAll(uploadFile)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
|
||||
chunkPath := filepath.Join(fileDir, fmt.Sprintf("%s.%d", filename, chunkIndex))
|
||||
err = ioutil.WriteFile(chunkPath, chunkData, 0644)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
|
||||
if chunkIndex+1 == chunkCount {
|
||||
err = mergeChunks(filename, fileDir, c.PostForm("path"), chunkCount)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrAppDelete, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, true)
|
||||
} else {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var wsUpgrade = websocket.Upgrader{
|
||||
CheckOrigin: func(r *http.Request) bool {
|
||||
return true
|
||||
|
||||
@@ -1,111 +0,0 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func mergeChunks(fileName string, fileDir string, dstDir string, chunkCount int) error {
|
||||
//fileInfoList, err := ioutil.ReadDir(fileDir)
|
||||
//if err != nil {
|
||||
// return err
|
||||
//}
|
||||
|
||||
targetFile, err := os.Create(filepath.Join(dstDir, fileName))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer targetFile.Close()
|
||||
|
||||
for i := 0; i < chunkCount; i++ {
|
||||
chunkPath := filepath.Join(fileDir, fmt.Sprintf("%s.%d", fileName, i))
|
||||
chunkData, err := ioutil.ReadFile(chunkPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = targetFile.Write(chunkData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return files.NewFileOp().DeleteDir(fileDir)
|
||||
}
|
||||
|
||||
func (b *BaseApi) UploadChunkFiles(c *gin.Context) {
|
||||
fileForm, err := c.FormFile("chunk")
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
uploadFile, err := fileForm.Open()
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
|
||||
chunkIndex, err := strconv.Atoi(c.PostForm("chunkIndex"))
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
|
||||
chunkCount, err := strconv.Atoi(c.PostForm("chunkCount"))
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
|
||||
fileOp := files.NewFileOp()
|
||||
if err := fileOp.CreateDir("uploads", 0755); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
//fileID := uuid.New().String()
|
||||
filename := c.PostForm("filename")
|
||||
fileDir := filepath.Join(global.CONF.System.DataDir, "upload", filename)
|
||||
|
||||
_ = os.MkdirAll(fileDir, 0755)
|
||||
filePath := filepath.Join(fileDir, filename)
|
||||
|
||||
emptyFile, err := os.Create(filePath)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
emptyFile.Close()
|
||||
|
||||
chunkData, err := ioutil.ReadAll(uploadFile)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
|
||||
chunkPath := filepath.Join(fileDir, fmt.Sprintf("%s.%d", filename, chunkIndex))
|
||||
err = ioutil.WriteFile(chunkPath, chunkData, 0644)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
|
||||
if chunkIndex+1 == chunkCount {
|
||||
err = mergeChunks(filename, fileDir, c.PostForm("path"), chunkCount)
|
||||
if err != nil {
|
||||
fmt.Println(err.Error())
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrAppDelete, err)
|
||||
return
|
||||
}
|
||||
helper.SuccessWithData(c, true)
|
||||
} else {
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
@@ -29,6 +31,23 @@ func (b *BaseApi) CreateHost(c *gin.Context) {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
if req.AuthMode == "password" && len(req.Password) != 0 {
|
||||
password, err := base64.StdEncoding.DecodeString(req.Password)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
req.Password = string(password)
|
||||
}
|
||||
if req.AuthMode == "key" && len(req.PrivateKey) != 0 {
|
||||
privateKey, err := base64.StdEncoding.DecodeString(req.PrivateKey)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
req.PrivateKey = string(privateKey)
|
||||
}
|
||||
|
||||
host, err := hostService.Create(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
@@ -55,17 +74,32 @@ func (b *BaseApi) TestByInfo(c *gin.Context) {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
if req.AuthMode == "password" && len(req.Password) != 0 {
|
||||
password, err := base64.StdEncoding.DecodeString(req.Password)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
req.Password = string(password)
|
||||
}
|
||||
if req.AuthMode == "key" && len(req.PrivateKey) != 0 {
|
||||
privateKey, err := base64.StdEncoding.DecodeString(req.PrivateKey)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
req.PrivateKey = string(privateKey)
|
||||
}
|
||||
|
||||
var connInfo ssh.ConnInfo
|
||||
if err := copier.Copy(&connInfo, &req); err != nil {
|
||||
helper.SuccessWithData(c, false)
|
||||
}
|
||||
_ = copier.Copy(&connInfo, &req)
|
||||
connInfo.PrivateKey = []byte(req.PrivateKey)
|
||||
client, err := connInfo.NewClient()
|
||||
if err != nil {
|
||||
helper.SuccessWithData(c, false)
|
||||
return
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
helper.SuccessWithData(c, true)
|
||||
}
|
||||
|
||||
@@ -212,6 +246,22 @@ func (b *BaseApi) UpdateHost(c *gin.Context) {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
if req.AuthMode == "password" && len(req.Password) != 0 {
|
||||
password, err := base64.StdEncoding.DecodeString(req.Password)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
req.Password = string(password)
|
||||
}
|
||||
if req.AuthMode == "key" && len(req.PrivateKey) != 0 {
|
||||
privateKey, err := base64.StdEncoding.DecodeString(req.PrivateKey)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
req.PrivateKey = string(privateKey)
|
||||
}
|
||||
|
||||
upMap := make(map[string]interface{})
|
||||
upMap["name"] = req.Name
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/copier"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/ssh"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/terminal"
|
||||
@@ -39,10 +40,8 @@ func (b *BaseApi) WsSsh(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
var connInfo ssh.ConnInfo
|
||||
if err := copier.Copy(&connInfo, &host); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, constant.ErrStructTransform)
|
||||
return
|
||||
}
|
||||
_ = copier.Copy(&connInfo, &host)
|
||||
connInfo.PrivateKey = []byte(host.PrivateKey)
|
||||
|
||||
wsConn, err := upGrader.Upgrade(c.Writer, c.Request, nil)
|
||||
if err != nil {
|
||||
@@ -156,6 +155,15 @@ func (b *BaseApi) ContainerWsSsh(c *gin.Context) {
|
||||
}
|
||||
defer wsConn.Close()
|
||||
|
||||
cmds := fmt.Sprintf("docker exec %s %s", containerID, command)
|
||||
if len(user) != 0 {
|
||||
cmds = fmt.Sprintf("docker exec -u %s %s %s", user, containerID, command)
|
||||
}
|
||||
stdout, err := cmd.Exec(cmds)
|
||||
if wshandleError(wsConn, errors.WithMessage(err, stdout)) {
|
||||
return
|
||||
}
|
||||
|
||||
commands := fmt.Sprintf("docker exec -it %s %s", containerID, command)
|
||||
if len(user) != 0 {
|
||||
commands = fmt.Sprintf("docker exec -it -u %s %s %s", user, containerID, command)
|
||||
@@ -187,8 +195,8 @@ func wshandleError(ws *websocket.Conn, err error) bool {
|
||||
if err != nil {
|
||||
global.LOG.Errorf("handler ws faled:, err: %v", err)
|
||||
dt := time.Now().Add(time.Second)
|
||||
if err := ws.WriteControl(websocket.CloseMessage, []byte(err.Error()), dt); err != nil {
|
||||
global.LOG.Errorf("websocket writes control message failed, err: %v", err)
|
||||
if ctlerr := ws.WriteControl(websocket.CloseMessage, []byte(err.Error()), dt); ctlerr != nil {
|
||||
_ = ws.WriteMessage(websocket.TextMessage, []byte(err.Error()))
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ type ContainerInfo struct {
|
||||
State string `json:"state"`
|
||||
RunTime string `json:"runTime"`
|
||||
|
||||
IsFromApp bool `json:"isFromApp"`
|
||||
IsFromCompose bool `json:"isFromCompose"`
|
||||
}
|
||||
|
||||
@@ -129,7 +130,7 @@ type ComposeContainer struct {
|
||||
State string `json:"state"`
|
||||
}
|
||||
type ComposeCreate struct {
|
||||
Name string `json:"name" validate:"required"`
|
||||
Name string `json:"name"`
|
||||
From string `json:"from" validate:"required,oneof=edit path template"`
|
||||
File string `json:"file"`
|
||||
Path string `json:"path"`
|
||||
|
||||
@@ -8,7 +8,7 @@ type HostOperate struct {
|
||||
ID uint `json:"id"`
|
||||
GroupID uint `json:"groupID"`
|
||||
Name string `json:"name"`
|
||||
Addr string `json:"addr" validate:"required,ip"`
|
||||
Addr string `json:"addr" validate:"required"`
|
||||
Port uint `json:"port" validate:"required,number,max=65535,min=1"`
|
||||
User string `json:"user" validate:"required"`
|
||||
AuthMode string `json:"authMode" validate:"oneof=password key"`
|
||||
@@ -19,7 +19,7 @@ type HostOperate struct {
|
||||
}
|
||||
|
||||
type HostConnTest struct {
|
||||
Addr string `json:"addr" validate:"required,ip"`
|
||||
Addr string `json:"addr" validate:"required"`
|
||||
Port uint `json:"port" validate:"required,number,max=65535,min=1"`
|
||||
User string `json:"user" validate:"required"`
|
||||
AuthMode string `json:"authMode" validate:"oneof=password key"`
|
||||
|
||||
@@ -24,7 +24,7 @@ type ICronjobRepo interface {
|
||||
Update(id uint, vars map[string]interface{}) error
|
||||
Delete(opts ...DBOption) error
|
||||
DeleteRecord(opts ...DBOption) error
|
||||
StartRecords(cronjobID uint, targetPath string) model.JobRecords
|
||||
StartRecords(cronjobID uint, fromLocal bool, targetPath string) model.JobRecords
|
||||
EndRecords(record model.JobRecords, status, message, records string)
|
||||
}
|
||||
|
||||
@@ -112,10 +112,11 @@ func (c *CronjobRepo) WithByJobID(id int) DBOption {
|
||||
}
|
||||
}
|
||||
|
||||
func (u *CronjobRepo) StartRecords(cronjobID uint, targetPath string) model.JobRecords {
|
||||
func (u *CronjobRepo) StartRecords(cronjobID uint, fromLocal bool, targetPath string) model.JobRecords {
|
||||
var record model.JobRecords
|
||||
record.StartTime = time.Now()
|
||||
record.CronjobID = cronjobID
|
||||
record.FromLocal = fromLocal
|
||||
record.Status = constant.StatusWaiting
|
||||
if err := global.DB.Create(&record).Error; err != nil {
|
||||
global.LOG.Errorf("create record status failed, err: %v", err)
|
||||
|
||||
@@ -19,6 +19,7 @@ type IMysqlRepo interface {
|
||||
Delete(ctx context.Context, opts ...DBOption) error
|
||||
Update(id uint, vars map[string]interface{}) error
|
||||
UpdateDatabaseInfo(id uint, vars map[string]interface{}) error
|
||||
DeleteAll(ctx context.Context) error
|
||||
}
|
||||
|
||||
func NewIMysqlRepo() IMysqlRepo {
|
||||
@@ -65,6 +66,10 @@ func (u *MysqlRepo) Delete(ctx context.Context, opts ...DBOption) error {
|
||||
return getTx(ctx, opts...).Delete(&model.DatabaseMysql{}).Error
|
||||
}
|
||||
|
||||
func (u *MysqlRepo) DeleteAll(ctx context.Context) error {
|
||||
return getTx(ctx).Where("1 = 1").Delete(&model.DatabaseMysql{}).Error
|
||||
}
|
||||
|
||||
func (u *MysqlRepo) Update(id uint, vars map[string]interface{}) error {
|
||||
return global.DB.Model(&model.DatabaseMysql{}).Where("id = ?", id).Updates(vars).Error
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ type IAppService interface {
|
||||
GetAppDetail(appId uint, version string) (response.AppDetailDTO, error)
|
||||
Install(ctx context.Context, req request.AppInstallCreate) (*model.AppInstall, error)
|
||||
SyncAppList() error
|
||||
GetAppUpdate() (*response.AppUpdateRes, error)
|
||||
}
|
||||
|
||||
func NewIAppService() IAppService {
|
||||
|
||||
@@ -275,16 +275,14 @@ func (a AppInstallService) SyncAll() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
go func() {
|
||||
for _, i := range allList {
|
||||
if i.Status == constant.Installing {
|
||||
continue
|
||||
}
|
||||
if err := syncById(i.ID); err != nil {
|
||||
global.LOG.Errorf("sync install app[%s] error,mgs: %s", i.Name, err.Error())
|
||||
}
|
||||
for _, i := range allList {
|
||||
if i.Status == constant.Installing {
|
||||
continue
|
||||
}
|
||||
}()
|
||||
if err := syncById(i.ID); err != nil {
|
||||
global.LOG.Errorf("sync install app[%s] error,mgs: %s", i.Name, err.Error())
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -4,8 +4,6 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/repo"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/env"
|
||||
"math"
|
||||
"os"
|
||||
"path"
|
||||
@@ -13,6 +11,9 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/repo"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/env"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto/response"
|
||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||
|
||||
@@ -159,7 +160,10 @@ func deleteAppInstall(ctx context.Context, install model.AppInstall, deleteBacku
|
||||
global.LOG.Infof("delete app %s-%s backups successful", install.App.Key, install.Name)
|
||||
}
|
||||
_ = backupRepo.DeleteRecord(ctx, commonRepo.WithByType("app"), commonRepo.WithByName(install.App.Key), backupRepo.WithByDetailName(install.Name))
|
||||
|
||||
_ = backupRepo.DeleteRecord(ctx, commonRepo.WithByType(install.App.Key))
|
||||
if install.App.Key == constant.AppMysql {
|
||||
_ = mysqlRepo.DeleteAll(ctx)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -134,7 +134,7 @@ func (u *BackupService) DownloadRecord(info dto.DownloadRecord) (string, error)
|
||||
tempPath := fmt.Sprintf("%sdownload%s", constant.DataDir, info.FileDir)
|
||||
if _, err := os.Stat(tempPath); err != nil && os.IsNotExist(err) {
|
||||
if err = os.MkdirAll(tempPath, os.ModePerm); err != nil {
|
||||
fmt.Println(err)
|
||||
global.LOG.Errorf("mkdir %s failed, err: %v", tempPath, err)
|
||||
}
|
||||
}
|
||||
targetPath := tempPath + info.FileName
|
||||
@@ -222,6 +222,12 @@ func (u *BackupService) Update(req dto.BackupOperate) error {
|
||||
if err := json.Unmarshal([]byte(req.Vars), &varMap); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
oldVars := backup.Vars
|
||||
oldDir, err := loadLocalDir()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
upMap := make(map[string]interface{})
|
||||
upMap["bucket"] = req.Bucket
|
||||
upMap["credential"] = req.Credential
|
||||
@@ -235,9 +241,8 @@ func (u *BackupService) Update(req dto.BackupOperate) error {
|
||||
if strings.HasSuffix(dirStr, "/") {
|
||||
dirStr = dirStr[:strings.LastIndex(dirStr, "/")]
|
||||
}
|
||||
if err := updateBackupDir(dirStr); err != nil {
|
||||
upMap["vars"] = backup.Vars
|
||||
_ = backupRepo.Update(req.ID, upMap)
|
||||
if err := updateBackupDir(dirStr, oldDir); err != nil {
|
||||
_ = backupRepo.Update(req.ID, (map[string]interface{}{"vars": oldVars}))
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -309,8 +314,7 @@ func loadLocalDir() (string, error) {
|
||||
return "", fmt.Errorf("error type dir: %T", varMap["dir"])
|
||||
}
|
||||
|
||||
func updateBackupDir(dir string) error {
|
||||
oldDir := global.CONF.System.Backup
|
||||
func updateBackupDir(dir, oldDir string) error {
|
||||
if _, err := os.Stat(dir); err != nil && os.IsNotExist(err) {
|
||||
if err = os.MkdirAll(dir, os.ModePerm); err != nil {
|
||||
return err
|
||||
@@ -323,6 +327,5 @@ func updateBackupDir(dir string) error {
|
||||
if err != nil {
|
||||
return errors.New(string(stdout))
|
||||
}
|
||||
global.CONF.System.Backup = dir
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ func handleAppBackup(install *model.AppInstall, backupDir, fileName string) erro
|
||||
}
|
||||
|
||||
resource, _ := appInstallResourceRepo.GetFirst(appInstallResourceRepo.WithAppInstallId(install.ID))
|
||||
if resource.ID != 0 {
|
||||
if resource.ID != 0 && resource.ResourceId != 0 {
|
||||
mysqlInfo, err := appInstallRepo.LoadBaseInfo(constant.AppMysql, "")
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -181,16 +181,19 @@ func handleAppRecover(install *model.AppInstall, recoverFile string, isRollback
|
||||
return err
|
||||
}
|
||||
if err := handleMysqlRecover(mysqlInfo, tmpPath, db.Name, fmt.Sprintf("%s.sql.gz", install.Name), true); err != nil {
|
||||
global.LOG.Errorf("handle recover from sql.gz failed, err: %v", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := handleUnTar(tmpPath+"/app.tar.gz", fmt.Sprintf("%s/%s", constant.AppInstallDir, install.App.Key)); err != nil {
|
||||
global.LOG.Errorf("handle recover from app.tar.gz failed, err: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
oldInstall.Status = constant.Running
|
||||
if err := appInstallRepo.Save(install); err != nil {
|
||||
global.LOG.Errorf("save db app install failed, err: %v", err)
|
||||
return err
|
||||
}
|
||||
isOk = true
|
||||
|
||||
@@ -121,7 +121,10 @@ func handleRedisRecover(redisInfo *repo.RootInfo, recoverFile string, isRollback
|
||||
}
|
||||
|
||||
if appendonly == "yes" {
|
||||
if !strings.HasSuffix(recoverFile, ".tar.gz") || !strings.HasSuffix(recoverFile, ".aof") {
|
||||
if redisInfo.Version == "6.0.16" && !strings.HasSuffix(recoverFile, ".aof") {
|
||||
return buserr.New(constant.ErrTypeOfRedis)
|
||||
}
|
||||
if redisInfo.Version == "7.0.5" && !strings.HasSuffix(recoverFile, ".tar.gz") {
|
||||
return buserr.New(constant.ErrTypeOfRedis)
|
||||
}
|
||||
} else {
|
||||
@@ -170,7 +173,7 @@ func handleRedisRecover(redisInfo *repo.RootInfo, recoverFile string, isRollback
|
||||
}
|
||||
} else {
|
||||
itemName := "dump.rdb"
|
||||
if redisInfo.Version == "6.0.16" {
|
||||
if appendonly == "yes" && redisInfo.Version == "6.0.16" {
|
||||
itemName = "appendonly.aof"
|
||||
}
|
||||
input, err := ioutil.ReadFile(recoverFile)
|
||||
@@ -184,5 +187,6 @@ func handleRedisRecover(redisInfo *repo.RootInfo, recoverFile string, isRollback
|
||||
if _, err := compose.Up(composeDir + "/docker-compose.yml"); err != nil {
|
||||
return err
|
||||
}
|
||||
isOk = true
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -106,8 +106,8 @@ func handleWebsiteRecover(website *model.Website, recoverFile string, isRollback
|
||||
return fmt.Errorf("backup website %s for rollback before recover failed, err: %v", website.Alias, err)
|
||||
}
|
||||
defer func() {
|
||||
global.LOG.Info("recover failed, start to rollback now")
|
||||
if !isOk {
|
||||
global.LOG.Info("recover failed, start to rollback now")
|
||||
if err := handleWebsiteRecover(website, rollbackFile, true); err != nil {
|
||||
global.LOG.Errorf("rollback website %s from %s failed, err: %v", website.Alias, rollbackFile, err)
|
||||
return
|
||||
@@ -126,6 +126,7 @@ func handleWebsiteRecover(website *model.Website, recoverFile string, isRollback
|
||||
}
|
||||
nginxConfPath := fmt.Sprintf("%s/openresty/%s/conf/conf.d", constant.AppInstallDir, nginxInfo.Name)
|
||||
if err := fileOp.CopyFile(fmt.Sprintf("%s/%s.conf", tmpPath, website.Alias), nginxConfPath); err != nil {
|
||||
global.LOG.Errorf("handle recover from conf.d failed, err: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -135,22 +136,27 @@ func handleWebsiteRecover(website *model.Website, recoverFile string, isRollback
|
||||
return err
|
||||
}
|
||||
if err := handleAppRecover(&app, fmt.Sprintf("%s/%s.app.tar.gz", tmpPath, website.Alias), true); err != nil {
|
||||
global.LOG.Errorf("handle recover from app.tar.gz failed, err: %v", err)
|
||||
return err
|
||||
}
|
||||
if _, err := compose.Restart(fmt.Sprintf("%s/%s/%s/docker-compose.yml", constant.AppInstallDir, app.App.Key, app.Name)); err != nil {
|
||||
global.LOG.Errorf("docker-compose restart failed, err: %v", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
siteDir := fmt.Sprintf("%s/openresty/%s/www/sites", constant.AppInstallDir, nginxInfo.Name)
|
||||
if err := handleUnTar(fmt.Sprintf("%s/%s.web.tar.gz", tmpPath, website.Alias), siteDir); err != nil {
|
||||
global.LOG.Errorf("handle recover from web.tar.gz failed, err: %v", err)
|
||||
return err
|
||||
}
|
||||
stdout, err := cmd.Execf("docker exec -i %s nginx -s reload", nginxInfo.ContainerName)
|
||||
if err != nil {
|
||||
global.LOG.Errorf("nginx -s reload failed, err: %s", stdout)
|
||||
return errors.New(string(stdout))
|
||||
}
|
||||
|
||||
if err := websiteRepo.SaveWithoutCtx(&oldWebsite); err != nil {
|
||||
global.LOG.Errorf("handle save website data failed, err: %v", err)
|
||||
return err
|
||||
}
|
||||
isOk = true
|
||||
|
||||
@@ -12,8 +12,10 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/docker"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
@@ -96,6 +98,10 @@ func (u *ContainerService) Page(req dto.PageContainer) (int64, interface{}, erro
|
||||
if _, ok := container.Labels[composeProjectLabel]; ok {
|
||||
IsFromCompose = true
|
||||
}
|
||||
IsFromApp := false
|
||||
if created, ok := container.Labels[composeCreatedBy]; ok && created == "Apps" {
|
||||
IsFromApp = true
|
||||
}
|
||||
backDatas = append(backDatas, dto.ContainerInfo{
|
||||
ContainerID: container.ID,
|
||||
CreateTime: time.Unix(container.Created, 0).Format("2006-01-02 15:04:05"),
|
||||
@@ -104,6 +110,7 @@ func (u *ContainerService) Page(req dto.PageContainer) (int64, interface{}, erro
|
||||
ImageName: container.Image,
|
||||
State: container.State,
|
||||
RunTime: container.Status,
|
||||
IsFromApp: IsFromApp,
|
||||
IsFromCompose: IsFromCompose,
|
||||
})
|
||||
}
|
||||
@@ -136,6 +143,13 @@ func (u *ContainerService) Inspect(req dto.InspectReq) (string, error) {
|
||||
}
|
||||
|
||||
func (u *ContainerService) ContainerCreate(req dto.ContainerCreate) error {
|
||||
if len(req.ExposedPorts) != 0 {
|
||||
for _, port := range req.ExposedPorts {
|
||||
if common.ScanPort(port.HostPort) {
|
||||
return buserr.WithDetail(constant.ErrPortInUsed, port.HostPort, nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
client, err := docker.NewDockerClient()
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -152,11 +153,16 @@ func (u *ContainerService) CreateCompose(req dto.ComposeCreate) error {
|
||||
req.Path = path
|
||||
}
|
||||
global.LOG.Infof("docker-compose.yml %s create successful, start to docker-compose up", req.Name)
|
||||
if stdout, err := compose.Up(req.Path); err != nil {
|
||||
return errors.New(string(stdout))
|
||||
}
|
||||
|
||||
if req.From == "path" {
|
||||
req.Name = path.Base(strings.ReplaceAll(req.Path, "/docker-compose.yml", ""))
|
||||
}
|
||||
if stdout, err := compose.Up(req.Path); err != nil {
|
||||
_, _ = compose.Down(req.Path)
|
||||
return errors.New(stdout)
|
||||
}
|
||||
_ = composeRepo.CreateRecord(&model.Compose{Name: req.Name})
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -170,7 +176,7 @@ func (u *ContainerService) ComposeOperation(req dto.ComposeOperation) error {
|
||||
global.LOG.Infof("docker-compose %s %s successful", req.Operation, req.Name)
|
||||
if req.Operation == "down" {
|
||||
_ = composeRepo.DeleteRecord(commonRepo.WithByName(req.Name))
|
||||
_ = os.RemoveAll(strings.ReplaceAll(req.Path, req.Name+"/docker-compose.yml", ""))
|
||||
_ = os.RemoveAll(strings.ReplaceAll(req.Path, "/docker-compose.yml", ""))
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -7,6 +7,8 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/docker"
|
||||
"github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
@@ -80,6 +82,9 @@ func (u *ContainerService) DeleteNetwork(req dto.BatchDelete) error {
|
||||
}
|
||||
for _, id := range req.Names {
|
||||
if err := client.NetworkRemove(context.TODO(), id); err != nil {
|
||||
if strings.Contains(err.Error(), "has active endpoints") {
|
||||
return buserr.WithDetail(constant.ErrInUsed, id, nil)
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,12 @@ package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/docker"
|
||||
"github.com/docker/docker/api/types"
|
||||
@@ -96,6 +96,9 @@ func (u *ContainerService) DeleteVolume(req dto.BatchDelete) error {
|
||||
}
|
||||
for _, id := range req.Names {
|
||||
if err := client.VolumeRemove(context.TODO(), id, true); err != nil {
|
||||
if strings.Contains(err.Error(), "volume is in use") {
|
||||
return buserr.WithDetail(constant.ErrInUsed, id, nil)
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -122,12 +125,8 @@ func (u *ContainerService) CreateVolume(req dto.VolumeCreat) error {
|
||||
DriverOpts: stringsToMap(req.Options),
|
||||
Labels: stringsToMap(req.Labels),
|
||||
}
|
||||
stat, err := client.VolumeCreate(context.TODO(), options)
|
||||
if err != nil {
|
||||
if _, err := client.VolumeCreate(context.TODO(), options); err != nil {
|
||||
return err
|
||||
}
|
||||
// if len(stat.CreatedAt) != 0 {
|
||||
fmt.Println(stat)
|
||||
// }
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -2,17 +2,14 @@ package service
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/cloud_storage"
|
||||
"github.com/jinzhu/copier"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/robfig/cron/v3"
|
||||
@@ -92,69 +89,28 @@ func (u *CronjobService) Download(down dto.CronjobDownload) (string, error) {
|
||||
if cronjob.ID == 0 {
|
||||
return "", constant.ErrRecordNotFound
|
||||
}
|
||||
|
||||
global.LOG.Infof("start to download records %s from %s", cronjob.Type, backup.Type)
|
||||
varMap := make(map[string]interface{})
|
||||
if err := json.Unmarshal([]byte(backup.Vars), &varMap); err != nil {
|
||||
if backup.Type == "LOCAL" {
|
||||
if _, err := os.Stat(record.File); err != nil && os.IsNotExist(err) {
|
||||
return "", constant.ErrRecordNotFound
|
||||
}
|
||||
return record.File, nil
|
||||
}
|
||||
if record.FromLocal {
|
||||
local, _ := loadLocalDir()
|
||||
if _, err := os.Stat(local + "/" + record.File); err == nil {
|
||||
return local + "/" + record.File, nil
|
||||
}
|
||||
}
|
||||
client, err := NewIBackupService().NewClient(&backup)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
varMap["type"] = backup.Type
|
||||
if backup.Type != "LOCAL" {
|
||||
varMap["bucket"] = backup.Bucket
|
||||
switch backup.Type {
|
||||
case constant.Sftp:
|
||||
varMap["username"] = backup.AccessKey
|
||||
varMap["password"] = backup.Credential
|
||||
case constant.OSS, constant.S3, constant.MinIo:
|
||||
varMap["accessKey"] = backup.AccessKey
|
||||
varMap["secretKey"] = backup.Credential
|
||||
}
|
||||
backClient, err := cloud_storage.NewCloudStorageClient(varMap)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("new cloud storage client failed, err: %v", err)
|
||||
}
|
||||
global.LOG.Info("new backup client successful")
|
||||
commonDir := fmt.Sprintf("%s/%s/", cronjob.Type, cronjob.Name)
|
||||
name := fmt.Sprintf("%s%s.tar.gz", commonDir, record.StartTime.Format("20060102150405"))
|
||||
if cronjob.Type == "database" {
|
||||
name = fmt.Sprintf("%s%s.gz", commonDir, record.StartTime.Format("20060102150405"))
|
||||
}
|
||||
tempPath := fmt.Sprintf("%s/download/%s", constant.DataDir, commonDir)
|
||||
if _, err := os.Stat(tempPath); err != nil && os.IsNotExist(err) {
|
||||
if err = os.MkdirAll(tempPath, os.ModePerm); err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
global.LOG.Infof("download records %s from %s to %s", name, commonDir, tempPath)
|
||||
targetPath := tempPath + strings.ReplaceAll(name, commonDir, "")
|
||||
if _, err = os.Stat(targetPath); err != nil && os.IsNotExist(err) {
|
||||
isOK, err := backClient.Download(name, targetPath)
|
||||
if !isOK {
|
||||
return "", fmt.Errorf("cloud storage download failed, err: %v", err)
|
||||
}
|
||||
}
|
||||
return targetPath, nil
|
||||
}
|
||||
if _, ok := varMap["dir"]; !ok {
|
||||
return "", errors.New("load local backup dir failed")
|
||||
}
|
||||
global.LOG.Infof("record is save in local dir %s", varMap["dir"])
|
||||
|
||||
switch cronjob.Type {
|
||||
case "website":
|
||||
return fmt.Sprintf("%v/website/%s/website_%s_%s.tar.gz", varMap["dir"], cronjob.Website, cronjob.Website, record.StartTime.Format("20060102150405")), nil
|
||||
case "database":
|
||||
mysqlInfo, err := appInstallRepo.LoadBaseInfo("mysql", "")
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("load mysqlInfo failed, err: %v", err)
|
||||
}
|
||||
return fmt.Sprintf("%v/database/mysql/%s/%s/db_%s_%s.sql.gz", varMap["dir"], mysqlInfo.Name, cronjob.DBName, cronjob.DBName, record.StartTime.Format("20060102150405")), nil
|
||||
case "directory":
|
||||
return fmt.Sprintf("%v/%s/%s/directory%s_%s.tar.gz", varMap["dir"], cronjob.Type, cronjob.Name, strings.ReplaceAll(cronjob.SourceDir, "/", "_"), record.StartTime.Format("20060102150405")), nil
|
||||
default:
|
||||
return "", fmt.Errorf("not support type %s", cronjob.Type)
|
||||
tempPath := fmt.Sprintf("%s/download/%s", constant.DataDir, record.File)
|
||||
isOK, _ := client.Download(record.File, tempPath)
|
||||
if !isOK || err != nil {
|
||||
return "", constant.ErrRecordNotFound
|
||||
}
|
||||
return tempPath, nil
|
||||
}
|
||||
|
||||
func (u *CronjobService) HandleOnce(id uint) error {
|
||||
@@ -178,24 +134,27 @@ func (u *CronjobService) Create(cronjobDto dto.CronjobCreate) error {
|
||||
cronjob.Spec = loadSpec(cronjob)
|
||||
|
||||
global.LOG.Infof("create cronjob %s successful, spec: %s", cronjob.Name, cronjob.Spec)
|
||||
if err := u.StartJob(&cronjob); err != nil {
|
||||
entryID, err := u.StartJob(&cronjob)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cronjob.EntryID = uint64(entryID)
|
||||
if err := cronjobRepo.Create(&cronjob); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (u *CronjobService) StartJob(cronjob *model.Cronjob) error {
|
||||
global.Cron.Remove(cron.EntryID(cronjob.EntryID))
|
||||
global.LOG.Infof("stop cronjob entryID: %d", cronjob.EntryID)
|
||||
func (u *CronjobService) StartJob(cronjob *model.Cronjob) (int, error) {
|
||||
if cronjob.EntryID != 0 {
|
||||
global.Cron.Remove(cron.EntryID(cronjob.EntryID))
|
||||
}
|
||||
entryID, err := u.AddCronJob(cronjob)
|
||||
if err != nil {
|
||||
return err
|
||||
return 0, err
|
||||
}
|
||||
_ = cronjobRepo.Update(cronjob.ID, map[string]interface{}{"entry_id": entryID})
|
||||
return nil
|
||||
global.LOG.Debug(global.Cron.Entries())
|
||||
return entryID, nil
|
||||
}
|
||||
|
||||
func (u *CronjobService) Delete(ids []uint) error {
|
||||
@@ -225,12 +184,15 @@ func (u *CronjobService) Update(id uint, req dto.CronjobUpdate) error {
|
||||
return constant.ErrRecordNotFound
|
||||
}
|
||||
cronjob.EntryID = cronModel.EntryID
|
||||
cronjob.Type = cronModel.Type
|
||||
cronjob.Spec = loadSpec(cronjob)
|
||||
if err := u.StartJob(&cronjob); err != nil {
|
||||
newEntryID, err := u.StartJob(&cronjob)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
upMap := make(map[string]interface{})
|
||||
upMap["entry_id"] = newEntryID
|
||||
upMap["name"] = req.Name
|
||||
upMap["script"] = req.Script
|
||||
upMap["spec_type"] = req.SpecType
|
||||
@@ -254,15 +216,20 @@ func (u *CronjobService) UpdateStatus(id uint, status string) error {
|
||||
if cronjob.ID == 0 {
|
||||
return errors.WithMessage(constant.ErrRecordNotFound, "record not found")
|
||||
}
|
||||
var (
|
||||
entryID int
|
||||
err error
|
||||
)
|
||||
if status == constant.StatusEnable {
|
||||
if err := u.StartJob(&cronjob); err != nil {
|
||||
entryID, err = u.StartJob(&cronjob)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
global.Cron.Remove(cron.EntryID(cronjob.EntryID))
|
||||
global.LOG.Infof("stop cronjob entryID: %d", cronjob.EntryID)
|
||||
}
|
||||
return cronjobRepo.Update(cronjob.ID, map[string]interface{}{"status": status})
|
||||
return cronjobRepo.Update(cronjob.ID, map[string]interface{}{"status": status, "entry_id": entryID})
|
||||
}
|
||||
|
||||
func (u *CronjobService) AddCronJob(cronjob *model.Cronjob) (int, error) {
|
||||
|
||||
@@ -22,8 +22,7 @@ func (u *CronjobService) HandleJob(cronjob *model.Cronjob) {
|
||||
message []byte
|
||||
err error
|
||||
)
|
||||
record := cronjobRepo.StartRecords(cronjob.ID, "")
|
||||
record.FromLocal = cronjob.KeepLocal
|
||||
record := cronjobRepo.StartRecords(cronjob.ID, cronjob.KeepLocal, "")
|
||||
go func() {
|
||||
switch cronjob.Type {
|
||||
case "shell":
|
||||
@@ -118,6 +117,8 @@ func (u *CronjobService) HandleBackup(cronjob *model.Cronjob, startTime time.Tim
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
itemFileDir := strings.ReplaceAll(backupDir, localDir+"/", "")
|
||||
if len(record.Name) != 0 {
|
||||
record.FileName = fileName
|
||||
record.FileDir = backupDir
|
||||
@@ -125,7 +126,7 @@ func (u *CronjobService) HandleBackup(cronjob *model.Cronjob, startTime time.Tim
|
||||
record.BackupType = backup.Type
|
||||
if !cronjob.KeepLocal && backup.Type != "LOCAL" {
|
||||
record.Source = backup.Type
|
||||
record.FileDir = strings.ReplaceAll(backupDir, localDir+"/", "")
|
||||
record.FileDir = itemFileDir
|
||||
}
|
||||
if err := backupRepo.CreateRecord(&record); err != nil {
|
||||
global.LOG.Errorf("save backup record failed, err: %v", err)
|
||||
@@ -133,7 +134,10 @@ func (u *CronjobService) HandleBackup(cronjob *model.Cronjob, startTime time.Tim
|
||||
}
|
||||
}
|
||||
|
||||
fullPath := fmt.Sprintf("%s/%s", record.FileDir, fileName)
|
||||
fullPath := fmt.Sprintf("%s/%s", backupDir, fileName)
|
||||
if backup.Type != "LOCAL" {
|
||||
fullPath = fmt.Sprintf("%s/%s", itemFileDir, fileName)
|
||||
}
|
||||
if backup.Type == "LOCAL" {
|
||||
u.HandleRmExpired(backup.Type, backupDir, cronjob, nil)
|
||||
return fullPath, nil
|
||||
@@ -148,10 +152,13 @@ func (u *CronjobService) HandleBackup(cronjob *model.Cronjob, startTime time.Tim
|
||||
if err != nil {
|
||||
return fullPath, err
|
||||
}
|
||||
if _, err = client.Upload(backupDir+"/"+fileName, fullPath); err != nil {
|
||||
if _, err = client.Upload(backupDir+"/"+fileName, itemFileDir+"/"+fileName); err != nil {
|
||||
return fullPath, err
|
||||
}
|
||||
u.HandleRmExpired(backup.Type, backupDir, cronjob, client)
|
||||
u.HandleRmExpired(backup.Type, itemFileDir, cronjob, client)
|
||||
if cronjob.KeepLocal {
|
||||
u.HandleRmExpired("LOCAL", backupDir, cronjob, client)
|
||||
}
|
||||
return fullPath, nil
|
||||
}
|
||||
|
||||
@@ -185,9 +192,7 @@ func (u *CronjobService) HandleRmExpired(backType, backupDir string, cronjob *mo
|
||||
for i := 0; i < len(currentObjs)-int(cronjob.RetainCopies); i++ {
|
||||
_, _ = backClient.Delete(currentObjs[i].(string))
|
||||
}
|
||||
if !cronjob.KeepLocal {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
files, err := ioutil.ReadDir(backupDir)
|
||||
if err != nil {
|
||||
|
||||
@@ -292,7 +292,7 @@ func (u *MysqlService) ChangeAccess(info dto.ChangeDBInfo) error {
|
||||
if err := excuteSql(app.ContainerName, app.Password, fmt.Sprintf("create user if not exists '%s'@'%s' identified by '%s';", mysql.Username, info.Value, mysql.Password)); err != nil {
|
||||
return err
|
||||
}
|
||||
grantStr := fmt.Sprintf("grant all privileges on %s.* to '%s'@'%s'", mysql.Name, mysql.Username, info.Value)
|
||||
grantStr := fmt.Sprintf("grant all privileges on `%s`.* to '%s'@'%s'", mysql.Name, mysql.Username, info.Value)
|
||||
if app.Version == "5.7.39" {
|
||||
grantStr = fmt.Sprintf("%s identified by '%s' with grant option;", grantStr, mysql.Password)
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ func (f FileService) Create(op request.FileCreate) error {
|
||||
return fo.CreateDir(op.Path, fs.FileMode(op.Mode))
|
||||
} else {
|
||||
if op.IsLink {
|
||||
if !fo.Stat(op.Path) {
|
||||
if !fo.Stat(op.LinkPath) {
|
||||
return buserr.New(constant.ErrLinkPathNotFound)
|
||||
}
|
||||
return fo.LinkFile(op.LinkPath, op.Path, op.IsSymlink)
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/buserr"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/docker"
|
||||
@@ -122,7 +123,7 @@ func (u *ImageService) ImageBuild(req dto.ImageBuild) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
if req.From == "edit" {
|
||||
dir := fmt.Sprintf("%s/docker/build/%s", constant.DataDir, req.Name)
|
||||
dir := fmt.Sprintf("%s/docker/build/%s", constant.DataDir, strings.ReplaceAll(req.Name, ":", "_"))
|
||||
if _, err := os.Stat(dir); err != nil && os.IsNotExist(err) {
|
||||
if err = os.MkdirAll(dir, os.ModePerm); err != nil {
|
||||
return "", err
|
||||
@@ -139,6 +140,8 @@ func (u *ImageService) ImageBuild(req dto.ImageBuild) (string, error) {
|
||||
_, _ = write.WriteString(string(req.Dockerfile))
|
||||
write.Flush()
|
||||
req.Dockerfile = dir
|
||||
} else {
|
||||
req.Dockerfile = strings.ReplaceAll(req.Dockerfile, "/Dockerfile", "")
|
||||
}
|
||||
tar, err := archive.TarWithOptions(req.Dockerfile+"/", &archive.TarOptions{})
|
||||
if err != nil {
|
||||
@@ -161,13 +164,27 @@ func (u *ImageService) ImageBuild(req dto.ImageBuild) (string, error) {
|
||||
go func() {
|
||||
defer file.Close()
|
||||
defer tar.Close()
|
||||
res, err := client.ImageBuild(context.TODO(), tar, opts)
|
||||
res, err := client.ImageBuild(context.Background(), tar, opts)
|
||||
if err != nil {
|
||||
global.LOG.Errorf("build image %s failed, err: %v", req.Name, err)
|
||||
_, _ = file.WriteString("image build failed!")
|
||||
return
|
||||
}
|
||||
defer res.Body.Close()
|
||||
body, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
global.LOG.Errorf("build image %s failed, err: %v", req.Name, err)
|
||||
_, _ = file.WriteString(fmt.Sprintf("build image %s failed, err: %v", req.Name, err))
|
||||
_, _ = file.WriteString("image build failed!")
|
||||
return
|
||||
}
|
||||
|
||||
if strings.Contains(string(body), "error") && strings.Contains(string(body), "failed:") {
|
||||
global.LOG.Errorf("build image %s failed", req.Name)
|
||||
_, _ = file.Write(body)
|
||||
_, _ = file.WriteString("image build failed!")
|
||||
return
|
||||
}
|
||||
global.LOG.Infof("build image %s successful!", req.Name)
|
||||
_, _ = io.Copy(file, res.Body)
|
||||
_, _ = file.WriteString("image build successful!")
|
||||
@@ -362,8 +379,14 @@ func (u *ImageService) ImageRemove(req dto.BatchDelete) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, ids := range req.Names {
|
||||
if _, err := client.ImageRemove(context.TODO(), ids, types.ImageRemoveOptions{Force: true, PruneChildren: true}); err != nil {
|
||||
for _, id := range req.Names {
|
||||
if _, err := client.ImageRemove(context.TODO(), id, types.ImageRemoveOptions{Force: true, PruneChildren: true}); err != nil {
|
||||
if strings.Contains(err.Error(), "image is being used") {
|
||||
if strings.Contains(id, "sha256:") {
|
||||
return buserr.New(constant.ErrObjectInUsed)
|
||||
}
|
||||
return buserr.WithDetail(constant.ErrInUsed, id, nil)
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,12 +4,15 @@ import (
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||
"github.com/jinzhu/copier"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type LogService struct{}
|
||||
|
||||
const logs = "https://resource.fit2cloud.com/installation-log.sh"
|
||||
|
||||
type ILogService interface {
|
||||
CreateLoginLog(operation model.LoginLog) error
|
||||
PageLoginLog(search dto.SearchLgLogWithPage) (int64, interface{}, error)
|
||||
@@ -77,3 +80,7 @@ func (u *LogService) CleanLogs(logtype string) error {
|
||||
}
|
||||
return logRepo.CleanLogin()
|
||||
}
|
||||
|
||||
func writeLogs(version string) {
|
||||
_, _ = cmd.Execf("curl -sfL %s | sh -s 1p upgrade %s", logs, version)
|
||||
}
|
||||
|
||||
@@ -172,17 +172,17 @@ func (u *SnapshotService) SnapshotCreate(req dto.SnapshotCreate) error {
|
||||
return
|
||||
}
|
||||
|
||||
if err := u.handlePanelDatas(snap.ID, fileOp, "snapshot", global.CONF.BaseDir+"/1panel", backupPanelDir, localDir, dockerDataDir); err != nil {
|
||||
if err := u.handlePanelDatas(snap.ID, fileOp, "snapshot", global.CONF.System.BaseDir+"/1panel", backupPanelDir, localDir, dockerDataDir); err != nil {
|
||||
updateSnapshotStatus(snap.ID, constant.StatusFailed, err.Error())
|
||||
return
|
||||
}
|
||||
_, _ = cmd.Exec("systemctl restart docker")
|
||||
|
||||
snapJson := SnapshotJson{
|
||||
BaseDir: global.CONF.BaseDir,
|
||||
BaseDir: global.CONF.System.BaseDir,
|
||||
DockerDataDir: dockerDataDir,
|
||||
BackupDataDir: localDir,
|
||||
PanelDataDir: global.CONF.BaseDir + "/1panel",
|
||||
PanelDataDir: global.CONF.System.BaseDir + "/1panel",
|
||||
LiveRestoreEnabled: liveRestoreStatus,
|
||||
}
|
||||
if err := u.saveJson(snapJson, rootDir); err != nil {
|
||||
@@ -287,8 +287,8 @@ func (u *SnapshotService) SnapshotRecover(req dto.SnapshotRecover) error {
|
||||
u.OriginalPath = fmt.Sprintf("%s/original_%s", snapJson.BaseDir, snap.Name)
|
||||
_ = os.MkdirAll(u.OriginalPath, os.ModePerm)
|
||||
|
||||
snapJson.OldBaseDir = global.CONF.BaseDir
|
||||
snapJson.OldPanelDataDir = global.CONF.BaseDir + "/1panel"
|
||||
snapJson.OldBaseDir = global.CONF.System.BaseDir
|
||||
snapJson.OldPanelDataDir = global.CONF.System.BaseDir + "/1panel"
|
||||
snapJson.OldBackupDataDir = localDir
|
||||
recoverPanelDir := fmt.Sprintf("%s/%s/1panel", baseDir, snap.Name)
|
||||
liveRestore := false
|
||||
|
||||
@@ -6,13 +6,13 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/common"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||
)
|
||||
|
||||
@@ -43,8 +43,8 @@ func (u *UpgradeService) SearchUpgrade() (*dto.UpgradeInfo, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
isNew, err := compareVersion(currentVersion.Value, string(version))
|
||||
if !isNew || err != nil {
|
||||
isNew := common.CompareVersion(string(version), currentVersion.Value)
|
||||
if !isNew {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ func (u *UpgradeService) Upgrade(req dto.Upgrade) error {
|
||||
fileName := fmt.Sprintf("1panel-%s-%s-%s.tar.gz", req.Version, "linux", runtime.GOARCH)
|
||||
_ = settingRepo.Update("SystemStatus", "Upgrading")
|
||||
go func() {
|
||||
if err := fileOp.DownloadFile(downloadPath+"/"+fileName, rootDir+"/service.tar.gz"); err != nil {
|
||||
if err := fileOp.DownloadFile(downloadPath+"/"+fileName, rootDir+"/"+fileName); err != nil {
|
||||
global.LOG.Errorf("download service file failed, err: %v", err)
|
||||
_ = settingRepo.Update("SystemStatus", "Free")
|
||||
return
|
||||
@@ -90,11 +90,12 @@ func (u *UpgradeService) Upgrade(req dto.Upgrade) error {
|
||||
defer func() {
|
||||
_ = os.Remove(rootDir)
|
||||
}()
|
||||
if err := fileOp.Decompress(rootDir+"/service.tar.gz", rootDir, files.TarGz); err != nil {
|
||||
if err := handleUnTar(rootDir+"/"+fileName, rootDir); err != nil {
|
||||
global.LOG.Errorf("decompress file failed, err: %v", err)
|
||||
_ = settingRepo.Update("SystemStatus", "Free")
|
||||
return
|
||||
}
|
||||
tmpDir := rootDir + "/" + strings.ReplaceAll(fileName, ".tar.gz", "")
|
||||
|
||||
if err := u.handleBackup(fileOp, originalDir); err != nil {
|
||||
global.LOG.Errorf("handle backup original file failed, err: %v", err)
|
||||
@@ -103,23 +104,31 @@ func (u *UpgradeService) Upgrade(req dto.Upgrade) error {
|
||||
}
|
||||
global.LOG.Info("backup original data successful, now start to upgrade!")
|
||||
|
||||
if err := cpBinary(rootDir+"/1panel", "/usr/local/bin/1panel"); err != nil {
|
||||
if err := cpBinary(tmpDir+"/1panel", "/usr/local/bin/1panel"); err != nil {
|
||||
u.handleRollback(fileOp, originalDir, 1)
|
||||
global.LOG.Errorf("upgrade 1panel failed, err: %v", err)
|
||||
return
|
||||
}
|
||||
if err := cpBinary(fmt.Sprintf("%s/1panel-online-installer-%s/1pctl", rootDir, req.Version), "/usr/local/bin/1pctl"); err != nil {
|
||||
|
||||
if err := cpBinary(tmpDir+"/1pctl", "/usr/local/bin/1pctl"); err != nil {
|
||||
u.handleRollback(fileOp, originalDir, 2)
|
||||
global.LOG.Errorf("upgrade 1pctl failed, err: %v", err)
|
||||
return
|
||||
}
|
||||
if err := cpBinary(fmt.Sprintf("%s/1panel-online-installer-%s/1panel/conf/1panel.service", rootDir, req.Version), "/etc/systemd/system/1panel.service"); err != nil {
|
||||
if _, err := cmd.Execf("sed -i -e 's#BASE_DIR=.*#BASE_DIR=%s#g' /usr/local/bin/1pctl", global.CONF.System.BaseDir); err != nil {
|
||||
u.handleRollback(fileOp, originalDir, 2)
|
||||
global.LOG.Errorf("upgrade basedir in 1pctl failed, err: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := cpBinary(tmpDir+"/1panel.service", "/etc/systemd/system/1panel.service"); err != nil {
|
||||
u.handleRollback(fileOp, originalDir, 3)
|
||||
global.LOG.Errorf("upgrade 1panel.service failed, err: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
global.LOG.Info("upgrade successful!")
|
||||
go writeLogs(req.Version)
|
||||
_ = settingRepo.Update("SystemVersion", req.Version)
|
||||
_ = settingRepo.Update("SystemStatus", "Free")
|
||||
_, _ = cmd.Exec("systemctl daemon-reload && systemctl restart 1panel.service")
|
||||
@@ -167,43 +176,3 @@ func (u *UpgradeService) handleRollback(fileOp files.FileOp, originalDir string,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func compareVersion(version, newVersion string) (bool, error) {
|
||||
if version == newVersion {
|
||||
return false, nil
|
||||
}
|
||||
if len(version) == 0 || len(newVersion) == 0 {
|
||||
return false, fmt.Errorf("incorrect version or new version entered %v -- %v", version, newVersion)
|
||||
}
|
||||
versions := strings.Split(strings.ReplaceAll(version, "v", ""), ".")
|
||||
if len(versions) != 3 {
|
||||
return false, fmt.Errorf("incorrect version input %v", version)
|
||||
}
|
||||
newVersions := strings.Split(strings.ReplaceAll(newVersion, "v", ""), ".")
|
||||
if len(newVersions) != 3 {
|
||||
return false, fmt.Errorf("incorrect newVersions input %v", version)
|
||||
}
|
||||
version1, _ := strconv.Atoi(versions[0])
|
||||
newVersion1, _ := strconv.Atoi(newVersions[0])
|
||||
if newVersion1 > version1 {
|
||||
return true, nil
|
||||
} else if newVersion1 == version1 {
|
||||
version2, _ := strconv.Atoi(versions[1])
|
||||
newVersion2, _ := strconv.Atoi(newVersions[1])
|
||||
if newVersion2 > version2 {
|
||||
return true, nil
|
||||
} else if newVersion2 == version2 {
|
||||
version3, _ := strconv.Atoi(versions[2])
|
||||
newVersion3, _ := strconv.Atoi(newVersions[2])
|
||||
if newVersion3 > version3 {
|
||||
return true, nil
|
||||
} else {
|
||||
return false, nil
|
||||
}
|
||||
} else {
|
||||
return false, nil
|
||||
}
|
||||
} else {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,6 +99,10 @@ func (w WebsiteSSLService) Create(create request.WebsiteSSLCreate) (request.Webs
|
||||
if err := client.UseHTTP(path.Join(constant.AppInstallDir, constant.AppOpenresty, appInstall.Name, "root")); err != nil {
|
||||
return res, err
|
||||
}
|
||||
case constant.DnsManual:
|
||||
if err := client.UseManualDns(); err != nil {
|
||||
return res, err
|
||||
}
|
||||
}
|
||||
|
||||
domains := []string{create.PrimaryDomain}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package configs
|
||||
|
||||
type ServerConfig struct {
|
||||
BaseDir string `mapstructure:"base_dir"`
|
||||
System System `mapstructure:"system"`
|
||||
LogConfig LogConfig `mapstructure:"log"`
|
||||
}
|
||||
|
||||
@@ -13,5 +13,6 @@ type System struct {
|
||||
BaseDir string `mapstructure:"base_dir"`
|
||||
Mode string `mapstructure:"mode"`
|
||||
RepoUrl string `mapstructure:"repo_url"`
|
||||
Version string `mapstructure:"version"`
|
||||
IsDemo bool `mapstructure:"is_demo"`
|
||||
}
|
||||
|
||||
@@ -95,3 +95,9 @@ var (
|
||||
var (
|
||||
ErrTypeOfRedis = "ErrTypeOfRedis"
|
||||
)
|
||||
|
||||
//container
|
||||
var (
|
||||
ErrInUsed = "ErrInUsed"
|
||||
ErrObjectInUsed = "ErrObjectInUsed"
|
||||
)
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/app/model"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/repo"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/service"
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
"github.com/1Panel-dev/1Panel/backend/cron/job"
|
||||
@@ -44,8 +45,12 @@ func Run() {
|
||||
global.LOG.Errorf("start my cronjob failed, err: %v", err)
|
||||
}
|
||||
for _, cronjob := range cronJobs {
|
||||
if err := service.ServiceGroupApp.StartJob(&cronjob); err != nil {
|
||||
entryID, err := service.ServiceGroupApp.StartJob(&cronjob)
|
||||
if err != nil {
|
||||
global.LOG.Errorf("start %s job %s failed, err: %v", cronjob.Type, cronjob.Name, err)
|
||||
}
|
||||
if err := repo.NewICronjobRepo().Update(cronjob.ID, map[string]interface{}{"entry_id": entryID}); err != nil {
|
||||
global.LOG.Errorf("update cronjob %s %s failed, err: %v", cronjob.Type, cronjob.Name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,4 +52,8 @@ ErrUserIsExist: "The current user already exists. Please enter a new user"
|
||||
ErrDatabaseIsExist: "The current database already exists. Please enter a new database"
|
||||
|
||||
#redis
|
||||
ErrTypeOfRedis: "The recovery file type does not match the current persistence mode. Modify the file type and try again"
|
||||
ErrTypeOfRedis: "The recovery file type does not match the current persistence mode. Modify the file type and try again"
|
||||
|
||||
#container
|
||||
ErrInUsed: "{{ .detail }} is in use and cannot be deleted"
|
||||
ErrObjectInUsed: "This object is in use and cannot be deleted"
|
||||
@@ -52,4 +52,8 @@ ErrUserIsExist: "当前用户已存在,请重新输入"
|
||||
ErrDatabaseIsExist: "当前数据库已存在,请重新输入"
|
||||
|
||||
#redis
|
||||
ErrTypeOfRedis: "恢复文件类型与当前持久化方式不符,请修改后重试"
|
||||
ErrTypeOfRedis: "恢复文件类型与当前持久化方式不符,请修改后重试"
|
||||
|
||||
#container
|
||||
ErrInUsed: "{{ .detail }} 正被使用,无法删除"
|
||||
ErrObjectInUsed: "该对象正被使用,无法删除"
|
||||
@@ -1,7 +1,6 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/constant"
|
||||
@@ -35,12 +34,12 @@ func createDir(fileOp files.FileOp, dirPath string) {
|
||||
func createDefaultDockerNetwork() {
|
||||
cli, err := docker.NewClient()
|
||||
if err != nil {
|
||||
fmt.Println("init docker client error", err.Error())
|
||||
global.LOG.Errorf("init docker client error", err.Error())
|
||||
return
|
||||
}
|
||||
if !cli.NetworkExist("1panel-network") {
|
||||
if err := cli.CreateNetwork("1panel-network"); err != nil {
|
||||
fmt.Println("init docker client error", err.Error())
|
||||
global.LOG.Errorf("init docker client error", err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package business
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/1Panel-dev/1Panel/backend/app/service"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
)
|
||||
@@ -13,7 +12,6 @@ func Init() {
|
||||
return
|
||||
}
|
||||
if setting.AppStoreVersion != "" {
|
||||
fmt.Println(setting.AppStoreVersion)
|
||||
global.LOG.Info("do not sync")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ var AddTableSetting = &gormigrate.Migration{
|
||||
if err := tx.Create(&model.Setting{Key: "DingVars", Value: ""}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Create(&model.Setting{Key: "SystemVersion", Value: "v1.0.0"}).Error; err != nil {
|
||||
if err := tx.Create(&model.Setting{Key: "SystemVersion", Value: global.CONF.System.Version}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tx.Create(&model.Setting{Key: "SystemStatus", Value: "Free"}).Error; err != nil {
|
||||
|
||||
+22
-19
@@ -20,6 +20,7 @@ func Init() {
|
||||
baseDir := "/opt"
|
||||
port := "9999"
|
||||
mode := ""
|
||||
version := ""
|
||||
fileOp := files.NewFileOp()
|
||||
v := viper.NewWithOptions()
|
||||
v.SetConfigType("yaml")
|
||||
@@ -38,23 +39,9 @@ func Init() {
|
||||
panic(fmt.Errorf("Fatal error config file: %s \n", err))
|
||||
}
|
||||
} else {
|
||||
stdout, err := cmd.Exec("grep '^BASE_DIR=' /usr/bin/1pctl | cut -d'=' -f2")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
baseDir = strings.ReplaceAll(stdout, "\n", "")
|
||||
if len(baseDir) == 0 {
|
||||
panic("error `BASE_DIR` find in /usr/bin/1pctl")
|
||||
}
|
||||
|
||||
stdoutPort, err := cmd.Exec("grep '^PANEL_PORT=' /usr/bin/1pctl | cut -d'=' -f2")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
port = strings.ReplaceAll(stdoutPort, "\n", "")
|
||||
if len(port) == 0 {
|
||||
panic("error `PANEL_PORT` find in /usr/bin/1pctl")
|
||||
}
|
||||
baseDir = loadParams("BASE_DIR")
|
||||
port = loadParams("PANEL_PORT")
|
||||
version = loadParams("ORIGINAL_INSTALLED_VERSION")
|
||||
|
||||
if strings.HasSuffix(baseDir, "/") {
|
||||
baseDir = baseDir[:strings.LastIndex(baseDir, "/")]
|
||||
@@ -79,16 +66,32 @@ func Init() {
|
||||
if mode == "dev" && fileOp.Stat("/opt/1panel/conf/app.yaml") && serverConfig.System.Port != "" {
|
||||
port = serverConfig.System.Port
|
||||
}
|
||||
if mode == "dev" && fileOp.Stat("/opt/1panel/conf/app.yaml") && serverConfig.System.Version != "" {
|
||||
version = serverConfig.System.Version
|
||||
}
|
||||
|
||||
global.CONF = serverConfig
|
||||
global.CONF.BaseDir = baseDir
|
||||
global.CONF.System.BaseDir = baseDir
|
||||
global.CONF.System.IsDemo = v.GetBool("system.is_demo")
|
||||
global.CONF.System.DataDir = global.CONF.BaseDir + "/1panel"
|
||||
global.CONF.System.DataDir = global.CONF.System.BaseDir + "/1panel"
|
||||
global.CONF.System.Cache = global.CONF.System.DataDir + "/cache"
|
||||
global.CONF.System.Backup = global.CONF.System.DataDir + "/backup"
|
||||
global.CONF.System.DbPath = global.CONF.System.DataDir + "/db"
|
||||
global.CONF.System.LogPath = global.CONF.System.DataDir + "/log"
|
||||
global.CONF.System.TmpDir = global.CONF.System.DataDir + "/tmp"
|
||||
global.CONF.System.Port = port
|
||||
global.CONF.System.Version = version
|
||||
global.Viper = v
|
||||
}
|
||||
|
||||
func loadParams(param string) string {
|
||||
stdout, err := cmd.Execf("grep '^%s=' /usr/bin/1pctl | cut -d'=' -f2", param)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
baseDir := strings.ReplaceAll(stdout, "\n", "")
|
||||
if len(baseDir) == 0 {
|
||||
panic(fmt.Sprintf("error `%s` find in /usr/bin/1pctl", param))
|
||||
}
|
||||
return baseDir
|
||||
}
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
package log
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
@@ -14,6 +11,9 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
"github.com/1Panel-dev/1Panel/backend/utils/files"
|
||||
)
|
||||
|
||||
type Writer struct {
|
||||
@@ -261,7 +261,6 @@ func (w *Writer) CompressFile(logFile string) error {
|
||||
comFileName := path.Base(logFile) + ".gz"
|
||||
filePath := path.Dir(logFile)
|
||||
|
||||
fmt.Println(path.Dir(logFile))
|
||||
if err := op.Compress([]string{logFile}, filePath, comFileName, files.Gz); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -96,7 +96,6 @@ func OperationLog() gin.HandlerFunc {
|
||||
var names []string
|
||||
if funcs.IsList {
|
||||
sql := fmt.Sprintf("SELECT %s FROM %s where %s in (?);", funcs.OutputColume, funcs.DB, funcs.InputColume)
|
||||
fmt.Println(value)
|
||||
_ = global.DB.Raw(sql, value).Scan(&names)
|
||||
} else {
|
||||
_ = global.DB.Raw(fmt.Sprintf("select %s from %s where %s = ?;", funcs.OutputColume, funcs.DB, funcs.InputColume), value).Scan(&names)
|
||||
|
||||
@@ -16,6 +16,7 @@ func (a *AppRouter) InitAppRouter(Router *gin.RouterGroup) {
|
||||
baseApi := v1.ApiGroupApp.BaseApi
|
||||
{
|
||||
appRouter.POST("/sync", baseApi.SyncApp)
|
||||
appRouter.GET("/checkupdate", baseApi.GetAppListUpdate)
|
||||
appRouter.POST("/search", baseApi.SearchApp)
|
||||
appRouter.GET("/:key", baseApi.GetApp)
|
||||
appRouter.GET("/detail/:appId/:version", baseApi.GetAppDetail)
|
||||
|
||||
@@ -17,5 +17,6 @@ func (s *BaseRouter) InitBaseRouter(Router *gin.RouterGroup) {
|
||||
baseRouter.GET("/status", baseApi.CheckIsFirstLogin)
|
||||
baseRouter.POST("/init", baseApi.InitUserInfo)
|
||||
baseRouter.POST("/logout", baseApi.LogOut)
|
||||
baseRouter.GET("/demo", baseApi.CheckIsDemo)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,11 +26,13 @@ func (f *FileRouter) InitFileRouter(Router *gin.RouterGroup) {
|
||||
fileRouter.POST("/content", baseApi.GetContent)
|
||||
fileRouter.POST("/save", baseApi.SaveContent)
|
||||
fileRouter.POST("/check", baseApi.CheckFile)
|
||||
fileRouter.POST("/upload", baseApi.UploadChunkFiles)
|
||||
fileRouter.POST("/upload", baseApi.UploadFiles)
|
||||
fileRouter.POST("/chunkupload", baseApi.UploadChunkFiles)
|
||||
fileRouter.POST("/rename", baseApi.ChangeFileName)
|
||||
fileRouter.POST("/wget", baseApi.WgetFile)
|
||||
fileRouter.POST("/move", baseApi.MoveFile)
|
||||
fileRouter.POST("/download", baseApi.Download)
|
||||
fileRouter.POST("/download/bypath", baseApi.DownloadFile)
|
||||
fileRouter.POST("/size", baseApi.Size)
|
||||
fileRouter.GET("/ws", baseApi.Ws)
|
||||
fileRouter.GET("/keys", baseApi.Keys)
|
||||
|
||||
@@ -19,8 +19,8 @@ func (s *SettingRouter) InitSettingRouter(Router *gin.RouterGroup) {
|
||||
baseApi := v1.ApiGroupApp.BaseApi
|
||||
{
|
||||
router.POST("/search", baseApi.GetSettingInfo)
|
||||
router.POST("/expired/handle", baseApi.HandlePasswordExpired)
|
||||
settingRouter.GET("/search/available", baseApi.GetSystemAvailable)
|
||||
settingRouter.POST("/expired/handle", baseApi.HandlePasswordExpired)
|
||||
settingRouter.POST("/update", baseApi.UpdateSetting)
|
||||
settingRouter.POST("/port/update", baseApi.UpdatePort)
|
||||
settingRouter.POST("/password/update", baseApi.UpdatePassword)
|
||||
|
||||
@@ -77,7 +77,7 @@ func (oss ossClient) Upload(src, target string) (bool, error) {
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
err = bucket.PutObjectFromFile(target, src)
|
||||
err = bucket.UploadFile(target, src, 200*1024*1024, osssdk.Routines(5), osssdk.Checkpoint(true, ""))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
@@ -89,7 +89,7 @@ func (oss ossClient) Download(src, target string) (bool, error) {
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
err = bucket.GetObjectToFile(src, target)
|
||||
err = bucket.DownloadFile(src, target, 200*1024*1024, osssdk.Routines(5), osssdk.Checkpoint(true, ""))
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
)
|
||||
|
||||
func Up(filePath string) (string, error) {
|
||||
stdout, err := cmd.Execf("docker-compose -f %s up -d", filePath)
|
||||
stdout, err := cmd.Execf("docker-compose -f %s up -d --quiet-pull", filePath)
|
||||
return stdout, err
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package files
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"bufio"
|
||||
"context"
|
||||
"encoding/json"
|
||||
@@ -12,6 +13,7 @@ import (
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -379,7 +381,9 @@ func getFormat(cType CompressType) archiver.CompressedArchive {
|
||||
format.Compression = archiver.Gz{}
|
||||
format.Archival = archiver.Tar{}
|
||||
case Zip:
|
||||
format.Archival = archiver.Zip{}
|
||||
format.Archival = archiver.Zip{
|
||||
Compression: zip.Deflate,
|
||||
}
|
||||
case Bz2:
|
||||
format.Compression = archiver.Bz2{}
|
||||
format.Archival = archiver.Tar{}
|
||||
@@ -413,9 +417,19 @@ func (f FileOp) Compress(srcRiles []string, dst string, name string, cType Compr
|
||||
return err
|
||||
}
|
||||
|
||||
err = format.Archive(context.Background(), out, files)
|
||||
if err != nil {
|
||||
return err
|
||||
switch cType {
|
||||
case Zip:
|
||||
if err := ZipFile(files, out); err != nil {
|
||||
_ = f.DeleteFile(dstFile)
|
||||
return err
|
||||
}
|
||||
default:
|
||||
err = format.Archive(context.Background(), out, files)
|
||||
if err != nil {
|
||||
_ = f.DeleteFile(dstFile)
|
||||
return err
|
||||
}
|
||||
break
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -488,3 +502,46 @@ func (f FileOp) CopyAndBackup(src string) (string, error) {
|
||||
}
|
||||
return backupPath, nil
|
||||
}
|
||||
|
||||
func ZipFile(files []archiver.File, dst afero.File) error {
|
||||
zw := zip.NewWriter(dst)
|
||||
defer zw.Close()
|
||||
|
||||
for _, file := range files {
|
||||
hdr, err := zip.FileInfoHeader(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
hdr.Name = file.NameInArchive
|
||||
if file.IsDir() {
|
||||
if !strings.HasSuffix(hdr.Name, "/") {
|
||||
hdr.Name += "/"
|
||||
}
|
||||
hdr.Method = zip.Store
|
||||
}
|
||||
w, err := zw.CreateHeader(hdr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if file.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
if file.LinkTarget != "" {
|
||||
_, err = w.Write([]byte(filepath.ToSlash(file.LinkTarget)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
fileReader, err := file.Open()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = io.Copy(w, fileReader)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -4,11 +4,9 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/backend/global"
|
||||
gossh "golang.org/x/crypto/ssh"
|
||||
)
|
||||
|
||||
@@ -46,7 +44,7 @@ func (c *ConnInfo) NewClient() (*ConnInfo, error) {
|
||||
}
|
||||
config.Timeout = c.DialTimeOut
|
||||
|
||||
config.HostKeyCallback = func(hostname string, remote net.Addr, key gossh.PublicKey) error { return nil }
|
||||
config.HostKeyCallback = gossh.InsecureIgnoreHostKey()
|
||||
client, err := gossh.Dial("tcp", addr, config)
|
||||
if nil != err {
|
||||
return c, err
|
||||
@@ -73,9 +71,7 @@ func (c *ConnInfo) Run(shell string) (string, error) {
|
||||
}
|
||||
|
||||
func (c *ConnInfo) Close() {
|
||||
if err := c.Client.Close(); err != nil {
|
||||
global.LOG.Errorf("close ssh client failed, err: %v", err)
|
||||
}
|
||||
_ = c.Client.Close()
|
||||
}
|
||||
|
||||
type SshConn struct {
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
package ssh
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSSH(t *testing.T) {
|
||||
ss := ConnInfo{
|
||||
Addr: "172.16.10.111",
|
||||
Port: 22,
|
||||
User: "root",
|
||||
AuthMode: "password",
|
||||
Password: "Calong@2015",
|
||||
}
|
||||
_, err := ss.NewClient()
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
fmt.Println(ss.Run("ip a"))
|
||||
}
|
||||
@@ -89,6 +89,7 @@ func NewPrivateKeyClient(email string, privateKey string) (*AcmeClient, error) {
|
||||
func newConfig(user *AcmeUser) *lego.Config {
|
||||
config := lego.NewConfig(user)
|
||||
config.CADirURL = "https://acme-v02.api.letsencrypt.org/directory"
|
||||
//config.CADirURL = "https://acme-staging-v02.api.letsencrypt.org/directory"
|
||||
config.UserAgent = "acm_go/0.0.1"
|
||||
config.Certificate.KeyType = certcrypto.RSA2048
|
||||
return config
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/go-acme/lego/v4/acme/api"
|
||||
"github.com/go-acme/lego/v4/certcrypto"
|
||||
@@ -154,10 +155,10 @@ func TestSSL(t *testing.T) {
|
||||
// panic(err)
|
||||
//}
|
||||
|
||||
// err = client.Challenge.SetDNS01Provider(&plainDnsProvider{}, dns01.AddDNSTimeout(6*time.Minute))
|
||||
// if err != nil {
|
||||
// panic(err)
|
||||
// }
|
||||
err = client.Challenge.SetDNS01Provider(&manualDnsProvider{}, dns01.AddDNSTimeout(6*time.Minute))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
core, err := api.New(config.HTTPClient, config.UserAgent, config.CADirURL, reg.URI, priKey)
|
||||
if err != nil {
|
||||
|
||||
@@ -115,22 +115,12 @@ func (c *AcmeClient) UseDns(dnsType DnsType, params string) error {
|
||||
return c.Client.Challenge.SetDNS01Provider(p, dns01.AddDNSTimeout(3*time.Minute))
|
||||
}
|
||||
|
||||
func (c *AcmeClient) UseManualDns(domains []string) (*Resolve, error) {
|
||||
func (c *AcmeClient) UseManualDns() error {
|
||||
p := &manualDnsProvider{}
|
||||
if err := c.Client.Challenge.SetDNS01Provider(p, dns01.AddDNSTimeout(3*time.Minute)); err != nil {
|
||||
return nil, nil
|
||||
return err
|
||||
}
|
||||
|
||||
request := certificate.ObtainRequest{
|
||||
Domains: domains,
|
||||
Bundle: true,
|
||||
}
|
||||
|
||||
_, err := c.Client.Certificate.Obtain(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return p.Resolve, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *AcmeClient) UseHTTP(path string) error {
|
||||
@@ -194,11 +184,11 @@ func (p *manualDnsProvider) CleanUp(domain, token, keyAuth string) error {
|
||||
func (c *AcmeClient) GetDNSResolve(domains []string) (map[string]Resolve, error) {
|
||||
core, err := api.New(c.Config.HTTPClient, c.Config.UserAgent, c.Config.CADirURL, c.User.Registration.URI, c.User.Key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return nil, err
|
||||
}
|
||||
order, err := core.Orders.New(domains)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return nil, err
|
||||
}
|
||||
resolves := make(map[string]Resolve)
|
||||
resc, errc := make(chan acme.Authorization), make(chan domainError)
|
||||
|
||||
+213
-27
@@ -62,6 +62,25 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/apps/checkupdate": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "获取应用更新版本",
|
||||
"tags": [
|
||||
"App"
|
||||
],
|
||||
"summary": "Get app list update",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/apps/detail/:appId/:version": {
|
||||
"get": {
|
||||
"security": [
|
||||
@@ -470,6 +489,48 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/apps/installed/params/update": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "修改应用参数",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"App"
|
||||
],
|
||||
"summary": "Change app params",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/request.AppInstalledUpdate"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [],
|
||||
"bodyKeys": [
|
||||
"installId"
|
||||
],
|
||||
"formatEN": "Application param update [installId]",
|
||||
"formatZH": "应用参数修改 [installId]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/apps/installed/port/change": {
|
||||
"post": {
|
||||
"security": [
|
||||
@@ -683,6 +744,20 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/demo": {
|
||||
"get": {
|
||||
"description": "判断是否为demo环境",
|
||||
"tags": [
|
||||
"Auth"
|
||||
],
|
||||
"summary": "Check System isDemo",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/init": {
|
||||
"post": {
|
||||
"description": "初始化用户",
|
||||
@@ -3899,6 +3974,43 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/files/chunkupload": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "分片上传文件",
|
||||
"tags": [
|
||||
"File"
|
||||
],
|
||||
"summary": "ChunkUpload file",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "file",
|
||||
"description": "request",
|
||||
"name": "file",
|
||||
"in": "formData",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [],
|
||||
"bodyKeys": [
|
||||
"path"
|
||||
],
|
||||
"formatEN": "Upload file [path]",
|
||||
"formatZH": "上传文件 [path]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/files/compress": {
|
||||
"post": {
|
||||
"security": [
|
||||
@@ -4112,6 +4224,48 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/files/download/bypath": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "下载指定文件",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"File"
|
||||
],
|
||||
"summary": "Download file with path",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/request.FilePath"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [],
|
||||
"bodyKeys": [
|
||||
"path"
|
||||
],
|
||||
"formatEN": "Download file [path]",
|
||||
"formatZH": "下载文件 [path]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/files/loadfile": {
|
||||
"post": {
|
||||
"security": [
|
||||
@@ -8623,8 +8777,7 @@ var doc = `{
|
||||
"dto.ComposeCreate": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"from",
|
||||
"name"
|
||||
"from"
|
||||
],
|
||||
"properties": {
|
||||
"file": {
|
||||
@@ -8860,9 +9013,7 @@ var doc = `{
|
||||
],
|
||||
"properties": {
|
||||
"day": {
|
||||
"type": "integer",
|
||||
"maximum": 31,
|
||||
"minimum": 1
|
||||
"type": "integer"
|
||||
},
|
||||
"dbName": {
|
||||
"type": "string"
|
||||
@@ -8871,17 +9022,13 @@ var doc = `{
|
||||
"type": "string"
|
||||
},
|
||||
"hour": {
|
||||
"type": "integer",
|
||||
"maximum": 23,
|
||||
"minimum": 0
|
||||
"type": "integer"
|
||||
},
|
||||
"keepLocal": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"minute": {
|
||||
"type": "integer",
|
||||
"maximum": 59,
|
||||
"minimum": 0
|
||||
"type": "integer"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
@@ -8942,9 +9089,7 @@ var doc = `{
|
||||
],
|
||||
"properties": {
|
||||
"day": {
|
||||
"type": "integer",
|
||||
"maximum": 31,
|
||||
"minimum": 1
|
||||
"type": "integer"
|
||||
},
|
||||
"dbName": {
|
||||
"type": "string"
|
||||
@@ -8953,9 +9098,7 @@ var doc = `{
|
||||
"type": "string"
|
||||
},
|
||||
"hour": {
|
||||
"type": "integer",
|
||||
"maximum": 23,
|
||||
"minimum": 0
|
||||
"type": "integer"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
@@ -8964,9 +9107,7 @@ var doc = `{
|
||||
"type": "boolean"
|
||||
},
|
||||
"minute": {
|
||||
"type": "integer",
|
||||
"maximum": 59,
|
||||
"minimum": 0
|
||||
"type": "integer"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
@@ -9060,15 +9201,9 @@ var doc = `{
|
||||
},
|
||||
"dto.DaemonJsonUpdateByFile": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"path"
|
||||
],
|
||||
"properties": {
|
||||
"file": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -9254,6 +9389,12 @@ var doc = `{
|
||||
"restart",
|
||||
"stop"
|
||||
]
|
||||
},
|
||||
"stopService": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"stopSocket": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -11042,6 +11183,22 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.AppInstalledUpdate": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"installId",
|
||||
"params"
|
||||
],
|
||||
"properties": {
|
||||
"installId": {
|
||||
"type": "integer"
|
||||
},
|
||||
"params": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.AppSearch": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@@ -11284,6 +11441,17 @@ var doc = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.FilePath": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"path"
|
||||
],
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.FilePathCheck": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@@ -12042,7 +12210,22 @@ var doc = `{
|
||||
"response.AppParam": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"label": {
|
||||
"edit": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"key": {
|
||||
"type": "string"
|
||||
},
|
||||
"labelEn": {
|
||||
"type": "string"
|
||||
},
|
||||
"labelZh": {
|
||||
"type": "string"
|
||||
},
|
||||
"rule": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
},
|
||||
"value": {}
|
||||
@@ -12185,6 +12368,9 @@ var doc = `{
|
||||
"appInstallId": {
|
||||
"type": "integer"
|
||||
},
|
||||
"appName": {
|
||||
"type": "string"
|
||||
},
|
||||
"createdAt": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
+213
-27
@@ -48,6 +48,25 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/apps/checkupdate": {
|
||||
"get": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "获取应用更新版本",
|
||||
"tags": [
|
||||
"App"
|
||||
],
|
||||
"summary": "Get app list update",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/apps/detail/:appId/:version": {
|
||||
"get": {
|
||||
"security": [
|
||||
@@ -456,6 +475,48 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/apps/installed/params/update": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "修改应用参数",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"App"
|
||||
],
|
||||
"summary": "Change app params",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/request.AppInstalledUpdate"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [],
|
||||
"bodyKeys": [
|
||||
"installId"
|
||||
],
|
||||
"formatEN": "Application param update [installId]",
|
||||
"formatZH": "应用参数修改 [installId]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/apps/installed/port/change": {
|
||||
"post": {
|
||||
"security": [
|
||||
@@ -669,6 +730,20 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/demo": {
|
||||
"get": {
|
||||
"description": "判断是否为demo环境",
|
||||
"tags": [
|
||||
"Auth"
|
||||
],
|
||||
"summary": "Check System isDemo",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/auth/init": {
|
||||
"post": {
|
||||
"description": "初始化用户",
|
||||
@@ -3885,6 +3960,43 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/files/chunkupload": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "分片上传文件",
|
||||
"tags": [
|
||||
"File"
|
||||
],
|
||||
"summary": "ChunkUpload file",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "file",
|
||||
"description": "request",
|
||||
"name": "file",
|
||||
"in": "formData",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [],
|
||||
"bodyKeys": [
|
||||
"path"
|
||||
],
|
||||
"formatEN": "Upload file [path]",
|
||||
"formatZH": "上传文件 [path]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/files/compress": {
|
||||
"post": {
|
||||
"security": [
|
||||
@@ -4098,6 +4210,48 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/files/download/bypath": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"ApiKeyAuth": []
|
||||
}
|
||||
],
|
||||
"description": "下载指定文件",
|
||||
"consumes": [
|
||||
"application/json"
|
||||
],
|
||||
"tags": [
|
||||
"File"
|
||||
],
|
||||
"summary": "Download file with path",
|
||||
"parameters": [
|
||||
{
|
||||
"description": "request",
|
||||
"name": "request",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/request.FilePath"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": ""
|
||||
}
|
||||
},
|
||||
"x-panel-log": {
|
||||
"BeforeFuntions": [],
|
||||
"bodyKeys": [
|
||||
"path"
|
||||
],
|
||||
"formatEN": "Download file [path]",
|
||||
"formatZH": "下载文件 [path]",
|
||||
"paramKeys": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"/files/loadfile": {
|
||||
"post": {
|
||||
"security": [
|
||||
@@ -8609,8 +8763,7 @@
|
||||
"dto.ComposeCreate": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"from",
|
||||
"name"
|
||||
"from"
|
||||
],
|
||||
"properties": {
|
||||
"file": {
|
||||
@@ -8846,9 +8999,7 @@
|
||||
],
|
||||
"properties": {
|
||||
"day": {
|
||||
"type": "integer",
|
||||
"maximum": 31,
|
||||
"minimum": 1
|
||||
"type": "integer"
|
||||
},
|
||||
"dbName": {
|
||||
"type": "string"
|
||||
@@ -8857,17 +9008,13 @@
|
||||
"type": "string"
|
||||
},
|
||||
"hour": {
|
||||
"type": "integer",
|
||||
"maximum": 23,
|
||||
"minimum": 0
|
||||
"type": "integer"
|
||||
},
|
||||
"keepLocal": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"minute": {
|
||||
"type": "integer",
|
||||
"maximum": 59,
|
||||
"minimum": 0
|
||||
"type": "integer"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
@@ -8928,9 +9075,7 @@
|
||||
],
|
||||
"properties": {
|
||||
"day": {
|
||||
"type": "integer",
|
||||
"maximum": 31,
|
||||
"minimum": 1
|
||||
"type": "integer"
|
||||
},
|
||||
"dbName": {
|
||||
"type": "string"
|
||||
@@ -8939,9 +9084,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"hour": {
|
||||
"type": "integer",
|
||||
"maximum": 23,
|
||||
"minimum": 0
|
||||
"type": "integer"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
@@ -8950,9 +9093,7 @@
|
||||
"type": "boolean"
|
||||
},
|
||||
"minute": {
|
||||
"type": "integer",
|
||||
"maximum": 59,
|
||||
"minimum": 0
|
||||
"type": "integer"
|
||||
},
|
||||
"name": {
|
||||
"type": "string"
|
||||
@@ -9046,15 +9187,9 @@
|
||||
},
|
||||
"dto.DaemonJsonUpdateByFile": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"path"
|
||||
],
|
||||
"properties": {
|
||||
"file": {
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -9240,6 +9375,12 @@
|
||||
"restart",
|
||||
"stop"
|
||||
]
|
||||
},
|
||||
"stopService": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"stopSocket": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -11028,6 +11169,22 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.AppInstalledUpdate": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"installId",
|
||||
"params"
|
||||
],
|
||||
"properties": {
|
||||
"installId": {
|
||||
"type": "integer"
|
||||
},
|
||||
"params": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.AppSearch": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@@ -11270,6 +11427,17 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.FilePath": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"path"
|
||||
],
|
||||
"properties": {
|
||||
"path": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"request.FilePathCheck": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
@@ -12028,7 +12196,22 @@
|
||||
"response.AppParam": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"label": {
|
||||
"edit": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"key": {
|
||||
"type": "string"
|
||||
},
|
||||
"labelEn": {
|
||||
"type": "string"
|
||||
},
|
||||
"labelZh": {
|
||||
"type": "string"
|
||||
},
|
||||
"rule": {
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"type": "string"
|
||||
},
|
||||
"value": {}
|
||||
@@ -12171,6 +12354,9 @@
|
||||
"appInstallId": {
|
||||
"type": "integer"
|
||||
},
|
||||
"appName": {
|
||||
"type": "string"
|
||||
},
|
||||
"createdAt": {
|
||||
"type": "string"
|
||||
},
|
||||
|
||||
+133
-18
@@ -152,7 +152,6 @@ definitions:
|
||||
type: integer
|
||||
required:
|
||||
- from
|
||||
- name
|
||||
type: object
|
||||
dto.ComposeOperation:
|
||||
properties:
|
||||
@@ -294,22 +293,16 @@ definitions:
|
||||
dto.CronjobCreate:
|
||||
properties:
|
||||
day:
|
||||
maximum: 31
|
||||
minimum: 1
|
||||
type: integer
|
||||
dbName:
|
||||
type: string
|
||||
exclusionRules:
|
||||
type: string
|
||||
hour:
|
||||
maximum: 23
|
||||
minimum: 0
|
||||
type: integer
|
||||
keepLocal:
|
||||
type: boolean
|
||||
minute:
|
||||
maximum: 59
|
||||
minimum: 0
|
||||
type: integer
|
||||
name:
|
||||
type: string
|
||||
@@ -352,24 +345,18 @@ definitions:
|
||||
dto.CronjobUpdate:
|
||||
properties:
|
||||
day:
|
||||
maximum: 31
|
||||
minimum: 1
|
||||
type: integer
|
||||
dbName:
|
||||
type: string
|
||||
exclusionRules:
|
||||
type: string
|
||||
hour:
|
||||
maximum: 23
|
||||
minimum: 0
|
||||
type: integer
|
||||
id:
|
||||
type: integer
|
||||
keepLocal:
|
||||
type: boolean
|
||||
minute:
|
||||
maximum: 59
|
||||
minimum: 0
|
||||
type: integer
|
||||
name:
|
||||
type: string
|
||||
@@ -439,10 +426,6 @@ definitions:
|
||||
properties:
|
||||
file:
|
||||
type: string
|
||||
path:
|
||||
type: string
|
||||
required:
|
||||
- path
|
||||
type: object
|
||||
dto.DashboardBase:
|
||||
properties:
|
||||
@@ -564,6 +547,10 @@ definitions:
|
||||
- restart
|
||||
- stop
|
||||
type: string
|
||||
stopService:
|
||||
type: boolean
|
||||
stopSocket:
|
||||
type: boolean
|
||||
required:
|
||||
- operation
|
||||
type: object
|
||||
@@ -1752,6 +1739,17 @@ definitions:
|
||||
- page
|
||||
- pageSize
|
||||
type: object
|
||||
request.AppInstalledUpdate:
|
||||
properties:
|
||||
installId:
|
||||
type: integer
|
||||
params:
|
||||
additionalProperties: true
|
||||
type: object
|
||||
required:
|
||||
- installId
|
||||
- params
|
||||
type: object
|
||||
request.AppSearch:
|
||||
properties:
|
||||
name:
|
||||
@@ -1914,6 +1912,13 @@ definitions:
|
||||
showHidden:
|
||||
type: boolean
|
||||
type: object
|
||||
request.FilePath:
|
||||
properties:
|
||||
path:
|
||||
type: string
|
||||
required:
|
||||
- path
|
||||
type: object
|
||||
request.FilePathCheck:
|
||||
properties:
|
||||
path:
|
||||
@@ -2421,7 +2426,17 @@ definitions:
|
||||
type: object
|
||||
response.AppParam:
|
||||
properties:
|
||||
label:
|
||||
edit:
|
||||
type: boolean
|
||||
key:
|
||||
type: string
|
||||
labelEn:
|
||||
type: string
|
||||
labelZh:
|
||||
type: string
|
||||
rule:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
value: {}
|
||||
type: object
|
||||
@@ -2515,6 +2530,8 @@ definitions:
|
||||
type: string
|
||||
appInstallId:
|
||||
type: integer
|
||||
appName:
|
||||
type: string
|
||||
createdAt:
|
||||
type: string
|
||||
defaultServer:
|
||||
@@ -2628,6 +2645,17 @@ paths:
|
||||
summary: Search app by key
|
||||
tags:
|
||||
- App
|
||||
/apps/checkupdate:
|
||||
get:
|
||||
description: 获取应用更新版本
|
||||
responses:
|
||||
"200":
|
||||
description: ""
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Get app list update
|
||||
tags:
|
||||
- App
|
||||
/apps/detail/:appId/:version:
|
||||
get:
|
||||
consumes:
|
||||
@@ -2887,6 +2915,33 @@ paths:
|
||||
summary: Search params by appInstallId
|
||||
tags:
|
||||
- App
|
||||
/apps/installed/params/update:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 修改应用参数
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/request.AppInstalledUpdate'
|
||||
responses:
|
||||
"200":
|
||||
description: ""
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Change app params
|
||||
tags:
|
||||
- App
|
||||
x-panel-log:
|
||||
BeforeFuntions: []
|
||||
bodyKeys:
|
||||
- installId
|
||||
formatEN: Application param update [installId]
|
||||
formatZH: 应用参数修改 [installId]
|
||||
paramKeys: []
|
||||
/apps/installed/port/change:
|
||||
post:
|
||||
consumes:
|
||||
@@ -3022,6 +3077,15 @@ paths:
|
||||
summary: Load captcha
|
||||
tags:
|
||||
- Auth
|
||||
/auth/demo:
|
||||
get:
|
||||
description: 判断是否为demo环境
|
||||
responses:
|
||||
"200":
|
||||
description: ""
|
||||
summary: Check System isDemo
|
||||
tags:
|
||||
- Auth
|
||||
/auth/init:
|
||||
post:
|
||||
consumes:
|
||||
@@ -5065,6 +5129,30 @@ paths:
|
||||
formatEN: Check whether file [path] exists
|
||||
formatZH: 检测文件 [path] 是否存在
|
||||
paramKeys: []
|
||||
/files/chunkupload:
|
||||
post:
|
||||
description: 分片上传文件
|
||||
parameters:
|
||||
- description: request
|
||||
in: formData
|
||||
name: file
|
||||
required: true
|
||||
type: file
|
||||
responses:
|
||||
"200":
|
||||
description: ""
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: ChunkUpload file
|
||||
tags:
|
||||
- File
|
||||
x-panel-log:
|
||||
BeforeFuntions: []
|
||||
bodyKeys:
|
||||
- path
|
||||
formatEN: Upload file [path]
|
||||
formatZH: 上传文件 [path]
|
||||
paramKeys: []
|
||||
/files/compress:
|
||||
post:
|
||||
consumes:
|
||||
@@ -5202,6 +5290,33 @@ paths:
|
||||
formatEN: Download file [name]
|
||||
formatZH: 下载文件 [name]
|
||||
paramKeys: []
|
||||
/files/download/bypath:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
description: 下载指定文件
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: request
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/request.FilePath'
|
||||
responses:
|
||||
"200":
|
||||
description: ""
|
||||
security:
|
||||
- ApiKeyAuth: []
|
||||
summary: Download file with path
|
||||
tags:
|
||||
- File
|
||||
x-panel-log:
|
||||
BeforeFuntions: []
|
||||
bodyKeys:
|
||||
- path
|
||||
formatEN: Download file [path]
|
||||
formatZH: 下载文件 [path]
|
||||
paramKeys: []
|
||||
/files/loadfile:
|
||||
post:
|
||||
consumes:
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 9.1 KiB |
Vendored
+3
-1
@@ -19,7 +19,6 @@ declare module 'vue' {
|
||||
ContainerLog: typeof import('./src/components/container-log/index.vue')['default']
|
||||
DrawerHeader: typeof import('./src/components/drawer-header/index.vue')['default']
|
||||
ElAlert: typeof import('element-plus/es')['ElAlert']
|
||||
ElAlter: typeof import('element-plus/es')['ElAlter']
|
||||
ElAside: typeof import('element-plus/es')['ElAside']
|
||||
ElAvatar: typeof import('element-plus/es')['ElAvatar']
|
||||
ElBadge: typeof import('element-plus/es')['ElBadge']
|
||||
@@ -80,12 +79,15 @@ declare module 'vue' {
|
||||
Loading: typeof import('element-plus/es')['ElLoadingDirective']
|
||||
Logo: typeof import('./src/components/app-layout/menu/components/Logo.vue')['default']
|
||||
Menu: typeof import('./src/components/app-layout/menu/index.vue')['default']
|
||||
MsgInfo: typeof import('./src/components/msg-info/index.vue')['default']
|
||||
Popover: typeof import('element-plus/es')['ElPopoverDirective']
|
||||
RouterButton: typeof import('./src/components/router-button/index.vue')['default']
|
||||
Status: typeof import('./src/components/status/index.vue')['default']
|
||||
SubItem: typeof import('./src/components/app-layout/menu/components/sub-item.vue')['default']
|
||||
SvgIcon: typeof import('./src/components/svg-icon/svg-icon.vue')['default']
|
||||
SystemUpgrade: typeof import('./src/components/system-upgrade/index.vue')['default']
|
||||
TableSetting: typeof import('./src/components/table-setting/index.vue')['default']
|
||||
Tooltip: typeof import('./src/components/tooltip/index.vue')['default']
|
||||
Upload: typeof import('./src/components/upload/index.vue')['default']
|
||||
VCharts: typeof import('./src/components/v-charts/index.vue')['default']
|
||||
}
|
||||
|
||||
Generated
+6
-21
@@ -30,7 +30,6 @@
|
||||
"sass-loader": "^13.0.2",
|
||||
"screenfull": "^6.0.2",
|
||||
"unplugin-vue-define-options": "^0.7.3",
|
||||
"vite-plugin-monaco-editor": "^1.1.0",
|
||||
"vue": "^3.2.25",
|
||||
"vue-clipboard3": "^2.0.0",
|
||||
"vue-codemirror": "^6.1.1",
|
||||
@@ -10274,14 +10273,6 @@
|
||||
"entities": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vite-plugin-monaco-editor": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/vite-plugin-monaco-editor/-/vite-plugin-monaco-editor-1.1.0.tgz",
|
||||
"integrity": "sha512-IvtUqZotrRoVqwT0PBBDIZPNraya3BxN/bfcNfnxZ5rkJiGcNtO5eAOWWSgT7zullIAEqQwxMU83yL9J5k7gww==",
|
||||
"peerDependencies": {
|
||||
"monaco-editor": ">=0.33.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vite-plugin-vue-setup-extend": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/vite-plugin-vue-setup-extend/-/vite-plugin-vue-setup-extend-0.4.0.tgz",
|
||||
@@ -10643,9 +10634,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/webpack": {
|
||||
"version": "5.75.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.75.0.tgz",
|
||||
"integrity": "sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ==",
|
||||
"version": "5.76.1",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.1.tgz",
|
||||
"integrity": "sha512-4+YIK4Abzv8172/SGqObnUjaIHjLEuUasz9EwQj/9xmPPkYJy2Mh03Q/lJfSD3YLzbxy5FeTq5Uw0323Oh6SJQ==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/eslint-scope": "^3.7.3",
|
||||
@@ -18367,12 +18358,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"vite-plugin-monaco-editor": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/vite-plugin-monaco-editor/-/vite-plugin-monaco-editor-1.1.0.tgz",
|
||||
"integrity": "sha512-IvtUqZotrRoVqwT0PBBDIZPNraya3BxN/bfcNfnxZ5rkJiGcNtO5eAOWWSgT7zullIAEqQwxMU83yL9J5k7gww==",
|
||||
"requires": {}
|
||||
},
|
||||
"vite-plugin-vue-setup-extend": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/vite-plugin-vue-setup-extend/-/vite-plugin-vue-setup-extend-0.4.0.tgz",
|
||||
@@ -18679,9 +18664,9 @@
|
||||
}
|
||||
},
|
||||
"webpack": {
|
||||
"version": "5.75.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.75.0.tgz",
|
||||
"integrity": "sha512-piaIaoVJlqMsPtX/+3KTTO6jfvrSYgauFVdt8cr9LTHKmcq/AMd4mhzsiP7ZF/PGRNPGA8336jldh9l2Kt2ogQ==",
|
||||
"version": "5.76.1",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.1.tgz",
|
||||
"integrity": "sha512-4+YIK4Abzv8172/SGqObnUjaIHjLEuUasz9EwQj/9xmPPkYJy2Mh03Q/lJfSD3YLzbxy5FeTq5Uw0323Oh6SJQ==",
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"@types/eslint-scope": "^3.7.3",
|
||||
|
||||
@@ -42,7 +42,6 @@
|
||||
"sass-loader": "^13.0.2",
|
||||
"screenfull": "^6.0.2",
|
||||
"unplugin-vue-define-options": "^0.7.3",
|
||||
"vite-plugin-monaco-editor": "^1.1.0",
|
||||
"vue": "^3.2.25",
|
||||
"vue-clipboard3": "^2.0.0",
|
||||
"vue-codemirror": "^6.1.1",
|
||||
|
||||
@@ -27,6 +27,11 @@ export namespace App {
|
||||
items: App.App[];
|
||||
}
|
||||
|
||||
export interface AppUpdateRes {
|
||||
version: string;
|
||||
canUpdate: boolean;
|
||||
}
|
||||
|
||||
export interface AppDetail extends CommonModel {
|
||||
appId: string;
|
||||
icon: string;
|
||||
|
||||
@@ -43,7 +43,8 @@ export namespace Container {
|
||||
state: string;
|
||||
runTime: string;
|
||||
|
||||
isFromCompose: string;
|
||||
isFromApp: boolean;
|
||||
isFromCompose: boolean;
|
||||
}
|
||||
export interface ContainerStats {
|
||||
cpuPercent: number;
|
||||
|
||||
@@ -32,10 +32,3 @@ export interface DescriptionUpdate {
|
||||
id: number;
|
||||
description: string;
|
||||
}
|
||||
|
||||
// * 文件上传模块
|
||||
export namespace Upload {
|
||||
export interface ResFileUrl {
|
||||
fileUrl: string;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,10 @@ export const SyncApp = () => {
|
||||
return http.post<any>('apps/sync', {});
|
||||
};
|
||||
|
||||
export const GetAppListUpdate = () => {
|
||||
return http.get<App.AppUpdateRes>('apps/checkupdate');
|
||||
};
|
||||
|
||||
export const SearchApp = (req: App.AppReq) => {
|
||||
return http.post<App.AppResPage>('apps/search', req);
|
||||
};
|
||||
|
||||
@@ -28,6 +28,11 @@ export const loginStatus = () => {
|
||||
export const checkIsFirst = () => {
|
||||
return http.get<boolean>('/auth/status');
|
||||
};
|
||||
|
||||
export const initUser = (params: Login.InitUser) => {
|
||||
return http.post(`/auth/init`, params);
|
||||
};
|
||||
|
||||
export const checkIsDemo = () => {
|
||||
return http.get<boolean>('/auth/demo');
|
||||
};
|
||||
|
||||
@@ -6,7 +6,7 @@ export const searchContainer = (params: Container.ContainerSearch) => {
|
||||
return http.post<ResPage<Container.ContainerInfo>>(`/containers/search`, params);
|
||||
};
|
||||
export const createContainer = (params: Container.ContainerCreate) => {
|
||||
return http.post(`/containers`, params);
|
||||
return http.post(`/containers`, params, 1200000);
|
||||
};
|
||||
export const logContainer = (params: Container.ContainerLogSearch) => {
|
||||
return http.post<string>(`/containers/search/log`, params);
|
||||
@@ -38,10 +38,10 @@ export const imagePush = (params: Container.ImagePush) => {
|
||||
return http.post<string>(`/containers/image/push`, params);
|
||||
};
|
||||
export const imageLoad = (params: Container.ImageLoad) => {
|
||||
return http.post(`/containers/image/load`, params);
|
||||
return http.post(`/containers/image/load`, params, 1200000);
|
||||
};
|
||||
export const imageSave = (params: Container.ImageSave) => {
|
||||
return http.post(`/containers/image/save`, params);
|
||||
return http.post(`/containers/image/save`, params, 1200000);
|
||||
};
|
||||
export const imageTag = (params: Container.ImageTag) => {
|
||||
return http.post(`/containers/image/tag`, params);
|
||||
@@ -117,13 +117,13 @@ export const searchCompose = (params: SearchWithPage) => {
|
||||
return http.post<ResPage<Container.ComposeInfo>>(`/containers/compose/search`, params);
|
||||
};
|
||||
export const upCompose = (params: Container.ComposeCreate) => {
|
||||
return http.post(`/containers/compose`, params);
|
||||
return http.post(`/containers/compose`, params, 600000);
|
||||
};
|
||||
export const composeOperator = (params: Container.ComposeOpration) => {
|
||||
return http.post(`/containers/compose/operate`, params);
|
||||
};
|
||||
export const composeUpdate = (params: Container.ComposeUpdate) => {
|
||||
return http.post(`/containers/compose/update`, params);
|
||||
return http.post(`/containers/compose/update`, params, 600000);
|
||||
};
|
||||
|
||||
// docker
|
||||
|
||||
@@ -31,7 +31,7 @@ export const updateStatus = (params: Cronjob.UpdateStatus) => {
|
||||
};
|
||||
|
||||
export const download = (params: Cronjob.Download) => {
|
||||
return http.download<BlobPart>(`cronjobs/download`, params, { responseType: 'blob' });
|
||||
return http.post<string>(`cronjobs/download`, params);
|
||||
};
|
||||
|
||||
export const handleOnce = (id: number) => {
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import http from '@/api';
|
||||
import { deepCopy } from '@/utils/util';
|
||||
import { Base64 } from 'js-base64';
|
||||
import { SearchWithPage, ResPage, DescriptionUpdate } from '../interface';
|
||||
import { Database } from '../interface/database';
|
||||
|
||||
@@ -7,13 +9,21 @@ export const searchMysqlDBs = (params: SearchWithPage) => {
|
||||
};
|
||||
|
||||
export const addMysqlDB = (params: Database.MysqlDBCreate) => {
|
||||
return http.post(`/databases`, params);
|
||||
let reqest = deepCopy(params) as Database.MysqlDBCreate;
|
||||
if (reqest.password) {
|
||||
reqest.password = Base64.encode(reqest.password);
|
||||
}
|
||||
return http.post(`/databases`, reqest);
|
||||
};
|
||||
export const updateMysqlAccess = (params: Database.ChangeInfo) => {
|
||||
return http.post(`/databases/change/access`, params);
|
||||
};
|
||||
export const updateMysqlPassword = (params: Database.ChangeInfo) => {
|
||||
return http.post(`/databases/change/password`, params);
|
||||
let reqest = deepCopy(params) as Database.ChangeInfo;
|
||||
if (reqest.value) {
|
||||
reqest.value = Base64.encode(reqest.value);
|
||||
}
|
||||
return http.post(`/databases/change/password`, reqest);
|
||||
};
|
||||
export const updateMysqlDescription = (params: DescriptionUpdate) => {
|
||||
return http.post(`/databases/description/update`, params);
|
||||
@@ -58,7 +68,11 @@ export const redisPersistenceConf = () => {
|
||||
return http.get<Database.RedisPersistenceConf>(`/databases/redis/persistence/conf`);
|
||||
};
|
||||
export const changeRedisPassword = (params: Database.ChangeInfo) => {
|
||||
return http.post(`/databases/redis/password`, params);
|
||||
let reqest = deepCopy(params) as Database.ChangeInfo;
|
||||
if (reqest.value) {
|
||||
reqest.value = Base64.encode(reqest.value);
|
||||
}
|
||||
return http.post(`/databases/redis/password`, reqest);
|
||||
};
|
||||
export const updateRedisPersistenceConf = (params: Database.RedisConfPersistenceUpdate) => {
|
||||
return http.post(`/databases/redis/persistence/update`, params);
|
||||
|
||||
@@ -59,6 +59,10 @@ export const UploadFileData = (params: FormData, config: AxiosRequestConfig) =>
|
||||
return http.upload<File.File>('files/upload', params, config);
|
||||
};
|
||||
|
||||
export const ChunkUploadFileData = (params: FormData, config: AxiosRequestConfig) => {
|
||||
return http.upload<File.File>('files/chunkupload', params, config);
|
||||
};
|
||||
|
||||
export const RenameRile = (params: File.FileRename) => {
|
||||
return http.post<File.File>('files/rename', params);
|
||||
};
|
||||
@@ -72,7 +76,11 @@ export const MoveFile = (params: File.FileMove) => {
|
||||
};
|
||||
|
||||
export const DownloadFile = (params: File.FileDownload) => {
|
||||
return http.download<BlobPart>('files/download', params, { responseType: 'blob' });
|
||||
return http.download<BlobPart>('files/download', params, { responseType: 'blob', timeout: 20000 });
|
||||
};
|
||||
|
||||
export const DownloadByPath = (path: string) => {
|
||||
return http.download<BlobPart>('files/download/bypath', { path: path }, { responseType: 'blob', timeout: 40000 });
|
||||
};
|
||||
|
||||
export const ComputeDirSize = (params: File.DirSizeReq) => {
|
||||
|
||||
@@ -3,6 +3,8 @@ import { ResPage } from '../interface';
|
||||
import { Command } from '../interface/command';
|
||||
import { Group } from '../interface/group';
|
||||
import { Host } from '../interface/host';
|
||||
import { Base64 } from 'js-base64';
|
||||
import { deepCopy } from '@/utils/util';
|
||||
|
||||
export const searchHosts = (params: Host.SearchWithPage) => {
|
||||
return http.post<ResPage<Host.Host>>(`/hosts/search`, params);
|
||||
@@ -14,16 +16,37 @@ export const getHostInfo = (id: number) => {
|
||||
return http.get<Host.Host>(`/hosts/` + id);
|
||||
};
|
||||
export const addHost = (params: Host.HostOperate) => {
|
||||
return http.post<Host.HostOperate>(`/hosts`, params);
|
||||
let reqest = deepCopy(params) as Host.HostOperate;
|
||||
if (reqest.password) {
|
||||
reqest.password = Base64.encode(reqest.password);
|
||||
}
|
||||
if (reqest.privateKey) {
|
||||
reqest.privateKey = Base64.encode(reqest.privateKey);
|
||||
}
|
||||
return http.post<Host.HostOperate>(`/hosts`, reqest);
|
||||
};
|
||||
export const testByInfo = (params: Host.HostConnTest) => {
|
||||
return http.post<boolean>(`/hosts/test/byinfo`, params);
|
||||
let reqest = deepCopy(params) as Host.HostOperate;
|
||||
if (reqest.password) {
|
||||
reqest.password = Base64.encode(reqest.password);
|
||||
}
|
||||
if (reqest.privateKey) {
|
||||
reqest.privateKey = Base64.encode(reqest.privateKey);
|
||||
}
|
||||
return http.post<boolean>(`/hosts/test/byinfo`, reqest);
|
||||
};
|
||||
export const testByID = (id: number) => {
|
||||
return http.post<boolean>(`/hosts/test/byid/${id}`);
|
||||
};
|
||||
export const editHost = (params: Host.HostOperate) => {
|
||||
return http.post(`/hosts/update`, params);
|
||||
let reqest = deepCopy(params) as Host.HostOperate;
|
||||
if (reqest.password) {
|
||||
reqest.password = Base64.encode(reqest.password);
|
||||
}
|
||||
if (reqest.privateKey) {
|
||||
reqest.privateKey = Base64.encode(reqest.privateKey);
|
||||
}
|
||||
return http.post(`/hosts/update`, reqest);
|
||||
};
|
||||
export const editHostGroup = (params: Host.GroupChange) => {
|
||||
return http.post(`/hosts/update/group`, params);
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import http from '@/api';
|
||||
import { deepCopy } from '@/utils/util';
|
||||
import { Base64 } from 'js-base64';
|
||||
import { ResPage, SearchWithPage, DescriptionUpdate } from '../interface';
|
||||
import { Backup } from '../interface/backup';
|
||||
import { Setting } from '../interface/setting';
|
||||
@@ -52,16 +54,16 @@ export const loadBaseDir = () => {
|
||||
|
||||
// backup
|
||||
export const handleBackup = (params: Backup.Backup) => {
|
||||
return http.post(`/settings/backup/backup`, params);
|
||||
return http.post(`/settings/backup/backup`, params, 400000);
|
||||
};
|
||||
export const handleRecover = (params: Backup.Recover) => {
|
||||
return http.post(`/settings/backup/recover`, params);
|
||||
return http.post(`/settings/backup/recover`, params, 400000);
|
||||
};
|
||||
export const handleRecoverByUpload = (params: Backup.Recover) => {
|
||||
return http.post(`/settings/backup/recover/byupload`, params);
|
||||
return http.post(`/settings/backup/recover/byupload`, params, 400000);
|
||||
};
|
||||
export const downloadBackupRecord = (params: Backup.RecordDownload) => {
|
||||
return http.download<BlobPart>(`/settings/backup/record/download`, params, { responseType: 'blob' });
|
||||
return http.post<string>(`/settings/backup/record/download`, params);
|
||||
};
|
||||
export const deleteBackupRecord = (params: { ids: number[] }) => {
|
||||
return http.post(`/settings/backup/record/del`, params);
|
||||
@@ -77,16 +79,37 @@ export const getFilesFromBackup = (type: string) => {
|
||||
return http.post<Array<any>>(`/settings/backup/search/files`, { type: type });
|
||||
};
|
||||
export const addBackup = (params: Backup.BackupOperate) => {
|
||||
return http.post<Backup.BackupOperate>(`/settings/backup`, params);
|
||||
let reqest = deepCopy(params) as Backup.BackupOperate;
|
||||
if (reqest.accessKey) {
|
||||
reqest.accessKey = Base64.encode(reqest.accessKey);
|
||||
}
|
||||
if (reqest.credential) {
|
||||
reqest.credential = Base64.encode(reqest.credential);
|
||||
}
|
||||
return http.post<Backup.BackupOperate>(`/settings/backup`, reqest);
|
||||
};
|
||||
export const editBackup = (params: Backup.BackupOperate) => {
|
||||
return http.post(`/settings/backup/update`, params);
|
||||
let reqest = deepCopy(params) as Backup.BackupOperate;
|
||||
if (reqest.accessKey) {
|
||||
reqest.accessKey = Base64.encode(reqest.accessKey);
|
||||
}
|
||||
if (reqest.credential) {
|
||||
reqest.credential = Base64.encode(reqest.credential);
|
||||
}
|
||||
return http.post(`/settings/backup/update`, reqest);
|
||||
};
|
||||
export const deleteBackup = (params: { ids: number[] }) => {
|
||||
return http.post(`/settings/backup/del`, params);
|
||||
};
|
||||
export const listBucket = (params: Backup.ForBucket) => {
|
||||
return http.post(`/settings/backup/buckets`, params);
|
||||
let reqest = deepCopy(params) as Backup.BackupOperate;
|
||||
if (reqest.accessKey) {
|
||||
reqest.accessKey = Base64.encode(reqest.accessKey);
|
||||
}
|
||||
if (reqest.credential) {
|
||||
reqest.credential = Base64.encode(reqest.credential);
|
||||
}
|
||||
return http.post(`/settings/backup/buckets`, reqest);
|
||||
};
|
||||
|
||||
// snapshot
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
import { Upload } from '@/api/interface/index';
|
||||
import { PORT1 } from '@/api/config/service-port';
|
||||
|
||||
import http from '@/api';
|
||||
|
||||
/**
|
||||
* @name 文件上传模块
|
||||
*/
|
||||
// * 图片上传
|
||||
export const uploadImg = (params: FormData) => {
|
||||
return http.post<Upload.ResFileUrl>(PORT1 + `/file/upload/img`, params);
|
||||
};
|
||||
|
||||
// * 视频上传
|
||||
export const uploadVideo = (params: FormData) => {
|
||||
return http.post<Upload.ResFileUrl>(PORT1 + `/file/upload/video`, params);
|
||||
};
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 576 KiB After Width: | Height: | Size: 170 KiB |
@@ -4,14 +4,18 @@
|
||||
</div>
|
||||
<div class="footer flx-justify-between">
|
||||
<div class="footer-left">
|
||||
<a href="https://fit2cloud.com/" target="_blank">杭州飞致云信息科技有限公司</a>
|
||||
<a href="https://fit2cloud.com/" target="_blank">Copyright @2014-2023 FIT2CLOUND 飞致云</a>
|
||||
</div>
|
||||
<div class="footer-right">
|
||||
<span>Version V1</span>
|
||||
<SystemUpgrade />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import SystemUpgrade from '@/components/system-upgrade/index.vue';
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.footer {
|
||||
height: 45px;
|
||||
|
||||
@@ -57,15 +57,17 @@ const loadStatus = async () => {
|
||||
await getSystemAvailable()
|
||||
.then((res) => {
|
||||
if (res) {
|
||||
location.reload();
|
||||
clearInterval(Number(timer));
|
||||
timer = null;
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
location.reload();
|
||||
clearInterval(Number(timer));
|
||||
timer = null;
|
||||
});
|
||||
}, 1000 * 20);
|
||||
}, 1000 * 10);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -58,6 +58,7 @@ import DrawerHeader from '@/components/drawer-header/index.vue';
|
||||
import { deleteBackupRecord, downloadBackupRecord, searchBackupRecords } from '@/api/modules/setting';
|
||||
import { Backup } from '@/api/interface/backup';
|
||||
import { MsgSuccess } from '@/utils/message';
|
||||
import { DownloadByPath } from '@/api/modules/files';
|
||||
|
||||
const selects = ref<any>([]);
|
||||
const loading = ref();
|
||||
@@ -145,14 +146,16 @@ const onDownload = async (row: Backup.RecordInfo) => {
|
||||
fileDir: row.fileDir,
|
||||
fileName: row.fileName,
|
||||
};
|
||||
const res = await downloadBackupRecord(params);
|
||||
const downloadUrl = window.URL.createObjectURL(new Blob([res]));
|
||||
const a = document.createElement('a');
|
||||
a.style.display = 'none';
|
||||
a.href = downloadUrl;
|
||||
a.download = row.fileName;
|
||||
const event = new MouseEvent('click');
|
||||
a.dispatchEvent(event);
|
||||
await downloadBackupRecord(params).then(async (res) => {
|
||||
const file = await DownloadByPath(res.data);
|
||||
const downloadUrl = window.URL.createObjectURL(new Blob([file]));
|
||||
const a = document.createElement('a');
|
||||
a.style.display = 'none';
|
||||
a.href = downloadUrl;
|
||||
a.download = row.fileName;
|
||||
const event = new MouseEvent('click');
|
||||
a.dispatchEvent(event);
|
||||
});
|
||||
};
|
||||
|
||||
const onBatchDelete = async (row: Backup.RecordInfo | null) => {
|
||||
|
||||
@@ -53,7 +53,6 @@ defineProps({
|
||||
const emit = defineEmits(['search', 'update:selects']);
|
||||
const condition = ref({});
|
||||
function search(conditions: any, e: any) {
|
||||
console.log(conditions);
|
||||
if (conditions) {
|
||||
condition.value = conditions;
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ const timeOptions = ref([
|
||||
|
||||
const searchLogs = async () => {
|
||||
const res = await logContainer(logSearch);
|
||||
logInfo.value = res.data;
|
||||
logInfo.value = res.data || '';
|
||||
nextTick(() => {
|
||||
const state = view.value.state;
|
||||
view.value.dispatch({
|
||||
|
||||
@@ -100,7 +100,6 @@ const props = defineProps({
|
||||
const em = defineEmits(['choose']);
|
||||
|
||||
const checkFile = (row: any) => {
|
||||
console.log(row.path);
|
||||
rowName.value = row.name;
|
||||
em('choose', row.path);
|
||||
popoverVisible.value = false;
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
<el-table-column :label="$t('commons.table.operate')">
|
||||
<template #default="{ row, $index }">
|
||||
<div>
|
||||
<el-button link v-if="row.edit" type="primary" @click="saveGroup(groupForm, row, true)">
|
||||
<el-button link v-if="row.edit" type="primary" @click="saveGroup(groupForm, row)">
|
||||
{{ $t('commons.button.save') }}
|
||||
</el-button>
|
||||
<el-button link v-if="!row.edit" type="primary" @click="editGroup($index)">
|
||||
@@ -46,12 +46,7 @@
|
||||
<el-button link v-if="row.edit" type="primary" @click="search()">
|
||||
{{ $t('commons.button.cancel') }}
|
||||
</el-button>
|
||||
<el-button
|
||||
link
|
||||
v-if="!row.edit && !row.isDefault"
|
||||
type="primary"
|
||||
@click="saveGroup(groupForm, row, false)"
|
||||
>
|
||||
<el-button link v-if="!row.edit && !row.isDefault" type="primary" @click="setDefault(row)">
|
||||
{{ $t('website.setDefault') }}
|
||||
</el-button>
|
||||
</div>
|
||||
@@ -83,7 +78,7 @@ interface DialogProps {
|
||||
type: string;
|
||||
}
|
||||
|
||||
const groupForm = ref();
|
||||
const groupForm = ref<FormInstance>();
|
||||
const acceptParams = (params: DialogProps): void => {
|
||||
type.value = params.type;
|
||||
open.value = true;
|
||||
@@ -106,16 +101,13 @@ const search = () => {
|
||||
});
|
||||
};
|
||||
|
||||
const saveGroup = async (formEl: FormInstance, group: Group.GroupInfo, isEdit: boolean) => {
|
||||
const saveGroup = async (formEl: FormInstance, group: Group.GroupInfo) => {
|
||||
if (!formEl) return;
|
||||
await formEl.validate((valid) => {
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
group.type = type.value;
|
||||
if (!isEdit) {
|
||||
group.isDefault = true;
|
||||
}
|
||||
if (group.id == 0) {
|
||||
CreateGroup(group).then(() => {
|
||||
MsgSuccess(i18n.global.t('commons.msg.createSuccess'));
|
||||
@@ -130,6 +122,14 @@ const saveGroup = async (formEl: FormInstance, group: Group.GroupInfo, isEdit: b
|
||||
});
|
||||
};
|
||||
|
||||
const setDefault = (group: Group.GroupInfo) => {
|
||||
group.isDefault = true;
|
||||
UpdateGroup(group).then(() => {
|
||||
MsgSuccess(i18n.global.t('commons.msg.updateSuccess'));
|
||||
search();
|
||||
});
|
||||
};
|
||||
|
||||
const openCreate = () => {
|
||||
for (const d of data.value) {
|
||||
if (d.name == '') {
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
<template>
|
||||
<el-tooltip placement="top-start">
|
||||
<template #content>
|
||||
<div class="info-break" :style="{ width: width + 'px' }">{{ info }}</div>
|
||||
</template>
|
||||
<div class="info-hidden" :style="{ width: width + 'px' }">{{ info }}</div>
|
||||
</el-tooltip>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
defineProps({
|
||||
width: {
|
||||
type: String,
|
||||
default: '100',
|
||||
},
|
||||
info: {
|
||||
type: String,
|
||||
default: '',
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.info-hidden {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.info-break {
|
||||
width: 100px;
|
||||
word-break: break-all;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
</style>
|
||||
@@ -25,7 +25,7 @@ const getType = (status: string) => {
|
||||
case 'error':
|
||||
return 'danger';
|
||||
case 'stopped':
|
||||
return 'warning';
|
||||
return 'danger';
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user