mirror of
https://github.com/tnb-labs/panel.git
synced 2026-08-31 09:19:41 +08:00
Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 30e78ccf46 | |||
| 22f4cc7fcb | |||
| 1771ae682d | |||
| d1beb60ffd | |||
| cba5f86667 | |||
| e1d9832ce0 | |||
| 6278535902 | |||
| 32fb87243b | |||
| 5f85e7fbe0 | |||
| c36104a075 | |||
| 583f5d13c7 | |||
| b453738daf | |||
| 98431fb4b2 | |||
| 4d76e9286d | |||
| c70758339f | |||
| ff524cdb0b | |||
| 73c95d880a | |||
| 8a1d8c0b05 | |||
| 2251175906 | |||
| 69edde98c8 | |||
| 29a3db640d | |||
| ee87bf65b4 |
@@ -2,7 +2,11 @@
|
||||
[简体中文] | [<a href="README_EN.md">English</a>]
|
||||
</p>
|
||||
|
||||
<h1 align="center">耗子面板</h1>
|
||||
<h1 align="center" style="font-size: 40px">耗子面板</h1>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://trendshift.io/repositories/10950" target="_blank"><img src="https://trendshift.io/api/badge/repositories/10950" alt="TheTNB%2Fpanel | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/TheTNB/panel/releases"><img src="https://img.shields.io/github/release/TheTNB/panel.svg"></a>
|
||||
|
||||
+5
-1
@@ -2,7 +2,11 @@
|
||||
[<a href="README.md">简体中文</a>] | [English]
|
||||
</p>
|
||||
|
||||
<h1 align="center">Rat Panel</h1>
|
||||
<h1 align="center" style="font-size: 40px">Rat Panel</h1>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://trendshift.io/repositories/10950" target="_blank"><img src="https://trendshift.io/api/badge/repositories/10950" alt="TheTNB%2Fpanel | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/TheTNB/panel/releases"><img src="https://img.shields.io/github/release/TheTNB/panel.svg"></a>
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"github.com/goravel/framework/support/color"
|
||||
"github.com/spf13/cast"
|
||||
|
||||
requests "github.com/TheTNB/panel/app/http/requests/website"
|
||||
"github.com/TheTNB/panel/app/models"
|
||||
"github.com/TheTNB/panel/internal/services"
|
||||
"github.com/TheTNB/panel/pkg/io"
|
||||
@@ -649,7 +650,7 @@ func (receiver *Panel) Handle(ctx console.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err = website.Delete(id); err != nil {
|
||||
if err = website.Delete(requests.Delete{ID: id}); err != nil {
|
||||
color.Red().Printfln(err.Error())
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -73,6 +73,10 @@ func (r *CertController) DNSProviders(ctx http.Context) http.Response {
|
||||
"name": "DNSPod",
|
||||
"dns": acme.DnsPod,
|
||||
},
|
||||
{
|
||||
"name": "腾讯云",
|
||||
"dns": acme.Tencent,
|
||||
},
|
||||
{
|
||||
"name": "阿里云",
|
||||
"dns": acme.AliYun,
|
||||
|
||||
@@ -225,9 +225,9 @@ func (r *MySQLController) DatabaseList(ctx http.Context) http.Response {
|
||||
// AddDatabase 添加数据库
|
||||
func (r *MySQLController) AddDatabase(ctx http.Context) http.Response {
|
||||
if sanitize := controllers.Sanitize(ctx, map[string]string{
|
||||
"database": "required|min_len:1|max_len:255|regex:^[a-zA-Z][a-zA-Z0-9_]+$",
|
||||
"user": "required|min_len:1|max_len:255|regex:^[a-zA-Z][a-zA-Z0-9_]+$",
|
||||
"password": "required|min_len:8|max_len:255",
|
||||
"database": "required|min_len:1|max_len:64|regex:^[a-zA-Z0-9_]+$",
|
||||
"user": "required|min_len:1|max_len:32|regex:^[a-zA-Z0-9_]+$",
|
||||
"password": "required|min_len:8|max_len:32",
|
||||
}); sanitize != nil {
|
||||
return sanitize
|
||||
}
|
||||
@@ -257,7 +257,7 @@ func (r *MySQLController) AddDatabase(ctx http.Context) http.Response {
|
||||
// DeleteDatabase 删除数据库
|
||||
func (r *MySQLController) DeleteDatabase(ctx http.Context) http.Response {
|
||||
if sanitize := controllers.Sanitize(ctx, map[string]string{
|
||||
"database": "required|min_len:1|max_len:255|regex:^[a-zA-Z][a-zA-Z0-9_]+$|not_in:information_schema,mysql,performance_schema,sys",
|
||||
"database": "required|min_len:1|max_len:64|regex:^[a-zA-Z0-9_]+$|not_in:information_schema,mysql,performance_schema,sys",
|
||||
}); sanitize != nil {
|
||||
return sanitize
|
||||
}
|
||||
@@ -316,7 +316,7 @@ func (r *MySQLController) UploadBackup(ctx http.Context) http.Response {
|
||||
// CreateBackup 创建备份
|
||||
func (r *MySQLController) CreateBackup(ctx http.Context) http.Response {
|
||||
if sanitize := controllers.Sanitize(ctx, map[string]string{
|
||||
"database": "required|min_len:1|max_len:255|regex:^[a-zA-Z][a-zA-Z0-9_]+$|not_in:information_schema,mysql,performance_schema,sys",
|
||||
"database": "required|min_len:1|max_len:64|regex:^[a-zA-Z0-9_]+$|not_in:information_schema,mysql,performance_schema,sys",
|
||||
}); sanitize != nil {
|
||||
return sanitize
|
||||
}
|
||||
@@ -350,7 +350,7 @@ func (r *MySQLController) DeleteBackup(ctx http.Context) http.Response {
|
||||
func (r *MySQLController) RestoreBackup(ctx http.Context) http.Response {
|
||||
if sanitize := controllers.Sanitize(ctx, map[string]string{
|
||||
"backup": "required|min_len:1|max_len:255",
|
||||
"database": "required|min_len:1|max_len:255|regex:^[a-zA-Z][a-zA-Z0-9_]+$|not_in:information_schema,mysql,performance_schema,sys",
|
||||
"database": "required|min_len:1|max_len:64|regex:^[a-zA-Z0-9_]+$|not_in:information_schema,mysql,performance_schema,sys",
|
||||
}); sanitize != nil {
|
||||
return sanitize
|
||||
}
|
||||
@@ -388,9 +388,9 @@ func (r *MySQLController) UserList(ctx http.Context) http.Response {
|
||||
// AddUser 添加用户
|
||||
func (r *MySQLController) AddUser(ctx http.Context) http.Response {
|
||||
if sanitize := controllers.Sanitize(ctx, map[string]string{
|
||||
"database": "required|min_len:1|max_len:255|regex:^[a-zA-Z][a-zA-Z0-9_]+$",
|
||||
"user": "required|min_len:1|max_len:255|regex:^[a-zA-Z][a-zA-Z0-9_]+$",
|
||||
"password": "required|min_len:8|max_len:255",
|
||||
"database": "required|min_len:1|max_len:64|regex:^[a-zA-Z0-9_]+$",
|
||||
"user": "required|min_len:1|max_len:32|regex:^[a-zA-Z0-9_]+$",
|
||||
"password": "required|min_len:8|max_len:32",
|
||||
}); sanitize != nil {
|
||||
return sanitize
|
||||
}
|
||||
@@ -416,7 +416,7 @@ func (r *MySQLController) AddUser(ctx http.Context) http.Response {
|
||||
// DeleteUser 删除用户
|
||||
func (r *MySQLController) DeleteUser(ctx http.Context) http.Response {
|
||||
if sanitize := controllers.Sanitize(ctx, map[string]string{
|
||||
"user": "required|min_len:1|max_len:255|regex:^[a-zA-Z][a-zA-Z0-9_]+$",
|
||||
"user": "required|min_len:1|max_len:32|regex:^[a-zA-Z0-9_]+$",
|
||||
}); sanitize != nil {
|
||||
return sanitize
|
||||
}
|
||||
@@ -437,8 +437,8 @@ func (r *MySQLController) DeleteUser(ctx http.Context) http.Response {
|
||||
// SetUserPassword 设置用户密码
|
||||
func (r *MySQLController) SetUserPassword(ctx http.Context) http.Response {
|
||||
if sanitize := controllers.Sanitize(ctx, map[string]string{
|
||||
"user": "required|min_len:1|max_len:255|regex:^[a-zA-Z][a-zA-Z0-9_]+$",
|
||||
"password": "required|min_len:8|max_len:255",
|
||||
"user": "required|min_len:1|max_len:32|regex:^[a-zA-Z0-9_]+$",
|
||||
"password": "required|min_len:8|max_len:32",
|
||||
}); sanitize != nil {
|
||||
return sanitize
|
||||
}
|
||||
@@ -460,8 +460,8 @@ func (r *MySQLController) SetUserPassword(ctx http.Context) http.Response {
|
||||
// SetUserPrivileges 设置用户权限
|
||||
func (r *MySQLController) SetUserPrivileges(ctx http.Context) http.Response {
|
||||
if sanitize := controllers.Sanitize(ctx, map[string]string{
|
||||
"user": "required|min_len:1|max_len:255|regex:^[a-zA-Z][a-zA-Z0-9_]+$",
|
||||
"database": "required|min_len:1|max_len:255",
|
||||
"user": "required|min_len:1|max_len:32|regex:^[a-zA-Z0-9_]+$",
|
||||
"database": "required|min_len:1|max_len:64|regex:^[a-zA-Z0-9_]+$",
|
||||
}); sanitize != nil {
|
||||
return sanitize
|
||||
}
|
||||
|
||||
@@ -202,9 +202,9 @@ func (r *PostgreSQLController) DatabaseList(ctx http.Context) http.Response {
|
||||
// AddDatabase 添加数据库
|
||||
func (r *PostgreSQLController) AddDatabase(ctx http.Context) http.Response {
|
||||
if sanitize := controllers.Sanitize(ctx, map[string]string{
|
||||
"database": "required|min_len:1|max_len:255|regex:^[a-zA-Z][a-zA-Z0-9_]+$",
|
||||
"user": "required|min_len:1|max_len:255|regex:^[a-zA-Z][a-zA-Z0-9_]+$",
|
||||
"password": "required|min_len:8|max_len:255",
|
||||
"database": "required|min_len:1|max_len:63|regex:^[a-zA-Z0-9_]+$",
|
||||
"user": "required|min_len:1|max_len:30|regex:^[a-zA-Z0-9_]+$",
|
||||
"password": "required|min_len:8|max_len:40",
|
||||
}); sanitize != nil {
|
||||
return sanitize
|
||||
}
|
||||
@@ -241,7 +241,7 @@ func (r *PostgreSQLController) AddDatabase(ctx http.Context) http.Response {
|
||||
// DeleteDatabase 删除数据库
|
||||
func (r *PostgreSQLController) DeleteDatabase(ctx http.Context) http.Response {
|
||||
if sanitize := controllers.Sanitize(ctx, map[string]string{
|
||||
"database": "required|min_len:1|max_len:255|regex:^[a-zA-Z][a-zA-Z0-9_]+$|not_in:postgres,template0,template1",
|
||||
"database": "required|min_len:1|max_len:63|regex:^[a-zA-Z0-9_]+$|not_in:postgres,template0,template1",
|
||||
}); sanitize != nil {
|
||||
return sanitize
|
||||
}
|
||||
@@ -295,7 +295,7 @@ func (r *PostgreSQLController) UploadBackup(ctx http.Context) http.Response {
|
||||
// CreateBackup 创建备份
|
||||
func (r *PostgreSQLController) CreateBackup(ctx http.Context) http.Response {
|
||||
if sanitize := controllers.Sanitize(ctx, map[string]string{
|
||||
"database": "required|min_len:1|max_len:255|regex:^[a-zA-Z][a-zA-Z0-9_]+$|not_in:information_schema,mysql,performance_schema,sys",
|
||||
"database": "required|min_len:1|max_len:63|regex:^[a-zA-Z0-9_]+$|not_in:postgres,template0,template1",
|
||||
}); sanitize != nil {
|
||||
return sanitize
|
||||
}
|
||||
@@ -329,7 +329,7 @@ func (r *PostgreSQLController) DeleteBackup(ctx http.Context) http.Response {
|
||||
func (r *PostgreSQLController) RestoreBackup(ctx http.Context) http.Response {
|
||||
if sanitize := controllers.Sanitize(ctx, map[string]string{
|
||||
"backup": "required|min_len:1|max_len:255",
|
||||
"database": "required|min_len:1|max_len:255|regex:^[a-zA-Z][a-zA-Z0-9_]+$|not_in:information_schema,mysql,performance_schema,sys",
|
||||
"database": "required|min_len:1|max_len:63|regex:^[a-zA-Z0-9_]+$|not_in:postgres,template0,template1",
|
||||
}); sanitize != nil {
|
||||
return sanitize
|
||||
}
|
||||
@@ -420,9 +420,9 @@ func (r *PostgreSQLController) RoleList(ctx http.Context) http.Response {
|
||||
// AddRole 添加角色
|
||||
func (r *PostgreSQLController) AddRole(ctx http.Context) http.Response {
|
||||
if sanitize := controllers.Sanitize(ctx, map[string]string{
|
||||
"database": "required|min_len:1|max_len:255|regex:^[a-zA-Z][a-zA-Z0-9_]+$",
|
||||
"user": "required|min_len:1|max_len:255|regex:^[a-zA-Z][a-zA-Z0-9_]+$",
|
||||
"password": "required|min_len:8|max_len:255",
|
||||
"database": "required|min_len:1|max_len:63|regex:^[a-zA-Z0-9_]+$",
|
||||
"user": "required|min_len:1|max_len:30|regex:^[a-zA-Z0-9_]+$",
|
||||
"password": "required|min_len:8|max_len:40",
|
||||
}); sanitize != nil {
|
||||
return sanitize
|
||||
}
|
||||
@@ -452,7 +452,7 @@ func (r *PostgreSQLController) AddRole(ctx http.Context) http.Response {
|
||||
// DeleteRole 删除角色
|
||||
func (r *PostgreSQLController) DeleteRole(ctx http.Context) http.Response {
|
||||
if sanitize := controllers.Sanitize(ctx, map[string]string{
|
||||
"user": "required|min_len:1|max_len:255|regex:^[a-zA-Z][a-zA-Z0-9_]+$",
|
||||
"user": "required|min_len:1|max_len:30|regex:^[a-zA-Z0-9_]+$",
|
||||
}); sanitize != nil {
|
||||
return sanitize
|
||||
}
|
||||
@@ -475,8 +475,8 @@ func (r *PostgreSQLController) DeleteRole(ctx http.Context) http.Response {
|
||||
// SetRolePassword 设置用户密码
|
||||
func (r *PostgreSQLController) SetRolePassword(ctx http.Context) http.Response {
|
||||
if sanitize := controllers.Sanitize(ctx, map[string]string{
|
||||
"user": "required|min_len:1|max_len:255|regex:^[a-zA-Z][a-zA-Z0-9_]+$",
|
||||
"password": "required|min_len:8|max_len:255",
|
||||
"user": "required|min_len:1|max_len:30|regex:^[a-zA-Z0-9_]+$",
|
||||
"password": "required|min_len:8|max_len:40",
|
||||
}); sanitize != nil {
|
||||
return sanitize
|
||||
}
|
||||
|
||||
@@ -118,23 +118,22 @@ func (r *WebsiteController) Add(ctx http.Context) http.Response {
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Security BearerToken
|
||||
// @Param id path int true "网站 ID"
|
||||
// @Success 200 {object} SuccessResponse
|
||||
// @Router /panel/websites/{id} [delete]
|
||||
// @Param data body requests.Delete true "request"
|
||||
// @Success 200 {object} SuccessResponse
|
||||
// @Router /panel/websites/delete [post]
|
||||
func (r *WebsiteController) Delete(ctx http.Context) http.Response {
|
||||
var idRequest requests.ID
|
||||
sanitize := SanitizeRequest(ctx, &idRequest)
|
||||
var deleteRequest requests.Delete
|
||||
sanitize := SanitizeRequest(ctx, &deleteRequest)
|
||||
if sanitize != nil {
|
||||
return sanitize
|
||||
}
|
||||
|
||||
err := r.website.Delete(idRequest.ID)
|
||||
if err != nil {
|
||||
if err := r.website.Delete(deleteRequest); err != nil {
|
||||
facades.Log().Request(ctx.Request()).Tags("面板", "网站管理").With(map[string]any{
|
||||
"id": idRequest.ID,
|
||||
"id": deleteRequest.ID,
|
||||
"error": err.Error(),
|
||||
}).Info("删除网站失败")
|
||||
return Error(ctx, http.StatusInternalServerError, "删除网站失败: "+err.Error())
|
||||
return Error(ctx, http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
|
||||
return Success(ctx, nil)
|
||||
|
||||
@@ -21,6 +21,10 @@ func (r *CertDeploy) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *CertDeploy) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *CertDeploy) Messages(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,10 @@ func (r *CertShowAndDestroy) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *CertShowAndDestroy) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *CertShowAndDestroy) Messages(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,10 @@ func (r *CertStore) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *CertStore) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *CertStore) Messages(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,10 @@ func (r *CertUpdate) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *CertUpdate) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *CertUpdate) Messages(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,10 @@ func (r *DNSShowAndDestroy) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *DNSShowAndDestroy) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *DNSShowAndDestroy) Messages(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
@@ -19,17 +19,21 @@ func (r *DNSStore) Authorize(ctx http.Context) error {
|
||||
|
||||
func (r *DNSStore) Rules(ctx http.Context) map[string]string {
|
||||
return map[string]string{
|
||||
"type": "required|in:dnspod,aliyun,cloudflare",
|
||||
"type": "required|in:dnspod,tencent,aliyun,cloudflare",
|
||||
"name": "required",
|
||||
"data": "required",
|
||||
"data.id": "required_if:type,dnspod",
|
||||
"data.token": "required_if:type,dnspod",
|
||||
"data.access_key": "required_if:type,aliyun",
|
||||
"data.secret_key": "required_if:type,aliyun",
|
||||
"data.access_key": "required_if:type,aliyun,tencent",
|
||||
"data.secret_key": "required_if:type,aliyun,tencent",
|
||||
"data.api_key": "required_if:type,cloudflare",
|
||||
}
|
||||
}
|
||||
|
||||
func (r *DNSStore) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *DNSStore) Messages(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
@@ -33,6 +33,10 @@ func (r *DNSUpdate) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *DNSUpdate) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *DNSUpdate) Messages(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,10 @@ func (r *Obtain) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Obtain) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *Obtain) Messages(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,10 @@ func (r *Renew) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Renew) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *Renew) Messages(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,10 @@ func (r *UserShowAndDestroy) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *UserShowAndDestroy) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *UserShowAndDestroy) Messages(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,10 @@ func (r *UserStore) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *UserStore) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *UserStore) Messages(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,10 @@ func (r *UserUpdate) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *UserUpdate) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *UserUpdate) Messages(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,10 @@ func (r *Paginate) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Paginate) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *Paginate) Messages(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
@@ -64,6 +64,10 @@ func (r *ContainerCreate) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *ContainerCreate) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *ContainerCreate) Messages(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,10 @@ func (r *ContainerRename) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *ContainerRename) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *ContainerRename) Messages(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
@@ -57,6 +57,10 @@ func (r *ContainerUpdate) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *ContainerUpdate) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *ContainerUpdate) Messages(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,10 @@ func (r *ID) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *ID) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *ID) Messages(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,10 @@ func (r *ImagePull) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *ImagePull) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *ImagePull) Messages(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,10 @@ func (r *NetworkConnectDisConnect) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *NetworkConnectDisConnect) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *NetworkConnectDisConnect) Messages(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,10 @@ func (r *NetworkCreate) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *NetworkCreate) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *NetworkCreate) Messages(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
@@ -27,6 +27,10 @@ func (r *VolumeCreate) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *VolumeCreate) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *VolumeCreate) Messages(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,10 @@ func (r *Archive) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Archive) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *Archive) Messages(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,10 @@ func (r *Copy) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Copy) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *Copy) Messages(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,10 @@ func (r *Exist) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Exist) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *Exist) Messages(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,10 @@ func (r *Move) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Move) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *Move) Messages(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,10 @@ func (r *NotExist) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *NotExist) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *NotExist) Messages(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,10 @@ func (r *Permission) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Permission) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *Permission) Messages(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,10 @@ func (r *Save) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Save) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *Save) Messages(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,10 @@ func (r *Search) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Search) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *Search) Messages(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,10 @@ func (r *UnArchive) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *UnArchive) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *UnArchive) Messages(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,10 @@ func (r *Upload) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Upload) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *Upload) Messages(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,10 @@ func (r *Service) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Service) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *Service) Messages(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,10 @@ func (r *UpdateConfig) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *UpdateConfig) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *UpdateConfig) Messages(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,10 @@ func (r *UpdateConfig) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *UpdateConfig) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *UpdateConfig) Messages(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,10 @@ func (r *UpdateRegistryConfig) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *UpdateRegistryConfig) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *UpdateRegistryConfig) Messages(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,10 @@ func (r *UpdateStorageConfig) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *UpdateStorageConfig) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *UpdateStorageConfig) Messages(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,10 @@ func (r *Create) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Create) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *Create) Messages(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,10 @@ func (r *Update) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Update) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *Update) Messages(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,10 @@ func (r *UpdateConfig) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *UpdateConfig) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *UpdateConfig) Messages(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,10 @@ func (r *Https) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Https) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *Https) Messages(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,10 @@ func (r *Update) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Update) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *Update) Messages(ctx http.Context) map[string]string {
|
||||
return map[string]string{
|
||||
"port.int": "port 值必须是一个整数且在 1000 - 65535 之间",
|
||||
|
||||
@@ -23,12 +23,16 @@ func (r *Login) Rules(ctx http.Context) map[string]string {
|
||||
|
||||
func (r *Login) Messages(ctx http.Context) map[string]string {
|
||||
return map[string]string{
|
||||
"username.required": "登录名不能为空",
|
||||
"username.required": "用户名不能为空",
|
||||
"password.required": "密码不能为空",
|
||||
"password.min_len": "密码长度不能小于 8 位",
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Login) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *Login) Attributes(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,10 @@ func (r *Add) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Add) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *Add) Messages(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
package requests
|
||||
|
||||
import (
|
||||
"github.com/goravel/framework/contracts/http"
|
||||
"github.com/goravel/framework/contracts/validation"
|
||||
)
|
||||
|
||||
type Delete struct {
|
||||
ID uint `form:"id" json:"id" filter:"uint"`
|
||||
Path bool `form:"path" json:"path"`
|
||||
DB bool `form:"db" json:"db"`
|
||||
}
|
||||
|
||||
func (r *Delete) Authorize(ctx http.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Delete) Rules(ctx http.Context) map[string]string {
|
||||
return map[string]string{
|
||||
"id": "required|exists:websites,id",
|
||||
"path": "bool",
|
||||
"db": "bool",
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Delete) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *Delete) Messages(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *Delete) Attributes(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *Delete) PrepareForValidation(ctx http.Context, data validation.Data) error {
|
||||
return nil
|
||||
}
|
||||
@@ -19,6 +19,10 @@ func (r *DeleteBackup) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *DeleteBackup) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *DeleteBackup) Messages(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,10 @@ func (r *ID) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *ID) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *ID) Messages(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,10 @@ func (r *RestoreBackup) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *RestoreBackup) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *RestoreBackup) Messages(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
@@ -57,6 +57,10 @@ func (r *SaveConfig) Rules(ctx http.Context) map[string]string {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *SaveConfig) Filters(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
func (r *SaveConfig) Messages(ctx http.Context) map[string]string {
|
||||
return map[string]string{}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
type CertDNS struct {
|
||||
orm.Model
|
||||
Name string `gorm:"not null" json:"name"` // 备注名称
|
||||
Type string `gorm:"not null" json:"type"` // DNS 提供商 (dnspod, aliyun, cloudflare)
|
||||
Type string `gorm:"not null" json:"type"` // DNS 提供商 (dnspod, tencent, aliyun, cloudflare)
|
||||
Data acme.DNSParam `gorm:"not null;serializer:json" json:"dns_param"`
|
||||
|
||||
Certs []*Cert `gorm:"foreignKey:DNSID" json:"-"`
|
||||
|
||||
@@ -25,7 +25,6 @@ func (receiver *ValidationServiceProvider) rules() []validation.Rule {
|
||||
return []validation.Rule{
|
||||
&rules.Exists{},
|
||||
&rules.NotExists{},
|
||||
&rules.Captcha{},
|
||||
&rules.PathExists{},
|
||||
&rules.PathNotExists{},
|
||||
}
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
package rules
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/goravel/framework/contracts/validation"
|
||||
|
||||
"github.com/TheTNB/panel/pkg/captcha"
|
||||
)
|
||||
|
||||
type Captcha struct {
|
||||
}
|
||||
|
||||
// Signature The name of the rule.
|
||||
func (receiver *Captcha) Signature() string {
|
||||
return "captcha"
|
||||
}
|
||||
|
||||
// Passes Determine if the validation rule passes.
|
||||
func (receiver *Captcha) Passes(data validation.Data, val any, options ...any) bool {
|
||||
captchaID, exist := data.Get("captcha_id")
|
||||
if !exist {
|
||||
return false
|
||||
}
|
||||
|
||||
// 第一个参数(如果有),是否清除验证码,如 false
|
||||
clear := true
|
||||
var err error
|
||||
if len(options) > 0 {
|
||||
clear, err = strconv.ParseBool(options[0].(string))
|
||||
if err != nil {
|
||||
clear = true
|
||||
}
|
||||
}
|
||||
|
||||
if !captcha.NewCaptcha().VerifyCaptcha(captchaID.(string), val.(string), clear) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Message Get the validation error message.
|
||||
func (receiver *Captcha) Message() string {
|
||||
return ""
|
||||
}
|
||||
+1
-1
@@ -11,7 +11,7 @@ import (
|
||||
|
||||
func Boot() {
|
||||
debug.SetGCPercent(10)
|
||||
debug.SetMemoryLimit(512 << 20)
|
||||
debug.SetMemoryLimit(64 << 20)
|
||||
|
||||
zhcn.RegisterGlobal()
|
||||
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"github.com/goravel/framework/facades"
|
||||
)
|
||||
|
||||
func init() {
|
||||
config := facades.Config()
|
||||
config.Add("captcha", map[string]any{
|
||||
// 验证码图片高度
|
||||
"height": 60,
|
||||
|
||||
// 验证码图片宽度
|
||||
"width": 120,
|
||||
|
||||
// 验证码的长度
|
||||
"length": 6,
|
||||
|
||||
// 数字的最大倾斜角度
|
||||
"maxskew": 0.6,
|
||||
|
||||
// 图片背景里的混淆点数量
|
||||
"dotcount": 40,
|
||||
|
||||
// 过期时间,单位是分钟
|
||||
"expire_time": 5,
|
||||
|
||||
// debug 模式下的过期时间,方便本地开发调试
|
||||
"debug_expire_time": 3600,
|
||||
|
||||
// 非 production 环境,使用此 key 可跳过验证,方便测试
|
||||
"testing_key": "captcha_skip_test",
|
||||
})
|
||||
}
|
||||
+1
-1
@@ -8,7 +8,7 @@ func init() {
|
||||
config := facades.Config()
|
||||
config.Add("panel", map[string]any{
|
||||
"name": "耗子面板",
|
||||
"version": "v2.2.17",
|
||||
"version": "v2.2.19",
|
||||
"ssl": config.Env("APP_SSL", false),
|
||||
})
|
||||
}
|
||||
|
||||
+24
-8
@@ -3574,8 +3574,8 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"/panel/websites/{id}": {
|
||||
"delete": {
|
||||
"/panel/websites/delete": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"BearerToken": []
|
||||
@@ -3593,11 +3593,13 @@ const docTemplate = `{
|
||||
"summary": "删除网站",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "网站 ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
"description": "request",
|
||||
"name": "data",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/requests.Delete"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -5156,7 +5158,7 @@ const docTemplate = `{
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"description": "DNS 提供商 (dnspod, aliyun, cloudflare)",
|
||||
"description": "DNS 提供商 (dnspod, tencent, aliyun, cloudflare)",
|
||||
"type": "string"
|
||||
},
|
||||
"updated_at": {
|
||||
@@ -5506,6 +5508,20 @@ const docTemplate = `{
|
||||
}
|
||||
}
|
||||
},
|
||||
"requests.Delete": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"db": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"path": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"requests.DeleteBackup": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
+24
-8
@@ -3567,8 +3567,8 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/panel/websites/{id}": {
|
||||
"delete": {
|
||||
"/panel/websites/delete": {
|
||||
"post": {
|
||||
"security": [
|
||||
{
|
||||
"BearerToken": []
|
||||
@@ -3586,11 +3586,13 @@
|
||||
"summary": "删除网站",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "integer",
|
||||
"description": "网站 ID",
|
||||
"name": "id",
|
||||
"in": "path",
|
||||
"required": true
|
||||
"description": "request",
|
||||
"name": "data",
|
||||
"in": "body",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"$ref": "#/definitions/requests.Delete"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -5149,7 +5151,7 @@
|
||||
"type": "string"
|
||||
},
|
||||
"type": {
|
||||
"description": "DNS 提供商 (dnspod, aliyun, cloudflare)",
|
||||
"description": "DNS 提供商 (dnspod, tencent, aliyun, cloudflare)",
|
||||
"type": "string"
|
||||
},
|
||||
"updated_at": {
|
||||
@@ -5499,6 +5501,20 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"requests.Delete": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"db": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"id": {
|
||||
"type": "integer"
|
||||
},
|
||||
"path": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"requests.DeleteBackup": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
+33
-23
@@ -148,7 +148,7 @@ definitions:
|
||||
description: 备注名称
|
||||
type: string
|
||||
type:
|
||||
description: DNS 提供商 (dnspod, aliyun, cloudflare)
|
||||
description: DNS 提供商 (dnspod, tencent, aliyun, cloudflare)
|
||||
type: string
|
||||
updated_at:
|
||||
$ref: '#/definitions/github_com_goravel_framework_support_carbon.DateTime'
|
||||
@@ -377,6 +377,15 @@ definitions:
|
||||
type:
|
||||
type: string
|
||||
type: object
|
||||
requests.Delete:
|
||||
properties:
|
||||
db:
|
||||
type: boolean
|
||||
id:
|
||||
type: integer
|
||||
path:
|
||||
type: boolean
|
||||
type: object
|
||||
requests.DeleteBackup:
|
||||
properties:
|
||||
name:
|
||||
@@ -2840,28 +2849,6 @@ paths:
|
||||
summary: 添加网站
|
||||
tags:
|
||||
- 网站
|
||||
/panel/websites/{id}:
|
||||
delete:
|
||||
consumes:
|
||||
- application/json
|
||||
parameters:
|
||||
- description: 网站 ID
|
||||
in: path
|
||||
name: id
|
||||
required: true
|
||||
type: integer
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/controllers.SuccessResponse'
|
||||
security:
|
||||
- BearerToken: []
|
||||
summary: 删除网站
|
||||
tags:
|
||||
- 网站
|
||||
/panel/websites/{id}/config:
|
||||
get:
|
||||
consumes:
|
||||
@@ -3048,6 +3035,29 @@ paths:
|
||||
summary: 更新网站备注
|
||||
tags:
|
||||
- 网站
|
||||
/panel/websites/delete:
|
||||
post:
|
||||
consumes:
|
||||
- application/json
|
||||
parameters:
|
||||
- description: request
|
||||
in: body
|
||||
name: data
|
||||
required: true
|
||||
schema:
|
||||
$ref: '#/definitions/requests.Delete'
|
||||
produces:
|
||||
- application/json
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
$ref: '#/definitions/controllers.SuccessResponse'
|
||||
security:
|
||||
- BearerToken: []
|
||||
summary: 删除网站
|
||||
tags:
|
||||
- 网站
|
||||
/plugins/frp/config:
|
||||
get:
|
||||
description: 获取 Frp 配置
|
||||
|
||||
@@ -3,13 +3,13 @@ module github.com/TheTNB/panel
|
||||
go 1.22
|
||||
|
||||
require (
|
||||
github.com/docker/docker v26.1.4+incompatible
|
||||
github.com/docker/docker v27.0.3+incompatible
|
||||
github.com/docker/go-connections v0.5.0
|
||||
github.com/go-gormigrate/gormigrate/v2 v2.1.2
|
||||
github.com/go-resty/resty/v2 v2.13.1
|
||||
github.com/go-sql-driver/mysql v1.8.1
|
||||
github.com/gookit/validate v1.5.2
|
||||
github.com/goravel/framework v1.14.1-0.20240618022250-731b8d9930a3
|
||||
github.com/goravel/framework v1.14.1-0.20240627172353-91c3c46cf333
|
||||
github.com/goravel/gin v1.2.1
|
||||
github.com/gorilla/websocket v1.5.3
|
||||
github.com/lib/pq v1.10.9
|
||||
@@ -17,9 +17,9 @@ require (
|
||||
github.com/libdns/cloudflare v0.1.1
|
||||
github.com/libdns/dnspod v0.0.3
|
||||
github.com/libdns/libdns v0.2.2
|
||||
github.com/libdns/tencentcloud v1.0.0
|
||||
github.com/mholt/acmez/v2 v2.0.1
|
||||
github.com/mholt/archiver/v3 v3.5.1
|
||||
github.com/mojocn/base64Captcha v1.3.6
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible
|
||||
github.com/spf13/cast v1.6.0
|
||||
github.com/stretchr/testify v1.9.0
|
||||
@@ -98,7 +98,6 @@ require (
|
||||
github.com/golang-module/carbon/v2 v2.3.12 // indirect
|
||||
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
|
||||
github.com/golang-sql/sqlexp v0.1.0 // indirect
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7 // indirect
|
||||
@@ -169,6 +168,7 @@ require (
|
||||
github.com/stretchr/objx v0.5.2 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
github.com/swaggo/files/v2 v2.0.0 // indirect
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.597 // indirect
|
||||
github.com/tklauser/go-sysconf v0.3.12 // indirect
|
||||
github.com/tklauser/numcpus v0.6.1 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
@@ -190,7 +190,6 @@ require (
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/arch v0.8.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 // indirect
|
||||
golang.org/x/image v0.13.0 // indirect
|
||||
golang.org/x/mod v0.17.0 // indirect
|
||||
golang.org/x/sync v0.7.0 // indirect
|
||||
golang.org/x/sys v0.21.0 // indirect
|
||||
|
||||
@@ -134,8 +134,8 @@ github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK
|
||||
github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
|
||||
github.com/dnaeon/go-vcr v1.1.0/go.mod h1:M7tiix8f0r6mKKJ3Yq/kqU1OYf3MnfmBWVbPx/yU9ko=
|
||||
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
|
||||
github.com/docker/docker v26.1.4+incompatible h1:vuTpXDuoga+Z38m1OZHzl7NKisKWaWlhjQk7IDPSLsU=
|
||||
github.com/docker/docker v26.1.4+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v27.0.3+incompatible h1:aBGI9TeQ4MPlhquTQKq9XbK79rKFVwXNUAYz9aXyEBE=
|
||||
github.com/docker/docker v27.0.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
|
||||
github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
|
||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||
@@ -225,8 +225,6 @@ github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 h1:au07oEsX2xN0kt
|
||||
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||
github.com/golang-sql/sqlexp v0.1.0 h1:ZCD6MBpcuOVfGVqsEmY5/4FtYiKz6tSyUv9LPEDei6A=
|
||||
github.com/golang-sql/sqlexp v0.1.0/go.mod h1:J4ad9Vo8ZCWQ2GMrC4UCQy1JpCbwU9m3EOqtpKwwwHI=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
@@ -278,8 +276,8 @@ github.com/gookit/validate v1.5.2 h1:i5I2OQ7WYHFRPRATGu9QarR9snnNHydvwSuHXaRWAV0
|
||||
github.com/gookit/validate v1.5.2/go.mod h1:yuPy2WwDlwGRa06fFJ5XIO8QEwhRnTC2LmxmBa5SE14=
|
||||
github.com/goravel/file-rotatelogs/v2 v2.4.2 h1:g68AzbePXcm0V2CpUMc9j4qVzcDn7+7aoWSjZ51C0m4=
|
||||
github.com/goravel/file-rotatelogs/v2 v2.4.2/go.mod h1:23VuSW8cBS4ax5cmbV+5AaiLpq25b8UJ96IhbAkdo8I=
|
||||
github.com/goravel/framework v1.14.1-0.20240618022250-731b8d9930a3 h1:G9aMInp4s2pL/bpVXrUj+NUtnVU8i7T9t6vGUJ60NaM=
|
||||
github.com/goravel/framework v1.14.1-0.20240618022250-731b8d9930a3/go.mod h1:RTwF0A7HySf5i+2jptT9oyFqmQAiQubWn1AQrJAzPWg=
|
||||
github.com/goravel/framework v1.14.1-0.20240627172353-91c3c46cf333 h1:hOj1S1TQQ/19ng0JzpbTfscB128L5E5dIcx/mU1zofc=
|
||||
github.com/goravel/framework v1.14.1-0.20240627172353-91c3c46cf333/go.mod h1:8Fz0+JHyqwnOLy8rFkFWPQXv0Bkk3JEB43OV/Wx7xCA=
|
||||
github.com/goravel/gin v1.2.1 h1:lnQX3NKUEaSx8x7AAJpoeVkXgi+MVQ9FXy4QywHQElo=
|
||||
github.com/goravel/gin v1.2.1/go.mod h1:Qt3NJysg/eoxXL4y/swwFUcfcIT7XG+xb0rWChweZfY=
|
||||
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
||||
@@ -363,6 +361,8 @@ github.com/libdns/libdns v0.2.0/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSO
|
||||
github.com/libdns/libdns v0.2.1/go.mod h1:yQCXzk1lEZmmCPa857bnk4TsOiqYasqpyOEeSObbb40=
|
||||
github.com/libdns/libdns v0.2.2 h1:O6ws7bAfRPaBsgAYt8MDe2HcNBGC29hkZ9MX2eUSX3s=
|
||||
github.com/libdns/libdns v0.2.2/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ=
|
||||
github.com/libdns/tencentcloud v1.0.0 h1:u4LXnYu/lu/9P5W+MCVPeSDnwI+6w+DxYhQ1wSnQOuU=
|
||||
github.com/libdns/tencentcloud v1.0.0/go.mod h1:NlCgPumzUsZWSOo1+Q/Hfh8G6TNRAaTUeWQdg6LbtUI=
|
||||
github.com/lithammer/fuzzysearch v1.1.8 h1:/HIuJnjHuXS8bKaiTMeeDlW2/AyIWk2brx1V8LFgLN4=
|
||||
github.com/lithammer/fuzzysearch v1.1.8/go.mod h1:IdqeyBClc3FFqSzYq/MXESsS4S0FsZ5ajtkr5xPLts4=
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
||||
@@ -396,8 +396,6 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8=
|
||||
github.com/mojocn/base64Captcha v1.3.6 h1:gZEKu1nsKpttuIAQgWHO+4Mhhls8cAKyiV2Ew03H+Tw=
|
||||
github.com/mojocn/base64Captcha v1.3.6/go.mod h1:i5CtHvm+oMbj1UzEPXaA8IH/xHFZ3DGY3Wh3dBpZ28E=
|
||||
github.com/montanaflynn/stats v0.7.0/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
|
||||
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||
@@ -513,6 +511,8 @@ github.com/swaggo/http-swagger/v2 v2.0.2 h1:FKCdLsl+sFCx60KFsyM0rDarwiUSZ8DqbfSy
|
||||
github.com/swaggo/http-swagger/v2 v2.0.2/go.mod h1:r7/GBkAWIfK6E/OLnE8fXnviHiDeAHmgIyooa4xm3AQ=
|
||||
github.com/swaggo/swag v1.16.3 h1:PnCYjPCah8FK4I26l2F/KQ4yz3sILcVUN3cTlBFA9Pg=
|
||||
github.com/swaggo/swag v1.16.3/go.mod h1:DImHIuOFXKpMFAQjcC7FG4m3Dg4+QuUgUzJmKjI/gRk=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.597 h1:C0GHdLTfikLVoEzfhgPfrZ7LwlG0xiCmk6iwNKE+xs0=
|
||||
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.597/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y=
|
||||
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
|
||||
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
|
||||
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
|
||||
@@ -596,8 +596,6 @@ golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5D
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225 h1:LfspQV/FYTatPTr/3HzIcmiUFH7PGP+OQ6mgDYo3yuQ=
|
||||
golang.org/x/exp v0.0.0-20240222234643-814bf88cf225/go.mod h1:CxmFvTBINI24O/j8iY7H1xHzx2i4OsyguNBmN/uPtqc=
|
||||
golang.org/x/image v0.13.0 h1:3cge/F/QTkNLauhf2QoE9zp+7sr+ZcL4HnoZmdwg9sg=
|
||||
golang.org/x/image v0.13.0/go.mod h1:6mmbMOeV28HuMTgA6OSRkdXKYw/t5W9Uwn2Yv1r3Yxk=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
|
||||
@@ -24,16 +24,16 @@ type Container interface {
|
||||
ContainerInspect(id string) (types.ContainerJSON, error)
|
||||
ContainerKill(id string) error
|
||||
ContainerRename(id string, newName string) error
|
||||
ContainerStats(id string) (types.ContainerStats, error)
|
||||
ContainerStats(id string) (container.StatsResponseReader, error)
|
||||
ContainerExist(name string) (bool, error)
|
||||
ContainerUpdate(id string, config container.UpdateConfig) error
|
||||
ContainerLogs(id string) (string, error)
|
||||
ContainerPrune() error
|
||||
NetworkList() ([]types.NetworkResource, error)
|
||||
NetworkList() ([]network.Inspect, error)
|
||||
NetworkCreate(config requests.NetworkCreate) (string, error)
|
||||
NetworkRemove(id string) error
|
||||
NetworkExist(name string) (bool, error)
|
||||
NetworkInspect(id string) (types.NetworkResource, error)
|
||||
NetworkInspect(id string) (network.Inspect, error)
|
||||
NetworkConnect(networkID string, containerID string) error
|
||||
NetworkDisconnect(networkID string, containerID string) error
|
||||
NetworkPrune() error
|
||||
|
||||
@@ -165,7 +165,7 @@ func (s *BackupImpl) MysqlBackup(database string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := shell.Execf("/www/server/mysql/bin/mysqldump -uroot " + database + " > " + backupPath + "/" + backupFile); err != nil {
|
||||
if _, err := shell.Execf("mysqldump -uroot " + database + " > " + backupPath + "/" + backupFile); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := shell.Execf("cd " + backupPath + " && zip -r " + backupPath + "/" + backupFile + ".zip " + backupFile); err != nil {
|
||||
@@ -219,7 +219,7 @@ func (s *BackupImpl) MysqlRestore(database string, backupFile string) error {
|
||||
return errors.New("无法找到备份文件")
|
||||
}
|
||||
|
||||
if _, err = shell.Execf("/www/server/mysql/bin/mysql -uroot " + database + " < " + filepath.Join(tempDir, backupFile)); err != nil {
|
||||
if _, err = shell.Execf("mysql -uroot " + database + " < " + filepath.Join(tempDir, backupFile)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -118,7 +118,7 @@ func (r *Container) ContainerRename(id string, newName string) error {
|
||||
}
|
||||
|
||||
// ContainerStats 查看容器状态
|
||||
func (r *Container) ContainerStats(id string) (types.ContainerStats, error) {
|
||||
func (r *Container) ContainerStats(id string) (container.StatsResponseReader, error) {
|
||||
return r.client.ContainerStats(context.Background(), id, false)
|
||||
}
|
||||
|
||||
@@ -167,8 +167,8 @@ func (r *Container) ContainerPrune() error {
|
||||
}
|
||||
|
||||
// NetworkList 列出网络
|
||||
func (r *Container) NetworkList() ([]types.NetworkResource, error) {
|
||||
return r.client.NetworkList(context.Background(), types.NetworkListOptions{})
|
||||
func (r *Container) NetworkList() ([]network.Inspect, error) {
|
||||
return r.client.NetworkList(context.Background(), network.ListOptions{})
|
||||
}
|
||||
|
||||
// NetworkCreate 创建网络
|
||||
@@ -189,8 +189,8 @@ func (r *Container) NetworkCreate(config requests.NetworkCreate) (string, error)
|
||||
})
|
||||
}
|
||||
|
||||
options := types.NetworkCreate{
|
||||
EnableIPv6: config.Ipv6.Enabled,
|
||||
options := network.CreateOptions{
|
||||
EnableIPv6: &config.Ipv6.Enabled,
|
||||
Driver: config.Driver,
|
||||
Options: r.KVToMap(config.Options),
|
||||
Labels: r.KVToMap(config.Labels),
|
||||
@@ -212,7 +212,7 @@ func (r *Container) NetworkRemove(id string) error {
|
||||
|
||||
// NetworkExist 判断网络是否存在
|
||||
func (r *Container) NetworkExist(name string) (bool, error) {
|
||||
var options types.NetworkListOptions
|
||||
var options network.ListOptions
|
||||
options.Filters = filters.NewArgs(filters.Arg("name", name))
|
||||
networks, err := r.client.NetworkList(context.Background(), options)
|
||||
if err != nil {
|
||||
@@ -223,8 +223,8 @@ func (r *Container) NetworkExist(name string) (bool, error) {
|
||||
}
|
||||
|
||||
// NetworkInspect 查看网络
|
||||
func (r *Container) NetworkInspect(id string) (types.NetworkResource, error) {
|
||||
return r.client.NetworkInspect(context.Background(), id, types.NetworkInspectOptions{})
|
||||
func (r *Container) NetworkInspect(id string) (network.Inspect, error) {
|
||||
return r.client.NetworkInspect(context.Background(), id, network.InspectOptions{})
|
||||
}
|
||||
|
||||
// NetworkConnect 连接网络
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
"github.com/TheTNB/panel/app/models"
|
||||
"github.com/TheTNB/panel/internal"
|
||||
"github.com/TheTNB/panel/pkg/cert"
|
||||
"github.com/TheTNB/panel/pkg/db"
|
||||
"github.com/TheTNB/panel/pkg/io"
|
||||
"github.com/TheTNB/panel/pkg/shell"
|
||||
"github.com/TheTNB/panel/pkg/str"
|
||||
@@ -296,16 +297,25 @@ server
|
||||
|
||||
rootPassword := r.setting.Get(models.SettingKeyMysqlRootPassword)
|
||||
if website.Db && website.DbType == "mysql" {
|
||||
_, _ = shell.Execf(`/www/server/mysql/bin/mysql -uroot -p` + rootPassword + ` -e "CREATE DATABASE IF NOT EXISTS ` + website.DbName + ` DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_general_ci;"`)
|
||||
_, _ = shell.Execf(`/www/server/mysql/bin/mysql -uroot -p` + rootPassword + ` -e "CREATE USER '` + website.DbUser + `'@'localhost' IDENTIFIED BY '` + website.DbPassword + `';"`)
|
||||
_, _ = shell.Execf(`/www/server/mysql/bin/mysql -uroot -p` + rootPassword + ` -e "GRANT ALL PRIVILEGES ON ` + website.DbName + `.* TO '` + website.DbUser + `'@'localhost';"`)
|
||||
_, _ = shell.Execf(`/www/server/mysql/bin/mysql -uroot -p` + rootPassword + ` -e "FLUSH PRIVILEGES;"`)
|
||||
mysql, err := db.NewMySQL("root", rootPassword, "/tmp/mysql.sock", "unix")
|
||||
if err != nil {
|
||||
return models.Website{}, err
|
||||
}
|
||||
if err = mysql.DatabaseCreate(website.DbName); err != nil {
|
||||
return models.Website{}, err
|
||||
}
|
||||
if err = mysql.UserCreate(website.DbUser, website.DbPassword); err != nil {
|
||||
return models.Website{}, err
|
||||
}
|
||||
if err = mysql.PrivilegesGrant(website.DbUser, website.DbName); err != nil {
|
||||
return models.Website{}, err
|
||||
}
|
||||
}
|
||||
if website.Db && website.DbType == "postgresql" {
|
||||
_, _ = shell.Execf(`echo "CREATE DATABASE ` + website.DbName + `;" | su - postgres -c "psql"`)
|
||||
_, _ = shell.Execf(`echo "CREATE USER ` + website.DbUser + ` WITH PASSWORD '` + website.DbPassword + `';" | su - postgres -c "psql"`)
|
||||
_, _ = shell.Execf(`echo "ALTER DATABASE ` + website.DbName + ` OWNER TO ` + website.DbUser + `;" | su - postgres -c "psql"`)
|
||||
_, _ = shell.Execf(`echo "GRANT ALL PRIVILEGES ON DATABASE ` + website.DbName + ` TO ` + website.DbUser + `;" | su - postgres -c "psql"`)
|
||||
_, _ = shell.Execf(`echo "CREATE DATABASE '%s';" | su - postgres -c "psql"`, website.DbName)
|
||||
_, _ = shell.Execf(`echo "CREATE USER '%s' WITH PASSWORD '%s';" | su - postgres -c "psql"`, website.DbUser, website.DbPassword)
|
||||
_, _ = shell.Execf(`echo "ALTER DATABASE '%s' OWNER TO '%s';" | su - postgres -c "psql"`, website.DbName, website.DbUser)
|
||||
_, _ = shell.Execf(`echo "GRANT ALL PRIVILEGES ON DATABASE '%s' TO '%s';" | su - postgres -c "psql"`, website.DbName, website.DbUser)
|
||||
userConfig := "host " + website.DbName + " " + website.DbUser + " 127.0.0.1/32 scram-sha-256"
|
||||
_, _ = shell.Execf(`echo "` + userConfig + `" >> /www/server/postgresql/data/pg_hba.conf`)
|
||||
_ = systemctl.Reload("postgresql")
|
||||
@@ -540,9 +550,9 @@ func (r *WebsiteImpl) SaveConfig(config requests.SaveConfig) error {
|
||||
}
|
||||
|
||||
// Delete 删除网站
|
||||
func (r *WebsiteImpl) Delete(id uint) error {
|
||||
func (r *WebsiteImpl) Delete(request requests.Delete) error {
|
||||
var website models.Website
|
||||
if err := facades.Orm().Query().With("Cert").Where("id", id).FirstOrFail(&website); err != nil {
|
||||
if err := facades.Orm().Query().With("Cert").Where("id", request.ID).FirstOrFail(&website); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -559,7 +569,21 @@ func (r *WebsiteImpl) Delete(id uint) error {
|
||||
_ = io.Remove("/www/server/vhost/acme/" + website.Name + ".conf")
|
||||
_ = io.Remove("/www/server/vhost/ssl/" + website.Name + ".pem")
|
||||
_ = io.Remove("/www/server/vhost/ssl/" + website.Name + ".key")
|
||||
_ = io.Remove(website.Path)
|
||||
|
||||
if request.Path {
|
||||
_ = io.Remove(website.Path)
|
||||
}
|
||||
if request.DB {
|
||||
rootPassword := r.setting.Get(models.SettingKeyMysqlRootPassword)
|
||||
mysql, err := db.NewMySQL("root", rootPassword, "/tmp/mysql.sock", "unix")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_ = mysql.DatabaseDrop(website.Name)
|
||||
_ = mysql.UserDrop(website.Name)
|
||||
_, _ = shell.Execf(`echo "DROP DATABASE IF EXISTS '%s';" | su - postgres -c "psql"`, website.Name)
|
||||
_, _ = shell.Execf(`echo "DROP USER IF EXISTS '%s';" | su - postgres -c "psql"`, website.Name)
|
||||
}
|
||||
|
||||
err := systemctl.Reload("openresty")
|
||||
if err != nil {
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ type Website interface {
|
||||
List(page int, limit int) (int64, []models.Website, error)
|
||||
Add(website types.WebsiteAdd) (models.Website, error)
|
||||
SaveConfig(config requests.SaveConfig) error
|
||||
Delete(id uint) error
|
||||
Delete(id requests.Delete) error
|
||||
GetConfig(id uint) (types.WebsiteSetting, error)
|
||||
GetConfigByName(name string) (types.WebsiteSetting, error)
|
||||
GetIDByName(name string) (uint, error)
|
||||
|
||||
@@ -3,6 +3,7 @@ package acme
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/libdns/tencentcloud"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
@@ -125,6 +126,11 @@ func (s dnsSolver) getDNSProvider() (DNSProvider, error) {
|
||||
dns = &dnspod.Provider{
|
||||
APIToken: s.param.ID + "," + s.param.Token,
|
||||
}
|
||||
case Tencent:
|
||||
dns = &tencentcloud.Provider{
|
||||
SecretId: s.param.AccessKey,
|
||||
SecretKey: s.param.SecretKey,
|
||||
}
|
||||
case AliYun:
|
||||
dns = &alidns.Provider{
|
||||
AccKeyID: s.param.AccessKey,
|
||||
@@ -145,6 +151,7 @@ type DnsType string
|
||||
|
||||
const (
|
||||
DnsPod DnsType = "dnspod"
|
||||
Tencent DnsType = "tencent"
|
||||
AliYun DnsType = "aliyun"
|
||||
CloudFlare DnsType = "cloudflare"
|
||||
)
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
// Package captcha 处理图片验证码逻辑
|
||||
package captcha
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/goravel/framework/facades"
|
||||
"github.com/mojocn/base64Captcha"
|
||||
)
|
||||
|
||||
type Captcha struct {
|
||||
Base64Captcha *base64Captcha.Captcha
|
||||
}
|
||||
|
||||
// once 确保 internalCaptcha 对象只初始化一次
|
||||
var once sync.Once
|
||||
|
||||
// internalCaptcha 内部使用的 Captcha 对象
|
||||
var internalCaptcha *Captcha
|
||||
|
||||
// NewCaptcha 单例模式获取
|
||||
func NewCaptcha() *Captcha {
|
||||
once.Do(func() {
|
||||
// 初始化 Captcha 对象
|
||||
internalCaptcha = &Captcha{}
|
||||
|
||||
// 使用 Cache facade 进行存储,并配置存储 Key 的前缀
|
||||
store := CacheStore{
|
||||
KeyPrefix: facades.Config().GetString("app.name") + ":captcha:",
|
||||
}
|
||||
|
||||
// 配置 base64Captcha 驱动信息
|
||||
driver := base64Captcha.NewDriverDigit(
|
||||
facades.Config().GetInt("captcha.height"), // 宽
|
||||
facades.Config().GetInt("captcha.width"), // 高
|
||||
facades.Config().GetInt("captcha.length"), // 长度
|
||||
facades.Config().Get("captcha.maxskew").(float64), // 数字的最大倾斜角度
|
||||
facades.Config().GetInt("captcha.dotcount"), // 图片背景里的混淆点数量
|
||||
)
|
||||
|
||||
// 实例化 base64Captcha 并赋值给内部使用的 internalCaptcha 对象
|
||||
internalCaptcha.Base64Captcha = base64Captcha.NewCaptcha(driver, &store)
|
||||
})
|
||||
|
||||
return internalCaptcha
|
||||
}
|
||||
|
||||
// GenerateCaptcha 生成图片验证码
|
||||
func (c *Captcha) GenerateCaptcha() (id string, b64s string, err error) {
|
||||
id, b64s, _, err = c.Base64Captcha.Generate()
|
||||
return id, b64s, err
|
||||
}
|
||||
|
||||
// VerifyCaptcha 验证验证码是否正确
|
||||
func (c *Captcha) VerifyCaptcha(id string, answer string, clear bool) (match bool) {
|
||||
|
||||
// 方便本地和 API 自动测试
|
||||
if facades.Config().GetBool("app.debug") && id == facades.Config().GetString("captcha.testing_key") {
|
||||
return true
|
||||
}
|
||||
// 这样方便用户多次提交,防止表单提交错误需要多次输入图片验证码
|
||||
return c.Base64Captcha.Verify(id, answer, clear)
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
package captcha
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/goravel/framework/testing/mock"
|
||||
testifymock "github.com/stretchr/testify/mock"
|
||||
"github.com/stretchr/testify/suite"
|
||||
)
|
||||
|
||||
type CaptchaTestSuite struct {
|
||||
suite.Suite
|
||||
captcha *Captcha
|
||||
}
|
||||
|
||||
func TestCaptchaTestSuite(t *testing.T) {
|
||||
facade := mock.Factory()
|
||||
mockConfig := facade.Config()
|
||||
mockConfig.On("GetString", "app.name").Return("HaoZiPanel").Once()
|
||||
mockConfig.On("GetInt", "captcha.height").Return(80).Once()
|
||||
mockConfig.On("GetInt", "captcha.width").Return(240).Once()
|
||||
mockConfig.On("GetInt", "captcha.length").Return(4).Once()
|
||||
mockConfig.On("Get", "captcha.maxskew").Return(0.7).Once()
|
||||
mockConfig.On("GetInt", "captcha.dotcount").Return(80).Once()
|
||||
mockConfig.On("GetInt", "captcha.expire_time").Return(5).Once()
|
||||
mockConfig.On("GetInt", "captcha.debug_expire_time").Return(10).Once()
|
||||
mockConfig.On("GetBool", "app.debug").Return(true).Once()
|
||||
mockCache := facade.Cache()
|
||||
mockCache.On("Put", testifymock.Anything, testifymock.Anything, time.Minute*time.Duration(10)).Return(nil).Once()
|
||||
|
||||
suite.Run(t, &CaptchaTestSuite{
|
||||
captcha: NewCaptcha(),
|
||||
})
|
||||
|
||||
mockConfig.AssertExpectations(t)
|
||||
}
|
||||
|
||||
func (s *CaptchaTestSuite) TestGenerateCaptcha() {
|
||||
id, base64, err := s.captcha.GenerateCaptcha()
|
||||
|
||||
s.NotEmpty(id)
|
||||
s.NotEmpty(base64)
|
||||
s.Nil(err)
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
package captcha
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/goravel/framework/facades"
|
||||
)
|
||||
|
||||
// CacheStore 实现 base64Captcha.Store interface
|
||||
type CacheStore struct {
|
||||
KeyPrefix string
|
||||
}
|
||||
|
||||
// Set 实现 base64Captcha.Store interface 的 Set 方法
|
||||
func (s *CacheStore) Set(key string, value string) error {
|
||||
|
||||
ExpireTime := time.Minute * time.Duration(facades.Config().GetInt("captcha.expire_time"))
|
||||
// 方便本地开发调试
|
||||
if facades.Config().GetBool("app.debug") {
|
||||
ExpireTime = time.Minute * time.Duration(facades.Config().GetInt("captcha.debug_expire_time"))
|
||||
}
|
||||
|
||||
err := facades.Cache().Put(s.KeyPrefix+key, value, ExpireTime)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get 实现 base64Captcha.Store interface 的 Get 方法
|
||||
func (s *CacheStore) Get(key string, clear bool) string {
|
||||
key = s.KeyPrefix + key
|
||||
val := facades.Cache().Get(key, "").(string)
|
||||
if clear {
|
||||
facades.Cache().Forget(key)
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// Verify 实现 base64Captcha.Store interface 的 Verify 方法
|
||||
func (s *CacheStore) Verify(key, answer string, clear bool) bool {
|
||||
v := s.Get(key, clear)
|
||||
return v == answer
|
||||
}
|
||||
+1
-1
@@ -79,7 +79,7 @@ func (m *MySQL) UserCreate(user, password string) error {
|
||||
}
|
||||
|
||||
func (m *MySQL) UserDrop(user string) error {
|
||||
_, err := m.Exec(fmt.Sprintf("DROP USER IF EXISTS '%s'@'localhost'", user))
|
||||
_, err := m.Exec(fmt.Sprintf("DROP USER IF EXISTS '%s'", user))
|
||||
m.flushPrivileges()
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -0,0 +1,206 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
|
||||
_ "github.com/lib/pq"
|
||||
|
||||
"github.com/TheTNB/panel/pkg/io"
|
||||
"github.com/TheTNB/panel/pkg/shell"
|
||||
"github.com/TheTNB/panel/pkg/systemctl"
|
||||
"github.com/TheTNB/panel/pkg/types"
|
||||
)
|
||||
|
||||
type Postgres struct {
|
||||
db *sql.DB
|
||||
username string
|
||||
password string
|
||||
address string
|
||||
port uint
|
||||
}
|
||||
|
||||
func NewPostgres(username, password, address string, port uint) (*Postgres, error) {
|
||||
dsn := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=postgres sslmode=disable", address, port, username, password)
|
||||
if password == "" {
|
||||
dsn = fmt.Sprintf("host=%s port=%d user=%s dbname=postgres sslmode=disable", address, port, username)
|
||||
}
|
||||
db, err := sql.Open("postgres", dsn)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("初始化Postgres连接失败: %w", err)
|
||||
}
|
||||
if db.Ping() != nil {
|
||||
return nil, fmt.Errorf("连接Postgres失败: %w", err)
|
||||
}
|
||||
return &Postgres{
|
||||
db: db,
|
||||
username: username,
|
||||
password: password,
|
||||
address: address,
|
||||
port: port,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m *Postgres) Close() error {
|
||||
return m.db.Close()
|
||||
}
|
||||
|
||||
func (m *Postgres) Ping() error {
|
||||
return m.db.Ping()
|
||||
}
|
||||
|
||||
func (m *Postgres) Query(query string, args ...any) (*sql.Rows, error) {
|
||||
return m.db.Query(query, args...)
|
||||
}
|
||||
|
||||
func (m *Postgres) QueryRow(query string, args ...any) *sql.Row {
|
||||
return m.db.QueryRow(query, args...)
|
||||
}
|
||||
|
||||
func (m *Postgres) Exec(query string, args ...any) (sql.Result, error) {
|
||||
return m.db.Exec(query, args...)
|
||||
}
|
||||
|
||||
func (m *Postgres) Prepare(query string) (*sql.Stmt, error) {
|
||||
return m.db.Prepare(query)
|
||||
}
|
||||
|
||||
func (m *Postgres) DatabaseCreate(name string) error {
|
||||
_, err := m.Exec(fmt.Sprintf("CREATE DATABASE %s", name))
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *Postgres) DatabaseDrop(name string) error {
|
||||
_, err := m.Exec(fmt.Sprintf("DROP DATABASE IF EXISTS %s", name))
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *Postgres) UserCreate(user, password string) error {
|
||||
_, err := m.Exec(fmt.Sprintf("CREATE USER %s WITH PASSWORD '%s'", user, password))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Postgres) UserDrop(user string) error {
|
||||
_, err := m.Exec(fmt.Sprintf("DROP USER IF EXISTS %s", user))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, _ = shell.Execf(`sed -i '/` + user + `/d' /www/server/postgresql/data/pg_hba.conf`)
|
||||
return systemctl.Reload("postgresql")
|
||||
}
|
||||
|
||||
func (m *Postgres) UserPassword(user, password string) error {
|
||||
_, err := m.Exec(fmt.Sprintf("ALTER USER %s WITH PASSWORD '%s'", user, password))
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *Postgres) PrivilegesGrant(user, database string) error {
|
||||
if _, err := m.Exec(fmt.Sprintf("ALTER DATABASE %s OWNER TO %s", database, user)); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := m.Exec(fmt.Sprintf("GRANT ALL PRIVILEGES ON DATABASE %s TO %s", database, user)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Postgres) PrivilegesRevoke(user, database string) error {
|
||||
_, err := m.Exec(fmt.Sprintf("REVOKE ALL PRIVILEGES ON DATABASE %s FROM %s", database, user))
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *Postgres) HostAdd(database, user, host string) error {
|
||||
config := fmt.Sprintf("host %s %s %s scram-sha-256", database, user, host)
|
||||
if err := io.WriteAppend("/www/server/postgresql/data/pg_hba.conf", config); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return systemctl.Reload("postgresql")
|
||||
}
|
||||
|
||||
func (m *Postgres) HostRemove(database, user, host string) error {
|
||||
regex := fmt.Sprintf(`host\s+%s\s+%s\s+%s`, database, user, host)
|
||||
if _, err := shell.Execf(`sed -i '/` + regex + `/d' /www/server/postgresql/data/pg_hba.conf`); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return systemctl.Reload("postgresql")
|
||||
}
|
||||
|
||||
func (m *Postgres) Users() ([]types.PostgresUser, error) {
|
||||
query := `
|
||||
SELECT rolname,
|
||||
rolsuper,
|
||||
rolcreaterole,
|
||||
rolcreatedb,
|
||||
rolreplication,
|
||||
rolbypassrls
|
||||
FROM pg_roles
|
||||
WHERE rolcanlogin = true;
|
||||
`
|
||||
rows, err := m.Query(query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var users []types.PostgresUser
|
||||
for rows.Next() {
|
||||
var user types.PostgresUser
|
||||
var super, canCreateRole, canCreateDb, replication, bypassRls bool
|
||||
if err = rows.Scan(&user.Role, &super, &canCreateRole, &canCreateDb, &replication, &bypassRls); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
permissions := map[string]bool{
|
||||
"超级用户": super,
|
||||
"创建角色": canCreateRole,
|
||||
"创建数据库": canCreateDb,
|
||||
"可以复制": replication,
|
||||
"绕过行级安全": bypassRls,
|
||||
}
|
||||
for perm, enabled := range permissions {
|
||||
if enabled {
|
||||
user.Attributes = append(user.Attributes, perm)
|
||||
}
|
||||
}
|
||||
|
||||
if len(user.Attributes) == 0 {
|
||||
user.Attributes = append(user.Attributes, "无")
|
||||
}
|
||||
|
||||
users = append(users, user)
|
||||
}
|
||||
|
||||
return users, nil
|
||||
}
|
||||
|
||||
func (m *Postgres) Databases() ([]types.PostgresDatabase, error) {
|
||||
query := `
|
||||
SELECT d.datname, pg_catalog.pg_get_userbyid(d.datdba), pg_catalog.pg_encoding_to_char(d.encoding)
|
||||
FROM pg_catalog.pg_database d
|
||||
WHERE datistemplate = false;
|
||||
`
|
||||
rows, err := m.Query(query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var databases []types.PostgresDatabase
|
||||
for rows.Next() {
|
||||
var db types.PostgresDatabase
|
||||
if err := rows.Scan(&db.Name, &db.Owner, &db.Encoding); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
databases = append(databases, db)
|
||||
}
|
||||
|
||||
return databases, nil
|
||||
}
|
||||
+3
-3
@@ -17,7 +17,7 @@ import (
|
||||
// Execf 执行 shell 命令
|
||||
func Execf(shell string, args ...any) (string, error) {
|
||||
if !CheckArgs(slice.ToString(args)...) {
|
||||
return "", errors.New("你想干什么?")
|
||||
return "", errors.New("发现危险的命令参数,中止执行")
|
||||
}
|
||||
|
||||
var cmd *exec.Cmd
|
||||
@@ -39,7 +39,7 @@ func Execf(shell string, args ...any) (string, error) {
|
||||
// ExecfAsync 异步执行 shell 命令
|
||||
func ExecfAsync(shell string, args ...any) error {
|
||||
if !CheckArgs(slice.ToString(args)...) {
|
||||
return errors.New("你想干什么?")
|
||||
return errors.New("发现危险的命令参数,中止执行")
|
||||
}
|
||||
|
||||
var cmd *exec.Cmd
|
||||
@@ -67,7 +67,7 @@ func ExecfAsync(shell string, args ...any) error {
|
||||
// ExecfWithTimeout 执行 shell 命令并设置超时时间
|
||||
func ExecfWithTimeout(timeout time.Duration, shell string, args ...any) (string, error) {
|
||||
if !CheckArgs(slice.ToString(args)...) {
|
||||
return "", errors.New("你想干什么?")
|
||||
return "", errors.New("发现危险的命令参数,中止执行")
|
||||
}
|
||||
|
||||
var cmd *exec.Cmd
|
||||
|
||||
+8
-1
@@ -482,14 +482,21 @@ func UpdatePanel(panelInfo PanelInfo) error {
|
||||
_, _ = shell.Execf("chmod -R 700 /usr/bin/panel")
|
||||
color.Green().Printfln("设置完成")
|
||||
|
||||
color.Green().Printfln("运行升级后脚本...")
|
||||
if _, err = shell.Execf("bash /www/panel/scripts/update_panel.sh"); err != nil {
|
||||
color.Red().Printfln("执行面板升级后脚本失败")
|
||||
color.Red().Printfln("运行面板升级后脚本失败")
|
||||
return err
|
||||
}
|
||||
if _, err = shell.Execf("cp -f /www/panel/scripts/panel.service /etc/systemd/system/panel.service"); err != nil {
|
||||
color.Red().Printfln("写入面板服务文件失败")
|
||||
return err
|
||||
}
|
||||
_, _ = shell.Execf("systemctl daemon-reload")
|
||||
if _, err = shell.Execf("panel writeSetting version " + panelInfo.Version); err != nil {
|
||||
color.Red().Printfln("写入面板版本号失败")
|
||||
return err
|
||||
}
|
||||
color.Green().Printfln("升级完成")
|
||||
|
||||
_, _ = shell.Execf("rm -rf /tmp/panel-storage.zip")
|
||||
_, _ = shell.Execf("rm -rf /tmp/panel.conf.bak")
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package types
|
||||
|
||||
type PostgresUser struct {
|
||||
Role string `json:"role"`
|
||||
Attributes []string `json:"attributes"`
|
||||
}
|
||||
|
||||
type PostgresDatabase struct {
|
||||
Name string `json:"name"`
|
||||
Owner string `json:"owner"`
|
||||
Encoding string `json:"encoding"`
|
||||
}
|
||||
+4
-1
@@ -13,7 +13,10 @@
|
||||
"packageRules": [
|
||||
{
|
||||
"description": "Automerge non-major updates",
|
||||
"matchUpdateTypes": ["minor", "patch"],
|
||||
"matchUpdateTypes": [
|
||||
"minor",
|
||||
"patch"
|
||||
],
|
||||
"matchCurrentVersion": "!/^0/",
|
||||
"automerge": true
|
||||
}
|
||||
|
||||
+1
-1
@@ -48,7 +48,7 @@ func Api() {
|
||||
websiteController := controllers.NewWebsiteController()
|
||||
r.Get("/", websiteController.List)
|
||||
r.Post("/", websiteController.Add)
|
||||
r.Delete("{id}", websiteController.Delete)
|
||||
r.Post("delete", websiteController.Delete)
|
||||
r.Get("{id}/config", websiteController.GetConfig)
|
||||
r.Post("{id}/config", websiteController.SaveConfig)
|
||||
r.Delete("{id}/log", websiteController.ClearLog)
|
||||
|
||||
+11
-28
@@ -88,31 +88,31 @@ Prepare_System() {
|
||||
[ -s /etc/selinux/config ] && sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
|
||||
setenforce 0 > /dev/null 2>&1
|
||||
|
||||
ulimit -n 204800
|
||||
echo 6553560 > /proc/sys/fs/file-max
|
||||
ulimit -n 1048576
|
||||
echo 2147483584 > /proc/sys/fs/file-max
|
||||
checkSoftNofile=$(cat /etc/security/limits.conf | grep '^* soft nofile .*$')
|
||||
checkHardNofile=$(cat /etc/security/limits.conf | grep '^* hard nofile .*$')
|
||||
checkSoftNproc=$(cat /etc/security/limits.conf | grep '^* soft nproc .*$')
|
||||
checkHardNproc=$(cat /etc/security/limits.conf | grep '^* hard nproc .*$')
|
||||
checkFsFileMax=$(cat /etc/sysctl.conf | grep '^fs.file-max.*$')
|
||||
if [ "${checkSoftNofile}" == "" ]; then
|
||||
echo "* soft nofile 204800" >> /etc/security/limits.conf
|
||||
echo "* soft nofile 1048576" >> /etc/security/limits.conf
|
||||
fi
|
||||
if [ "${checkHardNofile}" == "" ]; then
|
||||
echo "* hard nofile 204800" >> /etc/security/limits.conf
|
||||
echo "* hard nofile 1048576" >> /etc/security/limits.conf
|
||||
fi
|
||||
if [ "${checkSoftNproc}" == "" ]; then
|
||||
echo "* soft nproc 204800" >> /etc/security/limits.conf
|
||||
echo "* soft nproc 1048576" >> /etc/security/limits.conf
|
||||
fi
|
||||
if [ "${checkHardNproc}" == "" ]; then
|
||||
echo "* hard nproc 204800 " >> /etc/security/limits.conf
|
||||
echo "* hard nproc 1048576" >> /etc/security/limits.conf
|
||||
fi
|
||||
if [ "${checkFsFileMax}" == "" ]; then
|
||||
echo fs.file-max = 6553560 >> /etc/sysctl.conf
|
||||
echo fs.file-max = 2147483584 >> /etc/sysctl.conf
|
||||
fi
|
||||
|
||||
# 自动开启 BBR
|
||||
isBBRSupported=$(ls -l /lib/modules/*/kernel/net/ipv4/tcp_bbr.ko.xz | grep -c bbr)
|
||||
isBBRSupported=$(ls -l /lib/modules/*/kernel/net/ipv4 | grep -c tcp_bbr)
|
||||
if [ "${isBBRSupported}" != "0" ]; then
|
||||
qdisc=$(sysctl net.core.default_qdisc | awk '{print $3}')
|
||||
echo "net.core.default_qdisc=${qdisc}" >> /etc/sysctl.conf
|
||||
@@ -151,14 +151,14 @@ Prepare_System() {
|
||||
# Rocky Linux
|
||||
/usr/bin/crb enable
|
||||
dnf makecache -y
|
||||
dnf install -y curl wget zip unzip tar p7zip p7zip-plugins git jq git-core dos2unix rsyslog
|
||||
dnf install -y bash curl wget zip unzip tar p7zip p7zip-plugins git jq git-core dos2unix rsyslog make
|
||||
elif [ "${OS}" == "debian" ]; then
|
||||
if ${inChina}; then
|
||||
sed -i 's/deb.debian.org/mirrors.tencent.com/g' /etc/apt/sources.list
|
||||
sed -i 's/security.debian.org/mirrors.tencent.com/g' /etc/apt/sources.list
|
||||
fi
|
||||
apt-get update -y
|
||||
apt-get install -y curl wget zip unzip tar p7zip p7zip-full git jq git dos2unix rsyslog
|
||||
apt-get install -y bash curl wget zip unzip tar p7zip p7zip-full git jq git dos2unix rsyslog make
|
||||
fi
|
||||
if [ "$?" != "0" ]; then
|
||||
echo -e $HR
|
||||
@@ -309,24 +309,7 @@ Init_Panel() {
|
||||
exit 1
|
||||
fi
|
||||
# 写入服务文件
|
||||
cat > /etc/systemd/system/panel.service << EOF
|
||||
[Unit]
|
||||
Description=HaoZi Panel
|
||||
After=syslog.target network.target
|
||||
Wants=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
WorkingDirectory=${setup_Path}/panel/
|
||||
ExecStart=/www/panel/panel --env="/www/panel/panel.conf"
|
||||
ExecReload=kill -s HUP \$MAINPID
|
||||
ExecStop=kill -s QUIT \$MAINPID
|
||||
User=root
|
||||
Restart=always
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
EOF
|
||||
cp -f ${setup_Path}/panel/scripts/panel.service /etc/systemd/system/panel.service
|
||||
systemctl daemon-reload
|
||||
systemctl enable panel.service
|
||||
systemctl start panel.service
|
||||
|
||||
@@ -59,6 +59,11 @@ else
|
||||
echo "错误:耗子面板不支持该系统"
|
||||
exit 1
|
||||
fi
|
||||
if [ "$?" != "0" ]; then
|
||||
echo -e $HR
|
||||
echo "错误:安装依赖软件失败,请截图错误信息寻求帮助。"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
mysqlUserCheck=$(cat /etc/passwd | grep mysql)
|
||||
if [ "${mysqlUserCheck}" == "" ]; then
|
||||
|
||||
@@ -42,6 +42,11 @@ else
|
||||
echo "错误:耗子面板不支持该系统"
|
||||
exit 1
|
||||
fi
|
||||
if [ "$?" != "0" ]; then
|
||||
echo -e $HR
|
||||
echo "错误:安装依赖软件失败,请截图错误信息寻求帮助。"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 准备目录
|
||||
rm -rf ${openrestyPath}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
[Unit]
|
||||
Description=HaoZi Panel
|
||||
After=syslog.target network.target
|
||||
Wants=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
WorkingDirectory=/www/panel/
|
||||
ExecStart=/www/panel/panel --env="/www/panel/panel.conf"
|
||||
ExecReload=kill -s HUP $MAINPID
|
||||
ExecStop=kill -s QUIT $MAINPID
|
||||
User=root
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
LimitNOFILE=1048576
|
||||
LimitNPROC=1048576
|
||||
Delegate=yes
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -53,6 +53,11 @@ else
|
||||
echo "错误:耗子面板不支持该系统"
|
||||
exit 1
|
||||
fi
|
||||
if [ "$?" != "0" ]; then
|
||||
echo -e $HR
|
||||
echo "错误:安装依赖软件失败,请截图错误信息寻求帮助。"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 准备安装目录
|
||||
rm -rf ${phpPath}
|
||||
|
||||
@@ -53,6 +53,11 @@ else
|
||||
echo "错误:耗子面板不支持该系统"
|
||||
exit 1
|
||||
fi
|
||||
if [ "$?" != "0" ]; then
|
||||
echo -e $HR
|
||||
echo "错误:安装依赖软件失败,请截图错误信息寻求帮助。"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
postgresqlUserCheck=$(cat /etc/passwd | grep postgres)
|
||||
if [ "${postgresqlUserCheck}" == "" ]; then
|
||||
|
||||
@@ -45,6 +45,11 @@ else
|
||||
echo "错误:耗子面板不支持该系统"
|
||||
exit 1
|
||||
fi
|
||||
if [ "$?" != "0" ]; then
|
||||
echo -e $HR
|
||||
echo "错误:安装依赖软件失败,请截图错误信息寻求帮助。"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 准备目录
|
||||
rm -rf ${redisPath}
|
||||
|
||||
@@ -30,6 +30,11 @@ else
|
||||
echo "错误:不支持的操作系统"
|
||||
exit 1
|
||||
fi
|
||||
if [ "$?" != "0" ]; then
|
||||
echo -e $HR
|
||||
echo "错误:安装软件失败,请截图错误信息寻求帮助。"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 写入配置
|
||||
cat > /etc/rsyncd.conf << EOF
|
||||
|
||||
@@ -30,5 +30,10 @@ else
|
||||
echo "错误:不支持的操作系统"
|
||||
exit 1
|
||||
fi
|
||||
if [ "$?" != "0" ]; then
|
||||
echo -e $HR
|
||||
echo "错误:安装软件失败,请截图错误信息寻求帮助。"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
panel writePlugin s3fs 1.9
|
||||
|
||||
@@ -35,5 +35,10 @@ else
|
||||
echo "错误:不支持的操作系统"
|
||||
exit 1
|
||||
fi
|
||||
if [ "$?" != "0" ]; then
|
||||
echo -e $HR
|
||||
echo "错误:安装软件失败,请截图错误信息寻求帮助。"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
panel writePlugin supervisor 4.2.5
|
||||
|
||||
Reference in New Issue
Block a user