74 Commits

Author SHA1 Message Date
ssongliu
30cb471629 fix: 修改默认升级版本 (#390) 2023-03-24 03:52:10 +00:00
ssongliu
d70c22dde8 fix: 解决设置默认分组的问题 (#385) 2023-03-23 12:58:33 +00:00
ssongliu
01bb6b7c01 fix: 解决 mfa 验证回车时触发页面刷新的问题 (#383) 2023-03-23 12:34:33 +00:00
ssongliu
4f4879759e fix: 修改主机默认分组名称 (#381) 2023-03-23 08:26:33 +00:00
ssongliu
92a410fcea fix: 修改构建失败判断条件 (#380) 2023-03-23 08:24:36 +00:00
zhengkunwang223
5d1fced8e9 feat: 网站分组删除校验 (#377) 2023-03-23 04:14:31 +00:00
liqiang-fit2cloud
a56e5a8abe Pr@dev@docs add readme en.md (#378)
* docs: add README_EN.md.

* docs: add README_EN.md.

* docs: add README_EN.md.

* docs: add README_EN.md.
2023-03-23 11:43:43 +08:00
liqiang-fit2cloud
28ae7f3a0c docs: add README_EN.md. (#375) 2023-03-23 11:08:11 +08:00
zhengkunwang223
8d675c81c5 feat: 优化网站分组 (#372) 2023-03-22 13:42:30 +00:00
ssongliu
66a345364f fix: 优化分组显示 (#371) 2023-03-22 10:48:29 +00:00
zhengkunwang223
a3cb8be08f feat: 修改文件上传错误处理 (#370) 2023-03-22 10:34:29 +00:00
zhengkunwang223
0861b30a7b fix: 解决应用创建没有默认网络创建失败的BUG (#369) 2023-03-22 10:22:29 +00:00
ssongliu
36f2a3eb4b fix: 优化计划任务记录查询返回 (#364) 2023-03-22 10:16:29 +00:00
zhengkunwang223
092cbbf8da feat: 应用编辑增加 select 类型处理 (#363) 2023-03-22 07:38:30 +00:00
ssongliu
39e3e8f214 fix: 优化容器菜单页面状态加载样式 (#356) 2023-03-22 07:32:29 +00:00
ssongliu
fa983bdcc9 fix: 优化导入备份限制 (#361) 2023-03-22 07:20:30 +00:00
zhengkunwang223
67bb30c10c fix: 解决文件编辑,快捷提示不显示的 BUG (#355) 2023-03-22 11:56:09 +08:00
ssongliu
e85340ca5d fix: 数据库启用 WAL 模式,增加连接数与超时设置 (#349)
fix: 数据库启用 WAL 模式,增加连接数与超时设置
2023-03-21 11:00:28 +00:00
ssongliu
a3a1e17849 fix: 解决监控时间控件显示不全的问题 (#348)
fix: 解决监控时间控件显示不全的问题
2023-03-21 10:48:27 +00:00
ssongliu
2601135225 fix: 解决快照同步恢复失败的问题 (#345)
fix: 解决快照同步恢复失败的问题
2023-03-21 10:46:31 +00:00
ssongliu
c556affc91 fix: 解决数据库密码修改未同步到应用的问题 (#343)
fix: 解决数据库密码修改未同步到应用的问题
2023-03-21 10:44:35 +00:00
ssongliu
6ee9789a2f fix: 修改镜像构建和编排创建路径限制,增加 config 校验 (#342)
fix: 修改镜像构建和编排创建路径限制,增加 config 校验
2023-03-21 10:42:37 +00:00
ssongliu
68a457ae89 fix: 升级逻辑调整 (#341)
fix: 升级逻辑调整
2023-03-21 07:16:28 +00:00
zhengkunwang223
72237596f3 feat: 证书列表增加设置自动续签功能 (#337) 2023-03-21 14:42:50 +08:00
zhengkunwang223
f516333682 删除 issue 处理相关 workflow (#339) 2023-03-21 06:40:31 +00:00
zhengkunwang223
873af25684 fix: 解决网站定时任务没有执行的BUG (#333) 2023-03-21 05:10:27 +00:00
zhengkunwang223
8b058a873e feat: 登录增加社区软件许可协议同意选项 (#322) 2023-03-20 11:26:27 +00:00
ssongliu
0c5a5a6454 fix: 创建编排改为异步操作 (#318)
fix:  创建编排改为异步操作
2023-03-20 10:16:26 +00:00
zhengkunwang223
2096049708 feat: 删除自动创建 pr 的 workflow (#313) 2023-03-20 14:07:11 +08:00
1Panel-bot
1095aa2b65 fix: 解决镜像构建输出部分丢失的问题 (#310)
fix: 解决镜像构建输出部分丢失的问题
2023-03-20 03:34:09 +00:00
Ikko Eltociear Ashimine
13679ff301 Fix typo in image.go (#306)
lenth -> length
2023-03-20 10:41:54 +08:00
1Panel-bot
89b7a06662 feat: 系统启动增加同步已安装应用步骤 (#295)
Co-authored-by: zhengkunwang223 <zhengkun@fit2cloud.com>
2023-03-20 10:38:39 +08:00
maninhill
e8582bea75 Update README.md 2023-03-19 15:59:11 +08:00
wanghe
9af7926eb9 Create SECURITY.md 2023-03-18 23:08:08 +08:00
BugKing
bdcdf7e181 ci: add workflow to sync to Gitee repo 2023-03-18 22:48:17 +08:00
ssongliu
887db0aff7 fix: 页面切换时,隐藏默认配置提示 2023-03-18 09:28:30 +00:00
ssongliu
4a974b7e0a fix: 解决计划任务备份文件失效仍能下载的问题 2023-03-18 03:06:31 +00:00
ssongliu
fb286d2def fix: 解决慢日志开启后未刷新导致无法关闭的问题 2023-03-17 14:58:31 +00:00
ssongliu
89cb9e6693 fix: 解决 mysql 数据库带 - 字符授权失败的问题 2023-03-17 11:48:30 +00:00
ssongliu
927def4472 fix: 解决 compose 创建错误未存库的问题 2023-03-17 11:40:30 +00:00
ssongliu
84fcd31704 fix: 升级版本判断逻辑修改 2023-03-17 10:12:30 +00:00
maninhill
005e5cc01f Update README.md 2023-03-17 17:46:34 +08:00
ssongliu
2896409b3a fix: 解决计划任务保存到第三方备份账号不生效的问题 2023-03-17 09:08:31 +00:00
zhengkunwang223
791641f3e1 feat: 修改 .gitignore 规则 2023-03-17 09:02:29 +00:00
wangdan
79f266bbda fix: 修复国际化问题 2023-03-17 08:06:30 +00:00
maninhill
c9edaf0d1d Update README.md 2023-03-17 14:37:53 +08:00
ssongliu
ac5f73c687 fix: 国际化换行问题修改 2023-03-17 04:20:29 +00:00
ssongliu
cc0667429a fix: redis 最大连接数限制 2023-03-17 04:18:29 +00:00
zhengkunwang223
92a5d6faeb style: 网站跳转按钮挪到网站域名设置页面 2023-03-17 04:16:30 +00:00
ssongliu
1111b6b494 fix: 增加 ip 或 域名正则校验 2023-03-17 03:28:29 +00:00
zhengkunwang223
be5a7c99e1 feat: 删除自动关闭 issue 的 action 2023-03-17 03:16:29 +00:00
ssongliu
d6a963c087 fix: 容器创建默认值修改 2023-03-17 02:04:29 +00:00
ssongliu
af753bdffe fix: 表格可点击列超长样式优化 2023-03-16 14:50:29 +00:00
zhengkunwang223
59b025353f fix: 解决手动解析模式 申请证书失败的BUG 2023-03-16 11:34:28 +00:00
zhengkunwang223
355a6b0205 feat: 网站一键部署应用,名称与单独部署应用保持一致 2023-03-16 09:46:30 +00:00
zhengkunwang223
7de80e9d5a fix: 解决打开文件编辑,控制台报错的问题 2023-03-16 09:44:28 +00:00
ssongliu
4c6d8cd20c fix: 备份恢复增加一些失败日志打印 2023-03-16 09:42:28 +00:00
ssongliu
31da89d63a fix: 数据库重启等操作增加 loading 2023-03-16 09:40:32 +00:00
zhengkunwang223
e044ca7d12 style: 修改停用提示的样式 2023-03-16 07:52:28 +00:00
ssongliu
7c037b68cd fix: 容器删除使用中对象提示信息优化 2023-03-16 07:48:28 +00:00
ssongliu
9080824a59 fix: 解决 mysql 慢日志设置修改失败的问题 2023-03-16 06:06:32 +00:00
zhengkunwang223
11f4bc2c89 fix: 解决文件和网站名称过长只显示...的问题 2023-03-16 06:04:28 +00:00
zhengkunwang223
a64ddd1eb8 feat: 修改 action name 2023-03-15 18:25:34 +08:00
1Panel-bot
2fdaecfafe feat: 删除不必要的action (#228)
feat: 删除不必要的action
2023-03-15 10:20:26 +00:00
1Panel-bot
6d1fe20736 feat: 增加 actions (#226)
feat: 增加 actions
2023-03-15 10:08:28 +00:00
wanghe
f61bc047cd Update README.md 2023-03-15 17:47:18 +08:00
ssongliu
4f52580938 fix: 容器部分已知问题修改 (#224)
1. 删除存储卷增加使用中判断
2. 容器操作时增加来源判断
3. 解决删除镜像后页面没有自动刷新的问题
2023-03-15 08:48:26 +00:00
ssongliu
281d0cf880 fix: 敏感字符增加传输加密 (#219)
1. 敏感字符增加传输加密
2023-03-15 07:58:26 +00:00
zhengkunwang223
fdf9215d43 fix: 解决打开应用详情页,控制台报错的 BUG (#218) 2023-03-15 07:56:29 +00:00
zhengkunwang223
8c182e907d feat: 增加 OWNERS 文件 2023-03-15 15:39:02 +08:00
ssongliu
e55af04568 fix: 移除调试打印信息 2023-03-15 13:00:31 +08:00
wanghe-fit2cloud
2462ffdbab refactor: issue template 2023-03-15 11:42:45 +08:00
ssongliu
bfeb57e24f fix: oss 改用分片上传与下载 2023-03-15 11:19:25 +08:00
maninhill
9bb28cda27 Update README.md 2023-03-15 09:28:37 +08:00
171 changed files with 2889 additions and 1506 deletions

View File

@@ -25,7 +25,7 @@ body:
required: true
attributes:
label: "1Panel 版本"
description: "可通过系统右上角下拉菜单中的`关于`选项,或查看安装目录中的 version 文件获取。"
description: "登录 1Panel Web 控制台,在页面右下角查看当前版本。"
- type: markdown
id: details
attributes:

View File

@@ -14,7 +14,7 @@ body:
required: true
attributes:
label: "1Panel 版本"
description: "可通过系统右上角下拉菜单中的`关于`选项,或查看安装目录中的 version 文件获取。"
description: "登录 1Panel Web 控制台,在页面右下角查看当前版本。"
- type: markdown
id: details
attributes:

17
.github/workflows/add-labels-for-pr.yml vendored Normal file
View File

@@ -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 }}

View File

@@ -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 }}

View File

@@ -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 }}

16
.github/workflows/sync2gitee.yml vendored Normal file
View File

@@ -0,0 +1,16 @@
name: sync2gitee
on: [push]
jobs:
repo-sync:
runs-on: ubuntu-latest
steps:
- name: Mirror the Github organization repos to Gitee.
uses: Yikun/hub-mirror-action@master
with:
src: 'github/1Panel-dev'
dst: 'gitee/fit2cloud-xlab'
dst_key: ${{ secrets.GITEE_PRIVATE_KEY }}
dst_token: ${{ secrets.GITEE_TOKEN }}
static_list: "1Panel"
force_update: true

1
.gitignore vendored
View File

@@ -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

11
OWNERS Normal file
View File

@@ -0,0 +1,11 @@
reviewers:
- zhengkunwang223
- ssongliu
- wanghe-fit2cloud
- wangdan-fit2cloud
approvers:
- zhengkunwang223
- ssongliu
- wanghe-fit2cloud
- wangdan-fit2cloud

View File

@@ -1,3 +1,4 @@
[README_EN.md](README_EN.md)
<p align="center"><a href="https://1panel.cn"><img src="http://1panel.oss-cn-hangzhou.aliyuncs.com/img/1panel-logo.png" alt="1Panel" width="300" /></a></p>
<p align="center"><b>现代化、开源的 Linux 服务器运维管理面板</b></p>
<p align="center">
@@ -11,14 +12,14 @@
1Panel 是一个现代化、开源的 Linux 服务器运维管理面板。1Panel 的功能和优势包括:
- **快速建站**:深度集成 Wordpress 和 Halo域名绑定、SSL 证书配置等一键搞定;
- **高效管理**:通过 Web 端轻松管理 Linux 服务器,包括主机监控、文件管理、数据库管理、容器管理及常用应用软件管理
- **快速建站**:深度集成 Wordpress 和 [Halo](https://github.com/halo-dev/halo/)域名绑定、SSL 证书配置等一键搞定;
- **高效管理**:通过 Web 端轻松管理 Linux 服务器,包括应用管理、主机监控、文件管理、数据库管理、容器管理
- **安全可靠**:最小漏洞暴露面,提供防火墙和安全审计等功能;
- **一键备份**:支持一键备份和恢复,备份数据云端存储,永不丢失。
## UI 展示
![UI展示](https://1panel.oss-cn-hangzhou.aliyuncs.com/img/overview.png)
![UI展示](https://resource.fit2cloud.com/1panel/img/overview.png)
## 快速开始
@@ -30,16 +31,16 @@
**一键安装**
以 root 用户执行如下命令一键安装 1Panel:
执行如下命令一键安装 1Panel:
```sh
curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_start.sh && sh quick_start.sh
curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_start.sh && sudo bash quick_start.sh
```
**学习资料**
- [在线文档](https://1panel.cn/docs/)
- [入门视频](https://1panel.cn/video.html)
- [教学视频](https://space.bilibili.com/510493147/channel/collectiondetail?sid=1199760)
## 社区
@@ -47,18 +48,22 @@ curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_
**微信交流群**
<img src="http://1panel.oss-cn-hangzhou.aliyuncs.com/img/wechat-group.jpg" width="156" height="156"/>
<img src="https://1panel.cn/img/wechat-group.jpg" width="156" height="156"/>
## 安全说明
如果您在使用过程中发现任何安全问题,请通过以下方式直接联系我们:
- 邮箱support@fit2cloud.com
- 邮箱support@fit2cloud.com
- 电话400-052-0755
## Star History
[![Star History Chart](https://api.star-history.com/svg?repos=1Panel-dev/1Panel&type=Date)](https://star-history.com/#1Panel-dev/1Panel&Date)
## License
Copyright (c) 2014-2023 飞致云 FIT2CLOUD, All rights reserved.
Copyright (c) 2014-2023 [FIT2CLOUD 飞致云](https://fit2cloud.com/), All rights reserved.
Licensed under The GNU General Public License version 3 (GPLv3) (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

72
README_EN.md Normal file
View File

@@ -0,0 +1,72 @@
[中文 README.md](README.md)
<p align="center"><a href="https://1panel.cn"><img src="http://1panel.oss-cn-hangzhou.aliyuncs.com/img/1panel-logo.png" alt="1Panel" width="300" /></a></p>
<p align="center"><b>Modern and Open-Source Linux Server Operation and Management Panel</b></p>
<p align="center">
<a href="https://www.gnu.org/licenses/gpl-3.0.html"><img src="https://shields.io/github/license/1Panel-dev/1Panel" alt="License: GPL v3"></a>
<a href="https://app.codacy.com/gh/1Panel-dev/1Panel?utm_source=github.com&utm_medium=referral&utm_content=1Panel-dev/1Panel&utm_campaign=Badge_Grade_Dashboard"><img src="https://app.codacy.com/project/badge/Grade/da67574fd82b473992781d1386b937ef" alt="Codacy"></a>
<a href="https://github.com/1Panel-dev/1Panel/releases"><img src="https://img.shields.io/github/v/release/1Panel-dev/1Panel" alt="GitHub release"></a>
<a href="https://github.com/1Panel-dev/1Panel"><img src="https://img.shields.io/github/stars/1Panel-dev/1Panel?color=%231890FF&style=flat-square" alt="Stars"></a>
</p>
------------------------------
1Panel is a modern and Open-Source linux server operation and management panel, the functions and advantages of 1Panel include:
- **Quick website building**: Deeply integrated with Wordpress and [Halo](https://github.com/halo-dev/halo/), with one-click solutions for domain name binding, SSL certificate configuration, and more;
- **Efficient management**: Easily manage Linux servers through the web interface, including application management, host monitoring, file management, database management, container management, and more;
- **Secure and reliable**: Minimal vulnerability exposure, with firewall and security audit functions provided;
- **One-click backup**: Support for one-click backup and restore, with backup data stored in the cloud and never lost.
## UI Display
![UI Display](https://resource.fit2cloud.com/1panel/img/overview_en.png)
## Quick Start
**Online Demo**
- Address: <https://demo.1panel.cn/>
- Username: demo
- Password: 1panel
**One-Click Installation**
Execute the following command to install 1Panel with one click:
```sh
curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_start.sh && sudo bash quick_start.sh
```
**Learning Materials**
- [Online Documentation](https://1panel.cn/docs/)
- [Teaching Videos](https://space.bilibili.com/510493147/channel/collectiondetail?sid=1199760)
## Community
If you have any questions or suggestions, please submit a GitHub Issue or join our WeChat group for communication.
**WeChat Group**
<img src="https://1panel.cn/img/wechat-group.jpg" width="156" height="156"/>
## Security Information
If you discover any security issues, please contact us through:
- Email: support@fit2cloud.com
- Phone: 400-052-0755
## Star History
[![Star History Chart](https://api.star-history.com/svg?repos=1Panel-dev/1Panel&type=Date)](https://star-history.com/#1Panel-dev/1Panel&Date)
## License
Copyright (c) 2014-2023 [FIT2CLOUD 飞致云](https://fit2cloud.com/), All rights reserved.
Licensed under The GNU General Public License version 3 (GPLv3) (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
<https://www.gnu.org/licenses/gpl-3.0.html>
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

19
SECURITY.md Normal file
View File

@@ -0,0 +1,19 @@
# 安全说明
如果您发现安全问题,请直接联系我们:
- wanghe@fit2cloud.com
- support@fit2cloud.com
- 400-052-0755
感谢您的支持!
# Security Policy
All security bugs should be reported to the contact as below:
- wanghe@fit2cloud.com
- support@fit2cloud.com
- 400-052-0755
Thanks for your support!

View File

@@ -144,7 +144,7 @@ func (b *BaseApi) DeleteCheck(c *gin.Context) {
// @Router /apps/installed/sync [post]
// @x-panel-log {"bodyKeys":[],"paramKeys":[],"BeforeFuntions":[],"formatZH":"同步已安装应用列表","formatEN":"Sync the list of installed apps"}
func (b *BaseApi) SyncInstalled(c *gin.Context) {
if err := appInstallService.SyncAll(); err != nil {
if err := appInstallService.SyncAll(false); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}

View File

@@ -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

View File

@@ -70,6 +70,34 @@ func (b *BaseApi) SearchCompose(c *gin.Context) {
})
}
// @Tags Container Compose
// @Summary Test compose
// @Description 测试 compose 是否可用
// @Accept json
// @Param request body dto.ComposeCreate true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /containers/compose/test [post]
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"检测 compose [name] 格式","formatEN":"check compose [name]"}
func (b *BaseApi) TestCompose(c *gin.Context) {
var req dto.ComposeCreate
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
}
isOK, err := containerService.TestCompose(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, isOK)
}
// @Tags Container Compose
// @Summary Create compose
// @Description 创建容器编排
@@ -90,11 +118,12 @@ func (b *BaseApi) CreateCompose(c *gin.Context) {
return
}
if err := containerService.CreateCompose(req); err != nil {
log, err := containerService.CreateCompose(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
helper.SuccessWithData(c, log)
}
// @Tags Container Compose

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -35,7 +35,6 @@ var (
commandService = service.ServiceGroupApp.CommandService
websiteGroupService = service.ServiceGroupApp.WebsiteGroupService
websiteService = service.ServiceGroupApp.WebsiteService
websiteDnsAccountService = service.ServiceGroupApp.WebsiteDnsAccountService
websiteSSLService = service.ServiceGroupApp.WebsiteSSLService

View File

@@ -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"
@@ -14,13 +22,6 @@ import (
websocket2 "github.com/1Panel-dev/1Panel/backend/utils/websocket"
"github.com/gin-gonic/gin"
"github.com/gorilla/websocket"
"io/ioutil"
"net/http"
"os"
"path"
"path/filepath"
"strconv"
"strings"
)
// @Tags File
@@ -444,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 dto.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 获取文件夹大小
@@ -496,6 +519,12 @@ func (b *BaseApi) LoadFromFile(c *gin.Context) {
}
func mergeChunks(fileName string, fileDir string, dstDir string, chunkCount int) error {
if _, err := os.Stat(path.Dir(dstDir)); err != nil && os.IsNotExist(err) {
if err = os.MkdirAll(path.Dir(dstDir), os.ModePerm); err != nil {
return err
}
}
targetFile, err := os.Create(filepath.Join(dstDir, fileName))
if err != nil {
return err
@@ -524,7 +553,6 @@ func mergeChunks(fileName string, fileDir string, dstDir string, chunkCount int)
// @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 {
@@ -550,15 +578,18 @@ func (b *BaseApi) UploadChunkFiles(c *gin.Context) {
}
fileOp := files.NewFileOp()
if err := fileOp.CreateDir("uploads", 0755); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
tmpDir := path.Join(global.CONF.System.TmpDir, "upload")
if !fileOp.Stat(tmpDir) {
if err := fileOp.CreateDir(tmpDir, 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)
filename := c.PostForm("filename")
fileDir := filepath.Join(tmpDir, filename)
_ = os.MkdirAll(fileDir, 0755)
filePath := filepath.Join(fileDir, filename)
emptyFile, err := os.Create(filePath)
@@ -566,26 +597,25 @@ func (b *BaseApi) UploadChunkFiles(c *gin.Context) {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
emptyFile.Close()
defer emptyFile.Close()
chunkData, err := ioutil.ReadAll(uploadFile)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrFileUpload, 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)
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrFileUpload, 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)
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrFileUpload, err)
return
}
helper.SuccessWithData(c, true)

View File

@@ -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,6 +74,22 @@ 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
_ = copier.Copy(&connInfo, &req)
@@ -211,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

View File

@@ -22,6 +22,28 @@ func (b *BaseApi) GetUpgradeInfo(c *gin.Context) {
helper.SuccessWithData(c, info)
}
// @Tags System Setting
// @Summary Load release notes by version
// @Description 获取版本 release notes
// @Accept json
// @Param request body dto.Upgrade true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /settings/upgrade [get]
func (b *BaseApi) GetNotesByVersion(c *gin.Context) {
var req dto.Upgrade
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
notes, err := upgradeService.LoadNotes(req)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, notes)
}
// @Tags System Setting
// @Summary Upgrade
// @Description 系统更新

View File

@@ -1,89 +0,0 @@
package v1
import (
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/gin-gonic/gin"
)
// @Tags Website Group
// @Summary List website groups
// @Description 获取网站组
// @Success 200 {anrry} model.WebsiteGroup
// @Security ApiKeyAuth
// @Router /websites/groups [get]
func (b *BaseApi) GetWebGroups(c *gin.Context) {
list, err := websiteGroupService.GetGroups()
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, list)
}
// @Tags Website Group
// @Summary Create website group
// @Description 创建网站组
// @Accept json
// @Param request body request.WebsiteGroupCreate true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/groups [post]
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"创建网站组 [name]","formatEN":"Create website groups [name]"}
func (b *BaseApi) CreateWebGroup(c *gin.Context) {
var req request.WebsiteGroupCreate
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := websiteGroupService.CreateGroup(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
// @Tags Website Group
// @Summary Update website group
// @Description 更新网站组
// @Accept json
// @Param request body request.WebsiteGroupUpdate true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/groups/update [post]
// @x-panel-log {"bodyKeys":["name"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"更新网站组 [name]","formatEN":"Update website groups [name]"}
func (b *BaseApi) UpdateWebGroup(c *gin.Context) {
var req request.WebsiteGroupUpdate
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := websiteGroupService.UpdateGroup(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}
// @Tags Website Group
// @Summary Delete website group
// @Description 删除网站组
// @Accept json
// @Param request body request.WebsiteResourceReq true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/groups/del [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"website_groups","output_colume":"name","output_value":"name"}],"formatZH":"删除网站组 [name]","formatEN":"Delete website group [name]"}
func (b *BaseApi) DeleteWebGroup(c *gin.Context) {
var req request.WebsiteResourceReq
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := websiteGroupService.DeleteGroup(req.ID); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}

View File

@@ -176,3 +176,25 @@ func (b *BaseApi) GetWebsiteSSLById(c *gin.Context) {
}
helper.SuccessWithData(c, websiteSSL)
}
// @Tags Website SSL
// @Summary Update ssl
// @Description 更新 ssl
// @Accept json
// @Param request body request.WebsiteSSLUpdate true "request"
// @Success 200
// @Security ApiKeyAuth
// @Router /websites/ssl/update [post]
// @x-panel-log {"bodyKeys":["id"],"paramKeys":[],"BeforeFuntions":[{"input_colume":"id","input_value":"id","isList":false,"db":"website_ssls","output_colume":"primary_domain","output_value":"domain"}],"formatZH":"更新证书设置 [domain]","formatEN":"Update ssl config [domain]"}
func (b *BaseApi) UpdateWebsiteSSL(c *gin.Context) {
var req request.WebsiteSSLUpdate
if err := c.ShouldBindJSON(&req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
return
}
if err := websiteSSLService.Update(req); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, nil)
}

View File

@@ -69,15 +69,21 @@ type AppForm struct {
}
type AppFormFields struct {
Type string `json:"type"`
LabelZh string `json:"labelZh"`
LabelEn string `json:"labelEn"`
Required bool `json:"required"`
Default interface{} `json:"default"`
EnvKey string `json:"envKey"`
Disabled bool `json:"disabled"`
Edit bool `json:"edit"`
Rule string `json:"rule"`
Type string `json:"type"`
LabelZh string `json:"labelZh"`
LabelEn string `json:"labelEn"`
Required bool `json:"required"`
Default interface{} `json:"default"`
EnvKey string `json:"envKey"`
Disabled bool `json:"disabled"`
Edit bool `json:"edit"`
Rule string `json:"rule"`
Values []AppFormValue `json:"values"`
}
type AppFormValue struct {
Label string `json:"label"`
Value string `json:"value"`
}
type AppResource struct {

View File

@@ -9,7 +9,6 @@ type UserLoginInfo struct {
Name string `json:"name"`
Token string `json:"token"`
MfaStatus string `json:"mfaStatus"`
MfaSecret string `json:"mfaSecret"`
}
type MfaCredential struct {
@@ -28,7 +27,6 @@ type Login struct {
type MFALogin struct {
Name string `json:"name"`
Password string `json:"password"`
Secret string `json:"secret"`
Code string `json:"code"`
AuthMethod string `json:"authMethod"`
}

View File

@@ -22,6 +22,7 @@ type ContainerInfo struct {
State string `json:"state"`
RunTime string `json:"runTime"`
IsFromApp bool `json:"isFromApp"`
IsFromCompose bool `json:"isFromCompose"`
}

View File

@@ -13,6 +13,7 @@ type GroupSearch struct {
type GroupUpdate struct {
ID uint `json:"id"`
Name string `json:"name"`
Type string `json:"type" validate:"required"`
IsDefault bool `json:"isDefault"`
}

View File

@@ -44,3 +44,8 @@ type WebsiteDnsAccountUpdate struct {
type WebsiteResourceReq struct {
ID uint `json:"id" validate:"required"`
}
type WebsiteSSLUpdate struct {
ID uint `json:"id" validate:"required"`
AutoRenew bool `json:"autoRenew" validate:"required"`
}

View File

@@ -61,11 +61,13 @@ type AppService struct {
}
type AppParam struct {
Value interface{} `json:"value"`
Edit bool `json:"edit"`
Key string `json:"key"`
Rule string `json:"rule"`
LabelZh string `json:"labelZh"`
LabelEn string `json:"labelEn"`
Type string `json:"type"`
Value interface{} `json:"value"`
Edit bool `json:"edit"`
Key string `json:"key"`
Rule string `json:"rule"`
LabelZh string `json:"labelZh"`
LabelEn string `json:"labelEn"`
Type string `json:"type"`
Values interface{} `json:"values"`
ShowValue string `json:"showValue"`
}

View File

@@ -82,9 +82,11 @@ type SnapshotInfo struct {
}
type UpgradeInfo struct {
NewVersion string `json:"newVersion"`
ReleaseNote string `json:"releaseNote"`
NewVersion string `json:"newVersion"`
LatestVersion string `json:"latestVersion"`
ReleaseNote string `json:"releaseNote"`
}
type Upgrade struct {
Version string `json:"version"`
}

View File

@@ -1,11 +0,0 @@
package model
type WebsiteGroup struct {
BaseModel
Name string `gorm:"type:varchar(64);not null" json:"name"`
Default bool `json:"default"`
}
func (w WebsiteGroup) TableName() string {
return "website_groups"
}

View File

@@ -113,6 +113,7 @@ type RootInfo struct {
Name string `json:"name"`
Port int64 `json:"port"`
Password string `json:"password"`
UserPassword string `json:"userPassword"`
ContainerName string `json:"containerName"`
Param string `json:"param"`
Env string `json:"env"`
@@ -146,6 +147,10 @@ func (a *AppInstallRepo) LoadBaseInfo(key string, name string) (*RootInfo, error
if ok {
info.Password = password
}
userPassword, ok := envMap["PANEL_DB_USER_PASSWORD"].(string)
if ok {
info.UserPassword = userPassword
}
info.Port = int64(appInstall.HttpPort)
info.ID = appInstall.ID
info.ContainerName = appInstall.ContainerName

View File

@@ -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)

View File

@@ -19,7 +19,6 @@ type RepoGroup struct {
BackupRepo
WebsiteRepo
WebsiteDomainRepo
WebsiteGroupRepo
WebsiteDnsAccountRepo
WebsiteSSLRepo
WebsiteAcmeAccountRepo

View File

@@ -14,7 +14,7 @@ type IGroupRepo interface {
Create(group *model.Group) error
Update(id uint, vars map[string]interface{}) error
Delete(opts ...DBOption) error
CancelDefault() error
CancelDefault(groupType string) error
WithByIsDefault(isDefault bool) DBOption
}
@@ -64,6 +64,6 @@ func (u *GroupRepo) Delete(opts ...DBOption) error {
return db.Delete(&model.Group{}).Error
}
func (w GroupRepo) CancelDefault() error {
return global.DB.Model(&model.Group{}).Where("`is_default` = 1").Updates(map[string]interface{}{"is_default": 0}).Error
func (u *GroupRepo) CancelDefault(groupType string) error {
return global.DB.Model(&model.Group{}).Where("is_default = ? AND type = ?", 1, groupType).Updates(map[string]interface{}{"is_default": 0}).Error
}

View File

@@ -1,44 +0,0 @@
package repo
import (
"github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/global"
"gorm.io/gorm/clause"
)
type WebsiteGroupRepo struct {
}
func (w WebsiteGroupRepo) Page(page, size int, opts ...DBOption) (int64, []model.WebsiteGroup, error) {
var groups []model.WebsiteGroup
db := getDb(opts...).Model(&model.WebsiteGroup{})
count := int64(0)
db = db.Count(&count)
err := db.Limit(size).Offset(size * (page - 1)).Order("`default` desc").Find(&groups).Error
return count, groups, err
}
func (w WebsiteGroupRepo) GetBy(opts ...DBOption) ([]model.WebsiteGroup, error) {
var groups []model.WebsiteGroup
db := getDb(opts...).Model(&model.WebsiteGroup{})
if err := db.Order("`default` desc").Find(&groups).Error; err != nil {
return groups, err
}
return groups, nil
}
func (w WebsiteGroupRepo) Create(app *model.WebsiteGroup) error {
return getDb().Omit(clause.Associations).Create(app).Error
}
func (w WebsiteGroupRepo) Save(app *model.WebsiteGroup) error {
return getDb().Omit(clause.Associations).Save(app).Error
}
func (w WebsiteGroupRepo) DeleteBy(opts ...DBOption) error {
return getDb(opts...).Delete(&model.WebsiteGroup{}).Error
}
func (w WebsiteGroupRepo) CancelDefault() error {
return global.DB.Model(&model.WebsiteGroup{}).Where("`default` = 1").Updates(map[string]interface{}{"default": 0}).Error
}

View File

@@ -6,6 +6,7 @@ import (
"encoding/json"
"fmt"
"github.com/1Panel-dev/1Panel/backend/buserr"
"github.com/1Panel-dev/1Panel/backend/utils/docker"
"io/ioutil"
"net/http"
"os"
@@ -166,6 +167,9 @@ func (a AppService) GetAppDetail(appId uint, version string) (response.AppDetail
}
func (a AppService) Install(ctx context.Context, req request.AppInstallCreate) (*model.AppInstall, error) {
if err := docker.CreateDefaultDockerNetwork(); err != nil {
return nil, buserr.WithDetail(constant.Err1PanelNetworkFailed, err.Error(), nil)
}
if list, _ := appInstallRepo.ListBy(commonRepo.WithByName(req.Name)); len(list) > 0 {
return nil, buserr.New(constant.ErrNameIsExist)
}

View File

@@ -3,9 +3,6 @@ package service
import (
"encoding/json"
"fmt"
"github.com/1Panel-dev/1Panel/backend/utils/env"
"github.com/1Panel-dev/1Panel/backend/utils/nginx"
"github.com/joho/godotenv"
"io/ioutil"
"math"
"os"
@@ -14,6 +11,10 @@ import (
"strconv"
"strings"
"github.com/1Panel-dev/1Panel/backend/utils/env"
"github.com/1Panel-dev/1Panel/backend/utils/nginx"
"github.com/joho/godotenv"
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
"github.com/1Panel-dev/1Panel/backend/app/dto/response"
"github.com/1Panel-dev/1Panel/backend/buserr"
@@ -33,7 +34,28 @@ import (
type AppInstallService struct {
}
func (a AppInstallService) Page(req request.AppInstalledSearch) (int64, []response.AppInstalledDTO, error) {
type IAppInstallService interface {
Page(req request.AppInstalledSearch) (int64, []response.AppInstalledDTO, error)
CheckExist(key string) (*response.AppInstalledCheck, error)
LoadPort(key string) (int64, error)
LoadPassword(key string) (string, error)
SearchForWebsite(req request.AppInstalledSearch) ([]response.AppInstalledDTO, error)
Operate(req request.AppInstalledOperate) error
Update(req request.AppInstalledUpdate) error
SyncAll(systemInit bool) error
GetServices(key string) ([]response.AppService, error)
GetUpdateVersions(installId uint) ([]dto.AppVersion, error)
GetParams(id uint) ([]response.AppParam, error)
ChangeAppPort(req request.PortUpdate) error
GetDefaultConfigByKey(key string) (string, error)
DeleteCheck(installId uint) ([]dto.AppResource, error)
}
func NewIAppInstalledService() IAppInstallService {
return &AppInstallService{}
}
func (a *AppInstallService) Page(req request.AppInstalledSearch) (int64, []response.AppInstalledDTO, error) {
var opts []repo.DBOption
if req.Name != "" {
@@ -73,7 +95,7 @@ func (a AppInstallService) Page(req request.AppInstalledSearch) (int64, []respon
return total, installDTOs, nil
}
func (a AppInstallService) CheckExist(key string) (*response.AppInstalledCheck, error) {
func (a *AppInstallService) CheckExist(key string) (*response.AppInstalledCheck, error) {
res := &response.AppInstalledCheck{
IsExist: false,
}
@@ -103,7 +125,7 @@ func (a AppInstallService) CheckExist(key string) (*response.AppInstalledCheck,
return res, nil
}
func (a AppInstallService) LoadPort(key string) (int64, error) {
func (a *AppInstallService) LoadPort(key string) (int64, error) {
app, err := appInstallRepo.LoadBaseInfo(key, "")
if err != nil {
return int64(0), nil
@@ -111,7 +133,7 @@ func (a AppInstallService) LoadPort(key string) (int64, error) {
return app.Port, nil
}
func (a AppInstallService) LoadPassword(key string) (string, error) {
func (a *AppInstallService) LoadPassword(key string) (string, error) {
app, err := appInstallRepo.LoadBaseInfo(key, "")
if err != nil {
return "", nil
@@ -119,7 +141,7 @@ func (a AppInstallService) LoadPassword(key string) (string, error) {
return app.Password, nil
}
func (a AppInstallService) SearchForWebsite(req request.AppInstalledSearch) ([]response.AppInstalledDTO, error) {
func (a *AppInstallService) SearchForWebsite(req request.AppInstalledSearch) ([]response.AppInstalledDTO, error) {
var (
installs []model.AppInstall
err error
@@ -152,7 +174,7 @@ func (a AppInstallService) SearchForWebsite(req request.AppInstalledSearch) ([]r
return handleInstalled(installs, false)
}
func (a AppInstallService) Operate(req request.AppInstalledOperate) error {
func (a *AppInstallService) Operate(req request.AppInstalledOperate) error {
install, err := appInstallRepo.GetFirst(commonRepo.WithByID(req.InstallId))
if err != nil {
return err
@@ -196,7 +218,7 @@ func (a AppInstallService) Operate(req request.AppInstalledOperate) error {
}
}
func (a AppInstallService) Update(req request.AppInstalledUpdate) error {
func (a *AppInstallService) Update(req request.AppInstalledUpdate) error {
installed, err := appInstallRepo.GetFirst(commonRepo.WithByID(req.InstallId))
if err != nil {
return err
@@ -270,13 +292,18 @@ func (a AppInstallService) Update(req request.AppInstalledUpdate) error {
return nil
}
func (a AppInstallService) SyncAll() error {
func (a *AppInstallService) SyncAll(systemInit bool) error {
allList, err := appInstallRepo.ListBy()
if err != nil {
return err
}
for _, i := range allList {
if i.Status == constant.Installing {
if systemInit {
i.Status = constant.Error
i.Message = "System restart causes application exception"
_ = appInstallRepo.Save(&i)
}
continue
}
if err := syncById(i.ID); err != nil {
@@ -286,7 +313,7 @@ func (a AppInstallService) SyncAll() error {
return nil
}
func (a AppInstallService) GetServices(key string) ([]response.AppService, error) {
func (a *AppInstallService) GetServices(key string) ([]response.AppService, error) {
app, err := appRepo.GetFirst(appRepo.WithKey(key))
if err != nil {
return nil, err
@@ -310,7 +337,7 @@ func (a AppInstallService) GetServices(key string) ([]response.AppService, error
return res, nil
}
func (a AppInstallService) GetUpdateVersions(installId uint) ([]dto.AppVersion, error) {
func (a *AppInstallService) GetUpdateVersions(installId uint) ([]dto.AppVersion, error) {
install, err := appInstallRepo.GetFirst(commonRepo.WithByID(installId))
var versions []dto.AppVersion
if err != nil {
@@ -335,7 +362,7 @@ func (a AppInstallService) GetUpdateVersions(installId uint) ([]dto.AppVersion,
return versions, nil
}
func (a AppInstallService) ChangeAppPort(req request.PortUpdate) error {
func (a *AppInstallService) ChangeAppPort(req request.PortUpdate) error {
if common.ScanPort(int(req.Port)) {
return buserr.WithDetail(constant.ErrPortInUsed, req.Port, nil)
}
@@ -363,7 +390,7 @@ func (a AppInstallService) ChangeAppPort(req request.PortUpdate) error {
return nil
}
func (a AppInstallService) DeleteCheck(installId uint) ([]dto.AppResource, error) {
func (a *AppInstallService) DeleteCheck(installId uint) ([]dto.AppResource, error) {
var res []dto.AppResource
appInstall, err := appInstallRepo.GetFirst(commonRepo.WithByID(installId))
if err != nil {
@@ -404,7 +431,7 @@ func (a AppInstallService) DeleteCheck(installId uint) ([]dto.AppResource, error
return res, nil
}
func (a AppInstallService) GetDefaultConfigByKey(key string) (string, error) {
func (a *AppInstallService) GetDefaultConfigByKey(key string) (string, error) {
appInstall, err := getAppInstallByKey(key)
if err != nil {
return "", err
@@ -426,7 +453,7 @@ func (a AppInstallService) GetDefaultConfigByKey(key string) (string, error) {
return string(contentByte), nil
}
func (a AppInstallService) GetParams(id uint) ([]response.AppParam, error) {
func (a *AppInstallService) GetParams(id uint) ([]response.AppParam, error) {
var (
res []response.AppParam
appForm dto.AppForm
@@ -459,14 +486,20 @@ func (a AppInstallService) GetParams(id uint) ([]response.AppParam, error) {
}
appParam.LabelZh = form.LabelZh
appParam.LabelEn = form.LabelEn
appParam.Value = v
if form.Type == "service" {
appInstall, _ := appInstallRepo.GetFirst(appInstallRepo.WithServiceName(v.(string)))
appParam.Value = appInstall.Name
res = append(res, appParam)
} else {
appParam.Value = v
res = append(res, appParam)
appParam.ShowValue = appInstall.Name
} else if form.Type == "select" {
for _, fv := range form.Values {
if fv.Value == v {
appParam.ShowValue = fv.Label
break
}
}
appParam.Values = form.Values
}
res = append(res, appParam)
}
}
return res, nil
@@ -622,7 +655,7 @@ func updateInstallInfoInDB(appKey, appName, param string, isRestart bool, value
}, commonRepo.WithByID(appInstall.ID))
}
if param == "user-password" {
oldVal = fmt.Sprintf("\"PANEL_DB_USER_PASSWORD\":\"%v\"", appInstall.Password)
oldVal = fmt.Sprintf("\"PANEL_DB_USER_PASSWORD\":\"%v\"", appInstall.UserPassword)
newVal = fmt.Sprintf("\"PANEL_DB_USER_PASSWORD\":\"%v\"", value)
_ = appInstallRepo.BatchUpdateBy(map[string]interface{}{
"param": strings.ReplaceAll(appInstall.Param, oldVal, newVal),

View File

@@ -86,9 +86,9 @@ func (u *AuthService) MFALogin(c *gin.Context, info dto.MFALogin) (*dto.UserLogi
}
pass, err := encrypt.StringDecrypt(passwrodSetting.Value)
if err != nil {
return nil, constant.ErrAuth
return nil, err
}
if info.Password != pass && nameSetting.Value != info.Name {
if info.Password != pass || nameSetting.Value != info.Name {
return nil, constant.ErrAuth
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -3,6 +3,7 @@ package service
import (
"context"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"os/exec"
@@ -33,7 +34,7 @@ type IContainerService interface {
PageVolume(req dto.SearchWithPage) (int64, interface{}, error)
ListVolume() ([]dto.Options, error)
PageCompose(req dto.SearchWithPage) (int64, interface{}, error)
CreateCompose(req dto.ComposeCreate) error
CreateCompose(req dto.ComposeCreate) (string, error)
ComposeOperation(req dto.ComposeOperation) error
ContainerCreate(req dto.ContainerCreate) error
ContainerOperation(req dto.ContainerOperation) error
@@ -98,6 +99,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"),
@@ -106,6 +111,7 @@ func (u *ContainerService) Page(req dto.PageContainer) (int64, interface{}, erro
ImageName: container.Image,
State: container.State,
RunTime: container.Status,
IsFromApp: IsFromApp,
IsFromCompose: IsFromCompose,
})
}
@@ -234,7 +240,7 @@ func (u *ContainerService) ContainerLogs(req dto.ContainerLog) (string, error) {
}
stdout, err := cmd.CombinedOutput()
if err != nil {
return "", err
return "", errors.New(string(stdout))
}
return string(stdout), nil
}

View File

@@ -5,6 +5,8 @@ import (
"errors"
"fmt"
"os"
"os/exec"
"path"
"sort"
"strings"
"time"
@@ -123,41 +125,49 @@ func (u *ContainerService) PageCompose(req dto.SearchWithPage) (int64, interface
return int64(total), BackDatas, nil
}
func (u *ContainerService) CreateCompose(req dto.ComposeCreate) error {
if req.From == "template" {
template, err := composeRepo.Get(commonRepo.WithByID(req.Template))
if err != nil {
return err
}
req.From = "edit"
req.File = template.Content
func (u *ContainerService) TestCompose(req dto.ComposeCreate) (bool, error) {
if err := u.loadPath(&req); err != nil {
return false, err
}
if req.From == "edit" {
dir := fmt.Sprintf("%s/docker/compose/%s", constant.DataDir, req.Name)
if _, err := os.Stat(dir); err != nil && os.IsNotExist(err) {
if err = os.MkdirAll(dir, os.ModePerm); err != nil {
return err
}
}
cmd := exec.Command("docker-compose", "-f", req.Path, "config")
stdout, err := cmd.CombinedOutput()
if err != nil {
return false, errors.New(string(stdout))
}
return true, nil
}
path := fmt.Sprintf("%s/docker-compose.yml", dir)
file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
if err != nil {
return err
}
defer file.Close()
write := bufio.NewWriter(file)
_, _ = write.WriteString(string(req.File))
write.Flush()
req.Path = path
func (u *ContainerService) CreateCompose(req dto.ComposeCreate) (string, error) {
if err := u.loadPath(&req); err != nil {
return "", err
}
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))
}
_ = composeRepo.CreateRecord(&model.Compose{Name: req.Name})
return nil
if req.From == "path" {
req.Name = path.Base(strings.ReplaceAll(req.Path, "/"+path.Base(req.Path), ""))
}
logName := path.Dir(req.Path) + "/compose.log"
file, err := os.OpenFile(logName, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
if err != nil {
return "", err
}
go func() {
defer file.Close()
cmd := exec.Command("docker-compose", "-f", req.Path, "up", "-d")
stdout, err := cmd.CombinedOutput()
_, _ = file.Write(stdout)
if err != nil {
global.LOG.Errorf("docker-compose up %s failed, err: %v", req.Name, err)
_, _ = compose.Down(req.Path)
_, _ = file.WriteString("docker-compose up failed!")
return
}
global.LOG.Infof("docker-compose up %s successful!", req.Name)
_ = composeRepo.CreateRecord(&model.Compose{Name: req.Name})
_, _ = file.WriteString("docker-compose up successful!")
}()
return logName, nil
}
func (u *ContainerService) ComposeOperation(req dto.ComposeOperation) error {
@@ -199,3 +209,34 @@ func (u *ContainerService) ComposeUpdate(req dto.ComposeUpdate) error {
return nil
}
func (u *ContainerService) loadPath(req *dto.ComposeCreate) error {
if req.From == "template" {
template, err := composeRepo.Get(commonRepo.WithByID(req.Template))
if err != nil {
return err
}
req.From = "edit"
req.File = template.Content
}
if req.From == "edit" {
dir := fmt.Sprintf("%s/docker/compose/%s", constant.DataDir, req.Name)
if _, err := os.Stat(dir); err != nil && os.IsNotExist(err) {
if err = os.MkdirAll(dir, os.ModePerm); err != nil {
return err
}
}
path := fmt.Sprintf("%s/docker-compose.yml", dir)
file, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
if err != nil {
return err
}
defer file.Close()
write := bufio.NewWriter(file)
_, _ = write.WriteString(string(req.File))
write.Flush()
req.Path = path
}
return nil
}

View File

@@ -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
}
}

View File

@@ -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
}

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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)
}

View File

@@ -28,7 +28,6 @@ type ServiceGroup struct {
SettingService
BackupService
WebsiteGroupService
WebsiteService
WebsiteDnsAccountService
WebsiteSSLService
@@ -68,7 +67,6 @@ var (
backupRepo = repo.RepoGroupApp.BackupRepo
websiteRepo = repo.NewIWebsiteRepo()
websiteGroupRepo = repo.RepoGroupApp.WebsiteGroupRepo
websiteDomainRepo = repo.RepoGroupApp.WebsiteDomainRepo
websiteDnsRepo = repo.RepoGroupApp.WebsiteDnsAccountRepo
websiteSSLRepo = repo.NewISSLRepo()

View File

@@ -22,7 +22,7 @@ func NewIGroupService() IGroupService {
}
func (u *GroupService) List(req dto.GroupSearch) ([]dto.GroupInfo, error) {
groups, err := groupRepo.GetList(commonRepo.WithByType(req.Type))
groups, err := groupRepo.GetList(commonRepo.WithByType(req.Type), commonRepo.WithOrderBy("is_default desc"), commonRepo.WithOrderBy("created_at desc"))
if err != nil {
return nil, constant.ErrRecordNotFound
}
@@ -38,7 +38,7 @@ func (u *GroupService) List(req dto.GroupSearch) ([]dto.GroupInfo, error) {
}
func (u *GroupService) Create(req dto.GroupCreate) error {
group, _ := groupRepo.Get(commonRepo.WithByName(req.Name), commonRepo.WithByName(req.Name))
group, _ := groupRepo.Get(commonRepo.WithByName(req.Name), commonRepo.WithByType(req.Type))
if group.ID != 0 {
return constant.ErrRecordExist
}
@@ -58,7 +58,7 @@ func (u *GroupService) Delete(id uint) error {
}
switch group.Type {
case "website":
websites, _ := websiteRepo.GetBy(commonRepo.WithByGroupID(id))
websites, _ := websiteRepo.GetBy(websiteRepo.WithGroupID(id))
if len(websites) > 0 {
return buserr.New(constant.ErrGroupIsUsed)
}
@@ -73,7 +73,7 @@ func (u *GroupService) Delete(id uint) error {
func (u *GroupService) Update(req dto.GroupUpdate) error {
if req.IsDefault {
if err := groupRepo.CancelDefault(); err != nil {
if err := groupRepo.CancelDefault(req.Type); err != nil {
return err
}
}

View File

@@ -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"
@@ -53,8 +54,8 @@ func (u *ImageService) Page(req dto.SearchWithPage) (int64, interface{}, error)
return 0, nil, err
}
if len(req.Info) != 0 {
lenth, count := len(list), 0
for count < lenth {
length, count := len(list), 0
for count < length {
hasTag := false
for _, tag := range list[count].RepoTags {
if strings.Contains(tag, req.Info) {
@@ -64,7 +65,7 @@ func (u *ImageService) Page(req dto.SearchWithPage) (int64, interface{}, error)
}
if !hasTag {
list = append(list[:count], list[(count+1):]...)
lenth--
length--
} else {
count++
}
@@ -121,6 +122,7 @@ func (u *ImageService) ImageBuild(req dto.ImageBuild) (string, error) {
if err != nil {
return "", err
}
fileName := "Dockerfile"
if req.From == "edit" {
dir := fmt.Sprintf("%s/docker/build/%s", constant.DataDir, strings.ReplaceAll(req.Name, ":", "_"))
if _, err := os.Stat(dir); err != nil && os.IsNotExist(err) {
@@ -140,7 +142,8 @@ func (u *ImageService) ImageBuild(req dto.ImageBuild) (string, error) {
write.Flush()
req.Dockerfile = dir
} else {
req.Dockerfile = strings.ReplaceAll(req.Dockerfile, "/Dockerfile", "")
fileName = path.Base(req.Dockerfile)
req.Dockerfile = path.Dir(req.Dockerfile)
}
tar, err := archive.TarWithOptions(req.Dockerfile+"/", &archive.TarOptions{})
if err != nil {
@@ -148,7 +151,7 @@ func (u *ImageService) ImageBuild(req dto.ImageBuild) (string, error) {
}
opts := types.ImageBuildOptions{
Dockerfile: "Dockerfile",
Dockerfile: fileName,
Tags: []string{req.Name},
Remove: true,
Labels: stringsToMap(req.Tags),
@@ -178,14 +181,14 @@ func (u *ImageService) ImageBuild(req dto.ImageBuild) (string, error) {
return
}
if strings.Contains(string(body), "error") && strings.Contains(string(body), "failed:") {
if strings.Contains(string(body), "errorDetail") || strings.Contains(string(body), "error:") {
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.Write(body)
_, _ = file.WriteString("image build successful!")
}()
@@ -378,8 +381,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
}
}

View File

@@ -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)
}

View File

@@ -66,6 +66,9 @@ func (u *SnapshotService) SnapshotImport(req dto.SnapshotImport) error {
if err != nil {
return fmt.Errorf("incorrect snapshot name format of %s", snap)
}
if strings.HasSuffix(snap, ".tar.gz") {
snap = strings.ReplaceAll(snap, ".tar.gz", "")
}
itemSnap := model.Snapshot{
Name: snap,
From: req.From,

View File

@@ -1,18 +1,20 @@
package service
import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"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"
)
@@ -20,6 +22,7 @@ type UpgradeService struct{}
type IUpgradeService interface {
Upgrade(req dto.Upgrade) error
LoadNotes(req dto.Upgrade) (string, error)
SearchUpgrade() (*dto.UpgradeInfo, error)
}
@@ -34,36 +37,50 @@ func (u *UpgradeService) SearchUpgrade() (*dto.UpgradeInfo, error) {
return nil, err
}
versionRes, err := http.Get(fmt.Sprintf("%s/%s/latest", global.CONF.System.RepoUrl, global.CONF.System.Mode))
latestVersion, err := u.loadVersion(true, currentVersion.Value)
if err != nil {
global.LOG.Infof("load latest version failed, err: %v", err)
return nil, err
}
defer versionRes.Body.Close()
version, err := ioutil.ReadAll(versionRes.Body)
if err != nil {
if !common.CompareVersion(string(latestVersion), currentVersion.Value) {
return nil, err
}
isNew, err := compareVersion(currentVersion.Value, string(version))
if !isNew || err != nil {
return nil, err
upgrade.LatestVersion = latestVersion
if latestVersion[0:4] == currentVersion.Value[0:4] {
upgrade.NewVersion = ""
} else {
newerVersion, err := u.loadVersion(false, currentVersion.Value)
if err != nil {
global.LOG.Infof("load newer version failed, err: %v", err)
return nil, err
}
if newerVersion == currentVersion.Value {
upgrade.NewVersion = ""
} else {
upgrade.NewVersion = newerVersion
}
}
itemVersion := upgrade.LatestVersion
if upgrade.NewVersion != "" {
itemVersion = upgrade.NewVersion
}
notes, err := u.loadReleaseNotes(fmt.Sprintf("%s/%s/%s/release/1panel-%s-release-notes", global.CONF.System.RepoUrl, global.CONF.System.Mode, itemVersion, itemVersion))
upgrade.NewVersion = string(version)
releaseNotes, err := http.Get(fmt.Sprintf("%s/%s/%s/release/1panel-%s-release-notes", global.CONF.System.RepoUrl, global.CONF.System.Mode, upgrade.NewVersion, upgrade.NewVersion))
if err != nil {
return nil, err
return nil, fmt.Errorf("load relase-notes of version %s failed, err: %v", latestVersion, err)
}
defer releaseNotes.Body.Close()
release, err := ioutil.ReadAll(releaseNotes.Body)
if err != nil {
return nil, err
}
upgrade.ReleaseNote = string(release)
upgrade.ReleaseNote = notes
return &upgrade, nil
}
func (u *UpgradeService) LoadNotes(req dto.Upgrade) (string, error) {
notes, err := u.loadReleaseNotes(fmt.Sprintf("%s/%s/%s/release/1panel-%s-release-notes", global.CONF.System.RepoUrl, global.CONF.System.Mode, req.Version, req.Version))
if err != nil {
return "", fmt.Errorf("load relase-notes of version %s failed, err: %v", req.Version, err)
}
return notes, nil
}
func (u *UpgradeService) Upgrade(req dto.Upgrade) error {
global.LOG.Info("start to upgrade now...")
fileOp := files.NewFileOp()
@@ -128,6 +145,7 @@ func (u *UpgradeService) Upgrade(req dto.Upgrade) error {
}
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")
@@ -173,45 +191,49 @@ func (u *UpgradeService) handleRollback(fileOp files.FileOp, originalDir string,
if err := cpBinary(originalDir+"/1panel.service", "/etc/systemd/system/1panel.service"); err != nil {
global.LOG.Errorf("rollback 1panel failed, err: %v", err)
}
}
func compareVersion(version, newVersion string) (bool, error) {
if version == newVersion {
return false, nil
func (u *UpgradeService) loadVersion(isLatest bool, currentVersion string) (string, error) {
path := fmt.Sprintf("%s/%s/latest", global.CONF.System.RepoUrl, global.CONF.System.Mode)
if !isLatest {
path = fmt.Sprintf("%s/%s/latest.current", global.CONF.System.RepoUrl, global.CONF.System.Mode)
}
if len(version) == 0 || len(newVersion) == 0 {
return false, fmt.Errorf("incorrect version or new version entered %v -- %v", version, newVersion)
latestVersionRes, err := http.Get(path)
if err != nil {
return "", err
}
versions := strings.Split(strings.ReplaceAll(version, "v", ""), ".")
if len(versions) != 3 {
return false, fmt.Errorf("incorrect version input %v", version)
defer latestVersionRes.Body.Close()
version, err := ioutil.ReadAll(latestVersionRes.Body)
if err != nil {
return "", err
}
newVersions := strings.Split(strings.ReplaceAll(newVersion, "v", ""), ".")
if len(newVersions) != 3 {
return false, fmt.Errorf("incorrect newVersions input %v", version)
if isLatest {
return string(version), nil
}
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
versionMap := make(map[string]string)
if err := json.Unmarshal(version, &versionMap); err != nil {
return "", fmt.Errorf("load version map failed, err: %v", err)
}
if len(currentVersion) < 4 {
return "", fmt.Errorf("current version is error format: %s", currentVersion)
}
if version, ok := versionMap[currentVersion[0:4]]; ok {
return version, nil
}
return "", errors.New("load version failed in latest.current")
}
func (u *UpgradeService) loadReleaseNotes(path string) (string, error) {
releaseNotes, err := http.Get(path)
if err != nil {
return "", err
}
defer releaseNotes.Body.Close()
release, err := ioutil.ReadAll(releaseNotes.Body)
if err != nil {
return "", err
}
return string(release), nil
}

View File

@@ -1,61 +0,0 @@
package service
import (
"github.com/1Panel-dev/1Panel/backend/app/dto/request"
"github.com/1Panel-dev/1Panel/backend/app/model"
"github.com/1Panel-dev/1Panel/backend/buserr"
"github.com/1Panel-dev/1Panel/backend/constant"
)
type WebsiteGroupService struct {
}
func (w WebsiteGroupService) CreateGroup(create request.WebsiteGroupCreate) error {
groups, _ := websiteGroupRepo.GetBy(commonRepo.WithByName(create.Name))
if len(groups) > 0 {
return buserr.New(constant.ErrNameIsExist)
}
return websiteGroupRepo.Create(&model.WebsiteGroup{
Name: create.Name,
})
}
func (w WebsiteGroupService) GetGroups() ([]model.WebsiteGroup, error) {
return websiteGroupRepo.GetBy()
}
func (w WebsiteGroupService) UpdateGroup(update request.WebsiteGroupUpdate) error {
if update.Default {
if err := websiteGroupRepo.CancelDefault(); err != nil {
return err
}
return websiteGroupRepo.Save(&model.WebsiteGroup{
BaseModel: model.BaseModel{
ID: update.ID,
},
Name: update.Name,
Default: true,
})
} else {
exists, _ := websiteGroupRepo.GetBy(commonRepo.WithByName(update.Name))
for _, exist := range exists {
if exist.ID != update.ID {
return buserr.New(constant.ErrNameIsExist)
}
}
return websiteGroupRepo.Save(&model.WebsiteGroup{
BaseModel: model.BaseModel{
ID: update.ID,
},
Name: update.Name,
})
}
}
func (w WebsiteGroupService) DeleteGroup(id uint) error {
websites, _ := websiteRepo.GetBy(websiteRepo.WithGroupID(id))
if len(websites) > 0 {
return buserr.New(constant.ErrGroupIsUsed)
}
return websiteGroupRepo.DeleteBy(commonRepo.WithByID(id))
}

View File

@@ -27,6 +27,7 @@ type IWebsiteSSLService interface {
GetDNSResolve(req request.WebsiteDNSReq) ([]response.WebsiteDNSRes, error)
GetWebsiteSSL(websiteId uint) (response.WebsiteSSLDTO, error)
Delete(id uint) error
Update(update request.WebsiteSSLUpdate) error
}
func NewIWebsiteSSLService() IWebsiteSSLService {
@@ -99,6 +100,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}
@@ -128,6 +133,7 @@ func (w WebsiteSSLService) Create(create request.WebsiteSSLCreate) (request.Webs
websiteSSL.StartDate = cert.NotBefore
websiteSSL.Type = cert.Issuer.CommonName
websiteSSL.Organization = cert.Issuer.Organization[0]
websiteSSL.AutoRenew = create.AutoRenew
if err := websiteSSLRepo.Create(context.TODO(), &websiteSSL); err != nil {
return res, err
@@ -254,3 +260,12 @@ func (w WebsiteSSLService) Delete(id uint) error {
}
return websiteSSLRepo.DeleteBy(commonRepo.WithByID(id))
}
func (w WebsiteSSLService) Update(update request.WebsiteSSLUpdate) error {
websiteSSL, err := websiteSSLRepo.GetFirst(commonRepo.WithByID(update.ID))
if err != nil {
return err
}
websiteSSL.AutoRenew = update.AutoRenew
return websiteSSLRepo.Save(websiteSSL)
}

View File

@@ -50,15 +50,16 @@ var (
// app
var (
ErrPortInUsed = "ErrPortInUsed"
ErrAppLimit = "ErrAppLimit"
ErrAppRequired = "ErrAppRequired"
ErrFileCanNotRead = "ErrFileCanNotRead"
ErrFileToLarge = "ErrFileToLarge"
ErrNotInstall = "ErrNotInstall"
ErrPortInOtherApp = "ErrPortInOtherApp"
ErrDbUserNotValid = "ErrDbUserNotValid"
ErrUpdateBuWebsite = "ErrUpdateBuWebsite"
ErrPortInUsed = "ErrPortInUsed"
ErrAppLimit = "ErrAppLimit"
ErrAppRequired = "ErrAppRequired"
ErrFileCanNotRead = "ErrFileCanNotRead"
ErrFileToLarge = "ErrFileToLarge"
ErrNotInstall = "ErrNotInstall"
ErrPortInOtherApp = "ErrPortInOtherApp"
ErrDbUserNotValid = "ErrDbUserNotValid"
ErrUpdateBuWebsite = "ErrUpdateBuWebsite"
Err1PanelNetworkFailed = "Err1PanelNetworkFailed"
)
//website
@@ -83,6 +84,7 @@ var (
ErrMovePathFailed = "ErrMovePathFailed"
ErrLinkPathNotFound = "ErrLinkPathNotFound"
ErrFileIsExit = "ErrFileIsExit"
ErrFileUpload = "ErrFileUpload"
)
//mysql
@@ -95,3 +97,9 @@ var (
var (
ErrTypeOfRedis = "ErrTypeOfRedis"
)
//container
var (
ErrInUsed = "ErrInUsed"
ErrObjectInUsed = "ErrObjectInUsed"
)

View File

@@ -4,8 +4,9 @@ const (
WebRunning = "Running"
WebStopped = "Stopped"
DateLayout = "2006-01-02"
DefaultDate = "1970-01-01"
DateLayout = "2006-01-02"
DateTimeLayout = "2006-01-02 15:04:05"
DefaultDate = "1970-01-01"
ProtocolHTTP = "HTTP"
ProtocolHTTPS = "HTTPS"

View File

@@ -118,6 +118,9 @@ func loadNetIO() {
netStatAll2, _ := net.IOCounters(false)
for _, net2 := range netStatAll2 {
for _, net1 := range netStatAll {
if net1.BytesSent == 0 || net1.BytesRecv == 0 {
continue
}
if net2.Name == net1.Name {
var itemNet model.MonitorNetwork
itemNet.Name = net1.Name

View File

@@ -3,6 +3,7 @@ package job
import (
"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/global"
"time"
)
@@ -19,18 +20,18 @@ func (ssl *ssl) Run() {
sslService := service.NewIWebsiteSSLService()
sslList, _ := sslRepo.List()
global.LOG.Info("ssl renew cron job start...")
now := time.Now()
now := time.Now().Add(10 * time.Second)
for _, s := range sslList {
if !s.AutoRenew || s.Provider == "manual" || s.Provider == "dnsManual" {
continue
}
sum := s.ExpireDate.Sub(now)
if sum.Hours() < 168 {
expireDate, _ := time.ParseInLocation(constant.DateTimeLayout, s.ExpireDate.String(), time.Now().Location())
sum := expireDate.Sub(now)
if sum.Hours() < 720 {
if err := sslService.Renew(s.ID); err != nil {
global.LOG.Errorf("renew doamin [%s] ssl failed err:%s", s.PrimaryDomain, err.Error())
}
}
}
global.LOG.Info("ssl renew cron job end...")
}

View File

@@ -20,7 +20,7 @@ func NewWebsiteJob() *website {
func (w *website) Run() {
websites, _ := repo.NewIWebsiteRepo().List()
global.LOG.Info("website cron job start...")
now := time.Now()
now := time.Now().Add(10 * time.Second)
if len(websites) > 0 {
neverExpireDate, _ := time.Parse(constant.DateLayout, constant.DefaultDate)
var wg sync.WaitGroup
@@ -28,7 +28,8 @@ func (w *website) Run() {
if site.Status != constant.WebRunning || neverExpireDate.Equal(site.ExpireDate) {
continue
}
if site.ExpireDate.Before(now) {
expireDate, _ := time.ParseInLocation(constant.DateTimeLayout, site.ExpireDate.String(), time.Now().Location())
if expireDate.Before(now) {
wg.Add(1)
go func(ws model.Website) {
stopWebsite(ws.ID, &wg)

View File

@@ -11,35 +11,35 @@ import (
"gopkg.in/yaml.v3"
)
func GetMsgWithMap(msg string, maps map[string]interface{}) string {
func GetMsgWithMap(key string, maps map[string]interface{}) string {
content := ""
if maps == nil {
content = ginI18n.MustGetMessage(&i18n.LocalizeConfig{
MessageID: msg,
MessageID: key,
})
} else {
content = ginI18n.MustGetMessage(&i18n.LocalizeConfig{
MessageID: msg,
MessageID: key,
TemplateData: maps,
})
}
content = strings.ReplaceAll(content, ": <no value>", "")
if content == "" {
return msg
return key
} else {
return content
}
}
func GetErrMsg(msg string, maps map[string]interface{}) string {
func GetErrMsg(key string, maps map[string]interface{}) string {
content := ""
if maps == nil {
content = ginI18n.MustGetMessage(&i18n.LocalizeConfig{
MessageID: msg,
MessageID: key,
})
} else {
content = ginI18n.MustGetMessage(&i18n.LocalizeConfig{
MessageID: msg,
MessageID: key,
TemplateData: maps,
})
}

View File

@@ -26,6 +26,7 @@ ErrPortInOtherApp: "{{ .port }} port already in use by {{ .apps }}"
ErrDbUserNotValid: "Stock database, username and password do not match"
ErrDockerComposeNotValid: "docker-compose file format error!"
ErrUpdateBuWebsite: 'The application was updated successfully, but the modification of the website configuration file failed, please check the configuration!'
Err1PanelNetworkFailed: 'Default container network creation failed! {{ .detail }}'
#file
ErrFileCanNotRead: "File can not read"
@@ -34,6 +35,7 @@ ErrPathNotFound: "Path is not found"
ErrMovePathFailed: "The target path cannot contain the original path!"
ErrLinkPathNotFound: "Target path does not exist!"
ErrFileIsExit: "File already exists!"
ErrFileUpload: "Failed to upload file"
#website
ErrDomainIsExist: "Domain is already exist"
@@ -52,4 +54,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"

View File

@@ -26,6 +26,7 @@ ErrPortInOtherApp: "{{ .port }} 端口已被 {{ .apps }}占用!"
ErrDbUserNotValid: "存量数据库,用户名密码不匹配!"
ErrDockerComposeNotValid: "docker-compose 文件格式错误"
ErrUpdateBuWebsite: '应用更新成功,但是网站配置文件修改失败,请检查配置!'
Err1PanelNetworkFailed: '默认容器网络创建失败!{{ .detail }}'
#file
ErrFileCanNotRead: "此文件不支持预览"
@@ -34,6 +35,7 @@ ErrPathNotFound: "目录不存在"
ErrMovePathFailed: "目标路径不能包含原路径!"
ErrLinkPathNotFound: "目标路径不存在!"
ErrFileIsExit: "文件已存在!"
ErrFileUpload: "上传文件失败"
#website
ErrDomainIsExist: "域名已存在"
@@ -52,4 +54,8 @@ ErrUserIsExist: "当前用户已存在,请重新输入"
ErrDatabaseIsExist: "当前数据库已存在,请重新输入"
#redis
ErrTypeOfRedis: "恢复文件类型与当前持久化方式不符,请修改后重试"
ErrTypeOfRedis: "恢复文件类型与当前持久化方式不符,请修改后重试"
#container
ErrInUsed: "{{ .detail }} 正被使用,无法删除"
ErrObjectInUsed: "该对象正被使用,无法删除"

View File

@@ -1,12 +1,11 @@
package app
import (
"fmt"
"github.com/1Panel-dev/1Panel/backend/utils/docker"
"path"
"github.com/1Panel-dev/1Panel/backend/constant"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/1Panel-dev/1Panel/backend/utils/docker"
"github.com/1Panel-dev/1Panel/backend/utils/files"
)
@@ -23,7 +22,7 @@ func Init() {
createDir(fileOp, dir)
}
createDefaultDockerNetwork()
_ = docker.CreateDefaultDockerNetwork()
}
func createDir(fileOp files.FileOp, dirPath string) {
@@ -31,17 +30,3 @@ func createDir(fileOp files.FileOp, dirPath string) {
_ = fileOp.CreateDir(dirPath, 0755)
}
}
func createDefaultDockerNetwork() {
cli, err := docker.NewClient()
if err != nil {
fmt.Println("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())
return
}
}
}

View File

@@ -1,25 +1,35 @@
package business
import (
"fmt"
"github.com/1Panel-dev/1Panel/backend/app/service"
"github.com/1Panel-dev/1Panel/backend/global"
)
func Init() {
syncApp()
syncInstalledApp()
}
func syncApp() {
setting, err := service.NewISettingService().GetSettingInfo()
if err != nil {
global.LOG.Errorf("sync app error: %s", err.Error())
return
}
if setting.AppStoreVersion != "" {
fmt.Println(setting.AppStoreVersion)
global.LOG.Info("do not sync")
global.LOG.Info("no need to sync")
return
}
global.LOG.Info("sync app start...")
if err := service.NewIAppService().SyncAppList(); err != nil {
global.LOG.Errorf("sync app error: %s", err.Error())
return
}
global.LOG.Info("sync app successful")
}
func syncInstalledApp() {
if err := service.NewIAppInstalledService().SyncAll(true); err != nil {
global.LOG.Errorf("sync instaled app error: %s", err.Error())
}
global.LOG.Info("sync app success")
}

View File

@@ -2,9 +2,11 @@ package db
import (
"fmt"
"os"
"time"
"gorm.io/driver/sqlite"
"gorm.io/gorm"
"os"
"github.com/1Panel-dev/1Panel/backend/global"
)
@@ -28,6 +30,15 @@ func Init() {
if err != nil {
panic(err)
}
_ = db.Exec("PRAGMA journal_mode = WAL;")
sqlDB, dbError := db.DB()
if dbError != nil {
panic(err)
}
sqlDB.SetConnMaxIdleTime(10)
sqlDB.SetMaxOpenConns(100)
sqlDB.SetConnMaxLifetime(time.Hour)
global.DB = db
global.LOG.Info("init db successfully")
}

View File

@@ -20,6 +20,7 @@ func Init() {
migrations.AddTableWebsite,
migrations.AddTableDatabaseMysql,
migrations.AddTableSnap,
migrations.AddDefaultGroup,
})
if err := m.Migrate(); err != nil {
global.LOG.Error(err)

View File

@@ -140,7 +140,6 @@ var AddTableSetting = &gormigrate.Migration{
return err
}
if err := tx.Create(&model.Setting{Key: "SystemStatus", Value: "Free"}).Error; err != nil {
tx.Rollback()
return err
}
if err := tx.Create(&model.Setting{Key: "AppStoreVersion", Value: ""}).Error; err != nil {
@@ -211,14 +210,7 @@ var AddTableDatabaseMysql = &gormigrate.Migration{
var AddTableWebsite = &gormigrate.Migration{
ID: "20201009-add-table-website",
Migrate: func(tx *gorm.DB) error {
if err := tx.AutoMigrate(&model.Website{}, &model.WebsiteDomain{}, &model.WebsiteGroup{}, &model.WebsiteDnsAccount{}, &model.WebsiteSSL{}, &model.WebsiteAcmeAccount{}); err != nil {
return err
}
item := &model.WebsiteGroup{
Name: "默认",
Default: true,
}
if err := tx.Create(item).Error; err != nil {
if err := tx.AutoMigrate(&model.Website{}, &model.WebsiteDomain{}, &model.WebsiteDnsAccount{}, &model.WebsiteSSL{}, &model.WebsiteAcmeAccount{}); err != nil {
return err
}
return nil
@@ -234,3 +226,24 @@ var AddTableSnap = &gormigrate.Migration{
return nil
},
}
var AddDefaultGroup = &gormigrate.Migration{
ID: "2023022-change-default-group",
Migrate: func(tx *gorm.DB) error {
defaultGroup := &model.Group{
Name: "默认",
IsDefault: true,
Type: "website",
}
if err := tx.Create(defaultGroup).Error; err != nil {
return err
}
if err := tx.Model(&model.Group{}).Where("name = ? AND type = ?", "default", "host").Update("name", "默认").Error; err != nil {
return err
}
if err := tx.Model(&model.Website{}).Where("1 = 1").Update("website_group_id", defaultGroup.ID).Error; err != nil {
return err
}
return tx.Migrator().DropTable("website_groups")
},
}

View File

@@ -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
}

View File

@@ -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)

View File

@@ -33,6 +33,7 @@ func (s *ContainerRouter) InitContainerRouter(Router *gin.RouterGroup) {
baRouter.POST("/compose/search", baseApi.SearchCompose)
baRouter.POST("/compose", baseApi.CreateCompose)
baRouter.POST("/compose/test", baseApi.TestCompose)
baRouter.POST("/compose/operate", baseApi.OperatorCompose)
baRouter.POST("/compose/update", baseApi.ComposeUpdate)

View File

@@ -32,6 +32,7 @@ func (f *FileRouter) InitFileRouter(Router *gin.RouterGroup) {
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)

View File

@@ -10,14 +10,14 @@ type WebsiteGroupRouter struct {
}
func (a *WebsiteGroupRouter) InitWebsiteGroupRouter(Router *gin.RouterGroup) {
groupRouter := Router.Group("websites/groups")
groupRouter := Router.Group("groups")
groupRouter.Use(middleware.JwtAuth()).Use(middleware.SessionAuth()).Use(middleware.PasswordExpired())
baseApi := v1.ApiGroupApp.BaseApi
{
groupRouter.GET("", baseApi.GetWebGroups)
groupRouter.POST("", baseApi.CreateWebGroup)
groupRouter.POST("/update", baseApi.UpdateWebGroup)
groupRouter.POST("/del", baseApi.DeleteWebGroup)
groupRouter.POST("", baseApi.CreateGroup)
groupRouter.POST("/del", baseApi.DeleteGroup)
groupRouter.POST("/update", baseApi.UpdateGroup)
groupRouter.POST("/search", baseApi.ListGroup)
}
}

View File

@@ -26,11 +26,6 @@ func (s *HostRouter) InitHostRouter(Router *gin.RouterGroup) {
hostRouter.POST("/test/byid/:id", baseApi.TestByID)
hostRouter.GET(":id", baseApi.GetHostInfo)
hostRouter.POST("/group", baseApi.CreateGroup)
hostRouter.POST("/group/del", baseApi.DeleteGroup)
hostRouter.POST("/group/update", baseApi.UpdateGroup)
hostRouter.POST("/group/search", baseApi.ListGroup)
hostRouter.GET("/command", baseApi.ListCommand)
hostRouter.POST("/command", baseApi.CreateCommand)
hostRouter.POST("/command/del", baseApi.DeleteCommand)

View File

@@ -51,6 +51,7 @@ func (s *SettingRouter) InitSettingRouter(Router *gin.RouterGroup) {
settingRouter.POST("/backup/record/del", baseApi.DeleteBackupRecord)
settingRouter.POST("/upgrade", baseApi.Upgrade)
settingRouter.POST("/upgrade/notes", baseApi.GetNotesByVersion)
settingRouter.GET("/upgrade", baseApi.GetUpgradeInfo)
settingRouter.GET("/basedir", baseApi.LoadBaseDir)
}

View File

@@ -22,5 +22,6 @@ func (a *WebsiteSSLRouter) InitWebsiteSSLRouter(Router *gin.RouterGroup) {
groupRouter.POST("/del", baseApi.DeleteWebsiteSSL)
groupRouter.GET("/website/:websiteId", baseApi.GetWebsiteSSLByWebsiteId)
groupRouter.GET("/:id", baseApi.GetWebsiteSSLById)
groupRouter.POST("/update", baseApi.UpdateWebsiteSSL)
}
}

View File

@@ -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
}

View File

@@ -2,6 +2,7 @@ package docker
import (
"context"
"github.com/1Panel-dev/1Panel/backend/global"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/filters"
@@ -73,3 +74,18 @@ func (c Client) NetworkExist(name string) bool {
}
return len(networks) > 0
}
func CreateDefaultDockerNetwork() error {
cli, err := NewClient()
if err != nil {
global.LOG.Errorf("init docker client error %s", err.Error())
return err
}
if !cli.NetworkExist("1panel-network") {
if err := cli.CreateNetwork("1panel-network"); err != nil {
global.LOG.Errorf("create default docker network error %s", err.Error())
return err
}
}
return nil
}

View File

@@ -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"))
}

View File

@@ -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

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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": "初始化用户",
@@ -970,6 +1045,48 @@ var doc = `{
}
}
},
"/containers/compose/test": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "测试 compose 是否可用",
"consumes": [
"application/json"
],
"tags": [
"Container Compose"
],
"summary": "Test compose",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.ComposeCreate"
}
}
],
"responses": {
"200": {
"description": "OK"
}
},
"x-panel-log": {
"BeforeFuntions": [],
"bodyKeys": [
"name"
],
"formatEN": "check compose [name]",
"formatZH": "检测 compose [name] 格式",
"paramKeys": []
}
}
},
"/containers/compose/update": {
"post": {
"security": [
@@ -3899,6 +4016,34 @@ 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": ""
}
}
}
},
"/files/compress": {
"post": {
"security": [
@@ -4112,6 +4257,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/dto.FilePath"
}
}
],
"responses": {
"200": {
"description": ""
}
},
"x-panel-log": {
"BeforeFuntions": [],
"bodyKeys": [
"path"
],
"formatEN": "Download file [path]",
"formatZH": "下载文件 [path]",
"paramKeys": []
}
}
},
"/files/loadfile": {
"post": {
"security": [
@@ -6706,17 +6893,28 @@ var doc = `{
"ApiKeyAuth": []
}
],
"description": "系统更新信息",
"description": "获取版本 release notes",
"consumes": [
"application/json"
],
"tags": [
"System Setting"
],
"summary": "Load upgrade info",
"summary": "Load release notes by version",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.Upgrade"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/dto.UpgradeInfo"
}
"description": "OK"
}
}
},
@@ -8256,6 +8454,57 @@ var doc = `{
}
}
},
"/websites/ssl/update": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "更新 ssl",
"consumes": [
"application/json"
],
"tags": [
"Website SSL"
],
"summary": "Update ssl",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/request.WebsiteSSLUpdate"
}
}
],
"responses": {
"200": {
"description": ""
}
},
"x-panel-log": {
"BeforeFuntions": [
{
"db": "website_ssls",
"input_colume": "id",
"input_value": "id",
"isList": false,
"output_colume": "primary_domain",
"output_value": "domain"
}
],
"bodyKeys": [
"id"
],
"formatEN": "Update ssl config [domain]",
"formatZH": "更新证书设置 [domain]",
"paramKeys": []
}
}
},
"/websites/ssl/website/:websiteId": {
"get": {
"security": [
@@ -8623,8 +8872,7 @@ var doc = `{
"dto.ComposeCreate": {
"type": "object",
"required": [
"from",
"name"
"from"
],
"properties": {
"file": {
@@ -8860,9 +9108,7 @@ var doc = `{
],
"properties": {
"day": {
"type": "integer",
"maximum": 31,
"minimum": 1
"type": "integer"
},
"dbName": {
"type": "string"
@@ -8871,17 +9117,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 +9184,7 @@ var doc = `{
],
"properties": {
"day": {
"type": "integer",
"maximum": 31,
"minimum": 1
"type": "integer"
},
"dbName": {
"type": "string"
@@ -8953,9 +9193,7 @@ var doc = `{
"type": "string"
},
"hour": {
"type": "integer",
"maximum": 23,
"minimum": 0
"type": "integer"
},
"id": {
"type": "integer"
@@ -8964,9 +9202,7 @@ var doc = `{
"type": "boolean"
},
"minute": {
"type": "integer",
"maximum": 59,
"minimum": 0
"type": "integer"
},
"name": {
"type": "string"
@@ -9060,15 +9296,9 @@ var doc = `{
},
"dto.DaemonJsonUpdateByFile": {
"type": "object",
"required": [
"path"
],
"properties": {
"file": {
"type": "string"
},
"path": {
"type": "string"
}
}
},
@@ -9254,6 +9484,12 @@ var doc = `{
"restart",
"stop"
]
},
"stopService": {
"type": "boolean"
},
"stopSocket": {
"type": "boolean"
}
}
},
@@ -10511,6 +10747,9 @@ var doc = `{
"dto.UpgradeInfo": {
"type": "object",
"properties": {
"latestVersion": {
"type": "string"
},
"newVersion": {
"type": "string"
},
@@ -11042,6 +11281,22 @@ var doc = `{
}
}
},
"request.AppInstalledUpdate": {
"type": "object",
"required": [
"installId",
"params"
],
"properties": {
"installId": {
"type": "integer"
},
"params": {
"type": "object",
"additionalProperties": true
}
}
},
"request.AppSearch": {
"type": "object",
"required": [
@@ -11819,6 +12074,21 @@ var doc = `{
}
}
},
"request.WebsiteSSLUpdate": {
"type": "object",
"required": [
"autoRenew",
"id"
],
"properties": {
"autoRenew": {
"type": "boolean"
},
"id": {
"type": "integer"
}
}
},
"request.WebsiteSearch": {
"type": "object",
"required": [
@@ -12042,10 +12312,29 @@ var doc = `{
"response.AppParam": {
"type": "object",
"properties": {
"label": {
"edit": {
"type": "boolean"
},
"key": {
"type": "string"
},
"value": {}
"labelEn": {
"type": "string"
},
"labelZh": {
"type": "string"
},
"rule": {
"type": "string"
},
"showValue": {
"type": "string"
},
"type": {
"type": "string"
},
"value": {},
"values": {}
}
},
"response.FileInfo": {
@@ -12185,6 +12474,9 @@ var doc = `{
"appInstallId": {
"type": "integer"
},
"appName": {
"type": "string"
},
"createdAt": {
"type": "string"
},

View File

@@ -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": "初始化用户",
@@ -956,6 +1031,48 @@
}
}
},
"/containers/compose/test": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "测试 compose 是否可用",
"consumes": [
"application/json"
],
"tags": [
"Container Compose"
],
"summary": "Test compose",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.ComposeCreate"
}
}
],
"responses": {
"200": {
"description": "OK"
}
},
"x-panel-log": {
"BeforeFuntions": [],
"bodyKeys": [
"name"
],
"formatEN": "check compose [name]",
"formatZH": "检测 compose [name] 格式",
"paramKeys": []
}
}
},
"/containers/compose/update": {
"post": {
"security": [
@@ -3885,6 +4002,34 @@
}
}
},
"/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": ""
}
}
}
},
"/files/compress": {
"post": {
"security": [
@@ -4098,6 +4243,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/dto.FilePath"
}
}
],
"responses": {
"200": {
"description": ""
}
},
"x-panel-log": {
"BeforeFuntions": [],
"bodyKeys": [
"path"
],
"formatEN": "Download file [path]",
"formatZH": "下载文件 [path]",
"paramKeys": []
}
}
},
"/files/loadfile": {
"post": {
"security": [
@@ -6692,17 +6879,28 @@
"ApiKeyAuth": []
}
],
"description": "系统更新信息",
"description": "获取版本 release notes",
"consumes": [
"application/json"
],
"tags": [
"System Setting"
],
"summary": "Load upgrade info",
"summary": "Load release notes by version",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/dto.Upgrade"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/dto.UpgradeInfo"
}
"description": "OK"
}
}
},
@@ -8242,6 +8440,57 @@
}
}
},
"/websites/ssl/update": {
"post": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "更新 ssl",
"consumes": [
"application/json"
],
"tags": [
"Website SSL"
],
"summary": "Update ssl",
"parameters": [
{
"description": "request",
"name": "request",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/request.WebsiteSSLUpdate"
}
}
],
"responses": {
"200": {
"description": ""
}
},
"x-panel-log": {
"BeforeFuntions": [
{
"db": "website_ssls",
"input_colume": "id",
"input_value": "id",
"isList": false,
"output_colume": "primary_domain",
"output_value": "domain"
}
],
"bodyKeys": [
"id"
],
"formatEN": "Update ssl config [domain]",
"formatZH": "更新证书设置 [domain]",
"paramKeys": []
}
}
},
"/websites/ssl/website/:websiteId": {
"get": {
"security": [
@@ -8609,8 +8858,7 @@
"dto.ComposeCreate": {
"type": "object",
"required": [
"from",
"name"
"from"
],
"properties": {
"file": {
@@ -8846,9 +9094,7 @@
],
"properties": {
"day": {
"type": "integer",
"maximum": 31,
"minimum": 1
"type": "integer"
},
"dbName": {
"type": "string"
@@ -8857,17 +9103,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 +9170,7 @@
],
"properties": {
"day": {
"type": "integer",
"maximum": 31,
"minimum": 1
"type": "integer"
},
"dbName": {
"type": "string"
@@ -8939,9 +9179,7 @@
"type": "string"
},
"hour": {
"type": "integer",
"maximum": 23,
"minimum": 0
"type": "integer"
},
"id": {
"type": "integer"
@@ -8950,9 +9188,7 @@
"type": "boolean"
},
"minute": {
"type": "integer",
"maximum": 59,
"minimum": 0
"type": "integer"
},
"name": {
"type": "string"
@@ -9046,15 +9282,9 @@
},
"dto.DaemonJsonUpdateByFile": {
"type": "object",
"required": [
"path"
],
"properties": {
"file": {
"type": "string"
},
"path": {
"type": "string"
}
}
},
@@ -9240,6 +9470,12 @@
"restart",
"stop"
]
},
"stopService": {
"type": "boolean"
},
"stopSocket": {
"type": "boolean"
}
}
},
@@ -10497,6 +10733,9 @@
"dto.UpgradeInfo": {
"type": "object",
"properties": {
"latestVersion": {
"type": "string"
},
"newVersion": {
"type": "string"
},
@@ -11028,6 +11267,22 @@
}
}
},
"request.AppInstalledUpdate": {
"type": "object",
"required": [
"installId",
"params"
],
"properties": {
"installId": {
"type": "integer"
},
"params": {
"type": "object",
"additionalProperties": true
}
}
},
"request.AppSearch": {
"type": "object",
"required": [
@@ -11805,6 +12060,21 @@
}
}
},
"request.WebsiteSSLUpdate": {
"type": "object",
"required": [
"autoRenew",
"id"
],
"properties": {
"autoRenew": {
"type": "boolean"
},
"id": {
"type": "integer"
}
}
},
"request.WebsiteSearch": {
"type": "object",
"required": [
@@ -12028,10 +12298,29 @@
"response.AppParam": {
"type": "object",
"properties": {
"label": {
"edit": {
"type": "boolean"
},
"key": {
"type": "string"
},
"value": {}
"labelEn": {
"type": "string"
},
"labelZh": {
"type": "string"
},
"rule": {
"type": "string"
},
"showValue": {
"type": "string"
},
"type": {
"type": "string"
},
"value": {},
"values": {}
}
},
"response.FileInfo": {
@@ -12171,6 +12460,9 @@
"appInstallId": {
"type": "integer"
},
"appName": {
"type": "string"
},
"createdAt": {
"type": "string"
},

View File

@@ -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
@@ -1402,6 +1389,8 @@ definitions:
type: object
dto.UpgradeInfo:
properties:
latestVersion:
type: string
newVersion:
type: string
releaseNote:
@@ -1752,6 +1741,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:
@@ -2272,6 +2272,16 @@ definitions:
- page
- pageSize
type: object
request.WebsiteSSLUpdate:
properties:
autoRenew:
type: boolean
id:
type: integer
required:
- autoRenew
- id
type: object
request.WebsiteSearch:
properties:
name:
@@ -2421,9 +2431,22 @@ definitions:
type: object
response.AppParam:
properties:
label:
edit:
type: boolean
key:
type: string
labelEn:
type: string
labelZh:
type: string
rule:
type: string
showValue:
type: string
type:
type: string
value: {}
values: {}
type: object
response.FileInfo:
properties:
@@ -2515,6 +2538,8 @@ definitions:
type: string
appInstallId:
type: integer
appName:
type: string
createdAt:
type: string
defaultServer:
@@ -2628,6 +2653,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 +2923,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 +3085,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:
@@ -3205,6 +3277,33 @@ paths:
summary: Page composes
tags:
- Container Compose
/containers/compose/test:
post:
consumes:
- application/json
description: 测试 compose 是否可用
parameters:
- description: request
in: body
name: request
required: true
schema:
$ref: '#/definitions/dto.ComposeCreate'
responses:
"200":
description: OK
security:
- ApiKeyAuth: []
summary: Test compose
tags:
- Container Compose
x-panel-log:
BeforeFuntions: []
bodyKeys:
- name
formatEN: check compose [name]
formatZH: 检测 compose [name] 格式
paramKeys: []
/containers/compose/update:
post:
consumes:
@@ -5065,6 +5164,23 @@ 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
/files/compress:
post:
consumes:
@@ -5202,6 +5318,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/dto.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:
@@ -6853,15 +6996,22 @@ paths:
paramKeys: []
/settings/upgrade:
get:
description: 系统更新信息
consumes:
- application/json
description: 获取版本 release notes
parameters:
- description: request
in: body
name: request
required: true
schema:
$ref: '#/definitions/dto.Upgrade'
responses:
"200":
description: OK
schema:
$ref: '#/definitions/dto.UpgradeInfo'
security:
- ApiKeyAuth: []
summary: Load upgrade info
summary: Load release notes by version
tags:
- System Setting
post:
@@ -7840,6 +7990,39 @@ paths:
summary: Page website ssl
tags:
- Website SSL
/websites/ssl/update:
post:
consumes:
- application/json
description: 更新 ssl
parameters:
- description: request
in: body
name: request
required: true
schema:
$ref: '#/definitions/request.WebsiteSSLUpdate'
responses:
"200":
description: ""
security:
- ApiKeyAuth: []
summary: Update ssl
tags:
- Website SSL
x-panel-log:
BeforeFuntions:
- db: website_ssls
input_colume: id
input_value: id
isList: false
output_colume: primary_domain
output_value: domain
bodyKeys:
- id
formatEN: Update ssl config [domain]
formatZH: 更新证书设置 [domain]
paramKeys: []
/websites/ssl/website/:websiteId:
get:
consumes:

BIN
cmd/server/web/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

View File

@@ -87,6 +87,7 @@ declare module 'vue' {
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']
}

View File

@@ -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",

View File

@@ -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",

View File

@@ -163,5 +163,7 @@ export namespace App {
key: string;
rule: string;
type: string;
values?: any;
showValue?: string;
}
}

View File

@@ -9,7 +9,6 @@ export namespace Login {
export interface MFALoginForm {
name: string;
password: string;
secret: string;
code: string;
authMethod: string;
}
@@ -17,7 +16,6 @@ export namespace Login {
name: string;
token: string;
mfaStatus: string;
mfaSecret: string;
}
export interface InitUser {
name: string;

View File

@@ -43,7 +43,8 @@ export namespace Container {
state: string;
runTime: string;
isFromCompose: string;
isFromApp: boolean;
isFromCompose: boolean;
}
export interface ContainerStats {
cpuPercent: number;

View File

@@ -82,6 +82,7 @@ export namespace Setting {
}
export interface UpgradeInfo {
newVersion: string;
latestVersion: string;
releaseNote: string;
}
}

View File

@@ -79,17 +79,6 @@ export namespace Website {
content: string;
}
export interface Group extends CommonModel {
name: string;
default: boolean;
}
export interface GroupOp {
name: string;
id?: number;
default: boolean;
}
export interface Domain {
websiteId: number;
port: number;
@@ -160,6 +149,7 @@ export namespace Website {
startDate: string;
provider: string;
websites?: Website.Website[];
autoRenew: boolean;
}
export interface SSLCreate {
@@ -179,6 +169,11 @@ export namespace Website {
SSLId: number;
}
export interface SSLUpdate {
id: number;
autoRenew: boolean;
}
export interface AcmeAccount extends CommonModel {
email: string;
url: string;

View File

@@ -6,10 +6,10 @@ 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);
return http.post<string>(`/containers/search/log`, params, 400000);
};
export const ContainerStats = (id: string) => {
return http.get<Container.ContainerStats>(`/containers/stats/${id}`);
@@ -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,16 @@ 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<string>(`/containers/compose`, params);
};
export const testCompose = (params: Container.ComposeCreate) => {
return http.post<boolean>(`/containers/compose/test`, params);
};
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

View File

@@ -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) => {

View File

@@ -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);

View File

@@ -79,6 +79,10 @@ export const DownloadFile = (params: File.FileDownload) => {
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) => {
return http.post<File.DirSizeRes>('files/size', params);
};

Some files were not shown because too many files have changed in this diff Show More