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,46 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = ["card.go"],
importpath = "go-common/app/interface/main/account/service/card",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/account/conf:go_default_library",
"//app/service/main/card/api/grpc/v1: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"],
)
go_test(
name = "go_default_test",
srcs = ["card_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/account/conf:go_default_library",
"//app/service/main/card/api/grpc/v1:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)

View File

@@ -0,0 +1,91 @@
package card
import (
"context"
"go-common/app/interface/main/account/conf"
v1 "go-common/app/service/main/card/api/grpc/v1"
)
// Service .
type Service struct {
// conf
c *conf.Config
// card service
cardRPC v1.CardClient
}
// New create service instance and return.
func New(c *conf.Config) (s *Service) {
s = &Service{
c: c,
}
cardRPC, err := v1.NewClient(c.CardClient)
if err != nil {
panic(err)
}
s.cardRPC = cardRPC
return
}
// UserCard user card info.
func (s *Service) UserCard(c context.Context, mid int64) (res *v1.ModelUserCard, err error) {
var reply *v1.UserCardReply
if reply, err = s.cardRPC.UserCard(c, &v1.UserCardReq{Mid: mid}); err != nil {
return
}
res = reply.Res
return
}
// Card get card info by id.
func (s *Service) Card(c context.Context, id int64) (res *v1.ModelCard, err error) {
var reply *v1.CardReply
if reply, err = s.cardRPC.Card(c, &v1.CardReq{Id: id}); err != nil {
return
}
res = reply.Data_0
return
}
// CardHots get all hots cards.
func (s *Service) CardHots(c context.Context) (res []*v1.ModelCard, err error) {
var reply *v1.CardHotsReply
if reply, err = s.cardRPC.CardHots(c, &v1.CardHotsReq{}); err != nil {
return
}
res = reply.Data_0
return
}
// AllGroup all group.
func (s *Service) AllGroup(c context.Context, mid int64) (res *v1.ModelAllGroupResp, err error) {
var reply *v1.AllGroupReply
if reply, err = s.cardRPC.AllGroup(c, &v1.AllGroupReq{Mid: mid}); err != nil {
return
}
res = reply.Res
return
}
// CardsByGid get cards by gid.
func (s *Service) CardsByGid(c context.Context, id int64) (res []*v1.ModelCard, err error) {
var reply *v1.CardsByGidReply
if reply, err = s.cardRPC.CardsByGid(c, &v1.CardsByGidReq{Gid: id}); err != nil {
return
}
res = reply.Data_0
return
}
// Equip card equip.
func (s *Service) Equip(c context.Context, arg *v1.ModelArgEquip) (err error) {
_, err = s.cardRPC.Equip(c, &v1.EquipReq{Arg: arg})
return
}
// Demount card demount.
func (s *Service) Demount(c context.Context, mid int64) (err error) {
_, err = s.cardRPC.DemountEquip(c, &v1.DemountEquipReq{Mid: mid})
return
}

View File

@@ -0,0 +1,90 @@
package card
import (
"context"
"flag"
"testing"
"go-common/app/interface/main/account/conf"
v1 "go-common/app/service/main/card/api/grpc/v1"
. "github.com/smartystreets/goconvey/convey"
)
var (
s *Service
c = context.Background()
)
func init() {
flag.Set("conf", "../../cmd/account-interface-example.toml")
var err error
if err = conf.Init(); err != nil {
panic(err)
}
s = New(conf.Conf)
}
// go test -test.v -test.run TestServiceUserCard
func TestServiceUserCard(t *testing.T) {
Convey("TestServiceUserCard", t, func() {
res, err := s.UserCard(c, 1)
t.Logf("%v", res)
So(err, ShouldBeNil)
})
}
// go test -test.v -test.run TestServiceCard
func TestServiceCard(t *testing.T) {
Convey("TestServiceCard", t, func() {
res, err := s.Card(c, 1)
t.Logf("%v", res)
So(err, ShouldBeNil)
})
}
// go test -test.v -test.run TestCardHots
func TestCardHots(t *testing.T) {
Convey("TestCardHots", t, func() {
res, err := s.CardHots(c)
t.Logf("%v", res)
So(err, ShouldBeNil)
})
}
// go test -test.v -test.run TestAllGroup
func TestAllGroup(t *testing.T) {
Convey("TestAllGroup", t, func() {
res, err := s.AllGroup(c, 1)
t.Logf("%v", res)
So(err, ShouldBeNil)
})
}
// go test -test.v -test.run TestCardsByGid
func TestCardsByGid(t *testing.T) {
Convey("TestCardsByGid", t, func() {
res, err := s.CardsByGid(c, 1)
t.Logf("%v", res)
So(err, ShouldBeNil)
})
}
// go test -test.v -test.run TestEquip
func TestEquip(t *testing.T) {
Convey("TestEquip", t, func() {
err := s.Equip(c, &v1.ModelArgEquip{
Mid: 2,
CardId: 1,
})
So(err, ShouldBeNil)
})
}
// go test -test.v -test.run TestDemount
func TestDemount(t *testing.T) {
Convey("TestDemount", t, func() {
err := s.Demount(c, 2)
So(err, ShouldBeNil)
})
}

View File

@@ -0,0 +1,49 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = ["coupon_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/account/conf:go_default_library",
"//app/service/main/coupon/api:go_default_library",
"//app/service/main/coupon/model:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = ["coupon.go"],
importpath = "go-common/app/interface/main/account/service/coupon",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/account/conf:go_default_library",
"//app/service/main/coupon/api:go_default_library",
"//app/service/main/coupon/model:go_default_library",
"//app/service/main/coupon/rpc/client: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,80 @@
package coupon
import (
"context"
"go-common/app/interface/main/account/conf"
v1 "go-common/app/service/main/coupon/api"
"go-common/app/service/main/coupon/model"
courpc "go-common/app/service/main/coupon/rpc/client"
)
// Service .
type Service struct {
// conf
c *conf.Config
// rpc
couRPC *courpc.Service
// coupon grpc service
coupongRPC v1.CouponClient
}
// New create service instance and return.
func New(c *conf.Config) (s *Service) {
s = &Service{
c: c,
couRPC: courpc.New(c.RPCClient2.Coupon),
}
coupongRPC, err := v1.NewClient(c.CouponClient)
if err != nil {
panic(err)
}
s.coupongRPC = coupongRPC
return
}
// AllowanceList allowance list.
func (s *Service) AllowanceList(c context.Context, mid int64, state int8) (res []*model.CouponAllowancePanelInfo, err error) {
res, err = s.couRPC.AllowanceList(c, &model.ArgAllowanceList{Mid: mid, State: state})
return
}
// CouponPage coupon list.
func (s *Service) CouponPage(c context.Context, a *model.ArgRPCPage) (res *model.CouponPageRPCResp, err error) {
res, err = s.couRPC.CouponPage(c, a)
return
}
// CouponCartoonPage coupon cartoon list.
// func (s *Service) CouponCartoonPage(c context.Context, a *model.ArgRPCPage) (res *model.CouponCartoonPageResp, err error) {
// res, err = s.couRPC.CouponCartoonPage(c, a)
// return
// }
// PrizeCards .
func (s *Service) PrizeCards(c context.Context, a *model.ArgCount) (res []*model.PrizeCardRep, err error) {
res, err = s.couRPC.PrizeCards(c, a)
return
}
// PrizeDraw .
func (s *Service) PrizeDraw(c context.Context, a *model.ArgPrizeDraw) (res *model.PrizeCardRep, err error) {
res, err = s.couRPC.PrizeDraw(c, a)
return
}
// CaptchaToken captcha token.
func (s *Service) CaptchaToken(c context.Context, a *v1.CaptchaTokenReq) (res *v1.CaptchaTokenReply, err error) {
return s.coupongRPC.CaptchaToken(c, a)
}
// UseCouponCode use coupon code.
func (s *Service) UseCouponCode(c context.Context, a *model.ArgUseCouponCode) (res *v1.UseCouponCodeResp, err error) {
return s.coupongRPC.UseCouponCode(c, &v1.UseCouponCodeReq{
Token: a.Token,
Code: a.Code,
Verify: a.Verify,
Ip: a.IP,
Mid: a.Mid,
})
}

View File

@@ -0,0 +1,78 @@
package coupon
import (
"context"
"flag"
"fmt"
"testing"
"go-common/app/interface/main/account/conf"
v1 "go-common/app/service/main/coupon/api"
"go-common/app/service/main/coupon/model"
. "github.com/smartystreets/goconvey/convey"
)
var (
s *Service
)
func init() {
flag.Set("conf", "../../cmd/account-interface-example.toml")
var err error
if err = conf.Init(); err != nil {
panic(err)
}
s = New(conf.Conf)
}
// go test -test.v -test.run TestServiceAllowanceList
func TestServiceAllowanceList(t *testing.T) {
Convey("TestServiceAllowanceList", t, func() {
res, err := s.AllowanceList(context.TODO(), int64(1), int8(0))
t.Logf("%v", res)
So(err, ShouldBeNil)
})
}
// go test -test.v -test.run TestCouponPage
// func TestCouponPage(t *testing.T) {
// Convey("TestCouponPage", t, func() {
// res, err := s.CouponPage(context.TODO(), 1, int8(0), 1, 10)
// t.Logf("%v", res)
// So(err, ShouldBeNil)
// })
// }
// // go test -test.v -test.run TestCouponCartoonPage
// func TestCouponCartoonPage(t *testing.T) {
// Convey("TestCouponCartoonPage", t, func() {
// res, err := s.CouponCartoonPage(context.TODO(), 1, int8(0), 1, 10)
// t.Logf("%v", res)
// So(err, ShouldBeNil)
// })
// }
// go test -test.v -test.run TestServiceCaptchaToken
func TestServiceCaptchaToken(t *testing.T) {
Convey("TestServiceCaptchaToken", t, func() {
res, err := s.CaptchaToken(context.Background(), &v1.CaptchaTokenReq{Ip: ""})
fmt.Println("res:", res)
So(err, ShouldBeNil)
})
}
// go test -test.v -test.run TestServiceUseCouponCode
func TestServiceUseCouponCode(t *testing.T) {
Convey("TestServiceUseCouponCode", t, func() {
res, err := s.UseCouponCode(context.Background(), &model.ArgUseCouponCode{
IP: "",
Token: "927a6ea6e9d64e929beadfba6d2bd491",
Code: "sasazxcvfdsa",
Verify: "e8z90",
Mid: 1,
})
fmt.Println("res:", res)
So(err, ShouldBeNil)
})
}

View File

@@ -0,0 +1,49 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = ["geetest_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/account/conf:go_default_library",
"//app/interface/main/account/model:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = ["geetest.go"],
importpath = "go-common/app/interface/main/account/service/geetest",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/account/conf:go_default_library",
"//app/interface/main/account/dao/geetest:go_default_library",
"//app/interface/main/account/model:go_default_library",
"//library/log:go_default_library",
"//vendor/github.com/pkg/errors: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,169 @@
package geetest
import (
"context"
"crypto/md5"
"encoding/hex"
"fmt"
"math"
"math/rand"
"strconv"
"strings"
"go-common/app/interface/main/account/conf"
"go-common/app/interface/main/account/dao/geetest"
"go-common/app/interface/main/account/model"
"go-common/library/log"
"github.com/pkg/errors"
)
// Service is
type Service struct {
c *conf.Config
geetestDao *geetest.Dao
}
// New create service instance and return.
func New(c *conf.Config) (s *Service) {
s = &Service{
c: c,
geetestDao: geetest.New(c),
}
return
}
// Ping check server ok.
func (s *Service) Ping(c context.Context) (err error) {
return
}
// Close dao.
func (s *Service) Close() {}
// PreProcess preprocessing the geetest and get to challenge
func (s *Service) PreProcess(c context.Context, req *model.GeeCaptchaRequest) (res *model.ProcessRes, err error) {
var pre string
res = &model.ProcessRes{}
gc, clientType := s.geetestDao.GeeConfig(req.ClientType, s.c.Geetest)
res.CaptchaID = gc.CaptchaID
res.NewCaptcha = 1
if pre, err = s.geetestDao.PreProcess(c, req.MID, clientType, gc, 1); err != nil || pre == "" {
log.Error("s.geetestDao.PreProcess(%+v) err(%v)", req, err)
randOne := md5.Sum([]byte(strconv.Itoa(rand.Intn(100))))
randTwo := md5.Sum([]byte(strconv.Itoa(rand.Intn(100))))
challenge := hex.EncodeToString(randOne[:]) + hex.EncodeToString(randTwo[:])[0:2]
res.Challenge = challenge
return
}
res.Success = 1
slice := md5.Sum([]byte(pre + gc.PrivateKEY))
res.Challenge = hex.EncodeToString(slice[:])
log.Info("PreProcess success(%+v) ", res)
return
}
// Validate recheck the challenge validate seccode
func (s *Service) Validate(c context.Context, req *model.GeeCheckRequest) (stat bool) {
if len(req.Validate) != 32 {
log.Error("s.Validate(%+v) err(validate not eq 32byte)", req)
stat = s.failbackValidate(c, req.Challenge, req.Validate, req.Seccode)
return
}
gc, clientType := s.geetestDao.GeeConfig(req.ClientType, s.c.Geetest)
slice := md5.Sum([]byte(gc.PrivateKEY + "geetest" + req.Challenge))
if hex.EncodeToString(slice[:]) != req.Validate {
log.Error("s.Validate(%+v) err(challenge not found)", req)
return
}
res, err := s.geetestDao.Validate(c, req.Challenge, req.Seccode, clientType, gc.CaptchaID, req.MID)
if err != nil {
if errors.Cause(err) == context.DeadlineExceeded { // for geetest timeout
stat = true
return
}
log.Error("s.geetestDao.Validate(%+v) err(%v)", req, err)
return
}
slice = md5.Sum([]byte(req.Seccode))
stat = hex.EncodeToString(slice[:]) == res.Seccode
return
}
//failbackValidate geetest failback model.
func (s *Service) failbackValidate(c context.Context, challenge, validate, seccode string) bool {
varr := strings.Split(validate, "_")
if len(varr) < 3 {
return false
}
encodeAns := varr[0]
encodeFbii := varr[1]
encodeIgi := varr[2]
decodeAns := s.decodeResponse(challenge, encodeAns)
decodeFbii := s.decodeResponse(challenge, encodeFbii)
decodeIgi := s.decodeResponse(challenge, encodeIgi)
return s.validateFailImage(decodeAns, decodeFbii, decodeIgi)
}
func (s *Service) decodeResponse(challenge, userresponse string) (res int) {
if len(userresponse) > 100 {
return
}
digits := []int{1, 2, 5, 10, 50}
key := make(map[rune]int)
for _, i := range challenge {
if _, exist := key[i]; exist {
continue
}
value := digits[len(key)%5]
key[i] = value
}
for _, i := range userresponse {
res += key[i]
}
res -= s.decodeRandBase(challenge)
return
}
func (s *Service) decodeRandBase(challenge string) int {
baseStr := challenge[32:]
var tempList []int
for _, char := range baseStr {
tempChar := int(char)
result := tempChar - 48
if tempChar > 57 {
result = tempChar - 87
}
tempList = append(tempList, result)
}
return tempList[0]*36 + tempList[1]
}
func (s *Service) md5Encode(values []byte) string {
return fmt.Sprintf("%x", md5.Sum(values))
}
func (s *Service) validateFailImage(ans, fullBgIndex, imgGrpIndex int) bool {
var thread float64 = 3
fullBg := s.md5Encode([]byte(strconv.Itoa(fullBgIndex)))[0:10]
imgGrp := s.md5Encode([]byte(strconv.Itoa(imgGrpIndex)))[10:20]
var answerDecode []byte
for i := 0; i < 9; i++ {
if i%2 == 0 {
answerDecode = append(answerDecode, fullBg[i])
} else if i%2 == 1 {
answerDecode = append(answerDecode, imgGrp[i])
}
}
xDecode := answerDecode[4:]
xInt64, err := strconv.ParseInt(string(xDecode), 16, 32)
if err != nil {
log.Error("%+v", err)
}
xInt := int(xInt64)
result := xInt % 200
if result < 40 {
result = 40
}
return math.Abs(float64(ans-result)) < thread
}

View File

@@ -0,0 +1,154 @@
package geetest
import (
"context"
"flag"
"os"
"testing"
"go-common/app/interface/main/account/conf"
"go-common/app/interface/main/account/model"
"github.com/smartystreets/goconvey/convey"
)
var (
s *Service
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.account.account-interface")
flag.Set("conf_token", "967eef77ad40b478234f11b0d489d6d6")
flag.Set("tree_id", "3815")
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/account-interface-example.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
s = New(conf.Conf)
m.Run()
os.Exit(0)
}
func TestGeetestPreProcess(t *testing.T) {
convey.Convey("PreProcess", t, func(ctx convey.C) {
var (
c = context.Background()
req = &model.GeeCaptchaRequest{
MID: 1,
}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
res, err := s.PreProcess(c, req)
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)
ctx.Printf("%+v", res)
})
})
})
}
func TestGeetestValidate(t *testing.T) {
convey.Convey("Validate", t, func(ctx convey.C) {
var (
c = context.Background()
req = &model.GeeCheckRequest{
Challenge: "078348b20cda8680bd2a01ac79394c37",
Validate: "",
Seccode: "",
}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
stat := s.Validate(c, req)
ctx.Convey("Then stat should not be nil.", func(ctx convey.C) {
ctx.So(stat, convey.ShouldNotBeNil)
})
})
})
}
func TestGeetestfailbackValidate(t *testing.T) {
convey.Convey("failbackValidate", t, func(ctx convey.C) {
var (
c = context.Background()
challenge = ""
validate = ""
seccode = ""
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := s.failbackValidate(c, challenge, validate, seccode)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestGeetestdecodeResponse(t *testing.T) {
convey.Convey("decodeResponse", t, func(ctx convey.C) {
var (
challenge = ""
userresponse = ""
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
res := s.decodeResponse(challenge, userresponse)
ctx.Convey("Then res should not be nil.", func(ctx convey.C) {
ctx.So(res, convey.ShouldNotBeNil)
})
})
})
}
func TestGeetestdecodeRandBase(t *testing.T) {
convey.Convey("decodeRandBase", t, func(ctx convey.C) {
var (
challenge = ""
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := s.decodeRandBase(challenge)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestGeetestmd5Encode(t *testing.T) {
convey.Convey("md5Encode", t, func(ctx convey.C) {
var (
values = []byte("")
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := s.md5Encode(values)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestGeetestvalidateFailImage(t *testing.T) {
convey.Convey("validateFailImage", t, func(ctx convey.C) {
var (
ans = int(0)
fullBgIndex = int(0)
imgGrpIndex = int(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := s.validateFailImage(ans, fullBgIndex, imgGrpIndex)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,96 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"app_info_test.go",
"notice_test.go",
"remotelogin_test.go",
"reply_test.go",
"service_test.go",
"web_info_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/account/conf:go_default_library",
"//app/interface/main/account/model:go_default_library",
"//app/service/main/secure/model:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"app_info.go",
"medal.go",
"member.go",
"notice.go",
"remotelogin.go",
"reply.go",
"service.go",
"sudo.go",
"web_info.go",
],
importpath = "go-common/app/interface/main/account/service/member",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/account/conf:go_default_library",
"//app/interface/main/account/dao/account:go_default_library",
"//app/interface/main/account/dao/passport:go_default_library",
"//app/interface/main/account/dao/reply:go_default_library",
"//app/interface/main/account/model:go_default_library",
"//app/interface/openplatform/article/model:go_default_library",
"//app/interface/openplatform/article/rpc/client:go_default_library",
"//app/service/main/account/model:go_default_library",
"//app/service/main/account/rpc/client:go_default_library",
"//app/service/main/archive/api:go_default_library",
"//app/service/main/archive/api/gorpc:go_default_library",
"//app/service/main/archive/model/archive:go_default_library",
"//app/service/main/coin/api/gorpc:go_default_library",
"//app/service/main/coin/model:go_default_library",
"//app/service/main/filter/model/rpc:go_default_library",
"//app/service/main/filter/rpc/client:go_default_library",
"//app/service/main/location/model:go_default_library",
"//app/service/main/location/rpc/client:go_default_library",
"//app/service/main/member/api/gorpc:go_default_library",
"//app/service/main/member/model:go_default_library",
"//app/service/main/passport/model:go_default_library",
"//app/service/main/passport/rpc/client:go_default_library",
"//app/service/main/secure/model:go_default_library",
"//app/service/main/secure/rpc/client:go_default_library",
"//app/service/main/up/api/gorpc:go_default_library",
"//app/service/main/usersuit/model:go_default_library",
"//app/service/main/usersuit/rpc/client:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/metadata:go_default_library",
"//library/queue/databus:go_default_library",
"//library/queue/databus/report:go_default_library",
"//library/time:go_default_library",
"//vendor/github.com/pkg/errors: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,448 @@
package member
import (
"context"
"fmt"
"net/url"
"time"
"unicode/utf8"
"go-common/app/interface/main/account/model"
accModel "go-common/app/service/main/account/model"
coModel "go-common/app/service/main/coin/model"
ftModel "go-common/app/service/main/filter/model/rpc"
locModel "go-common/app/service/main/location/model"
meModel "go-common/app/service/main/member/model"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/net/metadata"
"go-common/library/queue/databus/report"
"github.com/pkg/errors"
)
var monitoredIPCountry = map[string]string{
"台湾": "台湾 IP",
"香港": "香港 IP",
"美国": "美国 IP",
"加拿大": "加拿大 IP",
}
var monitoredTelCountry = map[int64]string{
1: "美国/加拿大手机号",
}
var upNameCostCoins = 6.0
// Account get Account info.
func (s *Service) Account(c context.Context, mid int64, ip string) (acc *model.Account, err error) {
var (
nickFree *model.NickFree
mb *meModel.Member
)
marg := &meModel.ArgMemberMid{Mid: mid, RemoteIP: ip}
if mb, err = s.memRPC.Member(c, marg); err != nil {
log.Error("service.memberRPC.MyInfo(%v) error(%v)", marg, err)
return
}
if nickFree, err = s.NickFree(c, mid); err != nil {
return
}
acc = &model.Account{}
acc.Mid = mid
acc.Birthday = mb.Birthday.Time().Format("2006-01-02")
acc.Uname = mb.Name
acc.Face = mb.Face
acc.Sign = mb.Sign
acc.Sex = int8(mb.Sex)
acc.NickFree = nickFree.NickFree
return
}
// UpdateFace Update Face
func (s *Service) UpdateFace(c context.Context, mid int64, faceFile []byte, ftype string) (string, error) {
ip := metadata.String(c, metadata.RemoteIP)
// check
profile, err := s.accRPC.Profile3(c, &accModel.ArgMid{Mid: mid})
if err != nil {
return "", errors.WithStack(err)
}
//判断是否绑定手机号
if !s.validateTelStatus(profile.TelStatus) {
return "", ecode.MemberPhoneRequired
}
if profile.Silence != 0 {
return "", ecode.MemberBlocked
}
//Upload bfs
faceURL, err := s.accDao.UploadImage(c, ftype, faceFile, s.c.FaceBFS)
if err != nil {
log.Error("s.bfsDao.Upload(%d) error(%v)", mid, err)
return "", errors.WithStack(err)
}
URL, err := url.Parse(faceURL)
if err != nil {
return "", errors.WithStack(err)
}
inMonitor := s.ensureMonitor(c, mid, ip)
arg := &meModel.ArgAddPropertyReview{
Mid: mid,
New: URL.Path,
State: meModel.ReviewStateQueuing,
Property: meModel.ReviewPropertyFace,
}
if inMonitor {
arg.State = meModel.ReviewStateWait
return profile.Face, s.memRPC.AddPropertyReview(c, arg)
}
if err := s.memRPC.AddPropertyReview(c, arg); err != nil {
log.Error("s.memRPC.AddPropertyReview(%d,%s) error(%v)", mid, faceFile, err)
return "", errors.WithStack(err)
}
if err := s.memRPC.SetFace(c, &meModel.ArgUpdateFace{Mid: mid, Face: URL.Path}); err != nil {
log.Error("s.memRPC.SetFace(%d,%s) error(%v)", mid, faceURL, err)
return "", errors.WithStack(err)
}
return faceURL, nil
}
// UpdateName .
func (s *Service) UpdateName(c context.Context, mid int64, name, appkey string) error {
ip := metadata.String(c, metadata.RemoteIP)
_, inWhiteList := s.nickFreeAppKeys[appkey]
if inWhiteList {
return s.updateNameWithinWhiteList(c, mid, name, ip)
}
return s.updateName(c, mid, name, ip)
}
// updateNameWithinWhiteList 白名单 appkey 不扣硬币
func (s *Service) updateNameWithinWhiteList(c context.Context, mid int64, name, ip string) error {
if err := s.nameIsValid(c, mid, name, ip); err != nil {
return err
}
profile, err := s.accRPC.Profile3(c, &accModel.ArgMid{Mid: mid})
if err != nil {
return errors.WithStack(err)
}
if err := s.permitName(c, profile, ip); err != nil {
return err
}
if profile.Name == name {
log.Info("Update name is same to origin: mid: %d, name: %s, origin: %s", mid, name, profile.Name)
return nil
}
inMonitor := s.ensureMonitor(c, mid, ip)
remark := "appkey白名单修改昵称"
// 在监控列表里就加入添加审核列表
if inMonitor {
saveUpNameLog(mid, profile.Name, name, remark, inMonitor, ip)
return errors.WithStack(s.memRPC.AddPropertyReview(c, &meModel.ArgAddPropertyReview{
Mid: mid,
New: name,
State: meModel.ReviewStateWait,
Property: meModel.ReviewPropertyName,
Extra: map[string]interface{}{"nick_free": true},
}))
}
//修改昵称
if err := s.passDao.UpdateName(c, mid, name, ip); err != nil {
return errors.WithStack(err)
}
saveUpNameLog(mid, profile.Name, name, remark, inMonitor, ip)
return nil
}
//UpdateName update name.
func (s *Service) updateName(c context.Context, mid int64, name, ip string) error {
if err := s.nameIsValid(c, mid, name, ip); err != nil {
return err
}
profile, err := s.accRPC.Profile3(c, &accModel.ArgMid{Mid: mid})
if err != nil {
return errors.WithStack(err)
}
if err = s.permitName(c, profile, ip); err != nil {
return err
}
if profile.Name == name {
log.Info("Update name is same to origin: mid: %d, name: %s, origin: %s", mid, name, profile.Name)
return nil
}
// 判断是否改昵称免费
nickFree, err := s.NickFree(c, mid)
if err != nil {
return err
}
remark := "快速注册修改昵称"
if !nickFree.NickFree {
coins, coinErr := s.coinRPC.UserCoins(c, &coModel.ArgCoinInfo{Mid: mid, RealIP: ip})
if coinErr != nil {
return errors.WithStack(coinErr)
}
if coins < upNameCostCoins {
return ecode.UpdateUnameMoneyIsNot
}
remark = "修改昵称"
}
inMonitor := s.ensureMonitor(c, mid, ip)
// 在监控列表里就加入添加审核列表
if inMonitor {
saveUpNameLog(mid, profile.Name, name, remark, inMonitor, ip)
return errors.WithStack(s.memRPC.AddPropertyReview(c, &meModel.ArgAddPropertyReview{
Mid: mid,
New: name,
State: meModel.ReviewStateWait,
Property: meModel.ReviewPropertyName,
Extra: map[string]interface{}{"nick_free": nickFree.NickFree},
}))
}
//修改昵称
if err = s.passDao.UpdateName(c, mid, name, ip); err != nil {
return errors.WithStack(err)
}
saveUpNameLog(mid, profile.Name, name, remark, inMonitor, ip)
if nickFree.NickFree {
return errors.WithStack(s.memRPC.SetNickUpdated(c, &meModel.ArgMemberMid{Mid: mid}))
}
//扣除硬币
if _, err = s.coinRPC.ModifyCoin(c, &coModel.ArgModifyCoin{
Mid: mid,
Count: -upNameCostCoins,
Reason: fmt.Sprintf("UPDATE:NICK:%s=>%s", profile.Name, name),
IP: ip,
}); err != nil {
return errors.WithStack(err)
}
return nil
}
func (s *Service) monitorByIP(ctx context.Context, mid int64, ip string) (bool, string) {
IP, err := s.locRPC.Info(ctx, &locModel.ArgIP{IP: ip})
if err != nil || IP == nil {
log.Error("Failed to get ip info with ip: %s: %+v", ip, err)
return false, ""
}
descr, shouldMonitor := monitoredIPCountry[IP.Country]
if !shouldMonitor {
return false, ""
}
return true, descr
}
func (s *Service) monitorByTel(ctx context.Context, mid int64, ip string) (bool, string) {
p, err := s.passDao.QueryByMid(ctx, mid, ip)
if err != nil {
log.Error("Failed to query by mid form pasport: mid: %d: %+v", mid, err)
return false, ""
}
descr, shouldMonitor := monitoredTelCountry[p.CountryCode]
if !shouldMonitor {
return false, ""
}
return true, descr
}
func (s *Service) shouldMonitor(ctx context.Context, mid int64, ip string) (bool, string) {
should, descr := s.monitorByIP(ctx, mid, ip)
if should {
return true, descr
}
should, descr = s.monitorByTel(ctx, mid, ip)
if should {
return true, descr
}
return false, ""
}
func (s *Service) ensureMonitor(ctx context.Context, mid int64, ip string) bool {
inMonitor, _ := s.memRPC.IsInMonitor(ctx, &meModel.ArgMid{Mid: mid})
if inMonitor {
return true
}
should, descr := s.shouldMonitor(ctx, mid, ip)
if !should {
return false
}
if err := s.memRPC.AddUserMonitor(ctx, &meModel.ArgAddUserMonitor{
Mid: mid,
Operator: "system",
Remark: fmt.Sprintf("系统自动导入-%s", descr),
}); err != nil {
log.Error("Failed to add user moniter: mid: %d: %+v", mid, err)
}
return true
}
// UpdateSex update sex.
func (s *Service) UpdateSex(c context.Context, mid, sex int64) (err error) {
ip := metadata.String(c, metadata.RemoteIP)
return s.accDao.UpdateSex(c, mid, sex, ip)
}
//UpdateSign update sign.
func (s *Service) UpdateSign(c context.Context, mid int64, sign string) error {
ip := metadata.String(c, metadata.RemoteIP)
// 签名最长 70 个字符
if utf8.RuneCountInString(sign) > 70 {
return ecode.MemberSignOverLimit
}
// 签名不能包含 emoji
if model.HasEmoji(sign) {
return ecode.MemberSignHasEmoji
}
// 过滤敏感词
res, err := s.filterRPC.Filter(c, &ftModel.ArgFilter{Area: "sign", Message: sign})
if err != nil {
return err
}
// 大于 20 认为包含敏感词
if res.Level >= 20 {
return ecode.MemberSignSensitive
}
// 检查是否绑定手机
profile, err := s.accRPC.Profile3(c, &accModel.ArgMid{Mid: mid})
if err != nil {
return errors.WithStack(err)
}
if !s.validateTelStatus(profile.TelStatus) {
return ecode.MemberPhoneRequired
}
// 检查是否被禁言
if profile.Silence != 0 {
return ecode.MemberBlocked
}
// 如果和老的一模一样就没必要更新了
if profile.Sign == sign {
log.Info("Update sign is same to origin: mid: %d, sign: %s, origin: %s", mid, sign, profile.Sign)
return nil
}
inMonitor := s.ensureMonitor(c, mid, ip)
// 不在监控列表里就直接更新
if !inMonitor {
return errors.WithStack(s.memRPC.SetSign(c, &meModel.ArgUpdateSign{
Mid: mid,
Sign: sign,
RemoteIP: ip,
}))
}
// 否则就加入监控列表
return errors.WithStack(s.memRPC.AddPropertyReview(c, &meModel.ArgAddPropertyReview{
Mid: mid,
New: sign,
State: meModel.ReviewStateWait,
Property: meModel.ReviewPropertySign,
}))
}
// UpdateBirthday update birthday.
func (s *Service) UpdateBirthday(c context.Context, mid int64, birthday string) (err error) {
ip := metadata.String(c, metadata.RemoteIP)
return s.accDao.UpdateBirthday(c, mid, ip, birthday)
}
// NickFree .
func (s *Service) NickFree(c context.Context, mid int64) (nickFree *model.NickFree, err error) {
var (
isRegFast bool
nickUpdated bool
ip = metadata.String(c, metadata.RemoteIP)
)
sarg := &meModel.ArgMemberMid{Mid: mid}
if nickUpdated, err = s.memRPC.NickUpdated(c, sarg); err != nil {
log.Error("s.memRPC.IsUpNickFree(%v) error (%v)", sarg, err)
return
}
nickFree = &model.NickFree{}
if nickUpdated {
return
}
if isRegFast, err = s.passDao.FastReg(c, mid, ip); err != nil {
return
}
if isRegFast {
nickFree.NickFree = true
}
return
}
func saveUpNameLog(mid int64, oName, nName, remark string, isMonitor bool, ip string) {
report.User(&report.UserInfo{
Mid: mid,
Business: model.UpNameLogID,
Action: model.UpNameAction,
IP: ip,
Ctime: time.Now(),
Index: []interface{}{0, 0, 0, oName, nName, remark},
Content: map[string]interface{}{
"is_monitor": isMonitor,
"old_name": oName,
"new_name": nName,
"reason": fmt.Sprintf("修改昵称(原昵称:%s 新昵称:%s)", oName, nName),
"remark": remark,
},
})
}
func (s *Service) permitName(c context.Context, profile *accModel.Profile, ip string) error {
if !s.validateTelStatus(profile.TelStatus) {
return ecode.MemberPhoneRequired
}
// 检查是否被禁言
if profile.Silence != 0 {
return ecode.MemberBlocked
}
//昵称锁定,是否官方认证
if profile.Official.Role != 0 {
log.Info("update name fail, name is official, mid: %d", profile.Mid)
return ecode.UpdateUnameHadOfficial
}
pProfile, err := s.passDao.QueryByMid(c, profile.Mid, ip)
if err != nil {
return err
}
if pProfile.NickLock == 1 {
log.Info("update name fail, name is locked, mid: %d", profile.Mid)
return ecode.UpdateUnameHadLocked
}
return nil
}
func (s *Service) nameIsValid(c context.Context, mid int64, name, ip string) error {
if len(name) > 30 || utf8.RuneCountInString(name) > 16 {
return ecode.UpdateUnameTooLong
}
if utf8.RuneCountInString(name) < 3 {
return ecode.UpdateUnameTooShort
}
if !model.ValidName(name) {
return ecode.UpdateUnameFormat
}
// 判断昵称是否重复
if err := s.passDao.TestUserName(c, name, mid, ip); err != nil {
return err
}
// 过滤敏感词
res, err := s.filterRPC.Filter(c, &ftModel.ArgFilter{Area: "member", Message: name})
if err != nil {
return err
}
// 大于 20 认为包含敏感词
if res.Level >= 20 {
return ecode.UpdateUnameSensitive
}
return nil
}
func (s *Service) validateTelStatus(status int32) bool {
if s.c.Switch.UpdatePropertyPhoneRequired && status == 0 {
return false
}
return true
}

View File

@@ -0,0 +1,71 @@
package member
import (
"context"
"testing"
"time"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_Account(t *testing.T) {
Convey("get account info", t, func() {
Convey("when not timeout", func() {
time.Sleep(time.Second * 2)
res, err := s.Account(context.TODO(), 1, "127.0.0.1")
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
})
})
}
func TestService_UpdateUname(t *testing.T) {
Convey("update uname", t, func() {
Convey("when not timeout", func() {
time.Sleep(time.Second * 2)
err := s.UpdateName(context.TODO(), 110001353, "127.0.0.1", "127.0.0.1")
So(err, ShouldBeNil)
})
})
}
func TestService_NickFree(t *testing.T) {
Convey("update uname", t, func() {
Convey("when not timeout", func() {
time.Sleep(time.Second * 2)
nick, err := s.NickFree(context.TODO(), 110001353)
So(err, ShouldBeNil)
So(nick, ShouldNotBeEmpty)
})
})
}
func TestService_UpdateSign(t *testing.T) {
Convey("update sign", t, func() {
Convey("when not timeout", func() {
err := s.UpdateSign(context.TODO(), 61, "1989-09-19")
So(err, ShouldBeNil)
})
})
}
func TestService_UpdateSex(t *testing.T) {
Convey("update sex", t, func() {
Convey("when not timeout", func() {
err := s.UpdateSex(context.TODO(), 110001353, 1)
So(err, ShouldBeNil)
})
})
}
func TestService_UpdateBirthday(t *testing.T) {
Convey("update sex", t, func() {
Convey("when not timeout", func() {
err := s.UpdateBirthday(context.TODO(), 61, "1989-09-19")
So(err, ShouldBeNil)
})
})
}

View File

@@ -0,0 +1,76 @@
package member
import (
"context"
"go-common/app/service/main/usersuit/model"
"go-common/library/log"
"go-common/library/net/metadata"
)
// MedalHomeInfo return user mdeal home info.
func (s *Service) MedalHomeInfo(c context.Context, mid int64) (res []*model.MedalHomeInfo, err error) {
var arg = &model.ArgMid{Mid: mid}
res, err = s.usRPC.MedalHomeInfo(c, arg)
if err != nil {
log.Error("s.medalRPC.MedalHomeInfo(%d) error (%v)", mid, err)
return
}
return
}
// MedalUserInfo return medal user info.
func (s *Service) MedalUserInfo(c context.Context, mid int64) (res *model.MedalUserInfo, err error) {
ip := metadata.String(c, metadata.RemoteIP)
var arg = &model.ArgMedalUserInfo{Mid: mid, IP: ip}
res, err = s.usRPC.MedalUserInfo(c, arg)
if err != nil {
log.Error("s.medalRPC.MedalUserInfo(%d) error (%v)", mid, err)
return
}
return
}
// MedalInstall install or uninstall medal.
func (s *Service) MedalInstall(c context.Context, mid, nid int64, isActivated int8) (err error) {
var arg = &model.ArgMedalInstall{Mid: mid, Nid: nid, IsActivated: isActivated}
err = s.usRPC.MedalInstall(c, arg)
if err != nil {
log.Error("s.medalRPC.MedalInstall(mid:%d nid:%d isActivated:%d) error (%v)", mid, nid, isActivated, err)
return
}
return
}
// MedalPopup return medal popup.
func (s *Service) MedalPopup(c context.Context, mid int64) (res *model.MedalPopup, err error) {
var arg = &model.ArgMid{Mid: mid}
res, err = s.usRPC.MedalPopup(c, arg)
if err != nil {
log.Error("s.medalRPC.MedalPopup(mid:%d) error (%v)", mid, err)
return
}
return
}
// MedalMyInfo return medal my info.
func (s *Service) MedalMyInfo(c context.Context, mid int64) (res []*model.MedalMyInfos, err error) {
var arg = &model.ArgMid{Mid: mid}
res, err = s.usRPC.MedalMyInfo(c, arg)
if err != nil {
log.Error("s.medalRPC.MedalMyInfo(mid:%d) error (%v)", mid, err)
return
}
return
}
// MedalAllInfo return medal all info.
func (s *Service) MedalAllInfo(c context.Context, mid int64) (res *model.MedalAllInfos, err error) {
var arg = &model.ArgMid{Mid: mid}
res, err = s.usRPC.MedalAllInfo(c, arg)
if err != nil {
log.Error("s.medalRPC.MedalAllInfo(mid:%d) error (%v)", mid, err)
return
}
return
}

View File

@@ -0,0 +1,267 @@
package member
import (
"context"
"go-common/app/interface/main/account/model"
accmdl "go-common/app/service/main/account/model"
arcmdl "go-common/app/service/main/archive/model/archive"
memmdl "go-common/app/service/main/member/model"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/net/metadata"
)
const (
_maxMonthlyOfficialSubmitTimes = 3
)
// IdentifyInfo get user identify info.
func (s *Service) IdentifyInfo(c context.Context, mid int64, ip string) (res *model.Identification, err error) {
var rid *model.IdentifyInfo
if rid, err = s.accDao.IdentifyInfo(c, mid, ip); err != nil {
log.Error("s.memRPC.IdentifyInfo(%d) err(%+v)", mid, err)
return
}
res = &model.Identification{}
switch rid.Identify {
case model.APIIdentifyOk:
res.Identification = model.IdentifyOK
case model.APIIdentifyNoInfo:
res.Identification = model.IdentifyNotOK
default:
log.Error("unknow mid(%d) identify(%d) status", mid, rid.Identify)
}
return
}
// SubmitOfficial is.
func (s *Service) SubmitOfficial(c context.Context, mid int64, apply *model.OfficialApply) error {
//ip := metadata.String(c, metadata.RemoteIP)
if apply.Role == memmdl.OfficialRoleUp || apply.Role == memmdl.OfficialRoleIdentify {
cons, err := s.OfficialConditions(c, mid)
if err != nil {
return err
}
if !cons.AllPass() {
log.Warn("Unexpected official apply submited: mid: %d conditons: %+v apply: %+v", mid, cons, apply)
return ecode.RequestErr
}
}
// 是否超出本月提交次数限制
times, err := s.accDao.GetMonthlyOfficialSubmittedTimes(c, mid)
if err != nil {
log.Error("Faield to get monthly official submitted times with mid %d: %+v", mid, err)
}
if times >= _maxMonthlyOfficialSubmitTimes {
log.Warn("User %d is exceed max monthly official submitted times")
return ecode.LimitExceed
}
ood, err := s.memRPC.OfficialDoc(c, &memmdl.ArgMid{Mid: mid})
// 是否已经存在审核中的申请
if err == nil && ood != nil && ood.State == memmdl.OfficialStateWait {
return nil
}
if apply.Telephone != "" {
if apply.TelVerifyCode == 0 {
log.Error("Invalid tel verify code: mid: %d code:%d", mid, apply.TelVerifyCode)
return ecode.RequestErr
}
vcode, verr := s.accDao.GetVerifyCode(c, mid, apply.Telephone)
if verr != nil {
log.Error("Failed to get verify code: %d, %s: %+v", mid, apply.Telephone, verr)
return ecode.CaptchaErr
}
if apply.TelVerifyCode != vcode {
log.Error("Failed to verify telephone verification code: %s, %d, %d", apply.Telephone, apply.TelVerifyCode, vcode)
return ecode.CaptchaErr
}
}
arg := &memmdl.ArgOfficialDoc{
Mid: mid,
Name: apply.Name,
Role: apply.Role,
Title: apply.Title,
Desc: apply.Desc,
Operator: apply.Operator,
Telephone: apply.Telephone,
Email: apply.Email,
Address: apply.Address,
Company: apply.Company,
CreditCode: apply.CreditCode,
Organization: apply.Organization,
OrganizationType: apply.OrganizationType,
BusinessLicense: apply.BusinessLicense,
BusinessScale: apply.BusinessScale,
BusinessLevel: apply.BusinessLevel,
BusinessAuth: apply.BusinessAuth,
Supplement: apply.Supplement,
Professional: apply.Professional,
Identification: apply.Identification,
OfficialSite: apply.OfficialSite,
RegisteredCapital: apply.RegisteredCapital,
SubmitSource: "user", // 来自 account-interface 的全部为 user
}
pros, err := s.accRPC.ProfileWithStat3(c, &accmdl.ArgMid{Mid: mid})
if err != nil {
log.Error("Failed to call ProfileWithStat3(%d): %+v", mid, err)
return err
}
arg.Realname = int8(pros.Identification)
if err := s.accDao.DelVerifyCode(c, mid, apply.Telephone); err != nil {
log.Error("Failed to delete verify code: mid: %d: mobile: %s: %+v", mid, apply.Telephone, err)
}
if _, err = s.accDao.IncreaseMonthlyOfficialSubmittedTimes(c, mid); err != nil {
log.Error("Failed to increase monthly official submitted times with mid: %d: %+v", mid, err)
}
return s.memRPC.SetOfficialDoc(c, arg)
}
// OfficialConditions is.
func (s *Service) OfficialConditions(c context.Context, mid int64) (*model.OfficialConditions, error) {
con := new(model.OfficialConditions)
pros, err := s.accRPC.ProfileWithStat3(c, &accmdl.ArgMid{Mid: mid})
if err != nil {
log.Error("Failed to call ProfileWithStat3(%d): %+v", mid, err)
return nil, err
}
if pros.Rank >= 10000 {
con.IsFormal = true
}
// 1 正常号码2 虚拟号码
if pros.TelStatus >= 1 {
con.BindTel = true
}
if pros.Identification == 1 {
con.Realname = true
}
if pros.Follower >= 100000 {
con.FollowerCount = true
}
arcCount, err := s.arcRPC.UpCount2(c, &arcmdl.ArgUpCount2{Mid: mid})
if err != nil {
log.Error("Failed to call s.arcRPC.UpCount2(%d): %+v", mid, err)
// return nil, err
}
if err == nil && arcCount >= 1 {
con.ArchiveCount = true
}
// 累计播放数
// upStat, err := s.upRPC.UpStatBase(c, &upmdl.ArgMidWithDate{Mid: mid})
// if err != nil {
// log.Error("Failed to call s.upRPC.UpStatBase(%d): %+v", mid, err)
// }
// if err == nil && upStat != nil && upStat.View >= 1000000 {
// con.ViewCount = true
// }
return con, nil
}
// UploadImage article upload cover.
func (s *Service) UploadImage(c context.Context, fileType string, body []byte) (url string, err error) {
if len(body) == 0 {
err = ecode.FileNotExists
return
}
if len(body) > s.c.BFS.MaxFileSize {
err = ecode.FileTooLarge
return
}
url, err = s.accDao.UploadImage(c, fileType, body, s.c.BFS)
if err != nil {
log.Error("account-interface: s.bfs.Upload error(%v)", err)
return
}
return
}
// MobileVerify is.
func (s *Service) MobileVerify(c context.Context, mid int64, mobile string, country int64) error {
ip := metadata.String(c, metadata.RemoteIP)
vcode, err := s.accDao.GenVerifyCode(c, mid, mobile)
if err != nil {
log.Error("Failed to generate verify code: %+v", err)
return err
}
return s.accDao.SendMobileVerify(c, vcode, country, mobile, ip)
}
// OfficialDoc is.
func (s *Service) OfficialDoc(c context.Context, mid int64) (*memmdl.OfficialDoc, error) {
ip := metadata.String(c, metadata.RemoteIP)
od, err := s.memRPC.OfficialDoc(c, &memmdl.ArgMid{Mid: mid, RealIP: ip})
if err != nil {
return nil, err
}
return od, nil
}
// MonthlyOfficialSubmittedTimes is
func (s *Service) MonthlyOfficialSubmittedTimes(c context.Context, mid int64) *model.OfficialSubmittedTimes {
result := &model.OfficialSubmittedTimes{
Submitted: 0,
Remain: _maxMonthlyOfficialSubmitTimes,
}
times, err := s.accDao.GetMonthlyOfficialSubmittedTimes(c, mid)
if err != nil {
log.Warn("Failed to get monthly official submitted times with mid: %d: %+v", mid, err)
return result
}
result.Submitted = times
if result.Submitted > _maxMonthlyOfficialSubmitTimes {
result.Submitted = _maxMonthlyOfficialSubmitTimes
}
result.Remain = _maxMonthlyOfficialSubmitTimes - result.Submitted
return result
}
// OfficialAutoFillDoc is
func (s *Service) OfficialAutoFillDoc(ctx context.Context, mid int64) (*memmdl.OfficialDoc, error) {
res := &memmdl.OfficialDoc{
Mid: mid,
}
// default name
info, err := s.accRPC.Info3(ctx, &accmdl.ArgMid{Mid: mid})
if err != nil {
return nil, err
}
res.Name = info.Name
// default from cm api
func() {
cminfo, err := s.accDao.BusinessAccountInfo(ctx, mid)
if err != nil {
log.Error("Failed to get cm business account info with mid: %d: %+v", mid, err)
return
}
if cminfo.Nickname != "" {
res.Name = cminfo.Nickname
}
if cminfo.CertificationTitle != "" {
res.Title = cminfo.CertificationTitle
}
if cminfo.CreditCode != "" {
res.CreditCode = cminfo.CreditCode
}
if cminfo.CompanyName != "" {
res.Company = cminfo.CompanyName
}
if cminfo.Organization != "" {
res.Organization = cminfo.Organization
}
if cminfo.OrganizationType != "" {
res.OrganizationType = cminfo.OrganizationType
}
}()
return res, nil
}

View File

@@ -0,0 +1,54 @@
package member
import (
"context"
"net"
"go-common/app/interface/main/account/model"
secmodel "go-common/app/service/main/secure/model"
"go-common/library/log"
)
// NoticeV2 notice v2.
func (s *Service) NoticeV2(c context.Context, mid int64, uuid string, pf string, b int64) (res *model.Notice2, err error) {
var msg *secmodel.Msg
if msg, err = s.secureRPC.Status(c, &secmodel.ArgSecure{Mid: mid, UUID: uuid}); err != nil {
log.Error("service.secureRPC.Status(%d) uuid(%s) error(%v)", mid, uuid, err)
return
}
if msg == nil || !msg.Notify {
log.Info("s.NoticeV2(%d) msg(%v) continue", mid, msg)
res = &model.Notice2{Status: model.NoticeStatusNotNotify}
return
}
res = &model.Notice2{
Status: model.NoticeStatusNotify,
Type: model.NoticeTypeSecurity,
Security: &model.Security{
Location: msg.Log.Location,
Time: msg.Log.Time,
IP: inetNtoA(msg.Log.IP),
Mid: msg.Log.Mid,
}}
return
}
func inetNtoA(sum uint32) string {
ip := make(net.IP, net.IPv4len)
ip[0] = byte((sum >> 24) & 0xFF)
ip[1] = byte((sum >> 16) & 0xFF)
ip[2] = byte((sum >> 8) & 0xFF)
ip[3] = byte(sum & 0xFF)
return ip.String()
}
// CloseNoticeV2 close notice v2.
func (s *Service) CloseNoticeV2(c context.Context, mid int64, uuid string) (err error) {
arg := &secmodel.ArgSecure{Mid: mid, UUID: uuid}
if err = s.secureRPC.CloseNotify(c, arg); err != nil {
log.Error("service.secureRPC.CloseNotify(%v) error(%v)", arg, err)
return
}
return
}

View File

@@ -0,0 +1,38 @@
package member
import (
"context"
"testing"
"time"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_NoticeV2(t *testing.T) {
Convey("TestService_NoticeV2", func() {
time.Sleep(time.Second * 2)
var (
mid = int64(1)
u = "foo"
//ip = "127.0.0.1"
pf = "ios"
build int64 = 123
)
res, err := s.NoticeV2(context.TODO(), mid, u, pf, build)
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
})
}
func TestService_CloseNoticeV2(t *testing.T) {
Convey("TestService_CloseNoticeV2", func() {
time.Sleep(time.Second * 2)
var (
mid = int64(1)
u = "foo"
//ip = "127.0.0.1"
)
err := s.CloseNoticeV2(context.TODO(), mid, u)
So(err, ShouldBeNil)
})
}

View File

@@ -0,0 +1,18 @@
package member
import (
"context"
secmodel "go-common/app/service/main/secure/model"
"go-common/library/log"
)
// Status query user's remote login status.
func (s *Service) Status(c context.Context, mid int64, uuid string) (res *secmodel.Msg, err error) {
arg := &secmodel.ArgSecure{Mid: mid, UUID: uuid}
if res, err = s.secureRPC.Status(c, arg); err != nil {
log.Error("s.secureRPC.Status(mid:%d) error (%v)", mid, err)
return
}
return
}

View File

@@ -0,0 +1,25 @@
package member
import (
"context"
"testing"
secmodel "go-common/app/service/main/secure/model"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_Status(t *testing.T) {
var (
err error
c = context.TODO()
res *secmodel.Msg
)
Convey("TestService_Status", func() {
res, err = s.Status(c, 1, "xxxxx")
if err != nil {
t.Errorf("s.Status err(%v)", err)
}
t.Logf("s.Status result (%v)", res)
})
}

View File

@@ -0,0 +1,145 @@
package member
import (
"context"
"fmt"
"go-common/app/interface/main/account/model"
artMdl "go-common/app/interface/openplatform/article/model"
"go-common/app/service/main/archive/api"
arcMdl "go-common/app/service/main/archive/model/archive"
"go-common/library/log"
"go-common/library/net/metadata"
)
var (
_typeToURL = map[int64]string{
1: "https://www.bilibili.com/video/av%d/", // 稿件
2: "https://www.bilibili.com/topic/%d.html", // 话题
3: "https://h.bilibili.com/dy%d", // 画站
5: "https://vc.bilibili.com/video/%d", // 直播小视频
6: "https://www.bilibili.com/blackroom/ban/%d", // 封禁信息
7: "https://www.bilibili.com/blackroom/notice/%d", // 公告信息
10: "https://link.bilibili.com/p/eden/news#/newsdetail?id=%d", // 直播公告
11: "https://h.bilibili.com/%d", // 直播有文画
12: "https://www.bilibili.com/read/cv%d", // 专栏
13: "https://show.bilibili.com/platform/detail.html?id=%d", // 票务
15: "https://www.bilibili.com/judgement/case/%d", // 风纪委
}
)
// ReplyHistoryList reply history list
func (s *Service) ReplyHistoryList(c context.Context, mid int64, stime, etime, order, sort string, pn, ps int64, accessKey, cookie string) (rhl *model.ReplyHistory, err error) {
ip := metadata.String(c, metadata.RemoteIP)
if rhl, err = s.replyDao.ReplyHistoryList(c, mid, stime, etime, order, sort, pn, ps, accessKey, cookie, ip); err != nil {
log.Error("s.replyDao.ReplyHistoryList error(%v)", err)
return
}
idsMap := make(map[int64][]int64) // type -> ids
unique := make(map[int64]struct{})
for _, v := range rhl.Records {
if _, ok := unique[v.Oid]; !ok {
idsMap[v.Type] = append(idsMap[v.Type], v.Oid)
unique[v.Oid] = struct{}{}
}
}
rhlt, _ := s.fetchData(c, mid, idsMap, accessKey, cookie, ip)
for _, v := range rhl.Records {
if t, ok := rhlt[v.Type]; ok {
for _, b := range t {
if o, ok := b[v.Oid]; ok {
v.Title = o.Title
v.URL = o.URL
}
}
}
}
return
}
// fetchData
func (s *Service) fetchData(c context.Context, mid int64, idsMap map[int64][]int64, accessKey, cookie, ip string) (rhlt map[int64][]map[int64]*model.RecordAppend, err error) {
rhlt = make(map[int64][]map[int64]*model.RecordAppend) // type -> oid -> title/url
for t, v := range idsMap {
switch t {
case 1:
// 稿件
if len(v) > 0 {
var arcs map[int64]*api.Arc
arcArg := &arcMdl.ArgAids2{Aids: v, RealIP: ip}
if arcs, err = s.arcRPC.Archives3(c, arcArg); err != nil {
log.Error("s.arcRPC.Archives3 error(%v)", err)
return
}
for _, vv := range v {
if arc, ok := arcs[vv]; ok {
itu := &model.RecordAppend{
Title: arc.Title,
}
if arc.RedirectURL != "" {
itu.URL = arc.RedirectURL
} else {
itu.URL = fmt.Sprintf(_typeToURL[t], arc.Aid)
}
vitu := make(map[int64]*model.RecordAppend)
vitu[vv] = itu
rhlt[t] = append(rhlt[t], vitu)
}
}
}
case 4:
// 活动
if len(v) > 0 {
var aps map[int64]*model.RecordAppend
if aps, err = s.replyDao.ActivityPages(c, mid, v, accessKey, cookie, ip); err != nil {
log.Error("s.replyDao.ActivityPages error(%v)", err)
return
}
for _, vv := range v {
if ap, ok := aps[vv]; ok {
vitu := make(map[int64]*model.RecordAppend)
vitu[vv] = ap
rhlt[t] = append(rhlt[t], vitu)
}
}
}
case 12:
// 专栏
if len(v) > 0 {
var arts map[int64]*artMdl.Meta
artArg := &artMdl.ArgAids{Aids: v}
if arts, err = s.artRPC.ArticleMetas(c, artArg); err != nil {
log.Error("s.artRPC.ArticleMetas error(%v)", err)
return
}
for _, vv := range v {
if ap, ok := arts[vv]; ok {
itu := &model.RecordAppend{
Title: ap.Title,
URL: fmt.Sprintf(_typeToURL[t], ap.ID),
}
vitu := make(map[int64]*model.RecordAppend)
vitu[vv] = itu
rhlt[t] = append(rhlt[t], vitu)
}
}
}
default:
if len(v) > 0 {
for _, vv := range v {
itu := &model.RecordAppend{
Title: "",
URL: "",
}
if _, ok := _typeToURL[t]; ok {
itu.URL = fmt.Sprintf(_typeToURL[t], vv)
}
vitu := make(map[int64]*model.RecordAppend)
vitu[vv] = itu
rhlt[t] = append(rhlt[t], vitu)
}
}
}
}
return
}

View File

@@ -0,0 +1,36 @@
package member
import (
"context"
"testing"
"go-common/app/interface/main/account/model"
"github.com/smartystreets/goconvey/convey"
)
func TestService_ReplyHistoryList(t *testing.T) {
convey.Convey("ReplyHistoryList", t, func() {
var (
err error
//ip = ""
mid int64 = 88889069
stime = "1500805318"
etime = "1511237870"
order = "like"
sort = "desc"
pn int64 = 1
ps int64 = 100
accessKey = ""
cookie = ""
rhl *model.ReplyHistory
)
if rhl, err = s.ReplyHistoryList(context.TODO(), mid, stime, etime, order, sort, pn, ps, accessKey, cookie); err != nil {
convey.So(err, convey.ShouldBeNil)
t.Logf("err: %v", err)
}
for _, v := range rhl.Records {
t.Logf("title:%s, url:%s, id:%d, type: %d", v.Title, v.URL, v.ID, v.Type)
}
})
}

View File

@@ -0,0 +1,90 @@
package member
import (
"context"
"net"
"go-common/app/interface/main/account/conf"
"go-common/app/interface/main/account/dao/account"
"go-common/app/interface/main/account/dao/passport"
"go-common/app/interface/main/account/dao/reply"
artRPC "go-common/app/interface/openplatform/article/rpc/client"
accrpc "go-common/app/service/main/account/rpc/client"
arcRPC "go-common/app/service/main/archive/api/gorpc"
coinrpc "go-common/app/service/main/coin/api/gorpc"
filterrpc "go-common/app/service/main/filter/rpc/client"
locrpc "go-common/app/service/main/location/rpc/client"
memrpc "go-common/app/service/main/member/api/gorpc"
passRPC "go-common/app/service/main/passport/rpc/client"
securerpc "go-common/app/service/main/secure/rpc/client"
upRPC "go-common/app/service/main/up/api/gorpc"
usrpc "go-common/app/service/main/usersuit/rpc/client"
"go-common/library/queue/databus"
"github.com/pkg/errors"
)
// Service struct of service.
type Service struct {
// conf
c *conf.Config
accRPC *accrpc.Service3
memRPC *memrpc.Service
usRPC *usrpc.Service2
arcRPC *arcRPC.Service2
upRPC *upRPC.Service
artRPC *artRPC.Service
passRPC *passRPC.Client2
coinRPC *coinrpc.Service
locRPC *locrpc.Service
secureRPC *securerpc.Service
filterRPC *filterrpc.Service
accDao *account.Dao
replyDao *reply.Dao
passDao *passport.Dao
nickFreeAppKeys map[string]string
accountNotify *databus.Databus
removeLoginLogCIDR []*net.IPNet
}
// New create service instance and return.
func New(c *conf.Config) (s *Service) {
s = &Service{
c: c,
memRPC: memrpc.New(c.RPCClient2.Member),
accRPC: accrpc.New3(c.RPCClient2.Account),
usRPC: usrpc.New(c.RPCClient2.Usersuit),
arcRPC: arcRPC.New2(c.RPCClient2.Archive),
upRPC: upRPC.New(c.RPCClient2.UP),
artRPC: artRPC.New(c.RPCClient2.Article),
passRPC: passRPC.New(c.RPCClient2.PassPort),
coinRPC: coinrpc.New(c.RPCClient2.Coin),
locRPC: locrpc.New(c.RPCClient2.Location),
secureRPC: securerpc.New(c.RPCClient2.Secure),
filterRPC: filterrpc.New(c.RPCClient2.Filter),
accDao: account.New(c),
passDao: passport.New(c),
replyDao: reply.New(c),
nickFreeAppKeys: c.NickFreeAppKeys,
accountNotify: databus.New(c.AccountNotify),
}
cidrs := make([]*net.IPNet, 0, len(c.Account.RemoveLoginLogCIDR))
for _, raw := range c.Account.RemoveLoginLogCIDR {
_, inet, err := net.ParseCIDR(raw)
if err != nil {
panic(errors.Wrapf(err, "Invalid CIDR: %s", raw))
}
cidrs = append(cidrs, inet)
}
s.removeLoginLogCIDR = cidrs
return
}
// Ping check server ok.
func (s *Service) Ping(c context.Context) (err error) {
return
}
// Close dao.
func (s *Service) Close() {}

View File

@@ -0,0 +1,19 @@
package member
import (
"flag"
"go-common/app/interface/main/account/conf"
)
var (
s *Service
)
func init() {
flag.Set("conf", "../../cmd/account-interface-example.toml")
if err := conf.Init(); err != nil {
panic(err)
}
s = New(conf.Conf)
}

View File

@@ -0,0 +1,29 @@
package member
import (
"context"
"fmt"
)
func notifyKey(mid int64) string {
return fmt.Sprintf("AccountInterface-AccountNotify-T%d", mid)
}
// NotifyInfo notify info.
type NotifyInfo struct {
Uname string `json:"uname"`
Mid int64 `json:"mid"`
Type string `json:"type"`
NewName string `json:"newName"`
Action string `json:"action"`
}
// NotityPurgeCache is
func (s *Service) NotityPurgeCache(ctx context.Context, mid int64, action string) error {
msg := &NotifyInfo{
Mid: mid,
Action: action,
}
key := notifyKey(mid)
return s.accountNotify.Send(ctx, key, msg)
}

View File

@@ -0,0 +1,333 @@
package member
import (
"context"
"fmt"
"net"
"strconv"
"strings"
"go-common/app/interface/main/account/model"
cmodel "go-common/app/service/main/coin/model"
lmodel "go-common/app/service/main/location/model"
mmodel "go-common/app/service/main/member/model"
pmodel "go-common/app/service/main/passport/model"
smodel "go-common/app/service/main/secure/model"
"go-common/library/log"
"go-common/library/net/metadata"
"go-common/library/time"
)
// UpdateSettings Update Settings
func (s *Service) UpdateSettings(c context.Context, mid int64, settings *model.Settings) (err error) {
var (
mb *mmodel.Member
ip = metadata.String(c, metadata.RemoteIP)
)
if mb, err = s.memRPC.Member(c, &mmodel.ArgMemberMid{Mid: mid, RemoteIP: ip}); err != nil {
log.Error("s.Member(%d) error(%v)", mid, err)
return
}
if settings.Sex != sexName(mb.Sex) {
if err = s.accDao.UpdateSex(c, mid, sexID(settings.Sex), ip); err != nil {
return
}
}
if settings.Uname != mb.Name {
if err = s.updateName(c, mid, settings.Uname, ip); err != nil {
return
}
}
if settings.Sign != mb.Sign {
if err = s.UpdateSign(c, mid, settings.Sign); err != nil {
return
}
}
if settings.Birthday != mb.Birthday.Time().Format("2006-01-02") {
if err = s.accDao.UpdateBirthday(c, mid, ip, settings.Birthday); err != nil {
return
}
}
return
}
// SettingsInfo Settings Info
func (s *Service) SettingsInfo(c context.Context, mid int64) (user *model.User, err error) {
var (
mb *mmodel.Member
nickFree *model.NickFree
userID string
ip = metadata.String(c, metadata.RemoteIP)
)
user = &model.User{}
if mb, err = s.memRPC.Member(c, &mmodel.ArgMemberMid{Mid: mid, RemoteIP: ip}); err != nil {
log.Error("s.Member(%d) error(%v)", mid, err)
return
}
if nickFree, err = s.NickFree(c, mid); err != nil {
return
}
if userID, err = s.passDao.UserID(c, mid, ip); err != nil {
return
}
user.Userid = userID
user.Mid = mb.Mid
user.Uname = mb.Name
user.Birthday = mb.Birthday.Time().Format("2006-01-02")
user.NickFree = nickFree.NickFree
user.Sign = mb.Sign
user.Sex = sexName(mb.Sex)
// 尝试清理一次缓存减少用户反馈
s.NotityPurgeCache(c, mid, "updateUname")
return
}
// LogCoin Log Money
func (s *Service) LogCoin(c context.Context, mid int64) (logCoin *model.LogCoins, err error) {
var (
logs []*cmodel.Log
)
if logs, err = s.coinRPC.UserLog(c, &cmodel.ArgLog{Mid: mid, Recent: true, Translate: true}); err != nil {
return
}
logCoin = &model.LogCoins{}
logCoin.Count = len(logs)
logCoin.List = make([]*model.LogCoin, 0)
for _, l := range logs {
s := fmt.Sprintf("%0.1f", l.To-l.From)
delta, _ := strconv.ParseFloat(s, 64)
model := &model.LogCoin{Time: time.Time(l.TimeStamp).Time().Format("2006-01-02 15:04:05"), Reason: l.Desc, Delta: delta}
logCoin.List = append(logCoin.List, model)
}
return
}
// Coin coin.
func (s *Service) Coin(c context.Context, mid int64) (logCoin *model.Coin, err error) {
var (
coin float64
)
if coin, err = s.coinRPC.UserCoins(c, &cmodel.ArgCoinInfo{Mid: mid}); err != nil {
return
}
logCoin = &model.Coin{Money: coin}
return
}
// LogMoral Log Moral
func (s *Service) LogMoral(c context.Context, mid int64) (logMorals *model.LogMorals, err error) {
var (
logs []*mmodel.UserLog
moral *mmodel.Moral
toMoral, fromMoral, origin int64
)
if logs, err = s.memRPC.MoralLog(c, &mmodel.ArgMemberMid{Mid: mid}); err != nil {
log.Error("s.memRPC.MoralLog(%v) error(%v)", mid, err)
return
}
if moral, err = s.memRPC.Moral(c, &mmodel.ArgMemberMid{Mid: mid}); err != nil {
log.Error("s.memRPC.Moral(%v) error(%v)", mid, err)
return
}
logMorals = &model.LogMorals{Count: len(logs), Moral: moral.Moral / 100}
logMorals.List = make([]*model.LogMoral, 0)
for _, l := range logs {
ml := &model.LogMoral{}
ml.Reason = l.Content["reason"]
if origin, err = strconv.ParseInt(l.Content["origin"], 10, 64); err != nil {
log.Error("strconv.ParseInt(%v) error(%v)", l.Content["origin"], err)
continue
}
ml.Origin = model.Origin[origin]
ml.Time = time.Time(l.TS).Time().Format("2006-01-02 15:04:05")
if toMoral, err = strconv.ParseInt(l.Content["to_moral"], 10, 64); err != nil {
log.Error("strconv.ParseInt(%v) error(%v)", l.Content["to_moral"], err)
continue
}
if fromMoral, err = strconv.ParseInt(l.Content["from_moral"], 10, 64); err != nil {
log.Error("strconv.ParseInt(%v) error(%v)", l.Content["from_moral"], err)
continue
}
delta := float64(toMoral-fromMoral) / float64(100)
if ml.Delta, err = strconv.ParseFloat(fmt.Sprintf("%0.2f", delta), 64); err != nil {
log.Error("strconv.ParseFloat(%v) error(%v)", delta, err)
continue
}
logMorals.List = append(logMorals.List, ml)
}
return
}
// LogExp Log Exp
func (s *Service) LogExp(c context.Context, mid int64) (logExp *model.LogExps, err error) {
var (
logs []*mmodel.UserLog
toExp, fromExp float64
ip = metadata.String(c, metadata.RemoteIP)
)
logExp = &model.LogExps{}
if logs, err = s.memRPC.Log(c, &mmodel.ArgMid2{Mid: mid, RealIP: ip}); err != nil {
log.Error("s.memRPC.Log(%v) error(%v)", mid, err)
return
}
logExp.Count = len(logs)
logExp.List = make([]*model.LogExp, 0)
for _, l := range logs {
expLog := &model.LogExp{}
expLog.Time = time.Time(l.TS).Time().Format("2006-01-02 15:04:05")
expLog.Reason = l.Content["reason"]
if toExp, err = strconv.ParseFloat(l.Content["to_exp"], 10); err != nil {
log.Error("strconv.ParseFloat(%v) error(%v)", l.Content["to_exp"], err)
continue
}
if fromExp, err = strconv.ParseFloat(l.Content["from_exp"], 10); err != nil {
log.Error("strconv.ParseFloat(%v) error(%v)", l.Content["from_exp"], err)
continue
}
expLog.Delta = toExp - fromExp
logExp.List = append(logExp.List, expLog)
}
return
}
// LogLogin logLogin
func (s *Service) LogLogin(c context.Context, mid int64) (logLogins *model.LogLogins, err error) {
var (
logs []*pmodel.LoginLog
ips []string
locations map[string]*lmodel.Info
excLogs []*smodel.Expection
)
logLogins = &model.LogLogins{}
if logs, err = s.passRPC.LoginLogs(c, &pmodel.ArgLoginLogs{Mid: mid, Limit: 30}); err != nil {
log.Error("s.passRPC.LoginLogs(%v) error(%v)", mid, err)
return
}
if excLogs, err = s.secureRPC.ExpectionLoc(c, &smodel.ArgSecure{Mid: mid}); err != nil {
log.Error("s.secureRPC.ExpectionLoc(%v) error(%v)", mid, err)
return
}
logLogins.Count = len(logs)
logLogins.List = make([]*model.LogLogin, 0)
beRemoved := func(sip string) bool {
ip := net.ParseIP(sip)
for _, cidr := range s.removeLoginLogCIDR {
if cidr.Contains(ip) {
return true
}
}
lip, ierr := s.locRPC.Info(c, &lmodel.ArgIP{IP: sip})
if ierr != nil || lip == nil {
log.Error("Failed to get ip info with ip: %s: %+v", sip, ierr)
return false
}
// 过滤局域网登录
if lip.Country == "局域网" {
return true
}
return false
}
for _, l := range logs {
sip := string(int64ToIP(l.LoginIP).String())
if beRemoved(sip) {
continue
}
nl := &model.LogLogin{}
nl.Status = true
nl.Time = l.Timestamp
nl.TimeAt = time.Time(l.Timestamp).Time().Format("2006-01-02 15:04:05")
if len(excLogs) != 0 {
for _, e := range excLogs {
if int64(e.IP) == l.LoginIP && time.Time(l.Timestamp) == e.Time {
nl.Status = false
nl.Type = int64(e.FeedBack)
}
}
}
nl.IP = sip
ips = append(ips, nl.IP)
logLogins.List = append(logLogins.List, nl)
}
if locations, err = s.locRPC.Infos(c, ips); err != nil {
log.Error("s.locRPC.Infos(%v) error(%v)", ips, err)
return
}
for _, log := range logLogins.List {
if addr, ok := locations[log.IP]; ok {
log.Geo = addr.Country + addr.Province + addr.City + addr.ISP
}
log.IP = vagueIP(log.IP)
}
return
}
// Reward exp reward.
func (s *Service) Reward(c context.Context, mid int64) (reward *model.Reward, err error) {
var (
expStat *mmodel.ExpStat
todayExp int64
ip = metadata.String(c, metadata.RemoteIP)
)
if expStat, err = s.memRPC.Stat(c, &mmodel.ArgMid2{Mid: mid, RealIP: ip}); err != nil {
log.Error("s.s.memRPC.Stat(%d) error(%v)", mid, err)
return
}
if todayExp, err = s.coinRPC.TodayExp(c, &cmodel.ArgMid{Mid: mid, RealIP: ip}); err != nil {
log.Error("s.coinRPC.TodayExp(%d) error(%v)", mid, err)
return
}
if todayExp > 50 {
todayExp = 50
}
reward = &model.Reward{}
reward.Login = expStat.Login
reward.Share = expStat.Share
reward.Watch = expStat.Watch
reward.Coin = todayExp
return
}
func sexID(sex string) int64 {
switch sex {
case "男":
return 1
case "女":
return 2
default:
return 0
}
}
func sexName(sex int64) string {
switch sex {
case 1:
return "男"
case 2:
return "女"
default:
return "保密"
}
}
func vagueIP(ip string) string {
strs := strings.Split(ip, ".")
if len(strs) != 4 {
log.Error("error ip (%v)", ip)
return ""
}
strs[2] = "*"
strs[3] = "*"
return strs[0] + "." + strs[1] + "." + strs[2] + "." + strs[3]
}
func int64ToIP(ipnr int64) net.IP {
var bytes [4]byte
bytes[0] = byte(ipnr & 0xFF)
bytes[1] = byte((ipnr >> 8) & 0xFF)
bytes[2] = byte((ipnr >> 16) & 0xFF)
bytes[3] = byte((ipnr >> 24) & 0xFF)
return net.IPv4(bytes[3], bytes[2], bytes[1], bytes[0])
}

View File

@@ -0,0 +1,96 @@
package member
import (
"context"
. "github.com/smartystreets/goconvey/convey"
"go-common/app/interface/main/account/model"
"testing"
"time"
)
func TestService_SettingsInfo(t *testing.T) {
Convey("get settingsInfo info", t, func() {
Convey("when not timeout", func() {
time.Sleep(time.Second * 2)
res, err := s.SettingsInfo(context.TODO(), 110001260)
So(err, ShouldBeNil)
So(res, ShouldNotBeEmpty)
})
})
}
func TestService_LogLogin(t *testing.T) {
Convey("get settingsInfo info", t, func() {
Convey("when not timeout", func() {
time.Sleep(time.Second * 2)
res, err := s.LogLogin(context.TODO(), 110001260)
So(err, ShouldBeNil)
So(res, ShouldNotBeEmpty)
})
})
}
func TestService_LogCoin(t *testing.T) {
Convey("get settingsInfo info", t, func() {
Convey("when not timeout", func() {
time.Sleep(time.Second * 2)
res, err := s.LogCoin(context.TODO(), 1)
So(err, ShouldBeNil)
So(res, ShouldNotBeEmpty)
})
})
}
func TestService_LogExp(t *testing.T) {
Convey("get settingsInfo info", t, func() {
Convey("when not timeout", func() {
time.Sleep(time.Second * 2)
res, err := s.LogExp(context.TODO(), 110001260)
So(err, ShouldBeNil)
So(res, ShouldNotBeEmpty)
})
})
}
func TestService_LogMoral(t *testing.T) {
Convey("get settingsInfo info", t, func() {
Convey("when not timeout", func() {
time.Sleep(time.Second * 2)
res, err := s.LogMoral(context.TODO(), 110001260)
So(err, ShouldBeNil)
So(res, ShouldNotBeEmpty)
})
})
}
func TestService_Coin(t *testing.T) {
Convey("get settingsInfo info", t, func() {
Convey("when not timeout", func() {
time.Sleep(time.Second * 2)
res, err := s.Coin(context.TODO(), 1)
So(err, ShouldBeNil)
So(res, ShouldNotBeEmpty)
})
})
}
func TestService_UpdateSettings(t *testing.T) {
Convey("get settingsInfo info", t, func() {
Convey("when not timeout", func() {
time.Sleep(time.Second * 2)
err := s.UpdateSettings(context.TODO(), 110000092, &model.Settings{Uname: "test", Sex: "男"})
So(err, ShouldBeNil)
})
})
}
func TestService_Reward(t *testing.T) {
Convey("reward info", t, func() {
Convey("when not timeout", func() {
time.Sleep(time.Second * 2)
res, err := s.Reward(context.TODO(), 2)
So(err, ShouldBeNil)
So(res, ShouldNotBeEmpty)
})
})
}

View File

@@ -0,0 +1,45 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = ["passport.go"],
importpath = "go-common/app/interface/main/account/service/passport",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/account/conf:go_default_library",
"//app/interface/main/account/dao/passport:go_default_library",
"//library/net/metadata: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"],
)
go_test(
name = "go_default_test",
srcs = ["passport_test.go"],
embed = [":go_default_library"],
tags = ["automanaged"],
deps = [
"//app/interface/main/account/conf:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)

View File

@@ -0,0 +1,33 @@
package passport
import (
"context"
"go-common/app/interface/main/account/conf"
"go-common/app/interface/main/account/dao/passport"
"go-common/library/net/metadata"
)
// Service struct of service.
type Service struct {
// conf
c *conf.Config
passDao *passport.Dao
}
// New create service instance and return.
func New(c *conf.Config) (s *Service) {
s = &Service{
c: c,
passDao: passport.New(c),
}
return
}
// TestUserName is.
func (s *Service) TestUserName(ctx context.Context, name string, mid int64) error {
ip := metadata.String(ctx, metadata.RemoteIP)
return s.passDao.TestUserName(ctx, name, mid, ip)
}

View File

@@ -0,0 +1,30 @@
package passport
import (
"context"
"flag"
"testing"
"go-common/app/interface/main/account/conf"
. "github.com/smartystreets/goconvey/convey"
)
var (
s *Service
)
func init() {
flag.Set("conf", "../../cmd/account-interface-example.toml")
if err := conf.Init(); err != nil {
panic(err)
}
s = New(conf.Conf)
}
func Test_TestUserName(t *testing.T) {
Convey("TestUserName", func() {
err := s.TestUserName(context.TODO(), "testname", 1)
So(err, ShouldBeNil)
})
}

View File

@@ -0,0 +1,47 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = ["point.go"],
importpath = "go-common/app/interface/main/account/service/point",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/account/conf:go_default_library",
"//app/service/main/point/model:go_default_library",
"//app/service/main/point/rpc/client: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"],
)
go_test(
name = "go_default_test",
srcs = ["point_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/account/conf:go_default_library",
"//app/service/main/point/model:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)

View File

@@ -0,0 +1,38 @@
package point
import (
"context"
"go-common/app/interface/main/account/conf"
"go-common/app/service/main/point/model"
pointrpc "go-common/app/service/main/point/rpc/client"
)
// Service struct of service.
type Service struct {
// conf
c *conf.Config
// rpc
pointRPC *pointrpc.Service
}
// New create service instance and return.
func New(c *conf.Config) (s *Service) {
s = &Service{
c: c,
pointRPC: pointrpc.New(c.RPCClient2.Point),
}
return
}
// PointInfo point info.
func (s *Service) PointInfo(c context.Context, mid int64) (res *model.PointInfo, err error) {
res, err = s.pointRPC.PointInfo(c, &model.ArgRPCMid{Mid: mid})
return
}
// PointPage point page.
func (s *Service) PointPage(c context.Context, a *model.ArgRPCPointHistory) (res *model.PointHistoryResp, err error) {
res, err = s.pointRPC.PointHistory(c, a)
return
}

View File

@@ -0,0 +1,43 @@
package point
import (
"context"
"flag"
"testing"
"go-common/app/interface/main/account/conf"
"go-common/app/service/main/point/model"
. "github.com/smartystreets/goconvey/convey"
)
var (
s *Service
)
func init() {
flag.Set("conf", "../../cmd/account-interface-example.toml")
var err error
if err = conf.Init(); err != nil {
panic(err)
}
s = New(conf.Conf)
}
// go test -test.v -test.run TestServicePointInfo
func TestServicePointInfo(t *testing.T) {
Convey("TestServicePointInfo", t, func() {
res, err := s.PointInfo(context.TODO(), 110000262)
t.Logf("info: %v", res)
So(err, ShouldBeNil)
})
}
// go test -test.v -test.run TestServicePointPage
func TestServicePointPage(t *testing.T) {
Convey("TestServicePointPage", t, func() {
res, err := s.PointPage(context.TODO(), &model.ArgRPCPointHistory{Mid: 2089809, PN: 1, PS: 10})
t.Logf("res: %v", res)
So(err, ShouldBeNil)
})
}

View File

@@ -0,0 +1,63 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = ["realname_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/account/conf:go_default_library",
"//app/interface/main/account/model:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"alipay.go",
"antispam.go",
"data.go",
"geetest.go",
"realname.go",
"upload.go",
],
importpath = "go-common/app/interface/main/account/service/realname",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/account/conf:go_default_library",
"//app/interface/main/account/dao/realname:go_default_library",
"//app/interface/main/account/model:go_default_library",
"//app/interface/main/account/service/realname/crypto:go_default_library",
"//app/service/main/member/api/gorpc:go_default_library",
"//app/service/main/member/model:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [
":package-srcs",
"//app/interface/main/account/service/realname/crypto:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,219 @@
package realname
import (
"context"
"encoding/json"
"fmt"
"math/rand"
"net/url"
"regexp"
"time"
"go-common/app/interface/main/account/conf"
"go-common/app/interface/main/account/model"
memmodel "go-common/app/service/main/member/model"
"go-common/library/ecode"
"go-common/library/log"
"github.com/pkg/errors"
)
var (
_idCard18Regexp = regexp.MustCompile(`^\d{17}[\d|x]$`)
_idCard15Regexp = regexp.MustCompile(`^\d{15}$`)
)
// AlipayApply 提交芝麻认证申请
func (s *Service) AlipayApply(c context.Context, mid int64, param *model.ParamRealnameAlipayApply) (res *model.RealnameAlipayApply, err error) {
if !s.alipayAntispamCheck(c, mid) {
err = ecode.RealnameAlipayAntispam
return
}
if !s.checkID(param.CardNum) {
err = ecode.RealnameCardNumErr
return
}
var bizno string
if bizno, err = s.alipayInit(c, param.Realname, param.CardNum); err != nil {
return
}
res = &model.RealnameAlipayApply{}
if res.URL, err = s.alipayCertifyURL(c, bizno); err != nil {
return
}
var (
arg = &memmodel.ArgRealnameAlipayApply{
MID: mid,
CaptureCode: param.Capture,
Realname: param.Realname,
CardCode: param.CardNum,
IMGToken: param.ImgToken,
Bizno: bizno,
}
)
if err = s.memRPC.RealnameAlipayApply(c, arg); err != nil {
res = nil
return
}
s.addmiss(func() {
if missErr := s.alipayAntispamIncrease(context.Background(), mid); missErr != nil {
log.Error("%+v", err)
}
})
return
}
func (s *Service) checkID(card string) bool {
if !_idCard15Regexp.MatchString(card) && !_idCard18Regexp.MatchString(card) {
return false
}
return true
}
func (s *Service) alipayInit(c context.Context, realname, cardNum string) (bizno string, err error) {
var (
biz struct {
TransID string `json:"transaction_id"`
ProdCode string `json:"product_code"`
BizCode string `json:"biz_code"`
IdenParam struct {
IdentityType string `json:"identity_type"`
CertType string `json:"cert_type"`
CertName string `json:"cert_name"`
CertNo string `json:"cert_no"`
} `json:"identity_param"`
}
param url.Values
)
biz.TransID = s.alipayTransactionID() // 商户请求的唯一标志32位长度的字母数字下划线组合。该标识作为对账的关键信息商户要保证其唯一性.
biz.ProdCode = "w1010100000000002978" // 芝麻认证产品码
biz.BizCode = "FACE" // 认证场景码,支持的场景码有: FACE多因子活体人脸认证 SMART_FACE多因子快捷活体人脸认证 FACE_SDKSDK活体人脸认证 签约的协议决定了可以使用的场景
biz.IdenParam.IdentityType = "CERT_INFO"
biz.IdenParam.CertType = "IDENTITY_CARD"
biz.IdenParam.CertName = realname
biz.IdenParam.CertNo = cardNum
if param, err = s.alipayParam("zhima.customer.certification.initialize", biz, ""); err != nil {
return
}
if bizno, err = s.realnameDao.AlipayInit(c, param); err != nil {
log.Error("%+v", err)
err = ecode.RealnameAlipayErr
return
}
if bizno == "" {
err = ecode.RealnameAlipayErr
return
}
return
}
func (s *Service) alipayCertifyURL(c context.Context, bizno string) (u string, err error) {
var (
param url.Values
biz struct {
Bizno string `json:"biz_no"`
}
)
biz.Bizno = bizno
if param, err = s.alipayParam("zhima.customer.certification.certify", biz, "bilibili://auth.zhima"); err != nil {
return
}
u = conf.Conf.Realname.Alipay.Gateway + "?" + param.Encode()
return
}
// AlipayConfirm 查询芝麻认证状态
func (s *Service) AlipayConfirm(c context.Context, mid int64) (res *model.RealnameAlipayConfirm, err error) {
var (
pass bool
reason string
rpcarg = &memmodel.ArgMemberMid{
Mid: mid,
}
rpcres *memmodel.RealnameAlipayInfo
)
if rpcres, err = s.memRPC.RealnameAlipayBizno(c, rpcarg); err != nil {
return
}
if pass, reason, err = s.alipayQuery(c, rpcres.Bizno); err != nil {
log.Error("%+v", err)
err = ecode.RealnameAlipayErr
return
}
res = &model.RealnameAlipayConfirm{
Reason: reason,
}
if pass {
res.Passed = model.RealnameTrue
} else {
res.Passed = model.RealnameFalse
}
// rpc call
var (
rpcConfirmArg = &memmodel.ArgRealnameAlipayConfirm{
MID: mid,
Pass: pass,
Reason: reason,
}
)
if err = s.memRPC.RealnameAlipayConfirm(c, rpcConfirmArg); err != nil {
return
}
s.addmiss(func() {
if missErr := s.setAlipayAntispamPassFlag(context.Background(), mid, false); missErr != nil {
log.Error("%+v", err)
}
})
return
}
func (s *Service) alipayQuery(c context.Context, bizno string) (pass bool, reason string, err error) {
var (
param url.Values
biz struct {
Bizno string `json:"biz_no"`
}
)
biz.Bizno = bizno
if param, err = s.alipayParam("zhima.customer.certification.query", biz, ""); err != nil {
return
}
if pass, reason, err = s.realnameDao.AlipayQuery(c, param); err != nil {
log.Error("%+v", err)
err = ecode.RealnameAlipayErr
return
}
return
}
// alipayParam 构造阿里请求parambiz为 biz_content struct
func (s *Service) alipayParam(method string, biz interface{}, returnURL string) (p url.Values, err error) {
var (
sign string
bizBytes []byte
)
if bizBytes, err = json.Marshal(biz); err != nil {
err = errors.WithStack(err)
return
}
p = url.Values{}
p.Set("app_id", conf.Conf.Realname.Alipay.AppID)
p.Set("method", method)
p.Set("charset", "utf-8")
p.Set("sign_type", "RSA2")
p.Set("timestamp", time.Now().Format("2006-01-02 15:04:05"))
p.Set("version", "1.0")
p.Set("biz_content", string(bizBytes))
if returnURL != "" {
p.Set("return_url", returnURL)
}
if sign, err = s.alipayCryptor.SignParam(p); err != nil {
return
}
p.Set("sign", sign)
return
}
func (s *Service) alipayTransactionID() string {
return fmt.Sprintf("BILI%d%d", time.Now().UnixNano(), rand.Intn(100000))
}

View File

@@ -0,0 +1,63 @@
package realname
import (
"context"
"go-common/app/interface/main/account/conf"
dao "go-common/app/interface/main/account/dao/realname"
"go-common/library/log"
)
func (s *Service) alipayAntispamCheck(c context.Context, mid int64) bool {
var (
value *dao.AlipayAntispamValue
err error
)
if value, err = s.realnameDao.AlipayAntispam(c, mid); err != nil {
log.Error("%+v", err)
return true
}
if value == nil {
return true
}
if value.Count() > conf.Conf.Realname.AlipayAntispamThreshold && !value.Pass() {
return false
}
return true
}
// alipayAntispamIncrease 增加用户申请计数
func (s *Service) alipayAntispamIncrease(c context.Context, mid int64) (err error) {
var (
value *dao.AlipayAntispamValue
)
if value, err = s.realnameDao.AlipayAntispam(c, mid); err != nil {
return
}
if value == nil {
value = new(dao.AlipayAntispamValue)
}
value.IncreaseCount()
if err = s.realnameDao.SetAlipayAntispam(c, mid, value); err != nil {
return
}
return
}
// setAlipayAntispamPassFlag 更新用户通过标识位
func (s *Service) setAlipayAntispamPassFlag(c context.Context, mid int64, flag bool) (err error) {
var (
value *dao.AlipayAntispamValue
)
if value, err = s.realnameDao.AlipayAntispam(c, mid); err != nil {
return
}
if value == nil {
value = new(dao.AlipayAntispamValue)
}
value.SetPass(flag)
if err = s.realnameDao.SetAlipayAntispam(c, mid, value); err != nil {
return
}
return
}

View File

@@ -0,0 +1,43 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = ["crypto_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = ["//vendor/github.com/smartystreets/goconvey/convey:go_default_library"],
)
go_library(
name = "go_default_library",
srcs = [
"alipay.go",
"key.go",
"main.go",
],
importpath = "go-common/app/interface/main/account/service/realname/crypto",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = ["//vendor/github.com/pkg/errors: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,123 @@
package crypto
import (
stdcrypto "crypto"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"net/url"
"sort"
"strings"
"github.com/pkg/errors"
)
// Alipay alipay cryptor
type Alipay struct {
aliPub []byte
biliPriv []byte
}
// NewAlipay is.
func NewAlipay(aliPub, biliPriv string) (a *Alipay) {
return &Alipay{
aliPub: ParsePublicKey(aliPub),
biliPriv: ParsePrivateKey(biliPriv),
}
}
func (e *Alipay) splitData(originalData []byte, packageSize int) (r [][]byte) {
var src = make([]byte, len(originalData))
copy(src, originalData)
r = make([][]byte, 0)
if len(src) <= packageSize {
return append(r, src)
}
for len(src) > 0 {
var p = src[:packageSize]
r = append(r, p)
src = src[packageSize:]
if len(src) <= packageSize {
r = append(r, src)
break
}
}
return r
}
// EncryptParam rsa encrypt.
func (e *Alipay) EncryptParam(p url.Values) (ep string, err error) {
var (
pubInterface interface{}
pub *rsa.PublicKey
data []byte
block *pem.Block
)
block, _ = pem.Decode(e.aliPub)
if block == nil {
err = errors.New("private key error")
return
}
if pubInterface, err = x509.ParsePKIXPublicKey(block.Bytes); err != nil {
err = errors.WithStack(err)
return
}
pub = pubInterface.(*rsa.PublicKey)
var sd = e.splitData([]byte(p.Encode()), pub.N.BitLen()/8-11)
for _, d := range sd {
var pd []byte
if pd, err = rsa.EncryptPKCS1v15(rand.Reader, pub, d); err != nil {
err = errors.WithStack(err)
return
}
data = append(data, pd...)
}
ep = base64.StdEncoding.EncodeToString(data)
return
}
// SignParam sign alipay param
func (e *Alipay) SignParam(p url.Values) (sign string, err error) {
if p == nil {
p = make(url.Values)
}
var pList = make([]string, 0)
for key := range p {
var value = strings.TrimSpace(p.Get(key))
if len(value) > 0 {
pList = append(pList, key+"="+value)
}
}
sort.Strings(pList)
var src = strings.Join(pList, "&")
var h = stdcrypto.SHA256.New()
if _, err = h.Write([]byte(src)); err != nil {
err = errors.WithStack(err)
return
}
var (
hashed = h.Sum(nil)
pri *rsa.PrivateKey
data []byte
block *pem.Block
)
block, _ = pem.Decode(e.biliPriv)
if block == nil {
err = errors.New("private key error")
return
}
if pri, err = x509.ParsePKCS1PrivateKey(block.Bytes); err != nil {
err = errors.WithStack(err)
return
}
if data, err = rsa.SignPKCS1v15(rand.Reader, pri, stdcrypto.SHA256, hashed); err != nil {
err = errors.WithStack(err)
return
}
sign = base64.StdEncoding.EncodeToString(data)
return
}

View File

@@ -0,0 +1,40 @@
package crypto
import (
"bytes"
"fmt"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
var (
rsaBase64 = make([]byte, 1000)
aesBase64 = make([]byte, 5000000)
)
func TestEncrypt(t *testing.T) {
Convey("encrypt", t, func() {
// TODO
})
}
func BenchmarkBytesByFMT(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = fmt.Sprintf("%04x%s%s", len(rsaBase64), rsaBase64, aesBase64)
}
}
func BenchmarkBytesByBuffer(b *testing.B) {
var buf bytes.Buffer
b.ResetTimer()
for i := 0; i < b.N; i++ {
fmt.Fprintf(&buf, "%04x", len(rsaBase64))
buf.Write(rsaBase64)
buf.Write(aesBase64)
b.StopTimer()
buf.Reset()
b.StartTimer()
_ = buf.Bytes()
}
}

View File

@@ -0,0 +1,47 @@
package crypto
import (
"bytes"
"strings"
)
// ParsePublicKey parse raw public key to pem formation
func ParsePublicKey(raw string) (result []byte) {
return parseKey(raw, "-----BEGIN PUBLIC KEY-----", "-----END PUBLIC KEY-----")
}
// ParsePrivateKey parse raw priv key to pem formation
func ParsePrivateKey(raw string) (result []byte) {
return parseKey(raw, "-----BEGIN RSA PRIVATE KEY-----", "-----END RSA PRIVATE KEY-----")
}
func parseKey(raw, prefix, suffix string) (result []byte) {
raw = strings.Replace(raw, prefix, "", 1)
raw = strings.Replace(raw, suffix, "", 1)
raw = strings.Replace(raw, " ", "", -1)
raw = strings.Replace(raw, "\n", "", -1)
raw = strings.Replace(raw, "\r", "", -1)
raw = strings.Replace(raw, "\t", "", -1)
var ll = 64
var sl = len(raw)
var c = sl / ll
if sl%ll > 0 {
c = c + 1
}
var buf bytes.Buffer
buf.WriteString(prefix + "\n")
for i := 0; i < c; i++ {
var b = i * ll
var e = b + ll
if e > sl {
buf.WriteString(raw[b:])
} else {
buf.WriteString(raw[b:e])
}
buf.WriteString("\n")
}
buf.WriteString(suffix)
return buf.Bytes()
}

View File

@@ -0,0 +1,208 @@
package crypto
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/md5"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/base64"
"encoding/hex"
"encoding/pem"
"fmt"
"strconv"
"time"
"github.com/pkg/errors"
)
// const .
const (
BlockSizeMIN = 16 // AES-128
BlockSizeMID = 24 // AES-192
BlockSizeMAX = 32 // AES-256
)
// Main mainsite cryptor
type Main struct {
publicKey, privateKey []byte
}
// NewMain is.
func NewMain(pub, priv string) (e *Main) {
return &Main{
publicKey: []byte(pub),
privateKey: []byte(priv),
}
}
// IMGEncrypt rsa + AES-128
func (e *Main) IMGEncrypt(raw []byte) (data []byte, err error) {
if len(raw) == 0 {
return
}
var (
hash = md5.New()
randToken []byte
rsaData, aesData []byte
aesBase64 []byte
rsaBase64Str string
buf bytes.Buffer
)
if _, err = hash.Write([]byte(strconv.FormatInt(time.Now().UnixNano(), 10))); err != nil {
err = errors.WithStack(err)
return
}
randToken = []byte(hex.EncodeToString(hash.Sum(nil)))
if rsaData, err = e.RsaEncrypt(randToken); err != nil {
err = errors.WithStack(err)
return
}
if aesData, err = e.AESEncrypt(randToken, raw, BlockSizeMIN); err != nil {
err = errors.WithStack(err)
return
}
rsaBase64Str = base64.StdEncoding.EncodeToString(rsaData)
aesBase64 = make([]byte, base64.StdEncoding.EncodedLen(len(aesData)))
base64.StdEncoding.Encode(aesBase64, aesData)
fmt.Fprintf(&buf, "%04x", len(rsaBase64Str))
buf.Write([]byte(rsaBase64Str))
buf.Write(aesBase64)
data = buf.Bytes()
return
}
// IMGDecrypt rsa + AES-128
func (e *Main) IMGDecrypt(raw []byte) (data []byte, err error) {
if len(raw) == 0 {
return
}
var (
rsaLen int64
rsaRandToken []byte
randToken []byte
aesBase64 []byte
aesData []byte
base64DecodedSize int
)
if rsaLen, err = strconv.ParseInt(string(raw[:4]), 16, 64); err != nil {
err = errors.WithStack(err)
return
}
if rsaRandToken, err = base64.StdEncoding.DecodeString(string(raw[4 : 4+rsaLen])); err != nil {
err = errors.WithStack(err)
return
}
if randToken, err = e.RsaDecrypt(rsaRandToken); err != nil {
err = errors.WithStack(err)
return
}
aesBase64 = raw[4+rsaLen:]
aesData = make([]byte, base64.StdEncoding.DecodedLen(len(aesBase64)))
if base64DecodedSize, err = base64.StdEncoding.Decode(aesData, aesBase64); err != nil {
err = errors.WithStack(err)
return
}
if data, err = e.AESDecrypt(randToken, aesData[:base64DecodedSize], BlockSizeMIN); err != nil {
err = errors.WithStack(err)
return
}
return
}
// RsaEncrypt rsa encrypt.
func (e *Main) RsaEncrypt(text []byte) (data []byte, err error) {
var (
block *pem.Block
)
block, _ = pem.Decode(e.publicKey)
if block == nil {
return nil, errors.New("public key error")
}
var (
pubInterface interface{}
pub *rsa.PublicKey
)
if pubInterface, err = x509.ParsePKIXPublicKey(block.Bytes); err != nil {
err = errors.WithStack(err)
return nil, err
}
pub = pubInterface.(*rsa.PublicKey)
if data, err = rsa.EncryptPKCS1v15(rand.Reader, pub, text); err != nil {
err = errors.WithStack(err)
return
}
return
}
// RsaDecrypt rsa decrypt.
func (e *Main) RsaDecrypt(text []byte) (data []byte, err error) {
var (
block *pem.Block
)
block, _ = pem.Decode(e.privateKey)
if block == nil {
return nil, errors.New("private key error")
}
var (
privateKey *rsa.PrivateKey
)
if privateKey, err = x509.ParsePKCS1PrivateKey(block.Bytes); err != nil {
err = errors.WithStack(err)
return
}
if data, err = rsa.DecryptPKCS1v15(rand.Reader, privateKey, text); err != nil {
err = errors.WithStack(err)
return
}
return
}
// AESEncrypt AES-128, AES-192, or AES-256 encrypt.
// mod 16, 24, or 32 bytes
func (e *Main) AESEncrypt(key, text []byte, mod int) (data []byte, err error) {
var (
block cipher.Block
)
if block, err = aes.NewCipher(key[:mod]); err != nil {
err = errors.WithStack(err)
return
}
msg := pkPadding(text, block.BlockSize())
ciphertext := make([]byte, len(msg))
cbc := cipher.NewCBCEncrypter(block, key[mod:])
cbc.CryptBlocks(ciphertext, []byte(msg))
return ciphertext, nil
}
// AESDecrypt AES-128, AES-192, or AES-256 decrypt.
// mod 16, 24, or 32 bytes
func (e *Main) AESDecrypt(key, text []byte, mod int) (data []byte, err error) {
var (
block cipher.Block
)
if block, err = aes.NewCipher(key[:mod]); err != nil {
err = errors.WithStack(err)
return
}
blockModel := cipher.NewCBCDecrypter(block, key[mod:])
ciphertext := make([]byte, len(text))
blockModel.CryptBlocks(ciphertext, text)
ciphertext = pkUnPadding(ciphertext)
return ciphertext, nil
}
func pkPadding(src []byte, blockSize int) []byte {
padding := blockSize - len(src)%blockSize
padtext := bytes.Repeat([]byte{byte(0)}, padding)
return append(src, padtext...)
}
func pkUnPadding(src []byte) []byte {
length := len(src)
unpadding := int(src[length-1])
return src[:(length - unpadding)]
}

View File

@@ -0,0 +1,251 @@
package realname
import (
"go-common/app/interface/main/account/model"
)
var (
cardTypeList = []*model.RealnameCardType{
{ID: 0, Name: "身份证"},
{ID: 2, Name: "港澳居民来往内地通行证"},
{ID: 3, Name: "台湾居民来往大陆通行证"},
{ID: 4, Name: "护照(中国签发)"},
{ID: 5, Name: "外国人永久居留证"},
{ID: 6, Name: "其他国家或地区身份证"},
}
// ios粉 <= 5.35版本兼容
cardTypeOldIOSList = []*model.RealnameCardType{
{ID: 0, Name: "身份证"},
{ID: 1, Name: "护照(境外签发)"},
{ID: 2, Name: "港澳居民来往内地通行证"},
{ID: 3, Name: "台湾居民来往大陆通行证"},
{ID: 4, Name: "护照(中国签发)"},
{ID: 5, Name: "外国人永久居留证"},
{ID: 6, Name: "其他国家或地区身份证"},
}
// 兼容老版本的证件列表
cardTypeOldList = []*model.RealnameCardType{
{ID: 0, Name: "身份证"},
{ID: 1, Name: "护照(境外签发)"},
{ID: 2, Name: "港澳居民来往内地通行证"},
{ID: 3, Name: "台湾居民来往大陆通行证"},
{ID: 4, Name: "护照(中国签发)"},
{ID: 5, Name: "外国人永久居留证"},
}
countryList = []*model.RealnameCountry{
// &model.RealnameCountry{ID: -1, CName: "---其他---"},
// &model.RealnameCountry{ID: 0, CName: "---常见---"},
{ID: 11, CName: "美国"},
{ID: 12, CName: "加拿大"},
{ID: 13, CName: "比利时"},
{ID: 14, CName: "法国"},
{ID: 15, CName: "澳大利亚"},
{ID: 16, CName: "日本"},
{ID: 17, CName: "新加坡"},
{ID: 18, CName: "韩国"},
{ID: 19, CName: "马来西亚"},
{ID: 20, CName: "英国"},
{ID: 21, CName: "意大利"},
{ID: 22, CName: "德国"},
{ID: 23, CName: "俄罗斯"},
{ID: 24, CName: "新西兰"},
{ID: 25, CName: "阿尔巴尼亚"},
{ID: 26, CName: "阿尔及利亚"},
{ID: 27, CName: "阿富汗"},
{ID: 28, CName: "阿根廷"},
{ID: 29, CName: "阿联酋"},
{ID: 30, CName: "阿曼"},
{ID: 31, CName: "阿塞拜疆"},
{ID: 32, CName: "埃及"},
{ID: 33, CName: "埃塞俄比亚"},
{ID: 34, CName: "爱尔兰"},
{ID: 35, CName: "爱沙尼亚"},
{ID: 36, CName: "安道尔"},
{ID: 37, CName: "安哥拉"},
{ID: 38, CName: "安提瓜岛和巴布达"},
{ID: 39, CName: "奥地利"},
{ID: 40, CName: "巴巴多斯"},
{ID: 41, CName: "巴布亚新几内亚"},
{ID: 42, CName: "巴哈马群岛"},
{ID: 43, CName: "巴基斯坦"},
{ID: 44, CName: "巴拉圭"},
{ID: 45, CName: "巴林"},
{ID: 46, CName: "巴拿马"},
{ID: 47, CName: "巴西"},
{ID: 48, CName: "白俄罗斯"},
{ID: 49, CName: "百慕大群岛"},
{ID: 50, CName: "保加利亚"},
{ID: 51, CName: "贝宁"},
{ID: 52, CName: "冰岛"},
{ID: 53, CName: "波多黎各"},
{ID: 54, CName: "波黑"},
{ID: 55, CName: "波兰"},
{ID: 56, CName: "玻利维亚"},
{ID: 57, CName: "伯利兹"},
{ID: 58, CName: "博茨瓦纳"},
{ID: 59, CName: "不丹"},
{ID: 60, CName: "布基纳法索"},
{ID: 61, CName: "布隆迪"},
{ID: 62, CName: "赤道几内亚"},
{ID: 63, CName: "丹麦"},
{ID: 64, CName: "迪戈加西亚岛"},
{ID: 65, CName: "多哥"},
{ID: 66, CName: "多米尼加"},
{ID: 67, CName: "多米尼加代表"},
{ID: 68, CName: "厄瓜多尔"},
{ID: 69, CName: "厄立特里亚"},
{ID: 70, CName: "法罗岛"},
{ID: 71, CName: "法属波利尼西亚"},
{ID: 72, CName: "法属圭亚那"},
{ID: 73, CName: "非洲中部"},
{ID: 74, CName: "菲律宾"},
{ID: 75, CName: "斐济"},
{ID: 76, CName: "芬兰"},
{ID: 77, CName: "佛得角"},
{ID: 78, CName: "福克兰岛"},
{ID: 79, CName: "冈比亚"},
{ID: 80, CName: "刚果"},
{ID: 81, CName: "刚果CName:(金)"},
{ID: 82, CName: "哥伦比亚"},
{ID: 83, CName: "哥斯达黎加"},
{ID: 84, CName: "格林纳达"},
{ID: 85, CName: "格陵兰岛"},
{ID: 86, CName: "古巴"},
{ID: 87, CName: "瓜德罗普岛"},
{ID: 88, CName: "关岛"},
{ID: 89, CName: "海地"},
{ID: 90, CName: "韩国"},
{ID: 91, CName: "荷兰"},
{ID: 92, CName: "洪都拉斯"},
{ID: 93, CName: "维克岛"},
{ID: 94, CName: "基里巴斯"},
{ID: 95, CName: "吉布提"},
{ID: 96, CName: "吉尔吉斯斯坦"},
{ID: 97, CName: "几内亚"},
{ID: 98, CName: "几内亚比绍"},
{ID: 99, CName: "加纳"},
{ID: 100, CName: "加蓬"},
{ID: 101, CName: "柬埔寨"},
{ID: 102, CName: "捷克"},
{ID: 103, CName: "津巴布韦"},
{ID: 104, CName: "聚会岛"},
{ID: 105, CName: "喀麦隆"},
{ID: 106, CName: "卡塔尔"},
{ID: 107, CName: "开曼群岛"},
{ID: 108, CName: "科摩罗"},
{ID: 109, CName: "科威特"},
{ID: 110, CName: "克罗地亚"},
{ID: 111, CName: "肯尼亚"},
{ID: 112, CName: "库克岛"},
{ID: 113, CName: "拉脱维亚"},
{ID: 114, CName: "莱索托"},
{ID: 115, CName: "老挝"},
{ID: 116, CName: "黎巴嫩"},
{ID: 117, CName: "立陶宛"},
{ID: 118, CName: "利比里亚"},
{ID: 119, CName: "利比亚"},
{ID: 120, CName: "卢森堡"},
{ID: 121, CName: "卢旺达"},
{ID: 122, CName: "罗马尼亚"},
{ID: 123, CName: "马达加斯加"},
{ID: 124, CName: "马尔代夫"},
{ID: 125, CName: "马耳他"},
{ID: 126, CName: "马拉维"},
{ID: 127, CName: "马里"},
{ID: 128, CName: "马里亚纳岛"},
{ID: 129, CName: "马其顿"},
{ID: 130, CName: "马提尼克岛"},
{ID: 131, CName: "马歇尔岛"},
{ID: 132, CName: "毛里求斯"},
{ID: 133, CName: "毛利塔尼亚"},
{ID: 134, CName: "蒙古"},
{ID: 135, CName: "蒙特塞拉特岛"},
{ID: 136, CName: "孟加拉国"},
{ID: 137, CName: "秘鲁"},
{ID: 138, CName: "密克罗尼西亚"},
{ID: 139, CName: "缅甸"},
{ID: 140, CName: "摩尔多瓦"},
{ID: 141, CName: "摩洛哥"},
{ID: 142, CName: "摩纳哥"},
{ID: 143, CName: "莫桑比克"},
{ID: 144, CName: "墨西哥"},
{ID: 145, CName: "纳米比亚"},
{ID: 146, CName: "南非"},
{ID: 147, CName: "南斯拉夫"},
{ID: 148, CName: "瑙鲁"},
{ID: 149, CName: "尼泊尔"},
{ID: 150, CName: "尼加拉瓜"},
{ID: 151, CName: "尼日尔"},
{ID: 152, CName: "尼日利亚"},
{ID: 153, CName: "纽埃岛"},
{ID: 154, CName: "挪威"},
{ID: 155, CName: "诺福克岛"},
{ID: 156, CName: "帕劳"},
{ID: 157, CName: "葡萄牙"},
{ID: 158, CName: "瓦利斯群岛和富图纳群岛"},
{ID: 159, CName: "格鲁吉亚"},
{ID: 160, CName: "瑞典"},
{ID: 161, CName: "瑞士"},
{ID: 162, CName: "萨尔瓦多"},
{ID: 163, CName: "萨摩亚、西部"},
{ID: 164, CName: "萨摩亚、东部"},
{ID: 165, CName: "塞拉利昂"},
{ID: 166, CName: "塞内加尔"},
{ID: 167, CName: "塞浦路斯"},
{ID: 168, CName: "塞舌尔共和国"},
{ID: 169, CName: "桑给巴尔岛"},
{ID: 170, CName: "沙特阿拉伯"},
{ID: 171, CName: "圣多美和普林西比"},
{ID: 172, CName: "圣卢西亚"},
{ID: 173, CName: "圣马力诺"},
{ID: 174, CName: "圣皮埃尔和密克隆群岛"},
{ID: 175, CName: "斯里兰卡"},
{ID: 176, CName: "斯洛伐克"},
{ID: 177, CName: "斯洛文尼亚"},
{ID: 178, CName: "斯威士兰"},
{ID: 179, CName: "苏丹"},
{ID: 180, CName: "苏里南"},
{ID: 181, CName: "所罗门群岛"},
{ID: 182, CName: "索马里"},
{ID: 183, CName: "泰国"},
{ID: 184, CName: "坦桑尼亚"},
{ID: 185, CName: "汤加"},
{ID: 186, CName: "特克斯和凯科斯"},
{ID: 187, CName: "特立尼达和多巴哥"},
{ID: 188, CName: "阿森松岛"},
{ID: 189, CName: "突尼斯"},
{ID: 190, CName: "图瓦卢"},
{ID: 191, CName: "土耳其"},
{ID: 192, CName: "土库曼斯坦"},
{ID: 193, CName: "托克劳岛"},
{ID: 194, CName: "瓦努阿图"},
{ID: 195, CName: "维珍群岛:(美属)"},
{ID: 196, CName: "维珍群岛:(英属)"},
{ID: 197, CName: "委内瑞拉"},
{ID: 198, CName: "文莱"},
{ID: 199, CName: "乌干达"},
{ID: 200, CName: "乌克兰"},
{ID: 201, CName: "乌拉圭"},
{ID: 202, CName: "乌兹别克斯坦"},
{ID: 203, CName: "西班牙"},
{ID: 204, CName: "希腊"},
{ID: 205, CName: "科特迪瓦"},
{ID: 206, CName: "匈牙利"},
{ID: 207, CName: "叙利亚"},
{ID: 208, CName: "牙买加"},
{ID: 209, CName: "亚美尼亚"},
{ID: 210, CName: "也门"},
{ID: 211, CName: "伊拉克"},
{ID: 212, CName: "伊朗"},
{ID: 213, CName: "以色列"},
{ID: 214, CName: "印度"},
{ID: 215, CName: "印尼"},
{ID: 216, CName: "约旦"},
{ID: 217, CName: "越南"},
{ID: 218, CName: "赞比亚"},
{ID: 219, CName: "乍得"},
{ID: 220, CName: "直布罗陀"},
{ID: 221, CName: "智利"},
}
)

View File

@@ -0,0 +1,99 @@
package realname
import (
"context"
"crypto/md5"
"encoding/hex"
"fmt"
"math/rand"
"net/url"
"strconv"
"go-common/app/interface/main/account/conf"
"go-common/app/interface/main/account/model"
"go-common/library/ecode"
"go-common/library/log"
)
// CaptchaGTRegister register geetest
func (s *Service) CaptchaGTRegister(c context.Context, mid int64, ip, gtType string) (urlstr string, remote int, err error) {
var (
p = url.Values{}
challenge string
)
p.Set("ct", "1")
p.Set("gt", conf.Conf.Realname.Geetest.CaptchaID)
if challenge, err = s.realnameDao.RealnameCaptchaGTRegister(c, mid, ip, gtType, 1); err != nil || challenge == "" {
p.Set("success", "0")
remote = 0
err = nil
randOne := md5.Sum([]byte(strconv.Itoa(rand.Intn(100))))
randTwo := md5.Sum([]byte(strconv.Itoa(rand.Intn(100))))
p.Set("challenge", hex.EncodeToString(randOne[:])+hex.EncodeToString(randTwo[:])[0:2])
} else {
p.Set("success", "1")
remote = 1
array := md5.Sum([]byte(challenge + conf.Conf.Realname.Geetest.PrivateKey))
p.Set("challenge", hex.EncodeToString(array[:]))
}
p.Set("hash", fmt.Sprintf("%x", md5.Sum([]byte(p.Encode()))))
urlstr = "http://passport.bilibili.com/register/verification.html?" + p.Encode()
return
}
// CaptchaGTRefresh refresh geetest
func (s *Service) CaptchaGTRefresh(c context.Context, mid int64, ip, gtType string, hash string) (challenge string, gt string, success int, err error) {
log.Info("CaptchaGTRefresh got hash : %s", hash)
gt = conf.Conf.Realname.Geetest.CaptchaID
if challenge, err = s.realnameDao.RealnameCaptchaGTRegister(c, mid, ip, gtType, 1); err != nil || challenge == "" {
success = 0
randOne := md5.Sum([]byte(strconv.Itoa(rand.Intn(100))))
randTwo := md5.Sum([]byte(strconv.Itoa(rand.Intn(100))))
challenge = hex.EncodeToString(randOne[:]) + hex.EncodeToString(randTwo[:])[0:2]
} else {
success = 1
array := md5.Sum([]byte(challenge + conf.Conf.Realname.Geetest.PrivateKey))
challenge = hex.EncodeToString(array[:])
}
return
}
// CaptchaGTValidate validate geetest
func (s *Service) CaptchaGTValidate(c context.Context, mid int64, ip, clientType string, param *model.ParamRealnameCaptchaGTCheck) (res *model.RealnameCaptchaGTValidate, err error) {
res = &model.RealnameCaptchaGTValidate{
State: model.RealnameFalse,
}
switch param.Remote {
// 极验远程校验
case model.RealnameTrue:
md5Array := md5.Sum([]byte(conf.Conf.Realname.Geetest.PrivateKey + "geetest" + param.Challenge))
if hex.EncodeToString(md5Array[:]) != param.Validate {
return
}
var remoteSeccode string
if remoteSeccode, err = s.realnameDao.RealnameCaptchaGTRegisterValidate(c, param.Challenge, param.Seccode, clientType, ip, conf.Conf.Realname.Geetest.CaptchaID, mid); err != nil {
return
}
log.Info("CaptchaGTValidate remoteSec : %s", remoteSeccode)
md5Array = md5.Sum([]byte(remoteSeccode))
res.State = model.RealnameTrue
// if hex.EncodeToString(md5Array[:]) == param.Seccode {
// res.State = model.RealnameTrue
// }
// 极验本地校验
case model.RealnameFalse:
// md5Array := md5.Sum([]byte(param.Challenge))
// if hex.EncodeToString(md5Array[:]) == param.Validate {
// res.State = model.RealnameTrue
// }
res.State = model.RealnameTrue
default:
err = ecode.RequestErr
}
s.addmiss(func() {
if missErr := s.setAlipayAntispamPassFlag(context.Background(), mid, true); missErr != nil {
log.Error("%+v", err)
}
})
return
}

View File

@@ -0,0 +1,206 @@
package realname
import (
"context"
"strings"
"go-common/app/interface/main/account/conf"
"go-common/app/interface/main/account/dao/realname"
"go-common/app/interface/main/account/model"
"go-common/app/interface/main/account/service/realname/crypto"
memrpc "go-common/app/service/main/member/api/gorpc"
memmodel "go-common/app/service/main/member/model"
"go-common/library/log"
)
// Service is
type Service struct {
c *conf.Config
memRPC *memrpc.Service
realnameDao *realname.Dao
mainCryptor *crypto.Main
alipayCryptor *crypto.Alipay
missch chan func()
}
// New create service instance and return.
func New(c *conf.Config, rsapub, rsapriv, alipub, alibilipriv string) (s *Service) {
s = &Service{
c: c,
memRPC: memrpc.New(c.RPCClient2.Member),
realnameDao: realname.New(c),
mainCryptor: crypto.NewMain(rsapub, rsapriv),
alipayCryptor: crypto.NewAlipay(alipub, alibilipriv),
missch: make(chan func(), 1024),
}
go s.missproc()
return
}
// Status get status of realname
func (s *Service) Status(c context.Context, mid int64) (status int8, err error) {
var (
arg = &memmodel.ArgMemberMid{
Mid: mid,
}
res *memmodel.RealnameStatus
)
if res, err = s.memRPC.RealnameStatus(c, arg); err != nil {
return
}
status = int8(*res)
return
}
// ApplyStatus return realname apply status
func (s *Service) ApplyStatus(c context.Context, mid int64) (status int8, remark string, realname string, card string, err error) {
var (
arg = &memmodel.ArgMemberMid{
Mid: mid,
}
res *memmodel.RealnameApplyStatusInfo
)
if res, err = s.memRPC.RealnameApplyStatus(c, arg); err != nil {
return
}
status = int8(res.Status)
remark = res.Remark
realname, card = maskRealnameInfo(res.Realname, res.Card)
return
}
func maskRealnameInfo(realname, card string) (r, c string) {
var (
rStrs = strings.Split(realname, "")
cStrs = strings.Split(card, "")
)
if len(rStrs) > 0 {
r = "*" + strings.Join(rStrs[1:], "")
}
if len(cStrs) > 0 {
if len(cStrs) == 1 {
c = "*"
} else if len(cStrs) > 5 {
c = cStrs[0] + strings.Repeat("*", len(cStrs)-3) + strings.Join(cStrs[len(cStrs)-2:], "")
} else {
c = cStrs[0] + strings.Repeat("*", len(cStrs)-1)
}
}
return
}
// CountryList .
func (s *Service) CountryList(c context.Context) (list []*model.RealnameCountry, err error) {
list = countryList
return
}
// CardTypes .
func (s *Service) CardTypes(c context.Context, platform string, mobiapp string, device string, build int) (list []*model.RealnameCardType, err error) {
if (platform == "android" && build < 512000) || (platform == "ios" && build <= 5990) {
list = cardTypeOldList
return
}
// IOS粉暂返回 5.32 版本数据,待 5.36 IOS 重新接入后,根据 build 号,返回 cardTypeList
if platform == "ios" && mobiapp == "iphone" && device != "pad" {
list = cardTypeOldIOSList
return
}
list = cardTypeList
return
}
// CardTypesV2 .
func (s *Service) CardTypesV2(c context.Context) (list []*model.RealnameCardType, err error) {
list = cardTypeList
return
}
// TelCapture .
func (s *Service) TelCapture(c context.Context, mid int64) (err error) {
var (
arg = &memmodel.ArgMemberMid{
Mid: mid,
}
)
if err = s.memRPC.RealnameTelCapture(c, arg); err != nil {
return
}
return
}
// TelInfo .
func (s *Service) TelInfo(c context.Context, mid int64) (tel string, err error) {
if tel, err = s.realnameDao.TelInfo(c, mid); err != nil {
return
}
if len(tel) == 0 {
return
}
if len(tel) < 4 {
tel = tel[:1] + "****"
return
}
tel = tel[:3] + "****" + tel[len(tel)-4:]
return
}
// Apply .
func (s *Service) Apply(c context.Context, mid int64, realname string, cardType int, cardNum string, countryID int, captureCode int, handIMGToken, frontIMGToken, backIMGToken string) (err error) {
var (
arg = &memmodel.ArgRealnameApply{
MID: mid,
CaptureCode: captureCode,
Realname: realname,
CardType: int8(cardType),
CardCode: cardNum,
Country: int16(countryID),
HandIMGToken: handIMGToken,
FrontIMGToken: frontIMGToken,
BackIMGToken: backIMGToken,
}
)
if err = s.memRPC.RealnameApply(c, arg); err != nil {
return
}
return
}
// Channel .
func (s *Service) Channel(c context.Context) (channels []*model.RealnameChannel, err error) {
for _, c := range conf.Conf.Realname.Channel {
var (
channel = &model.RealnameChannel{
Name: c.Name,
Flag: model.RealnameFalse,
}
)
if c.Flag {
channel.Flag = model.RealnameTrue
}
channels = append(channels, channel)
}
return
}
func (s *Service) addmiss(f func()) {
select {
case s.missch <- f:
default:
log.Error("eventproc chan full")
}
}
// missproc is a routine for executing closure.
func (s *Service) missproc() {
defer func() {
if x := recover(); x != nil {
log.Error("missproc panic %+v", x)
}
go s.missproc()
}()
for {
f := <-s.missch
f()
}
}

View File

@@ -0,0 +1,189 @@
package realname
import (
"context"
"flag"
"io/ioutil"
"os"
"testing"
"go-common/app/interface/main/account/conf"
"go-common/app/interface/main/account/model"
. "github.com/smartystreets/goconvey/convey"
)
var (
s *Service
ctx = context.Background()
rsaPub, rsaPriv = ``, ``
alipayPub = ``
alipayOwnPriv = ``
)
func TestMain(m *testing.M) {
var err error
flag.Set("conf", "../../cmd/account-interface-example.toml")
if err = conf.Init(); err != nil {
panic(err)
}
s = New(conf.Conf, rsaPub, rsaPriv, alipayPub, alipayOwnPriv)
m.Run()
os.Exit(0)
}
func TestEncrypt(t *testing.T) {
var (
raw []byte
err error
)
if raw, err = ioutil.ReadFile("./test.jpg"); err != nil {
panic(err)
}
Convey("encrypt", t, func() {
var (
encrpted []byte
outputs []byte
)
if encrpted, err = s.mainCryptor.IMGEncrypt(raw); err != nil {
panic(err)
}
if err = ioutil.WriteFile("./encrypted", encrpted, os.ModePerm); err != nil {
panic(err)
}
if outputs, err = s.mainCryptor.IMGDecrypt(encrpted); err != nil {
panic(err)
}
if err = ioutil.WriteFile("./output.jpg", outputs, os.ModePerm); err != nil {
panic(err)
}
})
}
func TestRealname(t *testing.T) {
Convey("realname", t, func() {
var (
mid int64
err error
)
_, err = s.TelInfo(ctx, mid)
So(err, ShouldBeNil)
err = s.TelCapture(ctx, mid)
So(err, ShouldBeNil)
s.CountryList(ctx)
s.CardTypes(ctx, "pc", "", "", 1234)
})
}
func TestRealnameMask(t *testing.T) {
Convey("realname mask", t, func() {
var (
realname1 = ""
realname2 = "托"
realname3 = "托米"
realname4 = "托了一地的米"
card1 = ""
card2 = "t"
card3 = "tom"
card4 = "tommmmmy233"
)
r, c := maskRealnameInfo(realname1, card1)
So(r, ShouldEqual, "")
So(c, ShouldEqual, "")
r, c = maskRealnameInfo(realname2, card2)
So(r, ShouldEqual, "*")
So(c, ShouldEqual, "*")
r, c = maskRealnameInfo(realname3, card3)
So(r, ShouldEqual, "*米")
So(c, ShouldEqual, "t**")
r, c = maskRealnameInfo(realname4, card4)
So(r, ShouldEqual, "*了一地的米")
So(c, ShouldEqual, "t********33")
})
}
func TestAlipay(t *testing.T) {
Convey("alipay", t, func() {
// bizno, err := s.alipayInit(context.Background(), "沐阳", "340702199110120011")
// So(err, ShouldBeNil)
// t.Log(bizno)
// url, err := s.alipayCertifyURL(context.Background(), conf.Conf.Realname.Alipay.AppID, bizno)
// So(err, ShouldBeNil)
// t.Log(url)
bizno := "ZM201808153000000757500643766753"
pass, reason, err := s.alipayQuery(context.Background(), bizno)
So(err, ShouldBeNil)
t.Log(pass, reason)
})
}
func TestGeetest(t *testing.T) {
Convey("gt", t, func() {
var (
mid int64 = 111001723
)
// urlStr, err := s.CaptchaGTRegister(ctx, mid, "127.0.0.1", "h5")
// So(err, ShouldBeNil)
// t.Log(urlStr)
// challenge, gt, success, err := s.CaptchaGTRefresh(ctx, mid, "127.0.0.1", "h5", "fake hash")
// So(err, ShouldBeNil)
// t.Log(challenge, gt, success)
var (
validateArg = &model.ParamRealnameCaptchaGTCheck{
Remote: 1,
Challenge: "58fb29d758ef977717b8fd98d5d1371b9c",
Validate: "6171ad7e1243a50c8ca9b124cb6ae411",
Seccode: "6171ad7e1243a50c8ca9b124cb6ae411|jordan",
}
)
res, err := s.CaptchaGTValidate(ctx, mid, "127.0.0.1", "h5", validateArg)
So(err, ShouldBeNil)
t.Log(res)
})
}
func BenchmarkEncrypt(b *testing.B) {
var (
err error
raw []byte
)
if raw, err = ioutil.ReadFile("./test.jpg"); err != nil {
panic(err)
}
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
if _, err = s.mainCryptor.IMGEncrypt(raw); err != nil {
panic(err)
}
}
})
}
func BenchmarkDecrypt(b *testing.B) {
var (
err error
raw []byte
)
if raw, err = ioutil.ReadFile("./encrypted"); err != nil {
panic(err)
}
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
if _, err = s.mainCryptor.IMGDecrypt(raw); err != nil {
panic(err)
}
}
})
}

View File

@@ -0,0 +1,130 @@
package realname
import (
"context"
"crypto/md5"
"encoding/hex"
"fmt"
"io/ioutil"
"math/rand"
"os"
"strconv"
"strings"
"syscall"
"time"
"github.com/pkg/errors"
)
// Upload upload ID card.
func (s *Service) Upload(c context.Context, mid int64, data []byte) (src string, err error) {
var (
md5Engine = md5.New()
hashMID string
hashRand string
fileName string
dirPath string
dateStr string
)
md5Engine.Write([]byte(strconv.FormatInt(mid, 10)))
hashMID = hex.EncodeToString(md5Engine.Sum(nil))
md5Engine.Reset()
md5Engine.Write([]byte(strconv.FormatInt(time.Now().Unix(), 10)))
md5Engine.Write([]byte(strconv.FormatInt(rand.Int63n(1000000), 10)))
hashRand = hex.EncodeToString(md5Engine.Sum(nil))
fileName = fmt.Sprintf("%s_%s.txt", hashMID[:6], hashRand)
dateStr = time.Now().Format("20060102")
dirPath = fmt.Sprintf("%s/%s/", s.c.Realname.DataDir, dateStr)
var (
dataFile *os.File
writeFileSize int
encrptedData []byte
)
_, err = os.Stat(dirPath)
if os.IsNotExist(err) {
mask := syscall.Umask(0)
defer syscall.Umask(mask)
if err = os.MkdirAll(dirPath, 0777); err != nil {
err = errors.WithStack(err)
return
}
}
if encrptedData, err = s.mainCryptor.IMGEncrypt(data); err != nil {
err = errors.WithStack(err)
return
}
if dataFile, err = os.Create(dirPath + fileName); err != nil {
err = errors.Wrapf(err, "create file %s failed", dirPath+fileName)
return
}
defer dataFile.Close()
if writeFileSize, err = dataFile.Write(encrptedData); err != nil {
err = errors.Wrapf(err, "write file %s size %d failed", dirPath+fileName, len(encrptedData))
return
}
if writeFileSize != len(encrptedData) {
err = errors.Errorf("Write file data to %s , expected %d actual %d", dirPath+fileName, len(encrptedData), writeFileSize)
return
}
src = fmt.Sprintf("%s/%s", dateStr, strings.TrimSuffix(fileName, ".txt"))
return
}
// Preview preview id card
func (s *Service) Preview(c context.Context, mid int64, src string) (img []byte, err error) {
var (
filePath string
file *os.File
fileInfo os.FileInfo
)
if !s.validateSrc(mid, src) {
err = errors.Errorf("Preview src %s invalid", src)
return
}
filePath = fmt.Sprintf("%s/%s.txt", s.c.Realname.DataDir, src)
fileInfo, err = os.Stat(filePath)
if os.IsNotExist(err) {
err = errors.WithStack(err)
return
}
if time.Since(fileInfo.ModTime()) > time.Duration(s.c.Realname.ImageExpire) {
err = errors.Errorf("Realname upload image %s expired %+v", filePath, s.c.Realname.ImageExpire)
return
}
if file, err = os.Open(filePath); err != nil {
err = errors.WithStack(err)
return
}
defer file.Close()
if img, err = ioutil.ReadAll(file); err != nil {
err = errors.WithStack(err)
return
}
return s.mainCryptor.IMGDecrypt(img)
}
func (s *Service) validateSrc(mid int64, src string) (ok bool) {
var (
paths []string
fileNames []string
)
if paths = strings.Split(src, "/"); len(paths) != 2 {
return
}
if fileNames = strings.Split(paths[1], "_"); len(fileNames) != 2 {
return
}
var (
hash = md5.New()
midHash string
)
hash.Write([]byte(strconv.FormatInt(mid, 10)))
midHash = hex.EncodeToString(hash.Sum(nil))[:6]
if midHash != fileNames[0] {
return
}
ok = true
return
}

View File

@@ -0,0 +1,56 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = ["relation_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/account/conf:go_default_library",
"//app/service/main/relation/model:go_default_library",
"//library/log:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = ["relation.go"],
importpath = "go-common/app/interface/main/account/service/relation",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/account/conf:go_default_library",
"//app/interface/main/account/dao/relation:go_default_library",
"//app/interface/main/account/model:go_default_library",
"//app/service/main/account/model:go_default_library",
"//app/service/main/account/rpc/client:go_default_library",
"//app/service/main/archive/api/gorpc:go_default_library",
"//app/service/main/relation/model:go_default_library",
"//app/service/main/relation/rpc/client:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/metadata: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"],
)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,171 @@
package relation
import (
"context"
"sync"
"testing"
"go-common/app/interface/main/account/conf"
mrl "go-common/app/service/main/relation/model"
"go-common/library/log"
. "github.com/smartystreets/goconvey/convey"
)
var (
once sync.Once
//ip = "127.0.0.1"
s *Service
)
func startService() {
if err := conf.Init(); err != nil {
panic(err)
}
log.Init(conf.Conf.Xlog)
defer log.Close()
s = New(conf.Conf)
}
func TestRelation(t *testing.T) {
once.Do(startService)
Convey("relation", t, func() {
testBlacks(t)
testFollowers(t)
testFollowings(t)
testRelation(t)
testRelations(t)
testStat(t)
testWhispers(t)
})
}
func testBlacks(t *testing.T) {
res, _, total, err := s.Blacks(context.TODO(), 18552813, 0, 1, 100)
if err != nil {
t.Errorf("s.Black err(%v)", err)
}
t.Logf("black %v, total:%v", res, total)
}
func testRelation(t *testing.T) {
res, err := s.Relation(context.TODO(), 500, 100)
if err != nil {
t.Errorf("s.Relation err(%v)", err)
return
}
t.Logf("Relation res(%v)", res)
}
func testRelations(t *testing.T) {
res, err := s.Relations(context.TODO(), 500, []int64{100, 200})
if err != nil {
t.Errorf("s.Relations err(%v)", err)
return
}
t.Logf("Relations res(%v)", res)
}
func testWhispers(t *testing.T) {
res, _, err := s.Whispers(context.TODO(), 500, 1, 100, 0)
if err != nil {
t.Errorf("s.Whispers err(%v)", err)
return
}
t.Logf("Whispers res(%v)", res)
}
func testFollowers(t *testing.T) {
res, _, _, err := s.Followers(context.TODO(), 500, 1, 10, 1, 0)
if err != nil {
t.Errorf("s.Followers err(%v)", err)
return
}
t.Logf("Followers res(%v)", res)
}
func testFollowings(t *testing.T) {
res, _, _, err := s.Followings(context.TODO(), 500, 1, 10, 1, 0, "asc")
if err != nil {
t.Errorf("s.Followings err(%v)", err)
return
}
t.Logf("Followings res(%v)", res)
}
func testStat(t *testing.T) {
res, err := s.Stat(context.TODO(), 500, true)
if err != nil {
t.Errorf("s.Stat err(%v)", err)
return
}
t.Logf("Stat self res(%+v)", res)
res, err = s.Stat(context.TODO(), 500, false)
if err != nil {
t.Errorf("s.Stat err(%v)", err)
return
}
t.Logf("Stat res(%+v)", res)
}
func TestUnread(t *testing.T) {
Convey("Unread", t, func() {
_, err := s.Unread(context.TODO(), 1, false)
So(err, ShouldBeNil)
})
}
func TestUnreadCount(t *testing.T) {
Convey("UnreadCount", t, func() {
_, err := s.UnreadCount(context.TODO(), 1, false)
So(err, ShouldBeNil)
})
}
func TestSpecial(t *testing.T) {
Convey("Special", t, func() {
_, err := s.Special(context.TODO(), 1)
So(err, ShouldBeNil)
})
}
func TestDelSpecial(t *testing.T) {
Convey("DelSpecial", t, func() {
err := s.DelSpecial(context.TODO(), &mrl.ArgFollowing{Mid: 1})
So(err, ShouldBeNil)
})
}
func TestAddSpecial(t *testing.T) {
Convey("AddSpecial", t, func() {
err := s.AddSpecial(context.TODO(), &mrl.ArgFollowing{Mid: 1})
So(err, ShouldBeNil)
})
}
func TestClosePrompt(t *testing.T) {
Convey("ClosePrompt", t, func() {
err := s.ClosePrompt(context.TODO(), &mrl.ArgPrompt{Mid: 1})
So(err, ShouldBeNil)
})
}
func TestPrompt(t *testing.T) {
Convey("Prompt", t, func() {
_, err := s.Prompt(context.TODO(), &mrl.ArgPrompt{Mid: 1})
So(err, ShouldBeNil)
})
}
func TestTagsMoveUsers(t *testing.T) {
Convey("TagsMoveUsers", t, func() {
err := s.TagsMoveUsers(context.TODO(), 1, 1, "", "")
So(err, ShouldBeNil)
})
}
func TestTagsCopyUsers(t *testing.T) {
Convey("TagsCopyUsers", t, func() {
err := s.TagsCopyUsers(context.TODO(), 1, "", "")
So(err, ShouldBeNil)
})
}

View File

@@ -0,0 +1,72 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"invite.go",
"pendant.go",
"pendant_new.go",
"service.go",
],
importpath = "go-common/app/interface/main/account/service/usersuit",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/account/conf:go_default_library",
"//app/interface/main/account/dao/usersuit:go_default_library",
"//app/interface/main/account/dao/vip:go_default_library",
"//app/interface/main/account/model:go_default_library",
"//app/service/main/account/model:go_default_library",
"//app/service/main/account/rpc/client:go_default_library",
"//app/service/main/coin/api/gorpc:go_default_library",
"//app/service/main/coin/model:go_default_library",
"//app/service/main/member/api/gorpc:go_default_library",
"//app/service/main/member/model:go_default_library",
"//app/service/main/usersuit/model:go_default_library",
"//app/service/main/usersuit/rpc/client:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/metadata:go_default_library",
"//library/sync/errgroup: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"],
)
go_test(
name = "go_default_test",
srcs = [
"invite_test.go",
"pendant_test.go",
"service_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/account/conf:go_default_library",
"//app/service/main/usersuit/model:go_default_library",
"//app/service/main/usersuit/rpc/client:go_default_library",
"//library/ecode:go_default_library",
"//vendor/github.com/bouk/monkey:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)

View File

@@ -0,0 +1,134 @@
package usersuit
import (
"context"
"sync"
"time"
"go-common/app/interface/main/account/model"
accmdl "go-common/app/service/main/account/model"
usmdl "go-common/app/service/main/usersuit/model"
"go-common/library/log"
"go-common/library/net/metadata"
"go-common/library/sync/errgroup"
)
const (
_batch = 20
_fetchInfoTimeout = time.Second * 10
)
var (
_emptyRichInvites = make([]*model.RichInvite, 0)
_emptyInfoMap = make(map[int64]*accmdl.Info)
)
// Buy buy invite code.
func (s *Service) Buy(c context.Context, mid int64, num int64) (res []*model.RichInvite, err error) {
var invs []*usmdl.Invite
ip := metadata.String(c, metadata.RemoteIP)
arg := &usmdl.ArgBuy{Mid: mid, Num: num, IP: ip}
if invs, err = s.usRPC.Buy(c, arg); err != nil {
log.Error("service.userserviceRPC.Buy(%v) error(%v)", arg, err)
return
}
res = make([]*model.RichInvite, 0)
for _, inv := range invs {
res = append(res, model.NewRichInvite(inv, nil))
}
return
}
// Apply apply invite code.
func (s *Service) Apply(c context.Context, mid int64, code string, cookie string) (err error) {
ip := metadata.String(c, metadata.RemoteIP)
arg := &usmdl.ArgApply{Mid: mid, Code: code, Cookie: cookie, IP: ip}
if err = s.usRPC.Apply(c, arg); err != nil {
log.Error("service.userserviceRPC.Apply(%v) error(%v)", arg, err)
}
return
}
// Stat get user's invite code stat.
func (s *Service) Stat(c context.Context, mid int64) (res *model.RichInviteStat, err error) {
var st *usmdl.InviteStat
ip := metadata.String(c, metadata.RemoteIP)
arg := &usmdl.ArgStat{Mid: mid, IP: ip}
if st, err = s.usRPC.Stat(c, arg); err != nil {
log.Error("service.userserviceRPC.Stat(%v) error(%v)", arg, err)
return
}
res = &model.RichInviteStat{
Mid: st.Mid,
CurrentLimit: st.CurrentLimit,
CurrentBought: st.CurrentBought,
TotalBought: st.TotalBought,
TotalUsed: st.TotalUsed,
InviteCodes: s.fillInviteeInfo(c, st.InviteCodes, ip),
}
return
}
func (s *Service) fillInviteeInfo(c context.Context, invs []*usmdl.Invite, ip string) []*model.RichInvite {
if len(invs) == 0 {
return _emptyRichInvites
}
imidm := make(map[int64]int)
for _, inv := range invs {
if inv.Status == usmdl.StatusUsed {
imidm[inv.Imid] = 1
}
}
infom := _emptyInfoMap
if len(imidm) > 0 {
imids := make([]int64, 0, len(imidm))
for imid := range imidm {
imids = append(imids, imid)
}
var err1 error
if infom, err1 = s.fetchInfos(c, imids, ip, _fetchInfoTimeout); err1 != nil {
log.Error("service.fetchInfos(%v, %s, %v) error(%v)", imids, ip, _fetchInfoTimeout, err1)
}
}
rinvs := make([]*model.RichInvite, 0)
for _, inv := range invs {
rinvs = append(rinvs, model.NewRichInvite(inv, infom[inv.Imid]))
}
return rinvs
}
func (s *Service) fetchInfos(c context.Context, mids []int64, ip string, timeout time.Duration) (res map[int64]*accmdl.Info, err error) {
if len(mids) == 0 {
res = _emptyInfoMap
return
}
batches := len(mids)/_batch + 1
tc, cancel := context.WithTimeout(c, timeout)
defer cancel()
eg, errCtx := errgroup.WithContext(tc)
bms := make([]map[int64]*accmdl.Info, batches)
mu := sync.Mutex{}
for i := 0; i < batches; i++ {
idx := i
end := (idx + 1) * _batch
if idx == batches-1 {
end = len(mids)
}
ids := mids[idx*_batch : end]
eg.Go(func() error {
m, err1 := s.accRPC.Infos3(errCtx, &accmdl.ArgMids{Mids: ids})
mu.Lock()
bms[idx] = m
mu.Unlock()
return err1
})
}
err = eg.Wait()
res = make(map[int64]*accmdl.Info)
for _, bm := range bms {
for mid, info := range bm {
res[mid] = info
}
}
return
}

View File

@@ -0,0 +1,27 @@
package usersuit
import (
"context"
"testing"
"time"
"go-common/library/ecode"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_FetchMultiInfo(t *testing.T) {
time.Sleep(time.Second * 2)
Convey("Fetch multi info", t, func() {
mids := []int64{88888970}
Convey("when not timeout", func() {
res, err := s.fetchInfos(context.Background(), mids, "127.0.0.1", time.Second)
So(err, ShouldBeNil)
So(len(res), ShouldEqual, len(mids))
})
Convey("when timeout", func() {
_, err := s.fetchInfos(context.Background(), mids, "127.0.0.1", time.Millisecond)
So(err, ShouldEqual, ecode.Deadline.Error())
})
})
}

View File

@@ -0,0 +1,274 @@
package usersuit
import (
"context"
"math"
"go-common/app/interface/main/account/model"
cmdl "go-common/app/service/main/coin/model"
memmdl "go-common/app/service/main/member/model"
usmdl "go-common/app/service/main/usersuit/model"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/net/metadata"
)
// Equip user pendant equip.
func (s *Service) Equip(c context.Context, mid, pid int64, status int8, source int64) (err error) {
return s.usRPC.Equip(c, &usmdl.ArgEquip{Mid: mid, Pid: pid, Status: status, Source: source})
}
// Equipment get pendant current equipment
func (s *Service) Equipment(c context.Context, mid int64) (equipPHP *model.EquipPHP, err error) {
var equip *usmdl.PendantEquip
ip := metadata.String(c, metadata.RemoteIP)
if equip, err = s.usRPC.Equipment(c, &usmdl.ArgEquipment{Mid: mid, IP: ip}); err != nil {
log.Error("s.usRPC.Equipment(%d) error(%v)", mid, err)
return
}
var coin float64
if coin, err = s.coinRPC.UserCoins(c, &cmdl.ArgCoinInfo{Mid: mid}); err != nil {
log.Error("s.coinRPC.UserCoins(%d) error(%v)", mid, err)
return
}
var base *memmdl.BaseInfo
if base, err = s.memRPC.Base(c, &memmdl.ArgMemberMid{Mid: mid, RemoteIP: ip}); err != nil {
log.Error("s.memRPC.Base(%d) error(%v)", mid, err)
return
}
equipPHP = &model.EquipPHP{
Coins: coin,
FaceURL: base.Face,
}
if equip == nil || equip.Pendant == nil {
log.Info("s.Equipment(%d) usequip(%+v) or usequip.Pendant(%+v) is nil", equip, equip.Pendant)
return
}
equipPHP.Pid = equip.Pid
equipPHP.Image = model.FormatImgURL(mid, equip.Pendant.Image)
equipPHP.ImageModel = model.FormatImgURL(mid, equip.Pendant.ImageModel)
return
}
// Pendant return pendant info.
func (s *Service) Pendant(c context.Context, pid int64) (pendantPHP *model.PendantPHP, err error) {
var pendant *usmdl.Pendant
ip := metadata.String(c, metadata.RemoteIP)
if pendant, err = s.dao.Pendant(c, pid, ip); err != nil {
log.Error("s.dao.Group(%d) error(%v)", pid, err)
return
}
pendantPHP = &model.PendantPHP{}
pendantPHP.Name = pendant.Name
pendantPHP.Pid = pendant.ID
pendantPHP.Image = model.FormatImgURL(pid, pendant.Image)
pendantPHP.ImageModel = model.FormatImgURL(pid, pendant.ImageModel)
return
}
// Group return pendant group info.
func (s *Service) Group(c context.Context, mid int64) (groupPHP []*model.GroupPHP, err error) {
var groups []*usmdl.PendantGroupInfo
ip := metadata.String(c, metadata.RemoteIP)
if groups, err = s.dao.Group(c, ip); err != nil {
log.Error("s.dao.Group(%d) error(%v)", mid, err)
return
}
for _, g := range groups {
if g.ID == 30 || g.ID == 31 {
continue
}
for _, p := range g.SubPendant {
p.BCoin = p.BCoin / 100
p.Image = model.FormatImgURL(mid, p.Image)
p.ImageModel = model.FormatImgURL(mid, p.ImageModel)
}
gh := &model.GroupPHP{}
gh.Name = g.Name
gh.Count = g.Number
gh.Pendant = g.SubPendant
groupPHP = append(groupPHP, gh)
}
return
}
// GroupEntry return vip pendant.
func (s *Service) GroupEntry(c context.Context, mid int64) (entryPHP []*model.GroupEntryPHP, err error) {
var group *usmdl.PendantGroupInfo
ip := metadata.String(c, metadata.RemoteIP)
if group, err = s.dao.GroupEntry(c, ip); err != nil {
log.Error("s.dao.GroupEntry(%d) error(%v)", mid, ip)
return
}
if group == nil {
log.Info("s.dao.GroupEntry(%d) result value is nil", mid)
return
}
for _, p := range group.SubPendant {
entry := &model.GroupEntryPHP{}
entry.Pid = p.ID
entry.Name = p.Name
entry.Money = p.Point
entry.Image = model.FormatImgURL(mid, p.Image)
entry.ImageModel = model.FormatImgURL(mid, p.ImageModel)
entryPHP = append(entryPHP, entry)
}
return
}
// GroupVIP return vip pendant.
func (s *Service) GroupVIP(c context.Context, mid int64) (vipPHP []*model.GroupVipPHP, err error) {
var group *usmdl.PendantGroupInfo
ip := metadata.String(c, metadata.RemoteIP)
if group, err = s.dao.GroupVip(c, ip); err != nil {
log.Error("s.dao.GroupVip(%d) error(%v)", mid, ip)
return
}
if group == nil {
log.Info("s.dao.GroupEntry(%d) result value is nil", mid)
return
}
for _, p := range group.SubPendant {
vip := &model.GroupVipPHP{}
vip.Pid = p.ID
vip.Name = p.Name
vip.Money = 0
vip.MoneyType = 3
vip.Expire = 2678400
vip.Image = model.FormatImgURL(mid, p.Image)
vip.ImageModel = model.FormatImgURL(mid, p.ImageModel)
vipPHP = append(vipPHP, vip)
}
return
}
// VipGet pc vip install pendant.
func (s *Service) VipGet(c context.Context, mid, pid int64, activated int8) (err error) {
err = s.Equip(c, mid, pid, int8(activated), usmdl.EquipFromVIP)
return
}
// CheckOrder check order by oid.
func (s *Service) CheckOrder(c context.Context, mid int64, orderID string) (err error) {
var hs []*usmdl.PendantOrderInfo
ip := metadata.String(c, metadata.RemoteIP)
if hs, _, err = s.dao.OrderHistory(c, mid, 1, 0, orderID, ip); err != nil {
log.Error("s.dao.OrderHistory(%d) error(%v)", mid, err)
return
}
if len(hs) == 0 {
err = ecode.PendantOrderNotFound
log.Info("s.dao.OrderHistory(%d) orderID(%d) error(%v)", mid, orderID, err)
return
}
if hs[0].Stauts != 1 {
err = ecode.PendantOrderNotFound
log.Info("s.dao.OrderHistory(%d) orderID(%d) order not complete", mid, orderID, err)
return
}
return
}
// Order pay pandent by coin/bcoin/point.
func (s *Service) Order(c context.Context, mid, pid, timeLength int64, moneyType int8) (res interface{}, err error) {
var payInfo *usmdl.PayInfo
ip := metadata.String(c, metadata.RemoteIP)
if payInfo, err = s.dao.Order(c, mid, pid, timeLength, moneyType, ip); err != nil {
log.Error("s.dao.Order(%d) error(%v)", mid, err)
return
}
if payInfo != nil {
payInfo.PayURL = "https://pay.bilibili.com" + payInfo.PayURL
res = payInfo
return
}
if moneyType == 2 {
log.Info("s.dao.Order(%d) pid(%d) buy type with point", mid, pid)
s.Equip(c, mid, pid, 2, usmdl.EquipFromPackage)
}
var pkgs []*usmdl.PendantPackage
if pkgs, err = s.dao.Packages(c, mid, ip); err != nil {
log.Error("s.dao.Packages(%d) error(%v)", mid, err)
return
}
var pendant *usmdl.PendantPackage
for _, pkg := range pkgs {
if pkg.Pid == pid {
pendant = pkg
}
}
if pendant != nil {
res = &struct {
Msg string `json:"msg"`
Expire int64 `json:"expire"`
}{
Msg: "您已成功购买" + pendant.Pendant.Name,
Expire: pendant.Expires,
}
}
return
}
// My get my pandent
func (s *Service) My(c context.Context, mid int64) (my []*model.MyPHP, err error) {
var equip *usmdl.PendantEquip
ip := metadata.String(c, metadata.RemoteIP)
if equip, err = s.usRPC.Equipment(c, &usmdl.ArgEquipment{Mid: mid, IP: ip}); err != nil {
log.Error("s.usRPC.Equipment(%d) error(%v)", mid, err)
return
}
var pkgs []*usmdl.PendantPackage
if pkgs, err = s.dao.Packages(c, mid, ip); err != nil {
log.Error("s.dao.Packages(%d) error(%v)", mid, err)
return
}
for _, pkg := range pkgs {
m := &model.MyPHP{}
m.Pid = pkg.Pid
m.Name = pkg.Pendant.Name
m.MoneyType = int8(pkg.Type)
m.Image = model.FormatImgURL(mid, pkg.Pendant.Image)
m.ImageModel = model.FormatImgURL(mid, pkg.Pendant.ImageModel)
m.Expire = pkg.Expires
m.IsOnline = 1
if equip != nil && equip.Pid == pkg.Pid {
m.IsActivated = 1
}
my = append(my, m)
}
return
}
// MyHistory get my pandent buy history.
func (s *Service) MyHistory(c context.Context, mid, page int64) (res map[string]interface{}, err error) {
var (
hs []*usmdl.PendantOrderInfo
myhs []*model.MyHistoryPHP
count map[string]int64
ip = metadata.String(c, metadata.RemoteIP)
)
if hs, count, err = s.dao.OrderHistory(c, mid, page, 0, "", ip); err != nil {
log.Error("s.dao.OrderHistory(%d) error(%v)", mid, err)
return
}
if len(hs) == 0 {
log.Info("s.dao.OrderHistory(%d) result len eq(0)", mid)
return
}
for _, h := range hs {
my := &model.MyHistoryPHP{}
my.Pid = h.Pid
my.Image = model.FormatImgURL(mid, h.Image)
my.Name = h.Name
my.BuyTime = h.BuyTime
my.PayID = h.PayID
my.Cost = h.Cost
my.TimeLength = h.TimeLength
myhs = append(myhs, my)
}
res = make(map[string]interface{})
count["page_count"] = int64(math.Ceil(float64(count["result_count"]) / float64(count["page_size"])))
res["page"] = count
res["result"] = myhs
return
}

View File

@@ -0,0 +1,12 @@
package usersuit
import (
"context"
usmdl "go-common/app/service/main/usersuit/model"
)
// PointFlag .
func (s *Service) PointFlag(c context.Context, arg *usmdl.ArgMID) (res *usmdl.PointFlag, err error) {
return s.usRPC.PointFlag(c, arg)
}

View File

@@ -0,0 +1,208 @@
package usersuit
import (
"context"
"fmt"
"reflect"
"testing"
usmdl "go-common/app/service/main/usersuit/model"
usrpc "go-common/app/service/main/usersuit/rpc/client"
"github.com/bouk/monkey"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_Equip(t *testing.T) {
// 1背包里只要存在挂件且来源是背包不论挂件是否为大会员的都能佩戴 2背包里不存在挂件但来源是大会员挂件也可以佩戴反之报错用例如下
Convey("Equip interface", t, func() {
var (
c = context.Background()
)
// 穿戴一个非vip挂件但是挂件来源是vip报错
Convey(" wear vip pendant", t, func() {
var ArgEquip = &usmdl.ArgEquip{
Mid: 111001965,
Pid: 98,
Status: 2, //1 卸载 2 佩戴
Source: 2, // 0 未知 1背包 2 vip
}
guard := monkey.PatchInstanceMethod(reflect.TypeOf(s.usRPC), "Equip", func(_ *usrpc.Service2, _ context.Context, _ *usmdl.ArgEquip) error {
return fmt.Errorf("wear not vip pendant,but source is EquipFromVip")
})
defer guard.Unpatch()
err := s.usRPC.Equip(c, ArgEquip)
Convey("the pendant is not vip pendant,then err should not be nil", t, func() {
So(err, ShouldNotBeNil)
})
})
// 穿戴一个vip挂件但是挂件来源是背包(前提:背包里存在该挂件),正确
Convey(" wear vip pendant", t, func() {
var ArgEquip = &usmdl.ArgEquip{
Mid: 111001965,
Pid: 102,
Status: 2, //1 卸载 2 佩戴
Source: 1, // 0 未知 1背包 2 vip
}
guard := monkey.PatchInstanceMethod(reflect.TypeOf(s.usRPC), "Equip", func(_ *usrpc.Service2, _ context.Context, _ *usmdl.ArgEquip) error {
return nil
})
defer guard.Unpatch()
err := s.usRPC.Equip(c, ArgEquip)
Convey("wear vip pendant and this pendant exist in package, then err should be nil", t, func() {
So(err, ShouldBeNil)
})
})
// 穿戴挂件与来源一致 vip挂件
Convey(" wear vip pendant", t, func() {
var ArgEquip = &usmdl.ArgEquip{
Mid: 111001965,
Pid: 103,
Status: 2, //1 卸载 2 佩戴
Source: 2, // 0 未知 1背包 2 vip
}
guard := monkey.PatchInstanceMethod(reflect.TypeOf(s.usRPC), "Equip", func(_ *usrpc.Service2, _ context.Context, _ *usmdl.ArgEquip) error {
return nil
})
defer guard.Unpatch()
err := s.usRPC.Equip(c, ArgEquip)
Convey("the pendant is vip pendant and source is EquipFromVip,then err should be nil", t, func() {
So(err, ShouldBeNil)
})
})
// 穿戴挂件与来源一致 :背包挂件(背包存在该挂件)
Convey(" wear vip pendant", t, func() {
var ArgEquip = &usmdl.ArgEquip{
Mid: 111001965,
Pid: 98,
Status: 2, //1 卸载 2 佩戴
Source: 1, // 0 未知 1背包 2 vip
}
guard := monkey.PatchInstanceMethod(reflect.TypeOf(s.usRPC), "Equip", func(_ *usrpc.Service2, _ context.Context, _ *usmdl.ArgEquip) error {
return nil
})
defer guard.Unpatch()
err := s.usRPC.Equip(c, ArgEquip)
Convey("wear a pkg pendant and package exist the pendant and source is EquipFromPackage, then err should be nil", t, func() {
So(err, ShouldBeNil)
})
})
// 穿戴一个背包里不存在的挂件但是挂件来源是背包非vip挂件,报错
Convey(" wear vip pendant", t, func() {
var ArgEquip = &usmdl.ArgEquip{
Mid: 111001965,
Pid: 99,
Status: 2, //1 卸载 2 佩戴
Source: 1, // 0 未知 1背包 2 vip
}
guard := monkey.PatchInstanceMethod(reflect.TypeOf(s.usRPC), "Equip", func(_ *usrpc.Service2, _ context.Context, _ *usmdl.ArgEquip) error {
return fmt.Errorf("pendant is not exist, err_code: 64101")
})
defer guard.Unpatch()
err := s.usRPC.Equip(c, ArgEquip)
Convey("wear a pendant which is not exist in package and source is EquipFromPackage, then err should not be nil", t, func() {
So(err, ShouldNotBeNil)
})
})
// 卸下挂件(挂件存在),不会受到 source 的影响
Convey(" take off pkg pendant", t, func() {
var ArgEquip = &usmdl.ArgEquip{
Mid: 111001965, Pid: 98, Status: 1, Source: 2,
}
guard := monkey.PatchInstanceMethod(reflect.TypeOf(s.usRPC), "Equip", func(_ *usrpc.Service2, _ context.Context, _ *usmdl.ArgEquip) error {
return nil
})
defer guard.Unpatch()
err := s.usRPC.Equip(c, ArgEquip)
Convey("take off pendant is not be affected by source, then err should not be nil", t, func() {
So(err, ShouldBeNil)
})
})
Convey(" take off vip pendant", t, func() {
var ArgEquip = &usmdl.ArgEquip{
Mid: 111001965, Pid: 102, Status: 1, Source: 2,
}
guard := monkey.PatchInstanceMethod(reflect.TypeOf(s.usRPC), "Equip", func(_ *usrpc.Service2, _ context.Context, _ *usmdl.ArgEquip) error {
return nil
})
defer guard.Unpatch()
err := s.usRPC.Equip(c, ArgEquip)
Convey("take off pendant is not be affected by source, then err should not be nil", t, func() {
So(err, ShouldBeNil)
})
})
})
}
//func TestService_Equip(t *testing.T) {
// Convey("Equip interface", t, func() {
// So(s.Equip(context.Background(), 1, 1, 2, 1), ShouldBeNil)
// })
//}
func TestService_Equipment(t *testing.T) {
Convey("Equipment interface", t, func() {
equip, err := s.Equipment(context.Background(), 1)
So(err, ShouldBeNil)
So(equip, ShouldNotBeEmpty)
})
}
func TestService_Pendant(t *testing.T) {
Convey("Pendant interface", t, func() {
pendant, err := s.Pendant(context.Background(), 1)
So(err, ShouldBeNil)
So(pendant, ShouldNotBeEmpty)
})
}
func TestService_GroupEntry(t *testing.T) {
Convey("GroupEntry interface", t, func() {
groups, err := s.GroupEntry(context.Background(), 1)
So(err, ShouldBeNil)
So(groups, ShouldNotBeEmpty)
})
}
func TestService_GroupVIP(t *testing.T) {
Convey("GroupVIP interface", t, func() {
vips, err := s.GroupVIP(context.Background(), 1)
So(err, ShouldBeNil)
So(vips, ShouldNotBeEmpty)
})
}
func TestService_VipGet(t *testing.T) {
Convey("VipGet interface", t, func() {
So(s.VipGet(context.Background(), 1, 1, 2), ShouldBeNil)
})
}
func TestService_CheckOrder(t *testing.T) {
Convey("CheckOrder interface", t, func() {
So(s.CheckOrder(context.Background(), 1, "lalala"), ShouldBeNil)
})
}
func TestService_My(t *testing.T) {
Convey("My interface", t, func() {
my, err := s.My(context.Background(), 1)
So(err, ShouldBeNil)
So(my, ShouldNotBeEmpty)
})
}
func TestService_MyHistory(t *testing.T) {
Convey("MyHistory interface", t, func() {
res, err := s.MyHistory(context.Background(), 1, 1)
So(err, ShouldBeNil)
So(res, ShouldNotBeEmpty)
})
}

View File

@@ -0,0 +1,46 @@
package usersuit
import (
"context"
"go-common/app/interface/main/account/conf"
"go-common/app/interface/main/account/dao/usersuit"
"go-common/app/interface/main/account/dao/vip"
accrpc "go-common/app/service/main/account/rpc/client"
coinrpc "go-common/app/service/main/coin/api/gorpc"
memrpc "go-common/app/service/main/member/api/gorpc"
usrpc "go-common/app/service/main/usersuit/rpc/client"
)
// Service struct.
type Service struct {
c *conf.Config
dao *usersuit.Dao
vipDao *vip.Dao
usRPC *usrpc.Service2
accRPC *accrpc.Service3
coinRPC *coinrpc.Service
memRPC *memrpc.Service
}
// New a pendant service
func New(c *conf.Config) (s *Service) {
s = &Service{
c: c,
dao: usersuit.New(c),
vipDao: vip.New(c),
usRPC: usrpc.New(c.RPCClient2.Usersuit),
memRPC: memrpc.New(c.RPCClient2.Member),
accRPC: accrpc.New3(c.RPCClient2.Account),
coinRPC: coinrpc.New(c.RPCClient2.Coin),
}
return
}
// Ping check server ok.
func (s *Service) Ping(c context.Context) (err error) {
return
}
// Close dao.
func (s *Service) Close() {}

View File

@@ -0,0 +1,19 @@
package usersuit
import (
"flag"
"go-common/app/interface/main/account/conf"
)
var (
s *Service
)
func init() {
flag.Set("conf", "../../cmd/account-interface-example.toml")
if err := conf.Init(); err != nil {
panic(err)
}
s = New(conf.Conf)
}

View File

@@ -0,0 +1,79 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"associate_outer_test.go",
"coupon_test.go",
"manager_test.go",
"panel_test.go",
"vip_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/account/conf:go_default_library",
"//app/interface/main/account/model:go_default_library",
"//app/service/main/vip/model:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"associate.go",
"associate_limit.go",
"associate_outer.go",
"coupon.go",
"manager.go",
"panel.go",
"privilege.go",
"resource.go",
"tips.go",
"vip.go",
"welfare.go",
],
importpath = "go-common/app/interface/main/account/service/vip",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/account/conf:go_default_library",
"//app/interface/main/account/dao/vip:go_default_library",
"//app/interface/main/account/model:go_default_library",
"//app/service/main/coupon/model:go_default_library",
"//app/service/main/relation/model:go_default_library",
"//app/service/main/relation/rpc/client:go_default_library",
"//app/service/main/resource/model:go_default_library",
"//app/service/main/resource/rpc/client:go_default_library",
"//app/service/main/vip/api:go_default_library",
"//app/service/main/vip/model:go_default_library",
"//app/service/main/vip/rpc/client:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/metadata:go_default_library",
"//library/sync/errgroup:go_default_library",
"//vendor/github.com/pkg/errors: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,84 @@
package vip
import (
"context"
"encoding/json"
"go-common/app/interface/main/account/model"
vol "go-common/app/service/main/vip/model"
v1 "go-common/app/service/main/vip/api"
)
// BindInfoByMid bind info by mid[bilibili->third].
func (s *Service) BindInfoByMid(c context.Context, a *model.ArgBindInfo) (res *v1.BindInfoByMidReply, err error) {
return s.vipgRPC.BindInfoByMid(c, &v1.BindInfoByMidReq{
Mid: a.Mid,
AppId: a.AppID,
})
}
// CreateAssociateOrder create associate order.
func (s *Service) CreateAssociateOrder(c context.Context, req *model.ArgCreateAssociateOrder) (res map[string]interface{}, err error) {
var p *v1.CreateAssociateOrderReply
if p, err = s.vipgRPC.CreateAssociateOrder(c, &v1.CreateAssociateOrderReq{
Mid: req.Mid,
Month: req.Month,
Platform: req.Platform,
MobiApp: req.MobiApp,
Device: req.Device,
AppId: req.AppID,
AppSubId: req.AppSubID,
OrderType: int32(req.OrderType),
Dtype: int32(req.Dtype),
ReturnUrl: req.ReturnURL,
CouponToken: req.CouponToken,
Bmid: req.Bmid,
PanelType: req.PanelType,
Build: req.Build,
IP: req.IP,
}); err != nil {
return
}
json.Unmarshal([]byte(p.PayParam), &res)
return
}
// AssociatePanel associate panel.
func (s *Service) AssociatePanel(c context.Context, req *vol.ArgAssociatePanel) (res []*v1.AssociatePanelInfo, err error) {
var reply *v1.AssociatePanelReply
if reply, err = s.vipgRPC.AssociatePanel(c, &v1.AssociatePanelReq{
Mid: req.Mid,
SortTp: int32(req.SortTP),
IP: req.IP,
MobiApp: req.MobiApp,
Device: req.Device,
Platform: req.Platform,
PanelType: req.PanelType,
Build: req.Build,
}); err != nil {
return
}
res = reply.List
return
}
// EleRedPackages ele red packages.
func (s *Service) EleRedPackages(c context.Context) (res []*v1.ModelEleRedPackage, err error) {
var reply *v1.EleRedPackagesReply
if reply, err = s.vipgRPC.EleRedPackages(c, &v1.EleRedPackagesReq{}); err != nil {
return
}
res = reply.List
return
}
// EleSpecailFoods ele speacail foods.
func (s *Service) EleSpecailFoods(c context.Context) (res []*v1.ModelEleSpecailFoods, err error) {
var reply *v1.EleSpecailFoodsReply
if reply, err = s.vipgRPC.EleSpecailFoods(c, &v1.EleSpecailFoodsReq{}); err != nil {
return
}
res = reply.List
return
}

View File

@@ -0,0 +1,65 @@
package vip
import (
"time"
"go-common/library/ecode"
"go-common/library/log"
)
// ActivityTimeLimit activity time limit.
func (s *Service) ActivityTimeLimit(mid int64) error {
if len(s.c.Vipproperty.AssociateWhiteMidMap) > 0 && mid != 0 {
for _, v := range s.c.Vipproperty.AssociateWhiteMidMap {
if v == mid {
return nil
}
}
}
now := time.Now().Unix()
if s.c.Vipproperty.ActStartTime > now {
return ecode.VipActivityNotStart
}
if s.c.Vipproperty.ActEndTime < now {
return ecode.VipActivityHadEnd
}
return nil
}
// ActivityWhiteIPLimit act ip limit.
func (s *Service) ActivityWhiteIPLimit(appkey string, ip string) error {
var (
whiteips []string
ok bool
)
if whiteips, ok = s.c.Vipproperty.AssociateWhiteIPMap[appkey]; !ok {
log.Error("act ip limit appkey(%s) ip(%s)", appkey, ip)
return ecode.VipWhiteIPListErr
}
for _, v := range whiteips {
if v == ip {
return nil
}
}
log.Error("act ip limit appkey(%s) ip(%s)", appkey, ip)
return ecode.VipWhiteIPListErr
}
// ActivityWhiteOutOpenIDLimit act out open id limit.
func (s *Service) ActivityWhiteOutOpenIDLimit(openid string) error {
if len(s.c.Vipproperty.AssociateWhiteOutOpenIDMap) > 0 && openid != "" {
for _, v := range s.c.Vipproperty.AssociateWhiteOutOpenIDMap {
if v == openid {
return nil
}
}
}
now := time.Now().Unix()
if s.c.Vipproperty.ActStartTime > now {
return ecode.VipActivityNotStart
}
if s.c.Vipproperty.ActEndTime < now {
return ecode.VipActivityHadEnd
}
return nil
}

View File

@@ -0,0 +1,100 @@
package vip
import (
"bytes"
"context"
"go-common/app/interface/main/account/model"
v1 "go-common/app/service/main/vip/api"
"go-common/library/log"
)
// ElemeOAuthURI get ele oauth uri.
func (s *Service) ElemeOAuthURI(c context.Context, csrf string) string {
var buf bytes.Buffer
buf.WriteString(s.c.Vipproperty.EleOAuthURI)
buf.WriteString("?consumer_key=")
buf.WriteString(s.c.Vipproperty.EleConsumerKey)
buf.WriteString("&scope=user_basic_info&redirect_uri=")
buf.WriteString(s.c.Vipproperty.EleOAuthCallBackURI)
buf.WriteString("&state=")
buf.WriteString(csrf)
return buf.String()
}
// OpenIDByAuthCode third get open_id by auth code.
func (s *Service) OpenIDByAuthCode(c context.Context, a *model.ArgAuthCode) (res *model.OpenIDResp, err error) {
var (
data *model.OAuth2InfoResp
r *v1.RegisterOpenIDReply
)
//oauth2 token.
if data, err = s.vipDao.OAuth2ByCode(c, a); err != nil {
return
}
res = new(model.OpenIDResp)
if r, err = s.vipgRPC.RegisterOpenID(c, &v1.RegisterOpenIDReq{Mid: data.Mid, AppId: a.APPID}); err != nil {
return
}
res.OpenID = r.OpenId
return
}
// OpenAuthCallBack open auth callback[third->bilibili].
func (s *Service) OpenAuthCallBack(c context.Context, a *model.ArgOpenAuthCallBack) (uri string) {
var (
ret = "0"
err error
)
if _, err = s.vipgRPC.OpenAuthCallBack(c, &v1.OpenAuthCallBackReq{
Mid: a.Mid,
ThirdCode: a.ThirdCode,
AppId: a.AppID,
}); err != nil {
log.Error("vipSvc.OpenAuthCallBack(%+v) err(%+v)", a, err)
ret = "1"
}
uri = s.c.Vipproperty.ActivityURI + "?bind_ret=" + ret
return
}
// BilibiliPrizeGrant vip prize grant.
func (s *Service) BilibiliPrizeGrant(c context.Context, a *model.ArgBilibiliPrizeGrant) (res *v1.BilibiliPrizeGrantReply, err error) {
return s.vipgRPC.BilibiliPrizeGrant(c, &v1.BilibiliPrizeGrantReq{
PrizeKey: a.PrizeKey,
UniqueNo: a.UniqueNo,
OpenId: a.OpenID,
AppId: a.AppID,
})
}
// BilibiliVipGrant vip grant.
func (s *Service) BilibiliVipGrant(c context.Context, a *model.ArgBilibiliVipGrant) (err error) {
_, err = s.vipgRPC.BilibiliVipGrant(c, &v1.BilibiliVipGrantReq{
OpenId: a.OpenID,
AppId: a.AppID,
OutOpenId: a.OutOpenID,
OutOrderNo: a.OutOrderNO,
Duration: a.Duration,
})
return
}
// OpenBindByOutOpenID associate user bind by out_open_id [third -> bilibili].
func (s *Service) OpenBindByOutOpenID(c context.Context, a *model.ArgBind) (err error) {
_, err = s.vipgRPC.OpenBindByOutOpenID(c, &v1.OpenBindByOutOpenIDReq{
OpenId: a.OpenID,
OutOpenId: a.OutOpenID,
AppId: a.AppID,
})
return
}
// UserInfoByOpenID get userinfo by open_id.
func (s *Service) UserInfoByOpenID(c context.Context, a *model.ArgUserInfoByOpenID) (res *v1.UserInfoByOpenIDReply, err error) {
return s.vipgRPC.UserInfoByOpenID(c, &v1.UserInfoByOpenIDReq{
OpenId: a.OpenID,
Ip: a.IP,
AppId: a.AppID,
})
}

View File

@@ -0,0 +1,60 @@
package vip
import (
"context"
"fmt"
"go-common/app/interface/main/account/model"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
// go test -test.v -test.run TestServiceOpenIDByAuthCode
func TestServiceOpenIDByAuthCode(t *testing.T) {
Convey("TestServiceOpenIDByAuthCode", t, func() {
res, err := s.OpenIDByAuthCode(context.TODO(), &model.ArgAuthCode{})
fmt.Println("res", res)
So(err, ShouldBeNil)
})
}
// go test -test.v -test.run TestServiceOpenAuthCallBack
func TestServiceOpenAuthCallBack(t *testing.T) {
Convey("TestServiceOpenAuthCallBack", t, func() {
err := s.OpenAuthCallBack(context.TODO(), &model.ArgOpenAuthCallBack{})
So(err, ShouldBeNil)
})
}
// go test -test.v -test.run TestServiceBilibiliPrizeGrant
func TestServiceBilibiliPrizeGrant(t *testing.T) {
Convey("TestServiceBilibiliPrizeGrant", t, func() {
res, err := s.BilibiliPrizeGrant(context.TODO(), &model.ArgBilibiliPrizeGrant{
PrizeKey: "coupon_ele_1",
UniqueNo: "1x",
OpenID: "e11303e8c26268a6cbdc2dc7fce55199",
AppID: 32,
})
fmt.Println("res:", res)
So(err, ShouldBeNil)
})
}
func TestServiceOpenBindByOutOpenID(t *testing.T) {
Convey("TestServiceOpenBindByOutOpenID", t, func() {
err := s.OpenBindByOutOpenID(context.TODO(), &model.ArgBind{
AppID: 32,
OutOpenID: "o8f999ad5d724b4a2ljbp7cm",
OpenID: "e11303e8c26268a6cbdc2dc7fce55199",
})
So(err, ShouldBeNil)
})
}
func TestServiceElemeOAuthURI(t *testing.T) {
Convey("TestServiceElemeOAuthURI", t, func() {
url := s.ElemeOAuthURI(context.TODO(), "state")
fmt.Println("url-------", url)
So(url, ShouldNotBeNil)
})
}

View File

@@ -0,0 +1,47 @@
package vip
import (
"context"
"go-common/app/interface/main/account/model"
col "go-common/app/service/main/coupon/model"
v1 "go-common/app/service/main/vip/api"
vipml "go-common/app/service/main/vip/model"
)
// CouponBySuitID coupon by suit id.
func (s *Service) CouponBySuitID(c context.Context, mid int64, sid int64) (res *col.CouponAllowancePanelInfo, err error) {
res, err = s.vipRPC.CouponBySuitIDV2(c, &vipml.ArgCouponPanelV2{Mid: mid, Sid: sid})
return
}
// CouponBySuitIDV2 get coupon by mid and suit info.
func (s *Service) CouponBySuitIDV2(c context.Context, a *model.ArgCouponBySuitID) (res *v1.CouponBySuitIDReply, err error) {
return s.vipgRPC.CouponBySuitID(c, &v1.CouponBySuitIDReq{
Mid: a.Mid,
Sid: a.Sid,
MobiApp: a.MobiApp,
Device: a.Device,
Platform: a.Platform,
PanelType: a.PanelType,
Build: a.Build,
})
}
// CouponsForPanel coupon for panel.
func (s *Service) CouponsForPanel(c context.Context, mid int64, sid int64, platform string) (res *col.CouponAllowancePanelResp, err error) {
res, err = s.vipRPC.CouponsForPanel(c, &vipml.ArgCouponPanel{Mid: mid, Sid: sid, Platform: vipml.PlatformByName[platform]})
return
}
// CouponsForPanelV2 coupon for panel.
func (s *Service) CouponsForPanelV2(c context.Context, mid int64, sid int64) (res *col.CouponAllowancePanelResp, err error) {
res, err = s.vipRPC.CouponsForPanelV2(c, &vipml.ArgCouponPanelV2{Mid: mid, Sid: sid})
return
}
// CancelUseCoupon coupon cancel use.
func (s *Service) CancelUseCoupon(c context.Context, arg *vipml.ArgCancelUseCoupon) (err error) {
err = s.vipDao.CancelUseCoupon(c, arg)
return
}

View File

@@ -0,0 +1,17 @@
package vip
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
// go test -test.v -test.run TestServiceCouponsForPanel
func TestServiceCouponsForPanel(t *testing.T) {
Convey("TestServiceCouponsForPanel", t, func() {
res, err := s.CouponsForPanel(context.TODO(), int64(1), int64(96), "pc")
t.Logf("%v", res)
So(err, ShouldBeNil)
})
}

View File

@@ -0,0 +1,14 @@
package vip
import (
"context"
"go-common/app/interface/main/account/model"
)
// ManagerInfo manager info.
func (s *Service) ManagerInfo(c context.Context) (res *model.ManagerResp, err error) {
res = new(model.ManagerResp)
res.JointlyInfo, err = s.vipRPC.Jointly(c)
return
}

View File

@@ -0,0 +1,17 @@
package vip
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
// go test -test.v -test.run TestServiceManagerInfo
func TestServiceManagerInfo(t *testing.T) {
Convey("TestServiceManagerInfo", t, func() {
res, err := s.ManagerInfo(context.TODO())
t.Logf("res %+v", res)
So(err, ShouldBeNil)
})
}

View File

@@ -0,0 +1,220 @@
package vip
import (
"context"
"go-common/app/interface/main/account/model"
vipv1 "go-common/app/service/main/vip/api"
vipml "go-common/app/service/main/vip/model"
"go-common/library/log"
"go-common/library/net/metadata"
"go-common/library/sync/errgroup"
"github.com/pkg/errors"
)
// VipPanel .
func (s *Service) VipPanel(c context.Context, mid int64, a *model.VipPanelRes) (res *vipml.VipPirceResp, err error) {
ip := metadata.String(c, metadata.RemoteIP)
res, err = s.vipRPC.VipPanelInfo2(c, &vipml.ArgPanel{Mid: mid, SortTp: a.SortTP, IP: ip, Device: a.Device, MobiApp: a.MobiApp, Platform: a.Platform, PanelType: a.PanelType, SubType: a.SubType, Month: a.Month, Build: a.Build})
return
}
// VipPanel5 .
func (s *Service) VipPanel5(c context.Context, mid int64, a *model.VipPanelRes) (res *vipml.VipPirceResp5, err error) {
ip := metadata.String(c, metadata.RemoteIP)
res, err = s.vipRPC.VipPanelInfo5(c, &vipml.ArgPanel{Mid: mid, SortTp: a.SortTP, IP: ip, Device: a.Device, MobiApp: a.MobiApp, Platform: a.Platform, PanelType: a.PanelType, SubType: a.SubType, Month: a.Month, Build: a.Build})
return
}
// VipPanelV2 vip panel v2.
func (s *Service) VipPanelV2(c context.Context, a *model.ArgVipPanel) (res *model.VipPanelResp, err error) {
var (
g errgroup.Group
p *vipml.VipPirceResp5
ts []*vipml.TipsResp
)
res = new(model.VipPanelResp)
g.Go(func() (err error) {
if p, err = s.vipRPC.VipPanelInfo5(c, &vipml.ArgPanel{
Mid: a.Mid,
SortTp: a.SortTP,
IP: a.IP,
Device: a.Device,
MobiApp: a.MobiApp,
Platform: a.Platform,
PanelType: a.PanelType,
Build: a.Build,
}); err != nil || p == nil {
log.Error("s.vipRPC.VipPanelInfo2(%+v) error(%v)", a, err)
return
}
res.Vps = p.Vps
res.CodeSwitch = p.CodeSwitch
res.GiveSwitch = p.GiveSwitch
res.Privileges = p.Privileges
return
})
g.Go(func() (err error) {
if ts, err = s.vipRPC.Tips(c, &vipml.ArgTips{
Version: a.Build,
Platform: a.Platform,
Position: vipml.PanelPosition,
}); err != nil {
log.Error("s.vipRPC.Tips(%+v) error(%v)", a, err)
}
if len(ts) == 0 {
return
}
res.TipInfo = ts[0]
return
})
g.Go(func() (err error) {
if res.UserInfo, err = s.vipRPC.PanelExplain(c, &vipml.ArgPanelExplain{
Mid: a.Mid,
}); err != nil {
log.Error("s.vipRPC.PanelExplain(%+v) error(%v)", a, err)
}
return
})
if err = g.Wait(); err != nil {
err = errors.WithStack(err)
}
return
}
// VipPanelV8 vip panel v8
func (s *Service) VipPanelV8(c context.Context, a *model.ArgVipPanel) (res *model.VipPanelV8Resp, err error) {
var (
g errgroup.Group
p *vipml.VipPirceResp5
ts []*vipml.TipsResp
)
res = new(model.VipPanelV8Resp)
g.Go(func() (err error) {
if p, err = s.vipRPC.VipPanelInfo5(c, &vipml.ArgPanel{
Mid: a.Mid,
SortTp: a.SortTP,
IP: a.IP,
Device: a.Device,
MobiApp: a.MobiApp,
Platform: a.Platform,
PanelType: a.PanelType,
Build: a.Build,
}); err != nil || p == nil {
log.Error("s.vipRPC.VipPanelInfo2(%+v) error(%v)", a, err)
return
}
res.Vps = p.Vps
res.CodeSwitch = p.CodeSwitch
res.GiveSwitch = p.GiveSwitch
res.Privileges = p.Privileges
res.CouponInfo = p.CouponInfo
res.CouponSwith = p.CouponSwith
return
})
g.Go(func() (err error) {
if ts, err = s.vipRPC.Tips(c, &vipml.ArgTips{
Version: a.Build,
Platform: a.Platform,
Position: vipml.PanelPosition,
}); err != nil {
log.Error("s.vipRPC.Tips(%+v) error(%v)", a, err)
}
if len(ts) == 0 {
return
}
res.TipInfo = ts[0]
return
})
g.Go(func() (err error) {
if res.UserInfo, err = s.vipRPC.PanelExplain(c, &vipml.ArgPanelExplain{
Mid: a.Mid,
}); err != nil {
log.Error("s.vipRPC.PanelExplain(%+v) error(%v)", a, err)
}
return
})
g.Go(func() (err error) {
if res.AssociateVips, err = s.vipRPC.AssociateVips(c, &vipml.ArgAssociateVip{
Platform: a.Platform,
Device: a.Device,
MobiApp: a.MobiApp,
}); err != nil {
log.Error("s.vipRPC.AssociateVips(%+v) error(%v)", a, err)
}
return
})
if err = g.Wait(); err != nil {
err = errors.WithStack(err)
}
return
}
// VipPanelV9 vip panel v9
func (s *Service) VipPanelV9(c context.Context, a *model.ArgVipPanel) (res *model.VipPanelRespV9, err error) {
var (
p *vipv1.VipUserPanelReply
ts []*vipml.TipsResp
)
eg, ec := errgroup.WithContext(c)
res = new(model.VipPanelRespV9)
eg.Go(func() (err error) {
if p, err = s.vipgRPC.VipUserPanel(ec, &vipv1.VipUserPanelReq{
Mid: a.Mid,
SortTp: int32(a.SortTP),
Ip: a.IP,
Device: a.Device,
MobiApp: a.MobiApp,
Platform: a.Platform,
PanelType: a.PanelType,
Build: a.Build,
}); err != nil || p == nil {
log.Error("s.vipRPC.VipPanelInfo2(%+v) error(%v)", a, err)
return
}
res.Vps = p.PriceList
res.CodeSwitch = p.CodeSwitch
res.GiveSwitch = p.GiveSwitch
res.Privileges = p.Privileges
res.Coupon = p.Coupon
res.CouponSwith = p.CouponSwitch
return
})
eg.Go(func() (err error) {
if ts, err = s.vipRPC.Tips(ec, &vipml.ArgTips{
Version: a.Build,
Platform: a.Platform,
Position: vipml.PanelPosition,
}); err != nil {
log.Error("s.vipRPC.Tips(%+v) error(%v)", a, err)
}
if len(ts) == 0 {
return
}
res.TipInfo = ts[0]
return
})
eg.Go(func() (err error) {
if res.UserInfo, err = s.vipRPC.PanelExplain(ec, &vipml.ArgPanelExplain{
Mid: a.Mid,
}); err != nil {
log.Error("s.vipRPC.PanelExplain(%+v) error(%v)", a, err)
}
return
})
eg.Go(func() (err error) {
if res.AssociateVips, err = s.vipRPC.AssociateVips(ec, &vipml.ArgAssociateVip{
Platform: a.Platform,
Device: a.Device,
MobiApp: a.MobiApp,
}); err != nil {
log.Error("s.vipRPC.AssociateVips(%+v) error(%v)", a, err)
}
return
})
if err = eg.Wait(); err != nil {
err = errors.WithStack(err)
}
return
}

View File

@@ -0,0 +1,46 @@
package vip
import (
"context"
"fmt"
"testing"
"go-common/app/interface/main/account/model"
. "github.com/smartystreets/goconvey/convey"
)
// go test -test.v -test.run TestServiceVipPanelV2
func TestServiceVipPanelV2(t *testing.T) {
Convey("TestServiceVipPanelV2", t, func() {
res, err := s.VipPanelV2(context.TODO(), &model.ArgVipPanel{
Platform: "ios",
MobiApp: "mobi_app",
Device: "phone",
Build: 1000000,
Mid: 476853,
})
t.Logf("res %+v", res)
t.Logf("vps %+v", res.Vps)
t.Logf("Privileges %+v", res.Privileges)
t.Logf("TipInfo %+v", res.TipInfo)
t.Logf("UserInfo %+v", res.UserInfo)
So(err, ShouldBeNil)
})
}
// go test -test.v -test.run TestServiceVipPanelV8
func TestServiceVipPanelV8(t *testing.T) {
Convey("TestServiceVipPanelV8", t, func() {
res, err := s.VipPanelV8(context.Background(), &model.ArgVipPanel{
Platform: "android",
MobiApp: "android",
Device: "android",
})
fmt.Println("res,err", res, err)
fmt.Println("res:", res)
fmt.Println("res.AssociateVips:", res.AssociateVips)
fmt.Println("res.Vps:", res.Vps)
So(err, ShouldBeNil)
})
}

View File

@@ -0,0 +1,19 @@
package vip
import (
"context"
"go-common/app/service/main/vip/model"
)
// PrivilegebySid privilege by sid.
func (s *Service) PrivilegebySid(c context.Context, arg *model.ArgPrivilegeBySid) (res *model.PrivilegesResp, err error) {
res, err = s.vipRPC.PrivilegeBySid(c, arg)
return
}
// PrivilegebyType privilege by type.
func (s *Service) PrivilegebyType(c context.Context, arg *model.ArgPrivilegeDetail) (res []*model.PrivilegeDetailResp, err error) {
res, err = s.vipRPC.PrivilegeByType(c, arg)
return
}

View File

@@ -0,0 +1,81 @@
package vip
import (
"context"
"go-common/app/interface/main/account/model"
vipmod "go-common/app/service/main/vip/model"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/net/metadata"
"github.com/pkg/errors"
)
// CodeOpen .
func (s *Service) CodeOpen(c context.Context, mid int64, code, token, verify string) (codeInfo *model.ResourceCode, err error) {
var (
codeResp *model.ResourceCodeResq
)
if codeResp, err = s.vipDao.CodeOpen(c, mid, code, token, verify); err != nil {
err = errors.WithStack(err)
return
}
codeInfo = codeResp.Data
return
}
//CodeOpeneds sel code opened
func (s *Service) CodeOpeneds(c context.Context, arg *model.CodeInfoReq, ip string) (resp []*vipmod.CodeInfoResp, err error) {
if err = s.checkIP(arg.Appkey, ip); err != nil {
err = errors.WithStack(err)
return
}
if resp, err = s.vipDao.CodeOpeneds(c, arg, ip); err != nil {
err = errors.WithStack(err)
}
return
}
func (s *Service) checkIP(appkey, ip string) (err error) {
var (
strings []string
ok bool
)
if strings, ok = s.c.Vipproperty.CodeOpenwhiteIPMap[appkey]; !ok {
log.Error("checkIP s.c.Vipproperty.CodeOpenwhiteIPMap empty(%s)", appkey)
err = ecode.VipWhiteIPListErr
return
}
for _, v := range strings {
if v == ip {
return
}
}
log.Error("checkIP fail(%s, %s)", appkey, ip)
err = ecode.VipWhiteIPListErr
return
}
// CodeVerify .
func (s *Service) CodeVerify(c context.Context) (token *model.Token, err error) {
if token, err = s.vipDao.CodeVerify(c); err != nil {
err = errors.WithStack(err)
}
return
}
//UseBatch use resource batch
func (s *Service) UseBatch(c context.Context, arg *vipmod.ArgUseBatch) (err error) {
ip := metadata.String(c, metadata.RemoteIP)
if err = s.checkIP(arg.Appkey, ip); err != nil {
err = errors.WithStack(err)
return
}
if err = s.vipRPC.ResourceBatchOpenVip(c, arg); err != nil {
err = errors.WithStack(err)
return
}
return
}

View File

@@ -0,0 +1,40 @@
package vip
import (
"context"
"go-common/app/interface/main/account/model"
vipmol "go-common/app/service/main/vip/model"
"github.com/pkg/errors"
)
// Tips vip tips info.
func (s *Service) Tips(c context.Context, req *model.TipsReq) (res *vipmol.TipsResp, err error) {
var rs []*vipmol.TipsResp
arg := &vipmol.ArgTips{
Platform: req.Platform,
Version: req.Version,
Position: req.Position,
}
if rs, err = s.vipRPC.Tips(c, arg); err != nil {
err = errors.WithStack(err)
}
if len(rs) > 0 {
res = rs[0]
}
return
}
// TipsV2 vip tips info v2.
func (s *Service) TipsV2(c context.Context, req *model.TipsReq) (res []*vipmol.TipsResp, err error) {
arg := &vipmol.ArgTips{
Platform: req.Platform,
Version: req.Version,
Position: req.Position,
}
if res, err = s.vipRPC.Tips(c, arg); err != nil {
err = errors.WithStack(err)
}
return
}

View File

@@ -0,0 +1,183 @@
package vip
import (
"context"
"strconv"
"go-common/app/interface/main/account/conf"
"go-common/app/interface/main/account/dao/vip"
"go-common/app/interface/main/account/model"
mrl "go-common/app/service/main/relation/model"
rlrpc "go-common/app/service/main/relation/rpc/client"
resmdl "go-common/app/service/main/resource/model"
rscrpc "go-common/app/service/main/resource/rpc/client"
v1 "go-common/app/service/main/vip/api"
vipmod "go-common/app/service/main/vip/model"
viprpc "go-common/app/service/main/vip/rpc/client"
"go-common/library/log"
"go-common/library/net/metadata"
"github.com/pkg/errors"
)
// Service .
type Service struct {
// conf
c *conf.Config
// http
vipDao *vip.Dao
// vip rpc
vipRPC *viprpc.Service
relationRPC *rlrpc.Service
resourceRPC *rscrpc.Service
// vip service
vipgRPC v1.VipClient
}
// New create service instance and return.
func New(c *conf.Config) (s *Service) {
s = &Service{
c: c,
vipDao: vip.New(c),
vipRPC: viprpc.New(c.RPCClient2.Vip),
relationRPC: rlrpc.New(c.RPCClient2.Relation),
resourceRPC: rscrpc.New(c.RPCClient2.Resource),
}
vipgRPC, err := v1.NewClient(c.VipClient)
if err != nil {
panic(err)
}
s.vipgRPC = vipgRPC
return
}
// OrderStatus .
func (s *Service) OrderStatus(c context.Context, arg *vipmod.ArgDialog) (res *vipmod.OrderResult, err error) {
if res, err = s.vipRPC.OrderPayResult(c, arg); err != nil {
return
}
if res == nil || res.Dialog == nil {
log.Warn("s.vipRPC.OrderPayResult(%+v) get nil", arg)
return
}
if res.Dialog.Follow {
var (
f *mrl.Following
ferr error
ip = metadata.String(c, metadata.RemoteIP)
ar = &mrl.ArgRelation{Mid: arg.Mid, Fid: s.c.Vipproperty.OfficialMid, RealIP: ip}
)
if f, ferr = s.relationRPC.Relation(c, ar); ferr != nil {
log.Error("s.Relation(%+v) err(%v)", ar, ferr)
return
}
if f == nil {
return
}
// 如果已经关注就隐藏关注模块
res.Dialog.Follow = !f.Following()
}
return
}
//Unfrozen user unfrozen vip
func (s *Service) Unfrozen(c context.Context, mid int64) (err error) {
if err = s.vipRPC.Unfrozen(c, mid); err != nil {
err = errors.WithStack(err)
return
}
return
}
//FrozenTime get frozen time
func (s *Service) FrozenTime(c context.Context, mid int64) (stime int64, err error) {
if stime, err = s.vipRPC.SurplusFrozenTime(c, mid); err != nil {
err = errors.WithStack(err)
return
}
return
}
// ResourceBanner .
func (s *Service) ResourceBanner(c context.Context, arg *model.ArgResource) (res []*resmdl.Banner, err error) {
resID := ""
if model.IsIPhone(arg.Plat) {
resID = model.ResourceBannerIPhone
}
if model.IsAndroid(arg.Plat) {
resID = model.ResourceBannerAndroid
}
if model.IsIPad(arg.Plat) {
resID = model.ResourceBannerIPad
}
var argb = &resmdl.ArgBanner{
Plat: arg.Plat,
Build: arg.Build,
MID: arg.MID,
ResIDs: resID,
Channel: "master",
IP: metadata.String(c, metadata.RemoteIP),
Buvid: arg.Buvid,
Network: arg.Network,
MobiApp: arg.MobiApp,
Device: arg.Device,
}
bs, err := s.resourceRPC.Banners(c, argb)
if err != nil || bs == nil {
log.Error("s.resourceRPC.Banners(%v) error(%+v) or bs is nil", argb, err)
return
}
if len(bs.Banner) > 0 {
var rid int
rid, err = strconv.Atoi(resID)
if err != nil {
err = errors.WithStack(err)
return
}
res = bs.Banner[rid]
}
return
}
// ResourceBuy .
func (s *Service) ResourceBuy(c context.Context, arg *model.ArgResource) (res []*resmdl.Banner, err error) {
resID := ""
if model.IsIPhone(arg.Plat) {
resID = model.ResourceBuyIPhone
}
if model.IsAndroid(arg.Plat) {
resID = model.ResourceBuyAndroid
}
if model.IsIPad(arg.Plat) {
resID = model.ResourceBuyIPad
}
log.Info("ResourceBuy resID(%s) arg(%+v)", resID, arg)
var argb = &resmdl.ArgBanner{
Plat: arg.Plat,
Build: arg.Build,
MID: arg.MID,
ResIDs: resID,
Channel: "master",
IP: metadata.String(c, metadata.RemoteIP),
Buvid: arg.Buvid,
Network: arg.Network,
MobiApp: arg.MobiApp,
Device: arg.Device,
}
bs, err := s.resourceRPC.Banners(c, argb)
if err != nil || bs == nil {
log.Error("s.resourceRPC.Banners(%v) error(%+v) or bs is nil", argb, err)
return
}
log.Info("s.resourceRPC.Banners(%+v)", bs.Banner)
if len(bs.Banner) > 0 {
var rid int
rid, err = strconv.Atoi(resID)
if err != nil {
err = errors.WithStack(err)
return
}
res = bs.Banner[rid]
}
return
}

View File

@@ -0,0 +1,98 @@
package vip
import (
"context"
"flag"
"testing"
"go-common/app/interface/main/account/conf"
"go-common/app/interface/main/account/model"
vipmod "go-common/app/service/main/vip/model"
. "github.com/smartystreets/goconvey/convey"
)
var (
s *Service
)
func init() {
flag.Set("conf", "../../cmd/account-interface-example.toml")
var err error
if err = conf.Init(); err != nil {
panic(err)
}
s = New(conf.Conf)
}
func TestService_CodeOpen(t *testing.T) {
Convey("code open", t, func() {
codeInfo, err := s.CodeOpen(context.TODO(), 123, "7b6e2263b8355928", "fd09f95433ed4c579f03ca7112b843ab", "45tn")
t.Logf("%v", codeInfo)
So(err, ShouldBeNil)
})
}
func TestService_CodeVerify(t *testing.T) {
Convey("code verify", t, func() {
_, err := s.CodeVerify(context.TODO())
So(err, ShouldBeNil)
})
}
// go test -test.v -test.run TestServiceTips
func TestServiceTips(t *testing.T) {
Convey("TestServiceTips", t, func() {
req := &model.TipsReq{
Version: int64(6000),
Platform: "ios",
}
res, err := s.Tips(context.TODO(), req)
t.Logf("data(+%v)", res)
So(err, ShouldBeNil)
})
}
func TestService_CodeOpeneds(t *testing.T) {
Convey("test service code opened", t, func() {
arg := new(model.CodeInfoReq)
resp, err := s.CodeOpeneds(context.TODO(), arg, "127.0.0.1")
t.Logf("data(%+v)", resp)
So(err, ShouldBeNil)
})
}
func TestService_Unfrozen(t *testing.T) {
Convey("test unfrozen", t, func() {
err := s.Unfrozen(context.TODO(), 10001)
So(err, ShouldBeNil)
})
}
func TestService_FrozenTime(t *testing.T) {
Convey("test frozen time", t, func() {
ctime, err := s.FrozenTime(context.TODO(), 10001)
t.Logf("%+v", ctime)
So(err, ShouldBeNil)
})
}
func TestService_checkIp(t *testing.T) {
Convey("test check ip", t, func() {
err := s.checkIP("b2cf4e9dbe9fd2e3", "111.203.12.97")
So(err, ShouldBeNil)
err = s.checkIP("b2cf4e9dbe9fd2e31", "111.203.12.97")
So(err, ShouldNotBeNil)
})
}
func TestService_OrderStatus(t *testing.T) {
Convey("TestService_OrderStatus", t, func() {
arg := &vipmod.ArgDialog{OrderNo: "1"}
res, err := s.OrderStatus(context.Background(), arg)
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
})
}

View File

@@ -0,0 +1,63 @@
package vip
import (
"context"
"go-common/app/service/main/vip/api"
"go-common/library/log"
)
// WelfareList get welfare list
func (s *Service) WelfareList(c context.Context, tid, recommend, pn, ps int64) (res *v1.WelfareReply, err error) {
welfareReq := &v1.WelfareReq{Tid: tid, Recommend: recommend, Ps: ps, Pn: pn}
if res, err = s.vipgRPC.WelfareList(c, welfareReq); err != nil {
log.Error("vipSvc.WelfareList(%+v) err(%+v)", welfareReq, err)
}
return
}
// WelfareTypeList get welfare type list
func (s *Service) WelfareTypeList(c context.Context) (res *v1.WelfareTypeReply, err error) {
welfareTypeReq := &v1.WelfareTypeReq{}
if res, err = s.vipgRPC.WelfareTypeList(c, welfareTypeReq); err != nil {
log.Error("vipSvc.WelfareTypeList err(%+v)", err)
}
return
}
// WelfareInfo get welfare info
func (s *Service) WelfareInfo(c context.Context, wid, mid int64) (res *v1.WelfareInfoReply, err error) {
welfareInfoReq := &v1.WelfareInfoReq{Id: wid, Mid: mid}
if res, err = s.vipgRPC.WelfareInfo(c, welfareInfoReq); err != nil {
log.Error("vipSvc.WelfareInfo(%+v) err(%+v)", wid, err)
}
return
}
// WelfareReceive receive welfare
func (s *Service) WelfareReceive(c context.Context, wid, mid int64) (res *v1.WelfareReceiveReply, err error) {
welfareReceiveReq := &v1.WelfareReceiveReq{Wid: wid, Mid: mid}
if res, err = s.vipgRPC.WelfareReceive(c, welfareReceiveReq); err != nil {
log.Error("vipSvc.WelfareReceive(%+v) err(%+v)", wid, err)
}
return
}
// MyWelfare get my welfare
func (s *Service) MyWelfare(c context.Context, mid int64) (res *v1.MyWelfareReply, err error) {
myWelfareReq := &v1.MyWelfareReq{Mid: mid}
if res, err = s.vipgRPC.MyWelfare(c, myWelfareReq); err != nil {
log.Error("vipSvc.MyWelfare err(%+v)", err)
}
return
}