diff --git a/docs/guide-zh-CN/start-deploy.md b/docs/guide-zh-CN/start-deploy.md index 366c520..bc45833 100644 --- a/docs/guide-zh-CN/start-deploy.md +++ b/docs/guide-zh-CN/start-deploy.md @@ -60,7 +60,7 @@ echo "y" | gf build # 编译hotgo服务端 ### 启动服务 -> 这里推可以接使用gf官方推荐的启动方式,请参考:https://goframe.org/pages/viewpage.action?pageId=1114403 +> 这里可以接使用gf官方推荐的启动方式,请参考:https://goframe.org/pages/viewpage.action?pageId=1114403 ### Nginx配置 diff --git a/docs/guide-zh-CN/start-questions.md b/docs/guide-zh-CN/start-questions.md index 3a77860..843b631 100644 --- a/docs/guide-zh-CN/start-questions.md +++ b/docs/guide-zh-CN/start-questions.md @@ -4,7 +4,7 @@ - 平台: windows/linux - 软件与版本:golang 1.18, Mysql 5.7 ... -- 系统版本:gotho 2.1.4 +- 系统版本:hotgo 2.1.4 #### 你做了什么? diff --git a/docs/guide-zh-CN/start-update-log.md b/docs/guide-zh-CN/start-update-log.md index f42feba..2ce9a62 100644 --- a/docs/guide-zh-CN/start-update-log.md +++ b/docs/guide-zh-CN/start-update-log.md @@ -11,6 +11,14 @@ > 如果升级(覆盖)代码后打开会出现 sql 报错, 请检查更新的数据库格式或自行调整 + +### v2.5.3 +updated 2023.04.10 +- 优化:优化IP地理位置定位,增加地理位置缓存,避免相同IP并发操作 +- 优化:优化日志管理中相关列表字段过多在小屏设备列表不显示滚动条情况 +- 增加:增加短信驱动:腾讯云短信,可通过后台一键切换 +- 修复:修复角色权限选择自定义部门时,部门选项无法显示问题 + ### v2.4.9 updated 2023.04.05 - 优化:优化全局日志数据加载和分页加载,大分页增加分批次加载 diff --git a/server/api/admin/smslog/smslog.go b/server/api/admin/smslog/smslog.go index 4268db3..3ffa1fc 100644 --- a/server/api/admin/smslog/smslog.go +++ b/server/api/admin/smslog/smslog.go @@ -9,12 +9,8 @@ import ( // ListReq 查询列表 type ListReq struct { - form.PageReq - form.RangeDateReq - form.StatusReq - Title string `json:"title"` - Content string `json:"content"` - g.Meta `path:"/smsLog/list" method:"get" tags:"短信记录" summary:"获取短信记录列表"` + g.Meta `path:"/smsLog/list" method:"get" tags:"短信记录" summary:"获取短信记录列表"` + sysin.SmsLogListInp } type ListRes struct { diff --git a/server/go.mod b/server/go.mod index 788f08e..9b4b647 100644 --- a/server/go.mod +++ b/server/go.mod @@ -15,6 +15,7 @@ require ( github.com/casbin/casbin/v2 v2.55.0 github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/forgoer/openssl v1.4.0 + github.com/fwhezfwhez/errorx v1.1.0 github.com/go-resty/resty/v2 v2.7.0 github.com/gogf/gf/contrib/drivers/mysql/v2 v2.3.3 github.com/gogf/gf/contrib/nosql/redis/v2 v2.3.3 @@ -27,8 +28,11 @@ require ( github.com/qiniu/go-sdk/v7 v7.14.0 github.com/shirou/gopsutil/v3 v3.23.3 github.com/shopspring/decimal v1.3.1 + github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.633 + github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/sms v1.0.633 github.com/tencentyun/cos-go-sdk-v5 v0.7.41 github.com/ufilesdk-dev/ufile-gosdk v1.0.3 + github.com/xtaci/kcp-go v5.4.20+incompatible github.com/xuri/excelize/v2 v2.6.0 golang.org/x/tools v0.6.0 gopkg.in/yaml.v3 v3.0.1 @@ -60,6 +64,7 @@ require ( github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-redis/redis/v8 v8.11.5 // indirect github.com/go-sql-driver/mysql v1.7.0 // indirect + github.com/gofrs/uuid v4.0.0+incompatible // indirect github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect github.com/golang/mock v1.6.0 // indirect github.com/golang/snappy v0.0.4 // indirect @@ -76,6 +81,8 @@ require ( github.com/jcmturner/rpc/v2 v2.0.3 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.15.6 // indirect + github.com/klauspost/cpuid/v2 v2.1.1 // indirect + github.com/klauspost/reedsolomon v1.11.7 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/mattn/go-colorable v0.1.13 // indirect @@ -95,12 +102,15 @@ require ( github.com/rivo/uniseg v0.4.4 // indirect github.com/shoenig/go-m1cpu v0.1.4 // indirect github.com/sirupsen/logrus v1.8.1 // indirect + github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 // indirect + github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b // indirect github.com/tidwall/gjson v1.2.1 // indirect github.com/tidwall/match v1.0.1 // indirect github.com/tidwall/pretty v0.0.0-20190325153808-1166b9ac2b65 // indirect github.com/tjfoc/gmsm v1.3.2 // indirect github.com/tklauser/go-sysconf v0.3.11 // indirect github.com/tklauser/numcpus v0.6.0 // indirect + github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37 // indirect github.com/xuri/efp v0.0.0-20220407160117-ad0f7a785be8 // indirect github.com/xuri/nfp v0.0.0-20220409054826-5e722a1d9e22 // indirect github.com/yusufpapurcu/wmi v1.2.2 // indirect diff --git a/server/go.sum b/server/go.sum index 6d2cac5..a1fe287 100644 --- a/server/go.sum +++ b/server/go.sum @@ -140,6 +140,8 @@ github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5 github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/fwhezfwhez/errorx v1.1.0 h1:795cMWZFM+thQfKaC5Cjnp/h6naUEbsoQxOb/yvwn0c= +github.com/fwhezfwhez/errorx v1.1.0/go.mod h1:epOraH2nrfmf4JUao5290NFuXw9t6MZnzgwoW5guABE= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -172,6 +174,8 @@ github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= +github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogf/gf/contrib/drivers/mysql/v2 v2.3.3 h1:McqosVS9Bm7SzmsMTwfVT0YX6i/Is2aRn/XfqW/0iSI= github.com/gogf/gf/contrib/drivers/mysql/v2 v2.3.3/go.mod h1:z+/0qiOwMroAnj5ESuobTv0l5P83rf+XR3r6Fj8WJyk= github.com/gogf/gf/contrib/nosql/redis/v2 v2.3.3 h1:t1DA5NbyOk7FrDtFtJ5nS+RuGkmhJ9dUsQQKh5G3LOE= @@ -302,6 +306,10 @@ github.com/kayon/iploc v0.0.0-20200312105652-bda3e968a794/go.mod h1:IwrOeG3O3K9v github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.15.6 h1:6D9PcO8QWu0JyaQ2zUMmu16T1T+zjjEpP91guRsvDfY= github.com/klauspost/compress v1.15.6/go.mod h1:PhcZ0MbTNciWF3rruxRgKxI5NkcHHrHUDtV4Yw2GlzU= +github.com/klauspost/cpuid/v2 v2.1.1 h1:t0wUqjowdm8ezddV5k0tLWVklVuvLJpoHeb4WBdydm0= +github.com/klauspost/cpuid/v2 v2.1.1/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY= +github.com/klauspost/reedsolomon v1.11.7 h1:9uaHU0slncktTEEg4+7Vl7q7XUNMBUOK4R9gnKhMjAU= +github.com/klauspost/reedsolomon v1.11.7/go.mod h1:4bXRN+cVzMdml6ti7qLouuYi32KHJ5MGv0Qd8a47h6A= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= @@ -449,8 +457,16 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161 h1:89CEmDvlq/F7SJEOqkIdNDGJXrQIhuIx9D2DBXjavSU= +github.com/templexxx/cpufeat v0.0.0-20180724012125-cef66df7f161/go.mod h1:wM7WEvslTq+iOEAMDLSzhVuOt5BRZ05WirO+b09GHQU= +github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b h1:fj5tQ8acgNUr6O8LEplsxDhUIe2573iLkJc+PqnzZTI= +github.com/templexxx/xor v0.0.0-20191217153810-f85b25db303b/go.mod h1:5XA7W9S6mni3h5uvOC75dA3m9CCCaS83lltmc0ukdi4= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.194/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.633 h1:Yj8s35IjbgaHp4Ic9BZLVGWdN2gXBMtwYi1JJ+qYbrc= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.633/go.mod h1:7sCQWVkxcsR38nffDW057DRGk8mUjK1Ing/EFOK8s8Y= github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/kms v1.0.194/go.mod h1:yrBKWhChnDqNz1xuXdSbWXG56XawEq0G5j1lg4VwBD4= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/sms v1.0.633 h1:rtgRqgZNwDD665V02y2WBtZdVc/OmMNta3CAWgcGiS8= +github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/sms v1.0.633/go.mod h1:9q29WcGkZ7R0uQjoY10Tzb8A18C2cNggbq2ZC2HRXZE= github.com/tencentyun/cos-go-sdk-v5 v0.7.41 h1:iU0Li/Np78H4SBna0ECQoF3mpgi6ImLXU+doGzPFXGc= github.com/tencentyun/cos-go-sdk-v5 v0.7.41/go.mod h1:4dCEtLHGh8QPxHEkgq+nFaky7yZxQuYwgSJM87icDaw= github.com/tidwall/gjson v1.2.1 h1:j0efZLrZUvNerEf6xqoi0NjWMK5YlLrR7Guo/dxY174= @@ -471,6 +487,10 @@ github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/X github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= +github.com/xtaci/kcp-go v5.4.20+incompatible h1:TN1uey3Raw0sTz0Fg8GkfM0uH3YwzhnZWQ1bABv5xAg= +github.com/xtaci/kcp-go v5.4.20+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45a+AZwO7eyRCmEIbtvE= +github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37 h1:EWU6Pktpas0n8lLQwDsRyZfmkPeRbdgPtW609es+/9E= +github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37/go.mod h1:HpMP7DB2CyokmAh4lp0EQnnWhmycP/TvwBGzvuie+H0= github.com/xuri/efp v0.0.0-20220407160117-ad0f7a785be8 h1:3X7aE0iLKJ5j+tz58BpvIZkXNV7Yq4jC93Z/rbN2Fxk= github.com/xuri/efp v0.0.0-20220407160117-ad0f7a785be8/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI= github.com/xuri/excelize/v2 v2.6.0 h1:m/aXAzSAqxgt74Nfd+sNzpzVKhTGl7+S9nbG4A57mF4= @@ -674,6 +694,7 @@ golang.org/x/sys v0.0.0-20211020174200-9d6173849985/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/server/internal/consts/sms.go b/server/internal/consts/sms.go index b42f4b9..8ca4b7a 100644 --- a/server/internal/consts/sms.go +++ b/server/internal/consts/sms.go @@ -17,6 +17,17 @@ const ( SmsTemplateCash = "cash" // 申请提现 ) +var ( + SmsTemplateEventMap = map[string]string{ + SmsTemplateCode: "通用验证码", + SmsTemplateLogin: "登录", + SmsTemplateRegister: "注册", + SmsTemplateResetPwd: "重置密码", + SmsTemplateBind: "绑定手机号", + SmsTemplateCash: "申请提现", + } +) + // 验证码状态 const ( SmsStatusNotUsed = 1 // 未使用 diff --git a/server/internal/consts/version.go b/server/internal/consts/version.go index 340d543..1cb9dd2 100644 --- a/server/internal/consts/version.go +++ b/server/internal/consts/version.go @@ -7,5 +7,5 @@ package consts // VersionApp HotGo版本 const ( - VersionApp = "2.4.9" + VersionApp = "2.5.3" ) diff --git a/server/internal/controller/admin/sys/sms_log.go b/server/internal/controller/admin/sys/sms_log.go index 1c647a5..7efea74 100644 --- a/server/internal/controller/admin/sys/sms_log.go +++ b/server/internal/controller/admin/sys/sms_log.go @@ -3,7 +3,6 @@ // @Copyright Copyright (c) 2023 HotGo CLI // @Author Ms <133814250@qq.com> // @License https://github.com/bufanyun/hotgo/blob/master/LICENSE -// package sys import ( @@ -13,6 +12,7 @@ import ( "hotgo/internal/model/input/form" "hotgo/internal/model/input/sysin" "hotgo/internal/service" + "hotgo/utility/validate" ) var ( @@ -74,6 +74,10 @@ func (c *cSmsLog) List(ctx context.Context, req *smslog.ListReq) (res *smslog.Li return } + if err = validate.PreFilter(ctx, &in); err != nil { + return + } + list, totalCount, err := service.SysSmsLog().List(ctx, in) if err != nil { return diff --git a/server/internal/library/location/location.go b/server/internal/library/location/location.go index 4a0176f..7a22ba2 100644 --- a/server/internal/library/location/location.go +++ b/server/internal/library/location/location.go @@ -3,13 +3,13 @@ // @Copyright Copyright (c) 2023 HotGo CLI // @Author Ms <133814250@qq.com> // @License https://github.com/bufanyun/hotgo/blob/master/LICENSE -// package location import ( "context" "fmt" "github.com/axgle/mahonia" + "github.com/gogf/gf/v2/container/gmap" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/net/ghttp" "github.com/gogf/gf/v2/text/gstr" @@ -52,6 +52,12 @@ type WhoisRegionData struct { Err string `json:"err"` } +var cacheMap *gmap.Map + +func init() { + cacheMap = gmap.New(true) +} + // WhoisLocation 通过Whois接口查询IP归属地 func WhoisLocation(ctx context.Context, ip string) (*IpLocationData, error) { response, err := g.Client().Timeout(10*time.Second).Get(ctx, whoisApi+ip) @@ -120,7 +126,7 @@ func IsJurisByIpTitle(title string) bool { } // GetLocation 获取IP归属地信息 -func GetLocation(ctx context.Context, ip string) (*IpLocationData, error) { +func GetLocation(ctx context.Context, ip string) (data *IpLocationData, err error) { if !validate.IsIp(ip) { return nil, fmt.Errorf("invalid input ip:%v", ip) } @@ -128,11 +134,34 @@ func GetLocation(ctx context.Context, ip string) (*IpLocationData, error) { if validate.IsLocalIPAddr(ip) { return nil, fmt.Errorf("must be a public ip:%v", ip) } - method := g.Cfg().MustGet(ctx, "hotgo.ipMethod", "cz88") - if method.String() == "whois" { - return WhoisLocation(ctx, ip) + + if cacheMap.Contains(ip) { + value := cacheMap.Get(ip) + data1, ok := value.(*IpLocationData) + if !ok { + cacheMap.Remove(ip) + err = fmt.Errorf("data assertion failed in the cache ip:%v", ip) + return + } + return data1, nil } - return Cz88Find(ctx, ip) + + mode := g.Cfg().MustGet(ctx, "hotgo.ipMethod", "cz88").String() + switch mode { + case "whois": + data, err = WhoisLocation(ctx, ip) + default: + data, err = Cz88Find(ctx, ip) + } + + if err == nil && data != nil { + if cacheMap.Size() > 20000 { + cacheMap.Clear() + } + cacheMap.Set(ip, data) + } + + return } // GetPublicIP 获取公网IP @@ -195,7 +224,7 @@ func GetClientIp(r *ghttp.Request) string { ip = r.GetClientIp() } - // 如果存在多个,默认取第一个 + // 兼容部分云厂商CDN,如果存在多个,默认取第一个 if gstr.Contains(ip, ",") { ip = gstr.StrTillEx(ip, ",") } diff --git a/server/internal/library/sms/aliyun/handle.go b/server/internal/library/sms/aliyun/handle.go index 7c150fa..bca5393 100644 --- a/server/internal/library/sms/aliyun/handle.go +++ b/server/internal/library/sms/aliyun/handle.go @@ -7,13 +7,20 @@ import ( dysmsapi20170525 "github.com/alibabacloud-go/dysmsapi-20170525/v3/client" util "github.com/alibabacloud-go/tea-utils/v2/service" "github.com/alibabacloud-go/tea/tea" + "github.com/gogf/gf/v2/frame/g" "hotgo/internal/model" "hotgo/internal/model/input/sysin" "hotgo/internal/service" ) +var ( + Handle = aliYun{} +) + +type aliYun struct{} + // SendCode 发送验证码 -func SendCode(ctx context.Context, in sysin.SendCodeInp, config *model.SmsConfig) (err error) { +func (d *aliYun) SendCode(ctx context.Context, in sysin.SendCodeInp, config *model.SmsConfig) (err error) { if config == nil { config, err = service.SysConfig().GetSms(ctx) if err != nil { @@ -21,14 +28,14 @@ func SendCode(ctx context.Context, in sysin.SendCodeInp, config *model.SmsConfig } } - client, err := CreateClient(tea.String(config.SmsAliyunAccessKeyID), tea.String(config.SmsAliyunAccessKeySecret)) + client, err := CreateClient(tea.String(config.AliYunAccessKeyID), tea.String(config.AliYunAccessKeySecret)) if err != nil { return err } sendSmsRequest := &dysmsapi20170525.SendSmsRequest{ PhoneNumbers: tea.String(in.Mobile), - SignName: tea.String(config.SmsAliyunSign), + SignName: tea.String(config.AliYunSign), TemplateCode: tea.String(in.Template), TemplateParam: tea.String(fmt.Sprintf("{\"code\":\"%v\"}", in.Code)), } @@ -41,11 +48,13 @@ func SendCode(ctx context.Context, in sysin.SendCodeInp, config *model.SmsConfig }() // 复制代码运行请自行打印 API 的返回值 - _, err = client.SendSmsWithOptions(sendSmsRequest, &util.RuntimeOptions{}) + response, err := client.SendSmsWithOptions(sendSmsRequest, &util.RuntimeOptions{}) if err != nil { return err } + g.Log().Debugf(ctx, "aliyun.sendCode response:%+v", response.GoString()) + return nil }() return tryErr diff --git a/server/internal/library/sms/aliyun/init.go b/server/internal/library/sms/aliyun/init.go deleted file mode 100644 index 62a2332..0000000 --- a/server/internal/library/sms/aliyun/init.go +++ /dev/null @@ -1 +0,0 @@ -package aliyun diff --git a/server/internal/library/sms/aliyun/model.go b/server/internal/library/sms/aliyun/model.go deleted file mode 100644 index 62a2332..0000000 --- a/server/internal/library/sms/aliyun/model.go +++ /dev/null @@ -1 +0,0 @@ -package aliyun diff --git a/server/internal/library/sms/sms.go b/server/internal/library/sms/sms.go index d6fb06e..55a495a 100644 --- a/server/internal/library/sms/sms.go +++ b/server/internal/library/sms/sms.go @@ -1,2 +1,38 @@ package sms +import ( + "context" + "fmt" + "hotgo/internal/consts" + "hotgo/internal/library/sms/aliyun" + "hotgo/internal/library/sms/tencent" + "hotgo/internal/model" + "hotgo/internal/model/input/sysin" +) + +// SmsDrive 短信驱动 +type SmsDrive interface { + SendCode(ctx context.Context, in sysin.SendCodeInp, config *model.SmsConfig) (err error) +} + +func New(name ...string) SmsDrive { + var ( + instanceName = consts.SmsDriveAliYun + drive SmsDrive + ) + + if len(name) > 0 && name[0] != "" { + instanceName = name[0] + } + + switch instanceName { + case consts.SmsDriveAliYun: + drive = &aliyun.Handle + case consts.SmsDriveTencent: + drive = &tencent.Handle + default: + panic(fmt.Sprintf("暂不支持短信驱动:%v", instanceName)) + } + + return drive +} diff --git a/server/internal/library/sms/tencent/handle.go b/server/internal/library/sms/tencent/handle.go new file mode 100644 index 0000000..63459b2 --- /dev/null +++ b/server/internal/library/sms/tencent/handle.go @@ -0,0 +1,130 @@ +package tencent + +import ( + "context" + "encoding/json" + "fmt" + "github.com/gogf/gf/v2/frame/g" + "hotgo/internal/model" + "hotgo/internal/model/input/sysin" + + "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common" + "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/errors" + "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile" + sms "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/sms/v20210111" // 引入sms +) + +var ( + Handle = tencent{} +) + +type tencent struct{} + +// SendCode 发送验证码 +func (d *tencent) SendCode(ctx context.Context, in sysin.SendCodeInp, config *model.SmsConfig) (err error) { + /* 必要步骤: + * 实例化一个认证对象,入参需要传入腾讯云账户密钥对secretId,secretKey。 + * 这里采用的是从环境变量读取的方式,需要在环境变量中先设置这两个值。 + * 你也可以直接在代码中写死密钥对,但是小心不要将代码复制、上传或者分享给他人, + * 以免泄露密钥对危及你的财产安全。 + * SecretId、SecretKey 查询: https://console.cloud.tencent.com/cam/capi */ + credential := common.NewCredential( + config.TencentSecretId, + config.TencentSecretKey, + ) + + /* 非必要步骤: + * 实例化一个客户端配置对象,可以指定超时时间等配置 */ + cpf := profile.NewClientProfile() + + /* SDK默认使用POST方法。 + * 如果你一定要使用GET方法,可以在这里设置。GET方法无法处理一些较大的请求 */ + cpf.HttpProfile.ReqMethod = "POST" + + /* SDK有默认的超时时间,非必要请不要进行调整 + * 如有需要请在代码中查阅以获取最新的默认值 */ + // cpf.HttpProfile.ReqTimeout = 5 + + /* 指定接入地域域名,默认就近地域接入域名为 sms.tencentcloudapi.com ,也支持指定地域域名访问,例如广州地域的域名为 sms.ap-guangzhou.tencentcloudapi.com */ + cpf.HttpProfile.Endpoint = config.TencentEndpoint + + /* SDK默认用TC3-HMAC-SHA256进行签名,非必要请不要修改这个字段 */ + cpf.SignMethod = "HmacSHA1" + + /* 实例化要请求产品(以sms为例)的client对象 + * 第二个参数是地域信息,可以直接填写字符串ap-guangzhou,支持的地域列表参考 https://cloud.tencent.com/document/api/382/52071#.E5.9C.B0.E5.9F.9F.E5.88.97.E8.A1.A8 */ + client, err := sms.NewClient(credential, config.TencentRegion, cpf) + if err != nil { + return + } + + /* 实例化一个请求对象,根据调用的接口和实际情况,可以进一步设置请求参数 + * 你可以直接查询SDK源码确定接口有哪些属性可以设置 + * 属性可能是基本类型,也可能引用了另一个数据结构 + * 推荐使用IDE进行开发,可以方便的跳转查阅各个接口和数据结构的文档说明 */ + request := sms.NewSendSmsRequest() + + /* 基本类型的设置: + * SDK采用的是指针风格指定参数,即使对于基本类型你也需要用指针来对参数赋值。 + * SDK提供对基本类型的指针引用封装函数 + * 帮助链接: + * 短信控制台: https://console.cloud.tencent.com/smsv2 + * 腾讯云短信小助手: https://cloud.tencent.com/document/product/382/3773#.E6.8A.80.E6.9C.AF.E4.BA.A4.E6.B5.81 */ + + /* 短信应用ID: 短信SdkAppId在 [短信控制台] 添加应用后生成的实际SdkAppId,示例如1400006666 */ + // 应用 ID 可前往 [短信控制台](https://console.cloud.tencent.com/smsv2/app-manage) 查看 + request.SmsSdkAppId = common.StringPtr(config.TencentAppId) + + /* 短信签名内容: 使用 UTF-8 编码,必须填写已审核通过的签名 */ + // 签名信息可前往 [国内短信](https://console.cloud.tencent.com/smsv2/csms-sign) 或 [国际/港澳台短信](https://console.cloud.tencent.com/smsv2/isms-sign) 的签名管理查看 + request.SignName = common.StringPtr(config.TencentSign) + + /* 模板 ID: 必须填写已审核通过的模板 ID */ + // 模板 ID 可前往 [国内短信](https://console.cloud.tencent.com/smsv2/csms-template) 或 [国际/港澳台短信](https://console.cloud.tencent.com/smsv2/isms-template) 的正文模板管理查看 + request.TemplateId = common.StringPtr(in.Template) + + /* 模板参数: 模板参数的个数需要与 TemplateId 对应模板的变量个数保持一致,若无模板参数,则设置为空*/ + request.TemplateParamSet = common.StringPtrs([]string{in.Code}) + + /* 下发手机号码,采用 E.164 标准,+[国家或地区码][手机号] + * 示例如:+8613711112222, 其中前面有一个+号 ,86为国家码,13711112222为手机号,最多不要超过200个手机号*/ + request.PhoneNumberSet = common.StringPtrs([]string{fmt.Sprintf("+86%v", in.Mobile)}) + + ///* 用户的 session 内容(无需要可忽略): 可以携带用户侧 ID 等上下文信息,server 会原样返回 */ + //request.SessionContext = common.StringPtr("") + // + ///* 短信码号扩展号(无需要可忽略): 默认未开通,如需开通请联系 [腾讯云短信小助手] */ + //request.ExtendCode = common.StringPtr("") + // + ///* 国际/港澳台短信 SenderId(无需要可忽略): 国内短信填空,默认未开通,如需开通请联系 [腾讯云短信小助手] */ + //request.SenderId = common.StringPtr("") + + // 通过client对象调用想要访问的接口,需要传入请求对象 + response, err := client.SendSms(request) + // 处理异常 + if _, ok := err.(*errors.TencentCloudSDKError); ok { + return + } + + // 非SDK异常,直接失败。实际代码中可以加入其他的处理。 + if err != nil { + return + } + b, err := json.Marshal(response.Response) + if err != nil { + return + } + + // 打印返回的json字符串 + g.Log().Debugf(ctx, "tencent.sendCode response:%+v", string(b)) + + /* 当出现以下错误码时,快速解决方案参考 + * [FailedOperation.SignatureIncorrectOrUnapproved](https://cloud.tencent.com/document/product/382/9558#.E7.9F.AD.E4.BF.A1.E5.8F.91.E9.80.81.E6.8F.90.E7.A4.BA.EF.BC.9Afailedoperation.signatureincorrectorunapproved-.E5.A6.82.E4.BD.95.E5.A4.84.E7.90.86.EF.BC.9F) + * [FailedOperation.TemplateIncorrectOrUnapproved](https://cloud.tencent.com/document/product/382/9558#.E7.9F.AD.E4.BF.A1.E5.8F.91.E9.80.81.E6.8F.90.E7.A4.BA.EF.BC.9Afailedoperation.templateincorrectorunapproved-.E5.A6.82.E4.BD.95.E5.A4.84.E7.90.86.EF.BC.9F) + * [UnauthorizedOperation.SmsSdkAppIdVerifyFail](https://cloud.tencent.com/document/product/382/9558#.E7.9F.AD.E4.BF.A1.E5.8F.91.E9.80.81.E6.8F.90.E7.A4.BA.EF.BC.9Aunauthorizedoperation.smssdkappidverifyfail-.E5.A6.82.E4.BD.95.E5.A4.84.E7.90.86.EF.BC.9F) + * [UnsupportedOperation.ContainDomesticAndInternationalPhoneNumber](https://cloud.tencent.com/document/product/382/9558#.E7.9F.AD.E4.BF.A1.E5.8F.91.E9.80.81.E6.8F.90.E7.A4.BA.EF.BC.9Aunsupportedoperation.containdomesticandinternationalphonenumber-.E5.A6.82.E4.BD.95.E5.A4.84.E7.90.86.EF.BC.9F) + * 更多错误,可咨询[腾讯云助手](https://tccc.qcloud.com/web/im/index.html#/chat?webAppId=8fa15978f85cb41f7e2ea36920cb3ae1&title=Sms) + */ + + return +} diff --git a/server/internal/logic/sys/config.go b/server/internal/logic/sys/config.go index cd95ada..75817c4 100644 --- a/server/internal/logic/sys/config.go +++ b/server/internal/logic/sys/config.go @@ -23,10 +23,21 @@ import ( ) var MaskDemoField = []string{ - "smtpUser", "smtpPass", // 邮箱 - "uploadUCloudPublicKey", "uploadUCloudPrivateKey", // 云存储 - "geoAmapWebKey", // 地图 - "smsAliyunAccessKeyID", "smsAliyunAccessKeySecret", // 短信 + // 邮箱 + "smtpUser", "smtpPass", + + // 云存储 + "uploadUCloudPublicKey", "uploadUCloudPrivateKey", + "uploadCosSecretId", "uploadCosSecretKey", + "uploadOssSecretId", "uploadOssSecretKey", + "uploadQiNiuAccessKey", "uploadQiNiuSecretKey", + + // 地图 + "geoAmapWebKey", + + // 短信 + "smsAliYunAccessKeyID", "smsAliYunAccessKeySecret", + "smsTencentSecretId", "smsTencentSecretKey", } type sSysConfig struct{} diff --git a/server/internal/logic/sys/sms_log.go b/server/internal/logic/sys/sms_log.go index 067b7a5..6a9e5b3 100644 --- a/server/internal/logic/sys/sms_log.go +++ b/server/internal/logic/sys/sms_log.go @@ -3,7 +3,6 @@ // @Copyright Copyright (c) 2023 HotGo CLI // @Author Ms <133814250@qq.com> // @License https://github.com/bufanyun/hotgo/blob/master/LICENSE -// package sys import ( @@ -16,7 +15,7 @@ import ( "hotgo/internal/consts" "hotgo/internal/dao" "hotgo/internal/library/location" - "hotgo/internal/library/sms/aliyun" + "hotgo/internal/library/sms" "hotgo/internal/model" "hotgo/internal/model/entity" "hotgo/internal/model/input/sysin" @@ -129,6 +128,18 @@ func (s *sSysSmsLog) View(ctx context.Context, in sysin.SmsLogViewInp) (res *sys func (s *sSysSmsLog) List(ctx context.Context, in sysin.SmsLogListInp) (list []*sysin.SmsLogListModel, totalCount int, err error) { mod := dao.SysSmsLog.Ctx(ctx) + if in.Mobile != "" { + mod = mod.WhereLike("mobile", "%"+in.Mobile+"%") + } + + if in.Ip != "" { + mod = mod.Where("ip", in.Ip) + } + + if in.Event != "" { + mod = mod.Where("event", in.Event) + } + if in.Status > 0 { mod = mod.Where("status", in.Status) } @@ -160,9 +171,7 @@ func (s *sSysSmsLog) SendCode(ctx context.Context, in sysin.SendCodeInp) (err er return gerror.New("手机号不能为空") } - var ( - models *entity.SysSmsLog - ) + var models *entity.SysSmsLog if err = dao.SysSmsLog.Ctx(ctx).Where("event", in.Event).Where("mobile", in.Mobile).Scan(&models); err != nil { err = gerror.Wrap(err, consts.ErrorORM) return err @@ -187,16 +196,8 @@ func (s *sSysSmsLog) SendCode(ctx context.Context, in sysin.SendCodeInp) (err er in.Code = grand.Digits(4) } - switch config.SmsDrive { - case consts.SmsDriveAliYun: - err = aliyun.SendCode(ctx, in, config) - if err != nil { - return err - } - case consts.SmsDriveTencent: - return gerror.Newf("暂不支持短信驱动:%v", config.SmsDrive) - default: - return gerror.Newf("暂不支持短信驱动:%v", config.SmsDrive) + if err = sms.New(config.SmsDrive).SendCode(ctx, in, config); err != nil { + return err } var data = new(entity.SysSmsLog) @@ -230,18 +231,26 @@ func (s *sSysSmsLog) GetTemplate(ctx context.Context, template string, config *m switch config.SmsDrive { case consts.SmsDriveAliYun: - if len(config.SmsAliyunTemplate) == 0 { - return "", gerror.New("管理员还没有配置任何模板!") + if len(config.AliYunTemplate) == 0 { + return "", gerror.New("管理员还没有配置任何阿里云短信模板!") } - for _, v := range config.SmsAliyunTemplate { + for _, v := range config.AliYunTemplate { if v.Key == template { return v.Value, nil } } case consts.SmsDriveTencent: - return "", gerror.Newf("暂不支持短信驱动:%v", config.SmsDrive) + if len(config.TencentTemplate) == 0 { + return "", gerror.New("管理员还没有配置任何腾讯云短信模板!") + } + + for _, v := range config.TencentTemplate { + if v.Key == template { + return v.Value, nil + } + } default: return "", gerror.Newf("暂不支持短信驱动:%v", config.SmsDrive) } @@ -294,9 +303,7 @@ func (s *sSysSmsLog) VerifyCode(ctx context.Context, in sysin.VerifyCodeInp) (er return err } - var ( - models *entity.SysSmsLog - ) + var models *entity.SysSmsLog if err = dao.SysSmsLog.Ctx(ctx).Where("event", in.Event).Where("mobile", in.Mobile).Order("id desc").Scan(&models); err != nil { err = gerror.Wrap(err, consts.ErrorORM) return err @@ -334,10 +341,6 @@ func (s *sSysSmsLog) VerifyCode(ctx context.Context, in sysin.VerifyCodeInp) (er "status": consts.SmsStatusUsed, "updated_at": gtime.Now(), }).Update() - if err != nil { - err = gerror.Wrap(err, consts.ErrorORM) - return err - } return } diff --git a/server/internal/model/config.go b/server/internal/model/config.go index ccb007d..981234e 100644 --- a/server/internal/model/config.go +++ b/server/internal/model/config.go @@ -101,10 +101,18 @@ type SmsConfig struct { SmsMaxIpLimit int `json:"smsMaxIpLimit"` SmsCodeExpire int `json:"smsCodeExpire"` // 阿里云 - SmsAliyunAccessKeyID string `json:"smsAliyunAccessKeyID"` - SmsAliyunAccessKeySecret string `json:"smsAliyunAccessKeySecret"` - SmsAliyunSign string `json:"smsAliyunSign"` - SmsAliyunTemplate []*SmsTemplate `json:"smsAliyunTemplate"` + AliYunAccessKeyID string `json:"smsAliYunAccessKeyID"` + AliYunAccessKeySecret string `json:"smsAliYunAccessKeySecret"` + AliYunSign string `json:"smsAliYunSign"` + AliYunTemplate []*SmsTemplate `json:"smsAliYunTemplate"` + // 腾讯云 + TencentSecretId string `json:"smsTencentSecretId"` + TencentSecretKey string `json:"smsTencentSecretKey"` + TencentEndpoint string `json:"smsTencentEndpoint"` + TencentRegion string `json:"smsTencentRegion"` + TencentAppId string `json:"smsTencentAppId"` + TencentSign string `json:"smsTencentSign"` + TencentTemplate []*SmsTemplate `json:"smsTencentTemplate"` } ///////////// 以下是本地配置 diff --git a/server/internal/model/input/sysin/sms_log.go b/server/internal/model/input/sysin/sms_log.go index edba53a..9d14236 100644 --- a/server/internal/model/input/sysin/sms_log.go +++ b/server/internal/model/input/sysin/sms_log.go @@ -3,10 +3,12 @@ // @Copyright Copyright (c) 2023 HotGo CLI // @Author Ms <133814250@qq.com> // @License https://github.com/bufanyun/hotgo/blob/master/LICENSE -// package sysin import ( + "context" + "github.com/gogf/gf/v2/errors/gerror" + "hotgo/internal/consts" "hotgo/internal/model/entity" "hotgo/internal/model/input/form" ) @@ -46,8 +48,20 @@ type SmsLogListInp struct { form.PageReq form.RangeDateReq form.StatusReq - Title string - Content string + Mobile string + Ip string + Event string +} + +func (in *SmsLogListInp) Filter(ctx context.Context) (err error) { + if in.Event != "" { + _, ok := consts.SmsTemplateEventMap[in.Event] + if !ok { + err = gerror.Newf("无效的事件类型:%v", in.Event) + return + } + } + return } type SmsLogListModel struct { diff --git a/server/storage/data/hotgo.sql b/server/storage/data/hotgo.sql index 2455c50..01627d6 100644 --- a/server/storage/data/hotgo.sql +++ b/server/storage/data/hotgo.sql @@ -1,13 +1,14 @@ -- phpMyAdmin SQL Dump --- version 5.2.1 +-- version 4.9.0.1 -- https://www.phpmyadmin.net/ -- --- 主机: localhost --- 生成日期: 2023-04-05 04:14:35 --- 服务器版本: 5.7.41 --- PHP 版本: 7.3.33 +-- 主机: localhost:3306 +-- 生成日期: 2023-04-10 15:26:54 +-- 服务器版本: 5.7.38-log +-- PHP 版本: 5.6.40 SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO"; +SET AUTOCOMMIT = 0; START TRANSACTION; SET time_zone = "+00:00"; @@ -72,8 +73,8 @@ CREATE TABLE `hg_addon_hgexample_table` ( -- INSERT INTO `hg_addon_hgexample_table` (`id`, `category_id`, `flag`, `title`, `description`, `content`, `image`, `images`, `attachfile`, `attachfiles`, `map`, `star`, `price`, `views`, `activity_at`, `start_at`, `end_at`, `switch`, `sort`, `avatar`, `sex`, `qq`, `email`, `mobile`, `hobby`, `channel`, `city_id`, `pid`, `level`, `tree`, `remark`, `status`, `created_by`, `updated_by`, `created_at`, `updated_at`, `deleted_at`) VALUES -(1, 1, '[1, 2]', '测试标题', '描述', '
这是内容............
', 'http://bufanyun.cn-bj.ufileos.com/hotgo/attachment/2023-02-09/cqdqamvhlq4w3ki6bl.webp', '[\"http://bufanyun.cn-bj.ufileos.com/hotgo/attachment/2023-02-09/cqdqap5l9brk2lkavu.jpg\", \"http://bufanyun.cn-bj.ufileos.com/hotgo/attachment/2023-02-09/cqdqaqua7fw8ukbbp5.jpg\"]', 'http://bufanyun.cn-bj.ufileos.com/hotgo/attachment/2023-02-09/cqdqaup19k9oznyixz.doc', '[\"http://bufanyun.cn-bj.ufileos.com/hotgo/attachment/2023-02-09/cqdqawg96ba4cuezvv.xlsx\", \"http://bufanyun.cn-bj.ufileos.com/hotgo/attachment/2023-02-09/cqdqaup19k9oznyixz.doc\"]', '[{\"key\": \"qwe\", \"value\": \"123\"}, {\"key\": \"asd\", \"value\": \"456\"}]', 3.0, 88.00, 10, '2022-12-23', '2022-12-01 00:00:00', '2022-12-31 23:59:59', 1, 20, '', 15, '133814250', '133814250@qq.com', '15303830571', '[3, 2, 1]', 1, 140406, 0, 1, '', '备注!', 1, 1, 1, '2022-12-15 19:30:14', '2023-02-23 15:08:14', NULL), -(2, 0, '[1]', '测试2', '描述', '这是内容............
', 'http://bufanyun.cn-bj.ufileos.com/hotgo/attachment/2023-02-09/cqdqamvhlq4w3ki6bl.webp', '[\"http://bufanyun.cn-bj.ufileos.com/hotgo/attachment/2023-02-09/cqdqap5l9brk2lkavu.jpg\", \"http://bufanyun.cn-bj.ufileos.com/hotgo/attachment/2023-02-09/cqdqaqua7fw8ukbbp5.jpg\"]', 'http://bufanyun.cn-bj.ufileos.com/hotgo/attachment/2023-02-09/cqdqaup19k9oznyixz.doc', '[\"http://bufanyun.cn-bj.ufileos.com/hotgo/attachment/2023-02-09/cqdqawg96ba4cuezvv.xlsx\", \"http://bufanyun.cn-bj.ufileos.com/hotgo/attachment/2023-02-09/cqdqaup19k9oznyixz.doc\"]', '[{\"key\": \"qwe\", \"value\": \"123\"}, {\"key\": \"asd\", \"value\": \"456\"}]', '3.0', '88.00', 10, '2022-12-23', '2022-12-01 00:00:00', '2022-12-31 23:59:59', 1, 20, '', 15, '133814250', '133814250@qq.com', '15303830571', '[3, 2, 1]', 1, 140406, 0, 1, '', '备注!', 1, 1, 1, '2022-12-15 19:30:14', '2023-02-23 15:08:14', NULL), +(2, 0, '[1]', '测试2', '描述', '