2
0
mirror of https://github.com/acepanel/panel.git synced 2026-02-04 12:40:25 +08:00

feat: 规范部分控制器方法

This commit is contained in:
耗子
2023-11-08 02:01:28 +08:00
parent e032faeae0
commit d90423db4a
17 changed files with 939 additions and 221 deletions

View File

@@ -27,7 +27,7 @@ func NewCertController() *CertController {
// CAProviders
// @Summary 获取 CA 提供商
// @Description 获取面板证书管理支持的 CA 提供商
// @Tags 证书
// @Tags 证书管理
// @Produce json
// @Security BearerToken
// @Success 200 {object} SuccessResponse
@@ -61,7 +61,7 @@ func (r *CertController) CAProviders(ctx http.Context) http.Response {
// DNSProviders
// @Summary 获取 DNS 提供商
// @Description 获取面板证书管理支持的 DNS 提供商
// @Tags 证书
// @Tags 证书管理
// @Produce json
// @Security BearerToken
// @Success 200 {object} SuccessResponse
@@ -87,7 +87,7 @@ func (r *CertController) DNSProviders(ctx http.Context) http.Response {
// Algorithms
// @Summary 获取算法列表
// @Description 获取面板证书管理支持的算法列表
// @Tags 证书
// @Tags 证书管理
// @Produce json
// @Security BearerToken
// @Success 200 {object} SuccessResponse
@@ -117,7 +117,7 @@ func (r *CertController) Algorithms(ctx http.Context) http.Response {
// UserList
// @Summary 获取用户列表
// @Description 获取面板证书管理的 ACME 用户列表
// @Tags 证书
// @Tags 证书管理
// @Produce json
// @Security BearerToken
// @Success 200 {object} SuccessResponse{data=responses.CertList}
@@ -150,7 +150,7 @@ func (r *CertController) UserList(ctx http.Context) http.Response {
// UserStore
// @Summary 添加 ACME 用户
// @Description 添加 ACME 用户到面板证书管理
// @Tags 证书
// @Tags 证书管理
// @Accept json
// @Produce json
// @Security BearerToken
@@ -180,7 +180,7 @@ func (r *CertController) UserStore(ctx http.Context) http.Response {
// UserUpdate
// @Summary 更新 ACME 用户
// @Description 更新面板证书管理的 ACME 用户
// @Tags 证书
// @Tags 证书管理
// @Accept json
// @Produce json
// @Security BearerToken
@@ -212,7 +212,7 @@ func (r *CertController) UserUpdate(ctx http.Context) http.Response {
// UserShow
// @Summary 获取 ACME 用户
// @Description 获取面板证书管理的 ACME 用户
// @Tags 证书
// @Tags 证书管理
// @Produce json
// @Security BearerToken
// @Param id path int true "用户 ID"
@@ -242,7 +242,7 @@ func (r *CertController) UserShow(ctx http.Context) http.Response {
// UserDestroy
// @Summary 删除 ACME 用户
// @Description 删除面板证书管理的 ACME 用户
// @Tags 证书
// @Tags 证书管理
// @Accept json
// @Produce json
// @Security BearerToken
@@ -273,7 +273,7 @@ func (r *CertController) UserDestroy(ctx http.Context) http.Response {
// DNSList
// @Summary 获取 DNS 接口列表
// @Description 获取面板证书管理的 DNS 接口列表
// @Tags 证书
// @Tags 证书管理
// @Produce json
// @Security BearerToken
// @Success 200 {object} SuccessResponse{data=responses.DNSList}
@@ -306,7 +306,7 @@ func (r *CertController) DNSList(ctx http.Context) http.Response {
// DNSStore
// @Summary 添加 DNS 接口
// @Description 添加 DNS 接口到面板证书管理
// @Tags 证书
// @Tags 证书管理
// @Accept json
// @Produce json
// @Security BearerToken
@@ -336,7 +336,7 @@ func (r *CertController) DNSStore(ctx http.Context) http.Response {
// DNSShow
// @Summary 获取 DNS 接口
// @Description 获取面板证书管理的 DNS 接口
// @Tags 证书
// @Tags 证书管理
// @Produce json
// @Security BearerToken
// @Param id path int true "DNS 接口 ID"
@@ -366,7 +366,7 @@ func (r *CertController) DNSShow(ctx http.Context) http.Response {
// DNSUpdate
// @Summary 更新 DNS 接口
// @Description 更新面板证书管理的 DNS 接口
// @Tags 证书
// @Tags 证书管理
// @Accept json
// @Produce json
// @Security BearerToken
@@ -398,7 +398,7 @@ func (r *CertController) DNSUpdate(ctx http.Context) http.Response {
// DNSDestroy
// @Summary 删除 DNS 接口
// @Description 删除面板证书管理的 DNS 接口
// @Tags 证书
// @Tags 证书管理
// @Accept json
// @Produce json
// @Security BearerToken
@@ -429,7 +429,7 @@ func (r *CertController) DNSDestroy(ctx http.Context) http.Response {
// CertList
// @Summary 获取证书列表
// @Description 获取面板证书管理的证书列表
// @Tags 证书
// @Tags 证书管理
// @Produce json
// @Security BearerToken
// @Success 200 {object} SuccessResponse{data=responses.CertList}
@@ -462,7 +462,7 @@ func (r *CertController) CertList(ctx http.Context) http.Response {
// CertStore
// @Summary 添加证书
// @Description 添加证书到面板证书管理
// @Tags 证书
// @Tags 证书管理
// @Accept json
// @Produce json
// @Security BearerToken
@@ -492,7 +492,7 @@ func (r *CertController) CertStore(ctx http.Context) http.Response {
// CertUpdate
// @Summary 更新证书
// @Description 更新面板证书管理的证书
// @Tags 证书
// @Tags 证书管理
// @Accept json
// @Produce json
// @Security BearerToken
@@ -524,7 +524,7 @@ func (r *CertController) CertUpdate(ctx http.Context) http.Response {
// CertShow
// @Summary 获取证书
// @Description 获取面板证书管理的证书
// @Tags 证书
// @Tags 证书管理
// @Produce json
// @Security BearerToken
// @Param id path int true "证书 ID"
@@ -554,7 +554,7 @@ func (r *CertController) CertShow(ctx http.Context) http.Response {
// CertDestroy
// @Summary 删除证书
// @Description 删除面板证书管理的证书
// @Tags 证书
// @Tags 证书管理
// @Accept json
// @Produce json
// @Security BearerToken
@@ -585,7 +585,7 @@ func (r *CertController) CertDestroy(ctx http.Context) http.Response {
// Obtain
// @Summary 签发证书
// @Description 签发面板证书管理的证书
// @Tags 证书
// @Tags 证书管理
// @Accept json
// @Produce json
// @Security BearerToken
@@ -628,7 +628,7 @@ func (r *CertController) Obtain(ctx http.Context) http.Response {
// Renew
// @Summary 续签证书
// @Description 续签面板证书管理的证书
// @Tags 证书
// @Tags 证书管理
// @Accept json
// @Produce json
// @Security BearerToken
@@ -658,7 +658,7 @@ func (r *CertController) Renew(ctx http.Context) http.Response {
// ManualDNS
// @Summary 获取手动 DNS 记录
// @Description 获取签发证书所需的 DNS 记录
// @Tags 证书
// @Tags 证书管理
// @Accept json
// @Produce json
// @Security BearerToken

View File

@@ -119,7 +119,7 @@ func (c *InfoController) CountInfo(ctx http.Context) http.Response {
db, err := sql.Open("mysql", "root:"+rootPassword+"@unix(/tmp/mysql.sock)/")
if err != nil {
facades.Log().With(map[string]any{
facades.Log().Request(ctx.Request()).With(map[string]any{
"error": err.Error(),
}).Error("[面板][InfoController] 获取数据库列表失败")
databaseCount = -1
@@ -127,7 +127,7 @@ func (c *InfoController) CountInfo(ctx http.Context) http.Response {
defer db.Close()
rows, err := db.Query("SHOW DATABASES")
if err != nil {
facades.Log().With(map[string]any{
facades.Log().Request(ctx.Request()).With(map[string]any{
"error": err.Error(),
}).Error("[面板][InfoController] 获取数据库列表失败")
databaseCount = -1
@@ -305,7 +305,7 @@ func (c *InfoController) Update(ctx http.Context) http.Response {
panel, err := tools.GetLatestPanelVersion()
if err != nil {
facades.Log().With(map[string]any{
facades.Log().Request(ctx.Request()).With(map[string]any{
"error": err.Error(),
}).Error("[面板][InfoController] 获取最新版本失败")
return Error(ctx, http.StatusInternalServerError, "获取最新版本失败")
@@ -313,7 +313,7 @@ func (c *InfoController) Update(ctx http.Context) http.Response {
err = tools.UpdatePanel(panel)
if err != nil {
facades.Log().With(map[string]any{
facades.Log().Request(ctx.Request()).With(map[string]any{
"error": err.Error(),
}).Error("[面板][InfoController] 更新面板失败")
return Error(ctx, http.StatusInternalServerError, "更新失败: "+err.Error())

View File

@@ -1,11 +1,12 @@
package controllers
import (
"regexp"
"github.com/goravel/framework/contracts/http"
"github.com/goravel/framework/facades"
"github.com/spf13/cast"
requests "panel/app/http/requests/setting"
responses "panel/app/http/responses/setting"
"panel/app/models"
"panel/app/services"
"panel/pkg/tools"
@@ -21,7 +22,16 @@ func NewSettingController() *SettingController {
}
}
// List 获取设置列表
// List
// @Summary 设置列表
// @Description 获取面板设置列表
// @Tags 面板设置
// @Produce json
// @Security BearerToken
// @Success 200 {object} SuccessResponse{data=responses.Settings}
// @Failure 401 {object} ErrorResponse "登录已过期"
// @Failure 500 {object} ErrorResponse "系统内部错误"
// @Router /panel/setting/list [get]
func (r *SettingController) List(ctx http.Context) http.Response {
var settings []models.Setting
err := facades.Orm().Query().Get(&settings)
@@ -30,18 +40,7 @@ func (r *SettingController) List(ctx http.Context) http.Response {
return ErrorSystem(ctx)
}
type data struct {
Name string `json:"name"`
Username string `json:"username"`
Password string `json:"password"`
Email string `json:"email"`
Port string `json:"port"`
Entrance string `json:"entrance"`
WebsitePath string `json:"website_path"`
BackupPath string `json:"backup_path"`
}
var result data
var result responses.Settings
result.Name = r.setting.Get(models.SettingKeyName)
result.Entrance = facades.Config().GetString("http.entrance")
result.WebsitePath = r.setting.Get(models.SettingKeyWebsitePath)
@@ -61,79 +60,90 @@ func (r *SettingController) List(ctx http.Context) http.Response {
return Success(ctx, result)
}
// Save 保存设置
func (r *SettingController) Save(ctx http.Context) http.Response {
name := ctx.Request().Input("name")
port := ctx.Request().Input("port")
backupPath := ctx.Request().Input("backup_path")
websitePath := ctx.Request().Input("website_path")
entrance := ctx.Request().Input("entrance")
username := ctx.Request().Input("username")
email := ctx.Request().Input("email")
password := ctx.Request().Input("password")
if !regexp.MustCompile(`^/[^/]*[^/]$`).MatchString(entrance) || entrance == "/api" {
return Error(ctx, http.StatusUnprocessableEntity, "入口格式错误")
// Update
// @Summary 更新设置
// @Description 更新面板设置
// @Tags 面板设置
// @Accept json
// @Produce json
// @Security BearerToken
// @Param data body requests.Update true "更新设置"
// @Success 200 {object} SuccessResponse
// @Failure 401 {object} ErrorResponse "登录已过期"
// @Failure 500 {object} ErrorResponse "系统内部错误"
// @Router /panel/setting/update [post]
func (r *SettingController) Update(ctx http.Context) http.Response {
var updateRequest requests.Update
sanitize := Sanitize(ctx, &updateRequest)
if sanitize != nil {
return sanitize
}
err := r.setting.Set(models.SettingKeyName, name)
err := r.setting.Set(models.SettingKeyName, updateRequest.Name)
if err != nil {
facades.Log().Error("[面板][SettingController] 保存设置失败 ", err)
facades.Log().Request(ctx.Request()).With(map[string]any{
"error": err.Error(),
}).Tags("面板", "面板设置").Error("保存面板名称失败")
return ErrorSystem(ctx)
}
oldPort := tools.Exec(`cat /www/panel/panel.conf | grep APP_PORT | awk -F '=' '{print $2}' | tr -d '\n'`)
if oldPort != port {
tools.Exec("sed -i 's/APP_PORT=" + oldPort + "/APP_PORT=" + port + "/g' /www/panel/panel.conf")
}
oldEntrance := tools.Exec(`cat /www/panel/panel.conf | grep APP_ENTRANCE | awk -F '=' '{print $2}' | tr -d '\n'`)
if oldEntrance != entrance {
tools.Exec("sed -i 's/APP_ENTRANCE=" + oldEntrance + "/APP_ENTRANCE=" + entrance + "/g' /www/panel/panel.conf")
}
if !tools.Exists(backupPath) {
tools.Mkdir(backupPath, 0644)
if !tools.Exists(updateRequest.BackupPath) {
tools.Mkdir(updateRequest.BackupPath, 0644)
}
err = r.setting.Set(models.SettingKeyBackupPath, backupPath)
err = r.setting.Set(models.SettingKeyBackupPath, updateRequest.BackupPath)
if err != nil {
facades.Log().Error("[面板][SettingController] 保存设置失败 ", err)
facades.Log().Request(ctx.Request()).With(map[string]any{
"error": err.Error(),
}).Tags("面板", "面板设置").Error("保存备份目录失败")
return ErrorSystem(ctx)
}
if !tools.Exists(websitePath) {
tools.Mkdir(websitePath, 0755)
tools.Chown(websitePath, "www", "www")
if !tools.Exists(updateRequest.WebsitePath) {
tools.Mkdir(updateRequest.WebsitePath, 0755)
tools.Chown(updateRequest.WebsitePath, "www", "www")
}
err = r.setting.Set(models.SettingKeyWebsitePath, websitePath)
err = r.setting.Set(models.SettingKeyWebsitePath, updateRequest.WebsitePath)
if err != nil {
facades.Log().Error("[面板][SettingController] 保存设置失败 ", err)
facades.Log().Request(ctx.Request()).With(map[string]any{
"error": err.Error(),
}).Tags("面板", "面板设置").Error("保存建站目录失败")
return ErrorSystem(ctx)
}
var user models.User
err = facades.Auth().User(ctx, &user)
if err != nil {
facades.Log().Error("[面板][SettingController] 获取用户失败 ", err)
return ErrorSystem(ctx)
}
if len(username) > 0 {
user.Username = username
}
if len(email) > 0 {
user.Email = email
}
if len(password) > 0 {
hash, err := facades.Hash().Make(password)
user.Username = updateRequest.UserName
user.Email = updateRequest.Email
if len(updateRequest.Password) > 0 {
hash, err := facades.Hash().Make(updateRequest.Password)
if err != nil {
facades.Log().Error("[面板][SettingController] 保存设置失败 ", err)
return ErrorSystem(ctx)
}
user.Password = hash
}
if err = facades.Orm().Query().Save(&user); err != nil {
facades.Log().Error("[面板][SettingController] 保存设置失败 ", err)
facades.Log().Request(ctx.Request()).With(map[string]any{
"error": err.Error(),
}).Tags("面板", "面板设置").Error("保存用户信息失败")
return ErrorSystem(ctx)
}
oldPort := tools.Exec(`cat /www/panel/panel.conf | grep APP_PORT | awk -F '=' '{print $2}' | tr -d '\n'`)
port := cast.ToString(updateRequest.Port)
if oldPort != port {
tools.Exec("sed -i 's/APP_PORT=" + oldPort + "/APP_PORT=" + port + "/g' /www/panel/panel.conf")
}
oldEntrance := tools.Exec(`cat /www/panel/panel.conf | grep APP_ENTRANCE | awk -F '=' '{print $2}' | tr -d '\n'`)
entrance := cast.ToString(updateRequest.Entrance)
if oldEntrance != entrance {
tools.Exec("sed -i 's/APP_ENTRANCE=" + oldEntrance + "/APP_ENTRANCE=" + entrance + "/g' /www/panel/panel.conf")
}
if oldPort != port || oldEntrance != entrance {
tools.RestartPanel()
}
return Success(ctx, nil)
}

View File

@@ -38,7 +38,7 @@ func (r *TaskController) List(ctx http.Context) http.Response {
var total int64
err := facades.Orm().Query().Order("id desc").Paginate(ctx.Request().QueryInt("page", 1), ctx.Request().QueryInt("limit", 10), &tasks, &total)
if err != nil {
facades.Log().With(map[string]any{
facades.Log().Request(ctx.Request()).With(map[string]any{
"error": err.Error(),
}).Error("[面板][TaskController] 查询任务列表失败")
return ErrorSystem(ctx)
@@ -55,7 +55,7 @@ func (r *TaskController) Log(ctx http.Context) http.Response {
var task models.Task
err := facades.Orm().Query().Where("id", ctx.Request().QueryInt("id")).FirstOrFail(&task)
if err != nil {
facades.Log().With(map[string]any{
facades.Log().Request(ctx.Request()).With(map[string]any{
"id": ctx.Request().QueryInt("id"),
"error": err.Error(),
}).Error("[面板][TaskController] 查询任务失败")

View File

@@ -5,6 +5,7 @@ import (
"github.com/goravel/framework/facades"
"panel/app/http/requests/user"
responses "panel/app/http/responses/user"
"panel/app/models"
)
@@ -19,9 +20,9 @@ func NewUserController() *UserController {
}
// Login
// @Summary 用户登录
// @Summary 登录
// @Description 通过用户名和密码获取访问令牌
// @Tags 用户
// @Tags 用户鉴权
// @Accept json
// @Produce json
// @Param data body requests.Login true "登录信息"
@@ -72,21 +73,30 @@ func (r *UserController) Login(ctx http.Context) http.Response {
})
}
// Info 用户信息
// Info
// @Summary 用户信息
// @Description 获取当前登录用户信息
// @Tags 用户鉴权
// @Produce json
// @Security BearerToken
// @Success 200 {object} SuccessResponse{data=responses.Info}
// @Failure 401 {object} ErrorResponse "登录已过期"
// @Failure 500 {object} ErrorResponse "系统内部错误"
// @Router /panel/user/info [get]
func (r *UserController) Info(ctx http.Context) http.Response {
var user models.User
err := facades.Auth().User(ctx, &user)
if err != nil {
facades.Log().With(map[string]any{
facades.Log().Request(ctx.Request()).With(map[string]any{
"error": err.Error(),
}).Error("[面板][UserController] 查询用户信息失败")
}).Tags("面板", "用户").Error("获取用户信息失败")
return ErrorSystem(ctx)
}
return Success(ctx, http.Json{
"id": user.ID,
"role": []string{"admin"},
"username": user.Username,
"email": user.Email,
return Success(ctx, responses.Info{
ID: user.ID,
Role: []string{"admin"},
Username: user.Username,
Email: user.Email,
})
}

View File

@@ -0,0 +1,49 @@
package requests
import (
"github.com/goravel/framework/contracts/http"
"github.com/goravel/framework/contracts/validation"
)
type Update struct {
Name string `form:"name" json:"name"`
Port uint `form:"port" json:"port" filter:"int"`
BackupPath string `form:"backup_path" json:"backup_path"`
WebsitePath string `form:"website_path" json:"website_path"`
Entrance string `form:"entrance" json:"entrance"`
UserName string `form:"username" json:"username"`
Email string `form:"email" json:"email"`
Password string `form:"password" json:"password"`
}
func (r *Update) Authorize(ctx http.Context) error {
return nil
}
func (r *Update) Rules(ctx http.Context) map[string]string {
return map[string]string{
"name": "required|string:2,20",
"port": "required|int:1000,65535",
"backup_path": "required|string:2,255",
"website_path": "required|string:2,255",
"entrance": `required|regex:^/(\w+)?$|not_in:/api`,
"username": "required|string:2,20",
"email": "required|email",
"password": "string:8,255",
}
}
func (r *Update) Messages(ctx http.Context) map[string]string {
return map[string]string{
"port.int": "port 值必须是一个整数且在 1000 - 65535 之间",
"password.string": "password 必须是一个字符串且长度在 8 - 255 之间",
}
}
func (r *Update) Attributes(ctx http.Context) map[string]string {
return map[string]string{}
}
func (r *Update) PrepareForValidation(ctx http.Context, data validation.Data) error {
return nil
}

View File

@@ -0,0 +1,12 @@
package responses
type Settings struct {
Name string `json:"name"`
Username string `json:"username"`
Password string `json:"password"`
Email string `json:"email"`
Port string `json:"port"`
Entrance string `json:"entrance"`
WebsitePath string `json:"website_path"`
BackupPath string `json:"backup_path"`
}

View File

@@ -0,0 +1,8 @@
package responses
type Info struct {
ID uint `json:"id"`
Role []string `json:"role"`
Username string `json:"username"`
Email string `json:"email"`
}

View File

@@ -30,7 +30,7 @@ const docTemplate = `{
"application/json"
],
"tags": [
"证书"
"证书管理"
],
"summary": "获取算法列表",
"responses": {
@@ -61,7 +61,7 @@ const docTemplate = `{
"application/json"
],
"tags": [
"证书"
"证书管理"
],
"summary": "获取 CA 提供商",
"responses": {
@@ -92,7 +92,7 @@ const docTemplate = `{
"application/json"
],
"tags": [
"证书"
"证书管理"
],
"summary": "获取证书列表",
"responses": {
@@ -142,7 +142,7 @@ const docTemplate = `{
"application/json"
],
"tags": [
"证书"
"证书管理"
],
"summary": "添加证书",
"parameters": [
@@ -190,7 +190,7 @@ const docTemplate = `{
"application/json"
],
"tags": [
"证书"
"证书管理"
],
"summary": "获取证书",
"parameters": [
@@ -249,7 +249,7 @@ const docTemplate = `{
"application/json"
],
"tags": [
"证书"
"证书管理"
],
"summary": "更新证书",
"parameters": [
@@ -305,7 +305,7 @@ const docTemplate = `{
"application/json"
],
"tags": [
"证书"
"证书管理"
],
"summary": "删除证书",
"parameters": [
@@ -351,7 +351,7 @@ const docTemplate = `{
"application/json"
],
"tags": [
"证书"
"证书管理"
],
"summary": "获取 DNS 接口列表",
"responses": {
@@ -401,7 +401,7 @@ const docTemplate = `{
"application/json"
],
"tags": [
"证书"
"证书管理"
],
"summary": "添加 DNS 接口",
"parameters": [
@@ -449,7 +449,7 @@ const docTemplate = `{
"application/json"
],
"tags": [
"证书"
"证书管理"
],
"summary": "获取 DNS 接口",
"parameters": [
@@ -508,7 +508,7 @@ const docTemplate = `{
"application/json"
],
"tags": [
"证书"
"证书管理"
],
"summary": "更新 DNS 接口",
"parameters": [
@@ -564,7 +564,7 @@ const docTemplate = `{
"application/json"
],
"tags": [
"证书"
"证书管理"
],
"summary": "删除 DNS 接口",
"parameters": [
@@ -610,7 +610,7 @@ const docTemplate = `{
"application/json"
],
"tags": [
"证书"
"证书管理"
],
"summary": "获取 DNS 提供商",
"responses": {
@@ -644,7 +644,7 @@ const docTemplate = `{
"application/json"
],
"tags": [
"证书"
"证书管理"
],
"summary": "获取手动 DNS 记录",
"parameters": [
@@ -710,7 +710,7 @@ const docTemplate = `{
"application/json"
],
"tags": [
"证书"
"证书管理"
],
"summary": "签发证书",
"parameters": [
@@ -761,7 +761,7 @@ const docTemplate = `{
"application/json"
],
"tags": [
"证书"
"证书管理"
],
"summary": "续签证书",
"parameters": [
@@ -809,7 +809,7 @@ const docTemplate = `{
"application/json"
],
"tags": [
"证书"
"证书管理"
],
"summary": "获取用户列表",
"responses": {
@@ -859,7 +859,7 @@ const docTemplate = `{
"application/json"
],
"tags": [
"证书"
"证书管理"
],
"summary": "添加 ACME 用户",
"parameters": [
@@ -907,7 +907,7 @@ const docTemplate = `{
"application/json"
],
"tags": [
"证书"
"证书管理"
],
"summary": "获取 ACME 用户",
"parameters": [
@@ -966,7 +966,7 @@ const docTemplate = `{
"application/json"
],
"tags": [
"证书"
"证书管理"
],
"summary": "更新 ACME 用户",
"parameters": [
@@ -1022,7 +1022,7 @@ const docTemplate = `{
"application/json"
],
"tags": [
"证书"
"证书管理"
],
"summary": "删除 ACME 用户",
"parameters": [
@@ -1056,6 +1056,155 @@ const docTemplate = `{
}
}
},
"/panel/setting/list": {
"get": {
"security": [
{
"BearerToken": []
}
],
"description": "获取面板设置列表",
"produces": [
"application/json"
],
"tags": [
"面板设置"
],
"summary": "设置列表",
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/controllers.SuccessResponse"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/responses.Settings"
}
}
}
]
}
},
"401": {
"description": "登录已过期",
"schema": {
"$ref": "#/definitions/controllers.ErrorResponse"
}
},
"500": {
"description": "系统内部错误",
"schema": {
"$ref": "#/definitions/controllers.ErrorResponse"
}
}
}
}
},
"/panel/setting/update": {
"post": {
"security": [
{
"BearerToken": []
}
],
"description": "更新面板设置",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"面板设置"
],
"summary": "更新设置",
"parameters": [
{
"description": "更新设置",
"name": "data",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/requests.Update"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/controllers.SuccessResponse"
}
},
"401": {
"description": "登录已过期",
"schema": {
"$ref": "#/definitions/controllers.ErrorResponse"
}
},
"500": {
"description": "系统内部错误",
"schema": {
"$ref": "#/definitions/controllers.ErrorResponse"
}
}
}
}
},
"/panel/user/info": {
"get": {
"security": [
{
"BearerToken": []
}
],
"description": "获取当前登录用户信息",
"produces": [
"application/json"
],
"tags": [
"用户鉴权"
],
"summary": "用户信息",
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/controllers.SuccessResponse"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/responses.Info"
}
}
}
]
}
},
"401": {
"description": "登录已过期",
"schema": {
"$ref": "#/definitions/controllers.ErrorResponse"
}
},
"500": {
"description": "系统内部错误",
"schema": {
"$ref": "#/definitions/controllers.ErrorResponse"
}
}
}
}
},
"/panel/user/login": {
"post": {
"description": "通过用户名和密码获取访问令牌",
@@ -1066,9 +1215,9 @@ const docTemplate = `{
"application/json"
],
"tags": [
"用户"
"用户鉴权"
],
"summary": "用户登录",
"summary": "登录",
"parameters": [
{
"description": "登录信息",
@@ -1404,6 +1553,35 @@ const docTemplate = `{
}
}
},
"requests.Update": {
"type": "object",
"properties": {
"backup_path": {
"type": "string"
},
"email": {
"type": "string"
},
"entrance": {
"type": "string"
},
"name": {
"type": "string"
},
"password": {
"type": "string"
},
"port": {
"type": "integer"
},
"username": {
"type": "string"
},
"website_path": {
"type": "string"
}
}
},
"requests.UserStore": {
"type": "object",
"properties": {
@@ -1474,6 +1652,55 @@ const docTemplate = `{
"type": "integer"
}
}
},
"responses.Info": {
"type": "object",
"properties": {
"email": {
"type": "string"
},
"id": {
"type": "integer"
},
"role": {
"type": "array",
"items": {
"type": "string"
}
},
"username": {
"type": "string"
}
}
},
"responses.Settings": {
"type": "object",
"properties": {
"backup_path": {
"type": "string"
},
"email": {
"type": "string"
},
"entrance": {
"type": "string"
},
"name": {
"type": "string"
},
"password": {
"type": "string"
},
"port": {
"type": "string"
},
"username": {
"type": "string"
},
"website_path": {
"type": "string"
}
}
}
},
"securityDefinitions": {

View File

@@ -23,7 +23,7 @@
"application/json"
],
"tags": [
"证书"
"证书管理"
],
"summary": "获取算法列表",
"responses": {
@@ -54,7 +54,7 @@
"application/json"
],
"tags": [
"证书"
"证书管理"
],
"summary": "获取 CA 提供商",
"responses": {
@@ -85,7 +85,7 @@
"application/json"
],
"tags": [
"证书"
"证书管理"
],
"summary": "获取证书列表",
"responses": {
@@ -135,7 +135,7 @@
"application/json"
],
"tags": [
"证书"
"证书管理"
],
"summary": "添加证书",
"parameters": [
@@ -183,7 +183,7 @@
"application/json"
],
"tags": [
"证书"
"证书管理"
],
"summary": "获取证书",
"parameters": [
@@ -242,7 +242,7 @@
"application/json"
],
"tags": [
"证书"
"证书管理"
],
"summary": "更新证书",
"parameters": [
@@ -298,7 +298,7 @@
"application/json"
],
"tags": [
"证书"
"证书管理"
],
"summary": "删除证书",
"parameters": [
@@ -344,7 +344,7 @@
"application/json"
],
"tags": [
"证书"
"证书管理"
],
"summary": "获取 DNS 接口列表",
"responses": {
@@ -394,7 +394,7 @@
"application/json"
],
"tags": [
"证书"
"证书管理"
],
"summary": "添加 DNS 接口",
"parameters": [
@@ -442,7 +442,7 @@
"application/json"
],
"tags": [
"证书"
"证书管理"
],
"summary": "获取 DNS 接口",
"parameters": [
@@ -501,7 +501,7 @@
"application/json"
],
"tags": [
"证书"
"证书管理"
],
"summary": "更新 DNS 接口",
"parameters": [
@@ -557,7 +557,7 @@
"application/json"
],
"tags": [
"证书"
"证书管理"
],
"summary": "删除 DNS 接口",
"parameters": [
@@ -603,7 +603,7 @@
"application/json"
],
"tags": [
"证书"
"证书管理"
],
"summary": "获取 DNS 提供商",
"responses": {
@@ -637,7 +637,7 @@
"application/json"
],
"tags": [
"证书"
"证书管理"
],
"summary": "获取手动 DNS 记录",
"parameters": [
@@ -703,7 +703,7 @@
"application/json"
],
"tags": [
"证书"
"证书管理"
],
"summary": "签发证书",
"parameters": [
@@ -754,7 +754,7 @@
"application/json"
],
"tags": [
"证书"
"证书管理"
],
"summary": "续签证书",
"parameters": [
@@ -802,7 +802,7 @@
"application/json"
],
"tags": [
"证书"
"证书管理"
],
"summary": "获取用户列表",
"responses": {
@@ -852,7 +852,7 @@
"application/json"
],
"tags": [
"证书"
"证书管理"
],
"summary": "添加 ACME 用户",
"parameters": [
@@ -900,7 +900,7 @@
"application/json"
],
"tags": [
"证书"
"证书管理"
],
"summary": "获取 ACME 用户",
"parameters": [
@@ -959,7 +959,7 @@
"application/json"
],
"tags": [
"证书"
"证书管理"
],
"summary": "更新 ACME 用户",
"parameters": [
@@ -1015,7 +1015,7 @@
"application/json"
],
"tags": [
"证书"
"证书管理"
],
"summary": "删除 ACME 用户",
"parameters": [
@@ -1049,6 +1049,155 @@
}
}
},
"/panel/setting/list": {
"get": {
"security": [
{
"BearerToken": []
}
],
"description": "获取面板设置列表",
"produces": [
"application/json"
],
"tags": [
"面板设置"
],
"summary": "设置列表",
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/controllers.SuccessResponse"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/responses.Settings"
}
}
}
]
}
},
"401": {
"description": "登录已过期",
"schema": {
"$ref": "#/definitions/controllers.ErrorResponse"
}
},
"500": {
"description": "系统内部错误",
"schema": {
"$ref": "#/definitions/controllers.ErrorResponse"
}
}
}
}
},
"/panel/setting/update": {
"post": {
"security": [
{
"BearerToken": []
}
],
"description": "更新面板设置",
"consumes": [
"application/json"
],
"produces": [
"application/json"
],
"tags": [
"面板设置"
],
"summary": "更新设置",
"parameters": [
{
"description": "更新设置",
"name": "data",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/requests.Update"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/controllers.SuccessResponse"
}
},
"401": {
"description": "登录已过期",
"schema": {
"$ref": "#/definitions/controllers.ErrorResponse"
}
},
"500": {
"description": "系统内部错误",
"schema": {
"$ref": "#/definitions/controllers.ErrorResponse"
}
}
}
}
},
"/panel/user/info": {
"get": {
"security": [
{
"BearerToken": []
}
],
"description": "获取当前登录用户信息",
"produces": [
"application/json"
],
"tags": [
"用户鉴权"
],
"summary": "用户信息",
"responses": {
"200": {
"description": "OK",
"schema": {
"allOf": [
{
"$ref": "#/definitions/controllers.SuccessResponse"
},
{
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/responses.Info"
}
}
}
]
}
},
"401": {
"description": "登录已过期",
"schema": {
"$ref": "#/definitions/controllers.ErrorResponse"
}
},
"500": {
"description": "系统内部错误",
"schema": {
"$ref": "#/definitions/controllers.ErrorResponse"
}
}
}
}
},
"/panel/user/login": {
"post": {
"description": "通过用户名和密码获取访问令牌",
@@ -1059,9 +1208,9 @@
"application/json"
],
"tags": [
"用户"
"用户鉴权"
],
"summary": "用户登录",
"summary": "登录",
"parameters": [
{
"description": "登录信息",
@@ -1397,6 +1546,35 @@
}
}
},
"requests.Update": {
"type": "object",
"properties": {
"backup_path": {
"type": "string"
},
"email": {
"type": "string"
},
"entrance": {
"type": "string"
},
"name": {
"type": "string"
},
"password": {
"type": "string"
},
"port": {
"type": "integer"
},
"username": {
"type": "string"
},
"website_path": {
"type": "string"
}
}
},
"requests.UserStore": {
"type": "object",
"properties": {
@@ -1467,6 +1645,55 @@
"type": "integer"
}
}
},
"responses.Info": {
"type": "object",
"properties": {
"email": {
"type": "string"
},
"id": {
"type": "integer"
},
"role": {
"type": "array",
"items": {
"type": "string"
}
},
"username": {
"type": "string"
}
}
},
"responses.Settings": {
"type": "object",
"properties": {
"backup_path": {
"type": "string"
},
"email": {
"type": "string"
},
"entrance": {
"type": "string"
},
"name": {
"type": "string"
},
"password": {
"type": "string"
},
"port": {
"type": "string"
},
"username": {
"type": "string"
},
"website_path": {
"type": "string"
}
}
}
},
"securityDefinitions": {

View File

@@ -188,6 +188,25 @@ definitions:
id:
type: integer
type: object
requests.Update:
properties:
backup_path:
type: string
email:
type: string
entrance:
type: string
name:
type: string
password:
type: string
port:
type: integer
username:
type: string
website_path:
type: string
type: object
requests.UserStore:
properties:
ca:
@@ -234,6 +253,38 @@ definitions:
total:
type: integer
type: object
responses.Info:
properties:
email:
type: string
id:
type: integer
role:
items:
type: string
type: array
username:
type: string
type: object
responses.Settings:
properties:
backup_path:
type: string
email:
type: string
entrance:
type: string
name:
type: string
password:
type: string
port:
type: string
username:
type: string
website_path:
type: string
type: object
info:
contact:
email: i@haozi.net
@@ -260,7 +311,7 @@ paths:
- BearerToken: []
summary: 获取算法列表
tags:
- 证书
- 证书管理
/panel/cert/caProviders:
get:
description: 获取面板证书管理支持的 CA 提供商
@@ -279,7 +330,7 @@ paths:
- BearerToken: []
summary: 获取 CA 提供商
tags:
- 证书
- 证书管理
/panel/cert/certs:
get:
description: 获取面板证书管理的证书列表
@@ -307,7 +358,7 @@ paths:
- BearerToken: []
summary: 获取证书列表
tags:
- 证书
- 证书管理
post:
consumes:
- application/json
@@ -338,7 +389,7 @@ paths:
- BearerToken: []
summary: 添加证书
tags:
- 证书
- 证书管理
/panel/cert/certs/{id}:
delete:
consumes:
@@ -369,7 +420,7 @@ paths:
- BearerToken: []
summary: 删除证书
tags:
- 证书
- 证书管理
get:
description: 获取面板证书管理的证书
parameters:
@@ -402,7 +453,7 @@ paths:
- BearerToken: []
summary: 获取证书
tags:
- 证书
- 证书管理
put:
consumes:
- application/json
@@ -438,7 +489,7 @@ paths:
- BearerToken: []
summary: 更新证书
tags:
- 证书
- 证书管理
/panel/cert/dns:
get:
description: 获取面板证书管理的 DNS 接口列表
@@ -466,7 +517,7 @@ paths:
- BearerToken: []
summary: 获取 DNS 接口列表
tags:
- 证书
- 证书管理
post:
consumes:
- application/json
@@ -497,7 +548,7 @@ paths:
- BearerToken: []
summary: 添加 DNS 接口
tags:
- 证书
- 证书管理
/panel/cert/dns/{id}:
delete:
consumes:
@@ -528,7 +579,7 @@ paths:
- BearerToken: []
summary: 删除 DNS 接口
tags:
- 证书
- 证书管理
get:
description: 获取面板证书管理的 DNS 接口
parameters:
@@ -561,7 +612,7 @@ paths:
- BearerToken: []
summary: 获取 DNS 接口
tags:
- 证书
- 证书管理
put:
consumes:
- application/json
@@ -597,7 +648,7 @@ paths:
- BearerToken: []
summary: 更新 DNS 接口
tags:
- 证书
- 证书管理
/panel/cert/dnsProviders:
get:
description: 获取面板证书管理支持的 DNS 提供商
@@ -616,7 +667,7 @@ paths:
- BearerToken: []
summary: 获取 DNS 提供商
tags:
- 证书
- 证书管理
/panel/cert/manualDNS:
post:
consumes:
@@ -655,7 +706,7 @@ paths:
- BearerToken: []
summary: 获取手动 DNS 记录
tags:
- 证书
- 证书管理
/panel/cert/obtain:
post:
consumes:
@@ -687,7 +738,7 @@ paths:
- BearerToken: []
summary: 签发证书
tags:
- 证书
- 证书管理
/panel/cert/renew:
post:
consumes:
@@ -719,7 +770,7 @@ paths:
- BearerToken: []
summary: 续签证书
tags:
- 证书
- 证书管理
/panel/cert/users:
get:
description: 获取面板证书管理的 ACME 用户列表
@@ -747,7 +798,7 @@ paths:
- BearerToken: []
summary: 获取用户列表
tags:
- 证书
- 证书管理
post:
consumes:
- application/json
@@ -778,7 +829,7 @@ paths:
- BearerToken: []
summary: 添加 ACME 用户
tags:
- 证书
- 证书管理
/panel/cert/users/{id}:
delete:
consumes:
@@ -809,7 +860,7 @@ paths:
- BearerToken: []
summary: 删除 ACME 用户
tags:
- 证书
- 证书管理
get:
description: 获取面板证书管理的 ACME 用户
parameters:
@@ -842,7 +893,7 @@ paths:
- BearerToken: []
summary: 获取 ACME 用户
tags:
- 证书
- 证书管理
put:
consumes:
- application/json
@@ -878,7 +929,95 @@ paths:
- BearerToken: []
summary: 更新 ACME 用户
tags:
- 证书
- 证书管理
/panel/setting/list:
get:
description: 获取面板设置列表
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/controllers.SuccessResponse'
- properties:
data:
$ref: '#/definitions/responses.Settings'
type: object
"401":
description: 登录已过期
schema:
$ref: '#/definitions/controllers.ErrorResponse'
"500":
description: 系统内部错误
schema:
$ref: '#/definitions/controllers.ErrorResponse'
security:
- BearerToken: []
summary: 设置列表
tags:
- 面板设置
/panel/setting/update:
post:
consumes:
- application/json
description: 更新面板设置
parameters:
- description: 更新设置
in: body
name: data
required: true
schema:
$ref: '#/definitions/requests.Update'
produces:
- application/json
responses:
"200":
description: OK
schema:
$ref: '#/definitions/controllers.SuccessResponse'
"401":
description: 登录已过期
schema:
$ref: '#/definitions/controllers.ErrorResponse'
"500":
description: 系统内部错误
schema:
$ref: '#/definitions/controllers.ErrorResponse'
security:
- BearerToken: []
summary: 更新设置
tags:
- 面板设置
/panel/user/info:
get:
description: 获取当前登录用户信息
produces:
- application/json
responses:
"200":
description: OK
schema:
allOf:
- $ref: '#/definitions/controllers.SuccessResponse'
- properties:
data:
$ref: '#/definitions/responses.Info'
type: object
"401":
description: 登录已过期
schema:
$ref: '#/definitions/controllers.ErrorResponse'
"500":
description: 系统内部错误
schema:
$ref: '#/definitions/controllers.ErrorResponse'
security:
- BearerToken: []
summary: 用户信息
tags:
- 用户鉴权
/panel/user/login:
post:
consumes:
@@ -906,9 +1045,9 @@ paths:
description: 系统内部错误
schema:
$ref: '#/definitions/controllers.ErrorResponse'
summary: 用户登录
summary: 登录
tags:
- 用户
- 用户鉴权
/swagger:
get:
description: Swagger UI

19
go.mod
View File

@@ -8,8 +8,8 @@ require (
github.com/go-acme/lego/v4 v4.14.2
github.com/gookit/color v1.5.4
github.com/gookit/validate v1.5.1
github.com/goravel/fiber v1.1.10
github.com/goravel/framework v1.13.1-0.20231105184928-f95059f0588e
github.com/goravel/fiber v1.1.11-0.20231107174202-96a179fc3422
github.com/goravel/framework v1.13.1-0.20231107172540-ff0aeb1785f2
github.com/iancoleman/strcase v0.3.0
github.com/imroc/req/v3 v3.42.1
github.com/mojocn/base64Captcha v1.3.5
@@ -24,10 +24,10 @@ require (
)
require (
cloud.google.com/go v0.110.8 // indirect
cloud.google.com/go/compute v1.23.1 // indirect
cloud.google.com/go v0.110.9 // indirect
cloud.google.com/go/compute v1.23.2 // indirect
cloud.google.com/go/compute/metadata v0.2.3 // indirect
cloud.google.com/go/iam v1.1.3 // indirect
cloud.google.com/go/iam v1.1.4 // indirect
cloud.google.com/go/pubsub v1.33.0 // indirect
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
@@ -122,7 +122,7 @@ require (
github.com/json-iterator/go v1.1.12 // indirect
github.com/kelseyhightower/envconfig v1.4.0 // indirect
github.com/klauspost/compress v1.17.2 // indirect
github.com/klauspost/cpuid/v2 v2.2.5 // indirect
github.com/klauspost/cpuid/v2 v2.2.6 // indirect
github.com/lestrrat-go/strftime v1.0.5 // indirect
github.com/lib/pq v1.10.2 // indirect
github.com/magiconair/properties v1.8.7 // indirect
@@ -159,6 +159,7 @@ require (
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sagikazarmark/locafero v0.3.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/savioxavier/termlink v1.3.0 // indirect
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
@@ -200,9 +201,9 @@ require (
golang.org/x/tools v0.14.0 // indirect
google.golang.org/api v0.143.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20231012201019-e917dd12ba7a // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405 // indirect
google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 // indirect
google.golang.org/grpc v1.59.0 // indirect
google.golang.org/protobuf v1.31.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect

40
go.sum
View File

@@ -17,23 +17,23 @@ cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHOb
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=
cloud.google.com/go v0.110.8 h1:tyNdfIxjzaWctIiLYOTalaLKZ17SI44SKFW26QbOhME=
cloud.google.com/go v0.110.8/go.mod h1:Iz8AkXJf1qmxC3Oxoep8R1T36w8B92yU29PcBhHO5fk=
cloud.google.com/go v0.110.9 h1:e7ITSqGFFk4rbz/JFIqZh3G4VEHguhAL4BQcFlWtU68=
cloud.google.com/go v0.110.9/go.mod h1:rpxevX/0Lqvlbc88b7Sc1SPNdyK1riNBTUU6JXhYNpM=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/compute v1.23.1 h1:V97tBoDaZHb6leicZ1G6DLK2BAaZLJ/7+9BB/En3hR0=
cloud.google.com/go/compute v1.23.1/go.mod h1:CqB3xpmPKKt3OJpW2ndFIXnA9A4xAy/F3Xp1ixncW78=
cloud.google.com/go/compute v1.23.2 h1:nWEMDhgbBkBJjfpVySqU4jgWdc22PLR0o4vEexZHers=
cloud.google.com/go/compute v1.23.2/go.mod h1:JJ0atRC0J/oWYiiVBmsSsrRnh92DhZPG4hFDcR04Rns=
cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/iam v1.1.3 h1:18tKG7DzydKWUnLjonWcJO6wjSCAtzh4GcRKlH/Hrzc=
cloud.google.com/go/iam v1.1.3/go.mod h1:3khUlaBXfPKKe7huYgEpDn6FtgRyMEqbkvBxrQyY5SE=
cloud.google.com/go/kms v1.15.3 h1:RYsbxTRmk91ydKCzekI2YjryO4c5Y2M80Zwcs9/D/cI=
cloud.google.com/go/iam v1.1.4 h1:K6n/GZHFTtEoKT5aUG3l9diPi0VduZNQ1PfdnpkkIFk=
cloud.google.com/go/iam v1.1.4/go.mod h1:l/rg8l1AaA+VFMho/HYx2Vv6xinPSLMF8qfhRPIZ0L8=
cloud.google.com/go/kms v1.15.4 h1:gEZzC54ZBI+aeW8/jg9tgz9KR4Aa+WEDPbdGIV3iJ7A=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
@@ -379,14 +379,14 @@ github.com/gookit/goutil v0.6.14 h1:96elyOG4BvVoDaiT7vx1vHPrVyEtFfYlPPBODR0/FGQ=
github.com/gookit/goutil v0.6.14/go.mod h1:YyDBddefmjS+mU2PDPgCcjVzTDM5WgExiDv5ZA/b8I8=
github.com/gookit/validate v1.5.1 h1:rPp64QZQJM+fysGFAhKpvekQAav4Ok6sjfTs9ZtxcpA=
github.com/gookit/validate v1.5.1/go.mod h1:SskOHUQokzMNt6T3r7N+N/4me/6fxDx+tmoXf/3ZQog=
github.com/goravel/fiber v1.1.10 h1:Eu1nACrtbjdbXm7TfKq+ilgv+pW29rv3b1aixtd/vrI=
github.com/goravel/fiber v1.1.10/go.mod h1:rBy+e45mNyg3jTx2g2tarmxqsOgZlZE695FVyitSitk=
github.com/goravel/fiber v1.1.11-0.20231107174202-96a179fc3422 h1:jHdODj8Ix4J6sMH5yDvQyxgTJJI+kJHV9qwQBaZJTqY=
github.com/goravel/fiber v1.1.11-0.20231107174202-96a179fc3422/go.mod h1:HDIybfECtdRiysZcE+RHbz5XeFxJNBxQiGSz+V5LEx0=
github.com/goravel/file-rotatelogs v0.0.0-20211215053220-2ab31dd9575c h1:obhFK91JAhcf7s6h5sggZishm1VyGW/gBCreo+7/SwQ=
github.com/goravel/file-rotatelogs v0.0.0-20211215053220-2ab31dd9575c/go.mod h1:YSWsLXlG16u5CWFaXNZHhEQD10+NwF3xfgDV816OwLE=
github.com/goravel/file-rotatelogs/v2 v2.4.1 h1:ogkeIFcTHSBRUBpZYiyJbpul8hkVXxHPuDbOaP78O1M=
github.com/goravel/file-rotatelogs/v2 v2.4.1/go.mod h1:euk9qr52WrzM8ICs1hecFcR4CZ/ZZOPdacHfvHgbOf0=
github.com/goravel/framework v1.13.1-0.20231105184928-f95059f0588e h1:CXJeXd47UPO0/uSPmX5zTLP9DsZ0ptWxqW0TWhmlBrM=
github.com/goravel/framework v1.13.1-0.20231105184928-f95059f0588e/go.mod h1:5jKFbJzfqhaQTP3HCgbyrpnrCyoJjxN5JWSXO96H0iQ=
github.com/goravel/framework v1.13.1-0.20231107172540-ff0aeb1785f2 h1:2hi1MMia0iRfjGFozCrmhbm9HMIP5SFFvv7eVFAfyRM=
github.com/goravel/framework v1.13.1-0.20231107172540-ff0aeb1785f2/go.mod h1:5jKFbJzfqhaQTP3HCgbyrpnrCyoJjxN5JWSXO96H0iQ=
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI=
@@ -465,8 +465,8 @@ github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47e
github.com/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4=
github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg=
github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc=
github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
@@ -600,6 +600,8 @@ github.com/sagikazarmark/locafero v0.3.0 h1:zT7VEGWC2DTflmccN/5T1etyKvxSxpHsjb9c
github.com/sagikazarmark/locafero v0.3.0/go.mod h1:w+v7UsPNFwzF1cHuOajOOzoq4U7v/ig1mpRjqV+Bu1U=
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
github.com/savioxavier/termlink v1.3.0 h1:3Gl4FzQjUyiHzmoEDfmWEhgIwDiJY4poOQHP+k8ReA4=
github.com/savioxavier/termlink v1.3.0/go.mod h1:5T5ePUlWbxCHIwyF8/Ez1qufOoGM89RCg9NvG+3G3gc=
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee h1:8Iv5m6xEo1NR1AvpV+7XmhI4r39LGNzwUL4YpMuL5vk=
github.com/savsgio/gotils v0.0.0-20230208104028-c358bd845dee/go.mod h1:qwtSXrKuJh/zsFQ12yEE89xfCrGKK63Rr7ctU/uCo4g=
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
@@ -1090,12 +1092,12 @@ google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6D
google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210207032614-bba0dbe2a9ea/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b h1:+YaDE2r2OG8t/z5qmsh7Y+XXwCbvadxxZ0YY6mTdrVA=
google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:CgAqfJo+Xmu0GwA0411Ht3OU3OntXwsGmrmjI8ioGXI=
google.golang.org/genproto/googleapis/api v0.0.0-20231012201019-e917dd12ba7a h1:myvhA4is3vrit1a6NZCWBIwN0kNEnX21DJOJX/NvIfI=
google.golang.org/genproto/googleapis/api v0.0.0-20231012201019-e917dd12ba7a/go.mod h1:SUBoKXbI1Efip18FClrQVGjWcyd0QZd8KkvdP34t7ww=
google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405 h1:AB/lmRny7e2pLhFEYIbl5qkDAUt2h0ZRO4wGPhZf+ik=
google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405/go.mod h1:67X1fPuzjcrkymZzZV1vvkFeTn2Rvc6lYF9MYFGCcwE=
google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405 h1:I6WNifs6pF9tNdSob2W24JtyxIYjzFB9qDlpUC76q+U=
google.golang.org/genproto v0.0.0-20231030173426-d783a09b4405/go.mod h1:3WDQMjmJk36UQhjQ89emUzb1mdaHcPeeAh4SCBKznB4=
google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b h1:CIC2YMXmIhYw6evmhPxBKJ4fmLbOFtXQN/GV3XOZR8k=
google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:IBQ646DjkDkvUIsVq/cc03FUFQ9wbZu7yE396YcL870=
google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17 h1:Jyp0Hsi0bmHXG6k9eATXoYtjd6e2UzZ1SCn/wIupY14=
google.golang.org/genproto/googleapis/rpc v0.0.0-20231106174013-bbf56f31fb17/go.mod h1:oQ5rr10WTTMvP4A36n8JpR1OrO1BEiV4f78CneXZxkA=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=

View File

@@ -14,13 +14,21 @@ import (
// Write 写入文件
func Write(path string, data string, permission os.FileMode) bool {
if err := os.MkdirAll(filepath.Dir(path), permission); err != nil {
facades.Log().Errorf("[面板][Helpers] 创建目录失败: %s", err.Error())
facades.Log().With(map[string]any{
"path": filepath.Dir(path),
"permission": permission,
"error": err.Error(),
}).Tags("面板", "工具函数").Error("创建目录失败")
return false
}
err := os.WriteFile(path, []byte(data), permission)
if err != nil {
facades.Log().Errorf("[面板][Helpers] 写入文件 %s 失败: %s", path, err.Error())
facades.Log().With(map[string]any{
"path": path,
"permission": permission,
"error": err.Error(),
}).Tags("面板", "工具函数").Error("写入文件失败")
return false
}
@@ -31,17 +39,23 @@ func Write(path string, data string, permission os.FileMode) bool {
func Read(path string) string {
data, err := os.ReadFile(path)
if err != nil {
facades.Log().Errorf("[面板][Helpers] 读取文件 %s 失败: %s", path, err.Error())
facades.Log().With(map[string]any{
"path": path,
"error": err.Error(),
}).Tags("面板", "工具函数").Error("读取文件失败")
return ""
}
return string(data)
}
// Remove 删除文件
// Remove 删除文件/目录
func Remove(path string) bool {
if err := os.Remove(path); err != nil {
facades.Log().Errorf("[面板][Helpers] 删除文件 %s 失败: %s", path, err.Error())
if err := os.RemoveAll(path); err != nil {
facades.Log().With(map[string]any{
"path": path,
"error": err.Error(),
}).Tags("面板", "工具函数").Error("删除文件/目录失败")
return false
}
@@ -59,7 +73,10 @@ func Exec(shell string) string {
fmt.Println(err.Error())
panic(err)
} else {
facades.Log().Errorf("[面板][Helpers] 执行命令 %s 失败: %s", shell, err.Error())
facades.Log().With(map[string]any{
"shell": shell,
"error": err.Error(),
}).Tags("面板", "工具函数").Error("执行命令失败")
}
return ""
}
@@ -68,17 +85,11 @@ func Exec(shell string) string {
}
// ExecAsync 异步执行 shell 命令
func ExecAsync(shell string) {
func ExecAsync(shell string) error {
cmd := exec.Command("bash", "-c", shell)
err := cmd.Start()
if err != nil {
if support.Env == support.EnvTest {
fmt.Println(err.Error())
panic(err)
} else {
facades.Log().Errorf("[面板][Helpers] 执行命令 %s 失败: %s", shell, err.Error())
}
return err
}
go func() {
@@ -88,39 +99,56 @@ func ExecAsync(shell string) {
fmt.Println(err.Error())
panic(err)
} else {
facades.Log().Errorf("[面板][Helpers] 执行命令 %s 失败: %s", shell, err.Error())
facades.Log().With(map[string]any{
"shell": shell,
"error": err.Error(),
}).Tags("面板", "工具函数").Error("异步执行命令失败")
}
}
}()
return nil
}
// Mkdir 创建目录
func Mkdir(path string, permission os.FileMode) bool {
if err := os.MkdirAll(path, permission); err != nil {
facades.Log().Errorf("[面板][Helpers] 创建目录 %s 失败: %s", path, err.Error())
facades.Log().With(map[string]any{
"path": path,
"permission": permission,
"error": err.Error(),
}).Tags("面板", "工具函数").Error("创建目录失败")
return false
}
return true
}
// Chmod 修改文件权限
// Chmod 修改文件/目录权限
func Chmod(path string, permission os.FileMode) bool {
if err := os.Chmod(path, permission); err != nil {
facades.Log().Errorf("[面板][Helpers] 修改文件 %s 权限失败: %s", path, err.Error())
facades.Log().With(map[string]any{
"path": path,
"permission": permission,
}).Tags("面板", "工具函数").Error("修改文件/目录权限失败")
return false
}
return true
}
// Chown 修改路径所有者
// Chown 修改文件/目录所有者
func Chown(path, user, group string) bool {
cmd := exec.Command("chown", "-R", user+":"+group, path)
err := cmd.Run()
if err != nil {
facades.Log().Errorf("[面板][Helpers] 修改路径 %s 所有者失败: %s", path, err.Error())
facades.Log().With(map[string]any{
"path": path,
"user": user,
"group": group,
"error": err.Error(),
}).Tags("面板", "工具函数").Error("修改文件/目录所有者失败")
return false
}
@@ -143,20 +171,19 @@ func Empty(path string) bool {
return len(files) == 0
}
// Mv 移动路径
// Mv 移动文件/目录
func Mv(src, dst string) (bool, error) {
cmd := exec.Command("mv", src, dst)
err := cmd.Run()
if err != nil {
facades.Log().Errorf("[面板][Helpers] 移动 %s 到 %s 失败: %s", src, dst, err.Error())
return false, err
}
return true, nil
}
// Cp 复制路径
// Cp 复制文件/目录
func Cp(src, dst string) (bool, error) {
cmd := exec.Command("cp", "-r", src, dst)

View File

@@ -55,7 +55,8 @@ func (s *SystemHelperTestSuite) TestExecAsync() {
command := "echo 'test' > /tmp/testfile"
defer os.Remove("/tmp/testfile")
ExecAsync(command)
err := ExecAsync(command)
s.Nil(err)
time.Sleep(time.Second)

View File

@@ -376,7 +376,12 @@ func UpdatePanel(panelInfo PanelInfo) error {
func RestartPanel() {
color.Greenln("重启面板...")
ExecAsync("sleep 2 && systemctl restart panel")
err := ExecAsync("sleep 2 && systemctl restart panel")
if err != nil {
color.Redln("重启失败")
return
}
color.Greenln("重启完成")
}

View File

@@ -127,7 +127,7 @@ func Api() {
r.Prefix("setting").Middleware(middleware.Jwt()).Group(func(r route.Router) {
settingController := controllers.NewSettingController()
r.Get("list", settingController.List)
r.Post("save", settingController.Save)
r.Post("update", settingController.Update)
})
})