diff --git a/app/console/commands/cert_renew.go b/app/console/commands/cert_renew.go index 7b99fde2..30b95d26 100644 --- a/app/console/commands/cert_renew.go +++ b/app/console/commands/cert_renew.go @@ -66,7 +66,7 @@ func (receiver *CertRenew) Handle(ctx console.Context) error { facades.Log().Tags("面板", "证书管理").With(map[string]any{ "cert_id": cert.ID, "error": err.Error(), - }).Errorf("证书续签失败") + }).Infof("证书续签失败") } } diff --git a/app/console/commands/monitoring.go b/app/console/commands/monitoring.go index 26996c18..fe4e1ec4 100644 --- a/app/console/commands/monitoring.go +++ b/app/console/commands/monitoring.go @@ -49,7 +49,7 @@ func (receiver *Monitoring) Handle(ctx console.Context) error { Info: info, }) if err != nil { - facades.Log().Errorf("[面板] 系统监控保存失败: %s", err.Error()) + facades.Log().Infof("[面板] 系统监控保存失败: %s", err.Error()) color.Redf("[面板] 系统监控保存失败: %s", err.Error()) return nil } @@ -69,7 +69,7 @@ func (receiver *Monitoring) Handle(ctx console.Context) error { } _, err = facades.Orm().Query().Where("created_at < ?", carbon.Now().SubDays(days).ToDateTimeString()).Delete(&models.Monitor{}) if err != nil { - facades.Log().Errorf("[面板] 系统监控删除过期数据失败: %s", err.Error()) + facades.Log().Infof("[面板] 系统监控删除过期数据失败: %s", err.Error()) return nil } diff --git a/app/http/controllers/cert_controller.go b/app/http/controllers/cert_controller.go index 11a5a47c..62539d23 100644 --- a/app/http/controllers/cert_controller.go +++ b/app/http/controllers/cert_controller.go @@ -120,6 +120,7 @@ func (r *CertController) Algorithms(ctx http.Context) http.Response { // @Tags 证书管理 // @Produce json // @Security BearerToken +// @Param data body commonrequests.Paginate true "分页信息" // @Success 200 {object} SuccessResponse{data=responses.CertList} // @Failure 401 {object} ErrorResponse "登录已过期" // @Failure 500 {object} ErrorResponse "系统内部错误" @@ -137,11 +138,11 @@ func (r *CertController) UserList(ctx http.Context) http.Response { if err != nil { facades.Log().Request(ctx.Request()).Tags("面板", "证书管理").With(map[string]any{ "error": err.Error(), - }).Error("获取ACME用户列表失败") + }).Info("获取ACME用户列表失败") return ErrorSystem(ctx) } - return Success(ctx, &responses.UserList{ + return Success(ctx, responses.UserList{ Total: total, Items: users, }) @@ -170,7 +171,7 @@ func (r *CertController) UserStore(ctx http.Context) http.Response { if err != nil { facades.Log().Request(ctx.Request()).Tags("面板", "证书管理").With(map[string]any{ "error": err.Error(), - }).Error("添加ACME用户失败") + }).Info("添加ACME用户失败") return Error(ctx, http.StatusInternalServerError, err.Error()) } @@ -202,7 +203,7 @@ func (r *CertController) UserUpdate(ctx http.Context) http.Response { facades.Log().Request(ctx.Request()).Tags("面板", "证书管理").With(map[string]any{ "userID": updateRequest.ID, "error": err.Error(), - }).Error("更新ACME用户失败") + }).Info("更新ACME用户失败") return Error(ctx, http.StatusInternalServerError, err.Error()) } @@ -232,7 +233,7 @@ func (r *CertController) UserShow(ctx http.Context) http.Response { facades.Log().Request(ctx.Request()).Tags("面板", "证书管理").With(map[string]any{ "userID": showAndDestroyRequest.ID, "error": err.Error(), - }).Error("获取ACME用户失败") + }).Info("获取ACME用户失败") return ErrorSystem(ctx) } @@ -263,7 +264,7 @@ func (r *CertController) UserDestroy(ctx http.Context) http.Response { facades.Log().Request(ctx.Request()).Tags("面板", "证书管理").With(map[string]any{ "userID": showAndDestroyRequest.ID, "error": err.Error(), - }).Error("删除ACME用户失败") + }).Info("删除ACME用户失败") return Error(ctx, http.StatusInternalServerError, err.Error()) } @@ -276,6 +277,7 @@ func (r *CertController) UserDestroy(ctx http.Context) http.Response { // @Tags 证书管理 // @Produce json // @Security BearerToken +// @Param data body commonrequests.Paginate true "分页信息" // @Success 200 {object} SuccessResponse{data=responses.DNSList} // @Failure 401 {object} ErrorResponse "登录已过期" // @Failure 500 {object} ErrorResponse "系统内部错误" @@ -293,11 +295,11 @@ func (r *CertController) DNSList(ctx http.Context) http.Response { if err != nil { facades.Log().Request(ctx.Request()).Tags("面板", "证书管理").With(map[string]any{ "error": err.Error(), - }).Error("获取DNS接口列表失败") + }).Info("获取DNS接口列表失败") return ErrorSystem(ctx) } - return Success(ctx, &responses.DNSList{ + return Success(ctx, responses.DNSList{ Total: total, Items: dns, }) @@ -326,7 +328,7 @@ func (r *CertController) DNSStore(ctx http.Context) http.Response { if err != nil { facades.Log().Request(ctx.Request()).Tags("面板", "证书管理").With(map[string]any{ "error": err.Error(), - }).Error("添加DNS接口失败") + }).Info("添加DNS接口失败") return ErrorSystem(ctx) } @@ -356,7 +358,7 @@ func (r *CertController) DNSShow(ctx http.Context) http.Response { facades.Log().Request(ctx.Request()).Tags("面板", "证书管理").With(map[string]any{ "dnsID": showAndDestroyRequest.ID, "error": err.Error(), - }).Error("获取DNS接口失败") + }).Info("获取DNS接口失败") return ErrorSystem(ctx) } @@ -388,7 +390,7 @@ func (r *CertController) DNSUpdate(ctx http.Context) http.Response { facades.Log().Request(ctx.Request()).Tags("面板", "证书管理").With(map[string]any{ "dnsID": updateRequest.ID, "error": err.Error(), - }).Error("更新DNS接口失败") + }).Info("更新DNS接口失败") return ErrorSystem(ctx) } @@ -419,7 +421,7 @@ func (r *CertController) DNSDestroy(ctx http.Context) http.Response { facades.Log().Request(ctx.Request()).Tags("面板", "证书管理").With(map[string]any{ "dnsID": showAndDestroyRequest.ID, "error": err.Error(), - }).Error("删除DNS接口失败") + }).Info("删除DNS接口失败") return Error(ctx, http.StatusInternalServerError, err.Error()) } @@ -432,6 +434,7 @@ func (r *CertController) DNSDestroy(ctx http.Context) http.Response { // @Tags 证书管理 // @Produce json // @Security BearerToken +// @Param data body commonrequests.Paginate true "分页信息" // @Success 200 {object} SuccessResponse{data=responses.CertList} // @Failure 401 {object} ErrorResponse "登录已过期" // @Failure 500 {object} ErrorResponse "系统内部错误" @@ -449,11 +452,11 @@ func (r *CertController) CertList(ctx http.Context) http.Response { if err != nil { facades.Log().Request(ctx.Request()).Tags("面板", "证书管理").With(map[string]any{ "error": err.Error(), - }).Error("获取证书列表失败") + }).Info("获取证书列表失败") return ErrorSystem(ctx) } - return Success(ctx, &responses.CertList{ + return Success(ctx, responses.CertList{ Total: total, Items: certs, }) @@ -482,7 +485,7 @@ func (r *CertController) CertStore(ctx http.Context) http.Response { if err != nil { facades.Log().Request(ctx.Request()).Tags("面板", "证书管理").With(map[string]any{ "error": err.Error(), - }).Error("添加证书失败") + }).Info("添加证书失败") return ErrorSystem(ctx) } @@ -514,7 +517,7 @@ func (r *CertController) CertUpdate(ctx http.Context) http.Response { facades.Log().Request(ctx.Request()).Tags("面板", "证书管理").With(map[string]any{ "certID": updateRequest.ID, "error": err.Error(), - }).Error("更新证书失败") + }).Info("更新证书失败") return ErrorSystem(ctx) } @@ -544,7 +547,7 @@ func (r *CertController) CertShow(ctx http.Context) http.Response { facades.Log().Request(ctx.Request()).Tags("面板", "证书管理").With(map[string]any{ "certID": showAndDestroyRequest.ID, "error": err.Error(), - }).Error("获取证书失败") + }).Info("获取证书失败") return ErrorSystem(ctx) } @@ -575,7 +578,7 @@ func (r *CertController) CertDestroy(ctx http.Context) http.Response { facades.Log().Request(ctx.Request()).Tags("面板", "证书管理").With(map[string]any{ "certID": showAndDestroyRequest.ID, "error": err.Error(), - }).Error("删除证书失败") + }).Info("删除证书失败") return ErrorSystem(ctx) } @@ -606,7 +609,7 @@ func (r *CertController) Obtain(ctx http.Context) http.Response { facades.Log().Request(ctx.Request()).Tags("面板", "证书管理").With(map[string]any{ "certID": obtainRequest.ID, "error": err.Error(), - }).Error("获取证书失败") + }).Info("获取证书失败") return ErrorSystem(ctx) } @@ -618,7 +621,7 @@ func (r *CertController) Obtain(ctx http.Context) http.Response { if err != nil { facades.Log().Request(ctx.Request()).Tags("面板", "证书管理").With(map[string]any{ "error": err.Error(), - }).Error("签发证书失败") + }).Info("签发证书失败") return Error(ctx, http.StatusInternalServerError, err.Error()) } @@ -648,7 +651,7 @@ func (r *CertController) Renew(ctx http.Context) http.Response { if err != nil { facades.Log().Request(ctx.Request()).Tags("面板", "证书管理").With(map[string]any{ "error": err.Error(), - }).Error("续签证书失败") + }).Info("续签证书失败") return Error(ctx, http.StatusInternalServerError, err.Error()) } @@ -678,7 +681,7 @@ func (r *CertController) ManualDNS(ctx http.Context) http.Response { if err != nil { facades.Log().Request(ctx.Request()).Tags("面板", "证书管理").With(map[string]any{ "error": err.Error(), - }).Error("获取手动DNS记录失败") + }).Info("获取手动DNS记录失败") return Error(ctx, http.StatusInternalServerError, err.Error()) } diff --git a/app/http/controllers/controller.go b/app/http/controllers/controller.go index d9eede01..84109385 100644 --- a/app/http/controllers/controller.go +++ b/app/http/controllers/controller.go @@ -66,7 +66,7 @@ func Check(ctx http.Context, slug string) http.Response { installedPlugin := services.NewPluginImpl().GetInstalledBySlug(slug) installedPlugins, err := services.NewPluginImpl().AllInstalled() if err != nil { - facades.Log().Error("[面板][插件] 获取已安装插件失败") + facades.Log().Info("[面板][插件] 获取已安装插件失败") return ErrorSystem(ctx) } diff --git a/app/http/controllers/cron_controller.go b/app/http/controllers/cron_controller.go index 5d863aa1..64a266fd 100644 --- a/app/http/controllers/cron_controller.go +++ b/app/http/controllers/cron_controller.go @@ -34,7 +34,7 @@ func (c *CronController) List(ctx http.Context) http.Response { var total int64 err := facades.Orm().Query().Paginate(page, limit, &crons, &total) if err != nil { - facades.Log().Error("[面板][CronController] 查询计划任务列表失败 ", err) + facades.Log().Info("[面板][CronController] 查询计划任务列表失败 ", err) return ErrorSystem(ctx) } @@ -111,16 +111,16 @@ panel cutoff ${name} ${save} 2>&1 shellDir := "/www/server/cron/" shellLogDir := "/www/server/cron/logs/" if !tools.Exists(shellDir) { - facades.Log().Error("[面板][CronController] 计划任务目录不存在") + facades.Log().Info("[面板][CronController] 计划任务目录不存在") return Error(ctx, http.StatusInternalServerError, "计划任务目录不存在") } if !tools.Exists(shellLogDir) { - facades.Log().Error("[面板][CronController] 计划任务日志目录不存在") + facades.Log().Info("[面板][CronController] 计划任务日志目录不存在") return Error(ctx, http.StatusInternalServerError, "计划任务日志目录不存在") } shellFile := strconv.Itoa(int(carbon.Now().Timestamp())) + tools.RandomString(16) - if !tools.Write(shellDir+shellFile+".sh", shell, 0700) { - facades.Log().Error("[面板][CronController] 创建计划任务脚本失败 ", err) + if err = tools.Write(shellDir+shellFile+".sh", shell, 0700); err != nil { + facades.Log().Info("[面板][CronController] 创建计划任务脚本失败 ", err) return ErrorSystem(ctx) } tools.Exec("dos2unix " + shellDir + shellFile + ".sh") @@ -135,7 +135,7 @@ panel cutoff ${name} ${save} 2>&1 err = facades.Orm().Query().Create(&cron) if err != nil { - facades.Log().Error("[面板][CronController] 创建计划任务失败 ", err) + facades.Log().Info("[面板][CronController] 创建计划任务失败 ", err) return ErrorSystem(ctx) } @@ -190,12 +190,12 @@ func (c *CronController) Update(ctx http.Context) http.Response { cron.Name = ctx.Request().Input("name") err = facades.Orm().Query().Save(&cron) if err != nil { - facades.Log().Error("[面板][CronController] 更新计划任务失败 ", err) + facades.Log().Info("[面板][CronController] 更新计划任务失败 ", err) return ErrorSystem(ctx) } - if !tools.Write(cron.Shell, ctx.Request().Input("script"), 0644) { - facades.Log().Error("[面板][CronController] 更新计划任务脚本失败 ", err) + if err = tools.Write(cron.Shell, ctx.Request().Input("script"), 0644); err != nil { + facades.Log().Info("[面板][CronController] 更新计划任务脚本失败 ", err) return ErrorSystem(ctx) } tools.Exec("dos2unix " + cron.Shell) @@ -221,7 +221,7 @@ func (c *CronController) Delete(ctx http.Context) http.Response { _, err = facades.Orm().Query().Delete(&cron) if err != nil { - facades.Log().Error("[面板][CronController] 删除计划任务失败 ", err) + facades.Log().Info("[面板][CronController] 删除计划任务失败 ", err) return ErrorSystem(ctx) } @@ -249,7 +249,7 @@ func (c *CronController) Status(ctx http.Context) http.Response { cron.Status = ctx.Request().InputBool("status") err = facades.Orm().Query().Save(&cron) if err != nil { - facades.Log().Error("[面板][CronController] 更新计划任务状态失败 ", err) + facades.Log().Info("[面板][CronController] 更新计划任务状态失败 ", err) return ErrorSystem(ctx) } diff --git a/app/http/controllers/info_controller.go b/app/http/controllers/info_controller.go index e93eb43c..ea8ccbc1 100644 --- a/app/http/controllers/info_controller.go +++ b/app/http/controllers/info_controller.go @@ -38,7 +38,7 @@ func (c *InfoController) Name(ctx http.Context) http.Response { var setting models.Setting err := facades.Orm().Query().Where("key", "name").First(&setting) if err != nil { - facades.Log().Error("[面板][InfoController] 查询面板名称失败 ", err) + facades.Log().Info("[面板][InfoController] 查询面板名称失败 ", err) return ErrorSystem(ctx) } @@ -52,7 +52,7 @@ func (c *InfoController) HomePlugins(ctx http.Context) http.Response { var plugins []models.Plugin err := facades.Orm().Query().Where("show", 1).Find(&plugins) if err != nil { - facades.Log().Error("[面板][InfoController] 查询首页插件失败 ", err) + facades.Log().Info("[面板][InfoController] 查询首页插件失败 ", err) return ErrorSystem(ctx) } @@ -121,7 +121,7 @@ func (c *InfoController) CountInfo(ctx http.Context) http.Response { if err != nil { facades.Log().Request(ctx.Request()).With(map[string]any{ "error": err.Error(), - }).Error("[面板][InfoController] 获取数据库列表失败") + }).Info("[面板][InfoController] 获取数据库列表失败") databaseCount = -1 } else { defer db.Close() @@ -129,7 +129,7 @@ func (c *InfoController) CountInfo(ctx http.Context) http.Response { if err != nil { facades.Log().Request(ctx.Request()).With(map[string]any{ "error": err.Error(), - }).Error("[面板][InfoController] 获取数据库列表失败") + }).Info("[面板][InfoController] 获取数据库列表失败") databaseCount = -1 } else { defer rows.Close() @@ -307,7 +307,7 @@ func (c *InfoController) Update(ctx http.Context) http.Response { if err != nil { facades.Log().Request(ctx.Request()).With(map[string]any{ "error": err.Error(), - }).Error("[面板][InfoController] 获取最新版本失败") + }).Info("[面板][InfoController] 获取最新版本失败") return Error(ctx, http.StatusInternalServerError, "获取最新版本失败") } @@ -315,7 +315,7 @@ func (c *InfoController) Update(ctx http.Context) http.Response { if err != nil { facades.Log().Request(ctx.Request()).With(map[string]any{ "error": err.Error(), - }).Error("[面板][InfoController] 更新面板失败") + }).Info("[面板][InfoController] 更新面板失败") return Error(ctx, http.StatusInternalServerError, "更新失败: "+err.Error()) } diff --git a/app/http/controllers/monitor_controller.go b/app/http/controllers/monitor_controller.go index dba36846..0a107bc4 100644 --- a/app/http/controllers/monitor_controller.go +++ b/app/http/controllers/monitor_controller.go @@ -26,7 +26,7 @@ func (r *MonitorController) Switch(ctx http.Context) http.Response { value := ctx.Request().InputBool("monitor") err := r.setting.Set(models.SettingKeyMonitor, cast.ToString(value)) if err != nil { - facades.Log().Error("[面板][MonitorController] 更新监控开关失败 ", err) + facades.Log().Info("[面板][MonitorController] 更新监控开关失败 ", err) return ErrorSystem(ctx) } @@ -38,7 +38,7 @@ func (r *MonitorController) SaveDays(ctx http.Context) http.Response { days := ctx.Request().Input("days") err := r.setting.Set(models.SettingKeyMonitorDays, days) if err != nil { - facades.Log().Error("[面板][MonitorController] 更新监控天数失败 ", err) + facades.Log().Info("[面板][MonitorController] 更新监控天数失败 ", err) return ErrorSystem(ctx) } @@ -60,7 +60,7 @@ func (r *MonitorController) SwitchAndDays(ctx http.Context) http.Response { func (r *MonitorController) Clear(ctx http.Context) http.Response { _, err := facades.Orm().Query().Where("1 = 1").Delete(&models.Monitor{}) if err != nil { - facades.Log().Error("[面板][MonitorController] 清空监控数据失败 ", err) + facades.Log().Info("[面板][MonitorController] 清空监控数据失败 ", err) return ErrorSystem(ctx) } @@ -77,7 +77,7 @@ func (r *MonitorController) List(ctx http.Context) http.Response { var monitors []models.Monitor err := facades.Orm().Query().Where("created_at >= ?", startTime.ToDateTimeString()).Where("created_at <= ?", endTime.ToDateTimeString()).Get(&monitors) if err != nil { - facades.Log().Error("[面板][MonitorController] 查询监控数据失败 ", err) + facades.Log().Info("[面板][MonitorController] 查询监控数据失败 ", err) return ErrorSystem(ctx) } diff --git a/app/http/controllers/plugin_controller.go b/app/http/controllers/plugin_controller.go index 6978a716..f35b4ca8 100644 --- a/app/http/controllers/plugin_controller.go +++ b/app/http/controllers/plugin_controller.go @@ -100,7 +100,7 @@ func (r *PluginController) Install(ctx http.Context) http.Response { installedPlugin := r.plugin.GetInstalledBySlug(slug) installedPlugins, err := r.plugin.AllInstalled() if err != nil { - facades.Log().Error("[面板][PluginController] 获取已安装插件失败") + facades.Log().Info("[面板][PluginController] 获取已安装插件失败") return ErrorSystem(ctx) } @@ -141,7 +141,7 @@ func (r *PluginController) Install(ctx http.Context) http.Response { task.Shell = plugin.Install + " >> /tmp/" + plugin.Slug + ".log 2>&1" task.Log = "/tmp/" + plugin.Slug + ".log" if err := facades.Orm().Query().Create(&task); err != nil { - facades.Log().Error("[面板][PluginController] 创建任务失败: " + err.Error()) + facades.Log().Info("[面板][PluginController] 创建任务失败: " + err.Error()) return ErrorSystem(ctx) } @@ -156,7 +156,7 @@ func (r *PluginController) Uninstall(ctx http.Context) http.Response { installedPlugin := r.plugin.GetInstalledBySlug(slug) installedPlugins, err := r.plugin.AllInstalled() if err != nil { - facades.Log().Error("[面板][PluginController] 获取已安装插件失败") + facades.Log().Info("[面板][PluginController] 获取已安装插件失败") return ErrorSystem(ctx) } @@ -197,7 +197,7 @@ func (r *PluginController) Uninstall(ctx http.Context) http.Response { task.Shell = plugin.Uninstall + " >> /tmp/" + plugin.Slug + ".log 2>&1" task.Log = "/tmp/" + plugin.Slug + ".log" if err := facades.Orm().Query().Create(&task); err != nil { - facades.Log().Error("[面板][PluginController] 创建任务失败: " + err.Error()) + facades.Log().Info("[面板][PluginController] 创建任务失败: " + err.Error()) return ErrorSystem(ctx) } @@ -212,7 +212,7 @@ func (r *PluginController) Update(ctx http.Context) http.Response { installedPlugin := r.plugin.GetInstalledBySlug(slug) installedPlugins, err := r.plugin.AllInstalled() if err != nil { - facades.Log().Error("[面板][PluginController] 获取已安装插件失败") + facades.Log().Info("[面板][PluginController] 获取已安装插件失败") return ErrorSystem(ctx) } @@ -253,7 +253,7 @@ func (r *PluginController) Update(ctx http.Context) http.Response { task.Shell = plugin.Update + " >> /tmp/" + plugin.Slug + ".log 2>&1" task.Log = "/tmp/" + plugin.Slug + ".log" if err := facades.Orm().Query().Create(&task); err != nil { - facades.Log().Error("[面板][PluginController] 创建任务失败: " + err.Error()) + facades.Log().Info("[面板][PluginController] 创建任务失败: " + err.Error()) return ErrorSystem(ctx) } @@ -268,7 +268,7 @@ func (r *PluginController) UpdateShow(ctx http.Context) http.Response { var plugin models.Plugin if err := facades.Orm().Query().Where("slug", slug).First(&plugin); err != nil { - facades.Log().Error("[面板][PluginController] 查询插件失败: " + err.Error()) + facades.Log().Info("[面板][PluginController] 查询插件失败: " + err.Error()) return ErrorSystem(ctx) } if plugin.ID == 0 { @@ -277,7 +277,7 @@ func (r *PluginController) UpdateShow(ctx http.Context) http.Response { plugin.Show = show if err := facades.Orm().Query().Save(&plugin); err != nil { - facades.Log().Error("[面板][PluginController] 更新插件失败: " + err.Error()) + facades.Log().Info("[面板][PluginController] 更新插件失败: " + err.Error()) return ErrorSystem(ctx) } diff --git a/app/http/controllers/plugins/fail2ban_controller.go b/app/http/controllers/plugins/fail2ban_controller.go index f38f90ae..35576aae 100644 --- a/app/http/controllers/plugins/fail2ban_controller.go +++ b/app/http/controllers/plugins/fail2ban_controller.go @@ -236,7 +236,7 @@ func (r *Fail2banController) Add(ctx http.Context) http.Response { if err != nil { return controllers.Error(ctx, http.StatusUnprocessableEntity, "网站不存在") } - config, err := r.website.GetConfig(int(website.ID)) + config, err := r.website.GetConfig(website.ID) if err != nil { return controllers.Error(ctx, http.StatusUnprocessableEntity, "获取网站配置失败") } diff --git a/app/http/controllers/plugins/mysql57_controller.go b/app/http/controllers/plugins/mysql57_controller.go index 1b9d1ff4..49f8778e 100644 --- a/app/http/controllers/plugins/mysql57_controller.go +++ b/app/http/controllers/plugins/mysql57_controller.go @@ -155,7 +155,7 @@ func (r *Mysql57Controller) SaveConfig(ctx http.Context) http.Response { return controllers.Error(ctx, http.StatusUnprocessableEntity, "配置不能为空") } - if !tools.Write("/www/server/mysql/conf/my.cnf", config, 0644) { + if err := tools.Write("/www/server/mysql/conf/my.cnf", config, 0644); err != nil { return controllers.Error(ctx, http.StatusInternalServerError, "写入MySQL配置失败") } @@ -345,14 +345,14 @@ func (r *Mysql57Controller) DatabaseList(ctx http.Context) http.Response { db, err := sql.Open("mysql", "root:"+rootPassword+"@unix(/tmp/mysql.sock)/") if err != nil { - facades.Log().Error("[MySQL57] 连接数据库失败" + err.Error()) + facades.Log().Info("[MySQL57] 连接数据库失败" + err.Error()) return controllers.Error(ctx, http.StatusInternalServerError, "连接数据库失败") } defer db.Close() rows, err := db.Query("SHOW DATABASES") if err != nil { - facades.Log().Error("[MySQL57] 获取数据库列表失败" + err.Error()) + facades.Log().Info("[MySQL57] 获取数据库列表失败" + err.Error()) return controllers.Error(ctx, http.StatusInternalServerError, "获取数据库列表失败") } defer rows.Close() @@ -369,7 +369,7 @@ func (r *Mysql57Controller) DatabaseList(ctx http.Context) http.Response { } if err := rows.Err(); err != nil { - facades.Log().Error("[MySQL57] 获取数据库列表失败" + err.Error()) + facades.Log().Info("[MySQL57] 获取数据库列表失败" + err.Error()) return controllers.Error(ctx, http.StatusInternalServerError, "获取数据库列表失败") } @@ -459,7 +459,7 @@ func (r *Mysql57Controller) BackupList(ctx http.Context) http.Response { backupList, err := r.backup.MysqlList() if err != nil { - facades.Log().Error("[MySQL57] 获取备份列表失败:" + err.Error()) + facades.Log().Info("[MySQL57] 获取备份列表失败:" + err.Error()) return controllers.Error(ctx, http.StatusInternalServerError, "获取备份列表失败") } @@ -533,7 +533,7 @@ func (r *Mysql57Controller) CreateBackup(ctx http.Context) http.Response { database := ctx.Request().Input("database") err = r.backup.MysqlBackup(database) if err != nil { - facades.Log().Error("[MYSQL57] 创建备份失败:" + err.Error()) + facades.Log().Info("[MYSQL57] 创建备份失败:" + err.Error()) return controllers.Error(ctx, http.StatusInternalServerError, "创建备份失败") } @@ -584,7 +584,7 @@ func (r *Mysql57Controller) RestoreBackup(ctx http.Context) http.Response { err = r.backup.MysqlRestore(ctx.Request().Input("database"), ctx.Request().Input("backup")) if err != nil { - facades.Log().Error("[MYSQL57] 还原失败:" + err.Error()) + facades.Log().Info("[MYSQL57] 还原失败:" + err.Error()) return controllers.Error(ctx, http.StatusInternalServerError, "还原失败: "+err.Error()) } @@ -607,14 +607,14 @@ func (r *Mysql57Controller) UserList(ctx http.Context) http.Response { rootPassword := r.setting.Get(models.SettingKeyMysqlRootPassword) db, err := sql.Open("mysql", "root:"+rootPassword+"@unix(/tmp/mysql.sock)/") if err != nil { - facades.Log().Error("[MYSQL57] 连接数据库失败:" + err.Error()) + facades.Log().Info("[MYSQL57] 连接数据库失败:" + err.Error()) return controllers.Error(ctx, http.StatusInternalServerError, "连接数据库失败") } defer db.Close() rows, err := db.Query("SELECT user, host FROM mysql.user") if err != nil { - facades.Log().Error("[MYSQL57] 查询数据库失败:" + err.Error()) + facades.Log().Info("[MYSQL57] 查询数据库失败:" + err.Error()) return controllers.Error(ctx, http.StatusInternalServerError, "查询数据库失败") } defer rows.Close() diff --git a/app/http/controllers/plugins/mysql80_controller.go b/app/http/controllers/plugins/mysql80_controller.go index 9a12ff10..84f365e8 100644 --- a/app/http/controllers/plugins/mysql80_controller.go +++ b/app/http/controllers/plugins/mysql80_controller.go @@ -155,7 +155,7 @@ func (r *Mysql80Controller) SaveConfig(ctx http.Context) http.Response { return controllers.Error(ctx, http.StatusUnprocessableEntity, "配置不能为空") } - if !tools.Write("/www/server/mysql/conf/my.cnf", config, 0644) { + if err := tools.Write("/www/server/mysql/conf/my.cnf", config, 0644); err != nil { return controllers.Error(ctx, http.StatusInternalServerError, "写入MySQL配置失败") } @@ -345,14 +345,14 @@ func (r *Mysql80Controller) DatabaseList(ctx http.Context) http.Response { db, err := sql.Open("mysql", "root:"+rootPassword+"@unix(/tmp/mysql.sock)/") if err != nil { - facades.Log().Error("[MySQL80] 连接数据库失败" + err.Error()) + facades.Log().Info("[MySQL80] 连接数据库失败" + err.Error()) return controllers.Error(ctx, http.StatusInternalServerError, "连接数据库失败") } defer db.Close() rows, err := db.Query("SHOW DATABASES") if err != nil { - facades.Log().Error("[MySQL80] 获取数据库列表失败" + err.Error()) + facades.Log().Info("[MySQL80] 获取数据库列表失败" + err.Error()) return controllers.Error(ctx, http.StatusInternalServerError, "获取数据库列表失败") } defer rows.Close() @@ -369,7 +369,7 @@ func (r *Mysql80Controller) DatabaseList(ctx http.Context) http.Response { } if err := rows.Err(); err != nil { - facades.Log().Error("[MySQL80] 获取数据库列表失败" + err.Error()) + facades.Log().Info("[MySQL80] 获取数据库列表失败" + err.Error()) return controllers.Error(ctx, http.StatusInternalServerError, "获取数据库列表失败") } @@ -459,7 +459,7 @@ func (r *Mysql80Controller) BackupList(ctx http.Context) http.Response { backupList, err := r.backup.MysqlList() if err != nil { - facades.Log().Error("[MySQL80] 获取备份列表失败:" + err.Error()) + facades.Log().Info("[MySQL80] 获取备份列表失败:" + err.Error()) return controllers.Error(ctx, http.StatusInternalServerError, "获取备份列表失败") } @@ -533,7 +533,7 @@ func (r *Mysql80Controller) CreateBackup(ctx http.Context) http.Response { database := ctx.Request().Input("database") err = r.backup.MysqlBackup(database) if err != nil { - facades.Log().Error("[MYSQL80] 创建备份失败:" + err.Error()) + facades.Log().Info("[MYSQL80] 创建备份失败:" + err.Error()) return controllers.Error(ctx, http.StatusInternalServerError, "创建备份失败") } @@ -584,7 +584,7 @@ func (r *Mysql80Controller) RestoreBackup(ctx http.Context) http.Response { err = r.backup.MysqlRestore(ctx.Request().Input("database"), ctx.Request().Input("backup")) if err != nil { - facades.Log().Error("[MYSQL80] 还原失败:" + err.Error()) + facades.Log().Info("[MYSQL80] 还原失败:" + err.Error()) return controllers.Error(ctx, http.StatusInternalServerError, "还原失败: "+err.Error()) } @@ -607,14 +607,14 @@ func (r *Mysql80Controller) UserList(ctx http.Context) http.Response { rootPassword := r.setting.Get(models.SettingKeyMysqlRootPassword) db, err := sql.Open("mysql", "root:"+rootPassword+"@unix(/tmp/mysql.sock)/") if err != nil { - facades.Log().Error("[MYSQL80] 连接数据库失败:" + err.Error()) + facades.Log().Info("[MYSQL80] 连接数据库失败:" + err.Error()) return controllers.Error(ctx, http.StatusInternalServerError, "连接数据库失败") } defer db.Close() rows, err := db.Query("SELECT user, host FROM mysql.user") if err != nil { - facades.Log().Error("[MYSQL80] 查询数据库失败:" + err.Error()) + facades.Log().Info("[MYSQL80] 查询数据库失败:" + err.Error()) return controllers.Error(ctx, http.StatusInternalServerError, "查询数据库失败") } defer rows.Close() diff --git a/app/http/controllers/plugins/openresty_controller.go b/app/http/controllers/plugins/openresty_controller.go index 7c97ffbf..d8934a0f 100644 --- a/app/http/controllers/plugins/openresty_controller.go +++ b/app/http/controllers/plugins/openresty_controller.go @@ -149,7 +149,7 @@ func (r *OpenRestyController) SaveConfig(ctx http.Context) http.Response { return controllers.Error(ctx, http.StatusInternalServerError, "配置不能为空") } - if !tools.Write("/www/server/openresty/conf/nginx.conf", config, 0644) { + if err := tools.Write("/www/server/openresty/conf/nginx.conf", config, 0644); err != nil { return controllers.Error(ctx, http.StatusInternalServerError, "保存OpenResty配置失败") } @@ -192,7 +192,7 @@ func (r *OpenRestyController) Load(ctx http.Context) http.Response { client := req.C().SetTimeout(10 * time.Second) resp, err := client.R().Get("http://127.0.0.1/nginx_status") if err != nil || !resp.IsSuccessState() { - facades.Log().Error("[OpenResty] 获取OpenResty负载失败: " + err.Error()) + facades.Log().Info("[OpenResty] 获取OpenResty负载失败: " + err.Error()) return controllers.Error(ctx, http.StatusInternalServerError, "获取OpenResty负载失败") } diff --git a/app/http/controllers/plugins/php74_controller.go b/app/http/controllers/plugins/php74_controller.go index 1c6b4f92..0f6d4670 100644 --- a/app/http/controllers/plugins/php74_controller.go +++ b/app/http/controllers/plugins/php74_controller.go @@ -158,7 +158,7 @@ func (r *Php74Controller) Load(ctx http.Context) http.Response { client := req.C().SetTimeout(10 * time.Second) resp, err := client.R().Get("http://127.0.0.1/phpfpm_status/" + r.version) if err != nil || !resp.IsSuccessState() { - facades.Log().Error("获取PHP-" + r.version + "运行状态失败") + facades.Log().Info("获取PHP-" + r.version + "运行状态失败") return controllers.Error(ctx, http.StatusInternalServerError, "[PHP-"+r.version+"] 获取运行状态失败") } @@ -259,7 +259,7 @@ func (r *Php74Controller) InstallExtension(ctx http.Context) http.Response { task.Shell = `bash '/www/panel/scripts/php_extensions/` + item.Slug + `.sh' install ` + r.version + ` >> /tmp/` + item.Slug + `.log 2>&1` task.Log = "/tmp/" + item.Slug + ".log" if err := facades.Orm().Query().Create(&task); err != nil { - facades.Log().Error("[PHP-" + r.version + "] 创建安装拓展任务失败:" + err.Error()) + facades.Log().Info("[PHP-" + r.version + "] 创建安装拓展任务失败:" + err.Error()) return controllers.ErrorSystem(ctx) } @@ -296,7 +296,7 @@ func (r *Php74Controller) UninstallExtension(ctx http.Context) http.Response { task.Shell = `bash '/www/panel/scripts/php_extensions/` + item.Slug + `.sh' uninstall ` + r.version + ` >> /tmp/` + item.Slug + `.log 2>&1` task.Log = "/tmp/" + item.Slug + ".log" if err := facades.Orm().Query().Create(&task); err != nil { - facades.Log().Error("[PHP-" + r.version + "] 创建卸载拓展任务失败:" + err.Error()) + facades.Log().Info("[PHP-" + r.version + "] 创建卸载拓展任务失败:" + err.Error()) return controllers.ErrorSystem(ctx) } diff --git a/app/http/controllers/plugins/php80_controller.go b/app/http/controllers/plugins/php80_controller.go index 74b9283c..172bd44f 100644 --- a/app/http/controllers/plugins/php80_controller.go +++ b/app/http/controllers/plugins/php80_controller.go @@ -158,7 +158,7 @@ func (r *Php80Controller) Load(ctx http.Context) http.Response { client := req.C().SetTimeout(10 * time.Second) resp, err := client.R().Get("http://127.0.0.1/phpfpm_status/" + r.version) if err != nil || !resp.IsSuccessState() { - facades.Log().Error("获取PHP-" + r.version + "运行状态失败") + facades.Log().Info("获取PHP-" + r.version + "运行状态失败") return controllers.Error(ctx, http.StatusInternalServerError, "[PHP-"+r.version+"] 获取运行状态失败") } @@ -259,7 +259,7 @@ func (r *Php80Controller) InstallExtension(ctx http.Context) http.Response { task.Shell = `bash '/www/panel/scripts/php_extensions/` + item.Slug + `.sh' install ` + r.version + ` >> /tmp/` + item.Slug + `.log 2>&1` task.Log = "/tmp/" + item.Slug + ".log" if err := facades.Orm().Query().Create(&task); err != nil { - facades.Log().Error("[PHP-" + r.version + "] 创建安装拓展任务失败:" + err.Error()) + facades.Log().Info("[PHP-" + r.version + "] 创建安装拓展任务失败:" + err.Error()) return controllers.ErrorSystem(ctx) } @@ -296,7 +296,7 @@ func (r *Php80Controller) UninstallExtension(ctx http.Context) http.Response { task.Shell = `bash '/www/panel/scripts/php_extensions/` + item.Slug + `.sh' uninstall ` + r.version + ` >> /tmp/` + item.Slug + `.log 2>&1` task.Log = "/tmp/" + item.Slug + ".log" if err := facades.Orm().Query().Create(&task); err != nil { - facades.Log().Error("[PHP-" + r.version + "] 创建卸载拓展任务失败:" + err.Error()) + facades.Log().Info("[PHP-" + r.version + "] 创建卸载拓展任务失败:" + err.Error()) return controllers.ErrorSystem(ctx) } diff --git a/app/http/controllers/plugins/php81_controller.go b/app/http/controllers/plugins/php81_controller.go index 790705df..26d1e115 100644 --- a/app/http/controllers/plugins/php81_controller.go +++ b/app/http/controllers/plugins/php81_controller.go @@ -158,7 +158,7 @@ func (r *Php81Controller) Load(ctx http.Context) http.Response { client := req.C().SetTimeout(10 * time.Second) resp, err := client.R().Get("http://127.0.0.1/phpfpm_status/" + r.version) if err != nil || !resp.IsSuccessState() { - facades.Log().Error("获取PHP-" + r.version + "运行状态失败") + facades.Log().Info("获取PHP-" + r.version + "运行状态失败") return controllers.Error(ctx, http.StatusInternalServerError, "[PHP-"+r.version+"] 获取运行状态失败") } @@ -259,7 +259,7 @@ func (r *Php81Controller) InstallExtension(ctx http.Context) http.Response { task.Shell = `bash '/www/panel/scripts/php_extensions/` + item.Slug + `.sh' install ` + r.version + ` >> /tmp/` + item.Slug + `.log 2>&1` task.Log = "/tmp/" + item.Slug + ".log" if err := facades.Orm().Query().Create(&task); err != nil { - facades.Log().Error("[PHP-" + r.version + "] 创建安装拓展任务失败:" + err.Error()) + facades.Log().Info("[PHP-" + r.version + "] 创建安装拓展任务失败:" + err.Error()) return controllers.ErrorSystem(ctx) } @@ -296,7 +296,7 @@ func (r *Php81Controller) UninstallExtension(ctx http.Context) http.Response { task.Shell = `bash '/www/panel/scripts/php_extensions/` + item.Slug + `.sh' uninstall ` + r.version + ` >> /tmp/` + item.Slug + `.log 2>&1` task.Log = "/tmp/" + item.Slug + ".log" if err := facades.Orm().Query().Create(&task); err != nil { - facades.Log().Error("[PHP-" + r.version + "] 创建卸载拓展任务失败:" + err.Error()) + facades.Log().Info("[PHP-" + r.version + "] 创建卸载拓展任务失败:" + err.Error()) return controllers.ErrorSystem(ctx) } diff --git a/app/http/controllers/plugins/php82_controller.go b/app/http/controllers/plugins/php82_controller.go index 04e8f834..0f635a52 100644 --- a/app/http/controllers/plugins/php82_controller.go +++ b/app/http/controllers/plugins/php82_controller.go @@ -158,7 +158,7 @@ func (r *Php82Controller) Load(ctx http.Context) http.Response { client := req.C().SetTimeout(10 * time.Second) resp, err := client.R().Get("http://127.0.0.1/phpfpm_status/" + r.version) if err != nil || !resp.IsSuccessState() { - facades.Log().Error("获取PHP-" + r.version + "运行状态失败") + facades.Log().Info("获取PHP-" + r.version + "运行状态失败") return controllers.Error(ctx, http.StatusInternalServerError, "[PHP-"+r.version+"] 获取运行状态失败") } @@ -259,7 +259,7 @@ func (r *Php82Controller) InstallExtension(ctx http.Context) http.Response { task.Shell = `bash '/www/panel/scripts/php_extensions/` + item.Slug + `.sh' install ` + r.version + ` >> /tmp/` + item.Slug + `.log 2>&1` task.Log = "/tmp/" + item.Slug + ".log" if err := facades.Orm().Query().Create(&task); err != nil { - facades.Log().Error("[PHP-" + r.version + "] 创建安装拓展任务失败:" + err.Error()) + facades.Log().Info("[PHP-" + r.version + "] 创建安装拓展任务失败:" + err.Error()) return controllers.ErrorSystem(ctx) } @@ -296,7 +296,7 @@ func (r *Php82Controller) UninstallExtension(ctx http.Context) http.Response { task.Shell = `bash '/www/panel/scripts/php_extensions/` + item.Slug + `.sh' uninstall ` + r.version + ` >> /tmp/` + item.Slug + `.log 2>&1` task.Log = "/tmp/" + item.Slug + ".log" if err := facades.Orm().Query().Create(&task); err != nil { - facades.Log().Error("[PHP-" + r.version + "] 创建卸载拓展任务失败:" + err.Error()) + facades.Log().Info("[PHP-" + r.version + "] 创建卸载拓展任务失败:" + err.Error()) return controllers.ErrorSystem(ctx) } diff --git a/app/http/controllers/plugins/phpmyadmin_controller.go b/app/http/controllers/plugins/phpmyadmin_controller.go index 524e3f1d..ade2cf57 100644 --- a/app/http/controllers/plugins/phpmyadmin_controller.go +++ b/app/http/controllers/plugins/phpmyadmin_controller.go @@ -6,6 +6,7 @@ import ( "strings" "github.com/goravel/framework/contracts/http" + "github.com/goravel/framework/facades" "github.com/spf13/cast" "panel/app/http/controllers" @@ -65,7 +66,13 @@ func (r *PhpMyAdminController) SetPort(ctx http.Context) http.Response { conf := tools.Read("/www/server/vhost/phpmyadmin.conf") conf = regexp.MustCompile(`listen\s+(\d+);`).ReplaceAllString(conf, "listen "+port+";") - tools.Write("/www/server/vhost/phpmyadmin.conf", conf, 0644) + err := tools.Write("/www/server/vhost/phpmyadmin.conf", conf, 0644) + if err != nil { + facades.Log().Request(ctx.Request()).Tags("插件", "phpMyAdmin").With(map[string]any{ + "error": err.Error(), + }).Info("修改 phpMyAdmin 端口失败") + return controllers.ErrorSystem(ctx) + } if tools.IsRHEL() { tools.Exec("firewall-cmd --zone=public --add-port=" + port + "/tcp --permanent") diff --git a/app/http/controllers/plugins/postgresql15_controller.go b/app/http/controllers/plugins/postgresql15_controller.go index 6f8a8c83..8c635070 100644 --- a/app/http/controllers/plugins/postgresql15_controller.go +++ b/app/http/controllers/plugins/postgresql15_controller.go @@ -168,7 +168,7 @@ func (r *Postgresql15Controller) SaveConfig(ctx http.Context) http.Response { return controllers.Error(ctx, http.StatusUnprocessableEntity, "配置不能为空") } - if !tools.Write("/www/server/postgresql/data/postgresql.conf", config, 0644) { + if err := tools.Write("/www/server/postgresql/data/postgresql.conf", config, 0644); err != nil { return controllers.Error(ctx, http.StatusInternalServerError, "写入PostgreSQL配置失败") } @@ -187,7 +187,7 @@ func (r *Postgresql15Controller) SaveUserConfig(ctx http.Context) http.Response return controllers.Error(ctx, http.StatusUnprocessableEntity, "配置不能为空") } - if !tools.Write("/www/server/postgresql/data/pg_hba.conf", config, 0644) { + if err := tools.Write("/www/server/postgresql/data/pg_hba.conf", config, 0644); err != nil { return controllers.Error(ctx, http.StatusInternalServerError, "写入PostgreSQL配置失败") } @@ -369,7 +369,7 @@ func (r *Postgresql15Controller) BackupList(ctx http.Context) http.Response { backupList, err := r.backup.PostgresqlList() if err != nil { - facades.Log().Error("[PostgreSQL] 获取备份列表失败:" + err.Error()) + facades.Log().Info("[PostgreSQL] 获取备份列表失败:" + err.Error()) return controllers.Error(ctx, http.StatusInternalServerError, "获取备份列表失败") } @@ -443,7 +443,7 @@ func (r *Postgresql15Controller) CreateBackup(ctx http.Context) http.Response { database := ctx.Request().Input("database") err = r.backup.PostgresqlBackup(database) if err != nil { - facades.Log().Error("[PostgreSQL] 创建备份失败:" + err.Error()) + facades.Log().Info("[PostgreSQL] 创建备份失败:" + err.Error()) return controllers.Error(ctx, http.StatusInternalServerError, "创建备份失败") } @@ -494,7 +494,7 @@ func (r *Postgresql15Controller) RestoreBackup(ctx http.Context) http.Response { err = r.backup.PostgresqlRestore(ctx.Request().Input("database"), ctx.Request().Input("backup")) if err != nil { - facades.Log().Error("[PostgreSQL] 还原失败:" + err.Error()) + facades.Log().Info("[PostgreSQL] 还原失败:" + err.Error()) return controllers.Error(ctx, http.StatusInternalServerError, "还原失败: "+err.Error()) } diff --git a/app/http/controllers/plugins/postgresql16_controller.go b/app/http/controllers/plugins/postgresql16_controller.go index 4611c246..17f108c3 100644 --- a/app/http/controllers/plugins/postgresql16_controller.go +++ b/app/http/controllers/plugins/postgresql16_controller.go @@ -168,7 +168,7 @@ func (r *Postgresql16Controller) SaveConfig(ctx http.Context) http.Response { return controllers.Error(ctx, http.StatusUnprocessableEntity, "配置不能为空") } - if !tools.Write("/www/server/postgresql/data/postgresql.conf", config, 0644) { + if err := tools.Write("/www/server/postgresql/data/postgresql.conf", config, 0644); err != nil { return controllers.Error(ctx, http.StatusInternalServerError, "写入PostgreSQL配置失败") } @@ -187,7 +187,7 @@ func (r *Postgresql16Controller) SaveUserConfig(ctx http.Context) http.Response return controllers.Error(ctx, http.StatusUnprocessableEntity, "配置不能为空") } - if !tools.Write("/www/server/postgresql/data/pg_hba.conf", config, 0644) { + if err := tools.Write("/www/server/postgresql/data/pg_hba.conf", config, 0644); err != nil { return controllers.Error(ctx, http.StatusInternalServerError, "写入PostgreSQL配置失败") } @@ -369,7 +369,7 @@ func (r *Postgresql16Controller) BackupList(ctx http.Context) http.Response { backupList, err := r.backup.PostgresqlList() if err != nil { - facades.Log().Error("[PostgreSQL] 获取备份列表失败:" + err.Error()) + facades.Log().Info("[PostgreSQL] 获取备份列表失败:" + err.Error()) return controllers.Error(ctx, http.StatusInternalServerError, "获取备份列表失败") } @@ -443,7 +443,7 @@ func (r *Postgresql16Controller) CreateBackup(ctx http.Context) http.Response { database := ctx.Request().Input("database") err = r.backup.PostgresqlBackup(database) if err != nil { - facades.Log().Error("[PostgreSQL] 创建备份失败:" + err.Error()) + facades.Log().Info("[PostgreSQL] 创建备份失败:" + err.Error()) return controllers.Error(ctx, http.StatusInternalServerError, "创建备份失败") } @@ -494,7 +494,7 @@ func (r *Postgresql16Controller) RestoreBackup(ctx http.Context) http.Response { err = r.backup.PostgresqlRestore(ctx.Request().Input("database"), ctx.Request().Input("backup")) if err != nil { - facades.Log().Error("[PostgreSQL] 还原失败:" + err.Error()) + facades.Log().Info("[PostgreSQL] 还原失败:" + err.Error()) return controllers.Error(ctx, http.StatusInternalServerError, "还原失败: "+err.Error()) } diff --git a/app/http/controllers/plugins/redis_controller.go b/app/http/controllers/plugins/redis_controller.go index 5aa75e47..196facd5 100644 --- a/app/http/controllers/plugins/redis_controller.go +++ b/app/http/controllers/plugins/redis_controller.go @@ -123,7 +123,7 @@ func (r *RedisController) SaveConfig(ctx http.Context) http.Response { return controllers.Error(ctx, http.StatusUnprocessableEntity, "配置不能为空") } - if !tools.Write("/www/server/redis/redis.conf", config, 0644) { + if err := tools.Write("/www/server/redis/redis.conf", config, 0644); err != nil { return controllers.Error(ctx, http.StatusInternalServerError, "写入Redis配置失败") } diff --git a/app/http/controllers/setting_controller.go b/app/http/controllers/setting_controller.go index 8f0b2ef3..f43007c3 100644 --- a/app/http/controllers/setting_controller.go +++ b/app/http/controllers/setting_controller.go @@ -36,7 +36,7 @@ func (r *SettingController) List(ctx http.Context) http.Response { var settings []models.Setting err := facades.Orm().Query().Get(&settings) if err != nil { - facades.Log().Error("[面板][SettingController] 查询设置列表失败 ", err) + facades.Log().Info("[面板][SettingController] 查询设置列表失败 ", err) return ErrorSystem(ctx) } @@ -49,7 +49,7 @@ func (r *SettingController) List(ctx http.Context) http.Response { var user models.User err = facades.Auth().User(ctx, &user) if err != nil { - facades.Log().Error("[面板][SettingController] 获取用户失败 ", err) + facades.Log().Info("[面板][SettingController] 获取用户失败 ", err) return ErrorSystem(ctx) } result.Username = user.Username @@ -83,7 +83,7 @@ func (r *SettingController) Update(ctx http.Context) http.Response { if err != nil { facades.Log().Request(ctx.Request()).With(map[string]any{ "error": err.Error(), - }).Tags("面板", "面板设置").Error("保存面板名称失败") + }).Tags("面板", "面板设置").Info("保存面板名称失败") return ErrorSystem(ctx) } @@ -94,7 +94,7 @@ func (r *SettingController) Update(ctx http.Context) http.Response { if err != nil { facades.Log().Request(ctx.Request()).With(map[string]any{ "error": err.Error(), - }).Tags("面板", "面板设置").Error("保存备份目录失败") + }).Tags("面板", "面板设置").Info("保存备份目录失败") return ErrorSystem(ctx) } if !tools.Exists(updateRequest.WebsitePath) { @@ -105,7 +105,7 @@ func (r *SettingController) Update(ctx http.Context) http.Response { if err != nil { facades.Log().Request(ctx.Request()).With(map[string]any{ "error": err.Error(), - }).Tags("面板", "面板设置").Error("保存建站目录失败") + }).Tags("面板", "面板设置").Info("保存建站目录失败") return ErrorSystem(ctx) } @@ -126,7 +126,7 @@ func (r *SettingController) Update(ctx http.Context) http.Response { if err = facades.Orm().Query().Save(&user); err != nil { facades.Log().Request(ctx.Request()).With(map[string]any{ "error": err.Error(), - }).Tags("面板", "面板设置").Error("保存用户信息失败") + }).Tags("面板", "面板设置").Info("保存用户信息失败") return ErrorSystem(ctx) } diff --git a/app/http/controllers/ssh_controller.go b/app/http/controllers/ssh_controller.go index 94941f17..3bb8de91 100644 --- a/app/http/controllers/ssh_controller.go +++ b/app/http/controllers/ssh_controller.go @@ -69,22 +69,22 @@ func (r *SshController) UpdateInfo(ctx http.Context) http.Response { password := ctx.Request().Input("password") err = r.setting.Set(models.SettingKeySshHost, host) if err != nil { - facades.Log().Error("[面板][SSH] 更新配置失败 ", err) + facades.Log().Info("[面板][SSH] 更新配置失败 ", err) return ErrorSystem(ctx) } err = r.setting.Set(models.SettingKeySshPort, port) if err != nil { - facades.Log().Error("[面板][SSH] 更新配置失败 ", err) + facades.Log().Info("[面板][SSH] 更新配置失败 ", err) return ErrorSystem(ctx) } err = r.setting.Set(models.SettingKeySshUser, user) if err != nil { - facades.Log().Error("[面板][SSH] 更新配置失败 ", err) + facades.Log().Info("[面板][SSH] 更新配置失败 ", err) return ErrorSystem(ctx) } err = r.setting.Set(models.SettingKeySshPassword, password) if err != nil { - facades.Log().Error("[面板][SSH] 更新配置失败 ", err) + facades.Log().Info("[面板][SSH] 更新配置失败 ", err) return ErrorSystem(ctx) } @@ -142,21 +142,21 @@ func (r *SshController) Session(ctx http.Context) http.Response { defer wg.Done() err := turn.LoopRead(logBuff, ctx2) if err != nil { - facades.Log().Error("[面板][SSH] 读取数据失败 ", err.Error()) + facades.Log().Info("[面板][SSH] 读取数据失败 ", err.Error()) } }() go func() { defer wg.Done() err := turn.SessionWait() if err != nil { - facades.Log().Error("[面板][SSH] 会话失败 ", err.Error()) + facades.Log().Info("[面板][SSH] 会话失败 ", err.Error()) } cancel() }() wg.Wait() }) if err != nil { - facades.Log().Error("[面板][SSH] 建立连接失败 ", err) + facades.Log().Info("[面板][SSH] 建立连接失败 ", err) return ErrorSystem(ctx) } diff --git a/app/http/controllers/task_controller.go b/app/http/controllers/task_controller.go index 193e3f62..7b37da52 100644 --- a/app/http/controllers/task_controller.go +++ b/app/http/controllers/task_controller.go @@ -40,7 +40,7 @@ func (r *TaskController) List(ctx http.Context) http.Response { if err != nil { facades.Log().Request(ctx.Request()).With(map[string]any{ "error": err.Error(), - }).Error("[面板][TaskController] 查询任务列表失败") + }).Info("[面板][TaskController] 查询任务列表失败") return ErrorSystem(ctx) } @@ -58,7 +58,7 @@ func (r *TaskController) Log(ctx http.Context) http.Response { facades.Log().Request(ctx.Request()).With(map[string]any{ "id": ctx.Request().QueryInt("id"), "error": err.Error(), - }).Error("[面板][TaskController] 查询任务失败") + }).Info("[面板][TaskController] 查询任务失败") return ErrorSystem(ctx) } @@ -75,7 +75,7 @@ func (r *TaskController) Delete(ctx http.Context) http.Response { facades.Log().With(map[string]any{ "id": ctx.Request().QueryInt("id"), "error": err.Error(), - }).Error("[面板][TaskController] 删除任务失败") + }).Info("[面板][TaskController] 删除任务失败") return ErrorSystem(ctx) } diff --git a/app/http/controllers/user_controller.go b/app/http/controllers/user_controller.go index b86931e9..9056f0dd 100644 --- a/app/http/controllers/user_controller.go +++ b/app/http/controllers/user_controller.go @@ -42,7 +42,7 @@ func (r *UserController) Login(ctx http.Context) http.Response { if err != nil { facades.Log().Request(ctx.Request()).With(map[string]any{ "error": err.Error(), - }).Tags("面板", "用户").Error("查询用户失败") + }).Tags("面板", "用户").Info("查询用户失败") return ErrorSystem(ctx) } @@ -55,7 +55,7 @@ func (r *UserController) Login(ctx http.Context) http.Response { if err != nil { facades.Log().Request(ctx.Request()).With(map[string]any{ "error": err.Error(), - }).Tags("面板", "用户").Error("更新密码失败") + }).Tags("面板", "用户").Info("更新密码失败") return ErrorSystem(ctx) } } @@ -64,7 +64,7 @@ func (r *UserController) Login(ctx http.Context) http.Response { if loginErr != nil { facades.Log().Request(ctx.Request()).With(map[string]any{ "error": err.Error(), - }).Tags("面板", "用户").Error("登录失败") + }).Tags("面板", "用户").Info("登录失败") return ErrorSystem(ctx) } @@ -89,7 +89,7 @@ func (r *UserController) Info(ctx http.Context) http.Response { if err != nil { facades.Log().Request(ctx.Request()).With(map[string]any{ "error": err.Error(), - }).Tags("面板", "用户").Error("获取用户信息失败") + }).Tags("面板", "用户").Info("获取用户信息失败") return ErrorSystem(ctx) } diff --git a/app/http/controllers/website_controller.go b/app/http/controllers/website_controller.go index a4f00fd1..749bfe7a 100644 --- a/app/http/controllers/website_controller.go +++ b/app/http/controllers/website_controller.go @@ -3,12 +3,14 @@ package controllers import ( "fmt" "regexp" - "strconv" "strings" "github.com/goravel/framework/contracts/http" "github.com/goravel/framework/facades" + commonrequests "panel/app/http/requests/common" + requests "panel/app/http/requests/website" + responses "panel/app/http/responses/website" "panel/app/models" "panel/app/services" "panel/pkg/tools" @@ -28,84 +30,133 @@ func NewWebsiteController() *WebsiteController { } } -// List 网站列表 +// List +// @Summary 获取网站列表 +// @Description 获取网站管理的网站列表 +// @Tags 网站管理 +// @Produce json +// @Security BearerToken +// @Param data body commonrequests.Paginate true "分页信息" +// @Success 200 {object} SuccessResponse{data=responses.List} +// @Failure 401 {object} ErrorResponse "登录已过期" +// @Failure 403 {object} ErrorResponse "插件需更新" +// @Failure 500 {object} ErrorResponse "系统内部错误" +// @Router /panel/website [get] func (c *WebsiteController) List(ctx http.Context) http.Response { - limit := ctx.Request().QueryInt("limit", 10) - page := ctx.Request().QueryInt("page", 1) + var paginateRequest commonrequests.Paginate + sanitize := Sanitize(ctx, &paginateRequest) + if sanitize != nil { + return sanitize + } - total, websites, err := c.website.List(page, limit) + total, websites, err := c.website.List(paginateRequest.Page, paginateRequest.Limit) if err != nil { - facades.Log().Error("[面板][WebsiteController] 获取网站列表失败 ", err) + facades.Log().Request(ctx.Request()).Tags("面板", "网站管理").With(map[string]any{ + "error": err.Error(), + }).Info("获取网站列表失败") return ErrorSystem(ctx) } - return Success(ctx, http.Json{ - "total": total, - "items": websites, + return Success(ctx, responses.List{ + Total: total, + Items: websites, }) } -// Add 添加网站 +// Add +// @Summary 添加网站 +// @Description 添加网站到网站管理 +// @Tags 网站管理 +// @Accept json +// @Produce json +// @Security BearerToken +// @Param data body requests.Add true "网站信息" +// @Success 200 {object} SuccessResponse +// @Failure 401 {object} ErrorResponse "登录已过期" +// @Failure 403 {object} ErrorResponse "插件需更新" +// @Failure 500 {object} ErrorResponse "系统内部错误" +// @Router /panel/website [post] func (c *WebsiteController) Add(ctx http.Context) http.Response { check := Check(ctx, "openresty") if check != nil { return check } - validator, err := ctx.Request().Validate(map[string]string{ - "name": "required|regex:^[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)*$|not_exists:websites,name", - "domains": "required|slice", - "ports": "required|slice", - "php": "required", - "db": "bool", - "db_type": "required_if:db,true", - "db_name": "required_if:db,true", - "db_user": "required_if:db,true", - "db_password": "required_if:db,true", - }) - if err != nil { - return Error(ctx, http.StatusUnprocessableEntity, err.Error()) - } - if validator.Fails() { - return Error(ctx, http.StatusUnprocessableEntity, validator.Errors().One()) + var addRequest requests.Add + sanitize := Sanitize(ctx, &addRequest) + if sanitize != nil { + return sanitize } - var website services.PanelWebsite - website.Name = ctx.Request().Input("name") - website.Domains = ctx.Request().InputArray("domains") - website.Ports = ctx.Request().InputArray("ports") - website.Php = ctx.Request().InputInt("php") - website.Db = ctx.Request().InputBool("db") - website.DbType = ctx.Request().Input("db_type") - website.DbName = ctx.Request().Input("db_name") - website.DbUser = ctx.Request().Input("db_user") - website.DbPassword = ctx.Request().Input("db_password") + website := services.PanelWebsite{ + Name: addRequest.Name, + Domains: addRequest.Domains, + Ports: addRequest.Ports, + Php: addRequest.Php, + Db: addRequest.Db, + DbType: addRequest.DbType, + DbName: addRequest.DbName, + DbUser: addRequest.DbUser, + DbPassword: addRequest.DbPassword, + } - newSite, err := c.website.Add(website) + _, err := c.website.Add(website) if err != nil { - facades.Log().Error("[面板][WebsiteController] 添加网站失败 ", err) + facades.Log().Request(ctx.Request()).Tags("面板", "网站管理").With(map[string]any{ + "error": err.Error(), + }).Info("添加网站失败") return ErrorSystem(ctx) } - return Success(ctx, newSite) + return Success(ctx, nil) } -// Delete 删除网站 +// Delete +// @Summary 删除网站 +// @Description 删除网站管理的网站 +// @Tags 网站管理 +// @Accept json +// @Produce json +// @Security BearerToken +// @Param id path int true "网站 ID" +// @Success 200 {object} SuccessResponse +// @Failure 401 {object} ErrorResponse "登录已过期" +// @Failure 403 {object} ErrorResponse "插件需更新" +// @Failure 500 {object} ErrorResponse "系统内部错误" +// @Router /panel/website/{id} [delete] func (c *WebsiteController) Delete(ctx http.Context) http.Response { check := Check(ctx, "openresty") if check != nil { return check } - id := ctx.Request().InputInt("id") - err := c.website.Delete(id) + + var idRequest requests.ID + sanitize := Sanitize(ctx, &idRequest) + if sanitize != nil { + return sanitize + } + + err := c.website.Delete(idRequest.ID) if err != nil { - facades.Log().Error("[面板][WebsiteController] 删除网站失败 ", err) + facades.Log().Request(ctx.Request()).Tags("面板", "网站管理").With(map[string]any{ + "id": idRequest.ID, + "error": err.Error(), + }).Info("删除网站失败") return Error(ctx, http.StatusInternalServerError, "删除网站失败: "+err.Error()) } return Success(ctx, nil) } -// GetDefaultConfig 获取默认配置 +// GetDefaultConfig +// @Summary 获取默认配置 +// @Description 获取默认首页和停止页配置 +// @Tags 网站管理 +// @Produce json +// @Security BearerToken +// @Success 200 {object} SuccessResponse{data=map[string]string} +// @Failure 401 {object} ErrorResponse "登录已过期" +// @Failure 403 {object} ErrorResponse "插件需更新" +// @Router /panel/website/defaultConfig [get] func (c *WebsiteController) GetDefaultConfig(ctx http.Context) http.Response { check := Check(ctx, "openresty") if check != nil { @@ -120,7 +171,19 @@ func (c *WebsiteController) GetDefaultConfig(ctx http.Context) http.Response { }) } -// SaveDefaultConfig 保存默认配置 +// SaveDefaultConfig +// @Summary 保存默认配置 +// @Description 保存默认首页和停止页配置 +// @Tags 网站管理 +// @Accept json +// @Produce json +// @Security BearerToken +// @Param data body map[string]string true "页面信息" +// @Success 200 {object} SuccessResponse +// @Failure 401 {object} ErrorResponse "登录已过期" +// @Failure 403 {object} ErrorResponse "插件需更新" +// @Failure 500 {object} ErrorResponse "系统内部错误" +// @Router /panel/website/defaultConfig [post] func (c *WebsiteController) SaveDefaultConfig(ctx http.Context) http.Response { check := Check(ctx, "openresty") if check != nil { @@ -129,347 +192,240 @@ func (c *WebsiteController) SaveDefaultConfig(ctx http.Context) http.Response { index := ctx.Request().Input("index") stop := ctx.Request().Input("stop") - if !tools.Write("/www/server/openresty/html/index.html", index, 0644) { - facades.Log().Error("[面板][WebsiteController] 保存默认配置失败") + if err := tools.Write("/www/server/openresty/html/index.html", index, 0644); err != nil { + facades.Log().Request(ctx.Request()).Tags("面板", "网站管理").With(map[string]any{ + "error": err.Error(), + }).Info("保存默认首页配置失败") return ErrorSystem(ctx) } - if !tools.Write("/www/server/openresty/html/stop.html", stop, 0644) { - facades.Log().Error("[面板][WebsiteController] 保存默认配置失败") + if err := tools.Write("/www/server/openresty/html/stop.html", stop, 0644); err != nil { + facades.Log().Request(ctx.Request()).Tags("面板", "网站管理").With(map[string]any{ + "error": err.Error(), + }).Info("保存默认停止页配置失败") return ErrorSystem(ctx) } return Success(ctx, nil) } -// GetConfig 获取配置 +// GetConfig +// @Summary 获取配置 +// @Description 获取网站的配置 +// @Tags 网站管理 +// @Accept json +// @Produce json +// @Security BearerToken +// @Param id path int true "网站 ID" +// @Success 200 {object} SuccessResponse{data=services.PanelWebsite} +// @Failure 401 {object} ErrorResponse "登录已过期" +// @Failure 500 {object} ErrorResponse "系统内部错误" +// @Router /panel/website/config/{id} [get] func (c *WebsiteController) GetConfig(ctx http.Context) http.Response { check := Check(ctx, "openresty") if check != nil { return check } - id := ctx.Request().InputInt("id") - if id == 0 { - return Error(ctx, http.StatusUnprocessableEntity, "参数错误") + + var idRequest requests.ID + sanitize := Sanitize(ctx, &idRequest) + if sanitize != nil { + return sanitize } - config, err := c.website.GetConfig(id) + config, err := c.website.GetConfig(idRequest.ID) if err != nil { - facades.Log().Error("[面板][WebsiteController] 获取网站配置失败 ", err) + facades.Log().Request(ctx.Request()).Tags("面板", "网站管理").With(map[string]any{ + "id": idRequest.ID, + "error": err.Error(), + }).Info("获取网站配置失败") return ErrorSystem(ctx) } return Success(ctx, config) } -// SaveConfig 保存配置 +// SaveConfig +// @Summary 保存配置 +// @Description 保存网站的配置 +// @Tags 网站管理 +// @Accept json +// @Produce json +// @Security BearerToken +// @Param id path int true "网站 ID" +// @Param data body requests.SaveConfig true "网站配置" +// @Success 200 {object} SuccessResponse +// @Failure 401 {object} ErrorResponse "登录已过期" +// @Failure 500 {object} ErrorResponse "系统内部错误" +// @Router /panel/website/config/{id} [post] func (c *WebsiteController) SaveConfig(ctx http.Context) http.Response { check := Check(ctx, "openresty") if check != nil { return check } - validator, err := ctx.Request().Validate(map[string]string{ - "domains": "required|slice", - "ports": "required|slice", - "hsts": "bool", - "ssl": "bool", - "http_redirect": "bool", - "open_basedir": "bool", - "waf": "bool", - "waf_cache": "required", - "waf_mode": "required", - "waf_cc_deny": "required", - "index": "required", - "path": "required", - "root": "required", - "raw": "required", - "php": "required", - "ssl_certificate": "required_if:ssl,true", - "ssl_certificate_key": "required_if:ssl,true", - }) + + var saveConfigRequest requests.SaveConfig + sanitize := Sanitize(ctx, &saveConfigRequest) + if sanitize != nil { + return sanitize + } + + err := c.website.SaveConfig(saveConfigRequest) if err != nil { - return Error(ctx, http.StatusUnprocessableEntity, err.Error()) + facades.Log().Request(ctx.Request()).Tags("面板", "网站管理").With(map[string]any{ + "error": err.Error(), + }).Info("保存网站配置失败") + return Error(ctx, http.StatusInternalServerError, "保存网站配置失败: "+err.Error()) } - if validator.Fails() { - return Error(ctx, http.StatusUnprocessableEntity, validator.Errors().One()) - } - - var website models.Website - if facades.Orm().Query().Where("id", ctx.Request().Input("id")).FirstOrFail(&website) != nil { - return Error(ctx, http.StatusUnprocessableEntity, "网站不存在") - } - - if !website.Status { - return Error(ctx, http.StatusUnprocessableEntity, "网站已停用,请先启用") - } - - // 原文 - raw := tools.Read("/www/server/vhost/" + website.Name + ".conf") - if strings.TrimSpace(raw) != strings.TrimSpace(ctx.Request().Input("raw")) { - tools.Write("/www/server/vhost/"+website.Name+".conf", ctx.Request().Input("raw"), 0644) - tools.Exec("systemctl reload openresty") - return Success(ctx, nil) - } - - // 目录 - path := ctx.Request().Input("path") - if !tools.Exists(path) { - return Error(ctx, http.StatusUnprocessableEntity, "网站目录不存在") - } - website.Path = path - - // 域名 - domain := "server_name" - domains := ctx.Request().InputArray("domains") - if len(domains) == 0 { - return Error(ctx, http.StatusUnprocessableEntity, "域名不能为空") - } - for _, v := range domains { - if v == "" { - continue - } - domain += " " + v - } - domain += ";" - domainConfigOld := tools.Cut(raw, "# server_name标记位开始", "# server_name标记位结束") - if len(strings.TrimSpace(domainConfigOld)) == 0 { - return Error(ctx, http.StatusUnprocessableEntity, "配置文件中缺少server_name标记位") - } - raw = strings.Replace(raw, domainConfigOld, "\n "+domain+"\n ", -1) - - // 端口 - var port strings.Builder - ports := ctx.Request().InputArray("ports") - if len(ports) == 0 { - return Error(ctx, http.StatusUnprocessableEntity, "端口不能为空") - } - for i, v := range ports { - if _, err := strconv.Atoi(v); err != nil && v != "443 ssl http2" { - return Error(ctx, http.StatusUnprocessableEntity, "端口格式错误") - } - if v == "443" && ctx.Request().InputBool("ssl") { - v = "443 ssl http2" - } - if i != len(ports)-1 { - port.WriteString(" listen " + v + ";\n") - } else { - port.WriteString(" listen " + v + ";") - } - } - portConfigOld := tools.Cut(raw, "# port标记位开始", "# port标记位结束") - if len(strings.TrimSpace(portConfigOld)) == 0 { - return Error(ctx, http.StatusUnprocessableEntity, "配置文件中缺少port标记位") - } - raw = strings.Replace(raw, portConfigOld, "\n"+port.String()+"\n ", -1) - - // 运行目录 - root := tools.Cut(raw, "# root标记位开始", "# root标记位结束") - if len(strings.TrimSpace(root)) == 0 { - return Error(ctx, http.StatusUnprocessableEntity, "配置文件中缺少root标记位") - } - match := regexp.MustCompile(`root\s+(.+);`).FindStringSubmatch(root) - if len(match) != 2 { - return Error(ctx, http.StatusUnprocessableEntity, "配置文件中root标记位格式错误") - } - rootNew := strings.Replace(root, match[1], ctx.Request().Input("root"), -1) - raw = strings.Replace(raw, root, rootNew, -1) - - // 默认文件 - index := tools.Cut(raw, "# index标记位开始", "# index标记位结束") - if len(strings.TrimSpace(index)) == 0 { - return Error(ctx, http.StatusUnprocessableEntity, "配置文件中缺少index标记位") - } - match = regexp.MustCompile(`index\s+(.+);`).FindStringSubmatch(index) - if len(match) != 2 { - return Error(ctx, http.StatusUnprocessableEntity, "配置文件中index标记位格式错误") - } - indexNew := strings.Replace(index, match[1], ctx.Request().Input("index"), -1) - raw = strings.Replace(raw, index, indexNew, -1) - - // 防跨站 - root = ctx.Request().Input("root") - if !strings.HasSuffix(root, "/") { - root += "/" - } - if ctx.Request().InputBool("open_basedir") { - tools.Write(root+".user.ini", "open_basedir="+path+":/tmp/", 0644) - } else { - if tools.Exists(root + ".user.ini") { - tools.Remove(root + ".user.ini") - } - } - - // WAF - waf := ctx.Request().InputBool("waf") - wafStr := "off" - if waf { - wafStr = "on" - } - wafMode := ctx.Request().Input("waf_mode", "DYNAMIC") - wafCcDeny := ctx.Request().Input("waf_cc_deny", "rate=1000r/m duration=60m") - wafCache := ctx.Request().Input("waf_cache", "capacity=50") - wafConfig := `# waf标记位开始 - waf ` + wafStr + `; - waf_rule_path /www/server/openresty/ngx_waf/assets/rules/; - waf_mode ` + wafMode + `; - waf_cc_deny ` + wafCcDeny + `; - waf_cache ` + wafCache + `; - ` - wafConfigOld := tools.Cut(raw, "# waf标记位开始", "# waf标记位结束") - if len(strings.TrimSpace(wafConfigOld)) != 0 { - raw = strings.Replace(raw, wafConfigOld, "", -1) - } - raw = strings.Replace(raw, "# waf标记位开始", wafConfig, -1) - - // SSL - ssl := ctx.Request().InputBool("ssl") - website.Ssl = ssl - tools.Write("/www/server/vhost/ssl/"+website.Name+".pem", ctx.Request().Input("ssl_certificate"), 0644) - tools.Write("/www/server/vhost/ssl/"+website.Name+".key", ctx.Request().Input("ssl_certificate_key"), 0644) - if ssl { - sslConfig := `# ssl标记位开始 - ssl_certificate /www/server/vhost/ssl/` + website.Name + `.pem; - ssl_certificate_key /www/server/vhost/ssl/` + website.Name + `.key; - ssl_session_timeout 1d; - ssl_session_cache shared:SSL:10m; - ssl_session_tickets off; - ssl_protocols TLSv1.2 TLSv1.3; - ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; - ssl_prefer_server_ciphers off; - ` - if ctx.Request().InputBool("http_redirect") { - sslConfig += `# http重定向标记位开始 - if ($server_port !~ 443){ - return 301 https://$host$request_uri; - } - error_page 497 https://$host$request_uri; - # http重定向标记位结束 - ` - } - if ctx.Request().InputBool("hsts") { - sslConfig += `# hsts标记位开始 - add_header Strict-Transport-Security "max-age=63072000" always; - # hsts标记位结束 - ` - } - sslConfigOld := tools.Cut(raw, "# ssl标记位开始", "# ssl标记位结束") - if len(strings.TrimSpace(sslConfigOld)) != 0 { - raw = strings.Replace(raw, sslConfigOld, "", -1) - } - raw = strings.Replace(raw, "# ssl标记位开始", sslConfig, -1) - } else { - sslConfigOld := tools.Cut(raw, "# ssl标记位开始", "# ssl标记位结束") - if len(strings.TrimSpace(sslConfigOld)) != 0 { - raw = strings.Replace(raw, sslConfigOld, "\n ", -1) - } - } - - if website.Php != ctx.Request().InputInt("php") { - website.Php = ctx.Request().InputInt("php") - phpConfigOld := tools.Cut(raw, "# php标记位开始", "# php标记位结束") - phpConfig := ` - include enable-php-` + strconv.Itoa(website.Php) + `.conf; - ` - if len(strings.TrimSpace(phpConfigOld)) != 0 { - raw = strings.Replace(raw, phpConfigOld, phpConfig, -1) - } - } - - err = facades.Orm().Query().Save(&website) - if err != nil { - facades.Log().Error("[面板][WebsiteController] 保存网站配置失败 ", err) - return ErrorSystem(ctx) - } - - tools.Write("/www/server/vhost/"+website.Name+".conf", raw, 0644) - tools.Write("/www/server/vhost/rewrite/"+website.Name+".conf", ctx.Request().Input("rewrite"), 0644) - tools.Exec("systemctl reload openresty") return Success(ctx, nil) } -// ClearLog 清空日志 +// ClearLog +// @Summary 清空日志 +// @Description 清空网站的日志 +// @Tags 网站管理 +// @Accept json +// @Produce json +// @Security BearerToken +// @Param id path int true "网站 ID" +// @Success 200 {object} SuccessResponse +// @Failure 401 {object} ErrorResponse "登录已过期" +// @Failure 500 {object} ErrorResponse "系统内部错误" +// @Router /panel/website/log/{id} [delete] func (c *WebsiteController) ClearLog(ctx http.Context) http.Response { check := Check(ctx, "openresty") if check != nil { return check } - id := ctx.Request().InputInt("id") - if id == 0 { - return Error(ctx, http.StatusUnprocessableEntity, "参数错误") + + var idRequest requests.ID + sanitize := Sanitize(ctx, &idRequest) + if sanitize != nil { + return sanitize } website := models.Website{} - err := facades.Orm().Query().Where("id", id).Get(&website) + err := facades.Orm().Query().Where("id", idRequest.ID).Get(&website) if err != nil { - facades.Log().Error("[面板][WebsiteController] 获取网站信息失败 ", err) return ErrorSystem(ctx) } tools.Remove("/www/wwwlogs/" + website.Name + ".log") - return Success(ctx, nil) } -// UpdateRemark 更新备注 +// UpdateRemark +// @Summary 更新备注 +// @Description 更新网站的备注 +// @Tags 网站管理 +// @Accept json +// @Produce json +// @Security BearerToken +// @Param id path int true "网站 ID" +// @Success 200 {object} SuccessResponse +// @Failure 401 {object} ErrorResponse "登录已过期" +// @Failure 500 {object} ErrorResponse "系统内部错误" +// @Router /panel/website/updateRemark/{id} [post] func (c *WebsiteController) UpdateRemark(ctx http.Context) http.Response { - id := ctx.Request().InputInt("id") - if id == 0 { - return Error(ctx, http.StatusUnprocessableEntity, "参数错误") + var idRequest requests.ID + sanitize := Sanitize(ctx, &idRequest) + if sanitize != nil { + return sanitize } website := models.Website{} - err := facades.Orm().Query().Where("id", id).Get(&website) + err := facades.Orm().Query().Where("id", idRequest.ID).Get(&website) if err != nil { - facades.Log().Error("[面板][WebsiteController] 获取网站信息失败 ", err) return ErrorSystem(ctx) } website.Remark = ctx.Request().Input("remark") - err = facades.Orm().Query().Save(&website) - if err != nil { - facades.Log().Error("[面板][WebsiteController] 保存网站备注失败 ", err) + if err = facades.Orm().Query().Save(&website); err != nil { + facades.Log().Request(ctx.Request()).Tags("面板", "网站管理").With(map[string]any{ + "id": idRequest.ID, + "error": err.Error(), + }).Info("更新网站备注失败") return ErrorSystem(ctx) } return Success(ctx, nil) } -// BackupList 备份列表 +// BackupList +// @Summary 获取备份列表 +// @Description 获取网站的备份列表 +// @Tags 网站管理 +// @Produce json +// @Security BearerToken +// @Success 200 {object} SuccessResponse{data=[]services.BackupFile} +// @Failure 401 {object} ErrorResponse "登录已过期" +// @Failure 500 {object} ErrorResponse "系统内部错误" +// @Router /panel/website/backupList [get] func (c *WebsiteController) BackupList(ctx http.Context) http.Response { backupList, err := c.backup.WebsiteList() if err != nil { - facades.Log().Error("[面板][WebsiteController] 获取网站备份列表失败 ", err) + facades.Log().Request(ctx.Request()).Tags("面板", "网站管理").With(map[string]any{ + "error": err.Error(), + }).Info("获取备份列表失败") return ErrorSystem(ctx) } return Success(ctx, backupList) } -// CreateBackup 创建备份 +// CreateBackup +// @Summary 创建备份 +// @Description 创建网站的备份 +// @Tags 网站管理 +// @Accept json +// @Produce json +// @Security BearerToken +// @Param data body requests.ID true "网站 ID" +// @Success 200 {object} SuccessResponse +// @Failure 401 {object} ErrorResponse "登录已过期" +// @Failure 500 {object} ErrorResponse "系统内部错误" +// @Router /panel/website/createBackup [post] func (c *WebsiteController) CreateBackup(ctx http.Context) http.Response { - id := ctx.Request().InputInt("id") - if id == 0 { - return Error(ctx, http.StatusUnprocessableEntity, "参数错误") + var idRequest requests.ID + sanitize := Sanitize(ctx, &idRequest) + if sanitize != nil { + return sanitize } website := models.Website{} - err := facades.Orm().Query().Where("id", id).Get(&website) - if err != nil { - facades.Log().Error("[面板][WebsiteController] 获取网站信息失败 ", err) - return Error(ctx, http.StatusInternalServerError, "获取网站信息失败: "+err.Error()) + if err := facades.Orm().Query().Where("id", idRequest.ID).Get(&website); err != nil { + facades.Log().Request(ctx.Request()).Tags("面板", "网站管理").With(map[string]any{ + "id": idRequest.ID, + "error": err.Error(), + }).Info("获取网站信息失败") + return ErrorSystem(ctx) } - err = c.backup.WebSiteBackup(website) - if err != nil { - facades.Log().Error("[面板][WebsiteController] 备份网站失败 ", err) + if err := c.backup.WebSiteBackup(website); err != nil { + facades.Log().Request(ctx.Request()).Tags("面板", "网站管理").With(map[string]any{ + "id": idRequest.ID, + "error": err.Error(), + }).Info("备份网站失败") return Error(ctx, http.StatusInternalServerError, "备份网站失败: "+err.Error()) } return Success(ctx, nil) } -// UploadBackup 上传备份 +// UploadBackup +// @Summary 上传备份 +// @Description 上传网站的备份 +// @Tags 网站管理 +// @Accept json +// @Produce json +// @Security BearerToken +// @Param file formData file true "备份文件" +// @Success 200 {object} SuccessResponse +// @Failure 401 {object} ErrorResponse "登录已过期" +// @Failure 422 {object} ErrorResponse "上传文件失败" +// @Failure 500 {object} ErrorResponse "系统内部错误" +// @Router /panel/website/uploadBackup [post] func (c *WebsiteController) UploadBackup(ctx http.Context) http.Response { file, err := ctx.Request().File("file") if err != nil { @@ -484,44 +440,70 @@ func (c *WebsiteController) UploadBackup(ctx http.Context) http.Response { name := file.GetClientOriginalName() _, err = file.StoreAs(backupPath, name) if err != nil { - return Error(ctx, http.StatusUnprocessableEntity, "上传文件失败") + facades.Log().Request(ctx.Request()).Tags("面板", "网站管理").With(map[string]any{ + "error": err.Error(), + }).Info("上传备份失败") + return ErrorSystem(ctx) } - return Success(ctx, "上传文件成功") + return Success(ctx, nil) } -// RestoreBackup 还原备份 +// RestoreBackup +// @Summary 还原备份 +// @Description 还原网站的备份 +// @Tags 网站管理 +// @Accept json +// @Produce json +// @Security BearerToken +// @Param data body requests.RestoreBackup true "备份信息" +// @Success 200 {object} SuccessResponse +// @Failure 401 {object} ErrorResponse "登录已过期" +// @Failure 422 {object} ErrorResponse "参数错误" +// @Failure 500 {object} ErrorResponse "系统内部错误" +// @Router /panel/website/restoreBackup [post] func (c *WebsiteController) RestoreBackup(ctx http.Context) http.Response { - id := ctx.Request().InputInt("id") - if id == 0 { - return Error(ctx, http.StatusUnprocessableEntity, "参数错误") - } - fileName := ctx.Request().Input("name") - if len(fileName) == 0 { - return Error(ctx, http.StatusUnprocessableEntity, "参数错误") + var restoreBackupRequest requests.RestoreBackup + sanitize := Sanitize(ctx, &restoreBackupRequest) + if sanitize != nil { + return sanitize } website := models.Website{} - err := facades.Orm().Query().Where("id", id).Get(&website) - if err != nil { - facades.Log().Error("[面板][WebsiteController] 获取网站信息失败 ", err) - return Error(ctx, http.StatusInternalServerError, "获取网站信息失败: "+err.Error()) + if err := facades.Orm().Query().Where("id", restoreBackupRequest.ID).Get(&website); err != nil { + return ErrorSystem(ctx) } - err = c.backup.WebsiteRestore(website, fileName) - if err != nil { - facades.Log().Error("[面板][WebsiteController] 还原网站失败 ", err) + if err := c.backup.WebsiteRestore(website, restoreBackupRequest.Name); err != nil { + facades.Log().Request(ctx.Request()).Tags("面板", "网站管理").With(map[string]any{ + "id": restoreBackupRequest.ID, + "file": restoreBackupRequest.Name, + "error": err.Error(), + }).Info("还原网站失败") return Error(ctx, http.StatusInternalServerError, "还原网站失败: "+err.Error()) } return Success(ctx, nil) } -// DeleteBackup 删除备份 +// DeleteBackup +// @Summary 删除备份 +// @Description 删除网站的备份 +// @Tags 网站管理 +// @Accept json +// @Produce json +// @Security BearerToken +// @Param data body requests.DeleteBackup true "备份信息" +// @Success 200 {object} SuccessResponse +// @Failure 401 {object} ErrorResponse "登录已过期" +// @Failure 422 {object} ErrorResponse "参数错误" +// @Failure 500 {object} ErrorResponse "系统内部错误" +// @Router /panel/website/deleteBackup [delete] func (c *WebsiteController) DeleteBackup(ctx http.Context) http.Response { - fileName := ctx.Request().Input("name") - if len(fileName) == 0 { - return Error(ctx, http.StatusUnprocessableEntity, "参数错误") + var deleteBackupRequest requests.DeleteBackup + sanitize := Sanitize(ctx, &deleteBackupRequest) + if sanitize != nil { + return sanitize } backupPath := c.setting.Get(models.SettingKeyBackupPath) + "/website" @@ -529,34 +511,50 @@ func (c *WebsiteController) DeleteBackup(ctx http.Context) http.Response { tools.Mkdir(backupPath, 0644) } - if !tools.Remove(backupPath + "/" + fileName) { + if !tools.Remove(backupPath + "/" + deleteBackupRequest.Name) { return Error(ctx, http.StatusInternalServerError, "删除备份失败") } return Success(ctx, nil) } -// ResetConfig 重置配置 +// ResetConfig +// @Summary 重置配置 +// @Description 重置网站的配置 +// @Tags 网站管理 +// @Accept json +// @Produce json +// @Security BearerToken +// @Param data body requests.ID true "网站 ID" +// @Success 200 {object} SuccessResponse +// @Failure 401 {object} ErrorResponse "登录已过期" +// @Failure 422 {object} ErrorResponse "参数错误" +// @Failure 500 {object} ErrorResponse "系统内部错误" +// @Router /panel/website/resetConfig [post] func (c *WebsiteController) ResetConfig(ctx http.Context) http.Response { check := Check(ctx, "openresty") if check != nil { return check } - id := ctx.Request().InputInt("id") - if id == 0 { - return Error(ctx, http.StatusUnprocessableEntity, "参数错误") + + var idRequest requests.ID + sanitize := Sanitize(ctx, &idRequest) + if sanitize != nil { + return sanitize } website := models.Website{} - if err := facades.Orm().Query().Where("id", id).Get(&website); err != nil { - facades.Log().Error("[面板][WebsiteController] 获取网站信息失败 ", err) + if err := facades.Orm().Query().Where("id", idRequest.ID).Get(&website); err != nil { return ErrorSystem(ctx) } website.Status = true website.Ssl = false if err := facades.Orm().Query().Save(&website); err != nil { - facades.Log().Error("[面板][WebsiteController] 保存网站配置失败 ", err) + facades.Log().Request(ctx.Request()).Tags("面板", "网站管理").With(map[string]any{ + "id": idRequest.ID, + "error": err.Error(), + }).Info("保存网站配置失败") return ErrorSystem(ctx) } @@ -618,34 +616,51 @@ server } `, website.Path, website.Php, website.Name, website.Name, website.Name) - - tools.Write("/www/server/vhost/"+website.Name+".conf", raw, 0644) - tools.Write("/www/server/vhost/rewrite"+website.Name+".conf", "", 0644) + if err := tools.Write("/www/server/vhost/"+website.Name+".conf", raw, 0644); err != nil { + return nil + } + if err := tools.Write("/www/server/vhost/rewrite"+website.Name+".conf", "", 0644); err != nil { + return nil + } tools.Exec("systemctl reload openresty") return Success(ctx, nil) } -// Status 网站状态 +// Status +// @Summary 状态 +// @Description 启用或停用网站 +// @Tags 网站管理 +// @Accept json +// @Produce json +// @Security BearerToken +// @Param id path int true "网站 ID" +// @Success 200 {object} SuccessResponse +// @Failure 401 {object} ErrorResponse "登录已过期" +// @Failure 422 {object} ErrorResponse "参数错误" +// @Failure 500 {object} ErrorResponse "系统内部错误" +// @Router /panel/website/status/{id} [post] func (c *WebsiteController) Status(ctx http.Context) http.Response { check := Check(ctx, "openresty") if check != nil { return check } - id := ctx.Request().InputInt("id") - if id == 0 { - return Error(ctx, http.StatusUnprocessableEntity, "参数错误") + + var idRequest requests.ID + sanitize := Sanitize(ctx, &idRequest) + if sanitize != nil { + return sanitize } website := models.Website{} - if err := facades.Orm().Query().Where("id", id).Get(&website); err != nil { - facades.Log().Error("[面板][WebsiteController] 获取网站信息失败 ", err) + if err := facades.Orm().Query().Where("id", idRequest.ID).Get(&website); err != nil { + facades.Log().Info("[面板][WebsiteController] 获取网站信息失败 ", err) return ErrorSystem(ctx) } website.Status = ctx.Request().InputBool("status") if err := facades.Orm().Query().Save(&website); err != nil { - facades.Log().Error("[面板][WebsiteController] 保存网站配置失败 ", err) + facades.Log().Info("[面板][WebsiteController] 保存网站配置失败 ", err) return ErrorSystem(ctx) } @@ -675,7 +690,9 @@ func (c *WebsiteController) Status(ctx http.Context) http.Response { } } - tools.Write("/www/server/vhost/"+website.Name+".conf", raw, 0644) + if err := tools.Write("/www/server/vhost/"+website.Name+".conf", raw, 0644); err != nil { + return ErrorSystem(ctx) + } tools.Exec("systemctl reload openresty") return Success(ctx, nil) diff --git a/app/http/requests/website/add.go b/app/http/requests/website/add.go new file mode 100644 index 00000000..0ec9bfc1 --- /dev/null +++ b/app/http/requests/website/add.go @@ -0,0 +1,48 @@ +package requests + +import ( + "github.com/goravel/framework/contracts/http" + "github.com/goravel/framework/contracts/validation" +) + +type Add struct { + Name string `form:"name" json:"name"` + Domains []string `form:"domains" json:"domains"` + Ports []string `form:"ports" json:"ports"` + Php int `form:"php" json:"php"` + Db bool `form:"db" json:"db"` + DbType string `form:"db_type" json:"db_type"` + DbName string `form:"db_name" json:"db_name"` + DbUser string `form:"db_user" json:"db_user"` + DbPassword string `form:"db_password" json:"db_password"` +} + +func (r *Add) Authorize(ctx http.Context) error { + return nil +} + +func (r *Add) Rules(ctx http.Context) map[string]string { + return map[string]string{ + "name": "required|regex:^[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)*$|not_exists:websites,name", + "domains": "required|slice", + "ports": "required|slice", + "php": "required", + "db": "bool", + "db_type": "required_if:db,true|in:mysql,postgresql", + "db_name": "required_if:db,true|regex:^[a-zA-Z0-9_-]+$", + "db_user": "required_if:db,true|regex:^[a-zA-Z0-9_-]+$", + "db_password": "required_if:db,true|min_len:8", + } +} + +func (r *Add) Messages(ctx http.Context) map[string]string { + return map[string]string{} +} + +func (r *Add) Attributes(ctx http.Context) map[string]string { + return map[string]string{} +} + +func (r *Add) PrepareForValidation(ctx http.Context, data validation.Data) error { + return nil +} diff --git a/app/http/requests/website/delete_backup.go b/app/http/requests/website/delete_backup.go new file mode 100644 index 00000000..dc926461 --- /dev/null +++ b/app/http/requests/website/delete_backup.go @@ -0,0 +1,32 @@ +package requests + +import ( + "github.com/goravel/framework/contracts/http" + "github.com/goravel/framework/contracts/validation" +) + +type DeleteBackup struct { + Name string `form:"name" json:"name"` +} + +func (r *DeleteBackup) Authorize(ctx http.Context) error { + return nil +} + +func (r *DeleteBackup) Rules(ctx http.Context) map[string]string { + return map[string]string{ + "name": "required|string", + } +} + +func (r *DeleteBackup) Messages(ctx http.Context) map[string]string { + return map[string]string{} +} + +func (r *DeleteBackup) Attributes(ctx http.Context) map[string]string { + return map[string]string{} +} + +func (r *DeleteBackup) PrepareForValidation(ctx http.Context, data validation.Data) error { + return nil +} diff --git a/app/http/requests/website/id.go b/app/http/requests/website/id.go new file mode 100644 index 00000000..68b29ebd --- /dev/null +++ b/app/http/requests/website/id.go @@ -0,0 +1,32 @@ +package requests + +import ( + "github.com/goravel/framework/contracts/http" + "github.com/goravel/framework/contracts/validation" +) + +type ID struct { + ID uint `form:"id" json:"id" filter:"uint"` +} + +func (r *ID) Authorize(ctx http.Context) error { + return nil +} + +func (r *ID) Rules(ctx http.Context) map[string]string { + return map[string]string{ + "id": "required|exists:websites,id", + } +} + +func (r *ID) Messages(ctx http.Context) map[string]string { + return map[string]string{} +} + +func (r *ID) Attributes(ctx http.Context) map[string]string { + return map[string]string{} +} + +func (r *ID) PrepareForValidation(ctx http.Context, data validation.Data) error { + return nil +} diff --git a/app/http/requests/website/restore_backup.go b/app/http/requests/website/restore_backup.go new file mode 100644 index 00000000..420afb8f --- /dev/null +++ b/app/http/requests/website/restore_backup.go @@ -0,0 +1,34 @@ +package requests + +import ( + "github.com/goravel/framework/contracts/http" + "github.com/goravel/framework/contracts/validation" +) + +type RestoreBackup struct { + ID uint `form:"id" json:"id" filter:"uint"` + Name string `form:"name" json:"name"` +} + +func (r *RestoreBackup) Authorize(ctx http.Context) error { + return nil +} + +func (r *RestoreBackup) Rules(ctx http.Context) map[string]string { + return map[string]string{ + "id": "required|exists:websites,id", + "name": "required|string", + } +} + +func (r *RestoreBackup) Messages(ctx http.Context) map[string]string { + return map[string]string{} +} + +func (r *RestoreBackup) Attributes(ctx http.Context) map[string]string { + return map[string]string{} +} + +func (r *RestoreBackup) PrepareForValidation(ctx http.Context, data validation.Data) error { + return nil +} diff --git a/app/http/requests/website/save_config.go b/app/http/requests/website/save_config.go new file mode 100644 index 00000000..e33e8a4a --- /dev/null +++ b/app/http/requests/website/save_config.go @@ -0,0 +1,87 @@ +package requests + +import ( + "github.com/goravel/framework/contracts/http" + "github.com/goravel/framework/contracts/validation" +) + +type SaveConfig struct { + ID uint `form:"id" json:"id" filter:"uint"` + Domains []string `form:"domains" json:"domains"` + Ports []string `form:"ports" json:"ports"` + Hsts bool `form:"hsts" json:"hsts"` + Ssl bool `form:"ssl" json:"ssl"` + HttpRedirect bool `form:"http_redirect" json:"http_redirect"` + OpenBasedir bool `form:"open_basedir" json:"open_basedir"` + Waf bool `form:"waf" json:"waf"` + WafCache string `form:"waf_cache" json:"waf_cache"` + WafMode string `form:"waf_mode" json:"waf_mode"` + WafCcDeny string `form:"waf_cc_deny" json:"waf_cc_deny"` + Index string `form:"index" json:"index"` + Path string `form:"path" json:"path"` + Root string `form:"root" json:"root"` + Raw string `form:"raw" json:"raw"` + Rewrite string `form:"rewrite" json:"rewrite"` + Php int `form:"php" json:"php" filter:"uint"` + SslCertificate string `form:"ssl_certificate" json:"ssl_certificate"` + SslCertificateKey string `form:"ssl_certificate_key" json:"ssl_certificate_key"` +} + +func (r *SaveConfig) Authorize(ctx http.Context) error { + return nil +} + +func (r *SaveConfig) Rules(ctx http.Context) map[string]string { + return map[string]string{ + "id": "required|exists:websites,id", + "domains": "required|slice", + "ports": "required|slice", + "hsts": "required|bool", + "ssl": "required|bool", + "http_redirect": "required|bool", + "open_basedir": "required|bool", + "waf": "required|bool", + "waf_cache": "required|string", + "waf_mode": "required|string", + "waf_cc_deny": "required|string", + "index": "required|string", + "path": "required|string", + "root": "required|string", + "raw": "required|string", + "rewrite": "string", + "php": "required|uint", + "ssl_certificate": "required_if:ssl,true", + "ssl_certificate_key": "required_if:ssl,true", + } +} + +func (r *SaveConfig) Messages(ctx http.Context) map[string]string { + return map[string]string{} +} + +func (r *SaveConfig) Attributes(ctx http.Context) map[string]string { + return map[string]string{} +} + +func (r *SaveConfig) PrepareForValidation(ctx http.Context, data validation.Data) error { + _, exist := data.Get("waf_mode") + if !exist { + if err := data.Set("waf_mode", "DYNAMIC"); err != nil { + return err + } + } + _, exist = data.Get("waf_cc_deny") + if !exist { + if err := data.Set("waf_cc_deny", "rate=1000r/m duration=60m"); err != nil { + return err + } + } + _, exist = data.Get("waf_cache") + if !exist { + if err := data.Set("waf_cache", "capacity=50"); err != nil { + return err + } + } + + return nil +} diff --git a/app/http/responses/website/list.go b/app/http/responses/website/list.go new file mode 100644 index 00000000..a91a8a89 --- /dev/null +++ b/app/http/responses/website/list.go @@ -0,0 +1,8 @@ +package responses + +import "panel/app/models" + +type List struct { + Total int64 `json:"total"` + Items []models.Website `json:"items"` +} diff --git a/app/jobs/process_task.go b/app/jobs/process_task.go index 22679f01..dffc69a8 100644 --- a/app/jobs/process_task.go +++ b/app/jobs/process_task.go @@ -22,7 +22,7 @@ func (receiver *ProcessTask) Signature() string { func (receiver *ProcessTask) Handle(args ...any) error { taskID, ok := args[0].(uint) if !ok { - facades.Log().Error("[面板][ProcessTask] 任务ID参数错误") + facades.Log().Info("[面板][ProcessTask] 任务ID参数错误") return nil } @@ -35,13 +35,13 @@ func (receiver *ProcessTask) Handle(args ...any) error { var task models.Task if err := facades.Orm().Query().Where("id = ?", taskID).Get(&task); err != nil { - facades.Log().Errorf("[面板][ProcessTask] 获取任务%d失败: %s", taskID, err.Error()) + facades.Log().Infof("[面板][ProcessTask] 获取任务%d失败: %s", taskID, err.Error()) return nil } task.Status = models.TaskStatusRunning if err := facades.Orm().Query().Save(&task); err != nil { - facades.Log().Errorf("[面板][ProcessTask] 更新任务%d失败: %s", taskID, err.Error()) + facades.Log().Infof("[面板][ProcessTask] 更新任务%d失败: %s", taskID, err.Error()) return nil } @@ -51,16 +51,16 @@ func (receiver *ProcessTask) Handle(args ...any) error { if err != nil { task.Status = models.TaskStatusFailed if err := facades.Orm().Query().Save(&task); err != nil { - facades.Log().Errorf("[面板][ProcessTask] 更新任务%d失败: %s", taskID, err.Error()) + facades.Log().Infof("[面板][ProcessTask] 更新任务%d失败: %s", taskID, err.Error()) return nil } - facades.Log().Errorf("[面板][ProcessTask] 任务%d执行失败: %s", taskID, err.Error()) + facades.Log().Infof("[面板][ProcessTask] 任务%d执行失败: %s", taskID, err.Error()) return nil } task.Status = models.TaskStatusSuccess if err := facades.Orm().Query().Save(&task); err != nil { - facades.Log().Errorf("[面板][ProcessTask] 更新任务%d失败: %s", taskID, err.Error()) + facades.Log().Infof("[面板][ProcessTask] 更新任务%d失败: %s", taskID, err.Error()) return nil } @@ -72,7 +72,7 @@ func (receiver *ProcessTask) Handle(args ...any) error { func haveRunningTask() bool { var task models.Task if err := facades.Orm().Query().Where("status = ?", models.TaskStatusRunning).Get(&task); err != nil { - facades.Log().Error("[面板][ProcessTask] 获取任务失败: " + err.Error()) + facades.Log().Info("[面板][ProcessTask] 获取任务失败: " + err.Error()) return true } diff --git a/app/providers/validation_service_provider.go b/app/providers/validation_service_provider.go index 20878e26..43b11d3b 100644 --- a/app/providers/validation_service_provider.go +++ b/app/providers/validation_service_provider.go @@ -17,7 +17,7 @@ func (receiver *ValidationServiceProvider) Register(app foundation.Application) func (receiver *ValidationServiceProvider) Boot(app foundation.Application) { if err := facades.Validation().AddRules(receiver.rules()); err != nil { - facades.Log().Errorf("add rules error: %+v", err) + facades.Log().Infof("add rules error: %+v", err) } } diff --git a/app/services/task.go b/app/services/task.go index bc64c878..06673435 100644 --- a/app/services/task.go +++ b/app/services/task.go @@ -24,7 +24,7 @@ func (r *TaskImpl) Process(taskID uint) { {Type: "uint", Value: taskID}, }).Dispatch() if err != nil { - facades.Log().Error("[面板][TaskService] 运行任务失败: " + err.Error()) + facades.Log().Info("[面板][TaskService] 运行任务失败: " + err.Error()) return } }() diff --git a/app/services/website.go b/app/services/website.go index 572ae476..134a09ed 100644 --- a/app/services/website.go +++ b/app/services/website.go @@ -12,6 +12,7 @@ import ( "github.com/goravel/framework/facades" "golang.org/x/exp/slices" + requests "panel/app/http/requests/website" "panel/app/models" "panel/pkg/tools" @@ -20,8 +21,9 @@ import ( type Website interface { List(page int, limit int) (int64, []models.Website, error) Add(website PanelWebsite) (models.Website, error) - Delete(id int) error - GetConfig(id int) (WebsiteSetting, error) + SaveConfig(config requests.SaveConfig) error + Delete(id uint) error + GetConfig(id uint) (WebsiteSetting, error) GetConfigByName(name string) (WebsiteSetting, error) } @@ -292,8 +294,208 @@ server return w, nil } +// SaveConfig 保存网站配置 +func (r *WebsiteImpl) SaveConfig(config requests.SaveConfig) error { + var website models.Website + if err := facades.Orm().Query().Where("id", config.ID).First(&website); err != nil { + return err + } + + if !website.Status { + return errors.New("网站已停用,请先启用") + } + + // 原文 + raw := tools.Read("/www/server/vhost/" + website.Name + ".conf") + if strings.TrimSpace(raw) != strings.TrimSpace(config.Raw) { + err := tools.Write("/www/server/vhost/"+website.Name+".conf", config.Raw, 0644) + if err != nil { + return err + } + tools.Exec("systemctl reload openresty") + return nil + } + + // 目录 + path := config.Path + if !tools.Exists(path) { + return errors.New("网站目录不存在") + } + website.Path = path + + // 域名 + domain := "server_name" + domains := config.Domains + for _, v := range domains { + if v == "" { + continue + } + domain += " " + v + } + domain += ";" + domainConfigOld := tools.Cut(raw, "# server_name标记位开始", "# server_name标记位结束") + if len(strings.TrimSpace(domainConfigOld)) == 0 { + return errors.New("配置文件中缺少server_name标记位") + } + raw = strings.Replace(raw, domainConfigOld, "\n "+domain+"\n ", -1) + + // 端口 + var port strings.Builder + ports := config.Ports + for i, v := range ports { + if _, err := strconv.Atoi(v); err != nil && v != "443 ssl http2" { + return errors.New("端口格式错误") + } + if v == "443" && config.Ssl { + v = "443 ssl http2" + } + if i != len(ports)-1 { + port.WriteString(" listen " + v + ";\n") + } else { + port.WriteString(" listen " + v + ";") + } + } + portConfigOld := tools.Cut(raw, "# port标记位开始", "# port标记位结束") + if len(strings.TrimSpace(portConfigOld)) == 0 { + return errors.New("配置文件中缺少port标记位") + } + raw = strings.Replace(raw, portConfigOld, "\n"+port.String()+"\n ", -1) + + // 运行目录 + root := tools.Cut(raw, "# root标记位开始", "# root标记位结束") + if len(strings.TrimSpace(root)) == 0 { + return errors.New("配置文件中缺少root标记位") + } + match := regexp.MustCompile(`root\s+(.+);`).FindStringSubmatch(root) + if len(match) != 2 { + return errors.New("配置文件中root标记位格式错误") + } + rootNew := strings.Replace(root, match[1], config.Root, -1) + raw = strings.Replace(raw, root, rootNew, -1) + + // 默认文件 + index := tools.Cut(raw, "# index标记位开始", "# index标记位结束") + if len(strings.TrimSpace(index)) == 0 { + return errors.New("配置文件中缺少index标记位") + } + match = regexp.MustCompile(`index\s+(.+);`).FindStringSubmatch(index) + if len(match) != 2 { + return errors.New("配置文件中index标记位格式错误") + } + indexNew := strings.Replace(index, match[1], config.Index, -1) + raw = strings.Replace(raw, index, indexNew, -1) + + // 防跨站 + root = config.Root + if !strings.HasSuffix(root, "/") { + root += "/" + } + if config.OpenBasedir { + if err := tools.Write(root+".user.ini", "open_basedir="+path+":/tmp/", 0644); err != nil { + return err + } + } else { + if tools.Exists(root + ".user.ini") { + tools.Remove(root + ".user.ini") + } + } + + // WAF + waf := config.Waf + wafStr := "off" + if waf { + wafStr = "on" + } + wafMode := config.WafMode + wafCcDeny := config.WafCcDeny + wafCache := config.WafCache + wafConfig := `# waf标记位开始 + waf ` + wafStr + `; + waf_rule_path /www/server/openresty/ngx_waf/assets/rules/; + waf_mode ` + wafMode + `; + waf_cc_deny ` + wafCcDeny + `; + waf_cache ` + wafCache + `; + ` + wafConfigOld := tools.Cut(raw, "# waf标记位开始", "# waf标记位结束") + if len(strings.TrimSpace(wafConfigOld)) != 0 { + raw = strings.Replace(raw, wafConfigOld, "", -1) + } + raw = strings.Replace(raw, "# waf标记位开始", wafConfig, -1) + + // SSL + ssl := config.Ssl + website.Ssl = ssl + if err := tools.Write("/www/server/vhost/ssl/"+website.Name+".pem", config.SslCertificate, 0644); err != nil { + return err + } + if err := tools.Write("/www/server/vhost/ssl/"+website.Name+".key", config.SslCertificateKey, 0644); err != nil { + return err + } + if ssl { + sslConfig := `# ssl标记位开始 + ssl_certificate /www/server/vhost/ssl/` + website.Name + `.pem; + ssl_certificate_key /www/server/vhost/ssl/` + website.Name + `.key; + ssl_session_timeout 1d; + ssl_session_cache shared:SSL:10m; + ssl_session_tickets off; + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; + ssl_prefer_server_ciphers off; + ` + if config.HttpRedirect { + sslConfig += `# http重定向标记位开始 + if ($server_port !~ 443){ + return 301 https://$host$request_uri; + } + error_page 497 https://$host$request_uri; + # http重定向标记位结束 + ` + } + if config.Hsts { + sslConfig += `# hsts标记位开始 + add_header Strict-Transport-Security "max-age=63072000" always; + # hsts标记位结束 + ` + } + sslConfigOld := tools.Cut(raw, "# ssl标记位开始", "# ssl标记位结束") + if len(strings.TrimSpace(sslConfigOld)) != 0 { + raw = strings.Replace(raw, sslConfigOld, "", -1) + } + raw = strings.Replace(raw, "# ssl标记位开始", sslConfig, -1) + } else { + sslConfigOld := tools.Cut(raw, "# ssl标记位开始", "# ssl标记位结束") + if len(strings.TrimSpace(sslConfigOld)) != 0 { + raw = strings.Replace(raw, sslConfigOld, "\n ", -1) + } + } + + if website.Php != config.Php { + website.Php = config.Php + phpConfigOld := tools.Cut(raw, "# php标记位开始", "# php标记位结束") + phpConfig := ` + include enable-php-` + strconv.Itoa(website.Php) + `.conf; + ` + if len(strings.TrimSpace(phpConfigOld)) != 0 { + raw = strings.Replace(raw, phpConfigOld, phpConfig, -1) + } + } + + if err := facades.Orm().Query().Save(&website); err != nil { + return err + } + + if err := tools.Write("/www/server/vhost/"+website.Name+".conf", raw, 0644); err != nil { + return err + } + if err := tools.Write("/www/server/vhost/rewrite/"+website.Name+".conf", config.Rewrite, 0644); err != nil { + return err + } + tools.Exec("systemctl reload openresty") + return nil +} + // Delete 删除网站 -func (r *WebsiteImpl) Delete(id int) error { +func (r *WebsiteImpl) Delete(id uint) error { var website models.Website if err := facades.Orm().Query().With("Cert").Where("id", id).FirstOrFail(&website); err != nil { return err @@ -319,7 +521,7 @@ func (r *WebsiteImpl) Delete(id int) error { } // GetConfig 获取网站配置 -func (r *WebsiteImpl) GetConfig(id int) (WebsiteSetting, error) { +func (r *WebsiteImpl) GetConfig(id uint) (WebsiteSetting, error) { var website models.Website if err := facades.Orm().Query().Where("id", id).First(&website); err != nil { return WebsiteSetting{}, err @@ -421,5 +623,5 @@ func (r *WebsiteImpl) GetConfigByName(name string) (WebsiteSetting, error) { return WebsiteSetting{}, err } - return r.GetConfig(int(website.ID)) + return r.GetConfig(website.ID) } diff --git a/docs/docs.go b/docs/docs.go index ed37f514..1f1599da 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -95,6 +95,17 @@ const docTemplate = `{ "证书管理" ], "summary": "获取证书列表", + "parameters": [ + { + "description": "分页信息", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/commonrequests.Paginate" + } + } + ], "responses": { "200": { "description": "OK", @@ -354,6 +365,17 @@ const docTemplate = `{ "证书管理" ], "summary": "获取 DNS 接口列表", + "parameters": [ + { + "description": "分页信息", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/commonrequests.Paginate" + } + } + ], "responses": { "200": { "description": "OK", @@ -812,6 +834,17 @@ const docTemplate = `{ "证书管理" ], "summary": "获取用户列表", + "parameters": [ + { + "description": "分页信息", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/commonrequests.Paginate" + } + } + ], "responses": { "200": { "description": "OK", @@ -1251,6 +1284,891 @@ const docTemplate = `{ } } }, + "/panel/website": { + "get": { + "security": [ + { + "BearerToken": [] + } + ], + "description": "获取网站管理的网站列表", + "produces": [ + "application/json" + ], + "tags": [ + "网站管理" + ], + "summary": "获取网站列表", + "parameters": [ + { + "description": "分页信息", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/commonrequests.Paginate" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/controllers.SuccessResponse" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/responses.List" + } + } + } + ] + } + }, + "401": { + "description": "登录已过期", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + }, + "403": { + "description": "插件需更新", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + }, + "500": { + "description": "系统内部错误", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + } + } + }, + "post": { + "security": [ + { + "BearerToken": [] + } + ], + "description": "添加网站到网站管理", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "网站管理" + ], + "summary": "添加网站", + "parameters": [ + { + "description": "网站信息", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/requests.Add" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controllers.SuccessResponse" + } + }, + "401": { + "description": "登录已过期", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + }, + "403": { + "description": "插件需更新", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + }, + "500": { + "description": "系统内部错误", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + } + } + } + }, + "/panel/website/backupList": { + "get": { + "security": [ + { + "BearerToken": [] + } + ], + "description": "获取网站的备份列表", + "produces": [ + "application/json" + ], + "tags": [ + "网站管理" + ], + "summary": "获取备份列表", + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/controllers.SuccessResponse" + }, + { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/services.BackupFile" + } + } + } + } + ] + } + }, + "401": { + "description": "登录已过期", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + }, + "500": { + "description": "系统内部错误", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + } + } + } + }, + "/panel/website/config/{id}": { + "get": { + "security": [ + { + "BearerToken": [] + } + ], + "description": "获取网站的配置", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "网站管理" + ], + "summary": "获取配置", + "parameters": [ + { + "type": "integer", + "description": "网站 ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/controllers.SuccessResponse" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/services.PanelWebsite" + } + } + } + ] + } + }, + "401": { + "description": "登录已过期", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + }, + "500": { + "description": "系统内部错误", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + } + } + }, + "post": { + "security": [ + { + "BearerToken": [] + } + ], + "description": "保存网站的配置", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "网站管理" + ], + "summary": "保存配置", + "parameters": [ + { + "type": "integer", + "description": "网站 ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "网站配置", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/requests.SaveConfig" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controllers.SuccessResponse" + } + }, + "401": { + "description": "登录已过期", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + }, + "500": { + "description": "系统内部错误", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + } + } + } + }, + "/panel/website/createBackup": { + "post": { + "security": [ + { + "BearerToken": [] + } + ], + "description": "创建网站的备份", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "网站管理" + ], + "summary": "创建备份", + "parameters": [ + { + "description": "网站 ID", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/requests.ID" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controllers.SuccessResponse" + } + }, + "401": { + "description": "登录已过期", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + }, + "500": { + "description": "系统内部错误", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + } + } + } + }, + "/panel/website/defaultConfig": { + "get": { + "security": [ + { + "BearerToken": [] + } + ], + "description": "获取默认首页和停止页配置", + "produces": [ + "application/json" + ], + "tags": [ + "网站管理" + ], + "summary": "获取默认配置", + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/controllers.SuccessResponse" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + } + ] + } + }, + "401": { + "description": "登录已过期", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + }, + "403": { + "description": "插件需更新", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + } + } + }, + "post": { + "security": [ + { + "BearerToken": [] + } + ], + "description": "保存默认首页和停止页配置", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "网站管理" + ], + "summary": "保存默认配置", + "parameters": [ + { + "description": "页面信息", + "name": "data", + "in": "body", + "required": true, + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controllers.SuccessResponse" + } + }, + "401": { + "description": "登录已过期", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + }, + "403": { + "description": "插件需更新", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + }, + "500": { + "description": "系统内部错误", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + } + } + } + }, + "/panel/website/deleteBackup": { + "delete": { + "security": [ + { + "BearerToken": [] + } + ], + "description": "删除网站的备份", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "网站管理" + ], + "summary": "删除备份", + "parameters": [ + { + "description": "备份信息", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/requests.DeleteBackup" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controllers.SuccessResponse" + } + }, + "401": { + "description": "登录已过期", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + }, + "422": { + "description": "参数错误", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + }, + "500": { + "description": "系统内部错误", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + } + } + } + }, + "/panel/website/log/{id}": { + "delete": { + "security": [ + { + "BearerToken": [] + } + ], + "description": "清空网站的日志", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "网站管理" + ], + "summary": "清空日志", + "parameters": [ + { + "type": "integer", + "description": "网站 ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controllers.SuccessResponse" + } + }, + "401": { + "description": "登录已过期", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + }, + "500": { + "description": "系统内部错误", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + } + } + } + }, + "/panel/website/resetConfig": { + "post": { + "security": [ + { + "BearerToken": [] + } + ], + "description": "重置网站的配置", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "网站管理" + ], + "summary": "重置配置", + "parameters": [ + { + "description": "网站 ID", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/requests.ID" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controllers.SuccessResponse" + } + }, + "401": { + "description": "登录已过期", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + }, + "422": { + "description": "参数错误", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + }, + "500": { + "description": "系统内部错误", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + } + } + } + }, + "/panel/website/restoreBackup": { + "post": { + "security": [ + { + "BearerToken": [] + } + ], + "description": "还原网站的备份", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "网站管理" + ], + "summary": "还原备份", + "parameters": [ + { + "description": "备份信息", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/requests.RestoreBackup" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controllers.SuccessResponse" + } + }, + "401": { + "description": "登录已过期", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + }, + "422": { + "description": "参数错误", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + }, + "500": { + "description": "系统内部错误", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + } + } + } + }, + "/panel/website/status/{id}": { + "post": { + "security": [ + { + "BearerToken": [] + } + ], + "description": "启用或停用网站", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "网站管理" + ], + "summary": "状态", + "parameters": [ + { + "type": "integer", + "description": "网站 ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controllers.SuccessResponse" + } + }, + "401": { + "description": "登录已过期", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + }, + "422": { + "description": "参数错误", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + }, + "500": { + "description": "系统内部错误", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + } + } + } + }, + "/panel/website/updateRemark/{id}": { + "post": { + "security": [ + { + "BearerToken": [] + } + ], + "description": "更新网站的备注", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "网站管理" + ], + "summary": "更新备注", + "parameters": [ + { + "type": "integer", + "description": "网站 ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controllers.SuccessResponse" + } + }, + "401": { + "description": "登录已过期", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + }, + "500": { + "description": "系统内部错误", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + } + } + } + }, + "/panel/website/uploadBackup": { + "post": { + "security": [ + { + "BearerToken": [] + } + ], + "description": "上传网站的备份", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "网站管理" + ], + "summary": "上传备份", + "parameters": [ + { + "type": "file", + "description": "备份文件", + "name": "file", + "in": "formData", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controllers.SuccessResponse" + } + }, + "401": { + "description": "登录已过期", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + }, + "422": { + "description": "上传文件失败", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + }, + "500": { + "description": "系统内部错误", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + } + } + } + }, + "/panel/website/{id}": { + "delete": { + "security": [ + { + "BearerToken": [] + } + ], + "description": "删除网站管理的网站", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "网站管理" + ], + "summary": "删除网站", + "parameters": [ + { + "type": "integer", + "description": "网站 ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controllers.SuccessResponse" + } + }, + "401": { + "description": "登录已过期", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + }, + "403": { + "description": "插件需更新", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + }, + "500": { + "description": "系统内部错误", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + } + } + } + }, "/swagger": { "get": { "description": "Swagger UI", @@ -1307,6 +2225,17 @@ const docTemplate = `{ } } }, + "commonrequests.Paginate": { + "type": "object", + "properties": { + "limit": { + "type": "integer" + }, + "page": { + "type": "integer" + } + } + }, "controllers.ErrorResponse": { "type": "object", "properties": { @@ -1484,6 +2413,44 @@ const docTemplate = `{ } } }, + "requests.Add": { + "type": "object", + "properties": { + "db": { + "type": "boolean" + }, + "db_name": { + "type": "string" + }, + "db_password": { + "type": "string" + }, + "db_type": { + "type": "string" + }, + "db_user": { + "type": "string" + }, + "domains": { + "type": "array", + "items": { + "type": "string" + } + }, + "name": { + "type": "string" + }, + "php": { + "type": "integer" + }, + "ports": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, "requests.CertStore": { "type": "object", "properties": { @@ -1570,6 +2537,22 @@ const docTemplate = `{ } } }, + "requests.DeleteBackup": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + } + }, + "requests.ID": { + "type": "object", + "properties": { + "id": { + "type": "integer" + } + } + }, "requests.Login": { "type": "object", "properties": { @@ -1597,6 +2580,85 @@ const docTemplate = `{ } } }, + "requests.RestoreBackup": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + } + } + }, + "requests.SaveConfig": { + "type": "object", + "properties": { + "domains": { + "type": "array", + "items": { + "type": "string" + } + }, + "hsts": { + "type": "boolean" + }, + "http_redirect": { + "type": "boolean" + }, + "id": { + "type": "integer" + }, + "index": { + "type": "string" + }, + "open_basedir": { + "type": "boolean" + }, + "path": { + "type": "string" + }, + "php": { + "type": "integer" + }, + "ports": { + "type": "array", + "items": { + "type": "string" + } + }, + "raw": { + "type": "string" + }, + "rewrite": { + "type": "string" + }, + "root": { + "type": "string" + }, + "ssl": { + "type": "boolean" + }, + "ssl_certificate": { + "type": "string" + }, + "ssl_certificate_key": { + "type": "string" + }, + "waf": { + "type": "boolean" + }, + "waf_cache": { + "type": "string" + }, + "waf_cc_deny": { + "type": "string" + }, + "waf_mode": { + "type": "string" + } + } + }, "requests.Update": { "type": "object", "properties": { @@ -1717,6 +2779,20 @@ const docTemplate = `{ } } }, + "responses.List": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/models.Website" + } + }, + "total": { + "type": "integer" + } + } + }, "responses.Settings": { "type": "object", "properties": { @@ -1745,6 +2821,67 @@ const docTemplate = `{ "type": "string" } } + }, + "services.BackupFile": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "size": { + "type": "string" + } + } + }, + "services.PanelWebsite": { + "type": "object", + "properties": { + "db": { + "type": "boolean" + }, + "db_name": { + "type": "string" + }, + "db_password": { + "type": "string" + }, + "db_type": { + "type": "string" + }, + "db_user": { + "type": "string" + }, + "domains": { + "type": "array", + "items": { + "type": "string" + } + }, + "name": { + "type": "string" + }, + "path": { + "type": "string" + }, + "php": { + "type": "integer" + }, + "ports": { + "type": "array", + "items": { + "type": "string" + } + }, + "remark": { + "type": "string" + }, + "ssl": { + "type": "boolean" + }, + "status": { + "type": "boolean" + } + } } }, "securityDefinitions": { diff --git a/docs/swagger.json b/docs/swagger.json index a6b3302a..9f377eb8 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -88,6 +88,17 @@ "证书管理" ], "summary": "获取证书列表", + "parameters": [ + { + "description": "分页信息", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/commonrequests.Paginate" + } + } + ], "responses": { "200": { "description": "OK", @@ -347,6 +358,17 @@ "证书管理" ], "summary": "获取 DNS 接口列表", + "parameters": [ + { + "description": "分页信息", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/commonrequests.Paginate" + } + } + ], "responses": { "200": { "description": "OK", @@ -805,6 +827,17 @@ "证书管理" ], "summary": "获取用户列表", + "parameters": [ + { + "description": "分页信息", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/commonrequests.Paginate" + } + } + ], "responses": { "200": { "description": "OK", @@ -1244,6 +1277,891 @@ } } }, + "/panel/website": { + "get": { + "security": [ + { + "BearerToken": [] + } + ], + "description": "获取网站管理的网站列表", + "produces": [ + "application/json" + ], + "tags": [ + "网站管理" + ], + "summary": "获取网站列表", + "parameters": [ + { + "description": "分页信息", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/commonrequests.Paginate" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/controllers.SuccessResponse" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/responses.List" + } + } + } + ] + } + }, + "401": { + "description": "登录已过期", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + }, + "403": { + "description": "插件需更新", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + }, + "500": { + "description": "系统内部错误", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + } + } + }, + "post": { + "security": [ + { + "BearerToken": [] + } + ], + "description": "添加网站到网站管理", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "网站管理" + ], + "summary": "添加网站", + "parameters": [ + { + "description": "网站信息", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/requests.Add" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controllers.SuccessResponse" + } + }, + "401": { + "description": "登录已过期", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + }, + "403": { + "description": "插件需更新", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + }, + "500": { + "description": "系统内部错误", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + } + } + } + }, + "/panel/website/backupList": { + "get": { + "security": [ + { + "BearerToken": [] + } + ], + "description": "获取网站的备份列表", + "produces": [ + "application/json" + ], + "tags": [ + "网站管理" + ], + "summary": "获取备份列表", + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/controllers.SuccessResponse" + }, + { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/definitions/services.BackupFile" + } + } + } + } + ] + } + }, + "401": { + "description": "登录已过期", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + }, + "500": { + "description": "系统内部错误", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + } + } + } + }, + "/panel/website/config/{id}": { + "get": { + "security": [ + { + "BearerToken": [] + } + ], + "description": "获取网站的配置", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "网站管理" + ], + "summary": "获取配置", + "parameters": [ + { + "type": "integer", + "description": "网站 ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/controllers.SuccessResponse" + }, + { + "type": "object", + "properties": { + "data": { + "$ref": "#/definitions/services.PanelWebsite" + } + } + } + ] + } + }, + "401": { + "description": "登录已过期", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + }, + "500": { + "description": "系统内部错误", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + } + } + }, + "post": { + "security": [ + { + "BearerToken": [] + } + ], + "description": "保存网站的配置", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "网站管理" + ], + "summary": "保存配置", + "parameters": [ + { + "type": "integer", + "description": "网站 ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "网站配置", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/requests.SaveConfig" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controllers.SuccessResponse" + } + }, + "401": { + "description": "登录已过期", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + }, + "500": { + "description": "系统内部错误", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + } + } + } + }, + "/panel/website/createBackup": { + "post": { + "security": [ + { + "BearerToken": [] + } + ], + "description": "创建网站的备份", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "网站管理" + ], + "summary": "创建备份", + "parameters": [ + { + "description": "网站 ID", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/requests.ID" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controllers.SuccessResponse" + } + }, + "401": { + "description": "登录已过期", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + }, + "500": { + "description": "系统内部错误", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + } + } + } + }, + "/panel/website/defaultConfig": { + "get": { + "security": [ + { + "BearerToken": [] + } + ], + "description": "获取默认首页和停止页配置", + "produces": [ + "application/json" + ], + "tags": [ + "网站管理" + ], + "summary": "获取默认配置", + "responses": { + "200": { + "description": "OK", + "schema": { + "allOf": [ + { + "$ref": "#/definitions/controllers.SuccessResponse" + }, + { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + } + ] + } + }, + "401": { + "description": "登录已过期", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + }, + "403": { + "description": "插件需更新", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + } + } + }, + "post": { + "security": [ + { + "BearerToken": [] + } + ], + "description": "保存默认首页和停止页配置", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "网站管理" + ], + "summary": "保存默认配置", + "parameters": [ + { + "description": "页面信息", + "name": "data", + "in": "body", + "required": true, + "schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controllers.SuccessResponse" + } + }, + "401": { + "description": "登录已过期", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + }, + "403": { + "description": "插件需更新", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + }, + "500": { + "description": "系统内部错误", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + } + } + } + }, + "/panel/website/deleteBackup": { + "delete": { + "security": [ + { + "BearerToken": [] + } + ], + "description": "删除网站的备份", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "网站管理" + ], + "summary": "删除备份", + "parameters": [ + { + "description": "备份信息", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/requests.DeleteBackup" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controllers.SuccessResponse" + } + }, + "401": { + "description": "登录已过期", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + }, + "422": { + "description": "参数错误", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + }, + "500": { + "description": "系统内部错误", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + } + } + } + }, + "/panel/website/log/{id}": { + "delete": { + "security": [ + { + "BearerToken": [] + } + ], + "description": "清空网站的日志", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "网站管理" + ], + "summary": "清空日志", + "parameters": [ + { + "type": "integer", + "description": "网站 ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controllers.SuccessResponse" + } + }, + "401": { + "description": "登录已过期", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + }, + "500": { + "description": "系统内部错误", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + } + } + } + }, + "/panel/website/resetConfig": { + "post": { + "security": [ + { + "BearerToken": [] + } + ], + "description": "重置网站的配置", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "网站管理" + ], + "summary": "重置配置", + "parameters": [ + { + "description": "网站 ID", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/requests.ID" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controllers.SuccessResponse" + } + }, + "401": { + "description": "登录已过期", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + }, + "422": { + "description": "参数错误", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + }, + "500": { + "description": "系统内部错误", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + } + } + } + }, + "/panel/website/restoreBackup": { + "post": { + "security": [ + { + "BearerToken": [] + } + ], + "description": "还原网站的备份", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "网站管理" + ], + "summary": "还原备份", + "parameters": [ + { + "description": "备份信息", + "name": "data", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/requests.RestoreBackup" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controllers.SuccessResponse" + } + }, + "401": { + "description": "登录已过期", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + }, + "422": { + "description": "参数错误", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + }, + "500": { + "description": "系统内部错误", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + } + } + } + }, + "/panel/website/status/{id}": { + "post": { + "security": [ + { + "BearerToken": [] + } + ], + "description": "启用或停用网站", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "网站管理" + ], + "summary": "状态", + "parameters": [ + { + "type": "integer", + "description": "网站 ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controllers.SuccessResponse" + } + }, + "401": { + "description": "登录已过期", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + }, + "422": { + "description": "参数错误", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + }, + "500": { + "description": "系统内部错误", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + } + } + } + }, + "/panel/website/updateRemark/{id}": { + "post": { + "security": [ + { + "BearerToken": [] + } + ], + "description": "更新网站的备注", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "网站管理" + ], + "summary": "更新备注", + "parameters": [ + { + "type": "integer", + "description": "网站 ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controllers.SuccessResponse" + } + }, + "401": { + "description": "登录已过期", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + }, + "500": { + "description": "系统内部错误", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + } + } + } + }, + "/panel/website/uploadBackup": { + "post": { + "security": [ + { + "BearerToken": [] + } + ], + "description": "上传网站的备份", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "网站管理" + ], + "summary": "上传备份", + "parameters": [ + { + "type": "file", + "description": "备份文件", + "name": "file", + "in": "formData", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controllers.SuccessResponse" + } + }, + "401": { + "description": "登录已过期", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + }, + "422": { + "description": "上传文件失败", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + }, + "500": { + "description": "系统内部错误", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + } + } + } + }, + "/panel/website/{id}": { + "delete": { + "security": [ + { + "BearerToken": [] + } + ], + "description": "删除网站管理的网站", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "网站管理" + ], + "summary": "删除网站", + "parameters": [ + { + "type": "integer", + "description": "网站 ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controllers.SuccessResponse" + } + }, + "401": { + "description": "登录已过期", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + }, + "403": { + "description": "插件需更新", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + }, + "500": { + "description": "系统内部错误", + "schema": { + "$ref": "#/definitions/controllers.ErrorResponse" + } + } + } + } + }, "/swagger": { "get": { "description": "Swagger UI", @@ -1300,6 +2218,17 @@ } } }, + "commonrequests.Paginate": { + "type": "object", + "properties": { + "limit": { + "type": "integer" + }, + "page": { + "type": "integer" + } + } + }, "controllers.ErrorResponse": { "type": "object", "properties": { @@ -1477,6 +2406,44 @@ } } }, + "requests.Add": { + "type": "object", + "properties": { + "db": { + "type": "boolean" + }, + "db_name": { + "type": "string" + }, + "db_password": { + "type": "string" + }, + "db_type": { + "type": "string" + }, + "db_user": { + "type": "string" + }, + "domains": { + "type": "array", + "items": { + "type": "string" + } + }, + "name": { + "type": "string" + }, + "php": { + "type": "integer" + }, + "ports": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, "requests.CertStore": { "type": "object", "properties": { @@ -1563,6 +2530,22 @@ } } }, + "requests.DeleteBackup": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + } + }, + "requests.ID": { + "type": "object", + "properties": { + "id": { + "type": "integer" + } + } + }, "requests.Login": { "type": "object", "properties": { @@ -1590,6 +2573,85 @@ } } }, + "requests.RestoreBackup": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + } + } + }, + "requests.SaveConfig": { + "type": "object", + "properties": { + "domains": { + "type": "array", + "items": { + "type": "string" + } + }, + "hsts": { + "type": "boolean" + }, + "http_redirect": { + "type": "boolean" + }, + "id": { + "type": "integer" + }, + "index": { + "type": "string" + }, + "open_basedir": { + "type": "boolean" + }, + "path": { + "type": "string" + }, + "php": { + "type": "integer" + }, + "ports": { + "type": "array", + "items": { + "type": "string" + } + }, + "raw": { + "type": "string" + }, + "rewrite": { + "type": "string" + }, + "root": { + "type": "string" + }, + "ssl": { + "type": "boolean" + }, + "ssl_certificate": { + "type": "string" + }, + "ssl_certificate_key": { + "type": "string" + }, + "waf": { + "type": "boolean" + }, + "waf_cache": { + "type": "string" + }, + "waf_cc_deny": { + "type": "string" + }, + "waf_mode": { + "type": "string" + } + } + }, "requests.Update": { "type": "object", "properties": { @@ -1710,6 +2772,20 @@ } } }, + "responses.List": { + "type": "object", + "properties": { + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/models.Website" + } + }, + "total": { + "type": "integer" + } + } + }, "responses.Settings": { "type": "object", "properties": { @@ -1738,6 +2814,67 @@ "type": "string" } } + }, + "services.BackupFile": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "size": { + "type": "string" + } + } + }, + "services.PanelWebsite": { + "type": "object", + "properties": { + "db": { + "type": "boolean" + }, + "db_name": { + "type": "string" + }, + "db_password": { + "type": "string" + }, + "db_type": { + "type": "string" + }, + "db_user": { + "type": "string" + }, + "domains": { + "type": "array", + "items": { + "type": "string" + } + }, + "name": { + "type": "string" + }, + "path": { + "type": "string" + }, + "php": { + "type": "integer" + }, + "ports": { + "type": "array", + "items": { + "type": "string" + } + }, + "remark": { + "type": "string" + }, + "ssl": { + "type": "boolean" + }, + "status": { + "type": "boolean" + } + } } }, "securityDefinitions": { diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 75dc8afb..cc0f1dfd 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -24,6 +24,13 @@ definitions: value: type: string type: object + commonrequests.Paginate: + properties: + limit: + type: integer + page: + type: integer + type: object controllers.ErrorResponse: properties: code: @@ -144,6 +151,31 @@ definitions: updated_at: type: string type: object + requests.Add: + properties: + db: + type: boolean + db_name: + type: string + db_password: + type: string + db_type: + type: string + db_user: + type: string + domains: + items: + type: string + type: array + name: + type: string + php: + type: integer + ports: + items: + type: string + type: array + type: object requests.CertStore: properties: auto_renew: @@ -200,6 +232,16 @@ definitions: type: type: string type: object + requests.DeleteBackup: + properties: + name: + type: string + type: object + requests.ID: + properties: + id: + type: integer + type: object requests.Login: properties: password: @@ -217,6 +259,58 @@ definitions: id: type: integer type: object + requests.RestoreBackup: + properties: + id: + type: integer + name: + type: string + type: object + requests.SaveConfig: + properties: + domains: + items: + type: string + type: array + hsts: + type: boolean + http_redirect: + type: boolean + id: + type: integer + index: + type: string + open_basedir: + type: boolean + path: + type: string + php: + type: integer + ports: + items: + type: string + type: array + raw: + type: string + rewrite: + type: string + root: + type: string + ssl: + type: boolean + ssl_certificate: + type: string + ssl_certificate_key: + type: string + waf: + type: boolean + waf_cache: + type: string + waf_cc_deny: + type: string + waf_mode: + type: string + type: object requests.Update: properties: backup_path: @@ -295,6 +389,15 @@ definitions: username: type: string type: object + responses.List: + properties: + items: + items: + $ref: '#/definitions/models.Website' + type: array + total: + type: integer + type: object responses.Settings: properties: backup_path: @@ -314,6 +417,46 @@ definitions: website_path: type: string type: object + services.BackupFile: + properties: + name: + type: string + size: + type: string + type: object + services.PanelWebsite: + properties: + db: + type: boolean + db_name: + type: string + db_password: + type: string + db_type: + type: string + db_user: + type: string + domains: + items: + type: string + type: array + name: + type: string + path: + type: string + php: + type: integer + ports: + items: + type: string + type: array + remark: + type: string + ssl: + type: boolean + status: + type: boolean + type: object info: contact: email: i@haozi.net @@ -363,6 +506,13 @@ paths: /panel/cert/certs: get: description: 获取面板证书管理的证书列表 + parameters: + - description: 分页信息 + in: body + name: data + required: true + schema: + $ref: '#/definitions/commonrequests.Paginate' produces: - application/json responses: @@ -522,6 +672,13 @@ paths: /panel/cert/dns: get: description: 获取面板证书管理的 DNS 接口列表 + parameters: + - description: 分页信息 + in: body + name: data + required: true + schema: + $ref: '#/definitions/commonrequests.Paginate' produces: - application/json responses: @@ -803,6 +960,13 @@ paths: /panel/cert/users: get: description: 获取面板证书管理的 ACME 用户列表 + parameters: + - description: 分页信息 + in: body + name: data + required: true + schema: + $ref: '#/definitions/commonrequests.Paginate' produces: - application/json responses: @@ -1077,6 +1241,556 @@ paths: summary: 登录 tags: - 用户鉴权 + /panel/website: + get: + description: 获取网站管理的网站列表 + parameters: + - description: 分页信息 + in: body + name: data + required: true + schema: + $ref: '#/definitions/commonrequests.Paginate' + produces: + - application/json + responses: + "200": + description: OK + schema: + allOf: + - $ref: '#/definitions/controllers.SuccessResponse' + - properties: + data: + $ref: '#/definitions/responses.List' + type: object + "401": + description: 登录已过期 + schema: + $ref: '#/definitions/controllers.ErrorResponse' + "403": + description: 插件需更新 + schema: + $ref: '#/definitions/controllers.ErrorResponse' + "500": + description: 系统内部错误 + schema: + $ref: '#/definitions/controllers.ErrorResponse' + security: + - BearerToken: [] + summary: 获取网站列表 + tags: + - 网站管理 + post: + consumes: + - application/json + description: 添加网站到网站管理 + parameters: + - description: 网站信息 + in: body + name: data + required: true + schema: + $ref: '#/definitions/requests.Add' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/controllers.SuccessResponse' + "401": + description: 登录已过期 + schema: + $ref: '#/definitions/controllers.ErrorResponse' + "403": + description: 插件需更新 + schema: + $ref: '#/definitions/controllers.ErrorResponse' + "500": + description: 系统内部错误 + schema: + $ref: '#/definitions/controllers.ErrorResponse' + security: + - BearerToken: [] + summary: 添加网站 + tags: + - 网站管理 + /panel/website/{id}: + delete: + consumes: + - application/json + description: 删除网站管理的网站 + parameters: + - description: 网站 ID + in: path + name: id + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/controllers.SuccessResponse' + "401": + description: 登录已过期 + schema: + $ref: '#/definitions/controllers.ErrorResponse' + "403": + description: 插件需更新 + schema: + $ref: '#/definitions/controllers.ErrorResponse' + "500": + description: 系统内部错误 + schema: + $ref: '#/definitions/controllers.ErrorResponse' + security: + - BearerToken: [] + summary: 删除网站 + tags: + - 网站管理 + /panel/website/backupList: + get: + description: 获取网站的备份列表 + produces: + - application/json + responses: + "200": + description: OK + schema: + allOf: + - $ref: '#/definitions/controllers.SuccessResponse' + - properties: + data: + items: + $ref: '#/definitions/services.BackupFile' + type: array + type: object + "401": + description: 登录已过期 + schema: + $ref: '#/definitions/controllers.ErrorResponse' + "500": + description: 系统内部错误 + schema: + $ref: '#/definitions/controllers.ErrorResponse' + security: + - BearerToken: [] + summary: 获取备份列表 + tags: + - 网站管理 + /panel/website/config/{id}: + get: + consumes: + - application/json + description: 获取网站的配置 + parameters: + - description: 网站 ID + in: path + name: id + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + allOf: + - $ref: '#/definitions/controllers.SuccessResponse' + - properties: + data: + $ref: '#/definitions/services.PanelWebsite' + type: object + "401": + description: 登录已过期 + schema: + $ref: '#/definitions/controllers.ErrorResponse' + "500": + description: 系统内部错误 + schema: + $ref: '#/definitions/controllers.ErrorResponse' + security: + - BearerToken: [] + summary: 获取配置 + tags: + - 网站管理 + post: + consumes: + - application/json + description: 保存网站的配置 + parameters: + - description: 网站 ID + in: path + name: id + required: true + type: integer + - description: 网站配置 + in: body + name: data + required: true + schema: + $ref: '#/definitions/requests.SaveConfig' + 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/website/createBackup: + post: + consumes: + - application/json + description: 创建网站的备份 + parameters: + - description: 网站 ID + in: body + name: data + required: true + schema: + $ref: '#/definitions/requests.ID' + 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/website/defaultConfig: + get: + description: 获取默认首页和停止页配置 + produces: + - application/json + responses: + "200": + description: OK + schema: + allOf: + - $ref: '#/definitions/controllers.SuccessResponse' + - properties: + data: + additionalProperties: + type: string + type: object + type: object + "401": + description: 登录已过期 + schema: + $ref: '#/definitions/controllers.ErrorResponse' + "403": + description: 插件需更新 + schema: + $ref: '#/definitions/controllers.ErrorResponse' + security: + - BearerToken: [] + summary: 获取默认配置 + tags: + - 网站管理 + post: + consumes: + - application/json + description: 保存默认首页和停止页配置 + parameters: + - description: 页面信息 + in: body + name: data + required: true + schema: + additionalProperties: + type: string + type: object + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/controllers.SuccessResponse' + "401": + description: 登录已过期 + schema: + $ref: '#/definitions/controllers.ErrorResponse' + "403": + description: 插件需更新 + schema: + $ref: '#/definitions/controllers.ErrorResponse' + "500": + description: 系统内部错误 + schema: + $ref: '#/definitions/controllers.ErrorResponse' + security: + - BearerToken: [] + summary: 保存默认配置 + tags: + - 网站管理 + /panel/website/deleteBackup: + delete: + consumes: + - application/json + description: 删除网站的备份 + parameters: + - description: 备份信息 + in: body + name: data + required: true + schema: + $ref: '#/definitions/requests.DeleteBackup' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/controllers.SuccessResponse' + "401": + description: 登录已过期 + schema: + $ref: '#/definitions/controllers.ErrorResponse' + "422": + description: 参数错误 + schema: + $ref: '#/definitions/controllers.ErrorResponse' + "500": + description: 系统内部错误 + schema: + $ref: '#/definitions/controllers.ErrorResponse' + security: + - BearerToken: [] + summary: 删除备份 + tags: + - 网站管理 + /panel/website/log/{id}: + delete: + consumes: + - application/json + description: 清空网站的日志 + parameters: + - description: 网站 ID + in: path + name: id + required: true + type: integer + 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/website/resetConfig: + post: + consumes: + - application/json + description: 重置网站的配置 + parameters: + - description: 网站 ID + in: body + name: data + required: true + schema: + $ref: '#/definitions/requests.ID' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/controllers.SuccessResponse' + "401": + description: 登录已过期 + schema: + $ref: '#/definitions/controllers.ErrorResponse' + "422": + description: 参数错误 + schema: + $ref: '#/definitions/controllers.ErrorResponse' + "500": + description: 系统内部错误 + schema: + $ref: '#/definitions/controllers.ErrorResponse' + security: + - BearerToken: [] + summary: 重置配置 + tags: + - 网站管理 + /panel/website/restoreBackup: + post: + consumes: + - application/json + description: 还原网站的备份 + parameters: + - description: 备份信息 + in: body + name: data + required: true + schema: + $ref: '#/definitions/requests.RestoreBackup' + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/controllers.SuccessResponse' + "401": + description: 登录已过期 + schema: + $ref: '#/definitions/controllers.ErrorResponse' + "422": + description: 参数错误 + schema: + $ref: '#/definitions/controllers.ErrorResponse' + "500": + description: 系统内部错误 + schema: + $ref: '#/definitions/controllers.ErrorResponse' + security: + - BearerToken: [] + summary: 还原备份 + tags: + - 网站管理 + /panel/website/status/{id}: + post: + consumes: + - application/json + description: 启用或停用网站 + parameters: + - description: 网站 ID + in: path + name: id + required: true + type: integer + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/controllers.SuccessResponse' + "401": + description: 登录已过期 + schema: + $ref: '#/definitions/controllers.ErrorResponse' + "422": + description: 参数错误 + schema: + $ref: '#/definitions/controllers.ErrorResponse' + "500": + description: 系统内部错误 + schema: + $ref: '#/definitions/controllers.ErrorResponse' + security: + - BearerToken: [] + summary: 状态 + tags: + - 网站管理 + /panel/website/updateRemark/{id}: + post: + consumes: + - application/json + description: 更新网站的备注 + parameters: + - description: 网站 ID + in: path + name: id + required: true + type: integer + 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/website/uploadBackup: + post: + consumes: + - application/json + description: 上传网站的备份 + parameters: + - description: 备份文件 + in: formData + name: file + required: true + type: file + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/controllers.SuccessResponse' + "401": + description: 登录已过期 + schema: + $ref: '#/definitions/controllers.ErrorResponse' + "422": + description: 上传文件失败 + schema: + $ref: '#/definitions/controllers.ErrorResponse' + "500": + description: 系统内部错误 + schema: + $ref: '#/definitions/controllers.ErrorResponse' + security: + - BearerToken: [] + summary: 上传备份 + tags: + - 网站管理 /swagger: get: description: Swagger UI diff --git a/go.mod b/go.mod index c0daf43c..f11ce534 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/gookit/color v1.5.4 github.com/gookit/validate v1.5.1 github.com/goravel/fiber v1.1.11-0.20231108081345-36e967f101d0 - github.com/goravel/framework v1.13.1-0.20231109083801-f2c86a7c0796 + github.com/goravel/framework v1.13.1-0.20231110075143-376f1d9f92e1 github.com/iancoleman/strcase v0.3.0 github.com/imroc/req/v3 v3.42.1 github.com/mojocn/base64Captcha v1.3.5 diff --git a/go.sum b/go.sum index 6dbfa84f..ab596c57 100644 --- a/go.sum +++ b/go.sum @@ -385,8 +385,8 @@ github.com/goravel/file-rotatelogs v0.0.0-20211215053220-2ab31dd9575c h1:obhFK91 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.20231109083801-f2c86a7c0796 h1:4ZqUXMfPP8M10joipSdP9PGgDoVD51vZIcCPds/EyGk= -github.com/goravel/framework v1.13.1-0.20231109083801-f2c86a7c0796/go.mod h1:5jKFbJzfqhaQTP3HCgbyrpnrCyoJjxN5JWSXO96H0iQ= +github.com/goravel/framework v1.13.1-0.20231110075143-376f1d9f92e1 h1:J0FjRp0EGsyno2XNfUHIz2ghuE0dyg2/VUlR10/KRZA= +github.com/goravel/framework v1.13.1-0.20231110075143-376f1d9f92e1/go.mod h1:9vNb8pNm1HBF/1I4SOD88F5rP+/SvzrniJDx9t15OzU= 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= diff --git a/main.go b/main.go index 2f3f1316..003eb56e 100644 --- a/main.go +++ b/main.go @@ -41,7 +41,7 @@ func main() { // 启动 HTTP 服务 go func() { if err := facades.Route().Run(); err != nil { - facades.Log().Errorf("Route run error: %v", err) + facades.Log().Infof("Route run error: %v", err) } }() diff --git a/pkg/tools/system.go b/pkg/tools/system.go index 9f2a780d..3b343a8d 100644 --- a/pkg/tools/system.go +++ b/pkg/tools/system.go @@ -12,27 +12,17 @@ import ( ) // Write 写入文件 -func Write(path string, data string, permission os.FileMode) bool { +func Write(path string, data string, permission os.FileMode) error { if err := os.MkdirAll(filepath.Dir(path), permission); err != nil { - facades.Log().With(map[string]any{ - "path": filepath.Dir(path), - "permission": permission, - "error": err.Error(), - }).Tags("面板", "工具函数").Error("创建目录失败") - return false + return err } err := os.WriteFile(path, []byte(data), permission) if err != nil { - facades.Log().With(map[string]any{ - "path": path, - "permission": permission, - "error": err.Error(), - }).Tags("面板", "工具函数").Error("写入文件失败") - return false + return err } - return true + return nil } // Read 读取文件 @@ -42,7 +32,7 @@ func Read(path string) string { facades.Log().With(map[string]any{ "path": path, "error": err.Error(), - }).Tags("面板", "工具函数").Error("读取文件失败") + }).Tags("面板", "工具函数").Info("读取文件失败") return "" } @@ -55,7 +45,7 @@ func Remove(path string) bool { facades.Log().With(map[string]any{ "path": path, "error": err.Error(), - }).Tags("面板", "工具函数").Error("删除文件/目录失败") + }).Tags("面板", "工具函数").Info("删除文件/目录失败") return false } @@ -76,7 +66,7 @@ func Exec(shell string) string { facades.Log().With(map[string]any{ "shell": shell, "error": err.Error(), - }).Tags("面板", "工具函数").Error("执行命令失败") + }).Tags("面板", "工具函数").Info("执行命令失败") } return "" } @@ -102,7 +92,7 @@ func ExecAsync(shell string) error { facades.Log().With(map[string]any{ "shell": shell, "error": err.Error(), - }).Tags("面板", "工具函数").Error("异步执行命令失败") + }).Tags("面板", "工具函数").Info("异步执行命令失败") } } }() @@ -117,7 +107,7 @@ func Mkdir(path string, permission os.FileMode) bool { "path": path, "permission": permission, "error": err.Error(), - }).Tags("面板", "工具函数").Error("创建目录失败") + }).Tags("面板", "工具函数").Info("创建目录失败") return false } @@ -130,7 +120,7 @@ func Chmod(path string, permission os.FileMode) bool { facades.Log().With(map[string]any{ "path": path, "permission": permission, - }).Tags("面板", "工具函数").Error("修改文件/目录权限失败") + }).Tags("面板", "工具函数").Info("修改文件/目录权限失败") return false } @@ -148,7 +138,7 @@ func Chown(path, user, group string) bool { "user": user, "group": group, "error": err.Error(), - }).Tags("面板", "工具函数").Error("修改文件/目录所有者失败") + }).Tags("面板", "工具函数").Info("修改文件/目录所有者失败") return false } diff --git a/pkg/tools/system_test.go b/pkg/tools/system_test.go index 2d3a8208..a858eb19 100644 --- a/pkg/tools/system_test.go +++ b/pkg/tools/system_test.go @@ -21,7 +21,7 @@ func (s *SystemHelperTestSuite) TestWrite() { filePath := "/tmp/testfile" defer os.Remove(filePath) - s.True(Write(filePath, "test data", 0644)) + s.Nil(Write(filePath, "test data", 0644)) s.FileExists(filePath) content, _ := os.ReadFile(filePath) diff --git a/routes/api.go b/routes/api.go index dbba61fb..5711baa9 100644 --- a/routes/api.go +++ b/routes/api.go @@ -37,9 +37,9 @@ func Api() { }) r.Prefix("website").Middleware(middleware.Jwt()).Group(func(r route.Router) { websiteController := controllers.NewWebsiteController() - r.Get("list", websiteController.List) - r.Post("add", websiteController.Add) - r.Delete("delete/{id}", websiteController.Delete) + r.Get("/", websiteController.List) + r.Post("/", websiteController.Add) + r.Delete("{id}", websiteController.Delete) r.Get("defaultConfig", websiteController.GetDefaultConfig) r.Post("defaultConfig", websiteController.SaveDefaultConfig) r.Get("config/{id}", websiteController.GetConfig) @@ -49,9 +49,9 @@ func Api() { r.Get("backupList", websiteController.BackupList) r.Post("createBackup", websiteController.CreateBackup) r.Post("uploadBackup", websiteController.UploadBackup) - r.Post("restoreBackup/{id}", websiteController.RestoreBackup) - r.Post("deleteBackup/{id}", websiteController.DeleteBackup) - r.Post("resetConfig/{id}", websiteController.ResetConfig) + r.Post("restoreBackup", websiteController.RestoreBackup) + r.Post("deleteBackup", websiteController.DeleteBackup) + r.Post("resetConfig", websiteController.ResetConfig) r.Post("status/{id}", websiteController.Status) }) r.Prefix("cert").Middleware(middleware.Jwt()).Group(func(r route.Router) {