Browse Source

Merge branch 'master' into feature/change_log

# Conflicts:
#	utils/constants.go
xyxie 1 year ago
parent
commit
b15bec3061

+ 18 - 2
controllers/base_auth.go

@@ -21,8 +21,24 @@ func (this *BaseAuthController) Prepare() {
 	uri := this.Ctx.Input.URI()
 	fmt.Println("Url:", uri)
 	if method != "HEAD" {
-		if method == "POST" || method == "GET" {
-
+		if method == "POST" {
+			authorization := this.Ctx.Input.Header("authorization")
+			if authorization == "" {
+				this.JSON(models.BaseResponse{Ret: 408, Msg: "请重新授权!", ErrMsg: "请重新授权:authorization is empty "}, false, false)
+				this.StopRun()
+				return
+			}
+			checkAuthorization := utils.MD5(utils.EtaReportAppNameEn + utils.EtaReportKey)
+			fmt.Println(checkAuthorization)
+			if authorization != checkAuthorization {
+				this.JSON(models.BaseResponse{Ret: 408, Msg: "签名错误!", ErrMsg: "签名错误:authorization is err "}, false, false)
+				this.StopRun()
+				return
+			}
+		} else {
+			this.JSON(models.BaseResponse{Ret: 408, Msg: "请求异常,请联系客服!", ErrMsg: "POST之外的请求,暂不支持"}, false, false)
+			this.StopRun()
+			return
 		}
 	} else {
 		this.JSON(models.BaseResponse{Ret: 408, Msg: "请求异常,请联系客服!", ErrMsg: "POST之外的请求,暂不支持"}, false, false)

+ 231 - 0
controllers/english_report.go

@@ -0,0 +1,231 @@
+package controllers
+
+import (
+	"errors"
+	"eta/eta_report/models"
+	"eta/eta_report/services/alarm_msg"
+	"eta/eta_report/utils"
+	"fmt"
+	"html"
+	"time"
+)
+
+// EnglishReportShareController 报告分享
+type EnglishReportShareController struct {
+	BaseCommonController
+}
+
+// EnglishReportDetail
+// @Title 英文研报-分享详情
+// @Description 英文研报-分享详情
+// @Param   ReportCode   query   string  true	"报告唯一编码"
+// @Param   ShareEmail   query   int  false	"推送的邮箱ID"
+// @Success 200 {object} models.ReportShareDetailResp
+// @router /share/detail [get]
+func (this *EnglishReportShareController) EnglishReportDetail() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	reportCode := this.GetString("ReportCode")
+	if reportCode == "" {
+		br.Msg = "参数错误"
+		br.ErrMsg = "参数错误,reportCode 为空"
+		return
+	}
+	report, err := models.GetEnglishReportByCode(reportCode)
+	if err != nil {
+		br.Msg = "该报告已删除"
+		br.ErrMsg = "获取报告详情失败,Err:" + err.Error()
+		return
+	}
+	err = models.UpdateEnglishReportCounts(reportCode)
+	if err != nil {
+		br.Msg = "更新失败"
+		br.ErrMsg = "更新失败,Err:" + err.Error()
+		return
+	}
+	report.ContentSub = html.UnescapeString(report.ContentSub)
+	report.Content = html.UnescapeString(report.Content)
+
+	// 记录邮箱
+	shareEmail, _ := this.GetInt("ShareEmail", 0)
+	if shareEmail != 0 {
+		go func() {
+			var errMsg error
+			defer func() {
+				if errMsg != nil {
+					fmt.Println(errMsg.Error())
+					alarm_msg.SendAlarmMsg(utils.APPNAME+"更新英文报告邮箱PV失败, Err: "+errMsg.Error(), 2)
+				}
+			}()
+
+			userEmail, e := models.GetEnglishReportEmailById(shareEmail)
+			if e != nil && e.Error() != utils.ErrNoRow() {
+				errMsg = errors.New("获取客户邮箱信息失败, Err:" + e.Error())
+				return
+			}
+			if userEmail == nil {
+				return
+			}
+			// 更新报告邮箱pv(冗余)
+			if e = models.UpdateEnglishReportEmailCounts(reportCode); e != nil {
+				errMsg = errors.New("更新报告邮箱PV失败, Err:" + e.Error())
+				return
+			}
+			// 记录邮箱PV
+			pv := &models.EnglishReportEmailPV{
+				ReportId:   report.Id,
+				EmailId:    userEmail.Id,
+				CreateTime: time.Now().Local(),
+			}
+			if e = models.InsertTrialEnglishReportEmailPV(pv); e != nil {
+				errMsg = errors.New("新增邮箱PV失败, Err: " + e.Error())
+				return
+			}
+			// 更新阅读量
+			if e = models.UpdateEnglishReportEmailViewTotal(userEmail.Id); e != nil {
+				errMsg = errors.New("更新英文联系人阅读量失败, Err: " + e.Error())
+				return
+			}
+			if userEmail.CompanyId > 0 {
+				if e = models.UpdateEnglishCompanyViewTotal(userEmail.CompanyId); e != nil {
+					errMsg = errors.New("更新英文客户阅读量, Err: " + e.Error())
+					return
+				}
+			}
+		}()
+	}
+
+	resp := new(models.EnglishReportShareDetailResp)
+	// 免责声明
+	conf, e := models.GetBusinessConf()
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取免责声明失败, Err: " + e.Error()
+		return
+	}
+	// 研报分享抬头
+	if v, ok := conf[models.BusinessConfH5ShareEnName]; ok {
+		resp.H5ShareEnName = v
+	}
+	if v, ok := conf[models.BusinessConfH5ReportShareImg]; ok {
+		resp.H5ReportShareImg = v
+	}
+	resp.Hz = 1
+	resp.Report = report
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}
+
+// TrialEnglishReportDetail
+// @Title 英文研报-分享详情-ETA试用平台
+// @Description 英文研报-分享详情
+// @Param   ReportCode   query   string  true	"报告唯一编码"
+// @Param   ShareEmail   query   int  false	"推送的邮箱ID"
+// @Success 200 {object} models.ReportShareDetailResp
+// @router /trial/share/detail [get]
+func (this *EnglishReportShareController) TrialEnglishReportDetail() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	reportCode := this.GetString("ReportCode")
+	if reportCode == "" {
+		br.Msg = "参数错误"
+		br.ErrMsg = "参数错误,reportCode 为空"
+		return
+	}
+	report, err := models.GetTrialEnglishReportByCode(reportCode)
+	if err != nil {
+		br.Msg = "该报告已删除"
+		br.ErrMsg = "获取报告详情失败,Err:" + err.Error()
+		return
+	}
+	err = models.UpdateTrialEnglishReportCounts(reportCode)
+	if err != nil {
+		br.Msg = "更新失败"
+		br.ErrMsg = "更新失败,Err:" + err.Error()
+		return
+	}
+	report.ContentSub = html.UnescapeString(report.ContentSub)
+	report.Content = html.UnescapeString(report.Content)
+
+	// 记录邮箱
+	shareEmail, _ := this.GetInt("ShareEmail", 0)
+	if shareEmail != 0 {
+		go func() {
+			var errMsg error
+			defer func() {
+				if errMsg != nil {
+					alarm_msg.SendAlarmMsg(utils.APPNAME+"更新英文报告邮箱PV失败, Err: "+errMsg.Error(), 2)
+				}
+			}()
+
+			userEmail, e := models.GetTrialEnglishReportEmailById(shareEmail)
+			if e != nil && e.Error() != utils.ErrNoRow() {
+				errMsg = errors.New("获取客户邮箱信息失败, Err:" + e.Error())
+				return
+			}
+			if userEmail == nil {
+				return
+			}
+			// 更新报告邮箱pv(冗余)
+			if e = models.UpdateTrialEnglishReportEmailCounts(reportCode); e != nil {
+				errMsg = errors.New("更新报告邮箱PV失败, Err:" + e.Error())
+				return
+			}
+			// 记录邮箱PV
+			pv := &models.EnglishReportEmailPV{
+				ReportId:   report.Id,
+				EmailId:    userEmail.Id,
+				CreateTime: time.Now().Local(),
+			}
+			if e = models.InsertTrialEnglishReportEmailPV(pv); e != nil {
+				errMsg = errors.New("新增邮箱PV失败, Err: " + e.Error())
+				return
+			}
+			// 更新阅读量
+			if e = models.UpdateTrialEnglishReportEmailViewTotal(userEmail.Id); e != nil {
+				errMsg = errors.New("更新英文联系人阅读量失败, Err: " + e.Error())
+				return
+			}
+			if userEmail.CompanyId > 0 {
+				if e = models.UpdateTrialEnglishCompanyViewTotal(userEmail.CompanyId); e != nil {
+					errMsg = errors.New("更新英文客户阅读量, Err: " + e.Error())
+					return
+				}
+			}
+		}()
+	}
+
+	resp := new(models.EnglishReportShareDetailResp)
+	// 免责声明
+	conf, e := models.GetBusinessConf()
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取免责声明失败, Err: " + e.Error()
+		return
+	}
+
+	// 研报分享抬头
+	if v, ok := conf[models.BusinessConfH5ShareEnName]; ok {
+		resp.H5ShareEnName = v
+	}
+	if v, ok := conf[models.BusinessConfH5ReportShareImg]; ok {
+		resp.H5ReportShareImg = v
+	}
+	resp.Hz = 1
+
+	resp.Report = report
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取成功"
+	br.Data = resp
+}

+ 7 - 0
controllers/report_share.go

@@ -49,6 +49,13 @@ func (this *ReportShareController) Detail() {
 	if conf[models.BusinessConfDisclaimer] != "" {
 		resp.Disclaimer = conf[models.BusinessConfDisclaimer]
 	}
+	// 研报分享抬头
+	if v, ok := conf[models.BusinessConfH5ShareName]; ok {
+		resp.H5ShareName = v
+	}
+	if v, ok := conf[models.BusinessConfH5ReportShareImg]; ok {
+		resp.H5ReportShareImg = v
+	}
 
 	resp.Report = report
 	br.Ret = 200

+ 101 - 0
controllers/wechat.go

@@ -0,0 +1,101 @@
+package controllers
+
+import (
+	"eta/eta_report/models"
+	"eta/eta_report/services"
+	"eta/eta_report/services/wechat"
+	"eta/eta_report/utils"
+	"fmt"
+)
+
+type WechatCommonController struct {
+	BaseCommonController
+}
+
+// GetWxSign
+// @Title 微信获取签名接口-无token校验
+// @Description 微信获取签名接口
+// @Param   Url   query   string  true       "url地址"
+// @Success 200 {object} models.WechatSign
+// @router /open/getWxSign [get]
+func (this *WechatCommonController) GetWxSign() {
+	br := new(models.BaseResponse).Init()
+	defer func() {
+		this.Data["json"] = br
+		this.ServeJSON()
+	}()
+
+	// 微信配置信息
+	conf, e := models.GetBusinessConf()
+	if e != nil {
+		br.Msg = "获取失败"
+		br.ErrMsg = "获取配置信息失败, Err: " + e.Error()
+		return
+	}
+	appId := ""
+	appSecret := ""
+	if v, ok := conf[models.BusinessConfWxAppId]; ok {
+		appId = v
+	}
+	if v, ok := conf[models.BusinessConfWxAppSecret]; ok {
+		appSecret = v
+	}
+
+	if appId == "" || appSecret == "" {
+		br.Ret = models.BaseRespIgnoreTipsRet
+		br.Msg = "微信公众号信息未配置"
+		return
+	}
+	getUrl := this.GetString("Url")
+	fmt.Println("getUrl:", getUrl)
+	tReq := wechat.WxTokenReq{
+		WxAppId:     appId,
+		WxAppSecret: appSecret,
+	}
+	accessToken, err, errMsg := wechat.GetAccessToken(tReq)
+	if err != nil {
+		br.Msg = "获取微信信息失败"
+		br.ErrMsg = "获取access_token失败,err:" + errMsg
+		return
+	}
+
+	errCode, ticket, err := services.GetWxTicket(accessToken)
+	if err != nil {
+		if errCode == 40001 {
+			accessToken, err, errMsg = wechat.GetAccessToken(tReq)
+			if err != nil {
+				br.Msg = "获取微信配置失败"
+				br.ErrMsg = "获取access_token失败,err:" + errMsg
+				return
+			}
+
+			errCode, ticket, err = services.GetWxTicket(accessToken)
+			if err != nil {
+				br.Msg = "获取Ticket失败,请联系客服"
+				br.ErrMsg = "获取Ticket失败,Err" + err.Error()
+				return
+			}
+		}
+		br.Msg = "获取Ticket失败,请联系客服"
+		br.ErrMsg = "获取Ticket失败,Err" + err.Error()
+		return
+	}
+	if ticket == "" {
+		br.Msg = "获取Ticket失败,请联系客服"
+		br.ErrMsg = "ticket为空" + ticket
+		return
+	}
+	nonceStr := utils.GetRandStringNoSpecialChar(16)
+	signature, nonceString, timestamp := services.GetWxSignature(ticket, getUrl, nonceStr)
+	resp := new(models.WechatSign)
+	resp.AppId = appId
+	resp.NonceStr = nonceString
+	resp.Timestamp = timestamp
+	resp.Url = getUrl
+	resp.Signature = signature
+
+	br.Ret = 200
+	br.Success = true
+	br.Msg = "获取签名成功"
+	br.Data = resp
+}

+ 1 - 0
go.mod

@@ -6,6 +6,7 @@ require (
 	github.com/beego/beego/v2 v2.1.0
 	github.com/dgrijalva/jwt-go v3.2.0+incompatible
 	github.com/go-sql-driver/mysql v1.7.0
+	github.com/rdlucklib/rdluck_tools v1.0.3
 	github.com/sirupsen/logrus v1.9.3
 	gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
 	gopkg.in/natefinch/lumberjack.v2 v2.2.1

+ 148 - 1
go.sum

@@ -1,79 +1,226 @@
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
+github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk=
+github.com/astaxie/beego v1.12.3/go.mod h1:p3qIm0Ryx7zeBHLljmd7omloyca1s4yu1a8kM1FkpIA=
 github.com/beego/beego/v2 v2.1.0 h1:Lk0FtQGvDQCx5V5yEu4XwDsIgt+QOlNjt5emUa3/ZmA=
 github.com/beego/beego/v2 v2.1.0/go.mod h1:6h36ISpaxNrrpJ27siTpXBG8d/Icjzsc7pU1bWpp0EE=
+github.com/beego/goyaml2 v0.0.0-20130207012346-5545475820dd/go.mod h1:1b+Y/CofkYwXMUU0OhQqGvsY2Bvgr4j6jfT699wyZKQ=
+github.com/beego/x2j v0.0.0-20131220205130-a0352aadc542/go.mod h1:kSeGC/p1AbBiEp5kat81+DSQrZenVBZXklMLaELspWU=
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
 github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
 github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
+github.com/bradfitz/gomemcache v0.0.0-20180710155616-bc664df96737/go.mod h1:PmM6Mmwb0LSuEubjR8N7PtNe1KxZLtOUHtbeikc5h60=
+github.com/casbin/casbin v1.7.0/go.mod h1:c67qKN6Oum3UF5Q1+BByfFxkwKvhwW57ITjqwtzR1KE=
+github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
 github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
 github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
+github.com/cloudflare/golz4 v0.0.0-20150217214814-ef862a3cdc58/go.mod h1:EOBUe0h4xcZ5GoxqC5SDxFQ8gwyZPKQoEzownBlhI80=
+github.com/couchbase/go-couchbase v0.0.0-20200519150804-63f3cdb75e0d/go.mod h1:TWI8EKQMs5u5jLKW/tsb9VwauIrMIxQG1r5fMsswK5U=
+github.com/couchbase/gomemcached v0.0.0-20200526233749-ec430f949808/go.mod h1:srVSlQLB8iXBVXHgnqemxUXqN6FCvClgCMPCsjBDR7c=
+github.com/couchbase/goutils v0.0.0-20180530154633-e865a1461c8a/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs=
 github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
+github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
 github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
+github.com/elastic/go-elasticsearch/v6 v6.8.5/go.mod h1:UwaDJsD3rWLM5rKNFzv9hgox93HoX8utj1kxD9aFUcI=
+github.com/elazarl/go-bindata-assetfs v1.0.0/go.mod h1:v+YaWX3bdea5J/mo8dSETolEo7R71Vk1u8bnjau5yw4=
 github.com/elazarl/go-bindata-assetfs v1.0.1 h1:m0kkaHRKEu7tUIUFVwhGGGYClXvyl4RE03qmvRTNfbw=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/garyburd/redigo v1.6.3/go.mod h1:rTb6epsqigu3kYKBnaF028A7Tf/Aw5s0cqA47doKKqw=
+github.com/glendc/gopher-json v0.0.0-20170414221815-dc4743023d0c/go.mod h1:Gja1A+xZ9BoviGJNA2E9vFkPjjsl+CoJxSXiQM1UXtw=
+github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
+github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
+github.com/go-redis/redis v6.14.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
+github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
+github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
 github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
 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/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
 github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
 github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
+github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
 github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
 github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
 github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
 github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
 github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
 github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/ledisdb/ledisdb v0.0.0-20200510135210-d35789ec47e6/go.mod h1:n931TsDuKuq+uX4v1fulaMbA/7ZLLhjc85h7chZGBCQ=
+github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
+github.com/lib/pq v1.10.4/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
 github.com/lib/pq v1.10.5 h1:J+gdV2cUmX7ZqL2B0lFcW0m+egaHC2V3lpO8nWxyYiQ=
-github.com/mattn/go-sqlite3 v1.14.7 h1:fxWBnXkxfM6sRiuH3bqJ4CfzZojMOLVc0UTsTglEghA=
+github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
+github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
+github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
 github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
 github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
 github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
 github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0HfGg=
+github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
+github.com/pelletier/go-toml v1.0.1/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
+github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
+github.com/peterh/liner v1.0.1-0.20171122030339-3681c2a91233/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc=
+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 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/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
+github.com/prometheus/client_golang v1.7.0/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
 github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8=
 github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc=
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
 github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
 github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
+github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
 github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM=
 github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc=
+github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
 github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg=
 github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM=
+github.com/rdlucklib/rdluck_tools v1.0.3 h1:iOtK2QPlPQ6CL6c1htCk5VnFCHzyG6DCfJtunrMswK0=
+github.com/rdlucklib/rdluck_tools v1.0.3/go.mod h1:9Onw9o4w19C8KE5lxb8GyxgRBbZweRVkQSc79v38EaA=
 github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
+github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
 github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 h1:DAYUYH5869yV94zvCES9F51oYtN5oGlwjxJJz7ZCnik=
 github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
+github.com/siddontang/go v0.0.0-20170517070808-cb568a3e5cc0/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw=
+github.com/siddontang/goredis v0.0.0-20150324035039-760763f78400/go.mod h1:DDcKzU3qCuvj/tPnimWSsZZzvk9qvkvrIL5naVBPh5s=
+github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA=
+github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
 github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
 github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
+github.com/ssdb/gossdb v0.0.0-20180723034631-88f6b59b84ec/go.mod h1:QBvMkMya+gXctz3kmljlUCu/yB3GZ6oee+dUozsezQE=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
+github.com/syndtr/goleveldb v0.0.0-20160425020131-cfa635847112/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
+github.com/syndtr/goleveldb v0.0.0-20181127023241-353a9fca669c/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
+github.com/ugorji/go v0.0.0-20171122102828-84cb69a8af83/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ=
+github.com/wendal/errors v0.0.0-20130201093226-f66c77a7882b/go.mod h1:Q12BUT7DqIlHRmgv3RskH+UCM/4eqVMgI0EMmlSpAXc=
+github.com/ylywyn/jpush-api-go-client v0.0.0-20190906031852-8c4466c6e369/go.mod h1:Nv7wKD2/bCdKUFNKcJRa99a+1+aSLlCRJFriFYdjz/I=
+github.com/yuin/gopher-lua v0.0.0-20171031051903-609c9cd26973/go.mod h1:aEV29XrmTYFr3CiRxZeGHpkvbwq+prZduBqMaascyCU=
+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM=
 golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
 golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
 golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58=
 golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
+google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
+google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
 google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
 google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
 google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
 gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk=
 gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
 gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE=
 gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=
+gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
 gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
 gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

+ 10 - 8
models/base.go

@@ -1,12 +1,14 @@
 package models
 
+const BaseRespIgnoreTipsRet = 4003 // 忽略提示的状态码
+
 type BaseResponse struct {
-	Ret     int
-	Msg     string
-	ErrMsg  string
-	ErrCode string
-	Data    interface{}
-	Success bool `description:"true 执行成功,false 执行失败"`
+	Ret         int
+	Msg         string
+	ErrMsg      string
+	ErrCode     string
+	Data        interface{}
+	Success     bool `description:"true 执行成功,false 执行失败"`
 	IsSendEmail bool `json:"-"`
 }
 
@@ -19,7 +21,7 @@ type BaseResponseRef struct {
 }
 
 type BaseResponseResult struct {
-	Ret     int    `description:"状态:200 成功,408 重新登录,403:为失败"`
+	Ret     int    `description:"状态:200 成功,408 重新登录,403:为失败,4003为忽略提示的失败"`
 	Msg     string `description:"提示信息,对用户展示"`
 	ErrMsg  string `description:"错误信息,供开发定位问题"`
 	ErrCode string `description:"错误编码,预留"`
@@ -27,7 +29,7 @@ type BaseResponseResult struct {
 }
 
 func (r *BaseResponse) Init() *BaseResponse {
-	return &BaseResponse{Ret: 403,IsSendEmail: true}
+	return &BaseResponse{Ret: 403, IsSendEmail: true}
 }
 
 type RunLogReq struct {

+ 6 - 1
models/business_conf.go

@@ -7,7 +7,12 @@ import (
 )
 
 const (
-	BusinessConfDisclaimer = "Disclaimer"
+	BusinessConfDisclaimer       = "Disclaimer"
+	BusinessConfH5ShareName      = "H5ShareName"
+	BusinessConfH5ShareEnName    = "H5ShareEnName"
+	BusinessConfH5ReportShareImg = "H5ReportShareImg"
+	BusinessConfWxAppId          = "WxAppId"
+	BusinessConfWxAppSecret      = "WxAppSecret"
 )
 
 // BusinessConf 商户配置表

+ 81 - 0
models/english_company.go

@@ -0,0 +1,81 @@
+package models
+
+import (
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+// EnglishCompany 英文客户
+type EnglishCompany struct {
+	CompanyId   int       `orm:"column(company_id);pk" description:"英文客户ID"`
+	CompanyName string    `description:"客户名称"`
+	CountryCode string    `description:"国家Code"`
+	Country     string    `description:"国家"`
+	SellerId    int       `description:"销售ID"`
+	SellerName  string    `description:"销售姓名"`
+	ViewTotal   int       `description:"累计点击量/阅读量"`
+	IsDeleted   int       `description:"删除状态:0-正常;1-已删除"`
+	CreateTime  time.Time `description:"创建时间"`
+	ModifyTime  time.Time `description:"更新时间"`
+}
+
+func (item *EnglishCompany) TableName() string {
+	return "english_company"
+}
+
+func (item *EnglishCompany) Create() (err error) {
+	o := orm.NewOrm()
+	id, err := o.Insert(item)
+	if err != nil {
+		return
+	}
+	item.CompanyId = int(id)
+	return
+}
+
+// EnglishCompanySaveReq 英文客户-保存请求体
+type EnglishCompanySaveReq struct {
+	CompanyId   int    `description:"客户ID"`
+	CompanyName string `description:"客户名称"`
+	CountryCode string `description:"国家代码"`
+	Country     string `description:"国家"`
+	SellerId    int    `description:"销售ID"`
+}
+
+func (item *EnglishCompany) Update(cols []string) (err error) {
+	o := orm.NewOrm()
+	_, err = o.Update(item, cols...)
+	return
+}
+
+// GetEnglishCompanyById 主键获取客户
+func GetEnglishCompanyById(id int) (item *EnglishCompany, err error) {
+	o := orm.NewOrm()
+	sql := `SELECT * FROM english_company WHERE is_deleted = 0 AND company_id = ? LIMIT 1`
+	err = o.Raw(sql, id).QueryRow(&item)
+	return
+}
+
+// GetEnglishCompanyByName 名称获取客户
+func GetEnglishCompanyByName(companyName string) (item *EnglishCompany, err error) {
+	o := orm.NewOrm()
+	sql := `SELECT * FROM english_company WHERE is_deleted = 0 AND company_name = ? LIMIT 1`
+	err = o.Raw(sql, companyName).QueryRow(&item)
+	return
+}
+
+// UpdateEnglishCompanyViewTotal 更新英文客户阅读量
+func UpdateEnglishCompanyViewTotal(companyId int) (err error) {
+	o := orm.NewOrm()
+	sql := `UPDATE english_company SET view_total = view_total+1 WHERE company_id = ? `
+	_, err = o.Raw(sql, companyId).Exec()
+	return
+}
+
+// UpdateTrialEnglishCompanyViewTotal 更新英文客户阅读量-ETA试用平台
+func UpdateTrialEnglishCompanyViewTotal(companyId int) (err error) {
+	o := orm.NewOrm()
+	sql := `UPDATE english_company SET view_total = view_total+1 WHERE company_id = ? `
+	_, err = o.Raw(sql, companyId).Exec()
+	return
+}

+ 80 - 0
models/english_report.go

@@ -0,0 +1,80 @@
+package models
+
+import "github.com/beego/beego/v2/client/orm"
+
+type EnglishReportDetail struct {
+	Id                 int    `orm:"column(id)" description:"报告Id"`
+	AddType            int    `description:"新增方式:1:新增报告,2:继承报告"`
+	ClassifyIdFirst    int    `description:"一级分类id"`
+	ClassifyNameFirst  string `description:"一级分类名称"`
+	ClassifyIdSecond   int    `description:"二级分类id"`
+	ClassifyNameSecond string `description:"二级分类名称"`
+	Title              string `description:"标题"`
+	Abstract           string `description:"摘要"`
+	Author             string `description:"作者"`
+	Frequency          string `description:"频度"`
+	CreateTime         string `description:"创建时间"`
+	ModifyTime         string `description:"修改时间"`
+	State              int    `description:"1:未发布,2:已发布"`
+	PublishTime        string `description:"发布时间"`
+	Stage              int    `description:"期数"`
+	MsgIsSend          int    `description:"消息是否已发送,0:否,1:是"`
+	Content            string `description:"内容"`
+	VideoUrl           string `description:"音频文件URL"`
+	VideoName          string `description:"音频文件名称"`
+	VideoPlaySeconds   string `description:"音频播放时长"`
+	ContentSub         string `description:"内容前两个章节"`
+	ThsMsgIsSend       int    `description:"客户群消息是否已发送,0:否,1:是"`
+	HasChapter         int    `description:"是否有章节 0-否 1-是"`
+	ChapterType        string `description:"章节类型 day-晨报 week-周报"`
+	Overview           string `description:"英文概述部分"`
+}
+
+func GetEnglishReportByCode(reportCode string) (item *EnglishReportDetail, err error) {
+	o := orm.NewOrm()
+	sql := `SELECT * FROM english_report WHERE report_code=?`
+	err = o.Raw(sql, reportCode).QueryRow(&item)
+	return
+}
+
+type EnglishReportShareDetailResp struct {
+	Report           *EnglishReportDetail `description:"报告"`
+	H5ShareEnName    string               `description:"研报分享抬头"`
+	H5ReportShareImg string               `description:"研报分享图片"`
+	Hz               int
+}
+
+func UpdateEnglishReportCounts(reportCode string) (err error) {
+	o := orm.NewOrm()
+	sql := `UPDATE english_report SET pv = pv+1 WHERE report_code = ?  `
+	_, err = o.Raw(sql, reportCode).Exec()
+	return
+}
+
+func UpdateEnglishReportEmailCounts(reportCode string) (err error) {
+	o := orm.NewOrm()
+	sql := `UPDATE english_report SET pv_email = pv_email+1 WHERE report_code = ?  `
+	_, err = o.Raw(sql, reportCode).Exec()
+	return
+}
+
+func GetTrialEnglishReportByCode(reportCode string) (item *EnglishReportDetail, err error) {
+	o := orm.NewOrm()
+	sql := `SELECT * FROM english_report WHERE report_code=?`
+	err = o.Raw(sql, reportCode).QueryRow(&item)
+	return
+}
+
+func UpdateTrialEnglishReportCounts(reportCode string) (err error) {
+	o := orm.NewOrm()
+	sql := `UPDATE english_report SET pv = pv+1 WHERE report_code = ?  `
+	_, err = o.Raw(sql, reportCode).Exec()
+	return
+}
+
+func UpdateTrialEnglishReportEmailCounts(reportCode string) (err error) {
+	o := orm.NewOrm()
+	sql := `UPDATE english_report SET pv_email = pv_email+1 WHERE report_code = ?  `
+	_, err = o.Raw(sql, reportCode).Exec()
+	return
+}

+ 80 - 0
models/english_report_email.go

@@ -0,0 +1,80 @@
+package models
+
+import (
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+// EnglishReportEmail 英文研报-邮箱/客户联系人
+type EnglishReportEmail struct {
+	Id           int       `orm:"column(id);pk" description:"邮箱ID"`
+	CompanyId    int       `description:"客户ID"`
+	Name         string    `description:"联系人名称"`
+	Email        string    `description:"邮箱地址"`
+	ViewTotal    int       `description:"累计点击量/阅读量"`
+	LastViewTime time.Time `description:"最后阅读时间"`
+	IsDeleted    int       `description:"删除状态:0-正常;1-已删除"`
+	AdminId      int       `description:"创建人ID"`
+	AdminName    string    `description:"创建人姓名"`
+	CreateTime   time.Time `description:"创建时间"`
+	ModifyTime   time.Time `description:"更新时间"`
+}
+
+func (item *EnglishReportEmail) TableName() string {
+	return "english_report_email"
+}
+
+// EnglishReportEmailSaveReq 保存邮箱请求体
+type EnglishReportEmailSaveReq struct {
+	Id    int    `description:"邮箱ID, 大于0为编辑"`
+	Name  string `description:"客户名称"`
+	Email string `description:"邮箱地址"`
+}
+
+func (item *EnglishReportEmail) Create() (err error) {
+	o := orm.NewOrm()
+	id, err := o.Insert(item)
+	if err != nil {
+		return
+	}
+	item.Id = int(id)
+	return
+}
+
+func (item *EnglishReportEmail) Update(cols []string) (err error) {
+	o := orm.NewOrm()
+	_, err = o.Update(item, cols...)
+	return
+}
+
+// GetEnglishReportEmailById 主键获取邮箱
+func GetEnglishReportEmailById(id int) (item *EnglishReportEmail, err error) {
+	o := orm.NewOrm()
+	sql := `SELECT * FROM english_report_email WHERE is_deleted = 0 AND id = ? LIMIT 1`
+	err = o.Raw(sql, id).QueryRow(&item)
+	return
+}
+
+// UpdateEnglishReportEmailViewTotal 更新英文联系人阅读量
+func UpdateEnglishReportEmailViewTotal(emailId int) (err error) {
+	o := orm.NewOrm()
+	sql := `UPDATE english_report_email SET view_total = view_total+1, last_view_time = NOW() WHERE id = ? `
+	_, err = o.Raw(sql, emailId).Exec()
+	return
+}
+
+// GetTrialEnglishReportEmailById 主键获取邮箱-ETA试用平台
+func GetTrialEnglishReportEmailById(id int) (item *EnglishReportEmail, err error) {
+	o := orm.NewOrm()
+	sql := `SELECT * FROM english_report_email WHERE is_deleted = 0 AND id = ? LIMIT 1`
+	err = o.Raw(sql, id).QueryRow(&item)
+	return
+}
+
+// UpdateTrialEnglishReportEmailViewTotal 更新英文联系人阅读量-ETA试用平台
+func UpdateTrialEnglishReportEmailViewTotal(emailId int) (err error) {
+	o := orm.NewOrm()
+	sql := `UPDATE english_report_email SET view_total = view_total+1, last_view_time = NOW() WHERE id = ? `
+	_, err = o.Raw(sql, emailId).Exec()
+	return
+}

+ 22 - 0
models/english_report_email_pv.go

@@ -0,0 +1,22 @@
+package models
+
+import (
+	"github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+// EnglishReportEmailPV 英文研报-邮箱pv
+type EnglishReportEmailPV struct {
+	Id         int       `orm:"column(id);pk"`
+	ReportId   int       `description:"英文报告ID"`
+	EmailId    int       `description:"邮箱ID"`
+	CreateTime time.Time `description:"创建时间"`
+}
+
+// InsertTrialEnglishReportEmailPV ETA试用平台-新增英文邮箱PV
+func InsertTrialEnglishReportEmailPV(item *EnglishReportEmailPV) (err error) {
+	o := orm.NewOrm()
+	sql := `INSERT INTO english_report_email_pv(report_id, email_id, create_time) VALUES(?, ?, ?)`
+	_, err = o.Raw(sql, item.ReportId, item.EmailId, item.CreateTime).Exec()
+	return
+}

+ 5 - 2
models/report.go

@@ -40,6 +40,9 @@ func GetReportByCode(reportCode string) (item *Report, err error) {
 }
 
 type ReportShareDetailResp struct {
-	Report     *Report `description:"报告"`
-	Disclaimer string  `description:"免责声明"`
+	Report           *Report `description:"报告"`
+	Disclaimer       string  `description:"免责声明"`
+	H5ShareName      string  `description:"研报分享抬头"`
+	H5ReportShareImg string  `description:"研报分享图片"`
+	Hz               int
 }

+ 16 - 0
models/wechat.go

@@ -0,0 +1,16 @@
+package models
+
+type WechatSign struct {
+	AppId     string
+	NonceStr  string
+	Timestamp int64
+	Url       string
+	Signature string
+	RawString string
+}
+
+type WxTicket struct {
+	Errcode int    `json:"errcode"`
+	Errmsg  string `json:"errmsg"`
+	Ticket  string `json:"ticket"`
+}

+ 27 - 0
routers/commentsRouter.go

@@ -7,6 +7,24 @@ import (
 
 func init() {
 
+    beego.GlobalControllerRouter["eta/eta_report/controllers:EnglishReportShareController"] = append(beego.GlobalControllerRouter["eta/eta_report/controllers:EnglishReportShareController"],
+        beego.ControllerComments{
+            Method: "EnglishReportDetail",
+            Router: `/share/detail`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
+    beego.GlobalControllerRouter["eta/eta_report/controllers:EnglishReportShareController"] = append(beego.GlobalControllerRouter["eta/eta_report/controllers:EnglishReportShareController"],
+        beego.ControllerComments{
+            Method: "TrialEnglishReportDetail",
+            Router: `/trial/share/detail`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
     beego.GlobalControllerRouter["eta/eta_report/controllers:ReportShareController"] = append(beego.GlobalControllerRouter["eta/eta_report/controllers:ReportShareController"],
         beego.ControllerComments{
             Method: "Detail",
@@ -16,4 +34,13 @@ func init() {
             Filters: nil,
             Params: nil})
 
+    beego.GlobalControllerRouter["eta/eta_report/controllers:WechatCommonController"] = append(beego.GlobalControllerRouter["eta/eta_report/controllers:WechatCommonController"],
+        beego.ControllerComments{
+            Method: "GetWxSign",
+            Router: `/open/getWxSign`,
+            AllowHTTPMethods: []string{"get"},
+            MethodParams: param.Make(),
+            Filters: nil,
+            Params: nil})
+
 }

+ 10 - 0
routers/router.go

@@ -19,6 +19,16 @@ func init() {
 				&controllers.ReportShareController{},
 			),
 		),
+		web.NSNamespace("/wechat",
+			web.NSInclude(
+				&controllers.WechatCommonController{},
+			),
+		),
+		web.NSNamespace("/english_report",
+			web.NSInclude(
+				&controllers.EnglishReportShareController{},
+			),
+		),
 	)
 	web.AddNamespace(ns)
 }

+ 29 - 0
services/alarm_msg/alarm_msg.go

@@ -0,0 +1,29 @@
+package alarm_msg
+
+import (
+	"encoding/json"
+	"eta/eta_report/utils"
+	"github.com/rdlucklib/rdluck_tools/http"
+)
+
+// SendAlarmMsg
+// projectName-项目名称
+// runMode-运行模式
+// msgBody-消息内容
+// level:消息基本,1:提示消息,2:警告消息,3:严重错误信息,默认为1 提示消息
+func SendAlarmMsg(msgBody string, level int) {
+	if utils.AlarmMsgUrl == "" {
+		return
+	}
+	params := make(map[string]interface{})
+	params["ProjectName"] = utils.APPNAME
+	params["RunMode"] = utils.RunMode
+	params["MsgBody"] = msgBody
+	params["Level"] = level
+	param, err := json.Marshal(params)
+	if err != nil {
+		utils.FileLog.Info("SendAlarmMsg json.Marshal Err:" + err.Error())
+		return
+	}
+	http.Post(utils.AlarmMsgUrl, string(param))
+}

+ 73 - 0
services/wechat.go

@@ -0,0 +1,73 @@
+package services
+
+import (
+	"encoding/json"
+	"errors"
+	"eta/eta_report/models"
+	"eta/eta_report/services/wechat"
+	"eta/eta_report/utils"
+	"fmt"
+	"github.com/rdlucklib/rdluck_tools/http"
+	"strconv"
+	"strings"
+	"time"
+)
+
+func GetWxTicket(accessToken string) (int, string, error) {
+	Url := strings.Join([]string{"https://api.weixin.qq.com/cgi-bin/ticket/getticket",
+		"?access_token=", accessToken,
+		"&type=jsapi"}, "")
+	infoBody, err := http.Get(Url)
+	if err != nil {
+		return 0, "", err
+	}
+	atr := models.WxTicket{}
+	err = json.Unmarshal(infoBody, &atr)
+	fmt.Println("ticket result:", string(infoBody))
+	if err != nil {
+		return atr.Errcode, atr.Errmsg, err
+	} else {
+		return 0, atr.Ticket, nil
+	}
+}
+
+func GetWxSignature(ticket, url, noncestr string) (string, string, int64) {
+	timestamp := time.Now().Unix()
+	signStr := strings.Join([]string{"jsapi_ticket=", ticket,
+		"&noncestr=", noncestr,
+		"&timestamp=", strconv.FormatInt(timestamp, 10), "&url=", url}, "")
+	signature := utils.Sha1(signStr)
+	fmt.Println("signStr", signStr)
+	return signature, noncestr, timestamp
+}
+
+// GetDefaultWxAccessToken 获取微信token
+func GetDefaultWxAccessToken() (accessToken string, err error, errMsg string) {
+	// 微信配置信息
+	conf, e := models.GetBusinessConf()
+	if e != nil {
+		errMsg = "获取配置信息失败, Err: " + e.Error()
+		err = errors.New(errMsg)
+		return
+	}
+	appId := ""
+	appSecret := ""
+	if v, ok := conf[models.BusinessConfWxAppId]; ok {
+		appId = v
+	}
+	if v, ok := conf[models.BusinessConfWxAppSecret]; ok {
+		appSecret = v
+	}
+
+	if appId == "" || appSecret == "" {
+		errMsg = "获取微信公众号未配置"
+		err = errors.New(errMsg)
+		return
+	}
+	req := wechat.WxTokenReq{
+		WxAppId:     appId,
+		WxAppSecret: appSecret,
+	}
+	accessToken, err, errMsg = wechat.GetAccessToken(req)
+	return
+}

+ 89 - 0
services/wechat/token.go

@@ -0,0 +1,89 @@
+package wechat
+
+import (
+	"encoding/json"
+	"errors"
+	"eta/eta_report/services/alarm_msg"
+	"eta/eta_report/utils"
+	"fmt"
+	"io/ioutil"
+	"net/http"
+	"strings"
+)
+
+type WxTokenResp struct {
+	Ret         int
+	Msg         string
+	ErrMsg      string
+	ErrCode     string
+	Data        WxTokenData
+	Success     bool `description:"true 执行成功,false 执行失败"`
+	IsSendEmail bool `json:"-"`
+}
+
+type WxTokenReq struct {
+	WxAppId     string `description:"公众号appId"`
+	WxAppSecret string `description:"公众号appSecret"`
+}
+
+type WxTokenData struct {
+	AccessToken string `description:"微信token"`
+}
+
+// GetAccessToken 获取微信token
+func GetAccessToken(tokenReq WxTokenReq) (accessToken string, err error, errMsg string) {
+	if utils.EtaPubUrl == `` {
+		// 找不到推送服务
+		return
+	}
+	url := fmt.Sprintf("%s%s", utils.EtaPubUrl, "v1/wechat/access_token")
+	defer func() {
+		if err != nil {
+			go alarm_msg.SendAlarmMsg(errMsg, 1)
+		}
+	}()
+	postData, err := json.Marshal(tokenReq)
+	if err != nil {
+		errMsg = "SendTemplateMsg json.Marshal Err:" + err.Error()
+		return
+	}
+	body := ioutil.NopCloser(strings.NewReader(string(postData)))
+	client := &http.Client{}
+	req, err := http.NewRequest("POST", url, body)
+	if err != nil {
+		errMsg = "SendTemplateMsg http.NewRequest Err:" + err.Error()
+		return
+	}
+	contentType := "application/json;charset=utf-8"
+	req.Header.Set("Content-Type", contentType)
+	req.Header.Set("Authorization", utils.EtaPubAuthorization)
+	resp, err := client.Do(req)
+	if err != nil {
+		errMsg = "http client.Do Err:" + err.Error()
+		return
+	}
+	defer resp.Body.Close()
+	b, err := ioutil.ReadAll(resp.Body)
+	if err != nil {
+		errMsg = "ioutil.ReadAll Err:" + err.Error()
+		return
+	}
+	result := new(WxTokenResp)
+	err = json.Unmarshal(b, &result)
+	if err != nil {
+		errMsg = "json.Unmarshal Err:" + err.Error()
+		return
+	}
+	if result.Ret != 200 {
+		err = errors.New(string(b))
+		errMsg = "请求失败:" + err.Error()
+		return
+	}
+	accessToken = result.Data.AccessToken
+	if accessToken == "" {
+		err = errors.New("请求accessToken失败")
+		errMsg = "请求accessToken失败"
+		return
+	}
+	return
+}

+ 32 - 24
utils/common.go

@@ -20,7 +20,7 @@ import (
 	"time"
 )
 
-//随机数种子
+// 随机数种子
 var rnd = rand.New(rand.NewSource(time.Now().UnixNano()))
 
 func GetRandString(size int) string {
@@ -57,13 +57,13 @@ func StringsToJSON(str string) string {
 	return jsons
 }
 
-//序列化
+// 序列化
 func ToString(v interface{}) string {
 	data, _ := json.Marshal(v)
 	return string(data)
 }
 
-//md5加密
+// md5加密
 func MD5(data string) string {
 	m := md5.Sum([]byte(data))
 	return hex.EncodeToString(m[:])
@@ -91,7 +91,7 @@ func GetToday(format string) string {
 	return today
 }
 
-//获取今天剩余秒数
+// 获取今天剩余秒数
 func GetTodayLastSecond() time.Duration {
 	today := GetToday(FormatDate) + " 23:59:59"
 	end, _ := time.ParseInLocation(FormatDateTime, today, time.Local)
@@ -113,7 +113,7 @@ func GetBrithDate(idcard string) string {
 	return GetToday(FormatDate)
 }
 
-//处理性别
+// 处理性别
 func WhichSexByIdcard(idcard string) string {
 	var sexs = [2]string{"女", "男"}
 	length := len(idcard)
@@ -127,7 +127,7 @@ func WhichSexByIdcard(idcard string) string {
 	return "男"
 }
 
-//截取小数点后几位
+// 截取小数点后几位
 func SubFloatToString(f float64, m int) string {
 	n := strconv.FormatFloat(f, 'f', -1, 64)
 	if n == "" {
@@ -146,14 +146,14 @@ func SubFloatToString(f float64, m int) string {
 	return newn[0] + "." + newn[1][:m]
 }
 
-//截取小数点后几位
+// 截取小数点后几位
 func SubFloatToFloat(f float64, m int) float64 {
 	newn := SubFloatToString(f, m)
 	newf, _ := strconv.ParseFloat(newn, 64)
 	return newf
 }
 
-//获取相差时间-年
+// 获取相差时间-年
 func GetYearDiffer(start_time, end_time string) int {
 	t1, _ := time.ParseInLocation("2006-01-02", start_time, time.Local)
 	t2, _ := time.ParseInLocation("2006-01-02", end_time, time.Local)
@@ -164,7 +164,7 @@ func GetYearDiffer(start_time, end_time string) int {
 	return age
 }
 
-//获取相差时间-秒
+// 获取相差时间-秒
 func GetSecondDifferByTime(start_time, end_time time.Time) int64 {
 	diff := end_time.Unix() - start_time.Unix()
 	return diff
@@ -191,38 +191,38 @@ func StrListToString(strList []string) (str string) {
 	return ""
 }
 
-//Token
-func GetToken() string {
-	randStr := GetRandString(64)
-	token := MD5(randStr + Md5Key)
-	tokenLen := 64 - len(token)
-	return strings.ToUpper(token + GetRandString(tokenLen))
-}
+// Token
+//func GetToken() string {
+//	randStr := GetRandString(64)
+//	token := MD5(randStr + Md5Key)
+//	tokenLen := 64 - len(token)
+//	return strings.ToUpper(token + GetRandString(tokenLen))
+//}
 
-//数据没有记录
+// 数据没有记录
 func ErrNoRow() string {
 	return "<QuerySeter> no row found"
 }
 
-//校验邮箱格式
+// 校验邮箱格式
 func ValidateEmailFormatat(email string) bool {
 	reg := regexp.MustCompile(RegularEmail)
 	return reg.MatchString(email)
 }
 
-//验证是否是手机号
+// 验证是否是手机号
 func ValidateMobileFormatat(mobileNum string) bool {
 	reg := regexp.MustCompile(RegularMobile)
 	return reg.MatchString(mobileNum)
 }
 
-//判断文件是否存在
+// 判断文件是否存在
 func FileIsExist(filePath string) bool {
 	_, err := os.Stat(filePath)
 	return err == nil || os.IsExist(err)
 }
 
-//获取图片扩展名
+// 获取图片扩展名
 func GetImgExt(file string) (ext string, err error) {
 	var headerByte []byte
 	headerByte = make([]byte, 8)
@@ -265,7 +265,7 @@ func GetImgExt(file string) (ext string, err error) {
 	return ext, nil
 }
 
-//保存图片
+// 保存图片
 func SaveImage(path string, img image.Image) (err error) {
 	//需要保持的文件
 	imgfile, err := os.Create(path)
@@ -275,7 +275,7 @@ func SaveImage(path string, img image.Image) (err error) {
 	return err
 }
 
-//保存base64数据为文件
+// 保存base64数据为文件
 func SaveBase64ToFile(content, path string) error {
 	data, err := base64.StdEncoding.DecodeString(content)
 	if err != nil {
@@ -405,7 +405,7 @@ func GetWilsonScore(p, n float64) float64 {
 	return toFixed(((p+1.9208)/(p+n)-1.96*math.Sqrt(p*n/(p+n)+0.9604)/(p+n))/(1+3.8416/(p+n)), 2)
 }
 
-//将中文数字转化成数字,比如 第三百四十五章,返回第345章 不支持一亿及以上
+// 将中文数字转化成数字,比如 第三百四十五章,返回第345章 不支持一亿及以上
 func ChangeWordsToNum(str string) (numStr string) {
 	words := ([]rune)(str)
 	num := 0
@@ -572,3 +572,11 @@ func GetLocalIP() (ip string, err error) {
 	}
 	return
 }
+
+func TimeTransferString(format string, t time.Time) string {
+	str := t.Format(format)
+	if t.IsZero() {
+		return ""
+	}
+	return str
+}

+ 56 - 4
utils/config.go

@@ -21,6 +21,29 @@ var (
 	ApiLogFile string
 )
 
+// 系统配置
+var (
+	DesKey           string // 加密key
+	EmailSendToUsers string // 邮件提醒人员
+	BusinessCode     string // 商户号
+)
+
+// 公共api内部服务调用
+var (
+	// EtaPubUrl 模板消息推送
+	EtaPubUrl string
+
+	// EtaPubAuthorization 模板推送秘钥
+	EtaPubAuthorization string
+
+	// AlarmMsgUrl 报警服务地址
+	AlarmMsgUrl string
+
+	Html2ImgServerUrl  string // html转图片服务地址
+	EtaReportAppNameEn string // 内部调用该服务的英文名
+	EtaReportKey       string // 内部调用该服务的鉴权Key
+)
+
 func init() {
 	tmpRunMode, err := web.AppConfig.String("run_mode")
 	if err != nil {
@@ -51,11 +74,7 @@ func init() {
 	fmt.Println(RunMode + " 模式")
 	MYSQL_URL = config["mysql_url"]
 	MYSQL_URL_ETA = config["mysql_url_eta"]
-	if RunMode == "release" {
 
-	} else {
-
-	}
 	//日志配置
 	{
 		LogPath = config["log_path"]
@@ -65,4 +84,37 @@ func init() {
 		ApiLogPath = config["apilog_path"]
 		ApiLogFile = config["apilog_file"]
 	}
+
+	// 系统配置
+	{
+		// 接口返回加密KEY
+		DesKey = config["des_key"]
+
+		// 邮件提醒人员
+		EmailSendToUsers = config["email_send_to_users"]
+
+		// 商户号
+		BusinessCode = config["business_code"]
+	}
+
+	// 系统内部服务地址
+	{
+		// 发送微信模板消息地址
+		EtaPubUrl = config["eta_pub_url"]
+
+		// 发送微信模板消息地址
+		EtaPubAuthorization = config["eta_pub_authorization"]
+
+		// 报警服务地址
+		AlarmMsgUrl = config["alarm_msg_url"]
+
+		// html转图片服务地址
+		Html2ImgServerUrl = config["html2img_server_url"]
+
+		// 内部调用项目英文名
+		EtaReportAppNameEn = config["eta_report_app_name_en"]
+
+		// 内部调用鉴权Key
+		EtaReportKey = config["eta_report_key"]
+	}
 }

+ 1 - 2
utils/constants.go

@@ -20,8 +20,7 @@ const (
 )
 
 const (
-	APPNAME          = "弘则-日度点评"
-	EmailSendToUsers = "glji@hzinsights.com;pyan@hzinsights.com"
+	APPNAME = "ETA报告服务"
 )
 
 // 手机号,电子邮箱正则

+ 6 - 6
utils/des3.go

@@ -1,4 +1,4 @@
-//加密工具类,用了3des和base64
+// 加密工具类,用了3des和base64
 package utils
 
 import (
@@ -11,9 +11,9 @@ import (
 	"strings"
 )
 
-//des3 + base64 encrypt
+// des3 + base64 encrypt
 func DesBase64Encrypt(origData []byte) []byte {
-	result, err := TripleDesEncrypt(origData, []byte(key))
+	result, err := TripleDesEncrypt(origData, []byte(DesKey))
 	if err != nil {
 		panic(err)
 	}
@@ -29,7 +29,7 @@ func DesBase64Decrypt(crypted []byte) []byte {
 			result = append(result, 0)
 		}
 	}
-	origData, err := TripleDesDecrypt(result, []byte(key))
+	origData, err := TripleDesDecrypt(result, []byte(DesKey))
 	if err != nil {
 		panic(err)
 	}
@@ -90,7 +90,7 @@ func PKCS5UnPadding(origData []byte) []byte {
 	return origData[:(length - unpadding)]
 }
 
-//DES加密
+// DES加密
 func DesEncrypt(content string, key string) string {
 	contents := []byte(content)
 	keys := []byte(key)
@@ -117,7 +117,7 @@ func byteToHexString(bytes []byte) string {
 	return str
 }
 
-//DES解密
+// DES解密
 func DesDecrypt(content string, key string) string {
 	contentBytes, err := hex.DecodeString(content)
 	if err != nil {