Initial commit

This commit is contained in:
Donny
2019-04-22 20:46:32 +08:00
commit 49ab8aadd1
25441 changed files with 4055000 additions and 0 deletions

View File

@@ -0,0 +1,73 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = [
"captcha.go",
"dao.go",
"databus.go",
"memcache.go",
"mysql.go",
"redis.go",
],
importpath = "go-common/app/interface/main/answer/dao",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/answer/conf:go_default_library",
"//app/interface/main/answer/model:go_default_library",
"//library/cache/memcache:go_default_library",
"//library/cache/redis:go_default_library",
"//library/database/sql:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/metadata:go_default_library",
"//library/queue/databus:go_default_library",
"//library/xstr: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/answer/dao/account:all-srcs",
"//app/interface/main/answer/dao/geetest:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)
go_test(
name = "go_default_test",
srcs = [
"captcha_test.go",
"dao_test.go",
"memcache_test.go",
"mysql_test.go",
"redis_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/answer/conf:go_default_library",
"//app/interface/main/answer/model:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)

View File

@@ -0,0 +1,50 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = ["pendant_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/answer/conf:go_default_library",
"//vendor/github.com/go-sql-driver/mysql:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = ["pendant.go"],
importpath = "go-common/app/interface/main/answer/dao/account",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/answer/conf:go_default_library",
"//app/interface/main/answer/model:go_default_library",
"//library/cache/memcache:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster: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,114 @@
package account
import (
"context"
"fmt"
"net/url"
"strconv"
"go-common/app/interface/main/answer/conf"
"go-common/app/interface/main/answer/model"
"go-common/library/cache/memcache"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"github.com/pkg/errors"
)
// Dao is elec dao.
type Dao struct {
c *conf.Config
mc *memcache.Pool
client *bm.Client
pendant string
beFormal string
extraIds string
}
const (
_wasFormal = -659
)
// New pendant dao
func New(c *conf.Config) (d *Dao) {
d = &Dao{
c: c,
mc: memcache.NewPool(c.Memcache.Config),
client: bm.NewClient(c.HTTPClient.Normal),
pendant: c.Host.API + _multiGivePendant,
beFormal: c.Host.Account + _beFormal,
extraIds: c.Host.ExtraIds,
}
return
}
const (
_multiGivePendant = "/x/internal/pendant/multiGrantByMid"
_beFormal = "/api/internal/member/beFormal"
)
// GivePendant send user pendant
func (d *Dao) GivePendant(c context.Context, mid int64, pid int64, days int, ip string) (err error) {
log.Info(" GivePendant (%d,%d,%d) ", mid, pid, days)
params := url.Values{}
params.Set("mids", strconv.FormatInt(mid, 10))
params.Set("pid", strconv.FormatInt(pid, 10))
params.Set("expire", strconv.FormatInt(int64(days), 10))
var res struct {
Code int `json:"code"`
}
if err = d.client.Post(c, d.pendant, ip, params, &res); err != nil {
log.Error("pendant url(%s) error(%v)", d.pendant+"?"+params.Encode(), err)
log.Error("GivePendant(%d,%d),err:%+v", mid, pid, err)
return
}
if res.Code != 0 {
err = fmt.Errorf("pendant GivePendant failed(%v)", res.Code)
log.Error(" d.client.Get(%s) error(%v)", d.pendant+"?"+params.Encode(), err)
return
}
return
}
// BeFormal become a full member
func (d *Dao) BeFormal(c context.Context, mid int64, ip string) (err error) {
params := url.Values{}
params.Set("mid", strconv.FormatInt(mid, 10))
var res struct {
Code int `json:"code"`
}
if err = d.client.Post(c, d.beFormal, ip, params, &res); err != nil {
err = errors.Wrapf(err, "beFormal url(%s)", d.beFormal+"?"+params.Encode())
log.Error("BeFormal(%d),err:%+v", mid, err)
return
}
if res.Code != 0 && res.Code != _wasFormal {
err = errors.WithStack(fmt.Errorf("beFormal(%d) failed(%v)", mid, res.Code))
log.Error("BeFormal(%d),res:%+v", mid, res)
return
}
log.Info("beFormal suc(%d) ", mid)
return
}
// ExtraIds BigData Extra Question ids.
func (d *Dao) ExtraIds(c context.Context, mid int64, ip string) (done []int64, pend []int64, err error) {
params := url.Values{}
params.Set("mid", strconv.FormatInt(mid, 10))
var res struct {
Code int `json:"code"`
Data *model.ExtraBigData
}
if err = d.client.Get(c, d.extraIds, ip, params, &res); err != nil {
log.Error("ExtraIds url(%s) error(%v)", d.extraIds+"?"+params.Encode(), err)
return
}
if res.Code != 0 || res.Data == nil {
err = fmt.Errorf("ExtraIds failed(%v)", res.Code)
log.Error(" d.client.Get(%s) res(%v) error(%v)", d.extraIds+"?"+params.Encode(), res, err)
return
}
done = res.Data.Done
pend = res.Data.Pend
return
}

View File

@@ -0,0 +1,74 @@
package account
import (
"context"
"flag"
"os"
"testing"
"go-common/app/interface/main/answer/conf"
_ "github.com/go-sql-driver/mysql"
. "github.com/smartystreets/goconvey/convey"
)
var d *Dao
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.account-law.answer")
flag.Set("conf_appid", "main.account-law.answer")
flag.Set("conf_token", "ba3ee255695e8d7b46782268ddc9c8a3")
flag.Set("tree_id", "25260")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_env", "10")
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/answer-test.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
os.Exit(m.Run())
}
// Test_BeFormal .
func Test_BeFormal(t *testing.T) {
Convey("Test_BeFormal", t, func() {
var (
c = context.Background()
mid = int64(100000245)
)
d.BeFormal(c, mid, "127.0.0.1")
})
}
// Test_GivePendant .
func Test_GivePendant(t *testing.T) {
Convey("Test_GivePendant", t, func() {
err := d.GivePendant(context.Background(), 21432418, 1, 1, "127.0.0.1")
So(err, ShouldBeNil)
})
}
// go test -test.v -test.run TestDaoExtraIds
func Test_ExtraIds(t *testing.T) {
Convey("Test_GivePendant", t, func() {
var (
err error
c = context.Background()
mid = int64(100000245)
ds, ps []int64
)
ds, ps, err = d.ExtraIds(c, mid, "127.0.0.1")
So(err, ShouldBeNil)
So(ds, ShouldNotBeNil)
So(ps, ShouldNotBeNil)
})
}

View File

@@ -0,0 +1,56 @@
package dao
import (
"context"
"net/url"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/net/metadata"
)
// Captcha Captcha.
func (d *Dao) Captcha(c context.Context) (string, string, error) {
params := url.Values{}
params.Set("bid", "answer")
res := &struct {
Code int `json:"code"`
Data struct {
Token string `json:"token"`
URL string `json:"url"`
} `json:"data"`
Msg string `json:"message"`
TTL int `json:"ttl"`
}{}
ip := metadata.String(c, metadata.RemoteIP)
if err := d.captcha.Get(c, d.c.Answer.CaptchaTokenURL, ip, params, res); err != nil {
log.Error("s.captcha.Get(%s) error(%v)", d.c.Answer.CaptchaTokenURL+"?"+params.Encode(), err)
return "", "", err
}
if res.Code != 0 {
log.Error("s.captcha.Get(%s?%s) code:%d", d.c.Answer.CaptchaTokenURL, params.Encode(), res.Code)
return "", "", ecode.Int(res.Code)
}
return res.Data.Token, res.Data.URL, nil
}
// Verify Verify.
func (d *Dao) Verify(c context.Context, token, code, ip string) error {
params := url.Values{}
params.Set("token", token)
params.Set("code", code)
res := &struct {
Code int `json:"code"`
Msg string `json:"message"`
TTL int `json:"ttl"`
}{}
if err := d.captcha.Post(c, d.c.Answer.CaptchaVerifyURL, ip, params, res); err != nil {
log.Error("s.captcha.POST(%s) error(%v)", d.c.Answer.CaptchaVerifyURL+"?"+params.Encode(), err)
return err
}
if res.Code != 0 {
log.Error("s.captcha.POST(%s?%s) code:%d", d.c.Answer.CaptchaVerifyURL, params.Encode(), res.Code)
return ecode.Int(res.Code)
}
return nil
}

View File

@@ -0,0 +1,40 @@
package dao
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestCaptcha(t *testing.T) {
convey.Convey("Captcha", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1, p2, err := d.Captcha(c)
ctx.Convey("Then err should be nil.p1,p2 should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(p2, convey.ShouldNotBeNil)
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestVerify(t *testing.T) {
convey.Convey("Verify", t, func(ctx convey.C) {
var (
c = context.Background()
token = ""
code = ""
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.Verify(c, token, code, "")
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,58 @@
package dao
import (
"time"
"go-common/app/interface/main/answer/conf"
"go-common/library/cache/memcache"
"go-common/library/cache/redis"
"go-common/library/database/sql"
httpx "go-common/library/net/http/blademaster"
"go-common/library/queue/databus"
)
// Dao struct answer history of Dao
type Dao struct {
c *conf.Config
db *sql.DB
redis *redis.Pool
mc *memcache.Pool
mcExpire int32
redisExpire int32
ansCountExpire int32
ansAddFlagExpire int32
answerBlockExpire int32
dbExtraAnswerRet *databus.Databus
captcha *httpx.Client
}
// New new a Dao and return.
func New(c *conf.Config) (d *Dao) {
d = &Dao{
c: c,
db: sql.NewMySQL(c.Mysql),
redis: redis.NewPool(c.Redis.Config),
mc: memcache.NewPool(c.Memcache.Config),
redisExpire: int32(time.Duration(c.Redis.Expire) / time.Second),
ansCountExpire: int32(time.Duration(c.Redis.AnsCountExpire) / time.Second),
ansAddFlagExpire: int32(time.Duration(c.Redis.AnsCountExpire) / time.Second),
mcExpire: int32(time.Duration(c.Memcache.Expire) / time.Second),
answerBlockExpire: int32(time.Duration(c.Memcache.AnswerBolckExpire) / time.Second),
dbExtraAnswerRet: databus.New(c.DataBus.ExtraAnswer),
captcha: httpx.NewClient(c.Captcha),
}
return
}
// Close close connections of mc, redis, db.
func (d *Dao) Close() {
if d.redis != nil {
d.redis.Close()
}
if d.mc != nil {
d.mc.Close()
}
if d.db != nil {
d.db.Close()
}
}

View File

@@ -0,0 +1,38 @@
package dao
import (
"flag"
"os"
"testing"
"go-common/app/interface/main/answer/conf"
)
var (
d *Dao
mid int64 = 7593623
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.account-law.answer")
flag.Set("conf_appid", "main.account-law.answer")
flag.Set("conf_token", "ba3ee255695e8d7b46782268ddc9c8a3")
flag.Set("tree_id", "25260")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_env", "10")
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/answer-test.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
os.Exit(m.Run())
}

View File

@@ -0,0 +1,17 @@
package dao
import (
"context"
"strconv"
"go-common/library/log"
)
// PubExtraRet pub extra msg into databus.
func (d *Dao) PubExtraRet(c context.Context, mid int64, msg interface{}) (err error) {
key := strconv.FormatInt(mid, 10)
if err = d.dbExtraAnswerRet.Send(c, key, msg); err != nil {
log.Error("d.dbExtraAnswerRet.Send(%s, %v) error (%v)", key, msg, err)
}
return
}

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 = ["dao_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/answer/conf:go_default_library",
"//vendor/github.com/bouk/monkey:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
"//vendor/gopkg.in/h2non/gock.v1:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = ["dao.go"],
importpath = "go-common/app/interface/main/answer/dao/geetest",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/answer/conf:go_default_library",
"//app/interface/main/answer/model:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster: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,151 @@
package geetest
import (
"context"
"crypto/tls"
"errors"
"io/ioutil"
"net"
"net/http"
"net/url"
"strconv"
"strings"
"time"
"go-common/app/interface/main/answer/conf"
"go-common/app/interface/main/answer/model"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
)
const (
_register = "/register.php"
_validate = "/validate.php"
)
// Dao is account dao.
type Dao struct {
c *conf.Config
// url
registerURI string
validateURI string
// http client
client *http.Client
clientx *bm.Client
}
// New new a dao.
func New(c *conf.Config) (d *Dao) {
d = &Dao{
c: c,
registerURI: c.Host.Geetest + _register,
validateURI: c.Host.Geetest + _validate,
// http client
client: NewClient(c.HTTPClient),
clientx: bm.NewClient(c.HTTPClient.Slow),
}
return
}
// PreProcess preprocessing the geetest and get to challenge
func (d *Dao) PreProcess(c context.Context, mid int64, ip, geeType string, gc conf.GeetestConfig, newCaptcha int) (challenge string, err error) {
var (
req *http.Request
res *http.Response
bs []byte
params url.Values
)
params = url.Values{}
params.Set("user_id", strconv.FormatInt(mid, 10))
params.Set("new_captcha", strconv.Itoa(newCaptcha))
params.Set("ip_address", ip)
params.Set("client_type", geeType)
params.Set("gt", gc.CaptchaID)
if req, err = http.NewRequest("GET", d.registerURI+"?"+params.Encode(), nil); err != nil {
log.Error("d.preprocess uri(%s) params(%s) error(%v)", d.validateURI, params.Encode(), err)
return
}
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
if res, err = d.client.Do(req); err != nil {
log.Error("client.Do(%s) error(%v)", d.validateURI+"?"+params.Encode(), err)
return
}
defer res.Body.Close()
if res.StatusCode >= http.StatusInternalServerError {
err = errors.New("http status code 5xx")
log.Error("gtServerErr uri(%s) error(%v)", d.validateURI+"?"+params.Encode(), err)
return
}
if bs, err = ioutil.ReadAll(res.Body); err != nil {
log.Error("ioutil.ReadAll(%s) uri(%s) error(%v)", bs, d.validateURI+"?"+params.Encode(), err)
return
}
if len(bs) != 32 {
log.Error("d.preprocess len(%s) the length not equate 32byte", string(bs))
return
}
challenge = string(bs)
return
}
// Validate recheck the challenge code and get to seccode
func (d *Dao) Validate(c context.Context, challenge, seccode, clientType, ip, captchaID string, mid int64) (res *model.ValidateRes, err error) {
params := url.Values{}
params.Set("seccode", seccode)
params.Set("challenge", challenge)
params.Set("captchaid", captchaID)
params.Set("client_type", clientType)
params.Set("ip_address", ip)
params.Set("json_format", "1")
params.Set("sdk", "golang_3.0.0")
params.Set("user_id", strconv.FormatInt(mid, 10))
params.Set("timestamp", strconv.FormatInt(time.Now().Unix(), 10))
req, err := http.NewRequest("POST", d.validateURI, strings.NewReader(params.Encode()))
if err != nil {
log.Error("http.NewRequest error(%v) | uri(%s) params(%s)", err, d.validateURI, params.Encode())
return
}
log.Info("Validate(%v) start", params)
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
if err = d.clientx.Do(c, req, &res); err != nil {
log.Error("d.client.Do error(%v) | uri(%s) params(%s) res(%v)", err, d.validateURI, params.Encode(), res)
return
}
log.Info("Validate(%v) suc", res)
return
}
// NewClient new a http client.
func NewClient(c *conf.HTTPClient) (client *http.Client) {
var (
transport *http.Transport
dialer *net.Dialer
)
dialer = &net.Dialer{
Timeout: time.Duration(c.Slow.Dial),
KeepAlive: time.Duration(c.Slow.KeepAlive),
}
transport = &http.Transport{
DialContext: dialer.DialContext,
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
client = &http.Client{
Transport: transport,
}
return
}
// GeeConfig get geetest config.
func (d *Dao) GeeConfig(t string, c *conf.Geetest) (gc conf.GeetestConfig, geetype string) {
switch t {
case "pc":
gc = c.PC
case "h5":
gc = c.H5
default:
gc = c.PC
}
geetype = "web"
return
}

View File

@@ -0,0 +1,237 @@
package geetest
import (
"context"
"flag"
"fmt"
"io"
"io/ioutil"
"net/http"
"net/url"
"os"
"reflect"
"strconv"
"strings"
"testing"
"time"
"go-common/app/interface/main/answer/conf"
"github.com/bouk/monkey"
"github.com/smartystreets/goconvey/convey"
gock "gopkg.in/h2non/gock.v1"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.account-law.answer")
flag.Set("conf_appid", "main.account-law.answer")
flag.Set("conf_token", "ba3ee255695e8d7b46782268ddc9c8a3")
flag.Set("tree_id", "25260")
flag.Set("conf_version", "docker-1")
flag.Set("deploy_env", "uat")
flag.Set("conf_env", "10")
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/answer-test.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
os.Exit(m.Run())
}
func httpMock(method, url string) *gock.Request {
r := gock.New(url)
r.Method = strings.ToUpper(method)
return r
}
func TestDaoPreProcess(t *testing.T) {
var (
c = context.Background()
mid = int64(2205)
ip = "127.0.0,1"
geeType = "1222"
gc = conf.GeetestConfig{CaptchaID: "22"}
newCaptcha = 1
)
convey.Convey("PreProcess", t, func(ctx convey.C) {
ctx.Convey("req, err = http.NewRequest;err!=nil", func(ctx convey.C) {
monkey.Patch(http.NewRequest, func(_ string, _ string, _ io.Reader) (_ *http.Request, _ error) {
return nil, fmt.Errorf("Error")
})
_, err := d.PreProcess(c, mid, ip, geeType, gc, newCaptcha)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
})
})
ctx.Convey("req, err = http.NewRequest;err==nil", func(ctx convey.C) {
ctx.Convey("res, err = d.client.Do; err != nil", func(ctx convey.C) {
monkey.PatchInstanceMethod(reflect.TypeOf(d.client), "Do", func(_ *http.Client, _ *http.Request) (_ *http.Response, _ error) {
return nil, fmt.Errorf("Error")
})
_, err := d.PreProcess(c, mid, ip, geeType, gc, newCaptcha)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
})
})
ctx.Convey("res, err = d.client.Do; err == nil", func(ctx convey.C) {
params := url.Values{}
params.Set("user_id", strconv.FormatInt(mid, 10))
params.Set("new_captcha", strconv.Itoa(newCaptcha))
params.Set("ip_address", ip)
params.Set("client_type", geeType)
params.Set("gt", gc.CaptchaID)
d.client.Transport = gock.DefaultTransport
ctx.Convey("res.StatusCode >= http.StatusInternalServerError", func(ctx convey.C) {
httpMock("GET", d.registerURI+"?"+params.Encode()).Reply(501)
_, err := d.PreProcess(c, mid, ip, geeType, gc, newCaptcha)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
})
})
ctx.Convey("res.StatusCode < http.StatusInternalServerError", func(ctx convey.C) {
httpMock("GET", d.registerURI+"?"+params.Encode()).Reply(200).SetHeaders(map[string]string{
"StatusCode": "200",
})
ctx.Convey("bs, err = ioutil.ReadAll(res.Body); err != nil ", func(ctx convey.C) {
monkey.Patch(ioutil.ReadAll, func(_ io.Reader) (_ []byte, _ error) {
return nil, fmt.Errorf("Error")
})
_, err := d.PreProcess(c, mid, ip, geeType, gc, newCaptcha)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
})
})
ctx.Convey("bs, err = ioutil.ReadAll(res.Body); err == nil ", func(ctx convey.C) {
ctx.Convey("len(bs) != 32 ", func(ctx convey.C) {
challenge, err := d.PreProcess(c, mid, ip, geeType, gc, newCaptcha)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(challenge, convey.ShouldBeEmpty)
ctx.So(err, convey.ShouldBeNil)
})
})
ctx.Convey("len(bs) == 32 ", func(ctx convey.C) {
var (
str = "testeeeeeeeeeeyyyyyyyyyyyyrrrrrr"
bs = []byte(str)
)
monkey.Patch(ioutil.ReadAll, func(_ io.Reader) (_ []byte, _ error) {
return bs, nil
})
challenge, err := d.PreProcess(c, mid, ip, geeType, gc, newCaptcha)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(challenge, convey.ShouldNotBeNil)
ctx.So(err, convey.ShouldBeNil)
})
})
})
})
})
})
ctx.Reset(func() {
gock.OffAll()
d.client.Transport = http.DefaultClient.Transport
monkey.UnpatchAll()
})
})
}
func TestDaoValidate(t *testing.T) {
var (
c = context.Background()
challenge = "1"
seccode = "127.0.0,1"
clientType = ""
ip = "1222"
captchaID = "22"
mid = int64(14771787)
)
convey.Convey("Validate", t, func(ctx convey.C) {
ctx.Convey("req, err = http.NewRequest;err!=nil", func(ctx convey.C) {
monkey.Patch(http.NewRequest, func(_ string, _ string, _ io.Reader) (_ *http.Request, _ error) {
return nil, fmt.Errorf("Error")
})
_, err := d.Validate(c, challenge, seccode, clientType, ip, captchaID, mid)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
})
})
ctx.Convey("req, err = http.NewRequest;err==nil", func(ctx convey.C) {
ctx.Convey("res, err = d.client.Do; err != nil", func(ctx convey.C) {
monkey.PatchInstanceMethod(reflect.TypeOf(d.client), "Do", func(_ *http.Client, _ *http.Request) (_ *http.Response, _ error) {
return nil, fmt.Errorf("Error")
})
_, err := d.Validate(c, challenge, seccode, clientType, ip, captchaID, mid)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
})
})
ctx.Convey("res, err = d.client.Do; err == nil", func(ctx convey.C) {
params := url.Values{}
params.Set("seccode", seccode)
params.Set("challenge", challenge)
params.Set("captchaid", captchaID)
params.Set("client_type", clientType)
params.Set("ip_address", ip)
params.Set("json_format", "1")
params.Set("sdk", "golang_3.0.0")
params.Set("user_id", strconv.FormatInt(mid, 10))
params.Set("timestamp", strconv.FormatInt(time.Now().Unix(), 10))
// *bm.Client
d.clientx.SetTransport(gock.DefaultTransport)
httpMock("POST", d.validateURI).Reply(200).JSON(`{"code":0}`)
_, err := d.Validate(c, challenge, seccode, clientType, ip, captchaID, mid)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
ctx.Reset(func() {
gock.OffAll()
d.clientx.SetTransport(http.DefaultClient.Transport)
monkey.UnpatchAll()
})
})
}
func TestDaoGeeConfig(t *testing.T) {
var gtc = &conf.Geetest{PC: conf.GeetestConfig{CaptchaID: "22", PrivateKEY: "123"}, H5: conf.GeetestConfig{CaptchaID: "22", PrivateKEY: "456"}}
convey.Convey("GeeConfi", t, func(ctx convey.C) {
ctx.Convey("t=pc", func(ctx convey.C) {
var t = "pc"
gc, geetype := d.GeeConfig(t, gtc)
ctx.Convey("gc=gtc.PC,geetype =web", func(ctx convey.C) {
ctx.So(gc, convey.ShouldResemble, gtc.PC)
ctx.So(geetype, convey.ShouldResemble, "web")
})
})
ctx.Convey("t=h5", func(ctx convey.C) {
var t = "h5"
gc, geetype := d.GeeConfig(t, gtc)
ctx.Convey("gc=gtc.H5,geetype =web", func(ctx convey.C) {
ctx.So(gc, convey.ShouldResemble, gtc.H5)
ctx.So(geetype, convey.ShouldResemble, "web")
})
})
ctx.Convey("t=", func(ctx convey.C) {
var t = ""
gc, geetype := d.GeeConfig(t, gtc)
ctx.Convey("gc=gtc.PC,geetype =web", func(ctx convey.C) {
ctx.So(gc, convey.ShouldResemble, gtc.PC)
ctx.So(geetype, convey.ShouldResemble, "web")
})
})
})
}

View File

@@ -0,0 +1,275 @@
package dao
import (
"context"
"fmt"
"go-common/app/interface/main/answer/model"
"go-common/library/cache/memcache"
"go-common/library/log"
)
const (
_answerTimeKey = "v3_at_%d" // key of user's answer limit time
_answerHistoryKey = "v3_ah_%d" // key of user's answer history
_answerQidListKey = "v3_aqbi_%d"
_answerExtraQidListKey = "v3_aql_%d_%d"
_answerBlockKey = "v3_ablk_%d" // key of user's answer block flag
_answerHistory = "hid_%d" // ah_hid
)
var (
_blockFlag = []byte("1")
)
func answerQidListKey(mid int64, t int8) (key string) {
switch t {
case model.BaseExtraPassQ:
key = fmt.Sprintf(_answerExtraQidListKey, t, mid)
case model.BaseExtraNoPassQ:
key = fmt.Sprintf(_answerExtraQidListKey, t, mid)
default:
key = fmt.Sprintf(_answerQidListKey, mid)
}
return
}
// pingMC ping memcache.
func (d *Dao) pingMC(c context.Context) (err error) {
conn := d.mc.Get(c)
defer conn.Close()
if err = conn.Set(&memcache.Item{
Key: "ping",
Value: []byte{1},
Expiration: d.mcExpire,
}); err != nil {
log.Error("conn.Set(ping, 1) error(%v)", err)
}
return
}
// ExpireCache get user's answer stime and base answer error times cache.
func (d *Dao) ExpireCache(c context.Context, mid int64) (at *model.AnswerTime, err error) {
key := fmt.Sprintf(_answerTimeKey, mid)
conn := d.mc.Get(c)
defer conn.Close()
item, err := conn.Get(key)
if err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
log.Error("conn.Get(%s) error(%v)", key, err)
return
}
at = &model.AnswerTime{}
if err = conn.Scan(item, at); err != nil {
log.Error("conn.Scan(%s) error(%v)", string(item.Value), err)
}
return
}
// SetExpireCache set user's answer stime and base answer error times cache.
func (d *Dao) SetExpireCache(c context.Context, mid int64, at *model.AnswerTime) (err error) {
key := fmt.Sprintf(_answerTimeKey, mid)
conn := d.mc.Get(c)
defer conn.Close()
if err = conn.Set(&memcache.Item{
Key: key,
Object: at,
Flags: memcache.FlagJSON,
Expiration: d.mcExpire,
}); err != nil {
log.Error("conn.Set(%s, %v) error(%v)", key, at, err)
}
return
}
// DelExpireCache delete user's answer stime and base answer error times cache.
func (d *Dao) DelExpireCache(c context.Context, mid int64) (err error) {
key := fmt.Sprintf(_answerTimeKey, mid)
conn := d.mc.Get(c)
defer conn.Close()
if err = conn.Delete(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
log.Error("conn.Delete(%s) error(%v)", key, err)
}
return
}
// HistoryCache get user's answer history cache
func (d *Dao) HistoryCache(c context.Context, mid int64) (ah *model.AnswerHistory, err error) {
key := fmt.Sprintf(_answerHistoryKey, mid)
conn := d.mc.Get(c)
defer conn.Close()
item, err := conn.Get(key)
if err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
log.Error("conn.Get(%s) error(%v)", key, err)
return
}
ah = &model.AnswerHistory{}
if err = conn.Scan(item, ah); err != nil {
log.Error("conn.Scan(%s) error(%v)", string(item.Value), err)
}
return
}
// SetHistoryCache set user's answer history cache
func (d *Dao) SetHistoryCache(c context.Context, mid int64, ah *model.AnswerHistory) (err error) {
key := fmt.Sprintf(_answerHistoryKey, mid)
conn := d.mc.Get(c)
defer conn.Close()
if err = conn.Set(&memcache.Item{
Key: key,
Object: ah,
Flags: memcache.FlagJSON,
Expiration: d.mcExpire,
}); err != nil {
log.Error("conn.Set(%s, %v) error(%v)", key, ah, err)
}
return
}
// DelHistoryCache delete user's answer history cache
func (d *Dao) DelHistoryCache(c context.Context, mid int64) (err error) {
key := fmt.Sprintf(_answerHistoryKey, mid)
conn := d.mc.Get(c)
defer conn.Close()
if err = conn.Delete(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
log.Error("DelHistoryCache(%d),err:%+v", mid, err)
}
return
}
// IdsCache get user's base question ids
func (d *Dao) IdsCache(c context.Context, mid int64, t int8) (ids []int64, err error) {
key := answerQidListKey(mid, t)
conn := d.mc.Get(c)
defer conn.Close()
item, err := conn.Get(key)
if err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
log.Error("d.IdsCache(%d,%d) error(%v)", mid, t, err)
return
}
if err = conn.Scan(item, &ids); err != nil {
log.Error("conn.Scan(%s) error(%v)", string(item.Value), err)
}
return
}
// SetIdsCache set user's base question ids
func (d *Dao) SetIdsCache(c context.Context, mid int64, ids []int64, t int8) (err error) {
key := answerQidListKey(mid, t)
conn := d.mc.Get(c)
defer conn.Close()
if err = conn.Set(&memcache.Item{
Key: key,
Object: ids,
Flags: memcache.FlagJSON,
Expiration: d.mcExpire,
}); err != nil {
log.Error("conn.Set(%s, %v) error(%v)", key, ids, err)
}
return
}
// DelIdsCache delete user's base question ids
func (d *Dao) DelIdsCache(c context.Context, mid int64, t int8) (err error) {
key := answerQidListKey(mid, t)
conn := d.mc.Get(c)
defer conn.Close()
if err = conn.Delete(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
log.Error("DelIdsCache(%d,%d),err:%+v", mid, t, err)
}
return
}
// SetBlockCache set user's block.
func (d *Dao) SetBlockCache(c context.Context, mid int64) (err error) {
key := fmt.Sprintf(_answerBlockKey, mid)
conn := d.mc.Get(c)
defer conn.Close()
if err = conn.Set(&memcache.Item{
Key: key,
Value: _blockFlag,
Expiration: d.answerBlockExpire,
}); err != nil {
log.Error("conn.Store(%s, %v) error(%v)", key, string(_blockFlag), err)
}
return
}
// CheckBlockCache check user's block.
func (d *Dao) CheckBlockCache(c context.Context, mid int64) (exist bool, err error) {
key := fmt.Sprintf(_answerBlockKey, mid)
conn := d.mc.Get(c)
defer conn.Close()
_, err = conn.Get(key)
if err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
log.Error("conn.Get(%s) error(%v)", key, err)
return
}
exist = true
return
}
// HidCache get user's answer history cache
func (d *Dao) HidCache(c context.Context, hid int64) (ah *model.AnswerHistory, err error) {
key := fmt.Sprintf(_answerHistory, hid)
conn := d.mc.Get(c)
defer conn.Close()
item, err := conn.Get(key)
if err != nil {
if err == memcache.ErrNotFound {
err = nil
return
}
log.Error("conn.Get(%s) error(%v)", key, err)
return
}
ah = &model.AnswerHistory{}
if err = conn.Scan(item, ah); err != nil {
log.Error("conn.Scan(%s) error(%v)", string(item.Value), err)
}
return
}
// SetHidCache set user's answer history cache
func (d *Dao) SetHidCache(c context.Context, ah *model.AnswerHistory) (err error) {
key := fmt.Sprintf(_answerHistory, ah.Hid)
conn := d.mc.Get(c)
defer conn.Close()
if err = conn.Set(&memcache.Item{
Key: key,
Object: ah,
Flags: memcache.FlagJSON,
Expiration: d.mcExpire,
}); err != nil {
log.Error("conn.Set(%s, %v) error(%v)", key, ah, err)
}
return
}

View File

@@ -0,0 +1,110 @@
package dao
import (
"context"
"testing"
"time"
"go-common/app/interface/main/answer/model"
"github.com/smartystreets/goconvey/convey"
)
func TestAnswerQidListKey(t *testing.T) {
convey.Convey("answerQidListKey", t, func() {
key := answerQidListKey(7593623, model.BaseExtraPassQ)
convey.So(key, convey.ShouldNotBeNil)
})
}
func TestDaopingMC(t *testing.T) {
convey.Convey("pingMC", t, func() {
err := d.pingMC(context.Background())
convey.So(err, convey.ShouldBeNil)
})
}
func TestDaoSetExpireCache(t *testing.T) {
at := &model.AnswerTime{Etimes: 1}
convey.Convey("SetExpireCache", t, func() {
err := d.SetExpireCache(context.Background(), mid, at)
convey.So(err, convey.ShouldBeNil)
})
convey.Convey("ExpireCache", t, func() {
at, err := d.ExpireCache(context.Background(), mid)
convey.So(err, convey.ShouldBeNil)
convey.So(at, convey.ShouldNotBeNil)
})
}
func TestDaoDelExpireCache(t *testing.T) {
convey.Convey("DelExpireCache", t, func() {
err := d.DelExpireCache(context.Background(), 0)
convey.So(err, convey.ShouldBeNil)
})
}
func TestDaoSetHistoryCache(t *testing.T) {
his := &model.AnswerHistory{Hid: time.Now().Unix()}
convey.Convey("SetHistoryCache", t, func() {
err := d.SetHistoryCache(context.Background(), mid, his)
convey.So(err, convey.ShouldBeNil)
})
convey.Convey("HistoryCache", t, func() {
ah, err := d.HistoryCache(context.Background(), mid)
convey.So(err, convey.ShouldBeNil)
convey.So(ah, convey.ShouldNotBeNil)
})
}
func TestDaoSetIdsCache(t *testing.T) {
convey.Convey("SetIdsCache", t, func() {
err := d.SetIdsCache(context.Background(), mid, []int64{1, 2, 3}, 0)
convey.So(err, convey.ShouldBeNil)
})
convey.Convey("IdsCache", t, func() {
ids, err := d.IdsCache(context.Background(), mid, 0)
convey.So(err, convey.ShouldBeNil)
convey.So(ids, convey.ShouldNotBeNil)
})
convey.Convey("DelHistoryCache", t, func() {
err := d.DelHistoryCache(context.Background(), mid)
convey.So(err, convey.ShouldBeNil)
})
}
func TestDaoDelIdsCache(t *testing.T) {
convey.Convey("DelIdsCache", t, func() {
err := d.DelIdsCache(context.Background(), 0, 0)
convey.So(err, convey.ShouldBeNil)
})
}
func TestDaoSetBlockCache(t *testing.T) {
convey.Convey("SetBlockCache", t, func() {
err := d.SetBlockCache(context.Background(), 0)
convey.So(err, convey.ShouldBeNil)
})
}
func TestDaoCheckBlockCache(t *testing.T) {
convey.Convey("CheckBlockCache", t, func() {
exist, err := d.CheckBlockCache(context.Background(), 0)
convey.So(err, convey.ShouldBeNil)
convey.So(exist, convey.ShouldNotBeNil)
})
}
func TestDaoHidCache(t *testing.T) {
hid := time.Now().Unix()
his := &model.AnswerHistory{Hid: hid}
convey.Convey("SetHidCache", t, func() {
err := d.SetHidCache(context.Background(), his)
convey.So(err, convey.ShouldBeNil)
})
convey.Convey("HidCache", t, func() {
ah, err := d.HidCache(context.Background(), hid)
convey.So(err, convey.ShouldBeNil)
convey.So(ah, convey.ShouldNotBeNil)
})
}

View File

@@ -0,0 +1,319 @@
package dao
import (
"context"
xsql "database/sql"
"fmt"
"math/rand"
"time"
"go-common/app/interface/main/answer/model"
"go-common/library/database/sql"
"go-common/library/log"
"go-common/library/xstr"
"github.com/pkg/errors"
)
const (
_shard = 10
_getAnswerHistorySQL = "SELECT id,hid,mid,start_time,step_one_err_num,step_one_complete_time,step_two_start_time,complete_time,complete_result,score,is_pass_captcha,is_first_pass,passed_level,rank_id,step_extra_start_time,step_extra_complete_time,extra_score FROM answer_history_%d WHERE mid=? ORDER BY id DESC LIMIT 1"
_getHistoryByHidSQL = "SELECT id,hid,mid,start_time,step_one_err_num,step_one_complete_time,step_two_start_time,complete_time,complete_result,score,is_pass_captcha,is_first_pass,passed_level,rank_id,step_extra_start_time,step_extra_complete_time,extra_score FROM answer_history_%d WHERE hid=? ORDER BY id DESC LIMIT 1"
_sharingIndexSQL = "SELECT table_index FROM answer_history_mapping WHERE hid = ?"
_addAnswerHistorySQL = "INSERT INTO answer_history_%d (hid,mid,start_time,step_one_err_num,step_one_complete_time) VALUES (?,?,?,?,?)"
_setAnswerHistorySQL = "UPDATE answer_history_%d SET complete_result=?,complete_time=?,score=?,is_first_pass=?,passed_level=?,rank_id=? WHERE id=?"
_updateAnswerLevelSQL = "UPDATE answer_history_%d SET is_first_pass = ?,passed_level = ? WHERE id = ? "
_updateCaptchaSQL = "UPDATE answer_history_%d SET is_pass_captcha = ? WHERE id = ? "
_updateStepTwoTimeSQL = "UPDATE answer_history_%d SET step_two_start_time = ? WHERE id = ? "
_updateExtraStartTimeSQL = "UPDATE answer_history_%d SET step_extra_start_time = ? WHERE id = ? "
_updateExtraRetSQL = "UPDATE answer_history_%d SET step_extra_complete_time = ?,extra_score = ? WHERE id = ? "
_pendanHistorySQL = "SELECT hid,status FROM answer_pendant_history WHERE mid = ?"
_inPendantHistorySQL = "INSERT INTO answer_pendant_history (hid,mid) VALUES (?,?)"
_upPendantHistorySQL = "UPDATE answer_pendant_history SET status = 1 WHERE mid = ? AND hid = ? AND status = 0"
_allTypesSQL = "SELECT id,typename,parentid,lablename FROM ans_v3_question_type ORDER BY parentid;"
_questionByIdsSQL = "SELECT id,type_id,question,ans1,ans2,ans3,ans4,mid FROM ans_v3_question WHERE id IN (%s)"
_questionTypeSQL = "SELECT id,type_id FROM ans_v3_question WHERE state = ?"
_questionExtraByIdsSQL = "SELECT id,question,ans,status,origin_id,av_id,source,ctime,mtime FROM answer_extra_question WHERE state = 1 AND id IN (%s)"
_questionExtraTypeSQL = "SELECT id,ans FROM answer_extra_question WHERE isdel = 1 and state = 1 limit ?"
)
func hit(id int64) int64 {
return id % _shard
}
// PendantHistory .
func (d *Dao) PendantHistory(c context.Context, mid int64) (hid int64, status int8, err error) {
row := d.db.QueryRow(c, _pendanHistorySQL, mid)
if err = row.Scan(&hid, &status); err != nil {
if err == sql.ErrNoRows {
return 0, 0, nil
}
log.Error("PendantHistory(%d),error:%+v", mid, err)
return 0, 0, errors.WithStack(err)
}
return hid, status, nil
}
// History get user's answer history by mid.
func (d *Dao) History(c context.Context, mid int64) (res *model.AnswerHistory, err error) {
res = &model.AnswerHistory{}
row := d.db.QueryRow(c, fmt.Sprintf(_getAnswerHistorySQL, hit(mid)), mid)
if err = row.Scan(&res.ID, &res.Hid, &res.Mid, &res.StartTime, &res.StepOneErrTimes, &res.StepOneCompleteTime, &res.StepTwoStartTime, &res.CompleteTime,
&res.CompleteResult, &res.Score, &res.IsPassCaptcha, &res.IsFirstPass, &res.PassedLevel, &res.RankID, &res.StepExtraStartTime, &res.StepExtraCompleteTime, &res.StepExtraScore); err != nil {
if err == sql.ErrNoRows {
err = nil
} else {
log.Error("History(%d),error:%+v", mid, err)
}
}
return
}
// HistoryByHid get user's answer history by mid.
func (d *Dao) HistoryByHid(c context.Context, hid int64) (res *model.AnswerHistory, err error) {
res = &model.AnswerHistory{}
row := d.db.QueryRow(c, fmt.Sprintf(_getHistoryByHidSQL, hit(hid)), hid)
if err = row.Scan(&res.ID, &res.Hid, &res.Mid, &res.StartTime, &res.StepOneErrTimes, &res.StepOneCompleteTime, &res.StepTwoStartTime, &res.CompleteTime,
&res.CompleteResult, &res.Score, &res.IsPassCaptcha, &res.IsFirstPass, &res.PassedLevel, &res.RankID, &res.StepExtraStartTime, &res.StepExtraCompleteTime, &res.StepExtraScore); err != nil {
if err == sql.ErrNoRows {
err = nil
} else {
log.Error("HistoryByHid(%d),error:%+v", hid, err)
}
}
return
}
// OldHistory get user's answer history by hid and sharing index.
func (d *Dao) OldHistory(c context.Context, hid, idx int64) (res *model.AnswerHistory, err error) {
res = &model.AnswerHistory{}
row := d.db.QueryRow(c, fmt.Sprintf(_getHistoryByHidSQL, idx), hid)
if err = row.Scan(&res.ID, &res.Hid, &res.Mid, &res.StartTime, &res.StepOneErrTimes, &res.StepOneCompleteTime, &res.StepTwoStartTime, &res.CompleteTime,
&res.CompleteResult, &res.Score, &res.IsPassCaptcha, &res.IsFirstPass, &res.PassedLevel, &res.RankID, &res.StepExtraStartTime, &res.StepExtraCompleteTime, &res.StepExtraScore); err != nil {
if err == sql.ErrNoRows {
err = nil
} else {
log.Error("OldHistory(%d,%d),error:%+v", hid, idx, err)
}
}
return
}
// SharingIndexByHid get old history sharingIndex by hid
func (d *Dao) SharingIndexByHid(c context.Context, hid int64) (res int64, err error) {
row := d.db.QueryRow(c, _sharingIndexSQL, hid)
if err = row.Scan(&res); err != nil {
if err == sql.ErrNoRows {
err = nil
} else {
log.Error("OldHistory(%d),error:%+v", hid, err)
}
}
return
}
// AddPendantHistory .
func (d *Dao) AddPendantHistory(c context.Context, mid, hid int64) (affected int64, err error) {
var res xsql.Result
if res, err = d.db.Exec(c, _inPendantHistorySQL, hid, mid); err != nil {
log.Error("AddPendantHistory(%d,%d),error:%+v", mid, hid, err)
return
}
return res.RowsAffected()
}
// SetHistory set user's answer history by id.
func (d *Dao) SetHistory(c context.Context, mid int64, his *model.AnswerHistory) (affected int64, err error) {
var res xsql.Result
if res, err = d.db.Exec(c, fmt.Sprintf(_setAnswerHistorySQL, hit(mid)), his.CompleteResult, his.CompleteTime, his.Score, his.IsFirstPass, his.PassedLevel, his.RankID, his.ID); err != nil {
log.Error("setAnswerHistory: db.Exec(%d, %v) error(%v)", mid, his, err)
return
}
return res.RowsAffected()
}
// AddHistory add user's answer history by id.
func (d *Dao) AddHistory(c context.Context, mid int64, his *model.AnswerHistory) (affected int64, hid string, err error) {
var res xsql.Result
hid = fmt.Sprintf("%d%04d%02d", time.Now().Unix(), rand.Intn(9999), hit(mid))
if res, err = d.db.Exec(c, fmt.Sprintf(_addAnswerHistorySQL, hit(mid)), hid, his.Mid, his.StartTime, his.StepOneErrTimes, his.StepOneCompleteTime); err != nil {
log.Error("addAnswerHistory: db.Exec(%d, %v) error(%v)", mid, his, err)
return
}
affected, err = res.RowsAffected()
return
}
// UpdateLevel update answer history passedLevel and isFirstPass.
func (d *Dao) UpdateLevel(c context.Context, id int64, mid int64, isFirstPass, passedLevel int8) (ret int64, err error) {
var res xsql.Result
if res, err = d.db.Exec(c, fmt.Sprintf(_updateAnswerLevelSQL, hit(mid)), isFirstPass, passedLevel, id); err != nil {
log.Error("UpdateLevel: db.Exec(%d,%d,%d,%d) error(%v)", id, mid, isFirstPass, passedLevel, err)
return
}
return res.RowsAffected()
}
// UpdateCaptcha update answer history captcha.
func (d *Dao) UpdateCaptcha(c context.Context, id int64, mid int64, isPassCaptcha int8) (ret int64, err error) {
var res xsql.Result
if res, err = d.db.Exec(c, fmt.Sprintf(_updateCaptchaSQL, hit(mid)), isPassCaptcha, id); err != nil {
log.Error("UpdateCaptcha: db.Exec(%d, %d, %d) error(%v)", id, mid, isPassCaptcha, err)
return
}
return res.RowsAffected()
}
// UpdateStepTwoTime .
func (d *Dao) UpdateStepTwoTime(c context.Context, id int64, mid int64, t time.Time) (ret int64, err error) {
var res xsql.Result
if res, err = d.db.Exec(c, fmt.Sprintf(_updateStepTwoTimeSQL, hit(mid)), t, id); err != nil {
log.Error("UpdateCaptcha: db.Exec(%d,%d,%s) error(%v)", id, mid, t, err)
return
}
return res.RowsAffected()
}
// UpdateExtraStartTime update extra start time.
func (d *Dao) UpdateExtraStartTime(c context.Context, id int64, mid int64, t time.Time) (ret int64, err error) {
var res xsql.Result
if res, err = d.db.Exec(c, fmt.Sprintf(_updateExtraStartTimeSQL, hit(mid)), t, id); err != nil {
log.Error("updateExtraStartTime: db.Exec(%d, %d, %s) error(%v)", id, mid, t, err)
return
}
return res.RowsAffected()
}
// UpdateExtraRet update extra start time.
func (d *Dao) UpdateExtraRet(c context.Context, id int64, mid int64, t int64, extraScore int64) (ret int64, err error) {
var res xsql.Result
if res, err = d.db.Exec(c, fmt.Sprintf(_updateExtraRetSQL, hit(mid)), t, extraScore, id); err != nil {
log.Error("updateExtraRetSQL: db.Exec(%d, %d, %d, %d) error(%v)", id, mid, t, extraScore, err)
return
}
return res.RowsAffected()
}
// UpPendantHistory update pendant history.
func (d *Dao) UpPendantHistory(c context.Context, mid, hid int64) (ret int64, err error) {
var res xsql.Result
if res, err = d.db.Exec(c, _upPendantHistorySQL, mid, hid); err != nil {
log.Error("UpPendantHistory(%d,%d),error:%+v", mid, hid, err)
return
}
return res.RowsAffected()
}
// QidsExtraByState get extra question ids by check
func (d *Dao) QidsExtraByState(c context.Context, size int) (res []*model.ExtraQst, err error) {
var rows *sql.Rows
if rows, err = d.db.Query(c, _questionExtraTypeSQL, size); err != nil {
return
}
defer rows.Close()
for rows.Next() {
r := new(model.ExtraQst)
if err = rows.Scan(&r.ID, &r.Ans); err != nil {
log.Error("QidsExtraByState(%d),error:%+v", size, err)
res = nil
return
}
res = append(res, r)
}
err = rows.Err()
return
}
// ExtraByIds get extra question in idstr
func (d *Dao) ExtraByIds(c context.Context, ids []int64) (res map[int64]*model.ExtraQst, err error) {
var rows *sql.Rows
res = make(map[int64]*model.ExtraQst, len(ids))
idStr := xstr.JoinInts(ids)
if rows, err = d.db.Query(c, fmt.Sprintf(_questionExtraByIdsSQL, idStr)); err != nil {
log.Error("d.questionExtraByIds.Query error(%v)", err)
return
}
defer rows.Close()
for rows.Next() {
r := new(model.ExtraQst)
if err = rows.Scan(&r.ID, &r.Question, &r.Ans, &r.Status, &r.OriginID, &r.AvID, &r.Source, &r.Ctime, &r.Mtime); err != nil {
log.Error("row.Scan() error(%v)", err)
res = nil
return
}
res[r.ID] = r
}
err = rows.Err()
return
}
// Types get all types
func (d *Dao) Types(c context.Context) (res []*model.TypeInfo, err error) {
var rows *sql.Rows
if rows, err = d.db.Query(c, _allTypesSQL); err != nil {
log.Error("d.allTypesStmt.Query error(%v)", err)
return
}
defer rows.Close()
for rows.Next() {
r := new(model.TypeInfo)
if err = rows.Scan(&r.ID, &r.Name, &r.Parentid, &r.LabelName); err != nil {
log.Error("row.Scan() error(%v)", err)
res = nil
return
}
res = append(res, r)
}
err = rows.Err()
return
}
// ByIds get question in idStr
func (d *Dao) ByIds(c context.Context, ids []int64) (res map[int64]*model.Question, err error) {
var rows *sql.Rows
res = make(map[int64]*model.Question, len(ids))
idStr := xstr.JoinInts(ids)
if rows, err = d.db.Query(c, fmt.Sprintf(_questionByIdsSQL, idStr)); err != nil {
log.Error("d.queryQuestionByIdsStmt.Query error(%v)", err)
return
}
defer rows.Close()
for rows.Next() {
r := new(model.Question)
ans := make([]string, 4)
if err = rows.Scan(&r.ID, &r.TypeID, &r.Question, &ans[0], &ans[1], &ans[2], &ans[3], &r.Mid); err != nil {
log.Error("row.Scan() error(%v)", err)
res = nil
return
}
r.Ans = ans
res[r.ID] = r
}
err = rows.Err()
return
}
// QidsByState get question ids by check
func (d *Dao) QidsByState(c context.Context, state int8) (res []*model.Question, err error) {
var rows *sql.Rows
if rows, err = d.db.Query(c, _questionTypeSQL, state); err != nil {
log.Error("d.questionTypeStmt.Query error(%v)", err)
return
}
defer rows.Close()
for rows.Next() {
r := new(model.Question)
if err = rows.Scan(&r.ID, &r.TypeID); err != nil {
log.Error("row.Scan() error(%v)", err)
res = nil
return
}
res = append(res, r)
}
err = rows.Err()
return
}

View File

@@ -0,0 +1,177 @@
package dao
import (
"context"
"testing"
"time"
"go-common/app/interface/main/answer/model"
"github.com/smartystreets/goconvey/convey"
)
func TestHit(t *testing.T) {
convey.Convey("hit", t, func() {
p1 := hit(0)
convey.So(p1, convey.ShouldNotBeNil)
})
}
func TestDaoPendantHistory(t *testing.T) {
convey.Convey("PendantHistory", t, func() {
hid, status, err := d.PendantHistory(context.Background(), 0)
convey.So(err, convey.ShouldBeNil)
convey.So(status, convey.ShouldNotBeNil)
convey.So(hid, convey.ShouldNotBeNil)
})
}
func TestDaoHistory(t *testing.T) {
convey.Convey("History", t, func() {
res, err := d.History(context.Background(), 0)
convey.So(err, convey.ShouldBeNil)
convey.So(res, convey.ShouldNotBeNil)
})
}
func TestDaoHistoryByHid(t *testing.T) {
convey.Convey("HistoryByHid", t, func() {
res, err := d.HistoryByHid(context.Background(), 0)
convey.So(err, convey.ShouldBeNil)
convey.So(res, convey.ShouldNotBeNil)
})
}
func TestDaoOldHistory(t *testing.T) {
convey.Convey("OldHistory", t, func() {
res, err := d.OldHistory(context.Background(), 0, 0)
convey.So(err, convey.ShouldBeNil)
convey.So(res, convey.ShouldNotBeNil)
})
}
func TestDaoSharingIndexByHid(t *testing.T) {
convey.Convey("SharingIndexByHid", t, func() {
res, err := d.SharingIndexByHid(context.Background(), 0)
convey.So(err, convey.ShouldBeNil)
convey.So(res, convey.ShouldNotBeNil)
})
}
func TestDaoAddPendantHistory(t *testing.T) {
convey.Convey("AddPendantHistory", t, func() {
affected, err := d.AddPendantHistory(context.Background(), time.Now().Unix(), time.Now().Unix())
convey.So(err, convey.ShouldBeNil)
convey.So(affected, convey.ShouldNotBeNil)
})
}
func TestDaoHistorySuit(t *testing.T) {
var (
err error
affected int64
hid = time.Now().Unix()
)
ans := &model.AnswerHistory{
Hid: hid,
}
convey.Convey("AddHistory", t, func() {
affected, _, err = d.AddHistory(context.Background(), 0, ans)
convey.So(err, convey.ShouldBeNil)
convey.So(affected, convey.ShouldNotBeNil)
})
convey.Convey("HistoryByHid", t, func() {
ans, err = d.HistoryByHid(context.Background(), hid)
convey.So(err, convey.ShouldBeNil)
convey.So(affected, convey.ShouldNotBeNil)
})
convey.Convey("SetHistory", t, func() {
affected, err = d.SetHistory(context.Background(), 0, ans)
convey.So(err, convey.ShouldBeNil)
convey.So(affected, convey.ShouldNotBeNil)
})
}
func TestDaoUpdateLevel(t *testing.T) {
convey.Convey("UpdateLevel", t, func() {
ret, err := d.UpdateLevel(context.Background(), 0, 0, 0, 0)
convey.So(err, convey.ShouldBeNil)
convey.So(ret, convey.ShouldNotBeNil)
})
}
func TestDaoUpdateCaptcha(t *testing.T) {
convey.Convey("UpdateCaptcha", t, func() {
ret, err := d.UpdateCaptcha(context.Background(), 0, 0, 0)
convey.So(err, convey.ShouldBeNil)
convey.So(ret, convey.ShouldNotBeNil)
})
}
func TestDaoUpdateStepTwoTime(t *testing.T) {
convey.Convey("UpdateStepTwoTime", t, func() {
ret, err := d.UpdateStepTwoTime(context.Background(), 0, 0, time.Now())
convey.So(err, convey.ShouldBeNil)
convey.So(ret, convey.ShouldNotBeNil)
})
}
func TestDaoUpdateExtraStartTime(t *testing.T) {
convey.Convey("UpdateExtraStartTime", t, func() {
ret, err := d.UpdateExtraStartTime(context.Background(), 0, 0, time.Now())
convey.So(err, convey.ShouldBeNil)
convey.So(ret, convey.ShouldNotBeNil)
})
}
func TestDaoUpdateExtraRet(t *testing.T) {
convey.Convey("UpdateExtraRet", t, func() {
ret, err := d.UpdateExtraRet(context.Background(), 0, 0, 0, 0)
convey.So(err, convey.ShouldBeNil)
convey.So(ret, convey.ShouldNotBeNil)
})
}
func TestDaoUpPendantHistory(t *testing.T) {
convey.Convey("UpPendantHistory", t, func() {
ret, err := d.UpPendantHistory(context.Background(), 0, 0)
convey.So(err, convey.ShouldBeNil)
convey.So(ret, convey.ShouldNotBeNil)
})
}
func TestDaoQidsExtraByState(t *testing.T) {
convey.Convey("QidsExtraByState", t, func() {
_, err := d.QidsExtraByState(context.Background(), 1)
convey.So(err, convey.ShouldBeNil)
})
}
func TestDaoExtraByIds(t *testing.T) {
convey.Convey("ExtraByIds", t, func() {
res, err := d.ExtraByIds(context.Background(), []int64{1, 2, 3})
convey.So(err, convey.ShouldBeNil)
convey.So(res, convey.ShouldNotBeNil)
})
}
func TestDaoTypes(t *testing.T) {
convey.Convey("Types", t, func() {
_, err := d.Types(context.Background())
convey.So(err, convey.ShouldBeNil)
})
}
func TestDaoByIds(t *testing.T) {
convey.Convey("ByIds", t, func() {
_, err := d.ByIds(context.Background(), []int64{1, 2, 3})
convey.So(err, convey.ShouldBeNil)
})
}
func TestDaoQidsByState(t *testing.T) {
convey.Convey("QidsByState", t, func() {
_, err := d.QidsByState(context.Background(), 1)
convey.So(err, convey.ShouldBeNil)
})
}

View File

@@ -0,0 +1,111 @@
package dao
import (
"context"
"strconv"
"go-common/library/cache/redis"
"go-common/library/log"
)
const (
_qidByTypeID = "v3_qus_tids_"
_extraQidByTypeID = "v3_eq_t_"
)
func qusByType(tid int) string {
return _qidByTypeID + strconv.FormatInt(int64(tid), 10)
}
func extraQidByType(tid int8) string {
return _extraQidByTypeID + strconv.FormatInt(int64(tid), 10)
}
func (d *Dao) pingRedis(c context.Context) (err error) {
conn := d.redis.Get(c)
_, err = conn.Do("SET", "PING", "PONG")
conn.Close()
return
}
// QidByType get question by type.
func (d *Dao) QidByType(c context.Context, tid int, num uint8) (ids []int64, err error) {
key := qusByType(tid)
conn := d.redis.Get(c)
defer conn.Close()
if ids, err = redis.Int64s(conn.Do("SRANDMEMBER", key, num)); err != nil {
log.Error("RandBaseQs conn.Send('SRANDMEMBER', %s, %d) error(%v)", key, num, err)
}
return
}
// SetQids set question ids.
func (d *Dao) SetQids(c context.Context, qs []int64, typeID int) (err error) {
if len(qs) == 0 {
return
}
key := qusByType(typeID)
conn := d.redis.Get(c)
defer conn.Close()
args := make([]interface{}, 0, len(qs)+1)
args = append(args, key)
for _, q := range qs {
args = append(args, q)
}
if _, err = conn.Do("SADD", args...); err != nil {
log.Error("conn.Send(SADD, %v) error(%v)", args, err)
}
return
}
// SetExtraQids set extra question ids.
func (d *Dao) SetExtraQids(c context.Context, qs []int64, ans int8) (err error) {
if len(qs) == 0 {
return
}
key := extraQidByType(ans)
conn := d.redis.Get(c)
defer conn.Close()
args := make([]interface{}, 0, len(qs)+1)
args = append(args, key)
for _, q := range qs {
args = append(args, q)
}
if _, err = conn.Do("SADD", args...); err != nil {
log.Error("conn.Send(SADD, %v) error(%v)", args, err)
}
return
}
// DelQidsCache del qids cahce.
func (d *Dao) DelQidsCache(c context.Context, typeID int) (err error) {
key := qusByType(typeID)
conn := d.redis.Get(c)
defer conn.Close()
if err = conn.Send("DEL", key); err != nil {
log.Error("conn.Send(DEL, %s) error(%v)", key, err)
}
return
}
// DelExtraQidsCache del extra qids cahce.
func (d *Dao) DelExtraQidsCache(c context.Context, ans int8) (err error) {
key := extraQidByType(ans)
conn := d.redis.Get(c)
defer conn.Close()
if err = conn.Send("DEL", key); err != nil {
log.Error("conn.Send(DEL, %s) error(%v)", key, err)
}
return
}
// ExtraQidByType extra qis by type.
func (d *Dao) ExtraQidByType(c context.Context, ans int8, num uint8) (ids []int64, err error) {
key := extraQidByType(ans)
conn := d.redis.Get(c)
defer conn.Close()
if ids, err = redis.Int64s(conn.Do("SRANDMEMBER", key, num)); err != nil {
log.Error("ExtraQidByType conn.Send('SRANDMEMBER', %s, %d) error(%v)", key, num, err)
}
return
}

View File

@@ -0,0 +1,64 @@
package dao
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestQusByType(t *testing.T) {
convey.Convey("qusByType", t, func() {
p1 := qusByType(0)
convey.So(p1, convey.ShouldNotBeNil)
})
}
func TestExtraQidByType(t *testing.T) {
convey.Convey("extraQidByType", t, func() {
p1 := extraQidByType(0)
convey.So(p1, convey.ShouldNotBeNil)
})
}
func TestDaopingRedis(t *testing.T) {
convey.Convey("pingRedis", t, func() {
err := d.pingRedis(context.Background())
convey.So(err, convey.ShouldBeNil)
})
}
func TestDaoSetQids(t *testing.T) {
convey.Convey("SetQids", t, func() {
err := d.SetQids(context.Background(), []int64{1, 2, 3}, 0)
convey.So(err, convey.ShouldBeNil)
})
convey.Convey("QidByType", t, func() {
ids, err := d.QidByType(context.Background(), 0, 3)
convey.So(err, convey.ShouldBeNil)
convey.So(ids, convey.ShouldNotBeNil)
})
}
func TestDaoSetExtraQids(t *testing.T) {
convey.Convey("SetExtraQids", t, func() {
err := d.SetExtraQids(context.Background(), []int64{1, 2, 3}, 0)
convey.So(err, convey.ShouldBeNil)
})
convey.Convey("ExtraQidByType", t, func() {
ids, err := d.ExtraQidByType(context.Background(), 0, 2)
convey.So(err, convey.ShouldBeNil)
convey.So(ids, convey.ShouldNotBeNil)
})
convey.Convey("DelQidsCache", t, func() {
err := d.DelQidsCache(context.Background(), 0)
convey.So(err, convey.ShouldBeNil)
})
}
func TestDaoDelExtraQidsCache(t *testing.T) {
convey.Convey("DelExtraQidsCache", t, func() {
err := d.DelExtraQidsCache(context.Background(), 0)
convey.So(err, convey.ShouldBeNil)
})
}