作者 yangfu

Merge remote-tracking branch 'origin/dev' into test

FROM 192.168.0.243:5000/mmm/mmmopp:20200422 as builder
#FROM golang:1.13 as builder
#FROM 192.168.0.243:5000/mmm/mmmopp:20200110 as builder
FROM golang:1.13 as builder
ENV GOPROXY https://goproxy.cn
ENV GO111MODULE on
ENV GOPATH /go
#RUN git clone http://gitlab.fjmaimaimai.com/mmm-go/gocomm.git /go/src/gocomm
RUN git clone http://gitlab.fjmaimaimai.com/mmm-go/gocomm.git /go/src/gocomm
RUN cd /go/src/gocomm \
&& git pull
WORKDIR /go/src/openapi
... ... @@ -13,8 +13,8 @@ COPY go.mod .
COPY . .
RUN GOOS=linux CGO_ENABLED=0 go build -ldflags="-s -w" -o openapi main.go
#FROM alpine:latest
FROM 192.168.0.243:5000/mmm/mmmopp:20200110
FROM alpine:latest
#FROM 192.168.0.243:5000/mmm/mmmopp:20200110
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories \
&& apk add --no-cache tzdata \
&& ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
... ...
... ... @@ -8,6 +8,7 @@ require (
github.com/aliyun/aliyun-oss-go-sdk v2.1.4+incompatible
github.com/aliyun/aliyun-sts-go-sdk v0.0.0-20171106034748-98d3903a2309
github.com/astaxie/beego v1.10.0
github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f // indirect
github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072 // indirect
github.com/fatih/structs v1.1.0 // indirect
github.com/gavv/httpexpect v2.0.0+incompatible
... ...
package main
import _ "openapi/pkg/log"
import (
"fmt"
"github.com/astaxie/beego"
"gitlab.fjmaimaimai.com/mmm-go/gocomm/config"
"gitlab.fjmaimaimai.com/mmm-go/gocomm/pkg/log"
"gitlab.fjmaimaimai.com/mmm-go/gocomm/pkg/redis"
"openapi/pkg/constant"
_ "openapi/pkg/infrastructure/bgorm"
_ "openapi/pkg/log"
_ "openapi/pkg/port/beego"
)
... ... @@ -18,11 +21,20 @@ func main() {
//constant.DebugConfig()
//https
beego.BConfig.Listen.EnableHTTPS = true
beego.BConfig.Listen.Graceful = true
beego.BConfig.Listen.HTTPSPort = 443
beego.BConfig.Listen.HTTPSCertFile = "conf/_.fjmaimaimai.com_bundle.crt"
beego.BConfig.Listen.HTTPSKeyFile = "conf/fjmaimaimai.com_RSA.fjmaimaimai.com_RSA.key"
//beego.BConfig.Listen.EnableHTTPS = true
//beego.BConfig.Listen.Graceful = true
//beego.BConfig.Listen.HTTPSPort = 443
//beego.BConfig.Listen.HTTPSCertFile = "conf/_.fjmaimaimai.com_bundle.crt"
//beego.BConfig.Listen.HTTPSKeyFile = "conf/fjmaimaimai.com_RSA.fjmaimaimai.com_RSA.key"
err := redis.Init(config.Redis{
Addr: fmt.Sprintf("%v:%v", constant.REDIS_HOST, constant.REDIS_PORT),
Password: constant.REDIS_AUTH,
MaxIdle: 50,
})
if err != nil {
log.Error(err)
}
beego.Run()
}
... ...
... ... @@ -48,7 +48,12 @@ func Notification(header *protocol.RequestHeader, request *protocol.PushInfoRequ
return
}
if extInfo, ok := appInfo.GetExtInfo(); ok {
requestOriginal.Ext["intent"] = extInfo.Intent
if len(extInfo.Intent) > 0 {
requestOriginal.Ext["intent"] = extInfo.Intent
}
if len(extInfo.Sound) > 0 {
requestOriginal.Ext["sound"] = extInfo.Sound
}
}
if len(deviceList) == 0 {
err = protocol.NewSuccessWithMessage(fmt.Sprintf("接收人:%v 未查询到注册的设备信息!", request.Receivers))
... ...
package service
import (
"fmt"
"gitlab.fjmaimaimai.com/mmm-go/gocomm/common"
"gitlab.fjmaimaimai.com/mmm-go/gocomm/pkg/log"
"gitlab.fjmaimaimai.com/mmm-go/gocomm/pkg/redis"
protocol "openapi/pkg/domain"
"openapi/pkg/infrastructure/sms"
"openapi/pkg/infrastructure/sms/yunpian"
"strings"
)
// SmsCode 发送短信验证码
func SmsCode(header *protocol.RequestHeader, request *protocol.SmsCodeRequest) (rsp interface{}, err error) {
code := common.RandomStringWithChars(6, protocol.Nums)
var smsSvr sms.ISmsService = &yunpian.YPSmsService{}
content := fmt.Sprintf("【买买买信息科技】%v(手机验证码,请完成验证),如非本人操作,请忽略本短信", code)
// save log to db
log.Debug(fmt.Sprintf("【sms】 smscode phone:%v code:%v", request.Phone, code))
// save to redis
if err = redis.Set(smsRedisKey(request.Phone), code, sms.DefaultSmsCodeTimeOut); err != nil {
logError(err)
err = protocol.NewCustomMessage(1001, "请求超时,请检查手机号是否正确或网络连接状态")
return nil, err
}
if err = smsSvr.Send(&sms.Options{Phone: request.Phone, SendType: sms.SendSingle, Content: content}); err != nil {
logError(err)
err = protocol.NewCustomMessage(1001, "请求超时,请检查手机号是否正确或网络连接状态")
return nil, err
}
return
}
// CheckSmsCode 检查短信验证码
func CheckSmsCode(header *protocol.RequestHeader, request *protocol.CheckSmsCodeRequest) (rsp interface{}, err error) {
var value string
if value, err = redis.Get(smsRedisKey(request.Phone)); err != nil || len(value) == 0 {
logError(err)
err = protocol.NewCustomMessage(1004, "验证码已失效")
return nil, err
}
if !strings.EqualFold(value, request.Code) {
err = protocol.NewCustomMessage(1004, "验证码错误,重新输入")
return nil, err
}
redis.Del(smsRedisKey(request.Phone))
return
}
// SendSmsNotice 发送短信通知
func SendSmsNotice(header *protocol.RequestHeader, request *protocol.SendSmsNoticeRequest) (rsp interface{}, err error) {
var smsSvr sms.ISmsService = &yunpian.YPSmsService{}
options := sms.NewOptions(
sms.WithPhone(request.Phone),
sms.WithSendType(sms.SendSingleByTpl),
sms.WithTpl(request.TplId, request.TplValues),
)
err = smsSvr.Send(options)
return
}
func logError(err error) {
log.Error(fmt.Sprintf("【sms】 %v", err.Error()))
}
func smsRedisKey(phone string) string {
return strings.Join([]string{"sms", "smscode", phone}, ":")
}
... ...
... ... @@ -8,11 +8,13 @@ import (
var (
LogFilePath string = "F:/log/app.log"
LogLevel string = "error"
RunMode string = "dev"
)
func init() {
LogLevel = config.StringDefault("log_level", LogLevel)
LogFilePath = config.StringDefault("aliyun_logs_access", LogFilePath)
RunMode = config.StringDefault("RUN_MODE", RunMode)
}
func DebugConfig() {
... ...
package constant
import "os"
var REDIS_HOST = "127.0.0.1"
var REDIS_PORT = "6379"
var REDIS_AUTH = ""
func init() {
if os.Getenv("REDIS_HOST") != "" {
REDIS_HOST = os.Getenv("REDIS_HOST")
REDIS_AUTH = os.Getenv("REDIS_AUTH")
}
if os.Getenv("REDIS_PORT") != "" {
REDIS_PORT = os.Getenv("REDIS_PORT")
}
if _, ok := os.LookupEnv("REDIS_AUTH"); ok {
REDIS_AUTH = os.Getenv("REDIS_AUTH")
}
}
... ...
package constant
var (
YunPianAppKey = "0bf6fb10a11a68a95dee80901eb545b5"
YunPianSDKHost = "https://sms.yunpian.com/v2/"
SmsSendSingle = "sms/single_send.json"
SmsSendSingleByTpl = "sms/tpl_single_send.json"
)
... ...
package domain
var errmessge ErrorMap = map[int]string{
0: "成功",
1: "系统异常",
2: "参数错误",
113: "签名验证失败",
0: "成功",
1: "系统异常",
2: "参数错误",
113: "签名验证失败",
1001: "请求超时,请检查手机号是否正确或网络连接状态",
1002: "请输入正确的手机号码",
1003: "验证码错误,重新输入",
1004: "验证码已失效",
}
... ...
... ... @@ -65,6 +65,7 @@ type AppInfo struct {
type ExtInfo struct {
Intent string `json:"intent"`
Sound string `json:"sound,omitempty"`
}
func (t *AppInfo) GetExtInfo() (*ExtInfo, bool) {
... ...
package domain
var Nums = "0123456789"
/*发送短信验证码*/
type SmsCodeRequest struct {
Project string `json:"project"`
Phone string `json:"phone" valid:"required"`
}
type CheckSmsCodeRequest struct {
Phone string `json:"phone" valid:"required"`
Code string `json:"code" valid:"required"`
}
type SendSmsNoticeRequest struct {
// 手机号
Phone string `json:"phone" valid:"required"`
// 模板id
TplId int `json:"tplId" valid:"required"`
// 模板参数
TplValues map[string]interface{} `json:"tplValues"`
}
... ...
... ... @@ -183,6 +183,11 @@ func (notify *GetuiNotification) GetAuthToken() (token string, err error) {
authMux.Lock()
defer authMux.Unlock()
// recheck
if authtoken != "" && expire.Unix() > time.Now().Unix() {
token = authtoken
return
}
url := notify.Url(notify.Options.AppId, authSign)
notify.Request = httplib.Post(strings.TrimSpace(url))
req := &AuthSignRequest{
... ...
... ... @@ -3,6 +3,7 @@ package getuiV2
import (
"openapi/pkg/infrastructure/push"
"openapi/pkg/infrastructure/utils"
"sync"
"testing"
)
... ... @@ -77,3 +78,29 @@ func TestGetuiPrd(t *testing.T) {
t.Fatal(err)
}
}
func TestGetAuthToken(t *testing.T) {
var wg sync.WaitGroup
round := 100
notification := &GetuiNotification{}
var tokenMap = make(map[string]string)
notification.Init(
push.DebugModule(true),
push.AppId("WgrbaaStTk7JElrXOCgUg6"),
push.AppKey("FG5lbqVrHa5rS9NVfxNP7"),
push.AppMasterSecret("FW3jMNLJrRARYKv2iqA5H5"),
)
for i := 0; i < round; i++ {
wg.Add(1)
go func() {
defer wg.Done()
token, _ := notification.GetAuthToken()
tokenMap[token] = token
}()
}
wg.Wait()
if len(tokenMap) > 1 {
t.Fatalf("token want 1 get %v", len(tokenMap))
}
}
... ...
... ... @@ -72,6 +72,16 @@ func NewPushMessage(option *push.Options) map[string]interface{} {
// setting
m.AddFiled("settings.ttl", 3600*24)
/*
默认所有通道的策略选择1-4
1: 表示该消息在用户在线时推送个推通道,用户离线时推送厂商通道;
2: 表示该消息只通过厂商通道策略下发,不考虑用户是否在线;
3: 表示该消息只通过个推通道下发,不考虑用户是否在线;
4: 表示该消息优先从厂商通道下发,若消息内容在厂商通道代发失败后会从个推通道下发。
其中名称可填写: ios、st、hw、xm、vv、mz、op
*/
m.AddFiled("settings.strategy.default", 1)
m.AddFiled("settings.strategy.ios", 4)
// audience
m.AddFiled("audience.cid", []string{option.ClientId})
... ...
package sms
const (
SendSingle SendType = 1
SendList SendType = 2
SendSingleByTpl SendType = 10
)
const DefaultSmsCodeTimeOut int64 = 60 * 2
type (
SendType int
ISmsService interface {
Send(option *Options) error
}
Options struct {
Phone string
Content string
SendType SendType
TplId int
TplValues map[string]interface{}
}
option func(o *Options)
)
func NewOptions(options ...option) *Options {
o := &Options{}
for i := range options {
options[i](o)
}
return o
}
func WithPhone(phone string) option {
return func(o *Options) {
o.Phone = phone
}
}
func WithSendType(sendType SendType) option {
return func(o *Options) {
o.SendType = sendType
}
}
func WithTpl(tplId int, tplValues map[string]interface{}) option {
return func(o *Options) {
o.TplId = tplId
o.TplValues = tplValues
}
}
... ...
package yunpian
import (
"bytes"
"fmt"
"github.com/astaxie/beego/httplib"
"gitlab.fjmaimaimai.com/mmm-go/gocomm/common"
"gitlab.fjmaimaimai.com/mmm-go/gocomm/pkg/log"
"net/url"
"openapi/pkg/constant"
"openapi/pkg/infrastructure/sms"
"strconv"
)
type (
YPSmsService struct{}
YPSmsResponse struct {
Code int `json:"code"` //0代表发送成功,其他code代表出错,详细见"返回值说明"页面
Msg string `json:"msg"` //例如""发送成功"",或者相应错误信息
Count int `json:"count"` //发送成功短信的计费条数(计费条数:70个字一条,超出70个字时按每67字一条计费)
Mobile string `json:"string"` //发送手机号
Fee float64 `json:"fee"` //扣费金额,单位:元,类型:双精度浮点型/double
Sid int64 `json:"sid"` //短信id,64位整型
}
)
func (svr *YPSmsService) Send(option *sms.Options) error {
var err error
if option.SendType == sms.SendSingle {
_, err = sendSingle(option)
} else if option.SendType == sms.SendSingleByTpl {
_, err = sendSingleByTpl(option)
}
return err
}
func sendSingle(option *sms.Options) (map[string]interface{}, error) {
var (
resp *YPSmsResponse
err error
url = constant.YunPianSDKHost + constant.SmsSendSingle
)
post := httplib.Post(url)
post.Param("apikey", constant.YunPianAppKey)
post.Param("mobile", option.Phone)
post.Param("text", option.Content)
if err = post.ToJSON(&resp); err != nil {
return nil, err
}
err = resolveResponse(resp, err)
return nil, err
}
func sendSingleByTpl(option *sms.Options) (map[string]interface{}, error) {
var (
resp *YPSmsResponse
err error
url = constant.YunPianSDKHost + constant.SmsSendSingleByTpl
)
post := httplib.Post(url)
post.Param("apikey", constant.YunPianAppKey)
post.Param("mobile", option.Phone)
post.Param("tpl_id", strconv.Itoa(option.TplId))
if len(option.TplValues) > 0 {
post.Param("tpl_value", tplValue(option.TplValues))
log.Debug(tplValue(option.TplValues))
}
if err = post.ToJSON(&resp); err != nil {
return nil, err
}
err = resolveResponse(resp, err)
return nil, err
}
func resolveResponse(resp *YPSmsResponse, err error) error {
if resp.Code != 0 {
log.Error("【sms】 send sms code:", resp.Code, " error msg:", resp.Msg)
err = common.NewErrorWithMsg(1, resp.Msg)
return err
}
return err
}
func tplValue(tplValues map[string]interface{}) string {
var value bytes.Buffer
for k, v := range tplValues {
value.WriteString(url.PathEscape(fmt.Sprintf("#%v#=%v&", k, v)))
}
return string(value.Bytes()[:value.Len()-1])
}
... ...
... ... @@ -167,3 +167,10 @@ func GetPageInfo(pageIndex, pageSize int) (offset, size int) {
size = pageSize
return
}
func IsProductEnv(env string) bool {
if env == "prod" {
return true
}
return false
}
... ...
... ... @@ -35,6 +35,7 @@ func (this *PushController) PushInfo() {
if len(request.ProjectKey) == 0 || request.ProjectKey == "worth" {
request.ProjectKey = "mmm.ability.worth" //默认是价值项目
}
request.Type = 0 // TODO: 测试需要强制0,后期需要改回来
header := controllers.GetRequestHeader(this.Ctx)
msg = protocol.NewReturnResponse(push.Notification(header, request))
}
... ...
package v1
import (
"bytes"
"encoding/json"
"github.com/astaxie/beego/validation"
"gitlab.fjmaimaimai.com/mmm-go/gocomm/pkg/log"
sms "openapi/pkg/application/sms/service"
"openapi/pkg/constant"
protocol "openapi/pkg/domain"
"openapi/pkg/infrastructure/utils"
"openapi/pkg/port/beego/controllers"
)
type SmsController struct {
controllers.BaseController
}
//短信验证码 SmsCode
// @router /smsCode [post]
func (this *SmsController) SmsCode() {
var msg *protocol.ResponseMessage
defer func() {
this.Resp(msg)
}()
var request *protocol.SmsCodeRequest
decoder := json.NewDecoder(bytes.NewBuffer(this.ByteBody))
decoder.UseNumber()
if err := decoder.Decode(&request); err != nil {
log.Error(err)
msg = protocol.BadRequestParam(1)
return
}
if utils.IsProductEnv(constant.RunMode) {
valid := validation.Validation{}
if !valid.Mobile(request.Phone, "mobile").Ok {
msg = protocol.BadRequestParam(1001)
return
}
}
header := controllers.GetRequestHeader(this.Ctx)
msg = protocol.NewReturnResponse(sms.SmsCode(header, request))
}
//检查短信验证码 CheckSmsCode
// @router /checkSmsCode [post]
func (this *SmsController) CheckSmsCode() {
var msg *protocol.ResponseMessage
defer func() {
this.Resp(msg)
}()
var request *protocol.CheckSmsCodeRequest
decoder := json.NewDecoder(bytes.NewBuffer(this.ByteBody))
decoder.UseNumber()
if err := decoder.Decode(&request); err != nil {
log.Error(err)
msg = protocol.BadRequestParam(1)
return
}
if utils.IsProductEnv(constant.RunMode) {
valid := validation.Validation{}
if !valid.Mobile(request.Phone, "mobile").Ok {
msg = protocol.BadRequestParam(1002)
return
}
}
header := controllers.GetRequestHeader(this.Ctx)
msg = protocol.NewReturnResponse(sms.CheckSmsCode(header, request))
}
//发送短信通知 sendSmsNotice
// @router /sendSmsNotice [post]
func (this *SmsController) SendSmsNotice() {
var msg *protocol.ResponseMessage
defer func() {
this.Resp(msg)
}()
var request *protocol.SendSmsNoticeRequest
decoder := json.NewDecoder(bytes.NewBuffer(this.ByteBody))
decoder.UseNumber()
if err := decoder.Decode(&request); err != nil {
log.Error(err)
msg = protocol.BadRequestParam(1)
return
}
if utils.IsProductEnv(constant.RunMode) {
valid := validation.Validation{}
if !valid.Mobile(request.Phone, "mobile").Ok {
msg = protocol.BadRequestParam(1002)
return
}
}
header := controllers.GetRequestHeader(this.Ctx)
msg = protocol.NewReturnResponse(sms.SendSmsNotice(header, request))
}
... ...
... ... @@ -100,4 +100,25 @@ func init() {
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Params: nil})
beego.GlobalControllerRouter["openapi/pkg/port/beego/controllers/v1:SmsController"] = append(beego.GlobalControllerRouter["openapi/pkg/port/beego/controllers/v1:SmsController"],
beego.ControllerComments{
Method: "SmsCode",
Router: `/smsCode`,
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Params: nil})
beego.GlobalControllerRouter["openapi/pkg/port/beego/controllers/v1:SmsController"] = append(beego.GlobalControllerRouter["openapi/pkg/port/beego/controllers/v1:SmsController"],
beego.ControllerComments{
Method: "CheckSmsCode",
Router: `/checkSmsCode`,
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Params: nil})
beego.GlobalControllerRouter["openapi/pkg/port/beego/controllers/v1:SmsController"] = append(beego.GlobalControllerRouter["openapi/pkg/port/beego/controllers/v1:SmsController"],
beego.ControllerComments{
Method: "SendSmsNotice",
Router: `/sendSmsNotice`,
AllowHTTPMethods: []string{"post"},
MethodParams: param.Make(),
Params: nil})
}
... ...
... ... @@ -13,6 +13,7 @@ func init() {
nsV1 := beego.NewNamespace("v1",
beego.NSNamespace("vod", beego.NSBefore(controllers.AllowOption), beego.NSInclude(&v1.VodController{})),
beego.NSNamespace("push", beego.NSBefore(controllers.AllowOption), beego.NSInclude(&v1.PushController{})),
beego.NSNamespace("sms", beego.NSBefore(controllers.AllowOption), beego.NSInclude(&v1.SmsController{})),
)
beego.SetStaticPath("/log/NIONkenfieldon", constant.LogFilePath)
beego.AddNamespace(nsV1)
... ...