feat: complete settings
This commit is contained in:
Generated
+8
@@ -0,0 +1,8 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
<component name="InspectionProjectProfileManager">
|
||||
<profile version="1.0">
|
||||
<option name="myName" value="Project Default" />
|
||||
<inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||
</profile>
|
||||
</component>
|
||||
Generated
+9
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="Go" enabled="true" />
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
Generated
+8
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/message-nest.iml" filepath="$PROJECT_DIR$/.idea/message-nest.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
Generated
+6
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -12,6 +12,7 @@ require (
|
||||
github.com/go-playground/validator/v10 v10.16.0
|
||||
github.com/google/uuid v1.5.0
|
||||
github.com/jinzhu/gorm v0.0.0-20180213101209-6e1387b44c64
|
||||
github.com/robfig/cron/v3 v3.0.1
|
||||
github.com/sirupsen/logrus v1.9.3
|
||||
github.com/unknwon/com v1.0.1
|
||||
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
|
||||
|
||||
@@ -86,6 +86,8 @@ github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOS
|
||||
github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
|
||||
@@ -4,6 +4,8 @@ import (
|
||||
"fmt"
|
||||
"log"
|
||||
"message-nest/pkg/table"
|
||||
"message-nest/service/cron_service"
|
||||
"message-nest/service/env_service"
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
@@ -21,6 +23,8 @@ func init() {
|
||||
logging.Setup()
|
||||
util.Setup()
|
||||
table.Setup()
|
||||
env_service.Setup()
|
||||
cron_service.Setup()
|
||||
}
|
||||
|
||||
// @title Golang Gin API
|
||||
|
||||
+8
-5
@@ -13,11 +13,14 @@ import (
|
||||
|
||||
var db *gorm.DB
|
||||
|
||||
//type Model struct {
|
||||
// ID int `gorm:"primary_key" json:"id"`
|
||||
// CreatedOn util.Time `json:"created_on"`
|
||||
// ModifiedOn util.Time `json:"modified_on"`
|
||||
//}
|
||||
type IDModel struct {
|
||||
ID int `gorm:"primary_key" json:"id"`
|
||||
|
||||
CreatedBy string `json:"created_by"`
|
||||
ModifiedBy string `json:"modified_by"`
|
||||
CreatedOn util.Time `json:"created_on"`
|
||||
ModifiedOn util.Time `json:"modified_on"`
|
||||
}
|
||||
|
||||
type UUIDModel struct {
|
||||
ID uuid.UUID `gorm:"primary_key" json:"id"`
|
||||
|
||||
@@ -44,13 +44,13 @@ func GetSendLogs(pageNum int, pageSize int, name string, taskId string, maps int
|
||||
query := db.
|
||||
Table(logt).
|
||||
Select(fmt.Sprintf("%s.*, %s.name as task_name", logt, taskt)).
|
||||
Joins(fmt.Sprintf("JOIN %s ON %s.task_id = %s.id", taskt, logt, taskt))
|
||||
Joins(fmt.Sprintf("LEFT JOIN %s ON %s.task_id = %s.id", taskt, logt, taskt))
|
||||
|
||||
if name != "" {
|
||||
query = query.Where(fmt.Sprintf("%s.name like ?", taskt), fmt.Sprintf("%%%s%%", name))
|
||||
}
|
||||
if taskId != "" {
|
||||
query = query.Where(fmt.Sprintf("%s.id = ?", taskt), taskId)
|
||||
query = query.Where(fmt.Sprintf("%s.task_id = ?", logt), taskId)
|
||||
}
|
||||
query = query.Order("created_on DESC")
|
||||
if pageSize > 0 || pageNum > 0 {
|
||||
@@ -68,13 +68,33 @@ func GetSendLogsTotal(name string, taskId string, maps interface{}) (int, error)
|
||||
taskt := table.TasksTableName
|
||||
query := db.
|
||||
Table(logt).
|
||||
Joins(fmt.Sprintf("JOIN %s ON %s.task_id = %s.id", taskt, logt, taskt))
|
||||
Joins(fmt.Sprintf("LEFT JOIN %s ON %s.task_id = %s.id", taskt, logt, taskt))
|
||||
if name != "" {
|
||||
query = query.Where(fmt.Sprintf("%s.name like ?", taskt), fmt.Sprintf("%%%s%%", name))
|
||||
}
|
||||
if taskId != "" {
|
||||
query = query.Where(fmt.Sprintf("%s.id = ?", taskt), taskId)
|
||||
query = query.Where(fmt.Sprintf("%s.task_id = ?", logt), taskId)
|
||||
}
|
||||
query.Count(&total)
|
||||
return total, nil
|
||||
}
|
||||
|
||||
// GetSendLogsTotal 获取所有日志总数
|
||||
func DeleteOutDateLogs(keepNum int) error {
|
||||
logt := table.LogsTableName
|
||||
sql := fmt.Sprintf(`DELETE FROM %s
|
||||
WHERE id NOT IN (
|
||||
SELECT id FROM (
|
||||
SELECT id
|
||||
FROM %s
|
||||
ORDER BY created_on DESC
|
||||
LIMIT %d
|
||||
) tmp
|
||||
);`, logt, logt, keepNum)
|
||||
|
||||
result := db.Exec(sql)
|
||||
if result.Error != nil {
|
||||
return result.Error
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/jinzhu/gorm"
|
||||
"message-nest/pkg/table"
|
||||
)
|
||||
|
||||
type Settings struct {
|
||||
IDModel
|
||||
|
||||
Section string `json:"section"`
|
||||
Key string `json:"key"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
// AddOneSetting 添加一条设置
|
||||
func AddOneSetting(setting Settings) error {
|
||||
if err := db.Create(&setting).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// EditSetting 编辑设置
|
||||
func EditSetting(id int, data interface{}) error {
|
||||
if err := db.Model(&Settings{}).Where("id = ? ", id).Updates(data).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteMsgTaskIns 删除一条设置
|
||||
func DeleteSettingByKey(section string, key string) error {
|
||||
if err := db.Where("`section` = ? and `key` = ? ", section, key).Delete(&Settings{}).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetSettingByKey(section string, key string) (Settings, error) {
|
||||
var setting Settings
|
||||
err := db.Where("`section` = ? and `key` = ? ", section, key).Find(&setting).Error
|
||||
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return setting, err
|
||||
}
|
||||
return setting, nil
|
||||
}
|
||||
|
||||
func GetSettingBySection(section string) ([]Settings, error) {
|
||||
var settings []Settings
|
||||
err := db.Table(table.SettingsTableName).Where("`section` = ? ", section).Scan(&settings).Error
|
||||
if err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return settings, err
|
||||
}
|
||||
return settings, nil
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package constant
|
||||
|
||||
var CleanLogsTaskId = "00000000-0000-0000-0000-000000000001"
|
||||
var SiteSettingSectionName = "site_config"
|
||||
|
||||
//var SiteSettingTitleKeyName = "title"
|
||||
//var SiteSettingSloganKeyName = "slogan"
|
||||
//var SiteSettingLogoKeyName = "logo"
|
||||
|
||||
// 站点信息默认值
|
||||
var SiteSiteDefaultValueMap = map[string]string{
|
||||
"title": "Message Nest",
|
||||
"slogan": "A Message Way Hosted Site",
|
||||
"logo": "<svg t=\"1702547210136\" class=\"icon\" viewBox=\"0 0 1024 1024\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\" p-id=\"1861\" width=\"200\" height=\"200\"><path d=\"M970.091313 224.033616a14.201535 14.201535 0 0 0-14.100687-3.631838c-88.419556-13.429657-142.919111-12.953859-248.242424 23.762747-69.454869 24.217859-109.056 79.873293-135.267556 116.712728-6.692202 9.403475-18.949172 26.625293-23.77309 29.509818-5.70699-1.303273-21.929374-16.036202-31.762101-24.965172-28.626747-25.994343-64.252121-58.353778-106.767516-58.757172-0.312889-0.005172-0.627071-0.005172-0.939959-0.005171-29.62101 0-54.798222 13.434828-72.857859 38.89907-13.222788 18.651798-17.914828 37.388929-18.106182 38.176323a14.31402 14.31402 0 0 0 2.893576 12.515556 14.336 14.336 0 0 0 11.782465 5.095434l0.409858-0.024565c19.192242-1.152 59.141172-3.545212 65.807516 81.857939 4.288646 54.899071 29.742545 108.631919 69.833697 147.419798 45.499475 44.025535 106.237414 67.298263 175.650909 67.298263 98.97503 0 166.222869-24.480323 205.207272-45.015919 43.172202-22.742626 62.621737-45.918384 63.429819-46.898425a14.170505 14.170505 0 0 0 1.529535-15.874586 14.191192 14.191192 0 0 0-14.166626-7.337373c-37.924202 4.443798-92.767677 6.09099-138.666667-11.298909-7.580444-2.872889-13.878303-5.893172-18.959515-8.691071 20.273131-9.964606 51.000889-28.383677 83.621495-59.93503 34.186343-33.065374 37.722505-69.908687 40.838464-102.423273 2.297535-23.919192 4.666182-48.651636 18.500526-73.091879 28.807758-50.883232 66.645333-74.489535 74.560646-79.035475a14.201535 14.201535 0 0 0 12.135434-7.776969 14.193778 14.193778 0 0 0-2.59103-16.484849z\" fill=\"\" p-id=\"1862\"></path><path d=\"M674.834101 716.481939c-33.422222 4.90796-74.989899 16.884364-117.22602-8.102787-34.843152-20.613172-53.056646-20.993293-77.783919-18.49794-0.156444 0.015515-0.312889 0.015515-0.469334 0.034909-0.274101 0.033616-0.548202 0.060768-0.822303 0.094384-4.697212 0.487434-9.65301 1.065374-14.995394 1.62004-6.702545 0.649051-13.414141 1.19596-20.133495 1.634263-75.333818 4.102465-136.860444-5.381172-163.012525-10.404202-49.488162-9.872808-86.57196-23.921778-108.946101-33.970424-59.832889-26.868364-87.080081-56.671677-87.080081-72.989738 0-1.873455 0.384-2.222545 0.787394-2.585858 2.196687-1.974303 10.616242-6.520242 41.302626-6.004364 24.793212 0.418909 56.970343 3.858101 94.308849 7.853253 40.722101 4.348121 86.873212 9.283232 136.348444 11.686788 6.913293 0.333576 13.959758 0.625778 20.93899 0.858505 9.510788 0.307717 17.545051-7.182222 17.868283-16.707233 0.319354-9.535354-7.175758-17.550222-16.705939-17.868282a1386.24 1386.24 0 0 1-20.419233-0.839112c-48.521051-2.358303-94.161455-7.236525-134.434909-11.544565-90.868364-9.712485-139.353212-13.818828-162.333737 6.833131-8.02004 7.21196-12.262141 17.004606-12.262141 28.317737 0 0.672323 0.029737 1.348525 0.065939 2.026021l0.005172 0.100848c-0.045253 0.524929-0.071111 1.039515-0.071111 1.539879 0 41.464242 9.561212 81.661414 28.414707 119.484768 17.493333 35.088808 42.251636 66.663434 73.583192 93.927434 9.169455-6.551273 20.155475-13.604202 32.524929-20.050748 49.737697-25.921939 97.838545-29.339152 139.099798-9.884444 101.590626 47.906909 142.060606 47.837091 206.198949-0.364606 5.70699-4.287354 13.814949-3.140525 18.103596 2.567758 4.289939 5.708283 3.140525 13.813657-2.567757 18.103595-38.425859 28.877576-69.968162 41.279354-105.143596 41.280647-0.484848 0-0.969697-0.002586-1.457132-0.007758-32.760242-0.316768-69.311354-11.381657-126.16404-38.190545-51.905939-24.47903-106.215434 1.008485-139.548444 23.465374 64.611556 47.922424 146.341495 74.101657 232.704 74.101656 117.55701 0 226.204444-48.934788 292.761858-131.362909l0.002586-0.002586c18.79402-14.959192 12.028121-41.362101-23.442101-36.152889z\" fill=\"\" p-id=\"1863\"></path></svg>",
|
||||
}
|
||||
|
||||
// 日志清理自定义
|
||||
var LogsCleanSectionName = "log_config"
|
||||
var LogsCleanCronKeyName = "cron"
|
||||
var LogsCleanKeepKeyName = "keep_num"
|
||||
|
||||
// 日志清理默认值
|
||||
var LogsCleanDefaultValueMap = map[string]string{
|
||||
"cron": "1 0 * * *",
|
||||
"keep_num": "1000",
|
||||
}
|
||||
|
||||
var AboutSectionName = "about"
|
||||
@@ -0,0 +1,15 @@
|
||||
package constant
|
||||
|
||||
var LatestVersion = map[string]string{}
|
||||
|
||||
//var info map[string]string
|
||||
|
||||
var V1Version = "v1.0.0"
|
||||
var V1VersionDesc = `1. 支持邮件消息发送
|
||||
2. 支持日志定时删除
|
||||
3. 支持账号密码重置`
|
||||
|
||||
func init() {
|
||||
LatestVersion["version"] = V1Version
|
||||
LatestVersion["desc"] = V1VersionDesc
|
||||
}
|
||||
@@ -27,8 +27,8 @@ type App struct {
|
||||
LogFileExt string
|
||||
TimeFormat string
|
||||
|
||||
LogKeepNum int
|
||||
CleanTaskLogID string
|
||||
//LogKeepNum int
|
||||
//CleanTaskLogID string
|
||||
}
|
||||
|
||||
var AppSetting = &App{}
|
||||
@@ -83,9 +83,9 @@ func Setup() {
|
||||
ServerSetting.WriteTimeout = ServerSetting.WriteTimeout * time.Second
|
||||
RedisSetting.IdleTimeout = RedisSetting.IdleTimeout * time.Second
|
||||
|
||||
// 默认值
|
||||
AppSetting.LogKeepNum = 1000
|
||||
AppSetting.CleanTaskLogID = "00000000-0000-0000-0000-000000000001"
|
||||
//// 默认值
|
||||
//AppSetting.LogKeepNum = 1000
|
||||
//AppSetting.CleanTaskLogID = "00000000-0000-0000-0000-000000000001"
|
||||
}
|
||||
|
||||
// mapTo map section
|
||||
|
||||
@@ -9,10 +9,12 @@ var InsTableName string
|
||||
var WayTableName string
|
||||
var LogsTableName string
|
||||
var TasksTableName string
|
||||
var SettingsTableName string
|
||||
|
||||
func Setup() {
|
||||
InsTableName = fmt.Sprintf("%ssend_tasks_ins", setting.DatabaseSetting.TablePrefix)
|
||||
WayTableName = fmt.Sprintf("%ssend_ways", setting.DatabaseSetting.TablePrefix)
|
||||
LogsTableName = fmt.Sprintf("%ssend_tasks_logs", setting.DatabaseSetting.TablePrefix)
|
||||
TasksTableName = fmt.Sprintf("%ssend_tasks", setting.DatabaseSetting.TablePrefix)
|
||||
SettingsTableName = fmt.Sprintf("%ssettings", setting.DatabaseSetting.TablePrefix)
|
||||
}
|
||||
|
||||
@@ -9,7 +9,30 @@ import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type EditUserPasswd struct {
|
||||
type GetSettingReq struct {
|
||||
Section string `json:"section" validate:"required,max=50" label:"节点"`
|
||||
}
|
||||
|
||||
// GetUserSetting 用户重设密码
|
||||
func GetUserSetting(c *gin.Context) {
|
||||
var (
|
||||
appG = app.Gin{C: c}
|
||||
)
|
||||
section := c.Query("section")
|
||||
|
||||
settingService := settings_service.UserSettings{}
|
||||
settings, err := settingService.GetUserSetting(section)
|
||||
if err != nil {
|
||||
appG.CResponse(http.StatusBadRequest, fmt.Sprintf("获取失败!错误原因:%s", err), nil)
|
||||
return
|
||||
}
|
||||
|
||||
appG.CResponse(http.StatusOK, "获取成功!", settings)
|
||||
|
||||
}
|
||||
|
||||
// EditUserPasswdReq 编辑设置请求
|
||||
type EditUserPasswdReq struct {
|
||||
OldPassword string `json:"old_passwd" validate:"required,max=50" label:"旧密码"`
|
||||
NewPassword string `json:"new_passwd" validate:"required,max=50" label:"新密码"`
|
||||
}
|
||||
@@ -18,7 +41,7 @@ type EditUserPasswd struct {
|
||||
func EditPasswd(c *gin.Context) {
|
||||
var (
|
||||
appG = app.Gin{C: c}
|
||||
req EditUserPasswd
|
||||
req EditUserPasswdReq
|
||||
)
|
||||
|
||||
currentUser := app.GetCurrentUserName(c)
|
||||
@@ -28,12 +51,12 @@ func EditPasswd(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
sendTaskService := settings_service.UserSettings{
|
||||
settingService := settings_service.UserSettings{
|
||||
UserName: currentUser,
|
||||
OldPassword: req.OldPassword,
|
||||
NewPassword: req.NewPassword,
|
||||
}
|
||||
err := sendTaskService.EditUserPasswd()
|
||||
err := settingService.EditUserPasswd()
|
||||
if err != nil {
|
||||
appG.CResponse(http.StatusBadRequest, fmt.Sprintf("修改密码失败!错误原因:%s", err), nil)
|
||||
return
|
||||
@@ -42,3 +65,39 @@ func EditPasswd(c *gin.Context) {
|
||||
appG.CResponse(http.StatusOK, "修改成功!", nil)
|
||||
|
||||
}
|
||||
|
||||
type SettingReq struct {
|
||||
Section string `json:"section" validate:"required,max=50" label:"一级分类"`
|
||||
Data map[string]string
|
||||
}
|
||||
|
||||
// EditSettings 编辑设置
|
||||
func EditSettings(c *gin.Context) {
|
||||
var (
|
||||
appG = app.Gin{C: c}
|
||||
req SettingReq
|
||||
)
|
||||
errCode, errStr := app.BindJsonAndPlayValid(c, &req)
|
||||
if errCode != e.SUCCESS {
|
||||
appG.CResponse(errCode, errStr, nil)
|
||||
return
|
||||
}
|
||||
|
||||
currentUser := app.GetCurrentUserName(c)
|
||||
settingService := settings_service.UserSettings{}
|
||||
diffStr := settingService.ValidateDiffSetting(req.Section, req.Data)
|
||||
if diffStr != "" {
|
||||
appG.CResponse(http.StatusBadRequest, diffStr, nil)
|
||||
return
|
||||
}
|
||||
for key, value := range req.Data {
|
||||
err := settingService.EditSettings(req.Section, key, value, currentUser)
|
||||
if err != nil {
|
||||
appG.CResponse(http.StatusBadRequest, fmt.Sprintf("修改密码失败!错误原因:%s", err), nil)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
appG.CResponse(http.StatusOK, "修改成功!", nil)
|
||||
|
||||
}
|
||||
|
||||
@@ -46,6 +46,8 @@ func InitRouter() *gin.Engine {
|
||||
|
||||
// settings
|
||||
apiv1.POST("/settings/setpasswd", v1.EditPasswd)
|
||||
apiv1.POST("/settings/set", v1.EditSettings)
|
||||
apiv1.GET("/settings/getsetting", v1.GetUserSetting)
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
package cron_service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/robfig/cron/v3"
|
||||
"github.com/unknwon/com"
|
||||
"message-nest/models"
|
||||
"message-nest/pkg/constant"
|
||||
"message-nest/pkg/logging"
|
||||
"message-nest/service/send_message_service"
|
||||
)
|
||||
|
||||
type CronService struct {
|
||||
}
|
||||
|
||||
var ClearLogsTaskId cron.EntryID
|
||||
|
||||
// 清除日志的定时任务
|
||||
func ClearLogs() {
|
||||
var logOutput []string
|
||||
var errStr string
|
||||
status := 1
|
||||
|
||||
sm := send_message_service.SendMessageService{TaskID: constant.CleanLogsTaskId}
|
||||
logging.Logger.Error("开始清除日志")
|
||||
logOutput = append(logOutput, "开始清除日志")
|
||||
|
||||
setting, err := models.GetSettingByKey(constant.LogsCleanSectionName, constant.LogsCleanKeepKeyName)
|
||||
if err != nil {
|
||||
errStr = fmt.Sprintf("获取日志的保留数失败,原因:%s", err)
|
||||
logging.Logger.Error(errStr)
|
||||
sm.MarkStatus(errStr, &status)
|
||||
logOutput = append(logOutput, errStr)
|
||||
}
|
||||
|
||||
keepNum := com.StrTo(setting.Value).MustInt()
|
||||
err = models.DeleteOutDateLogs(keepNum)
|
||||
if err != nil {
|
||||
errStr = fmt.Sprintf("删除日志失败,原因:%s", err)
|
||||
logging.Logger.Error(errStr)
|
||||
sm.MarkStatus(errStr, &status)
|
||||
logOutput = append(logOutput, errStr)
|
||||
} else {
|
||||
errStr = fmt.Sprintf("删除日志成功,保留数目:%d", keepNum)
|
||||
logging.Logger.Error(errStr)
|
||||
logOutput = append(logOutput, errStr)
|
||||
}
|
||||
sm.RecordSendLog(logOutput, status)
|
||||
}
|
||||
|
||||
// 启动注册清除任务定时任务
|
||||
func (cs *CronService) InitLogsCronRun() {
|
||||
setting, err := models.GetSettingByKey(constant.LogsCleanSectionName, constant.LogsCleanCronKeyName)
|
||||
if err != nil {
|
||||
logging.Logger.Error(fmt.Sprintf("获取日志的cron失败,原因:%s", err))
|
||||
}
|
||||
ClearLogsTaskId = AddTask(ScheduledTask{
|
||||
Schedule: setting.Value,
|
||||
Job: ClearLogs,
|
||||
})
|
||||
}
|
||||
|
||||
// 更新清除任务定时任务
|
||||
func (cs *CronService) UpdateLogsCronRun(cron string) {
|
||||
RemoveTask(ClearLogsTaskId)
|
||||
ClearLogsTaskId = AddTask(ScheduledTask{
|
||||
Schedule: cron,
|
||||
Job: ClearLogs,
|
||||
})
|
||||
logging.Logger.Error(fmt.Sprintf("更新日志的cron成功,%s", cron))
|
||||
logging.Logger.Info(fmt.Sprintf("所有的定时任务: %s", TaskList))
|
||||
|
||||
}
|
||||
|
||||
func Setup() {
|
||||
cs := CronService{}
|
||||
cs.InitLogsCronRun()
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package cron_service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/robfig/cron/v3"
|
||||
"message-nest/pkg/logging"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type ScheduledTask struct {
|
||||
//ID int
|
||||
Schedule string
|
||||
Job func()
|
||||
}
|
||||
|
||||
var (
|
||||
CronInstance *cron.Cron
|
||||
TaskList map[cron.EntryID]*ScheduledTask
|
||||
mutex sync.Mutex
|
||||
)
|
||||
|
||||
func init() {
|
||||
CronInstance = cron.New()
|
||||
CronInstance.Start()
|
||||
TaskList = make(map[cron.EntryID]*ScheduledTask)
|
||||
}
|
||||
|
||||
// 添加定时任务
|
||||
func AddTask(task ScheduledTask) cron.EntryID {
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
|
||||
taskId, err := CronInstance.AddFunc(task.Schedule, task.Job)
|
||||
if err != nil {
|
||||
// 处理错误
|
||||
logging.Logger.Error(fmt.Sprintf("添加定时任务失败,原因:%s", err))
|
||||
} else {
|
||||
TaskList[taskId] = &task
|
||||
logging.Logger.Error(fmt.Sprintf("添加日志清除任务成功,entryID: %d", taskId))
|
||||
}
|
||||
return taskId
|
||||
}
|
||||
|
||||
// 删除定时任务
|
||||
func RemoveTask(taskID cron.EntryID) {
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
if _, ok := TaskList[taskID]; ok {
|
||||
CronInstance.Remove(taskID)
|
||||
delete(TaskList, taskID)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package env_service
|
||||
|
||||
import (
|
||||
"message-nest/models"
|
||||
"message-nest/pkg/constant"
|
||||
"message-nest/pkg/logging"
|
||||
)
|
||||
|
||||
type EnvService struct {
|
||||
}
|
||||
|
||||
func (es *EnvService) CommonAdd(section string, key string, value string) {
|
||||
setting, _ := models.GetSettingByKey(section, key)
|
||||
if setting.ID <= 0 {
|
||||
err := models.AddOneSetting(models.Settings{
|
||||
Section: section,
|
||||
Key: key,
|
||||
Value: value,
|
||||
})
|
||||
if err != nil {
|
||||
logging.Logger.Error("初始化%s:%s失败", section, key)
|
||||
} else {
|
||||
logging.Logger.Infof("初始化%s:%s成功", section, key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// InitSiteConfig 初始化、重置站点信息设置
|
||||
func (es *EnvService) InitSiteConfig() {
|
||||
section := constant.SiteSettingSectionName
|
||||
for key, value := range constant.SiteSiteDefaultValueMap {
|
||||
es.CommonAdd(section, key, value)
|
||||
}
|
||||
}
|
||||
|
||||
// InitLogConfig 初始化日志清理设置
|
||||
func (es *EnvService) InitLogConfig() {
|
||||
section := constant.LogsCleanSectionName
|
||||
for key, value := range constant.LogsCleanDefaultValueMap {
|
||||
es.CommonAdd(section, key, value)
|
||||
}
|
||||
}
|
||||
|
||||
func Setup() {
|
||||
es := EnvService{}
|
||||
es.InitSiteConfig()
|
||||
es.InitLogConfig()
|
||||
}
|
||||
@@ -2,7 +2,12 @@ package settings_service
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/robfig/cron/v3"
|
||||
"message-nest/models"
|
||||
"message-nest/pkg/app"
|
||||
"message-nest/pkg/constant"
|
||||
"message-nest/service/cron_service"
|
||||
)
|
||||
|
||||
type UserSettings struct {
|
||||
@@ -21,3 +26,88 @@ func (us *UserSettings) EditUserPasswd() error {
|
||||
user["password"] = us.NewPassword
|
||||
return models.EditUser(us.UserName, user)
|
||||
}
|
||||
|
||||
// GetUserSetting 获取用户设置
|
||||
func (us *UserSettings) GetUserSetting(section string) (map[string]string, error) {
|
||||
result := make(map[string]string)
|
||||
settings, err := models.GetSettingBySection(section)
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
for _, setting := range settings {
|
||||
result[setting.Key] = setting.Value
|
||||
}
|
||||
// 版本信息单独获取
|
||||
if section == constant.AboutSectionName {
|
||||
result = constant.LatestVersion
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// EditSettings 便捷自定义设置
|
||||
func (us *UserSettings) EditSettings(section string, key string, value string, currentUser string) error {
|
||||
setting, _ := models.GetSettingByKey(section, key)
|
||||
if setting.ID <= 0 {
|
||||
err := models.AddOneSetting(models.Settings{
|
||||
IDModel: models.IDModel{
|
||||
CreatedBy: currentUser,
|
||||
ModifiedBy: currentUser,
|
||||
},
|
||||
Section: section,
|
||||
Key: key,
|
||||
Value: value,
|
||||
})
|
||||
return err
|
||||
} else {
|
||||
if value == "" {
|
||||
return nil
|
||||
}
|
||||
data := make(map[string]interface{})
|
||||
data["section"] = section
|
||||
data["key"] = key
|
||||
data["value"] = value
|
||||
data["modified_by"] = currentUser
|
||||
err := models.EditSetting(setting.ID, data)
|
||||
if key == constant.LogsCleanCronKeyName {
|
||||
cronService := cron_service.CronService{}
|
||||
cronService.UpdateLogsCronRun(value)
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// 站点自定义的结构
|
||||
type SiteConfig struct {
|
||||
Title string `json:"title" validate:"omitempty,min=1,max=50" label:"网站标题"`
|
||||
Slogan string `json:"slogan" validate:"omitempty,min=1,max=50" label:"网站slogan"`
|
||||
Logo string `json:"logo" validate:"omitempty,min=1" label:"logo"`
|
||||
}
|
||||
|
||||
type LogConfig struct {
|
||||
Cron string `json:"cron" validate:"required,cron" label:"日志定时表达式"`
|
||||
KeepNum string `json:"keep_num" validate:"required,min=1,max=50" label:"日志保留数"`
|
||||
}
|
||||
|
||||
// ValidateDiffSetting 校验不同的设置
|
||||
func (us *UserSettings) ValidateDiffSetting(section string, data map[string]string) string {
|
||||
if section == constant.SiteSettingSectionName {
|
||||
var config SiteConfig
|
||||
config.Title = data["title"]
|
||||
config.Slogan = data["slogan"]
|
||||
config.Logo = data["logo"]
|
||||
_, errStr := app.CommonPlaygroundValid(config)
|
||||
return errStr
|
||||
}
|
||||
if section == constant.LogsCleanSectionName {
|
||||
var config LogConfig
|
||||
config.Cron = data["cron"]
|
||||
config.KeepNum = data["keep_num"]
|
||||
_, err := cron.ParseStandard(config.Cron)
|
||||
if err != nil {
|
||||
return fmt.Sprintf("%s 不是合法的corn表达式", config.Cron)
|
||||
}
|
||||
_, errStr := app.CommonPlaygroundValid(config)
|
||||
return errStr
|
||||
}
|
||||
return fmt.Sprintf("未知的section:%s", section)
|
||||
}
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
<el-menu-item index="logCleanSetting">
|
||||
日志清理
|
||||
</el-menu-item>
|
||||
<el-menu-item index="siteCustomSetting">
|
||||
<!-- <el-menu-item index="siteCustomSetting">
|
||||
站点设置
|
||||
</el-menu-item>
|
||||
</el-menu-item> -->
|
||||
<el-menu-item index="aboutSetting">
|
||||
站点关于
|
||||
</el-menu-item>
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
<template>
|
||||
<div class="setting-container">
|
||||
<el-text size="small">当前版本:v1.0.0</el-text>
|
||||
<el-text size="small">当前版本:{{ version }}</el-text>
|
||||
<div class="buttom">
|
||||
<div class="tips">
|
||||
<el-text size="small">版本功能说明</el-text>
|
||||
<el-tooltip placement="top">
|
||||
<template #content>
|
||||
logo请输入svg文本,替换后登录页面、ico、导航栏logo将全部一起更换
|
||||
<br />
|
||||
*将在下一次登录的时候生效
|
||||
<div v-html="desc"></div>
|
||||
</template>
|
||||
<el-icon>
|
||||
<QuestionFilled />
|
||||
@@ -20,7 +18,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent, reactive, toRefs } from 'vue';
|
||||
import { defineComponent, reactive, toRefs, onMounted } from 'vue';
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { request } from '@/api/api'
|
||||
import { QuestionFilled } from '@element-plus/icons-vue'
|
||||
@@ -35,8 +33,8 @@ export default defineComponent({
|
||||
},
|
||||
setup() {
|
||||
const state = reactive({
|
||||
oldPasswd: '',
|
||||
newPasswd: '',
|
||||
version: '',
|
||||
desc: '',
|
||||
});
|
||||
|
||||
const handleChange = async () => {
|
||||
@@ -47,6 +45,21 @@ export default defineComponent({
|
||||
ElMessage({ message: msg, type: 'success' })
|
||||
}
|
||||
}
|
||||
|
||||
const getAbout = async () => {
|
||||
let params = { params: { section: "about" } };
|
||||
const rsp = await request.get('/settings/getsetting', params);
|
||||
if (await rsp.data.code == 200) {
|
||||
let data = await rsp.data.data;
|
||||
state.version = data.version;
|
||||
state.desc = data.desc.replace(/\n/g, '<br />');
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getAbout();
|
||||
})
|
||||
|
||||
return {
|
||||
...toRefs(state), handleChange
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<el-input v-model="cron" size="small" placeholder="请输入定时日志清除的Cron表达式">
|
||||
<template size="small" #prepend>cron://</template>
|
||||
</el-input>
|
||||
<el-input v-model.number="keepNum" size="small" placeholder="请输入要保留的最近的日志条数" style="margin-top: 15px;">
|
||||
<el-input v-model="keepNum" size="small" placeholder="请输入要保留的最近的日志条数" style="margin-top: 15px;">
|
||||
<template size="small" #prepend>保留数</template>
|
||||
</el-input>
|
||||
</div>
|
||||
@@ -29,7 +29,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent, reactive, toRefs } from 'vue';
|
||||
import { defineComponent, reactive, toRefs, onMounted } from 'vue';
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { QuestionFilled } from '@element-plus/icons-vue'
|
||||
import { useRouter } from 'vue-router';
|
||||
@@ -47,13 +47,20 @@ export default defineComponent({
|
||||
setup() {
|
||||
const router = useRouter();
|
||||
const state = reactive({
|
||||
section: 'log_config',
|
||||
cron: '',
|
||||
keepNum: 1000,
|
||||
keepNum: '1000',
|
||||
});
|
||||
|
||||
const handleSubmit = async () => {
|
||||
let postData = { old_passwd: state.oldPasswd, new_passwd: state.newPasswd };
|
||||
const rsp = await request.post('/settings/setpasswd', postData);
|
||||
let postData = {
|
||||
section: state.section,
|
||||
data: {
|
||||
cron: state.cron.trim(),
|
||||
keep_num: state.keepNum.trim(),
|
||||
},
|
||||
};
|
||||
const rsp = await request.post('/settings/set', postData);
|
||||
if (await rsp.data.code == 200) {
|
||||
let msg = await rsp.data.msg;
|
||||
ElMessage({ message: msg, type: 'success' })
|
||||
@@ -62,6 +69,21 @@ export default defineComponent({
|
||||
const handleView = async () => {
|
||||
router.push('/sendlogs?taskid=' + CONSTANT.LOG_TASK_ID, { replace: true });
|
||||
}
|
||||
|
||||
const getSiteConfig = async () => {
|
||||
let params = { params: { section: "log_config" } };
|
||||
const rsp = await request.get('/settings/getsetting', params);
|
||||
if (await rsp.data.code == 200) {
|
||||
let data = await rsp.data.data;
|
||||
state.cron = data.cron;
|
||||
state.keepNum = data.keep_num;
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getSiteConfig();
|
||||
})
|
||||
|
||||
return {
|
||||
...toRefs(state), handleSubmit, handleView
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<el-tooltip placement="top">
|
||||
<template #content>
|
||||
1. logo请输入svg文本,替换后登录页面,ico,导航栏logo将全部一起更换
|
||||
<br />
|
||||
<br />
|
||||
2. slogan将在登录页面展示
|
||||
<br />
|
||||
*将在下一次登录的时候生效
|
||||
@@ -27,14 +27,14 @@
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</div>
|
||||
<el-button @click="handleView" size="small">查看日志</el-button>
|
||||
<el-button @click="handleView" size="small">恢复默认</el-button>
|
||||
<el-button @click="handleSubmit" size="small" type="primary">确定</el-button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent, reactive, toRefs } from 'vue';
|
||||
import { defineComponent, reactive, toRefs, onMounted } from 'vue';
|
||||
import { ElMessage } from 'element-plus'
|
||||
import { QuestionFilled } from '@element-plus/icons-vue'
|
||||
import { useRouter } from 'vue-router';
|
||||
@@ -55,11 +55,19 @@ export default defineComponent({
|
||||
title: '',
|
||||
slogan: '',
|
||||
logo: '',
|
||||
section: 'site_config',
|
||||
});
|
||||
|
||||
const handleSubmit = async () => {
|
||||
let postData = { old_passwd: state.oldPasswd, new_passwd: state.newPasswd };
|
||||
const rsp = await request.post('/settings/setpasswd', postData);
|
||||
let postData = {
|
||||
section: state.section,
|
||||
data: {
|
||||
title: state.title.trim(),
|
||||
slogan: state.slogan.trim(),
|
||||
logo: state.logo.trim(),
|
||||
},
|
||||
};
|
||||
const rsp = await request.post('/settings/set', postData);
|
||||
if (await rsp.data.code == 200) {
|
||||
let msg = await rsp.data.msg;
|
||||
ElMessage({ message: msg, type: 'success' })
|
||||
@@ -68,6 +76,22 @@ export default defineComponent({
|
||||
const handleView = async () => {
|
||||
router.push('/sendlogs?taskid=' + CONSTANT.LOG_TASK_ID, { replace: true });
|
||||
}
|
||||
|
||||
const getSiteConfig = async () => {
|
||||
let params = { params: { section: "site_config" } };
|
||||
const rsp = await request.get('/settings/getsetting', params);
|
||||
if (await rsp.data.code == 200) {
|
||||
let data = await rsp.data.data;
|
||||
state.title = data.title;
|
||||
state.logo = data.logo;
|
||||
state.slogan = data.slogan;
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
getSiteConfig();
|
||||
})
|
||||
|
||||
return {
|
||||
...toRefs(state), handleSubmit, handleView
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user