From d90423db4a078b80d4d620f3b6571f28cdc2f0d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=80=97=E5=AD=90?= Date: Wed, 8 Nov 2023 02:01:28 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E8=A7=84=E8=8C=83=E9=83=A8=E5=88=86?= =?UTF-8?q?=E6=8E=A7=E5=88=B6=E5=99=A8=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/http/controllers/cert_controller.go | 42 ++-- app/http/controllers/info_controller.go | 8 +- app/http/controllers/setting_controller.go | 134 +++++----- app/http/controllers/task_controller.go | 4 +- app/http/controllers/user_controller.go | 30 ++- app/http/requests/setting/update.go | 49 ++++ app/http/responses/setting/list.go | 12 + app/http/responses/user/info.go | 8 + docs/docs.go | 273 +++++++++++++++++++-- docs/swagger.json | 273 +++++++++++++++++++-- docs/swagger.yaml | 185 ++++++++++++-- go.mod | 19 +- go.sum | 40 +-- pkg/tools/system.go | 75 ++++-- pkg/tools/system_test.go | 3 +- pkg/tools/tools.go | 7 +- routes/api.go | 2 +- 17 files changed, 941 insertions(+), 223 deletions(-) create mode 100644 app/http/requests/setting/update.go create mode 100644 app/http/responses/setting/list.go create mode 100644 app/http/responses/user/info.go diff --git a/app/http/controllers/cert_controller.go b/app/http/controllers/cert_controller.go index e587c8fc94..14b5647c1d 100644 --- a/app/http/controllers/cert_controller.go +++ b/app/http/controllers/cert_controller.go @@ -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 diff --git a/app/http/controllers/info_controller.go b/app/http/controllers/info_controller.go index 32ca77bbce..e93eb43c6d 100644 --- a/app/http/controllers/info_controller.go +++ b/app/http/controllers/info_controller.go @@ -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()) diff --git a/app/http/controllers/setting_controller.go b/app/http/controllers/setting_controller.go index 1746c68623..3d4fb44054 100644 --- a/app/http/controllers/setting_controller.go +++ b/app/http/controllers/setting_controller.go @@ -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, "入口格式错误") - } - - err := r.setting.Set(models.SettingKeyName, name) +// 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, 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) } diff --git a/app/http/controllers/task_controller.go b/app/http/controllers/task_controller.go index 3b23710235..193e3f622e 100644 --- a/app/http/controllers/task_controller.go +++ b/app/http/controllers/task_controller.go @@ -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] 查询任务失败") diff --git a/app/http/controllers/user_controller.go b/app/http/controllers/user_controller.go index 273b839cd6..b86931e949 100644 --- a/app/http/controllers/user_controller.go +++ b/app/http/controllers/user_controller.go @@ -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, }) } diff --git a/app/http/requests/setting/update.go b/app/http/requests/setting/update.go new file mode 100644 index 0000000000..9556afb55a --- /dev/null +++ b/app/http/requests/setting/update.go @@ -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 +} diff --git a/app/http/responses/setting/list.go b/app/http/responses/setting/list.go new file mode 100644 index 0000000000..e7bdc37f42 --- /dev/null +++ b/app/http/responses/setting/list.go @@ -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"` +} diff --git a/app/http/responses/user/info.go b/app/http/responses/user/info.go new file mode 100644 index 0000000000..0e01efd9ad --- /dev/null +++ b/app/http/responses/user/info.go @@ -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"` +} diff --git a/docs/docs.go b/docs/docs.go index 6174306d96..c2ff860eda 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -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": { diff --git a/docs/swagger.json b/docs/swagger.json index 6cd200850b..aad3edb218 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -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": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 93b67936ae..90275d074a 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -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 diff --git a/go.mod b/go.mod index 615e79f6a6..cb39d8457e 100644 --- a/go.mod +++ b/go.mod @@ -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 diff --git a/go.sum b/go.sum index 6359b32024..85a47763f1 100644 --- a/go.sum +++ b/go.sum @@ -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= diff --git a/pkg/tools/system.go b/pkg/tools/system.go index 679d658c52..9f2a780d3e 100644 --- a/pkg/tools/system.go +++ b/pkg/tools/system.go @@ -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) diff --git a/pkg/tools/system_test.go b/pkg/tools/system_test.go index e2c6ccf954..2d3a8208e9 100644 --- a/pkg/tools/system_test.go +++ b/pkg/tools/system_test.go @@ -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) diff --git a/pkg/tools/tools.go b/pkg/tools/tools.go index 1fa5b17e56..7607d92996 100644 --- a/pkg/tools/tools.go +++ b/pkg/tools/tools.go @@ -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("重启完成") } diff --git a/routes/api.go b/routes/api.go index 79d93acaac..7e0a11dce1 100644 --- a/routes/api.go +++ b/routes/api.go @@ -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) }) })