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

refactor: 重构网站管理

This commit is contained in:
耗子
2023-11-11 03:19:06 +08:00
parent fe98a5be1b
commit 46e027b18c
44 changed files with 3954 additions and 506 deletions

View File

@@ -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("证书续签失败")
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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, "获取网站配置失败")
}

View File

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

View File

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

View File

@@ -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负载失败")
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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配置失败")
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,8 @@
package responses
import "panel/app/models"
type List struct {
Total int64 `json:"total"`
Items []models.Website `json:"items"`
}

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

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

2
go.mod
View File

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

4
go.sum
View File

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

View File

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

View File

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

View File

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

View File

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