Browse Source

更新

master
huangjiajun 5 months ago
parent
commit
07e86deae3
21 changed files with 1096 additions and 20 deletions
  1. +3
    -2
      app/cfg/cfg_app.go
  2. +4
    -2
      app/cfg/init_cfg.go
  3. +63
    -0
      app/db/db_sys_mod_format_img.go
  4. +104
    -0
      app/db/dbs.go
  5. +194
    -0
      app/db/dbs_map.go
  6. +18
    -0
      app/db/model/db_mapping.go
  7. +8
    -0
      app/db/model/user_app_list.go
  8. +7
    -0
      app/db/station/sys_cfg.go
  9. +41
    -0
      app/hdl/zhimeng_platform/hdl_withdrawal.go
  10. +270
    -0
      app/lib/mob/api.go
  11. +84
    -0
      app/lib/sms/sms.go
  12. +66
    -0
      app/lib/zhimeng/api.go
  13. +98
    -0
      app/lib/zhimeng/sdk.go
  14. +70
    -0
      app/lib/zhimeng/sms_send.go
  15. +8
    -0
      app/md/md_login.go
  16. +10
    -1
      app/mw/mw_auth_jwt.go
  17. +2
    -2
      app/mw/mw_request_cache.go
  18. +1
    -0
      app/router/router.go
  19. +40
    -11
      app/svc/platform/svc_withdrawal.go
  20. +1
    -1
      go.mod
  21. +4
    -1
      main.go

+ 3
- 2
app/cfg/cfg_app.go View File

@@ -13,9 +13,10 @@ type Config struct {
ZhimengDB DBCfg `yaml:"zhimeng_db"`
Log LogCfg `yaml:"log"`
ES ESCfg `yaml:"es"`
Local bool
}

//数据库配置结构体
// 数据库配置结构体
type DBCfg struct {
Host string `yaml:"host"` //ip及端口
Name string `yaml:"name"` //库名
@@ -28,7 +29,7 @@ type DBCfg struct {
Path string `yaml:"path"` //日志文件存放路径
}

//日志配置结构体
// 日志配置结构体
type LogCfg struct {
AppName string `yaml:"app_name" `
Level string `yaml:"level"`


+ 4
- 2
app/cfg/init_cfg.go View File

@@ -7,7 +7,7 @@ import (
"gopkg.in/yaml.v2"
)

//配置文件数据,全局变量
// 配置文件数据,全局变量
var (
Debug bool
Prd bool
@@ -17,9 +17,10 @@ var (
ZhimengDB *DBCfg
Log *LogCfg
ES *ESCfg
Local bool
)

//初始化配置文件,将cfg.yml读入到内存
// 初始化配置文件,将cfg.yml读入到内存
func InitCfg() {
//用指定的名称、默认值、使用信息注册一个string类型flag。
path := flag.String("c", "etc/cfg.yml", "config file")
@@ -47,4 +48,5 @@ func InitCfg() {
Log = &conf.Log
RedisAddr = conf.RedisAddr
SrvAddr = conf.SrvAddr
Local = conf.Local
}

+ 63
- 0
app/db/db_sys_mod_format_img.go View File

@@ -0,0 +1,63 @@
package db

import (
"applet/app/db/station"
"applet/app/utils/logx"
"github.com/gin-gonic/gin"
"xorm.io/xorm"
)

// 单条记录获取DB
func SysCfgGet(c *gin.Context, key string) string {
res := SysCfgFind(c, key)
if _, ok := res[key]; !ok {
return ""
}
return res[key]
}

// 多条记录获取
func SysCfgFind(c *gin.Context, keys ...string) map[string]string {
eg := DBs[c.GetString("master_id")]
masterId := c.GetString("master_id")
res := map[string]string{}
//TODO::判断keys长度(大于10个直接查数据库)
if len(keys) > 10 {
cfgList, _ := SysCfgGetAll(eg)
if cfgList == nil {
return nil
}
for _, v := range *cfgList {
res[v.Key] = v.Val
}
} else {
for _, key := range keys {
res[key] = SysCfgGetWithDb(eg, masterId, key)
}
}
return res
}
func SysCfgGetAll(Db *xorm.Engine) (*[]model.SysCfg, error) {
var cfgList []model.SysCfg
if err := Db.Cols("key,val,memo").Find(&cfgList); err != nil {
return nil, logx.Error(err)
}
return &cfgList, nil
}
func SysCfgGetOne(Db *xorm.Engine, key string) (*model.SysCfg, error) {
var cfgList model.SysCfg
if has, err := Db.Where("`key`=?", key).Get(&cfgList); err != nil || has == false {
return nil, logx.Error(err)
}
return &cfgList, nil
}

// 单条记录获取DB
func SysCfgGetWithDb(eg *xorm.Engine, masterId string, HKey string) string {
cfg, err := SysCfgGetOne(eg, HKey)
if err != nil || cfg == nil {
_ = logx.Error(err)
return ""
}
return cfg.Val
}

+ 104
- 0
app/db/dbs.go View File

@@ -0,0 +1,104 @@
package db

import (
"fmt"
"os"
"time"

"xorm.io/xorm"
"xorm.io/xorm/log"

"applet/app/cfg"
"applet/app/db/model"
"applet/app/utils/logx"
)

var DBs map[string]*xorm.Engine

// 每个站长都要有自己的syscfg 缓存, 键是站长id,值是缓存名
// var SysCfgMapKey map[string]string

func NewDB(c *cfg.DBCfg) (*xorm.Engine, error) {
db, err := xorm.NewEngine("mysql", fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4", c.User, c.Psw, c.Host, c.Name))
if err != nil {
return nil, err
}
db.SetConnMaxLifetime(c.MaxLifetime * time.Second)
db.SetMaxOpenConns(c.MaxOpenConns)
db.SetMaxIdleConns(c.MaxIdleConns)
err = db.Ping()
if err != nil {
return nil, err
}
if c.ShowLog {
db.ShowSQL(true)
db.Logger().SetLevel(log.LOG_DEBUG)
f, err := os.OpenFile(c.Path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0777)
if err != nil {
os.RemoveAll(c.Path)
if f, err = os.OpenFile(c.Path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0777); err != nil {
return nil, err
}
}
logger := log.NewSimpleLogger(f)
logger.ShowSQL(true)
db.SetLogger(logger)
}
return db, nil
}

// InitDBs is 初始化多数据库
func InitDBs(ch chan int) {
// 初始化多数据库
var tables *[]model.DbMapping
InitMapDbs(cfg.DB, cfg.Prd)
ch <- 1
// 每10s 查询一次模板数据库的db mapping 表,如果有新增数据库记录,则添加到 DBs中
ticker := time.NewTicker(time.Duration(time.Second * 120))
for range ticker.C {
if cfg.Prd {
tables = GetAllDatabasePrd() //默认获取全部
} else {
tables = GetAllDatabaseDev() //默认获取全部
}
if tables == nil {
logx.Warn("no database tables data")
continue
}
for _, item := range *tables {
_, ok := DBs[item.DbMasterId]
if !ok {
// 不在db.DBs 则添加进去
dbCfg := cfg.DBCfg{
Name: item.DbName,
ShowLog: cfg.DB.ShowLog,
MaxLifetime: cfg.DB.MaxLifetime,
MaxOpenConns: cfg.DB.MaxOpenConns,
MaxIdleConns: cfg.DB.MaxIdleConns,
Path: fmt.Sprintf(cfg.DB.Path, item.DbName),
}
if item.DbHost != "" && item.DbUsername != "" && item.DbPassword != "" {
dbCfg.Host = item.DbHost
dbCfg.User = item.DbUsername
dbCfg.Psw = item.DbPassword
} else {
dbCfg.Host = cfg.DB.Host
dbCfg.User = cfg.DB.User
dbCfg.Psw = cfg.DB.Psw
}
e, err := NewDB(&dbCfg)
if err != nil || e == nil {
logx.Warnf("db engine can't create, please check config, params[host:%s, user:%s, psw: %s, name: %s], err: %v", dbCfg.Host, dbCfg.User, dbCfg.Psw, dbCfg.Name, err)
} else {
DBs[item.DbMasterId] = e
}
}
// 如果 被禁用则删除
if item.DeletedAt == 1 {
logx.Infof("%s have been removed", item.DbMasterId)
delete(DBs, item.DbMasterId)
}
}
}

}

+ 194
- 0
app/db/dbs_map.go View File

@@ -0,0 +1,194 @@
package db

import (
"errors"
"fmt"

"xorm.io/xorm"

"applet/app/cfg"
"applet/app/db/model"
"applet/app/utils/logx"
)

func MapBaseExists() (bool, error) {
return Db.IsTableExist("db_mapping")
}

func InitMapDbs(c *cfg.DBCfg, prd bool) {
var tables *[]model.DbMapping
exists, err := MapBaseExists()
if !exists || err != nil {
logx.Fatalf("db_mapping not exists : %v", err)
}
// tables := MapAllDatabases(debug)
if prd {
tables = GetAllDatabasePrd() //debug 获取生产
} else {
tables = GetAllDatabaseDev() //debug 获取开发
}

if tables == nil {
logx.Fatal("no database tables data")
}
var e *xorm.Engine
DBs = map[string]*xorm.Engine{}
for _, v := range *tables {
if v.DbName != "" && v.DeletedAt == 0 && v.DbName != c.Name {
dbCfg := cfg.DBCfg{
Name: v.DbName,
ShowLog: c.ShowLog,
MaxLifetime: c.MaxLifetime,
MaxOpenConns: c.MaxOpenConns,
MaxIdleConns: c.MaxIdleConns,
Path: fmt.Sprintf(c.Path, v.DbName),
}
if v.DbHost != "" && v.DbUsername != "" && v.DbPassword != "" {
dbCfg.Host = v.DbHost
dbCfg.User = v.DbUsername
dbCfg.Psw = v.DbPassword
} else {
dbCfg.Host = c.Host
dbCfg.User = c.User
dbCfg.Psw = c.Psw
}
e, err = NewDB(&dbCfg)
if err != nil || e == nil {
logx.Warnf("db engine can't create, please check config, params[host:%s, user:%s, psw: %s, name: %s], err: %v", dbCfg.Host, dbCfg.User, dbCfg.Psw, dbCfg.Name, err)
} else {
DBs[v.DbMasterId] = e
}
}
}
}

func MapAllDatabases(debug bool) *[]model.DbMapping {
sql := "`db_name` != ?"
if debug {
sql = "`db_name` = ?"
}
var m []model.DbMapping
if err := Db.Where(sql, cfg.DB.Name).Find(&m); err != nil || len(m) == 0 {
logx.Warn(err)
return nil
}
return &m
}

// GetAllDatabasePrd is 获取生成库 所有db 除了 deleted_at = 1 的
func GetAllDatabasePrd() *[]model.DbMapping {
var m []model.DbMapping
if err := Db.Where("deleted_at != ? AND is_dev = '0' ", 1).Find(&m); err != nil || len(m) == 0 {
logx.Warn(err)
return nil
}
return &m
}

// GetAllDatabaseDev is 获取开发库 所有db 除了 deleted_at = 1 的
func GetAllDatabaseDev() *[]model.DbMapping {
var m []model.DbMapping
var err error
if cfg.Local { // 本地调试 加快速度
fmt.Println("notice:LOCAL TEST, only masterId:** 123456 ** available!")
err = Db.Where("deleted_at != ? AND is_dev = '1' AND db_master_id=?", 1, 22255132).Or("db_master_id=?", 56593133).Find(&m)
//err = Db.Where("deleted_at != ? AND is_dev = '1' AND db_master_id=?", 1, 22255132).Find(&m)
} else {
err = Db.Where("deleted_at != ? AND is_dev = '1' ", 1).Find(&m)
}

//err := Db.Where("deleted_at != ? AND is_dev = '1' and db_master_id='123456'", 1).Find(&m)
if err != nil || len(m) == 0 {
logx.Warn(err)
return nil
}
return &m
}

// GetDatabaseByMasterID is 根据站长id 获取对应的的数据库信息
func GetDatabaseByMasterID(Db *xorm.Engine, id string) (*model.DbMapping, error) {
var m model.DbMapping
has, err := Db.Where("db_master_id=?", id).Get(&m)
if !has {
return nil, errors.New("Not Found DB data by " + id)
}
if err != nil {
return nil, err
}
if m.DbHost == "" {
m.DbHost = cfg.DB.Host
m.DbUsername = cfg.DB.User
m.DbPassword = cfg.DB.Psw
}
return &m, nil
}

// SessionGetDatabaseByMasterID is 根据站长id 获取对应的的数据库信息
func SessionGetDatabaseByMasterID(Db *xorm.Session, id string) (*model.DbMapping, error) {
var m model.DbMapping
has, err := Db.Where("db_master_id=?", id).Get(&m)
if !has {
return nil, errors.New("Not Found DB data by " + id)
}
if err != nil {
return nil, err
}
if m.DbHost == "" {
m.DbHost = cfg.DB.Host
m.DbName = cfg.DB.Name
m.DbUsername = cfg.DB.User
m.DbPassword = cfg.DB.Psw
}
return &m, nil
}

// 获取自动任务队列
func MapCrontabCfg(eg *xorm.Engine) *[]model.SysCfg {
var c []model.SysCfg
// 数据库查询如果有下划线会认为是一个任意字符
if err := eg.Where("`key` LIKE 'cron\\_%' AND val != ''").Cols("`key`,`val`").Find(&c); err != nil || len(c) == 0 {
logx.Warn(err)
return nil
}
return &c
}

// 获取官方域名
func GetOfficialDomainInfoByType(Db *xorm.Engine, masterId, key string) (string, error) {
type SysCfg struct {
K string
V string
Memo string
}
var domainBase SysCfg

has, err := Db.Where("k=?", "domain_wap_base").Get(&domainBase)
if err != nil {
return "", err
}
if has == false {
return "", errors.New("can not find key by : domain_base")
}

if key == "wap" {
return masterId + "." + domainBase.V, nil
}

if key == "api" {
var apiDomain SysCfg
has, err = Db.Where("k=?", "domain_api_base").Get(&apiDomain)
if err != nil {
return "", err
}
if has == false {
return "", errors.New("can not find key by : domain_api_base")
}
return apiDomain.V, nil
}

if key == "admin" {
return "admin." + masterId + "." + domainBase.V, nil
}
// 默认返回H5的
return masterId + "." + domainBase.V, nil
}

+ 18
- 0
app/db/model/db_mapping.go View File

@@ -0,0 +1,18 @@
package model

import (
"time"
)

type DbMapping struct {
DbMasterId string `json:"db_master_id" xorm:"not pk null comment('站长id') VARCHAR(32)"`
DbHost string `json:"db_host" xorm:"not null default '' comment('数据库连接(带port)') VARCHAR(255)"`
DbUsername string `json:"db_username" xorm:"not null default '' comment('数据库用户名') VARCHAR(255)"`
DbPassword string `json:"db_password" xorm:"not null default '' comment('数据库用户名密码') VARCHAR(255)"`
DbName string `json:"db_name" xorm:"not null comment('数据库名') VARCHAR(255)"`
ExternalMysql string `json:"external_mysql" xorm:"not null default '0' comment('是否外部mysql(0是内部,1是外部)') VARCHAR(255)"`
IsDev int `json:"is_dev" xorm:"not null default 0 comment('开发库是1,0是生产库') TINYINT(1)"`
CreatedAt time.Time `json:"created_at" xorm:"not null default CURRENT_TIMESTAMP comment('创建时间') TIMESTAMP"`
UpdatedAt time.Time `json:"updated_at" xorm:"not null default CURRENT_TIMESTAMP comment('更新时间') TIMESTAMP"`
DeletedAt int `json:"deleted_at" xorm:"not null default 0 comment('是否已删除') TINYINT(1)"`
}

+ 8
- 0
app/db/model/user_app_list.go View File

@@ -0,0 +1,8 @@
package model

type UserAppList struct {
Id int `json:"id" xorm:"int(11) NOT NULL "`
Uuid int64 `json:"uuid" xorm:"int(10) NOT NULL "`
AppId int64 `json:"app_id" xorm:"int(10) NOT NULL "`
SmsPlatform string `json:"sms_platform" xorm:"varchar(255) DEFAULT 'mob' "`
}

+ 7
- 0
app/db/station/sys_cfg.go View File

@@ -0,0 +1,7 @@
package model

type SysCfg struct {
Key string `json:"key" xorm:"not null pk comment('键') VARCHAR(127)"`
Val string `json:"val" xorm:"comment('值') TEXT"`
Memo string `json:"memo" xorm:"not null default '' comment('备注') VARCHAR(255)"`
}

+ 41
- 0
app/hdl/zhimeng_platform/hdl_withdrawal.go View File

@@ -1,8 +1,17 @@
package zhimeng_platform

import (
"applet/app/db"
"applet/app/e"
sms2 "applet/app/lib/sms"
"applet/app/svc/platform"
"applet/app/utils"
"encoding/json"
"fmt"
"github.com/gin-gonic/gin"
"github.com/syyongx/php2go"
"math/rand"
"time"
)

func WithdrawalIncome(c *gin.Context) {
@@ -23,3 +32,35 @@ func WithdrawalInvoiceImg(c *gin.Context) {
func WithdrawalBindAlipay(c *gin.Context) {
platform.WithdrawalBindAlipay(c)
}
func Sms(c *gin.Context) {
if c.GetString("is_system") == "" {
e.OutErr(c, 400, e.NewErr(400, "请重新在后台进入聚合联盟"))
return
}
if c.GetString("is_system") != "1" {
e.OutErr(c, 400, e.NewErr(400, "请使用超管账号设置"))
return
}
appName := db.SysCfgGet(c, "sms_push_sign")
captcha := createCaptcha()
content := fmt.Sprintf("【%s】验证码:%s", appName, captcha)
templateCode := ""
marshal, _ := json.Marshal(c.Request.Header)
waykeys := "zhimeng_" + c.ClientIP() + "_" + utils.IntToStr(utils.GetApiVersion(c)) + "_" + c.Request.RequestURI + "_" + string(marshal)
postData := map[string]interface{}{
"content": content,
"mobile": c.GetString("phone"),
"templateCode": templateCode,
"way": php2go.Base64Encode(waykeys),
}
err := sms2.GetSmsConfig(c, "86", postData)
if err != nil {
e.OutErr(c, 400, err.Error())
return
}
e.OutSuc(c, "success", nil)
return
}
func createCaptcha() string {
return fmt.Sprintf("%05v", rand.New(rand.NewSource(time.Now().UnixNano())).Int31n(1000000))
}

+ 270
- 0
app/lib/mob/api.go View File

@@ -0,0 +1,270 @@
package mob

import (
"applet/app/db"
"applet/app/e"
"applet/app/lib/sms"
"applet/app/utils"
"applet/app/utils/logx"
"bytes"
"crypto/cipher"
"crypto/des"
"crypto/md5"
"encoding/base64"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net/http"
"sort"
"time"

"github.com/gin-gonic/gin"
"github.com/tidwall/gjson"
)

const base string = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"

// Mob is mob sdk
var Mob *SDK

// MobMap is 每个站长都要有自己的mob 对象
var MobMap map[string]*SDK

// Init 初始化
func Init() {
// 后续可能要传请求的上下文来获取对应的配置
// mob 目前都是我们来管理每个站长的app 所以使用template 库
//fmt.Println("Mob SDK init ....")
ch := make(chan struct{}) // 只是做信号标志的话 空struct 更省点资源
MobMap = make(map[string]*SDK)
// 初始化
for k, e := range db.DBs {
m := db.SysCfgGetWithDb(e, k, "third_app_push_set")
if m == "" {
fmt.Printf("masterid:%s 找不到推送配置", k)
continue
}
key := gjson.Get(m, "mobAppKey").String()
secret := gjson.Get(m, "mobAppSecret").String()
if key == "" || secret == "" {
fmt.Println(k + ":mob no config")
continue
}
// fmt.Println(k, key, secret)
mob := new(SDK)
mob.AppKey = key
mob.AppSecret = secret
MobMap[k] = mob
fmt.Println(k + ":mob config success")
}
go func() {
ch <- struct{}{}
}()

// 定时任务
go func(MobMap map[string]*SDK, ch chan struct{}) {
<-ch
ticker := time.NewTicker(time.Duration(time.Second * 15))
//每 15s 一次更新一次mob 配置
for range ticker.C {
for k, e := range db.DBs {
if err := e.Ping(); err != nil {
logx.Info(err)
continue
}
m := db.SysCfgGetWithDb(e, k, "third_app_push_set")
if m == "" {
fmt.Printf("masterid:%s 找不到推送配置", k)
continue
}
key := gjson.Get(m, "mobAppKey").String()
secret := gjson.Get(m, "mobAppSecret").String()
if key == "" || secret == "" {
fmt.Println(k + ":mob no config")
continue
}
// fmt.Println(k, key, secret)
mob := new(SDK)
mob.AppKey = key
mob.AppSecret = secret
MobMap[k] = mob
// fmt.Println(k + ":mob config success")
}
}
}(MobMap, ch)
}

// GetMobSDK is 获取mob 的sdk
func GetMobSDK(mid string) (*SDK, error) {

return &SDK{AppKey: "30dc33054b635", AppSecret: "396e98c293130c9976fb7428b6b434d6"}, nil
}

// SDK is mob_push 的sdk
type SDK struct {
AppKey string
AppSecret string
}

// MobFreeLogin is 秒验
func (s *SDK) MobFreeLogin(args map[string]interface{}) (string, error) {
var url string = "http://identify.verify.mob.com/auth/auth/sdkClientFreeLogin"
// https://www.mob.com/wiki/detailed/?wiki=miaoyan_for_fuwuduan_mianmifuwuduanjieru&id=78
//加appkey
args["appkey"] = s.AppKey
//加签名
args["sign"] = generateSign(args, s.AppSecret)
b, err := json.Marshal(args)
if err != nil {
return "", logx.Warn(err)
}
// 发送请求
respBody, err := httpPostBody(url, b)
if err != nil {
return "", logx.Warn(err)
}
// 反序列化
ret := struct {
Status int `json:"status"`
Error string `json:"error"`
Res interface{} `json:"res"`
}{}
// 要拿 ret 里面 Res 再解密
if err := json.Unmarshal(respBody, &ret); err != nil {
return "", logx.Warn(err)
}
//fmt.Println(ret)
// ret里面的Res 反序列化为结构体
res := struct {
IsValid int `json:"isValid"`
Phone string `json:"phone"`
}{}
// 判断是否返回正确 状态码
if ret.Status == 200 {
decode, _ := base64Decode([]byte(ret.Res.(string)))
decr, _ := desDecrypt(decode, []byte(s.AppSecret)[0:8])
if err := json.Unmarshal(decr, &res); err != nil {
return "", logx.Warn(err)
}
}
// 有效则拿出res 里的电话号码
if res.IsValid == 1 {
return res.Phone, nil
}
// Status 不等于200 则返回空
return "", fmt.Errorf("Mob error , status code %v ", ret.Status)
}

// MobSMS is mob 的短信验证
func (s *SDK) MobSMS(c *gin.Context, args map[string]interface{}) (bool, error) {
// mob 的短信验证
// https://www.mob.com/wiki/detailed/?wiki=SMSSDK_for_yanzhengmafuwuduanxiaoyanjiekou&id=23
url := "https://webapi.sms.mob.com/sms/verify"
//加appkey
args["appkey"] = s.AppKey
fmt.Println(args)
//fmt.Println(args)
// 发送请求
respBody, err := utils.CurlPost(url, args, nil)
if err != nil {
fmt.Println(err)
return false, logx.Warn(err)
}
fmt.Println("=======================mob")
fmt.Println("mob", string(respBody))
code := gjson.GetBytes(respBody, "status").Int()
if code == 468 {
return false, errors.New("验证码错误")
}
if code != 200 {
utils.FilePutContents("sms", string(respBody))
return false, errors.New("验证码错误~")
}
return true, nil
}

func pkcs5UnPadding(origData []byte) []byte {
length := len(origData)
// 去掉最后一个字节 unpadding 次
unpadding := int(origData[length-1])
return origData[:(length - unpadding)]
}

func desDecrypt(crypted, key []byte) ([]byte, error) {
block, err := des.NewCipher(key)
if err != nil {
return nil, err
}
blockMode := cipher.NewCBCDecrypter(block, []byte("00000000"))
origData := make([]byte, len(crypted))
// origData := crypted
blockMode.CryptBlocks(origData, crypted)
origData = pkcs5UnPadding(origData)
// origData = ZeroUnPadding(origData)
return origData, nil
}

func base64Decode(src []byte) ([]byte, error) {
var coder *base64.Encoding
coder = base64.NewEncoding(base)
return coder.DecodeString(string(src))
}

func httpPostBody(url string, msg []byte) ([]byte, error) {
resp, err := http.Post(url, "application/json;charset=utf-8", bytes.NewBuffer(msg))
if err != nil {
return []byte(""), err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
return body, err
}

func generateSign(request map[string]interface{}, secret string) string {
ret := ""
var keys []string
for k := range request {
keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
ret = ret + fmt.Sprintf("%v=%v&", k, request[k])
}
ret = ret[:len(ret)-1] + secret

md5Ctx := md5.New()
md5Ctx.Write([]byte(ret))
cipherStr := md5Ctx.Sum(nil)
return hex.EncodeToString(cipherStr)
}

func Check(c *gin.Context, phone, zone, validCode string, ok1 bool) (bool, error) {
smsPlatform := sms.GetSmsPlatform(c)

if smsPlatform == "mob" {
mob1, errr := GetMobSDK(c.GetString("master_id"))
if errr != nil {
return false, e.NewErr(400, "mob配置错误")
}
send := map[string]interface{}{
"phone": phone,
"zone": zone,
"code": validCode,
}
if zone == "" {
send["zone"] = "86"
}
c.Set("not_deduction_doing", "1")
ok, err := mob1.MobSMS(c, send)
fmt.Println(ok)
if err != nil {
fmt.Println(err)
return false, e.NewErr(400, "验证码校验错误")
}

return ok, nil
}
return ok1, nil
}

+ 84
- 0
app/lib/sms/sms.go View File

@@ -0,0 +1,84 @@
package sms

import (
"applet/app/db"
"applet/app/db/model"
"applet/app/lib/zhimeng"
"applet/app/utils"
"applet/app/utils/cache"
"applet/app/utils/logx"
"code.fnuoos.com/go_rely_warehouse/zyos_go_third_party_api.git/sms"
"fmt"
"github.com/tidwall/gjson"

"github.com/gin-gonic/gin"
)

// NewZhimengSMS is 智盟的短信服务
func NewZhimengSMS(c *gin.Context) *zhimeng.SDK {
sms := new(zhimeng.SDK)
key := db.SysCfgGet(c, "third_zm_sms_key")
secret := db.SysCfgGet(c, "third_zm_sms_secret")
if key == "" || secret == "" {
_ = logx.Warn("短信服务配置错误")
}
sms.Init("send_msg", key, secret)
return sms
}
func GetSmsPlatform(c *gin.Context) string {
var smsPlatform = "ljioe"
key := fmt.Sprintf("%s:sms_platform", c.GetString("master_id"))
smsPlatformTmp, _ := cache.GetString(key)
if smsPlatformTmp == "" {
smsPlatformTmp = GetWebSiteAppSmsPlatform(c.GetString("master_id"))
if smsPlatformTmp != "" {
cache.SetEx(key, smsPlatformTmp, 300)
}
}
if smsPlatformTmp != "" {
smsPlatform = smsPlatformTmp
}
return smsPlatform
}
func GetWebSiteAppSmsPlatform(mid string) string {
obj := new(model.UserAppList)
has, err := db.Db.Where("uuid=? ", mid).Asc("id").Get(obj)
if err != nil || !has {
return ""
}
return utils.AnyToString(obj.SmsPlatform)
}

func GetTplId(c *gin.Context, zone, types string) string {
// 校验短信验证码
tplId := ""
if zone != "86" {
tplId = db.SysCfgGet(c, "mob_sms_sdk_international_template_id")
} else {
tplId = db.SysCfgGet(c, "mob_sms_sdk_template_id")
}
if c.GetString("app_type") == "o2o" {
tplId = db.SysCfgGet(c, "biz_mob_sms_sdk_template_id")
}
normal := gjson.Get(tplId, types).String()
if normal == "" {
normal = gjson.Get(tplId, "normal").String()
}
return normal
}
func GetSmsConfig(c *gin.Context, zone string, postData map[string]interface{}) error {
postData["is_mob"] = "1"
postData["type"] = "mob"
postData["sms_type"] = "putong"
zone = "86"
postData["templateCode"] = "14373673"
postData["zone"] = zone
postData["smsmsg_key"] = "30dc33054b635"
postData["uid"] = c.GetString("master_id")
err := sms.SmsSendZy(db.Db, postData)
if err != nil {
return err
}
return nil

}

+ 66
- 0
app/lib/zhimeng/api.go View File

@@ -0,0 +1,66 @@
package zhimeng

import (
"fmt"
"sort"
"strconv"
"time"

"applet/app/utils"
)

var StatusSuc int = 1

type ZM struct {
AK string
SK string
SMS_AK string
SMS_SK string
}

// 智盟接口, 可以调取京东, 拼多多等
const ZM_HOST = "http://www.izhim.com/"

var (
ZM_BASE_URL = ZM_HOST + "?mod=api&act=%s&ctrl=%s"
APP_KEY = "300000001"
SECRET_KEY = "95c347002b2750dbd4b6a03bd4196c18"
SMS_APP_KEY = "300000175"
SMS_SECRET_KEY = "6cf1dcd1820a576ff2cbecbe00d31df2"
)

func Send(act, op string, args map[string]interface{}) ([]byte, error) {
router := fmt.Sprintf(ZM_BASE_URL, act, op)
// args["appkey"] = APP_KEY
args["time"] = strconv.Itoa(int(time.Now().Unix()))
args["sign"] = sign(args, args["secret_key"].(string))
// b, _ := json.Marshal(args)
// fmt.Println(string(b))
return utils.CurlPost(router, args, nil)
}

// SMSend is 发送短信用的key 和签名
func SMSend(act, op, key, secret string, args map[string]interface{}) ([]byte, error) {
router := fmt.Sprintf(ZM_BASE_URL, act, op)
args["appkey"] = key
args["time"] = strconv.Itoa(int(time.Now().Unix()))
args["sign"] = sign(args, secret)
fmt.Println("====短信==", router, args)
return utils.CurlPost(router, args, nil)
}

func sign(m map[string]interface{}, SK string) string {
// key sort
keys := make([]string, 0, len(m))
for k := range m {
keys = append(keys, k)
}
sort.Strings(keys)
str := ""
for _, k := range keys {
str += k + utils.AnyToString(m[k])
}
// merge string
str = SK + str + SK + "方诺科技"
return utils.Md5(str)
}

+ 98
- 0
app/lib/zhimeng/sdk.go View File

@@ -0,0 +1,98 @@
package zhimeng

import (
"applet/app/utils/logx"
"encoding/json"
"errors"
"fmt"

"github.com/tidwall/gjson"
)

// SDK is zm sdk
type SDK struct {
Action string
operation string
response []byte
SmsKey string
SmsSecret string
data interface{}
err error
}

// ToInterface is data to Interface
func (sdk *SDK) ToInterface() interface{} {
return sdk.data
}

// Init is init action
// In some condition, such as send Sms, need pass sms key and secret after 'action'
func (sdk *SDK) Init(action string, keys ...string) {
sdk.Action = action
//if keys[0] == "" || keys[1] == "" {
// sdk.err = errors.New("智盟短信未配置")
//}
if len(keys) > 1 {
sdk.SmsKey = keys[0]
sdk.SmsSecret = keys[1]
}

}

// SelectFunction is select api with operation
func (sdk *SDK) SelectFunction(operation string) *SDK {
sdk.operation = operation
return sdk
}

// WithSMSArgs is SMS
func (sdk *SDK) WithSMSArgs(args map[string]interface{}) *SDK {
res, err := SMSend(sdk.Action, sdk.operation, sdk.SmsKey, sdk.SmsSecret, args)
if err != nil {
logx.Error(err)
}
sdk.response = res
return sdk
}

// WithArgs is post data to api
func (sdk *SDK) WithArgs(args map[string]interface{}) *SDK {
// args["appkey"] = svc.SysCfgGet(c, md.KEY_CFG_ZM_AK)
// args["secret_key"] = svc.SysCfgGet(c, md.KEY_CFG_ZM_SK)

res, err := Send(sdk.Action, sdk.operation, args)
if err != nil {
logx.Error(err)
}
// for k, v := range args {
// fmt.Printf("%s:%v \n", k, v)
// }
fmt.Println("唯品会请求", args, string(res))
sdk.response = res
return sdk
}

// Result is response data from api , return interface{}
func (sdk *SDK) Result() (*SDK, error) {
if sdk.err != nil {
return nil, sdk.err
}
tmp := struct {
Msg string `json:"msg"`
Success int `json:"success"`
Data interface{} `json:"data"`
}{}
if err := json.Unmarshal(sdk.response, &tmp); err != nil {
return nil, logx.Error("【Resp】" + string(sdk.response) + ", 【Error】" + err.Error())
}
if tmp.Success != StatusSuc {
return nil, logx.Error(string(sdk.response))
}

if gjson.GetBytes(sdk.response, "data").String() == "[]" {
return nil, errors.New("no result")
}

sdk.data = tmp.Data
return sdk, nil
}

+ 70
- 0
app/lib/zhimeng/sms_send.go View File

@@ -0,0 +1,70 @@
package zhimeng

import (
"applet/app/utils"
"applet/app/utils/logx"
"code.fnuoos.com/go_rely_warehouse/zyos_go_third_party_api.git/sms"
"encoding/json"
"xorm.io/xorm"
)

// 查询数量
func SmsNum(engine *xorm.Engine, dbName, smsType, appKey, appSecret string) (int, error) {
if smsType == "1" { //新的
num := sms.SmsNumGetSmsNum(engine, "putong", dbName)
return num, nil
}
params := map[string]interface{}{
"appkey": appKey,
"secret_key": appSecret,
}
resp, err := Send("send_msg", "msg_num", params)
if err != nil {
return 0, logx.Warn(err)
}
var tmp struct {
Msg string `json:"msg"`
Success int `json:"success"`
Data struct {
Count string `json:"count"`
} `json:"data"`
}
if err = json.Unmarshal(resp, &tmp); err != nil {
return 0, logx.Warn("[resp]: " + string(resp) + ", [err]:" + err.Error())
}
return utils.StrToInt(tmp.Data.Count), nil
}

func SmsToSend(engine *xorm.Engine, dbName, smsType, appKey, appSecret, content, phone string) (int, error) {
if smsType == "1" { //新的
args := map[string]interface{}{
"mobile": phone,
"content": content,
"sms_type": "putong",
"uid": dbName,
}
err := sms.SmsSend(engine, args)
if err != nil {
return 0, err
}
return 1, nil
}
params := map[string]interface{}{
"appkey": appKey,
"secret_key": appSecret,
"mobile": phone,
"content": content,
}
resp, err := Send("send_msg", "msg_doing", params)
if err != nil {
return 0, logx.Warn(err)
}
var tmp struct {
Msg string `json:"msg"`
Success int `json:"success"`
}
if err = json.Unmarshal(resp, &tmp); err != nil {
return 0, logx.Warn("[resp]: " + string(resp) + ", [err]:" + err.Error())
}
return tmp.Success, nil
}

+ 8
- 0
app/md/md_login.go View File

@@ -8,3 +8,11 @@ type LoginReq struct {
type LoginResponse struct {
Token string `json:"token"`
}
type Register struct {
Mobile string `json:"mobile"`
Captcha string `json:"captcha"`
Type string `json:"type"`
Zone string `json:"zone"`
PicCode string `json:"pic_code"`
PicCodeId string `json:"pic_code_id"`
}

+ 10
- 1
app/mw/mw_auth_jwt.go View File

@@ -45,7 +45,16 @@ func AuthJWT(c *gin.Context) {
e.OutErr(c, e.ERR_TOKEN_EXPIRE, errors.New("token 过期已失效"))
return
}
MasterId := claim.MasterId
if strings.Contains(MasterId, "_") {
ex := strings.Split(MasterId, "_")
if len(ex) >= 3 {
MasterId = ex[0]
c.Set("phone", ex[1])
c.Set("is_system", ex[2])
}
}
//设置上下文信息
c.Set("master_id", claim.MasterId)
c.Set("master_id", MasterId)
c.Next()
}

+ 2
- 2
app/mw/mw_request_cache.go View File

@@ -11,13 +11,13 @@ import (
"io/ioutil"
)

//自己实现一个type gin.ResponseWriter interface
// 自己实现一个type gin.ResponseWriter interface
type responseWriter struct {
gin.ResponseWriter
b *bytes.Buffer
}

//重写Write([]byte) (int, error)
// 重写Write([]byte) (int, error)
func (w responseWriter) Write(b []byte) (int, error) {
//向一个bytes.buffer中再写一份数据
w.b.Write(b)


+ 1
- 0
app/router/router.go View File

@@ -99,6 +99,7 @@ func routeZhimeng(r *gin.RouterGroup) {

r.POST("/withdrawal_income", platformHdl.WithdrawalIncome)
r.POST("/withdrawal_bind_alipay", platformHdl.WithdrawalBindAlipay)
r.GET("/sms", platformHdl.Sms)
r.POST("/withdrawal_list", platformHdl.WithdrawalList)
r.POST("/withdrawal_doing", platformHdl.WithdrawalDoing)
r.POST("/withdrawal_output", platformHdl.WithdrawalOutput)


+ 40
- 11
app/svc/platform/svc_withdrawal.go View File

@@ -5,6 +5,7 @@ import (
"applet/app/db/model"
offical "applet/app/db/official"
"applet/app/e"
"applet/app/lib/mob"
"applet/app/utils"
"applet/app/utils/cache"
"encoding/json"
@@ -321,19 +322,47 @@ func WithdrawalBindAlipay(c *gin.Context) {
e.OutErr(c, 400, e.NewErr(400, "支付宝信息不能为空"))
return
}
masterId, _ := c.Get("master_id")
mid := utils.AnyToString(masterId)
masterDb := db.MasterDb{}
masterDb.Set()
master := masterDb.GetMaster(mid)
master.AlipayName = args["alipay_name"]
master.Alipay = args["alipay"]
update := masterDb.MasterUpdate(master)
if update == false {
e.OutErr(c, 400, e.NewErr(400, "修改失败"))
mob1, errr := mob.GetMobSDK(c.GetString("master_id"))
if errr != nil {
e.OutErr(c, e.ERR_MOB_CONFIG, errr)
return
}
e.OutSuc(c, "success", nil)
if c.GetString("is_system") == "" {
e.OutErr(c, 400, e.NewErr(400, "请重新在后台进入聚合联盟"))
return
}
if c.GetString("is_system") != "1" {
e.OutErr(c, 400, e.NewErr(400, "请使用超管账号设置"))
return
}
send := map[string]interface{}{
"phone": c.GetString("phone"),
"zone": "86",
"code": args["captcha"],
}
ok, err := mob1.MobSMS(c, send)
if err != nil {
e.OutErr(c, 400, err.Error())
return
}
ok = true
if ok {
masterId, _ := c.Get("master_id")
mid := utils.AnyToString(masterId)
masterDb := db.MasterDb{}
masterDb.Set()
master := masterDb.GetMaster(mid)
master.AlipayName = args["alipay_name"]
master.Alipay = args["alipay"]
update := masterDb.MasterUpdate(master)
if update == false {
e.OutErr(c, 400, e.NewErr(400, "修改失败"))
return
}
e.OutSuc(c, "success", nil)
return
}
e.OutErr(c, 400, e.NewErr(400, "验证码错误"))
return
}



+ 1
- 1
go.mod View File

@@ -4,7 +4,7 @@ go 1.15

require (
code.fnuoos.com/go_rely_warehouse/zyos_go_es.git v1.0.1-0.20230707081910-52e70aa52998
code.fnuoos.com/go_rely_warehouse/zyos_go_third_party_api.git v1.1.21-0.20240628083932-3a853b9ed178
code.fnuoos.com/go_rely_warehouse/zyos_go_third_party_api.git v1.1.21-0.20240701084733-e197a1ca8795
github.com/360EntSecGroup-Skylar/excelize v1.4.1
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5
github.com/boombuler/barcode v1.0.1


+ 4
- 1
main.go View File

@@ -15,7 +15,7 @@ import (
"applet/app/router"
)

//系统初始化
// 系统初始化
func init() {
cfg.InitCfg() //配置初始化
cfg.InitLog() //日志初始化
@@ -28,6 +28,9 @@ func init() {
if err := db.InitZhimengDB(cfg.ZhimengDB); err != nil {
panic(err)
}
channel := make(chan int, 0) //开辟管道,缓冲为
go db.InitDBs(channel)
<-channel
}
fmt.Println("init success")



Loading…
Cancel
Save