Create & Init Project...

This commit is contained in:
2019-04-22 18:49:16 +08:00
commit fc4fa37393
25440 changed files with 4054998 additions and 0 deletions

View File

@@ -0,0 +1,64 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"dao_test.go",
"mc_test.go",
"qq_test.go",
"sns_test.go",
"weibo_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/service/main/passport-sns/conf:go_default_library",
"//app/service/main/passport-sns/model:go_default_library",
"//library/database/sql:go_default_library",
"//vendor/github.com/bouk/monkey:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"dao.go",
"mc.go",
"qq.go",
"sns.go",
"weibo.go",
],
importpath = "go-common/app/service/main/passport-sns/dao",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/service/main/passport-sns/conf:go_default_library",
"//app/service/main/passport-sns/model:go_default_library",
"//library/cache/memcache:go_default_library",
"//library/database/sql:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,51 @@
package dao
import (
"context"
"net/http"
"time"
"go-common/app/service/main/passport-sns/conf"
"go-common/library/cache/memcache"
"go-common/library/database/sql"
)
// Dao dao struct
type Dao struct {
c *conf.Config
db *sql.DB
mc *memcache.Pool
client *http.Client
mcExpire int32
}
// New create new dao
func New(c *conf.Config) (d *Dao) {
d = &Dao{
c: c,
db: sql.NewMySQL(c.MySQL),
mc: memcache.NewPool(c.Memcache.Config),
mcExpire: int32(time.Duration(c.Memcache.Expire) / time.Second),
client: &http.Client{
Timeout: 600 * time.Millisecond,
},
}
return
}
// Ping check db and mc health.
func (d *Dao) Ping(c context.Context) (err error) {
return
}
// Close close connections of mc, redis, db.
func (d *Dao) Close() {
if d.db != nil {
d.db.Close()
}
}
// BeginTran begin transcation.
func (d *Dao) BeginTran(c context.Context) (tx *sql.Tx, err error) {
return d.db.Begin(c)
}

View File

@@ -0,0 +1,77 @@
package dao
import (
"context"
"flag"
"os"
"reflect"
"testing"
"go-common/app/service/main/passport-sns/conf"
"go-common/library/database/sql"
"github.com/bouk/monkey"
"github.com/smartystreets/goconvey/convey"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.passport.passport-sns-service")
flag.Set("conf_token", "f0a341c60edec0e51fd0fbb731c00b39")
flag.Set("tree_id", "80847")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_host", "config.bilibili.co")
flag.Set("conf_path", "/tmp")
flag.Set("region", "sh")
flag.Set("zone", "sh001")
} else {
flag.Set("conf", "../cmd/passport-sns-service.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
m.Run()
os.Exit(0)
}
func TestDaoPing(t *testing.T) {
var c = context.Background()
convey.Convey("Ping", t, func(ctx convey.C) {
err := d.Ping(c)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoClose(t *testing.T) {
convey.Convey("Close", t, func(ctx convey.C) {
monkey.PatchInstanceMethod(reflect.TypeOf(d.db), "Close", func(_ *sql.DB) error {
return nil
})
defer monkey.UnpatchAll()
var err error
d.Close()
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
}
func TestDaoBeginTran(t *testing.T) {
var c = context.Background()
convey.Convey("BeginTran", t, func(ctx convey.C) {
res, err := d.BeginTran(c)
ctx.Convey("Then err should be nil. res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
})
}

View File

@@ -0,0 +1,114 @@
package dao
import (
"context"
"fmt"
"go-common/app/service/main/passport-sns/model"
"go-common/library/cache/memcache"
"go-common/library/log"
)
func snsKey(platform string, mid int64) string {
return fmt.Sprintf("sns_%s_%d", platform, mid)
}
func oauth2Key(platform string, openID string) string {
return fmt.Sprintf("sns_oauth2_%s_%s", platform, openID)
}
// SetSnsCache set sns to cache
func (d *Dao) SetSnsCache(c context.Context, mid int64, platform string, sns *model.SnsProto) (err error) {
key := snsKey(platform, mid)
conn := d.mc.Get(c)
defer conn.Close()
item := &memcache.Item{Key: key, Object: sns, Flags: memcache.FlagProtobuf, Expiration: d.mcExpire}
if err = conn.Set(item); err != nil {
log.Error("fail to set sns to mc, key(%s) expire(%d) error(%+v)", key, d.mcExpire, err)
}
return
}
// SetOauth2Cache set oauth2 info to cache
func (d *Dao) SetOauth2Cache(c context.Context, openID, platform string, sns *model.Oauth2Proto) (err error) {
key := oauth2Key(platform, openID)
conn := d.mc.Get(c)
defer conn.Close()
item := &memcache.Item{Key: key, Object: sns, Flags: memcache.FlagProtobuf, Expiration: 300}
if err = conn.Set(item); err != nil {
log.Error("fail to set oauth2 info to mc, key(%s) expire(%d) error(%+v)", key, 300, err)
}
return
}
// SnsCache sns cache
func (d *Dao) SnsCache(c context.Context, mid int64, platform string) (res *model.SnsProto, err error) {
key := snsKey(platform, mid)
conn := d.mc.Get(c)
defer conn.Close()
item, err := conn.Get(key)
if err != nil {
if err == memcache.ErrNotFound {
return nil, nil
}
log.Error("conn.Get(%s) error(%v)", key, err)
return nil, err
}
res = new(model.SnsProto)
if err = conn.Scan(item, res); err != nil {
log.Error("conn.Scan(%s) error(%v)", string(item.Value), err)
return nil, err
}
return res, nil
}
// Oauth2Cache oauth2 info cache
func (d *Dao) Oauth2Cache(c context.Context, openID, platform string) (res *model.Oauth2Proto, err error) {
key := oauth2Key(platform, openID)
conn := d.mc.Get(c)
defer conn.Close()
item, err := conn.Get(key)
if err != nil {
if err == memcache.ErrNotFound {
return nil, nil
}
log.Error("conn.Get(%s) error(%v)", key, err)
return nil, err
}
res = new(model.Oauth2Proto)
if err = conn.Scan(item, res); err != nil {
log.Error("conn.Scan(%s) error(%v)", string(item.Value), err)
return nil, err
}
return res, nil
}
// DelSnsCache del sns cache
func (d *Dao) DelSnsCache(c context.Context, mid int64, platform string) (err error) {
key := snsKey(platform, mid)
conn := d.mc.Get(c)
defer conn.Close()
if err = conn.Delete(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
log.Error("fail to del sns cache, key(%s) error(%+v)", key, err)
}
return
}
// DelOauth2Cache del oauth2 cache
func (d *Dao) DelOauth2Cache(c context.Context, openID, platform string) (err error) {
key := oauth2Key(platform, openID)
conn := d.mc.Get(c)
defer conn.Close()
if err = conn.Delete(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
log.Error("fail to del oauth2 cache, key(%s) error(%+v)", key, err)
}
return
}

View File

@@ -0,0 +1,152 @@
package dao
import (
"context"
"testing"
"go-common/app/service/main/passport-sns/model"
"github.com/smartystreets/goconvey/convey"
)
func TestDao_snsKey(t *testing.T) {
convey.Convey("snsKey", t, func(ctx convey.C) {
var (
platform = model.PlatformQQStr
mid = int64(0)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
res := snsKey(platform, mid)
ctx.Convey("Then res should not be nil.", func(ctx convey.C) {
ctx.So(res, convey.ShouldNotBeNil)
})
})
})
}
func TestDao_oauth2Key(t *testing.T) {
convey.Convey("oauth2Key", t, func(ctx convey.C) {
var (
platform = model.PlatformQQStr
openID = ""
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
res := oauth2Key(platform, openID)
ctx.Convey("Then res should not be nil.", func(ctx convey.C) {
ctx.So(res, convey.ShouldNotBeNil)
})
})
})
}
func TestDao_SetSnsCache(t *testing.T) {
convey.Convey("SetSnsCache", t, func(ctx convey.C) {
var (
c = context.Background()
mid = int64(0)
platform = model.PlatformQQStr
qq = &model.SnsProto{}
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
err := d.SetSnsCache(c, mid, platform, qq)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDao_SetOauth2Cache(t *testing.T) {
convey.Convey("SetOauth2Cache", t, func(ctx convey.C) {
var (
c = context.Background()
openID = ""
platform = model.PlatformQQStr
qq = &model.Oauth2Proto{}
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
err := d.SetOauth2Cache(c, openID, platform, qq)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDao_SnsCache(t *testing.T) {
convey.Convey("SnsCache", t, func(ctx convey.C) {
var (
c = context.Background()
platform = model.PlatformQQStr
mid = int64(0)
midNotExist = int64(-1)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
info, err := d.SnsCache(c, mid, platform)
ctx.Convey("Then err should be nil.info should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(info, convey.ShouldNotBeNil)
})
info2, err2 := d.SnsCache(c, midNotExist, platform)
ctx.Convey("Then err should be nil.info should be nil.", func(ctx convey.C) {
ctx.So(err2, convey.ShouldBeNil)
ctx.So(info2, convey.ShouldBeNil)
})
})
})
}
func TestDao_Oauth2Cache(t *testing.T) {
convey.Convey("Oauth2Cache", t, func(ctx convey.C) {
var (
c = context.Background()
openID = ""
openIDNotExist = "-1"
platform = model.PlatformQQStr
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
info, err := d.Oauth2Cache(c, openID, platform)
ctx.Convey("Then err should be nil.info should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(info, convey.ShouldNotBeNil)
})
info2, err2 := d.Oauth2Cache(c, openIDNotExist, platform)
ctx.Convey("Then err should be nil.info should be nil.", func(ctx convey.C) {
ctx.So(err2, convey.ShouldBeNil)
ctx.So(info2, convey.ShouldBeNil)
})
})
})
}
func TestDao_DelSnsCache(t *testing.T) {
convey.Convey("DelSnsCache", t, func(ctx convey.C) {
var (
c = context.Background()
mid = int64(0)
platform = model.PlatformQQStr
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
err := d.DelSnsCache(c, mid, platform)
ctx.Convey("Then err should be nil.info should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestDao_DelOauth2Cache(t *testing.T) {
convey.Convey("DelOauth2Cache", t, func(ctx convey.C) {
var (
c = context.Background()
openID = ""
platform = model.PlatformQQStr
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
err := d.DelOauth2Cache(c, openID, platform)
ctx.Convey("Then err should be nil.info should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,148 @@
package dao
import (
"context"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"strconv"
"strings"
"time"
"go-common/app/service/main/passport-sns/model"
"go-common/library/ecode"
"go-common/library/log"
)
const (
_qqAuthorizeUrl = "https://graph.qq.com/oauth2.0/authorize"
_qqAccessTokenUrl = "https://graph.qq.com/oauth2.0/token"
_qqOpenIDUrl = "https://graph.qq.com/oauth2.0/me"
_respCodeSuccess = 0
)
// QQAuthorize .
func (d *Dao) QQAuthorize(c context.Context, appID, redirectURL, display string) (url string) {
scope := "do_like,get_user_info,get_simple_userinfo,get_vip_info,get_vip_rich_info,add_one_blog,list_album,upload_pic,add_album,list_photo,get_info,add_t,del_t,add_pic_t,get_repost_list,get_other_info,get_fanslist,get_idollist,add_idol,del_idol,get_tenpay_addr"
displayParam := ""
if display != "" {
displayParam = "&display=" + display
}
return fmt.Sprintf(_qqAuthorizeUrl+"?response_type=code&state=authorize%s&client_id=%s&redirect_uri=%s&scope=%s", displayParam, appID, redirectURL, scope)
}
// QQOauth2Info .
func (d *Dao) QQOauth2Info(c context.Context, code, redirectUrl string, app *model.SnsApps) (res *model.Oauth2Info, err error) {
accessResp, err := d.qqAccessToken(c, code, app.AppID, app.AppSecret, redirectUrl)
if err != nil {
return nil, err
}
openIdResp, err := d.qqOpenID(c, accessResp.Token, app.Business)
if err != nil {
return nil, err
}
// TODO 保证能获取到UnionID的情况可以考虑去掉
if openIdResp.UnionID == "" {
openIdResp.UnionID = openIdResp.OpenID
}
res = &model.Oauth2Info{
UnionID: openIdResp.UnionID,
OpenID: openIdResp.OpenID,
Token: accessResp.Token,
Refresh: accessResp.Refresh,
Expires: accessResp.Expires,
}
return
}
// qqAccessToken .
func (d *Dao) qqAccessToken(c context.Context, code, appID, appSecret, redirectUrl string) (resp *model.QQAccessResp, err error) {
var (
res *http.Response
bs []byte
params = url.Values{}
value = url.Values{}
expires int64
)
params.Set("client_id", appID)
params.Set("client_secret", appSecret)
params.Set("grant_type", "authorization_code")
params.Set("code", code)
params.Set("redirect_uri", redirectUrl)
if res, err = d.client.Get(_qqAccessTokenUrl + "?" + params.Encode()); err != nil {
log.Error("d.qqAccessToken error(%+v) code(%s) appID(%s)", err, code, appID)
return nil, err
}
defer res.Body.Close()
if bs, err = ioutil.ReadAll(res.Body); err != nil {
log.Error("ioutil.ReadAll() error(%+v) code(%s) appID(%s)", err, code, appID)
return nil, err
}
respStr := string(bs)
if strings.HasPrefix(respStr, "callback") {
resp = new(model.QQAccessResp)
start := strings.Index(respStr, "{")
end := strings.Index(respStr, "}")
respStr = respStr[start : end+1]
if err = json.Unmarshal([]byte(respStr), resp); err != nil {
return nil, err
}
log.Error("request qq token failed with code(%d) desc(%s)", resp.Code, resp.Description)
return nil, ecode.PassportSnsRequestErr
}
value, err = url.ParseQuery(respStr)
expires, err = strconv.ParseInt(value.Get("expires_in"), 10, 64)
resp = &model.QQAccessResp{
Token: value.Get("access_token"),
Refresh: value.Get("refresh_token"),
Expires: time.Now().Unix() + expires,
}
return resp, nil
}
// qqOpenID .
func (d *Dao) qqOpenID(c context.Context, token string, business int) (resp *model.QQOpenIDResp, err error) {
var (
res *http.Response
bs []byte
params = url.Values{}
)
params.Set("access_token", token)
params.Set("unionid", "1")
// TODO 如果后续要支持没有unionid权限的appid可以考虑在sns_apps表增加unionid权限标识的字段
//if business == model.BusinessMall {
// params.Set("unionid", "1")
//}
if res, err = d.client.Get(_qqOpenIDUrl + "?" + params.Encode()); err != nil {
log.Error("d.qqOpenID error(%+v) token(%d) business(%d)", err, token, business)
return nil, err
}
defer res.Body.Close()
if bs, err = ioutil.ReadAll(res.Body); err != nil {
log.Error("ioutil.ReadAll() error(%+v) token(%d) business(%d)", err, token, business)
return nil, err
}
respStr := string(bs)
if strings.HasPrefix(respStr, "callback") {
start := strings.Index(respStr, "{")
end := strings.Index(respStr, "}")
respStr = respStr[start : end+1]
}
resp = new(model.QQOpenIDResp)
if err = json.Unmarshal([]byte(respStr), resp); err != nil {
return nil, err
}
if resp.Code == _respCodeSuccess {
return resp, nil
}
log.Error("request qq openid failed with code(%d) desc(%s)", resp.Code, resp.Description)
return nil, ecode.PassportSnsRequestErr
}

View File

@@ -0,0 +1,84 @@
package dao
import (
"context"
"fmt"
"testing"
"go-common/app/service/main/passport-sns/model"
"github.com/smartystreets/goconvey/convey"
)
func TestDao_QQAuthorize(t *testing.T) {
var (
c = context.Background()
AppID = "101135748"
RedirectUrl = "https://passport.bilibili.com/login/snsback?sns=qq"
Display = "mobile"
// AppID : "1108092926",
// RedirectUrl : "https://passport.bilibili.com/web/sns/bind/callback/qq",
)
convey.Convey("QQAuthorize", t, func(ctx convey.C) {
res := d.QQAuthorize(c, AppID, RedirectUrl, Display)
ctx.Convey("Then res should not be nil.", func(ctx convey.C) {
ctx.So(res, convey.ShouldNotBeNil)
})
fmt.Println(res)
})
}
func TestDao_QQOauth2Info(t *testing.T) {
var (
c = context.Background()
code = "C4946CD493AEEDE67C574DFE2C756D09"
redirectUrl = "https://passport.bilibili.com/web/sns/bind/callback"
app = &model.SnsApps{
AppID: "",
AppSecret: "",
Business: model.BusinessMall,
}
)
convey.Convey("QQSnsInfo", t, func(ctx convey.C) {
res, err := d.QQOauth2Info(c, code, redirectUrl, app)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
ctx.So(res, convey.ShouldBeNil)
})
fmt.Printf("(%+v) error(%+v)", res, err)
})
}
func TestDao_qqAccessToken(t *testing.T) {
var (
c = context.Background()
code = "CF8CE1408E8E43E4CD2DC778B5993FBB"
appID = ""
appSecret = ""
redirectUrl = "https://passport.bilibili.com/web/sns/bind/callback"
)
convey.Convey("qqAccessToken", t, func(ctx convey.C) {
res, err := d.qqAccessToken(c, code, appID, appSecret, redirectUrl)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
ctx.So(res, convey.ShouldBeNil)
})
fmt.Printf("(%+v) error(%+v)", res, err)
})
}
func TestDao_qqOpenID(t *testing.T) {
var (
c = context.Background()
token = ""
business = model.BusinessMall
)
convey.Convey("qqOpenID", t, func(ctx convey.C) {
res, err := d.qqOpenID(c, token, business)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
ctx.So(res, convey.ShouldNotBeEmpty)
})
fmt.Printf("(%+v) error(%+v)", res, err)
})
}

View File

@@ -0,0 +1,200 @@
package dao
import (
"context"
"database/sql"
"fmt"
"hash/crc32"
"go-common/app/service/main/passport-sns/model"
xsql "go-common/library/database/sql"
"go-common/library/log"
)
const (
_getSnsAppsSQL = "SELECT appid,appsecret,platform,business FROM sns_apps"
_getSnsUsersSQL = "SELECT mid,unionid,platform,expires FROM sns_user WHERE mid = ?"
_getSnsTokensSQL = "SELECT mid,openid,unionid,platform,token,expires FROM sns_token WHERE mid = ?"
_getSnsUserByMidSQL = "SELECT mid,unionid,platform FROM sns_user WHERE mid = ? and platform = ?"
_getSnsUserByUnionIDSQL = "SELECT mid,unionid,platform FROM sns_user WHERE unionid = ? and platform = ?"
_addSnsUserSQL = "INSERT INTO sns_user (mid,unionid,platform,expires) VALUES(?,?,?,?)"
_addSnsOpenIDSQL = "INSERT IGNORE INTO sns_openid_%02d (openid,unionid,appid,platform) VALUES(?,?,?,?)"
_addSnsTokenSQL = "INSERT INTO sns_token (mid,openid,unionid,platform,token,expires,appid) VALUES(?,?,?,?,?,?,?) ON DUPLICATE KEY UPDATE mid=?, openid =?, token =?, expires =?, appid =?"
_updateSnsTokenSQL = "UPDATE sns_token SET token =?, expires =? WHERE mid =? and platform = ?"
_updateSnsUserSQL = "UPDATE sns_user SET expires =? WHERE mid =? and platform =?"
_delSnsUserSQL = "DELETE FROM sns_user WHERE mid = ? and platform = ?"
_delSnsUsersSQL = "DELETE FROM sns_user WHERE mid = ?"
)
// SnsApps get sns apps
func (d *Dao) SnsApps(c context.Context) (res []*model.SnsApps, err error) {
var rows *xsql.Rows
if rows, err = d.db.Query(c, _getSnsAppsSQL); err != nil {
log.Error("SnsApps dao.db.Query error(%+v)", err)
return
}
res = make([]*model.SnsApps, 0)
defer rows.Close()
for rows.Next() {
r := new(model.SnsApps)
if err = rows.Scan(&r.AppID, &r.AppSecret, &r.Platform, &r.Business); err != nil {
log.Error("SnsApps row.Scan() error(%+v)", err)
res = nil
return
}
res = append(res, r)
}
return
}
// SnsUsers get sns users
func (d *Dao) SnsUsers(c context.Context, mid int64) (res []*model.SnsUser, err error) {
var rows *xsql.Rows
if rows, err = d.db.Query(c, _getSnsUsersSQL, mid); err != nil {
log.Error("SnsUsers dao.db.Query error(%+v)", err)
return
}
res = make([]*model.SnsUser, 0)
defer rows.Close()
for rows.Next() {
r := new(model.SnsUser)
if err = rows.Scan(&r.Mid, &r.UnionID, &r.Platform, &r.Expires); err != nil {
log.Error("SnsUsers row.Scan() error(%+v)", err)
res = nil
return
}
res = append(res, r)
}
return
}
// SnsTokens get sns tokens
func (d *Dao) SnsTokens(c context.Context, mid int64) (res []*model.SnsToken, err error) {
var rows *xsql.Rows
if rows, err = d.db.Query(c, _getSnsTokensSQL, mid); err != nil {
log.Error("SnsTokens dao.db.Query error(%+v)", err)
return
}
res = make([]*model.SnsToken, 0)
defer rows.Close()
for rows.Next() {
r := new(model.SnsToken)
if err = rows.Scan(&r.Mid, &r.OpenID, &r.UnionID, &r.Platform, &r.Token, &r.Expires); err != nil {
log.Error("SnsTokens row.Scan() error(%+v)", err)
res = nil
return
}
res = append(res, r)
}
return
}
// SnsUserByMid get sns user by mid and platform
func (d *Dao) SnsUserByMid(c context.Context, mid int64, platform int) (res *model.SnsUser, err error) {
res = new(model.SnsUser)
row := d.db.QueryRow(c, _getSnsUserByMidSQL, mid, platform)
if err = row.Scan(&res.Mid, &res.UnionID, &res.Platform); err != nil {
if err == xsql.ErrNoRows {
err = nil
res = nil
return
}
log.Error("SnsUserByMid mid(%d) platform(%d) row.Scan() error(%+v)", mid, platform, err)
return
}
return
}
// SnsUserByUnionID get sns user by unionID and platform
func (d *Dao) SnsUserByUnionID(c context.Context, unionID string, platform int) (res *model.SnsUser, err error) {
res = new(model.SnsUser)
row := d.db.QueryRow(c, _getSnsUserByUnionIDSQL, unionID, platform)
if err = row.Scan(&res.Mid, &res.UnionID, &res.Platform); err != nil {
if err == xsql.ErrNoRows {
err = nil
res = nil
return
}
log.Error("SnsUserByUnionID unionID(%s) platform(%d) row.Scan() error(%+v)", unionID, platform, err)
return
}
return
}
// TxAddSnsUser add sns user.
func (d *Dao) TxAddSnsUser(tx *xsql.Tx, a *model.SnsUser) (affected int64, err error) {
var res sql.Result
if res, err = tx.Exec(_addSnsUserSQL, a.Mid, a.UnionID, a.Platform, a.Expires); err != nil {
log.Error("TxAddSnsUser(%+v) tx.Exec() error(%+v)", a, err)
return
}
return res.RowsAffected()
}
// TxAddSnsOpenID add sns openid.
func (d *Dao) TxAddSnsOpenID(tx *xsql.Tx, a *model.SnsOpenID) (affected int64, err error) {
var res sql.Result
if res, err = tx.Exec(fmt.Sprintf(_addSnsOpenIDSQL, openIDSuffix(a.OpenID)), a.OpenID, a.UnionID, a.AppID, a.Platform); err != nil {
log.Error("TxAddSnsOpenID(%+v) tx.Exec() error(%+v)", a, err)
return
}
return res.RowsAffected()
}
// TxAddSnsToken add sns token.
func (d *Dao) TxAddSnsToken(tx *xsql.Tx, a *model.SnsToken) (affected int64, err error) {
var res sql.Result
if res, err = tx.Exec(_addSnsTokenSQL, a.Mid, a.OpenID, a.UnionID, a.Platform, a.Token, a.Expires, a.AppID, a.Mid, a.OpenID, a.Token, a.Expires, a.AppID); err != nil {
log.Error("TxAddSnsToken(%+v) tx.Exec() error(%+v)", a, err)
return
}
return res.RowsAffected()
}
// TxUpdateSnsUser update sns user expires.
func (d *Dao) TxUpdateSnsUser(tx *xsql.Tx, a *model.SnsUser) (affected int64, err error) {
var res sql.Result
if res, err = tx.Exec(_updateSnsUserSQL, a.Expires, a.Mid, a.Platform); err != nil {
log.Error("TxUpdateSnsUser(%+v) tx.Exec() error(%+v)", a, err)
return
}
return res.RowsAffected()
}
// TxUpdateSnsToken update sns token.
func (d *Dao) TxUpdateSnsToken(tx *xsql.Tx, a *model.SnsToken) (affected int64, err error) {
var res sql.Result
if res, err = tx.Exec(_updateSnsTokenSQL, a.Token, a.Expires, a.Mid, a.Platform); err != nil {
log.Error("TxUpdateSnsToken(%+v) tx.Exec() error(%+v)", a, err)
return
}
return res.RowsAffected()
}
// DelSnsUser del sns user.
func (d *Dao) DelSnsUser(c context.Context, mid int64, platform int) (affected int64, err error) {
var res sql.Result
if res, err = d.db.Exec(c, _delSnsUserSQL, mid, platform); err != nil {
log.Error("DelSnsUser mid(%d) platform(%d) d.db.Exec() error(%+v)", mid, platform, err)
return
}
return res.RowsAffected()
}
// DelSnsUsers del sns user by mid.
func (d *Dao) DelSnsUsers(c context.Context, mid int64) (affected int64, err error) {
var res sql.Result
if res, err = d.db.Exec(c, _delSnsUsersSQL, mid); err != nil {
log.Error("DelAllSnsUser mid(%d) d.db.Exec() error(%+v)", mid, err)
return
}
return res.RowsAffected()
}
func openIDSuffix(openID string) int {
v := int(crc32.ChecksumIEEE([]byte(openID)))
if v < 0 {
v = -v
}
return v % 100
}

View File

@@ -0,0 +1,255 @@
package dao
import (
"context"
"database/sql"
"database/sql/driver"
"fmt"
"reflect"
"testing"
"go-common/app/service/main/passport-sns/model"
xsql "go-common/library/database/sql"
"github.com/bouk/monkey"
"github.com/smartystreets/goconvey/convey"
)
func TestDao_SnsApps(t *testing.T) {
convey.Convey("SnsApps", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
res, err := d.SnsApps(c)
ctx.Convey("Then err should be nil.res should not nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
})
})
}
func TestDao_SnsUsers(t *testing.T) {
convey.Convey("SnsUsers", t, func(ctx convey.C) {
var (
c = context.Background()
mid = int64(0)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
res, err := d.SnsUsers(c, mid)
ctx.Convey("Then err should be nil.res should not nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
})
})
}
func TestDao_SnsTokens(t *testing.T) {
convey.Convey("SnsTokens", t, func(ctx convey.C) {
var (
c = context.Background()
mid = int64(0)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
res, err := d.SnsTokens(c, mid)
ctx.Convey("Then err should be nil.res should not nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
})
})
}
func TestDao_SnsUserByMid(t *testing.T) {
convey.Convey("SnsUserByMid", t, func(ctx convey.C) {
var (
c = context.Background()
mid = int64(0)
platform = model.PlatformQQ
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
res, err := d.SnsUserByMid(c, mid, platform)
ctx.Convey("Then err should be nil.res should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldBeNil)
})
})
})
}
func TestDao_SnsUserByUnionID(t *testing.T) {
convey.Convey("SnsUserByUnionID", t, func(ctx convey.C) {
var (
c = context.Background()
unionID = ""
platform = model.PlatformQQ
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
res, err := d.SnsUserByUnionID(c, unionID, platform)
ctx.Convey("Then err should be nil.res should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldBeNil)
})
})
})
}
func TestDao_TxAddSnsUser(t *testing.T) {
convey.Convey("TxAddSnsUser", t, func(ctx convey.C) {
var (
tx, _ = d.BeginTran(context.Background())
a = &model.SnsUser{}
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
mock := monkey.PatchInstanceMethod(reflect.TypeOf(tx), "Exec", func(_ *xsql.Tx, _ string, _ ...interface{}) (res sql.Result, err error) {
return driver.RowsAffected(1), nil
})
defer mock.Unpatch()
affected, err := d.TxAddSnsUser(tx, a)
ctx.Convey("Then err should be nil.affected should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(affected, convey.ShouldNotBeNil)
})
})
})
}
func TestDao_TxAddSnsOpenID(t *testing.T) {
convey.Convey("TxAddSnsOpenID", t, func(ctx convey.C) {
var (
tx, _ = d.BeginTran(context.Background())
a = &model.SnsOpenID{}
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
mock := monkey.PatchInstanceMethod(reflect.TypeOf(tx), "Exec", func(_ *xsql.Tx, _ string, _ ...interface{}) (res sql.Result, err error) {
return driver.RowsAffected(1), nil
})
defer mock.Unpatch()
affected, err := d.TxAddSnsOpenID(tx, a)
ctx.Convey("Then err should be nil.affected should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(affected, convey.ShouldNotBeNil)
})
})
})
}
func TestDao_TxAddSnsToken(t *testing.T) {
convey.Convey("TxAddSnsToken", t, func(ctx convey.C) {
var (
tx, _ = d.BeginTran(context.Background())
a = &model.SnsToken{}
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
mock := monkey.PatchInstanceMethod(reflect.TypeOf(tx), "Exec", func(_ *xsql.Tx, _ string, _ ...interface{}) (res sql.Result, err error) {
return driver.RowsAffected(1), nil
})
defer mock.Unpatch()
affected, err := d.TxAddSnsToken(tx, a)
ctx.Convey("Then err should be nil.affected should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(affected, convey.ShouldNotBeNil)
})
})
})
}
func TestDao_TxUpdateSnsUser(t *testing.T) {
convey.Convey("TxUpdateSnsUser", t, func(ctx convey.C) {
var (
tx, _ = d.BeginTran(context.Background())
a = &model.SnsUser{}
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
mock := monkey.PatchInstanceMethod(reflect.TypeOf(tx), "Exec", func(_ *xsql.Tx, _ string, _ ...interface{}) (res sql.Result, err error) {
return driver.RowsAffected(1), nil
})
defer mock.Unpatch()
affected, err := d.TxUpdateSnsUser(tx, a)
ctx.Convey("Then err should be nil.affected should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(affected, convey.ShouldNotBeNil)
})
})
})
}
func TestDao_TxUpdateSnsToken(t *testing.T) {
convey.Convey("TxUpdateSnsToken", t, func(ctx convey.C) {
var (
tx, _ = d.BeginTran(context.Background())
a = &model.SnsToken{}
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
mock := monkey.PatchInstanceMethod(reflect.TypeOf(tx), "Exec", func(_ *xsql.Tx, _ string, _ ...interface{}) (res sql.Result, err error) {
return driver.RowsAffected(1), nil
})
defer mock.Unpatch()
affected, err := d.TxUpdateSnsToken(tx, a)
ctx.Convey("Then err should be nil.affected should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(affected, convey.ShouldNotBeNil)
})
})
})
}
func TestDao_DelSnsUser(t *testing.T) {
convey.Convey("DelSnsUser", t, func(ctx convey.C) {
var (
c = context.Background()
mid = int64(0)
platform = model.PlatformQQ
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
mock := monkey.PatchInstanceMethod(reflect.TypeOf(d.db), "Exec", func(_ *xsql.DB, _ context.Context, _ string, _ ...interface{}) (res sql.Result, err error) {
return driver.RowsAffected(1), nil
})
defer mock.Unpatch()
affected, err := d.DelSnsUser(c, mid, platform)
ctx.Convey("Then err should be nil.affected should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(affected, convey.ShouldNotBeNil)
})
})
})
}
func TestDao_DelAllSnsUser(t *testing.T) {
convey.Convey("DelAllSnsUser", t, func(ctx convey.C) {
var (
c = context.Background()
mid = int64(0)
)
ctx.Convey("When everything gose positive", func(ctx convey.C) {
mock := monkey.PatchInstanceMethod(reflect.TypeOf(d.db), "Exec", func(_ *xsql.DB, _ context.Context, _ string, _ ...interface{}) (res sql.Result, err error) {
return driver.RowsAffected(1), nil
})
defer mock.Unpatch()
affected, err := d.DelSnsUsers(c, mid)
ctx.Convey("Then err should be nil.affected should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(affected, convey.ShouldNotBeNil)
})
})
})
}
func TestDao_openIDSuffix(t *testing.T) {
convey.Convey("openIDSuffix", t, func(ctx convey.C) {
res := openIDSuffix("test")
fmt.Println(res)
ctx.Convey("Then res should not be nil.", func(ctx convey.C) {
ctx.So(res, convey.ShouldNotBeNil)
})
})
}

View File

@@ -0,0 +1,70 @@
package dao
import (
"context"
"encoding/json"
"fmt"
"net/http"
"net/url"
"time"
"go-common/app/service/main/passport-sns/model"
"go-common/library/ecode"
"go-common/library/log"
)
const (
_weiboAuthorizeUrl = "https://api.weibo.com/oauth2/authorize"
_weiboAccessTokenUrl = "https://api.weibo.com/oauth2/access_token"
)
// WeiboAuthorize .
func (d *Dao) WeiboAuthorize(c context.Context, appID, redirectURL, display string) (url string) {
return fmt.Sprintf(_weiboAuthorizeUrl+"?client_id=%s&redirect_uri=%s&scope=all", appID, redirectURL)
}
// WeiboOauth2Info .
func (d *Dao) WeiboOauth2Info(c context.Context, code, redirectUrl string, app *model.SnsApps) (res *model.Oauth2Info, err error) {
accessResp, err := d.weiboAccessToken(c, code, app.AppID, app.AppSecret, redirectUrl)
if err != nil {
return nil, err
}
res = &model.Oauth2Info{
Token: accessResp.Token,
Refresh: accessResp.Refresh,
Expires: time.Now().Unix() + accessResp.Expires,
OpenID: accessResp.OpenID,
UnionID: accessResp.OpenID,
}
return
}
// weiboAccessToken .
func (d *Dao) weiboAccessToken(c context.Context, code, appID, appSecret, redirectUrl string) (resp *model.WeiboAccessResp, err error) {
var (
res *http.Response
params = url.Values{}
)
params.Set("client_id", appID)
params.Set("client_secret", appSecret)
params.Set("grant_type", "authorization_code")
params.Set("code", code)
params.Set("redirect_uri", redirectUrl)
res, err = d.client.PostForm(_weiboAccessTokenUrl, params)
if err != nil {
log.Error("d.weiboAccessToken error(%+v) code(%s) appID(%s)", err, code, appID)
return nil, err
}
defer res.Body.Close()
dc := json.NewDecoder(res.Body)
resp = new(model.WeiboAccessResp)
if err = dc.Decode(resp); err != nil {
return
}
if resp.Code == _respCodeSuccess {
return resp, nil
}
log.Error("request weibo failed with code(%d) desc(%s)", resp.Code, resp.Description)
return nil, ecode.PassportSnsRequestErr
}

View File

@@ -0,0 +1,68 @@
package dao
import (
"context"
"fmt"
"testing"
"go-common/app/service/main/passport-sns/model"
"github.com/smartystreets/goconvey/convey"
)
func TestDao_WeiboAuthorize(t *testing.T) {
var (
c = context.Background()
AppID = "101135748"
RedirectUrl = "https://passport.bilibili.com/login/snsback?sns=weibo"
Display = "mobile"
// AppID : "1108092926",
// RedirectUrl : "https://passport.bilibili.com/web/sns/bind/callback/weibo",
)
convey.Convey("WeiboAuthorize", t, func(ctx convey.C) {
res := d.WeiboAuthorize(c, AppID, RedirectUrl, Display)
ctx.Convey("Then res should not be nil.", func(ctx convey.C) {
ctx.So(res, convey.ShouldNotBeNil)
})
fmt.Println(res)
})
}
func TestDao_WeiboOauth2Info(t *testing.T) {
var (
c = context.Background()
code = "C4946CD493AEEDE67C574DFE2C756D09"
redirectUrl = "https://passport.bilibili.com/web/sns/bind/callback"
app = &model.SnsApps{
AppID: "",
AppSecret: "",
Business: model.BusinessMall,
}
)
convey.Convey("WeiboOauth2Info", t, func(ctx convey.C) {
res, err := d.WeiboOauth2Info(c, code, redirectUrl, app)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
ctx.So(res, convey.ShouldBeNil)
})
fmt.Printf("(%+v) error(%+v)", res, err)
})
}
func TestDao_weiboAccessToken(t *testing.T) {
var (
c = context.Background()
code = "CF8CE1408E8E43E4CD2DC778B5993FBB"
appID = ""
appSecret = ""
redirectUrl = "https://passport.bilibili.com/web/sns/bind/callback"
)
convey.Convey("weiboAccessToken", t, func(ctx convey.C) {
res, err := d.weiboAccessToken(c, code, appID, appSecret, redirectUrl)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
ctx.So(res, convey.ShouldBeNil)
})
fmt.Printf("(%+v) error(%+v)", res, err)
})
}