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,54 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"ai_test.go",
"bigdata_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/reply/conf:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"ai.go",
"bigdata.go",
],
importpath = "go-common/app/interface/main/reply/dao/bigdata",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/reply/conf:go_default_library",
"//library/ecode: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,57 @@
package bigdata
import (
"bytes"
"context"
"encoding/json"
"net/http"
"go-common/library/log"
"github.com/pkg/errors"
)
type topicResponse struct {
Code int `json:"error_code"`
Message string `json:"error_message"`
Topics []string `json:"topics"`
}
type topicReq struct {
Mid int64 `json:"mid"`
Oid int64 `json:"oid"`
Type int8 `json:"type"`
Message string `json:"message"`
}
// Topics return topics
func (dao *Dao) Topics(c context.Context, mid int64, oid int64, typ int8, msg string) ([]string, error) {
res := &topicResponse{}
content, err := json.Marshal(&topicReq{
Mid: mid,
Oid: oid,
Type: typ,
Message: msg,
})
if err != nil {
err = errors.WithStack(err)
return nil, err
}
req, err := http.NewRequest("POST", dao.topicURL, bytes.NewReader(content))
if err != nil {
log.Error("bigdata.Topics(%d,%d,%d,%s) url(%s) req(%s)send POST error(%v)", mid, oid, typ, msg, dao.topicURL, string(content), err)
err = errors.WithStack(err)
return nil, err
}
req.Header.Set("Content-Type", "application/json")
err = dao.httpClient.Do(c, req, res)
if err != nil {
log.Error("bigdata.Topics(%d,%d,%d,%s) url(%s) req(%s) error(%v)", mid, oid, typ, msg, dao.topicURL, string(content), err)
return nil, err
}
if res.Code != 0 {
log.Error("bigdata.Topics(%d,%d,%d,%s) url(%s) req(%s) return not success,error_msg(%d,%v)", mid, oid, typ, msg, dao.topicURL, string(content), res.Code, res.Message)
return nil, err
}
return res.Topics, nil
}

View File

@@ -0,0 +1,56 @@
package bigdata
import (
"context"
"flag"
"go-common/app/interface/main/reply/conf"
"os"
"testing"
"github.com/smartystreets/goconvey/convey"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "")
flag.Set("conf_token", "")
flag.Set("tree_id", "")
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/reply-test.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
os.Exit(m.Run())
}
func TestBigdataTopics(t *testing.T) {
convey.Convey("Topics", t, func(ctx convey.C) {
var (
c = context.Background()
mid = int64(0)
oid = int64(0)
typ = int8(0)
msg = ""
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1, err := d.Topics(c, mid, oid, typ, msg)
ctx.Convey("Then err should be nil.p1 should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
ctx.So(p1, convey.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,48 @@
package bigdata
import (
"context"
"net/url"
"go-common/app/interface/main/reply/conf"
"go-common/library/ecode"
"go-common/library/log"
httpx "go-common/library/net/http/blademaster"
)
type result struct {
Code int `json:"code"`
}
// Dao bigdata dao
type Dao struct {
url string
topicURL string
httpClient *httpx.Client
}
// New return a bigdata dao
func New(c *conf.Config) *Dao {
d := &Dao{
httpClient: httpx.NewClient(c.HTTPClient),
url: c.Reply.BigdataURL,
topicURL: c.Reply.AiTopicURL,
}
return d
}
// Filter Filter
func (dao *Dao) Filter(c context.Context, msg string) (err error) {
params := url.Values{}
res := &result{}
params.Set("comment", msg)
if err = dao.httpClient.Post(c, dao.url, "", params, res); err != nil {
log.Error("Bigdata url(%s) error(%v)", dao.url+"?"+params.Encode(), err)
return
}
if res.Code != 0 {
log.Error("Bigdata url(%s) error(%v)", dao.url+"?"+params.Encode(), res.Code)
err = ecode.ReplyDeniedAsGarbage
}
return
}

View File

@@ -0,0 +1,39 @@
package bigdata
import (
"context"
"testing"
"go-common/app/interface/main/reply/conf"
"github.com/smartystreets/goconvey/convey"
)
func TestBigdataNew(t *testing.T) {
convey.Convey("New", t, func(ctx convey.C) {
var (
c = conf.Conf
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := New(c)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestBigdataFilter(t *testing.T) {
convey.Convey("Filter", t, func(ctx convey.C) {
var (
c = context.Background()
msg = ""
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.Filter(c, msg)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,48 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = ["drawyoo_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/reply/conf:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = ["drawyoo.go"],
importpath = "go-common/app/interface/main/reply/dao/drawyoo",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/reply/conf:go_default_library",
"//app/interface/main/reply/model/drawyoo:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/xstr: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,73 @@
package drawyoo
import (
"context"
"net/url"
"strconv"
"go-common/app/interface/main/reply/conf"
"go-common/app/interface/main/reply/model/drawyoo"
"go-common/library/log"
httpx "go-common/library/net/http/blademaster"
"go-common/library/xstr"
)
// Dao Dao
type Dao struct {
url string
http *httpx.Client
}
// New New
func New(c *conf.Config) *Dao {
d := &Dao{
url: "http://h.bilibili.com/api/pushS",
http: httpx.NewClient(c.DrawyooHTTPClient),
}
return d
}
// Info Info
func (dao *Dao) Info(c context.Context, hid int64) (info *drawyoo.Drawyoo, err error) {
params := url.Values{}
params.Set("act", "getHidInfo")
params.Set("hid", strconv.FormatInt(hid, 10))
var res struct {
State int `json:"state"`
Data []*drawyoo.Drawyoo `json:"data"`
}
if err = dao.http.Post(c, dao.url, "", params, &res); err != nil {
log.Error("drawyoo url(%v),err (%v)", dao.url+"?"+params.Encode(), err)
return
}
if res.State != 200 || len(res.Data) == 0 {
log.Error("drawyoo url (%v),err (%v)", dao.url+"?"+params.Encode(), err)
return
}
info = res.Data[0]
return
}
// Infos Infos
func (dao *Dao) Infos(c context.Context, hids []int64) (info map[int64]interface{}, err error) {
params := url.Values{}
params.Set("act", "getHidInfo")
params.Set("hid", xstr.JoinInts(hids))
var res struct {
State int `json:"state"`
Data []*drawyoo.Drawyoo `json:"data"`
}
if err = dao.http.Post(c, dao.url, "", params, &res); err != nil {
log.Error("drawyoo url(%v),err (%v)", dao.url+"?"+params.Encode(), err)
return
}
if res.State != 200 || len(res.Data) == 0 {
log.Error("drawyoo url (%v),err (%v)", dao.url+"?"+params.Encode(), err)
return
}
info = make(map[int64]interface{}, len(res.Data))
for _, r := range res.Data {
info[r.Hid] = r
}
return
}

View File

@@ -0,0 +1,84 @@
package drawyoo
import (
"context"
"flag"
"go-common/app/interface/main/reply/conf"
"os"
"testing"
"github.com/smartystreets/goconvey/convey"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "")
flag.Set("conf_token", "")
flag.Set("tree_id", "")
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/reply-test.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
os.Exit(m.Run())
}
func TestDrawyooNew(t *testing.T) {
convey.Convey("New", t, func(ctx convey.C) {
var (
c = conf.Conf
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := New(c)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestDrawyooInfo(t *testing.T) {
convey.Convey("Info", t, func(ctx convey.C) {
var (
c = context.Background()
hid = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
info, err := d.Info(c, hid)
ctx.Convey("Then err should be nil.info should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
ctx.So(info, convey.ShouldBeNil)
})
})
})
}
func TestDrawyooInfos(t *testing.T) {
convey.Convey("Infos", t, func(ctx convey.C) {
var (
c = context.Background()
hids = []int64{}
d = New(conf.Conf)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
info, err := d.Infos(c, hids)
ctx.Convey("Then err should be nil.info should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
ctx.So(info, convey.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,47 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = ["fans_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/reply/conf:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = ["fans.go"],
importpath = "go-common/app/interface/main/reply/dao/fans",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/reply/conf:go_default_library",
"//app/interface/main/reply/model/reply: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,58 @@
package fans
import (
"context"
"net/url"
"strconv"
"time"
"go-common/app/interface/main/reply/conf"
"go-common/app/interface/main/reply/model/reply"
"go-common/library/log"
httpx "go-common/library/net/http/blademaster"
)
// Dao Dao
type Dao struct {
fansReceivedListURL string
fansReceivedListHTTPClient *httpx.Client
}
// New New
func New(c *conf.Config) *Dao {
d := &Dao{
fansReceivedListURL: c.Reply.FansReceivedListURL,
fansReceivedListHTTPClient: httpx.NewClient(c.HTTPClient),
}
return d
}
// Fetch Fetch
func (dao *Dao) Fetch(c context.Context, uids []int64, mid int64, now time.Time) (map[int64]*reply.FansDetail, error) {
fansMap := make(map[int64]*reply.FansDetail)
if len(uids) == 0 {
return fansMap, nil
}
params := url.Values{}
params.Set("target_id", strconv.FormatInt(mid, 10))
params.Set("source", strconv.FormatInt(2, 10))
for index := range uids {
params.Add("uid[]", strconv.FormatInt(uids[index], 10))
}
var res struct {
Code int `json:"code"`
Message string `json:"msg"`
Data []*reply.FansDetail `json:"data"`
}
if err := dao.fansReceivedListHTTPClient.Get(c, dao.fansReceivedListURL, "", params, &res); err != nil {
log.Error("fansFetch url(%v),err (%v)", dao.fansReceivedListURL+"?"+params.Encode(), err)
return fansMap, err
}
if res.Code != 0 {
return fansMap, nil
}
for _, d := range res.Data {
fansMap[d.UID] = d
}
return fansMap, nil
}

View File

@@ -0,0 +1,70 @@
package fans
import (
"context"
"flag"
"go-common/app/interface/main/reply/conf"
"os"
"testing"
"time"
"github.com/smartystreets/goconvey/convey"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "")
flag.Set("conf_token", "")
flag.Set("tree_id", "")
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/reply-test.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
os.Exit(m.Run())
}
func TestFansNew(t *testing.T) {
convey.Convey("New", t, func(ctx convey.C) {
var (
c = conf.Conf
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := New(c)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestFansFetch(t *testing.T) {
convey.Convey("Fetch", t, func(ctx convey.C) {
var (
c = context.Background()
uids = []int64{}
mid = int64(0)
now = time.Now()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1, err := d.Fetch(c, uids, mid, now)
ctx.Convey("Then err should be nil.p1 should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
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 = [
"admin_test.go",
"block_status_test.go",
"business_test.go",
"captcha_test.go",
"config_test.go",
"content_test.go",
"credit_user_test.go",
"cursor_test.go",
"dao_test.go",
"databus_test.go",
"emoji_test.go",
"memcache_test.go",
"notice_test.go",
"redis_test.go",
"reply_test.go",
"report_test.go",
"subject_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/reply/conf:go_default_library",
"//app/interface/main/reply/model/reply:go_default_library",
"//library/database/sql:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/queue/databus:go_default_library",
"//library/time:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"admin.go",
"block_status.go",
"business.go",
"captcha.go",
"config.go",
"content.go",
"credit_user.go",
"cursor.go",
"dao.go",
"databus.go",
"emoji.go",
"memcache.go",
"notice.go",
"redis.go",
"reply.go",
"report.go",
"subject.go",
],
importpath = "go-common/app/interface/main/reply/dao/reply",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/reply/conf:go_default_library",
"//app/interface/main/reply/model/reply:go_default_library",
"//app/interface/main/reply/model/xreply: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",
],
)
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,47 @@
package reply
import (
"context"
"time"
"go-common/library/database/sql"
"go-common/library/log"
)
const (
_inAdminSQL = "INSERT INTO reply_admin_log (oid,type,rpid,adminid,result,remark,isnew,isreport,state,ctime,mtime) VALUES(?,?,?,?,?,?,?,?,?,?,?)"
_upAdminSQL = "UPDATE reply_admin_log SET isnew=0,mtime=? WHERE rpid=? AND isnew=1"
)
// AdminDao AdminDao
type AdminDao struct {
mysql *sql.DB
}
// NewAdminDao new ReplyReportDao and return.
func NewAdminDao(db *sql.DB) (dao *AdminDao) {
dao = &AdminDao{
mysql: db,
}
return
}
// Insert insert reply report.
func (dao *AdminDao) Insert(c context.Context, adminid, oid, rpID int64, tp int8, result, remark string, isnew, isreport, state int8, now time.Time) (id int64, err error) {
res, err := dao.mysql.Exec(c, _inAdminSQL, oid, tp, rpID, adminid, result, remark, isnew, isreport, state, now, now)
if err != nil {
log.Error("adminDao.Exec error(%v)", err)
return
}
return res.LastInsertId()
}
// UpIsNotNew update reply report.
func (dao *AdminDao) UpIsNotNew(c context.Context, rpID int64, now time.Time) (rows int64, err error) {
res, err := dao.mysql.Exec(c, _upAdminSQL, now, rpID)
if err != nil {
log.Error("adminDao.Exec error(%v)", err)
return
}
return res.RowsAffected()
}

View File

@@ -0,0 +1,66 @@
package reply
import (
"context"
"go-common/library/database/sql"
"testing"
"time"
"github.com/smartystreets/goconvey/convey"
)
func TestReplyNewAdminDao(t *testing.T) {
convey.Convey("NewAdminDao", t, func(ctx convey.C) {
var (
db = &sql.DB{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
dao := NewAdminDao(db)
ctx.Convey("Then dao should not be nil.", func(ctx convey.C) {
ctx.So(dao, convey.ShouldNotBeNil)
})
})
})
}
func TestReplyAdminInsert(t *testing.T) {
convey.Convey("Insert", t, func(ctx convey.C) {
var (
c = context.Background()
adminid = int64(0)
oid = int64(0)
rpID = int64(0)
tp = int8(0)
result = ""
remark = ""
isnew = int8(0)
isreport = int8(0)
state = int8(0)
now = time.Now()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
id, err := d.Admin.Insert(c, adminid, oid, rpID, tp, result, remark, isnew, isreport, state, now)
ctx.Convey("Then err should be nil.id should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(id, convey.ShouldNotBeNil)
})
})
})
}
func TestReplyUpIsNotNew(t *testing.T) {
convey.Convey("UpIsNotNew", t, func(ctx convey.C) {
var (
c = context.Background()
rpID = int64(0)
now = time.Now()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
rows, err := d.Admin.UpIsNotNew(c, rpID, now)
ctx.Convey("Then err should be nil.rows should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(rows, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,70 @@
package reply
import (
"context"
"fmt"
"net/url"
"go-common/app/interface/main/reply/conf"
"go-common/library/log"
httpx "go-common/library/net/http/blademaster"
)
// BlockStatusDao BlockStatusDao
type BlockStatusDao struct {
requestURL string
httpClient *httpx.Client
}
// NewBlockStatusDao NewBlockStatusDao
func NewBlockStatusDao(c *conf.Config) *BlockStatusDao {
d := &BlockStatusDao{
httpClient: httpx.NewClient(c.HTTPClient),
requestURL: c.Reply.BlockStatusURL,
}
return d
}
// BlockInfo BlockInfo
type BlockInfo struct {
// block_status 变成了 PassTest,原因不可描述
PassTest int `json:"block_status"` // 1: fail 0: succ
ForeverBlock bool `json:"blocked_forever"`
BlockUntil int64 `json:"blocked_end"`
Moral int `json:"moral"`
}
// BlockStatusResp BlockStatusResp
type BlockStatusResp struct {
Code int `json:"code"`
Data BlockInfo `json:"data"`
Msg string `json:"msg"`
}
// BlockInfo BlockInfo
func (dao *BlockStatusDao) BlockInfo(c context.Context, mid int64) (*BlockInfo, error) {
var res BlockStatusResp
params := url.Values{}
params.Set("mid", fmt.Sprintf("%d", mid))
err := dao.httpClient.Get(c, dao.requestURL, "", params, &res)
// WARNING: must put urlStr after httpClient.Get()
// since params will be modified
urlStr := dao.requestURL + "?" + params.Encode()
if err != nil {
log.Error("call 账号系统小黑屋(%s) error(%v)", urlStr, err)
return nil, err
}
if res.Code != 0 {
err = fmt.Errorf("call 账号系统小黑屋(%s) error, return code(%v)", urlStr, res.Code)
log.Error("%v", err)
return nil, err
}
log.Info("call 账号系统小黑屋(%s) successful. resp(%+v)", urlStr, res.Data)
resData := res.Data
if resData.PassTest != 0 && resData.PassTest != 1 {
err = fmt.Errorf("call 账号系统小黑屋(%s) successful. but got error resp(blocked_status=%d), want 0 or 1", urlStr, resData.PassTest)
log.Error("%v", err)
return nil, err
}
return &res.Data, nil
}

View File

@@ -0,0 +1,24 @@
package reply
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestReplyBlockInfo(t *testing.T) {
convey.Convey("BlockInfo", t, func(ctx convey.C) {
var (
c = context.Background()
mid = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1, err := d.BlockStatus.BlockInfo(c, mid)
ctx.Convey("Then err should be nil.p1 should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,46 @@
package reply
import (
"context"
"go-common/app/interface/main/reply/model/reply"
"go-common/library/database/sql"
"go-common/library/log"
)
const (
_selBussinessSQL = "SELECT type, alias, appkey FROM business WHERE state=0"
)
// BusinessDao business dao.
type BusinessDao struct {
db *sql.DB
}
// NewBusinessDao new BusinessDao and return.
func NewBusinessDao(db *sql.DB) (dao *BusinessDao) {
dao = &BusinessDao{
db: db,
}
return
}
// ListBusiness gets all business records
func (dao *BusinessDao) ListBusiness(c context.Context) (business []*reply.Business, err error) {
rows, err := dao.db.Query(c, _selBussinessSQL)
if err != nil {
log.Error("sql query error(%v)", err)
return
}
defer rows.Close()
business = make([]*reply.Business, 0)
for rows.Next() {
b := new(reply.Business)
if err = rows.Scan(&b.Type, &b.Alias, &b.Appkey); err != nil {
return
}
business = append(business, b)
}
err = rows.Err()
return
}

View File

@@ -0,0 +1,38 @@
package reply
import (
"context"
"go-common/library/database/sql"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestReplyNewBusinessDao(t *testing.T) {
convey.Convey("NewBusinessDao", t, func(ctx convey.C) {
var (
db = &sql.DB{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
dao := NewBusinessDao(db)
ctx.Convey("Then dao should not be nil.", func(ctx convey.C) {
ctx.So(dao, convey.ShouldNotBeNil)
})
})
})
}
func TestReplyListBusiness(t *testing.T) {
convey.Convey("ListBusiness", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
business, err := d.Business.ListBusiness(c)
ctx.Convey("Then err should be nil.business should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(business, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,68 @@
package reply
import (
"context"
"go-common/app/interface/main/reply/conf"
"go-common/library/ecode"
"go-common/library/log"
httpx "go-common/library/net/http/blademaster"
"go-common/library/net/metadata"
"net/url"
)
// NewCaptchaDao NewCaptchaDao
func NewCaptchaDao(c *httpx.ClientConfig) *CaptchaDao {
return &CaptchaDao{httpClient: httpx.NewClient(c)}
}
// CaptchaDao CaptchaDao
type CaptchaDao struct {
httpClient *httpx.Client
}
// Captcha Captcha.
func (s *CaptchaDao) Captcha(c context.Context) (string, string, error) {
params := url.Values{}
params.Set("bid", "reply")
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 := s.httpClient.Get(c, conf.Conf.Reply.CaptchaTokenURL, ip, params, res); err != nil {
log.Error("s.httpClient.Get(%s) error(%v)", conf.Conf.Reply.CaptchaTokenURL+"?"+params.Encode(), err)
return "", "", err
}
if res.Code != 0 {
log.Error("s.httpClient.Get(%s?%s) code:%d", conf.Conf.Reply.CaptchaTokenURL, params.Encode(), res.Code)
return "", "", ecode.Int(res.Code)
}
return res.Data.Token, res.Data.URL, nil
}
// Verify Verify.
func (s *CaptchaDao) Verify(c context.Context, token, code 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"`
}{}
ip := metadata.String(c, metadata.RemoteIP)
if err := s.httpClient.Post(c, conf.Conf.Reply.CaptchaVerifyURL, ip, params, res); err != nil {
log.Error("s.httpClient.POST(%s) error(%v)", conf.Conf.Reply.CaptchaVerifyURL+"?"+params.Encode(), err)
return err
}
if res.Code != 0 {
log.Error("s.httpClient.POST(%s?%s) code:%d", conf.Conf.Reply.CaptchaVerifyURL, params.Encode(), res.Code)
return ecode.Int(res.Code)
}
return nil
}

View File

@@ -0,0 +1,64 @@
package reply
import (
"context"
httpx "go-common/library/net/http/blademaster"
xtime "go-common/library/time"
"testing"
"time"
"github.com/smartystreets/goconvey/convey"
)
func TestReplyNewCaptchaDao(t *testing.T) {
convey.Convey("NewCaptchaDao", t, func(ctx convey.C) {
var (
c = &httpx.ClientConfig{
App: &httpx.App{
Key: "test",
Secret: "test",
},
Dial: xtime.Duration(time.Second),
Timeout: xtime.Duration(time.Second),
}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := NewCaptchaDao(c)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestReplyCaptcha(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.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 TestReplyVerify(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.Captcha.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,49 @@
package reply
import (
"context"
"encoding/json"
"go-common/app/interface/main/reply/model/reply"
"go-common/library/database/sql"
"go-common/library/log"
)
const (
_loadConfigSQL = "SELECT id, type, oid, adminid, operator, category, config, ctime, mtime FROM reply_config WHERE type=? AND oid=? AND category = ?"
)
// ConfigDao ConfigDao
type ConfigDao struct {
mysql *sql.DB
}
// NewConfigDao new ConfigDao and return.
func NewConfigDao(db *sql.DB) (dao *ConfigDao) {
dao = &ConfigDao{
mysql: db,
}
return
}
// LoadConfig :load a config record
func (dao *ConfigDao) LoadConfig(c context.Context, oid int64, tp, category int8) (m *reply.Config, err error) {
m = &reply.Config{}
row := dao.mysql.QueryRow(c, _loadConfigSQL, tp, oid, category)
if err = row.Scan(&m.ID, &m.Type, &m.Oid, &m.AdminID, &m.Operator, &m.Category, &m.Config, &m.CTime, &m.MTime); err != nil {
if err == sql.ErrNoRows {
m = nil
err = nil
return
}
log.Error("row.Scan error(%v)", err)
}
if m.ID > 0 {
var dat reply.Config
if err := json.Unmarshal([]byte(m.Config), &dat); err == nil {
m.ShowEntry = dat.ShowEntry
m.ShowAdmin = dat.ShowAdmin
}
}
return
}

View File

@@ -0,0 +1,41 @@
package reply
import (
"context"
"go-common/library/database/sql"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestReplyNewConfigDao(t *testing.T) {
convey.Convey("NewConfigDao", t, func(ctx convey.C) {
var (
db = &sql.DB{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
dao := NewConfigDao(db)
ctx.Convey("Then dao should not be nil.", func(ctx convey.C) {
ctx.So(dao, convey.ShouldNotBeNil)
})
})
})
}
func TestReplyLoadConfig(t *testing.T) {
convey.Convey("LoadConfig", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
tp = int8(0)
category = int8(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
m, err := d.Config.LoadConfig(c, oid, tp, category)
ctx.Convey("Then err should be nil.m should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(m, convey.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,98 @@
package reply
import (
"context"
"fmt"
"time"
"go-common/app/interface/main/reply/model/reply"
"go-common/library/database/sql"
"go-common/library/log"
"go-common/library/xstr"
)
const (
_contSharding int64 = 200
)
const (
_selContSQL = "SELECT rpid,message,ats,ip,plat,device,topics FROM reply_content_%d WHERE rpid=?"
_selContsSQL = "SELECT rpid,message,ats,ip,plat,device,topics FROM reply_content_%d WHERE rpid IN (%s)"
_upContMsgSQL = "UPDATE reply_content_%d SET message=?,mtime=? WHERE rpid=?"
)
// ContentDao ContentDao
type ContentDao struct {
upContMsgStmts []*sql.Stmt
db *sql.DB
dbSlave *sql.DB
}
// NewContentDao new replyDao and return.
func NewContentDao(db *sql.DB, dbSlave *sql.DB) (dao *ContentDao) {
dao = &ContentDao{
db: db,
dbSlave: dbSlave,
upContMsgStmts: make([]*sql.Stmt, _contSharding),
}
for i := int64(0); i < _contSharding; i++ {
dao.upContMsgStmts[i] = dao.db.Prepared(fmt.Sprintf(_upContMsgSQL, i))
}
return
}
func (dao *ContentDao) hit(oid int64) int64 {
return oid % int64(_contSharding)
}
// UpMessage update content's message.
func (dao *ContentDao) UpMessage(c context.Context, oid int64, rpID int64, msg string, now time.Time) (rows int64, err error) {
res, err := dao.upContMsgStmts[dao.hit(oid)].Exec(c, msg, now, rpID)
if err != nil {
log.Error("contentDao.UpMessage error(%v)", err)
return
}
return res.RowsAffected()
}
// Get get reply content.
func (dao *ContentDao) Get(c context.Context, oid int64, rpID int64) (rc *reply.Content, err error) {
row := dao.db.QueryRow(c, fmt.Sprintf(_selContSQL, dao.hit(oid)), rpID)
rc = &reply.Content{}
if err = row.Scan(&rc.RpID, &rc.Message, &rc.Ats, &rc.IP, &rc.Plat, &rc.Device, &rc.Topics); err != nil {
if err == sql.ErrNoRows {
err = nil
rc = nil
} else {
log.Error("row.Scan error(%v)", err)
}
}
return
}
// GetByIds get reply contents by reply ids.
func (dao *ContentDao) GetByIds(c context.Context, oid int64, rpIds []int64) (rcMap map[int64]*reply.Content, err error) {
if len(rpIds) == 0 {
return
}
rows, err := dao.dbSlave.Query(c, fmt.Sprintf(_selContsSQL, dao.hit(oid), xstr.JoinInts(rpIds)))
if err != nil {
log.Error("contentDao.Query error(%v)", err)
return
}
defer rows.Close()
rcMap = make(map[int64]*reply.Content, len(rpIds))
for rows.Next() {
rc := &reply.Content{}
if err = rows.Scan(&rc.RpID, &rc.Message, &rc.Ats, &rc.IP, &rc.Plat, &rc.Device, &rc.Topics); err != nil {
log.Error("row.Scan error(%v)", err)
return
}
rcMap[rc.RpID] = rc
}
if err = rows.Err(); err != nil {
log.Error("rows.err error(%v)", err)
return
}
return
}

View File

@@ -0,0 +1,94 @@
package reply
import (
"context"
"go-common/app/interface/main/reply/conf"
"go-common/library/database/sql"
"testing"
"time"
"github.com/smartystreets/goconvey/convey"
)
func TestReplyNewContentDao(t *testing.T) {
convey.Convey("NewContentDao", t, func(ctx convey.C) {
var (
db = sql.NewMySQL(conf.Conf.MySQL.Reply)
dbSlave = sql.NewMySQL(conf.Conf.MySQL.ReplySlave)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
dao := NewContentDao(db, dbSlave)
recover()
ctx.Convey("Then dao should not be nil.", func(ctx convey.C) {
ctx.So(dao, convey.ShouldNotBeNil)
})
})
})
}
func TestReplyContenthit(t *testing.T) {
convey.Convey("hit", t, func(ctx convey.C) {
var (
oid = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := d.Content.hit(oid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestReplyUpMessage(t *testing.T) {
convey.Convey("UpMessage", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
rpID = int64(0)
msg = ""
now = time.Now()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
rows, err := d.Content.UpMessage(c, oid, rpID, msg, now)
ctx.Convey("Then err should be nil.rows should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(rows, convey.ShouldNotBeNil)
})
})
})
}
func TestReplyContentGet(t *testing.T) {
convey.Convey("Get", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
rpID = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
rc, err := d.Content.Get(c, oid, rpID)
ctx.Convey("Then err should be nil.rc should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(rc, convey.ShouldBeNil)
})
})
})
}
func TestReplyContentGetByIds(t *testing.T) {
convey.Convey("GetByIds", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
rpIds = []int64{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
rcMap, err := d.Content.GetByIds(c, oid, rpIds)
ctx.Convey("Then err should be nil.rcMap should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(rcMap, convey.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,55 @@
package reply
import (
"context"
"fmt"
"net/url"
"go-common/app/interface/main/reply/conf"
"go-common/library/log"
httpx "go-common/library/net/http/blademaster"
)
// CreditUserDao CreditUserDao
type CreditUserDao struct {
requestURL string
httpClient *httpx.Client
}
// NewCreditDao NewCreditDao
func NewCreditDao(c *conf.Config) *CreditUserDao {
d := &CreditUserDao{
httpClient: httpx.NewClient(c.HTTPClient),
requestURL: c.Reply.CreditUserURL,
}
return d
}
// Result Result
type Result struct {
Code int `json:"code"`
Data map[int64]struct {
Mid int64 `json:"mid"`
Expired int64 `json:"expired"`
Status int `json:"status"`
} `json:"data"`
Msg string `json:"msg"`
}
// IsCreditUser IsCreditUser
func (dao *CreditUserDao) IsCreditUser(c context.Context, mid int64) (bool, error) {
var res Result
params := url.Values{}
params.Set("mids", fmt.Sprintf("%d", mid))
if err := dao.httpClient.Get(c, dao.requestURL, "", params, &res); err != nil {
log.Error("call 风纪委身份验证 url(%s) error(%v)", dao.requestURL+"?"+params.Encode(), err)
return false, err
}
if res.Code != 0 {
err := fmt.Errorf("call 风纪委身份验证 url(%s) error(%v)", dao.requestURL+"?"+params.Encode(), res.Code)
log.Error("%v", err)
return false, err
}
log.Info("call 风纪委身份验证 successful. url(%s)", dao.requestURL+"?"+params.Encode())
return res.Data[mid].Status == 1, nil
}

View File

@@ -0,0 +1,39 @@
package reply
import (
"context"
"go-common/app/interface/main/reply/conf"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestReplyNewCreditDao(t *testing.T) {
convey.Convey("NewCreditDao", t, func(ctx convey.C) {
var (
c = conf.Conf
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := NewCreditDao(c)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestReplyIsCreditUser(t *testing.T) {
convey.Convey("IsCreditUser", t, func(ctx convey.C) {
var (
c = context.Background()
mid = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1, err := d.CreditUser.IsCreditUser(c, mid)
ctx.Convey("Then err should be nil.p1 should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,409 @@
package reply
import (
"context"
"errors"
"fmt"
"strconv"
model "go-common/app/interface/main/reply/model/reply"
"go-common/library/cache/redis"
"go-common/library/log"
)
const (
selectRootIDsByLatestFloorSQL = "SELECT id FROM reply_%d WHERE oid=? AND type=? AND root=0 AND state in (0,1,2,5,6) ORDER BY floor DESC limit 0,%d"
selectRootIDsByCursorOnFloorSQL = "SELECT id FROM reply_%d WHERE oid=? AND type=? AND root=0 AND state in (0,1,2,5,6) AND floor %s %d ORDER BY floor limit 0,%d"
selectRootIDsByRootStateSQL = "SELECT id FROM reply_%d WHERE oid=? AND type=? AND root=? AND state in (0,1,2,5,6) ORDER BY floor limit ?,?"
selectChildrenIDsByLatestFloorSQL = "SELECT id FROM reply_%d WHERE oid=? AND type=? AND root=? AND state in (0,1,2,5,6) ORDER BY floor ASC limit 0,%d"
selectChildrenIDsByCursorOnFloorSQL = "SELECT id FROM reply_%d WHERE oid=? AND type=? AND root=? AND state in (0,1,2,5,6) AND floor %s %d ORDER BY floor limit 0,%d"
)
// ErrCursorDirection ErrCursorDirection
var ErrCursorDirection = errors.New("error cursor direction")
// ChildrenIDsOfRootReply ChildrenIDsOfRootReply
func (dao *RpDao) ChildrenIDsOfRootReply(ctx context.Context,
oid, rootID int64, tp int8, offset, limit int) ([]int64, error) {
rows, err := dao.dbSlave.Query(ctx,
fmt.Sprintf(selectRootIDsByRootStateSQL, dao.hit(oid)),
oid, tp, rootID, offset, limit)
if err != nil {
log.Error("%v", err)
return nil, err
}
defer rows.Close()
ids := make([]int64, 0)
for rows.Next() {
var id int64
if err = rows.Scan(&id); err != nil {
log.Error("%v", err)
return nil, err
}
ids = append(ids, id)
}
if err = rows.Err(); err != nil {
log.Error("rows.err error(%v)", err)
return nil, err
}
return ids, nil
}
// CacheKeyRootReplyIDs CacheKeyRootReplyIDs
func (dao *RedisDao) CacheKeyRootReplyIDs(oid int64, tp, sort int8) string {
// subject:root_reply_ids
if oid > _oidOverflow {
return fmt.Sprintf("%s_%d_%d_%d", _prefixIdx, oid, tp, sort)
}
return _prefixIdx + strconv.FormatInt((oid<<16)|(int64(tp)<<8)|int64(sort), 10)
}
// ParentChildrenReplyIDMap ParentChildrenReplyIDMap
func (dao *RedisDao) ParentChildrenReplyIDMap(ctx context.Context,
parentIDs []int64, start, end int) (parentChildrenMap map[int64][]int64, missedIDs []int64, err error) {
parentChildrenMap = make(map[int64][]int64)
arrayOfChildrenIDs, missedKeys, err := dao.RangeChildrenReplyIDs(ctx,
genChildrenKeyByRootReplyIDs(parentIDs), start, end)
if err != nil {
return nil, nil, err
}
m := genChildrenKeyParentIDMap(parentIDs)
for _, k := range missedKeys {
if pid, ok := m[k]; ok {
missedIDs = append(missedIDs, pid)
}
}
for i, pid := range parentIDs {
parentChildrenMap[pid] = arrayOfChildrenIDs[i]
}
return parentChildrenMap, missedIDs, nil
}
// RangeChildrenReplyIDs RangeChildrenReplyIDs
func (dao *RedisDao) RangeChildrenReplyIDs(ctx context.Context,
keys []string, start, end int) (arrOfChildrenReplyIDs [][]int64, missedKeys []string, err error) {
if len(keys) == 0 {
return
}
conn := dao.redis.Get(ctx)
defer conn.Close()
for _, key := range keys {
if err = conn.Send("EXPIRE", key, dao.expireRdsIdx); err != nil {
log.Error("%v", err)
return nil, nil, err
}
if err = conn.Send("ZRANGE", key, start, end); err != nil {
log.Error("%v", err)
return nil, nil, err
}
}
if err = conn.Flush(); err != nil {
log.Error("%v", err)
return nil, nil, err
}
arrOfChildrenReplyIDs = make([][]int64, 0)
missedKeys = make([]string, 0)
for _, key := range keys {
if exists, err := redis.Bool(conn.Receive()); err != nil {
log.Error("%v", err)
return nil, nil, err
} else if !exists {
missedKeys = append(missedKeys, key)
}
values, err := redis.Values(conn.Receive())
if err != nil {
log.Error("%v", err)
return nil, nil, err
}
if len(values) == 0 {
arrOfChildrenReplyIDs = append(arrOfChildrenReplyIDs, []int64{})
continue
}
var ids []int64
if err = redis.ScanSlice(values, &ids); err != nil {
log.Error("%v ", err)
return nil, nil, err
}
arrOfChildrenReplyIDs = append(arrOfChildrenReplyIDs, ids)
}
return arrOfChildrenReplyIDs, missedKeys, nil
}
// RangeChildrenIDByCursorScore RangeChildrenIDByCursorScore
func (dao *RedisDao) RangeChildrenIDByCursorScore(ctx context.Context, key string, cursor *model.Cursor) ([]int64, error) {
conn := dao.redis.Get(ctx)
defer conn.Close()
var (
vals []interface{}
err error
)
if cursor.Latest() {
vals, err = redis.Values(conn.Do("ZRANGEBYSCORE", key, 0, "+inf", "LIMIT", 0, cursor.Len()))
} else if cursor.Descrease() {
vals, err = redis.Values(conn.Do("ZREVRANGEBYSCORE", key, cursor.Current(), "-inf", "LIMIT", 0, cursor.Len()))
} else if cursor.Increase() {
vals, err = redis.Values(conn.Do("ZRANGEBYSCORE", key, cursor.Current(), "+inf", "LIMIT", 0, cursor.Len()))
} else {
err = ErrCursorDirection
}
if err != nil {
log.Error("%v", err)
return nil, err
}
replyIDs := make([]int64, 0)
if err = redis.ScanSlice(vals, &replyIDs); err != nil {
return nil, err
}
if cursor.Descrease() {
// ZREVRANGEBYSCORE to ASC
for i, j := 0, len(replyIDs)-1; i < j; i, j = i+1, j-1 {
replyIDs[i], replyIDs[j] = replyIDs[j], replyIDs[i]
}
}
return replyIDs, nil
}
// RangeRootIDByCursorScore RangeRootIDByCursorScore
func (dao *RedisDao) RangeRootIDByCursorScore(ctx context.Context, key string, cursor *model.Cursor) ([]int64, bool, error) {
conn := dao.redis.Get(ctx)
defer conn.Close()
var (
vals []interface{}
err error
)
if cursor.Latest() {
vals, err = redis.Values(conn.Do("ZREVRANGEBYSCORE", key, "+inf", 0, "LIMIT", 0, cursor.Len()))
} else if cursor.Increase() {
vals, err = redis.Values(conn.Do("ZRANGEBYSCORE", key, cursor.Current(), "+inf", "LIMIT", 0, cursor.Len()))
} else if cursor.Descrease() {
vals, err = redis.Values(conn.Do("ZREVRANGEBYSCORE", key, cursor.Current(), "-inf", "LIMIT", 0, cursor.Len()))
} else {
err = ErrCursorDirection
}
if err != nil {
log.Error("%v", err)
return nil, false, err
}
replyIDs := make([]int64, 0)
if err = redis.ScanSlice(vals, &replyIDs); err != nil {
return nil, false, err
}
if len(replyIDs) > 0 && replyIDs[len(replyIDs)-1] == -1 {
replyIDs = replyIDs[:len(replyIDs)-1]
return replyIDs, true, nil
}
return replyIDs, false, nil
}
// RangeRootReplyIDs RangeRootReplyIDs
func (dao *RedisDao) RangeRootReplyIDs(ctx context.Context, key string, start, end int) ([]int64, error) {
conn := dao.redis.Get(ctx)
defer conn.Close()
vals, err := redis.Values(conn.Do("ZREVRANGE", key, start, end))
if err != nil {
log.Error("%v", err)
return nil, err
}
replyIDs := make([]int64, 0)
if err = redis.ScanSlice(vals, &replyIDs); err != nil {
log.Error("%v", err)
return nil, err
}
return replyIDs, nil
}
// ExpireCache ExpireCache
func (dao *RedisDao) ExpireCache(ctx context.Context, key string) (bool, error) {
conn := dao.redis.Get(ctx)
defer conn.Close()
ok, err := redis.Bool(conn.Do("EXPIRE", key, dao.expireRdsIdx))
if err != nil {
log.Error("%v", err)
return false, err
}
return ok, nil
}
// genChildrenKeyParentIDMap genChildrenKeyParentIDMap
func genChildrenKeyParentIDMap(ids []int64) map[string]int64 {
m := make(map[string]int64)
for _, id := range ids {
m[GenNewChildrenKeyByRootReplyID(id)] = id
}
return m
}
// genChildrenKeyByRootReplyIDs genChildrenKeyByRootReplyIDs
func genChildrenKeyByRootReplyIDs(ids []int64) []string {
ks := make([]string, len(ids))
for i, id := range ids {
ks[i] = GenNewChildrenKeyByRootReplyID(id)
}
return ks
}
// GenNewChildrenKeyByRootReplyID GenNewChildrenKeyByRootReplyID
func GenNewChildrenKeyByRootReplyID(id int64) string {
return _prefixRtIdx + strconv.FormatInt(id, 10)
}
// genChildrenKeyByRootReplyID genChildrenKeyByRootReplyID
func genChildrenKeyByRootReplyID(id int64) string {
// score: timestamp
// reply:id:ids
return _prefixRtIdx + strconv.FormatInt(id, 10)
}
// genReplyKeyByID genReplyKeyByID
func genReplyKeyByID(id int64) string {
// "subject:reply:ids"
return _prefixRp + strconv.FormatInt(id, 10)
}
func contains(arr []string, b string) bool {
for _, a := range arr {
if a == b {
return true
}
}
return false
}
// GetReplyByIDs GetReplyByIDs
func (dao *MemcacheDao) GetReplyByIDs(ctx context.Context, ids []int64) ([]*model.Reply, []int64, error) {
if len(ids) == 0 {
return []*model.Reply{}, []int64{}, nil
}
keys := make([]string, len(ids))
keyIDMap := make(map[string]int64)
for i, id := range ids {
key := genReplyKeyByID(id)
keys[i] = key
keyIDMap[key] = id
}
conn := dao.mc.Get(ctx)
defer conn.Close()
items, err := conn.GetMulti(keys)
if err != nil {
log.Error("%v", err)
return nil, nil, err
}
foundKeys := make([]string, 0)
for _, item := range items {
foundKeys = append(foundKeys, item.Key)
}
missedKeys := make([]string, 0)
if len(foundKeys) < len(keys) {
for _, key := range keys {
if !contains(foundKeys, key) {
missedKeys = append(missedKeys, key)
}
}
}
missedIDs := make([]int64, 0)
for _, mk := range missedKeys {
missedIDs = append(missedIDs, keyIDMap[mk])
}
var rs = make([]*model.Reply, 0)
for _, item := range items {
rp := new(model.Reply)
if err := conn.Scan(item, rp); err != nil {
log.Error("%v", err)
missedIDs = append(missedIDs, keyIDMap[item.Key])
continue
}
rs = append(rs, rp)
}
return rs, missedIDs, nil
}
// ChildrenIDSortByFloorCursor ChildrenIDSortByFloorCursor
func (dao *RpDao) ChildrenIDSortByFloorCursor(ctx context.Context, oid int64, tp int8, rootID int64, cursor *model.Cursor) ([]int64, error) {
var rawSQL string
if cursor.Latest() {
rawSQL = fmt.Sprintf(selectChildrenIDsByLatestFloorSQL, dao.hit(oid), cursor.Len())
} else if cursor.Descrease() {
rawSQL = fmt.Sprintf(selectChildrenIDsByCursorOnFloorSQL, dao.hit(oid), "<=", cursor.Current(), cursor.Len())
} else if cursor.Increase() {
rawSQL = fmt.Sprintf(selectChildrenIDsByCursorOnFloorSQL, dao.hit(oid), ">=", cursor.Current(), cursor.Len())
} else {
log.Error("%v", ErrCursorDirection)
return nil, ErrCursorDirection
}
rows, err := dao.dbSlave.Query(ctx, rawSQL, oid, tp, rootID)
if err != nil {
log.Error("%v", err)
return nil, err
}
defer rows.Close()
var id int64
res := make([]int64, 0, cursor.Len())
for rows.Next() {
if err = rows.Scan(&id); err != nil {
log.Error("%v", err)
return nil, err
}
res = append(res, id)
}
if err = rows.Err(); err != nil {
log.Error("rows.err error(%v)", err)
return nil, err
}
return res, nil
}
// RootIDSortByFloorCursor RootIDSortByFloorCursor
func (dao *RpDao) RootIDSortByFloorCursor(ctx context.Context, oid int64, tp int8, cursor *model.Cursor) ([]int64, error) {
var rawSQL string
if cursor.Latest() {
rawSQL = fmt.Sprintf(selectRootIDsByLatestFloorSQL, dao.hit(oid), cursor.Len())
} else if cursor.Increase() {
rawSQL = fmt.Sprintf(selectRootIDsByCursorOnFloorSQL, dao.hit(oid), ">=", cursor.Current(), cursor.Len())
} else if cursor.Descrease() {
rawSQL = fmt.Sprintf(selectRootIDsByCursorOnFloorSQL, dao.hit(oid), "<=", cursor.Current(), cursor.Len())
} else {
log.Error("%v", ErrCursorDirection)
return nil, ErrCursorDirection
}
rows, err := dao.dbSlave.Query(ctx, rawSQL, oid, tp)
if err != nil {
log.Error("%v", err)
return nil, err
}
defer rows.Close()
var id int64
ids := make([]int64, 0, cursor.Len())
for rows.Next() {
if err = rows.Scan(&id); err != nil {
log.Error("%v", err)
return nil, err
}
ids = append(ids, id)
}
if err = rows.Err(); err != nil {
log.Error("rows.err error(%v)", err)
return nil, err
}
return ids, nil
}

View File

@@ -0,0 +1,277 @@
package reply
import (
"context"
model "go-common/app/interface/main/reply/model/reply"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestReplyChildrenIDsOfRootReply(t *testing.T) {
convey.Convey("ChildrenIDsOfRootReply", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
rootID = int64(0)
tp = int8(0)
offset = int(0)
limit = int(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1, err := d.Reply.ChildrenIDsOfRootReply(c, oid, rootID, tp, offset, limit)
ctx.Convey("Then err should be nil.p1 should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestReplyCacheKeyRootReplyIDs(t *testing.T) {
convey.Convey("CacheKeyRootReplyIDs", t, func(ctx convey.C) {
var (
oid = int64(0)
tp = int8(0)
sort = int8(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := d.Redis.CacheKeyRootReplyIDs(oid, tp, sort)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestReplyParentChildrenReplyIDMap(t *testing.T) {
convey.Convey("ParentChildrenReplyIDMap", t, func(ctx convey.C) {
var (
c = context.Background()
parentIDs = []int64{}
start = int(0)
end = int(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
parentChildrenMap, missedIDs, err := d.Redis.ParentChildrenReplyIDMap(c, parentIDs, start, end)
ctx.Convey("Then err should be nil.parentChildrenMap,missedIDs should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(missedIDs, convey.ShouldBeNil)
ctx.So(parentChildrenMap, convey.ShouldNotBeNil)
})
})
})
}
func TestReplyRangeChildrenReplyIDs(t *testing.T) {
convey.Convey("RangeChildrenReplyIDs", t, func(ctx convey.C) {
var (
c = context.Background()
keys = []string{}
start = int(0)
end = int(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
arrOfChildrenReplyIDs, missedKeys, err := d.Redis.RangeChildrenReplyIDs(c, keys, start, end)
ctx.Convey("Then err should be nil.arrOfChildrenReplyIDs,missedKeys should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(missedKeys, convey.ShouldBeNil)
ctx.So(arrOfChildrenReplyIDs, convey.ShouldBeNil)
})
})
})
}
func TestReplyRangeChildrenIDByCursorScore(t *testing.T) {
convey.Convey("RangeChildrenIDByCursorScore", t, func(ctx convey.C) {
var (
c = context.Background()
key = ""
cursor = &model.Cursor{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1, err := d.Redis.RangeChildrenIDByCursorScore(c, key, cursor)
ctx.Convey("Then err should be nil.p1 should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestReplyRangeRootIDByCursorScore(t *testing.T) {
convey.Convey("RangeRootIDByCursorScore", t, func(ctx convey.C) {
var (
c = context.Background()
key = ""
cursor = &model.Cursor{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1, p2, err := d.Redis.RangeRootIDByCursorScore(c, key, cursor)
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 TestReplyRangeRootReplyIDs(t *testing.T) {
convey.Convey("RangeRootReplyIDs", t, func(ctx convey.C) {
var (
c = context.Background()
key = ""
start = int(0)
end = int(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1, err := d.Redis.RangeRootReplyIDs(c, key, start, end)
ctx.Convey("Then err should be nil.p1 should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestReplyExpireCache(t *testing.T) {
convey.Convey("ExpireCache", t, func(ctx convey.C) {
var (
c = context.Background()
key = ""
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1, err := d.Redis.ExpireCache(c, key)
ctx.Convey("Then err should be nil.p1 should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestReplygenChildrenKeyParentIDMap(t *testing.T) {
convey.Convey("genChildrenKeyParentIDMap", t, func(ctx convey.C) {
var (
ids = []int64{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := genChildrenKeyParentIDMap(ids)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestReplygenChildrenKeyByRootReplyIDs(t *testing.T) {
convey.Convey("genChildrenKeyByRootReplyIDs", t, func(ctx convey.C) {
var (
ids = []int64{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := genChildrenKeyByRootReplyIDs(ids)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestReplygenNewChildrenKeyByRootReplyID(t *testing.T) {
convey.Convey("GenNewChildrenKeyByRootReplyID", t, func(ctx convey.C) {
var (
id = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := GenNewChildrenKeyByRootReplyID(id)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestReplygenReplyKeyByID(t *testing.T) {
convey.Convey("genReplyKeyByID", t, func(ctx convey.C) {
var (
id = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := genReplyKeyByID(id)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestReplycontains(t *testing.T) {
convey.Convey("contains", t, func(ctx convey.C) {
var (
arr = []string{}
b = ""
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := contains(arr, b)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestReplyGetReplyByIDs(t *testing.T) {
convey.Convey("GetReplyByIDs", t, func(ctx convey.C) {
var (
c = context.Background()
ids = []int64{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1, p2, err := d.Mc.GetReplyByIDs(c, ids)
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 TestReplyChildrenIDSortByFloorCursor(t *testing.T) {
convey.Convey("ChildrenIDSortByFloorCursor", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
tp = int8(0)
rootID = int64(0)
cursor = &model.Cursor{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1, err := d.Reply.ChildrenIDSortByFloorCursor(c, oid, tp, rootID, cursor)
ctx.Convey("Then err should be nil.p1 should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestReplyRootIDSortByFloorCursor(t *testing.T) {
convey.Convey("RootIDSortByFloorCursor", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
tp = int8(0)
cursor = &model.Cursor{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1, err := d.Reply.RootIDSortByFloorCursor(c, oid, tp, cursor)
ctx.Convey("Then err should be nil.p1 should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,83 @@
package reply
import (
"context"
"go-common/app/interface/main/reply/conf"
"go-common/library/database/sql"
)
// Dao Dao
type Dao struct {
// memcache
Mc *MemcacheDao
// mysql
mysql *sql.DB
dbSlave *sql.DB
Admin *AdminDao
Content *ContentDao
Report *ReportDao
Reply *RpDao
Captcha *CaptchaDao
Notice *NoticeDao
CreditUser *CreditUserDao
Subject *SubjectDao
Config *ConfigDao
BlockStatus *BlockStatusDao
Business *BusinessDao
// redis
Redis *RedisDao
// kafka
Databus *DatabusDao
Emoji *EmoDao
}
// New New
func New(c *conf.Config) (d *Dao) {
d = &Dao{
// memchache
Mc: NewMemcacheDao(c.Memcache),
// mysql
mysql: sql.NewMySQL(c.MySQL.Reply),
dbSlave: sql.NewMySQL(c.MySQL.ReplySlave),
// redis
Redis: NewRedisDao(c.Redis),
Databus: NewDatabusDao(c.Databus),
}
d.Admin = NewAdminDao(d.mysql)
d.Content = NewContentDao(d.mysql, d.dbSlave)
d.Reply = NewReplyDao(d.mysql, d.dbSlave)
d.Report = NewReportDao(d.mysql)
d.Subject = NewSubjectDao(d.mysql)
d.Notice = NewNoticeDao(d.mysql)
d.Config = NewConfigDao(d.mysql)
d.Captcha = NewCaptchaDao(c.HTTPClient)
d.CreditUser = NewCreditDao(c)
d.BlockStatus = NewBlockStatusDao(c)
d.Business = NewBusinessDao(d.mysql)
d.Emoji = NewEmojiDao(d.mysql)
return
}
// Ping Ping
func (d *Dao) Ping(c context.Context) (err error) {
if err = d.mysql.Ping(c); err != nil {
return
}
if err = d.Redis.Ping(c); err != nil {
return
}
return d.Mc.Ping(c)
}
// Close Close
func (d *Dao) Close() {
if d.Mc.mc != nil {
d.Mc.mc.Close()
}
if d.Redis.redis != nil {
d.Redis.redis.Close()
}
d.mysql.Close()
}

View File

@@ -0,0 +1,36 @@
package reply
import (
"flag"
"go-common/app/interface/main/reply/conf"
"os"
"testing"
)
var (
d *Dao
D *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.community.reply")
flag.Set("conf_token", "54e85e3ab609f79ae908b9ea3e3f0775")
flag.Set("tree_id", "2125")
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/reply-test.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
D = d
os.Exit(m.Run())
}

View File

@@ -0,0 +1,559 @@
package reply
import (
"context"
"strconv"
"go-common/app/interface/main/reply/model/reply"
"go-common/library/queue/databus"
)
// DatabusDao DatabusDao
type DatabusDao struct {
topic string
databus *databus.Databus
}
type kafkadata struct {
Op string `json:"op,omitempty"`
Mid int64 `json:"mid,omitempty"`
Adid int64 `json:"adid,omitempty"`
Oid int64 `json:"oid,omitempty"`
Rpid int64 `json:"rpid,omitempty"`
Root int64 `json:"root,omitempty"`
Dialog int64 `json:"dialog,omitempty"`
Remark string `json:"remark,omitempty"`
Adname string `json:"adname,omitempty"`
Mtime int64 `json:"mtime,omitempty"`
Action int8 `json:"action,omitempty"`
Sort int8 `json:"sort,omitempty"`
Tp int8 `json:"tp,omitempty"`
Moral int `json:"moral,omitempty"`
Notify bool `json:"notify,omitempty"`
Top uint32 `json:"top,omitempty"`
Ftime int64 `json:"ftime,omitempty"`
State int8 `json:"state,omitempty"`
Audit int8 `json:"audit,omitempty"`
Reason int8 `json:"reason,omitempty"`
Content string `json:"content,omitempty"`
FReason int8 `json:"freason,omitempty"`
Assist bool `json:"assist,omitempty"`
Count int `json:"count,omitempty"`
Floor int `json:"floor,omitempty"`
IsUp bool `json:"is_up,omitempty"`
}
// NewDatabusDao new ReplyKafkaDao and return.
func NewDatabusDao(c *databus.Config) (dao *DatabusDao) {
dao = &DatabusDao{
topic: c.Topic,
databus: databus.New(c),
}
return
}
// PubEvent pub reply event.
func (dao *DatabusDao) push(c context.Context, key string, value interface{}) error {
return dao.databus.Send(c, key, value)
}
// RecoverFixDialogIdx ...
func (dao *DatabusDao) RecoverFixDialogIdx(c context.Context, oid int64, tp int8, root int64) {
var message = map[string]interface{}{}
message["action"] = "fix_dialog"
message["data"] = kafkadata{
Oid: oid,
Tp: tp,
Root: root,
}
key := strconv.FormatInt(oid, 10)
dao.push(c, key, message)
}
// RecoverFolderIdx ...
func (dao *DatabusDao) RecoverFolderIdx(c context.Context, oid int64, tp int8, root int64) {
var message = map[string]interface{}{}
message["action"] = "folder"
message["data"] = kafkadata{
Op: "re_idx",
Oid: oid,
Tp: tp,
Root: root,
}
key := strconv.FormatInt(oid, 10)
dao.push(c, key, message)
}
// RecoverDialogIdx Recover dialog index
func (dao *DatabusDao) RecoverDialogIdx(c context.Context, oid int64, tp int8, root, dialog int64) {
var message = map[string]interface{}{}
message["action"] = "idx_dialog"
message["data"] = kafkadata{
Oid: oid,
Tp: tp,
Root: root,
Dialog: dialog,
}
key := strconv.FormatInt(oid, 10)
dao.push(c, key, message)
}
// RecoverFloorIdx RecoverFloorIdx
func (dao *DatabusDao) RecoverFloorIdx(c context.Context, oid int64, tp int8, num int, isFloor bool) {
var (
message = map[string]interface{}{}
)
message["action"] = "idx_floor"
if isFloor {
message["data"] = kafkadata{
Oid: oid,
Tp: tp,
Floor: num,
}
} else {
message["data"] = kafkadata{
Oid: oid,
Tp: tp,
Count: num,
}
}
key := strconv.FormatInt(oid, 10)
dao.push(c, key, message)
}
// AddTop AddTop
func (dao *DatabusDao) AddTop(c context.Context, oid int64, tp int8, top uint32) {
var (
message = make(map[string]interface{})
)
message["action"] = "add_top"
message["data"] = kafkadata{
Oid: oid,
Tp: tp,
Top: top,
}
key := strconv.FormatInt(oid, 10)
dao.push(c, key, message)
}
// AddReply push event message into kafka.
func (dao *DatabusDao) AddReply(c context.Context, oid int64, rp *reply.Reply) {
var (
message = make(map[string]interface{})
)
message["action"] = "add"
message["data"] = rp
key := strconv.FormatInt(oid, 10)
dao.push(c, key, message)
}
// AddSpam push event message into kafka.
func (dao *DatabusDao) AddSpam(c context.Context, oid, mid int64, isUp bool, tp int8) {
var (
message = make(map[string]interface{})
)
message["action"] = "spam"
data := kafkadata{
Mid: mid,
IsUp: isUp,
Tp: tp,
}
message["data"] = data
key := strconv.FormatInt(oid, 10)
dao.push(c, key, message)
}
// AddReport push event message into kafka.
func (dao *DatabusDao) AddReport(c context.Context, oid, rpID int64, tp int8) {
var (
message = make(map[string]interface{})
)
message["action"] = "rpt"
data := kafkadata{
Oid: oid,
Rpid: rpID,
Tp: tp,
}
message["data"] = data
key := strconv.FormatInt(oid, 10)
dao.push(c, key, message)
}
// Like push event message into kafka.
func (dao *DatabusDao) Like(c context.Context, oid, rpID, mid int64, action int8, ts int64) {
var (
message = make(map[string]interface{})
)
message["action"] = "act"
data := kafkadata{
Oid: oid,
Mid: mid,
Rpid: rpID,
Action: action,
Op: "like",
Mtime: ts,
}
message["data"] = data
key := strconv.FormatInt(oid, 10)
dao.push(c, key, message)
}
// Hate push event message into kafka.
func (dao *DatabusDao) Hate(c context.Context, oid, rpID, mid int64, action int8, ts int64) {
var (
message = make(map[string]interface{})
)
message["action"] = "act"
data := kafkadata{
Oid: oid,
Mid: mid,
Rpid: rpID,
Action: action,
Op: "hate",
Mtime: ts,
}
message["data"] = data
key := strconv.FormatInt(oid, 10)
dao.push(c, key, message)
}
// RecoverIndex push event message into kafka.
func (dao *DatabusDao) RecoverIndex(c context.Context, oid int64, tp, sort int8) {
var (
message = make(map[string]interface{})
)
message["action"] = "re_idx"
data := kafkadata{
Oid: oid,
Tp: tp,
Sort: sort,
}
message["data"] = data
key := strconv.FormatInt(oid, 10)
dao.push(c, key, message)
}
// RecoverIndexByRoot push event message into kafka.
func (dao *DatabusDao) RecoverIndexByRoot(c context.Context, oid, root int64, tp int8) {
var (
message = make(map[string]interface{})
)
message["action"] = "re_rt_idx"
data := kafkadata{
Oid: oid,
Tp: tp,
Root: root,
}
message["data"] = data
key := strconv.FormatInt(oid, 10)
dao.push(c, key, message)
}
// Hide push event message into kafka.
func (dao *DatabusDao) Hide(c context.Context, oid, rpID int64, tp int8, ts int64) {
var (
message = make(map[string]interface{})
)
message["action"] = "up"
data := kafkadata{
Oid: oid,
Rpid: rpID,
Mtime: ts,
Tp: tp,
Op: "hide",
}
message["data"] = data
key := strconv.FormatInt(oid, 10)
dao.push(c, key, message)
}
// Show push event message into kafka.
func (dao *DatabusDao) Show(c context.Context, oid, rpID int64, tp int8, ts int64) {
var (
message = make(map[string]interface{})
)
message["action"] = "up"
data := kafkadata{
Op: "show",
Oid: oid,
Tp: tp,
Rpid: rpID,
Mtime: ts,
}
message["data"] = data
key := strconv.FormatInt(oid, 10)
dao.push(c, key, message)
}
// Delete push event message into kafka.
func (dao *DatabusDao) Delete(c context.Context, mid, oid, rpID int64, ts int64, tp int8, assist bool) {
var (
message = make(map[string]interface{})
)
message["action"] = "admin"
data := kafkadata{
Op: "del_up",
Oid: oid,
Mid: mid,
Rpid: rpID,
Tp: tp,
Mtime: ts,
Assist: assist,
}
message["data"] = data
key := strconv.FormatInt(oid, 10)
dao.push(c, key, message)
}
// AdminEdit push event message into kafka.
func (dao *DatabusDao) AdminEdit(c context.Context, oid, rpID int64, tp int8) {
var (
message = make(map[string]interface{})
)
message["action"] = "admin"
data := kafkadata{
Op: "edit",
Oid: oid,
Tp: tp,
Rpid: rpID,
}
message["data"] = data
key := strconv.FormatInt(oid, 10)
dao.push(c, key, message)
}
// AdminAddTop push event message into kafka.
func (dao *DatabusDao) AdminAddTop(c context.Context, adid, oid, rpID, ts int64, act, tp int8) {
var (
message = make(map[string]interface{})
)
message["action"] = "admin"
data := kafkadata{
Op: "top_add",
Oid: oid,
Adid: adid,
Rpid: rpID,
Tp: tp,
Action: act,
Mtime: ts,
}
message["data"] = data
key := strconv.FormatInt(oid, 10)
dao.push(c, key, message)
}
// UpperAddTop push event message into kafka.
func (dao *DatabusDao) UpperAddTop(c context.Context, mid, oid, rpID, ts int64, act, tp int8) {
var (
message = make(map[string]interface{})
)
message["action"] = "up"
data := kafkadata{
Op: "top_add",
Oid: oid,
Tp: tp,
Mid: mid,
Rpid: rpID,
Action: act,
Mtime: ts,
}
message["data"] = data
key := strconv.FormatInt(oid, 10)
dao.push(c, key, message)
}
// AdminDelete push event message into kafka.
func (dao *DatabusDao) AdminDelete(c context.Context, adid, oid, rpID, ftime int64, moral int, notify bool, adname, remark string, ts int64, tp, reason, freason int8) {
var (
message = make(map[string]interface{})
)
message["action"] = "admin"
data := kafkadata{
Op: "del",
Adid: adid,
Rpid: rpID,
Oid: oid,
Moral: moral,
Notify: notify,
Tp: tp,
Adname: adname,
Remark: remark,
Mtime: ts,
Ftime: ftime,
Reason: reason,
FReason: freason,
}
message["data"] = data
key := strconv.FormatInt(oid, 10)
dao.push(c, key, message)
}
// AdminDeleteByReport push event message into kafka.
func (dao *DatabusDao) AdminDeleteByReport(c context.Context, adid, oid, rpID, mid, ftime int64, moral int, notify bool, adname, remark string, ts int64, tp, audit, reason int8, content string, freason int8) {
var (
message = make(map[string]interface{})
)
message["action"] = "admin"
data := kafkadata{
Op: "del_rpt",
Adid: adid,
Oid: oid,
Rpid: rpID,
Mid: mid,
Moral: moral,
Tp: tp,
Notify: notify,
Adname: adname,
Remark: remark,
Mtime: ts,
Ftime: ftime,
Audit: audit,
Reason: reason,
Content: content,
FReason: freason,
}
message["data"] = data
key := strconv.FormatInt(oid, 10)
dao.push(c, key, message)
}
// AdminRecover push event message into kafka.
func (dao *DatabusDao) AdminRecover(c context.Context, adid, oid, rpID int64, remark string, ts int64, tp int8) {
var (
message = make(map[string]interface{})
)
message["action"] = "admin"
data := kafkadata{
Op: "re",
Adid: adid,
Oid: oid,
Rpid: rpID,
Tp: tp,
Remark: remark,
Mtime: ts,
}
message["data"] = data
key := strconv.FormatInt(oid, 10)
dao.push(c, key, message)
}
// AdminPass push pass event message into kafka.
func (dao *DatabusDao) AdminPass(c context.Context, adid, oid, rpID int64, remark string, ts int64, tp int8) {
var (
message = make(map[string]interface{})
)
message["action"] = "admin"
data := kafkadata{
Op: "pass",
Adid: adid,
Oid: oid,
Rpid: rpID,
Tp: tp,
Remark: remark,
Mtime: ts,
}
message["data"] = data
key := strconv.FormatInt(oid, 10)
dao.push(c, key, message)
}
// AdminStateSet push event message into kafka.
func (dao *DatabusDao) AdminStateSet(c context.Context, adid, oid, rpID, ts int64, tp, state int8) {
var (
message = make(map[string]interface{})
)
message["action"] = "admin"
data := kafkadata{
Op: "stateset",
Adid: adid,
Oid: oid,
Rpid: rpID,
Tp: tp,
State: state,
Mtime: ts,
}
message["data"] = data
key := strconv.FormatInt(oid, 10)
dao.push(c, key, message)
}
// AdminTransfer push event message into kafka.
func (dao *DatabusDao) AdminTransfer(c context.Context, adid, oid, rpID, ts int64, tp, audit int8) {
var (
message = make(map[string]interface{})
)
message["action"] = "admin"
message["data"] = kafkadata{
Op: "transfer",
Adid: adid,
Oid: oid,
Rpid: rpID,
Tp: tp,
Audit: audit,
Mtime: ts,
}
key := strconv.FormatInt(oid, 10)
dao.push(c, key, message)
}
// AdminIgnore push event message into kafka.
func (dao *DatabusDao) AdminIgnore(c context.Context, adid, oid, rpID, ts int64, tp, audit int8) {
var (
message = make(map[string]interface{})
)
message["action"] = "admin"
data := kafkadata{
Op: "ignore",
Adid: adid,
Oid: oid,
Rpid: rpID,
Tp: tp,
Audit: audit,
Mtime: ts,
}
message["data"] = data
key := strconv.FormatInt(oid, 10)
dao.push(c, key, message)
}
// AdminReportRecover push event message into kafka.
func (dao *DatabusDao) AdminReportRecover(c context.Context, adid, oid, rpID int64, remark string, ts int64, tp, audit int8) {
var (
message = make(map[string]interface{})
)
message["action"] = "admin"
data := kafkadata{
Op: "rpt_re",
Adid: adid,
Oid: oid,
Rpid: rpID,
Tp: tp,
Audit: audit,
Remark: remark,
Mtime: ts,
}
message["data"] = data
key := strconv.FormatInt(oid, 10)
dao.push(c, key, message)
}

View File

@@ -0,0 +1,496 @@
package reply
import (
"context"
"go-common/app/interface/main/reply/model/reply"
"go-common/library/queue/databus"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestReplyNewDatabusDao(t *testing.T) {
convey.Convey("NewDatabusDao", t, func(ctx convey.C) {
var (
c = &databus.Config{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
dao := NewDatabusDao(c)
ctx.Convey("Then dao should not be nil.", func(ctx convey.C) {
ctx.So(dao, convey.ShouldNotBeNil)
})
})
})
}
func TestReplypush(t *testing.T) {
convey.Convey("push", t, func(ctx convey.C) {
var (
c = context.Background()
key = ""
value = interface{}(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.Databus.push(c, key, value)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestReplyRecoverFixDialogIdx(t *testing.T) {
convey.Convey("RecoverFixDialogIdx", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
tp = int8(0)
root = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
d.Databus.RecoverFixDialogIdx(c, oid, tp, root)
ctx.Convey("No return values", func(ctx convey.C) {
})
})
})
}
func TestReplyRecoverDialogIdx(t *testing.T) {
convey.Convey("RecoverDialogIdx", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
tp = int8(0)
root = int64(0)
dialog = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
d.Databus.RecoverDialogIdx(c, oid, tp, root, dialog)
ctx.Convey("No return values", func(ctx convey.C) {
})
})
})
}
func TestReplyRecoverFloorIdx(t *testing.T) {
convey.Convey("RecoverFloorIdx", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
tp = int8(0)
num = int(0)
isFloor bool
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
d.Databus.RecoverFloorIdx(c, oid, tp, num, isFloor)
ctx.Convey("No return values", func(ctx convey.C) {
})
})
})
}
func TestReplyDatabusAddTop(t *testing.T) {
convey.Convey("AddTop", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
tp = int8(0)
top = uint32(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
d.Databus.AddTop(c, oid, tp, top)
ctx.Convey("No return values", func(ctx convey.C) {
})
})
})
}
func TestReplyDatabusAddReply(t *testing.T) {
convey.Convey("AddReply", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
rp = &reply.Reply{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
d.Databus.AddReply(c, oid, rp)
ctx.Convey("No return values", func(ctx convey.C) {
})
})
})
}
func TestReplyAddSpam(t *testing.T) {
convey.Convey("AddSpam", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
mid = int64(0)
tp = int8(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
d.Databus.AddSpam(c, oid, mid, false, tp)
ctx.Convey("No return values", func(ctx convey.C) {
})
})
})
}
func TestReplyAddReport(t *testing.T) {
convey.Convey("AddReport", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
rpID = int64(0)
tp = int8(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
d.Databus.AddReport(c, oid, rpID, tp)
ctx.Convey("No return values", func(ctx convey.C) {
})
})
})
}
func TestReplyLike(t *testing.T) {
convey.Convey("Like", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
rpID = int64(0)
mid = int64(0)
action = int8(0)
ts = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
d.Databus.Like(c, oid, rpID, mid, action, ts)
ctx.Convey("No return values", func(ctx convey.C) {
})
})
})
}
func TestReplyHate(t *testing.T) {
convey.Convey("Hate", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
rpID = int64(0)
mid = int64(0)
action = int8(0)
ts = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
d.Databus.Hate(c, oid, rpID, mid, action, ts)
ctx.Convey("No return values", func(ctx convey.C) {
})
})
})
}
func TestReplyRecoverIndex(t *testing.T) {
convey.Convey("RecoverIndex", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
tp = int8(0)
sort = int8(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
d.Databus.RecoverIndex(c, oid, tp, sort)
ctx.Convey("No return values", func(ctx convey.C) {
})
})
})
}
func TestReplyRecoverIndexByRoot(t *testing.T) {
convey.Convey("RecoverIndexByRoot", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
root = int64(0)
tp = int8(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
d.Databus.RecoverIndexByRoot(c, oid, root, tp)
ctx.Convey("No return values", func(ctx convey.C) {
})
})
})
}
func TestReplyHide(t *testing.T) {
convey.Convey("Hide", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
rpID = int64(0)
tp = int8(0)
ts = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
d.Databus.Hide(c, oid, rpID, tp, ts)
ctx.Convey("No return values", func(ctx convey.C) {
})
})
})
}
func TestReplyShow(t *testing.T) {
convey.Convey("Show", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
rpID = int64(0)
tp = int8(0)
ts = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
d.Databus.Show(c, oid, rpID, tp, ts)
ctx.Convey("No return values", func(ctx convey.C) {
})
})
})
}
func TestReplyDelete(t *testing.T) {
convey.Convey("Delete", t, func(ctx convey.C) {
var (
c = context.Background()
mid = int64(0)
oid = int64(0)
rpID = int64(0)
ts = int64(0)
tp = int8(0)
assist bool
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
d.Databus.Delete(c, mid, oid, rpID, ts, tp, assist)
ctx.Convey("No return values", func(ctx convey.C) {
})
})
})
}
func TestReplyAdminEdit(t *testing.T) {
convey.Convey("AdminEdit", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
rpID = int64(0)
tp = int8(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
d.Databus.AdminEdit(c, oid, rpID, tp)
ctx.Convey("No return values", func(ctx convey.C) {
})
})
})
}
func TestReplyAdminAddTop(t *testing.T) {
convey.Convey("AdminAddTop", t, func(ctx convey.C) {
var (
c = context.Background()
adid = int64(0)
oid = int64(0)
rpID = int64(0)
ts = int64(0)
act = int8(0)
tp = int8(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
d.Databus.AdminAddTop(c, adid, oid, rpID, ts, act, tp)
ctx.Convey("No return values", func(ctx convey.C) {
})
})
})
}
func TestReplyUpperAddTop(t *testing.T) {
convey.Convey("UpperAddTop", t, func(ctx convey.C) {
var (
c = context.Background()
mid = int64(0)
oid = int64(0)
rpID = int64(0)
ts = int64(0)
act = int8(0)
tp = int8(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
d.Databus.UpperAddTop(c, mid, oid, rpID, ts, act, tp)
ctx.Convey("No return values", func(ctx convey.C) {
})
})
})
}
func TestReplyAdminDelete(t *testing.T) {
convey.Convey("AdminDelete", t, func(ctx convey.C) {
var (
c = context.Background()
adid = int64(0)
oid = int64(0)
rpID = int64(0)
ftime = int64(0)
moral = int(0)
notify bool
adname = ""
remark = ""
ts = int64(0)
tp = int8(0)
reason = int8(0)
freason = int8(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
d.Databus.AdminDelete(c, adid, oid, rpID, ftime, moral, notify, adname, remark, ts, tp, reason, freason)
ctx.Convey("No return values", func(ctx convey.C) {
})
})
})
}
func TestReplyAdminDeleteByReport(t *testing.T) {
convey.Convey("AdminDeleteByReport", t, func(ctx convey.C) {
var (
c = context.Background()
adid = int64(0)
oid = int64(0)
rpID = int64(0)
mid = int64(0)
ftime = int64(0)
moral = int(0)
notify bool
adname = ""
remark = ""
ts = int64(0)
tp = int8(0)
audit = int8(0)
reason = int8(0)
content = ""
freason = int8(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
d.Databus.AdminDeleteByReport(c, adid, oid, rpID, mid, ftime, moral, notify, adname, remark, ts, tp, audit, reason, content, freason)
ctx.Convey("No return values", func(ctx convey.C) {
})
})
})
}
func TestReplyAdminRecover(t *testing.T) {
convey.Convey("AdminRecover", t, func(ctx convey.C) {
var (
c = context.Background()
adid = int64(0)
oid = int64(0)
rpID = int64(0)
remark = ""
ts = int64(0)
tp = int8(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
d.Databus.AdminRecover(c, adid, oid, rpID, remark, ts, tp)
ctx.Convey("No return values", func(ctx convey.C) {
})
})
})
}
func TestReplyAdminPass(t *testing.T) {
convey.Convey("AdminPass", t, func(ctx convey.C) {
var (
c = context.Background()
adid = int64(0)
oid = int64(0)
rpID = int64(0)
remark = ""
ts = int64(0)
tp = int8(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
d.Databus.AdminPass(c, adid, oid, rpID, remark, ts, tp)
ctx.Convey("No return values", func(ctx convey.C) {
})
})
})
}
func TestReplyAdminStateSet(t *testing.T) {
convey.Convey("AdminStateSet", t, func(ctx convey.C) {
var (
c = context.Background()
adid = int64(0)
oid = int64(0)
rpID = int64(0)
ts = int64(0)
tp = int8(0)
state = int8(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
d.Databus.AdminStateSet(c, adid, oid, rpID, ts, tp, state)
ctx.Convey("No return values", func(ctx convey.C) {
})
})
})
}
func TestReplyAdminTransfer(t *testing.T) {
convey.Convey("AdminTransfer", t, func(ctx convey.C) {
var (
c = context.Background()
adid = int64(0)
oid = int64(0)
rpID = int64(0)
ts = int64(0)
tp = int8(0)
audit = int8(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
d.Databus.AdminTransfer(c, adid, oid, rpID, ts, tp, audit)
ctx.Convey("No return values", func(ctx convey.C) {
})
})
})
}
func TestReplyAdminIgnore(t *testing.T) {
convey.Convey("AdminIgnore", t, func(ctx convey.C) {
var (
c = context.Background()
adid = int64(0)
oid = int64(0)
rpID = int64(0)
ts = int64(0)
tp = int8(0)
audit = int8(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
d.Databus.AdminIgnore(c, adid, oid, rpID, ts, tp, audit)
ctx.Convey("No return values", func(ctx convey.C) {
})
})
})
}
func TestReplyAdminReportRecover(t *testing.T) {
convey.Convey("AdminReportRecover", t, func(ctx convey.C) {
var (
c = context.Background()
adid = int64(0)
oid = int64(0)
rpID = int64(0)
remark = ""
ts = int64(0)
tp = int8(0)
audit = int8(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
d.Databus.AdminReportRecover(c, adid, oid, rpID, remark, ts, tp, audit)
ctx.Convey("No return values", func(ctx convey.C) {
})
})
})
}

View File

@@ -0,0 +1,81 @@
package reply
import (
"context"
"go-common/app/interface/main/reply/model/reply"
"go-common/library/database/sql"
)
const (
_selEmojiSQL = "select id,package_id,name,url,state,remark from emoji where state=0 order by sort"
_selEmoByPidSQL = "select id,package_id,name,url,state,remark from emoji where state=0 and package_id=? order by sort"
_selEmojiPackageSQL = "select id,name,url,state from emoji_package where state=0 order by sort"
)
// EmoDao emoji dao
type EmoDao struct {
db *sql.DB
}
// NewEmojiDao NewEmojiDao
func NewEmojiDao(db *sql.DB) (dao *EmoDao) {
dao = &EmoDao{
db: db,
}
return
}
// EmojiList get all emoji
func (dao *EmoDao) EmojiList(c context.Context) (emo []*reply.Emoji, err error) {
rows, err := dao.db.Query(c, _selEmojiSQL)
if err != nil {
return
}
defer rows.Close()
for rows.Next() {
emoji := &reply.Emoji{}
if err = rows.Scan(&emoji.ID, &emoji.PackageID, &emoji.Name, &emoji.URL, &emoji.State, &emoji.Remark); err != nil {
return
}
emo = append(emo, emoji)
}
err = rows.Err()
return
}
// EmojiListByPid get emoji by package_id
func (dao *EmoDao) EmojiListByPid(c context.Context, pid int64) (emo []*reply.Emoji, err error) {
rows, err := dao.db.Query(c, _selEmoByPidSQL, pid)
if err != nil {
return
}
defer rows.Close()
emo = make([]*reply.Emoji, 0)
for rows.Next() {
emoji := &reply.Emoji{}
if err = rows.Scan(&emoji.ID, &emoji.PackageID, &emoji.Name, &emoji.URL, &emoji.State, &emoji.Remark); err != nil {
return
}
emo = append(emo, emoji)
}
err = rows.Err()
return
}
// ListEmojiPack get all emojipack
func (dao *EmoDao) ListEmojiPack(c context.Context) (packs []*reply.EmojiPackage, err error) {
rows, err := dao.db.Query(c, _selEmojiPackageSQL)
if err != nil {
return
}
defer rows.Close()
for rows.Next() {
p := &reply.EmojiPackage{}
if err = rows.Scan(&p.ID, &p.Name, &p.URL, &p.State); err != nil {
return
}
packs = append(packs, p)
}
err = rows.Err()
return
}

View File

@@ -0,0 +1,69 @@
package reply
import (
"context"
"go-common/library/database/sql"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestReplyNewEmojiDao(t *testing.T) {
convey.Convey("NewEmojiDao", t, func(ctx convey.C) {
var (
db = &sql.DB{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
dao := NewEmojiDao(db)
ctx.Convey("Then dao should not be nil.", func(ctx convey.C) {
ctx.So(dao, convey.ShouldNotBeNil)
})
})
})
}
func TestReplyEmojiList(t *testing.T) {
convey.Convey("EmojiList", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
emo, err := d.Emoji.EmojiList(c)
ctx.Convey("Then err should be nil.emo should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(emo, convey.ShouldNotBeNil)
})
})
})
}
func TestReplyEmojiListByPid(t *testing.T) {
convey.Convey("EmojiListByPid", t, func(ctx convey.C) {
var (
c = context.Background()
pid = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
emo, err := d.Emoji.EmojiListByPid(c, pid)
ctx.Convey("Then err should be nil.emo should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(emo, convey.ShouldNotBeNil)
})
})
})
}
func TestReplyListEmojiPack(t *testing.T) {
convey.Convey("ListEmojiPack", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
packs, err := d.Emoji.ListEmojiPack(c)
ctx.Convey("Then err should be nil.packs should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(packs, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,380 @@
package reply
import (
"context"
"fmt"
"strconv"
"time"
"go-common/app/interface/main/reply/conf"
model "go-common/app/interface/main/reply/model/reply"
"go-common/library/cache/memcache"
"go-common/library/log"
)
const (
_prefixSub = "s_"
_prefixRp = "r_"
_prefixAdminTop = "at_"
_prefixUpperTop = "ut_"
_prefixConfig = "c_%d_%d_%d"
_prefixCaptcha = "pc_%d"
)
// MemcacheDao memcache dao.
type MemcacheDao struct {
mc *memcache.Pool
expire int32
emptyExpire int32
}
// NewMemcacheDao new a memcache dao and return.
func NewMemcacheDao(c *conf.Memcache) *MemcacheDao {
m := &MemcacheDao{
mc: memcache.NewPool(c.Config),
expire: int32(time.Duration(c.Expire) / time.Second),
emptyExpire: int32(time.Duration(c.EmptyExpire) / time.Second),
}
return m
}
func keyCaptcha(mid int64) string { return fmt.Sprintf(_prefixCaptcha, mid) }
func keyAdminTop(oid int64, tp int8) string {
if oid > _oidOverflow {
return fmt.Sprintf("%s_%d_%d", _prefixAdminTop, oid, tp)
}
return _prefixAdminTop + strconv.FormatInt((oid<<8)|int64(tp), 10)
}
func keyUpperTop(oid int64, tp int8) string {
if oid > _oidOverflow {
return fmt.Sprintf("%s_%d_%d", _prefixUpperTop, oid, tp)
}
return _prefixUpperTop + strconv.FormatInt((oid<<8)|int64(tp), 10)
}
func keySub(oid int64, tp int8) string {
if oid > _oidOverflow {
return fmt.Sprintf("%s_%d_%d", _prefixSub, oid, tp)
}
return _prefixSub + strconv.FormatInt((oid<<8)|int64(tp), 10)
}
func keyRp(rpID int64) string {
return _prefixRp + strconv.FormatInt(rpID, 10)
}
func keyConfig(oid int64, typ, category int8) string {
return fmt.Sprintf(_prefixConfig, oid, typ, category)
}
// Ping check connection success.
func (dao *MemcacheDao) Ping(c context.Context) (err error) {
conn := dao.mc.Get(c)
item := memcache.Item{Key: "ping", Value: []byte{1}, Expiration: dao.expire}
err = conn.Set(&item)
conn.Close()
return
}
// CaptchaToken CaptchaToken
func (dao *MemcacheDao) CaptchaToken(c context.Context, mid int64) (string, error) {
conn := dao.mc.Get(c)
defer conn.Close()
item, err := conn.Get(keyCaptcha(mid))
if err == memcache.ErrNotFound {
return "", nil
}
if err != nil {
return "", err
}
var token string
if err = conn.Scan(item, &token); err != nil {
log.Error("conn.Scan(%s) error(%v)", item.Value, err)
return "", err
}
return token, nil
}
// SetCaptchaToken SetCaptchaToken
func (dao *MemcacheDao) SetCaptchaToken(c context.Context, mid int64, token string) error {
conn := dao.mc.Get(c)
defer conn.Close()
return conn.Set(&memcache.Item{
Key: keyCaptcha(mid),
Value: []byte(token),
Expiration: int32(time.Minute * 5 / time.Second),
})
}
// GetSubject get subject from memcache.
func (dao *MemcacheDao) GetSubject(c context.Context, oid int64, tp int8) (sub *model.Subject, err error) {
key := keySub(oid, tp)
conn := dao.mc.Get(c)
defer conn.Close()
item, err := conn.Get(key)
if err != nil {
if err == memcache.ErrNotFound {
err = nil
}
return
}
sub = new(model.Subject)
if err = conn.Scan(item, sub); err != nil {
log.Error("conn.Scan(%s) error(%v)", item.Value, err)
sub = nil
}
return
}
// GetMultiSubject get subject from memcache.
func (dao *MemcacheDao) GetMultiSubject(c context.Context, oids []int64, tp int8) (res map[int64]*model.Subject, missed []int64, err error) {
var (
keys = make([]string, len(oids))
missKeys = make(map[string]int64, len(oids))
)
for i, oid := range oids {
key := keySub(oid, tp)
keys[i] = key
missKeys[key] = oid
}
conn := dao.mc.Get(c)
defer conn.Close()
items, err := conn.GetMulti(keys)
if err != nil {
if err == memcache.ErrNotFound {
err = nil
}
missed = oids
return
}
res = make(map[int64]*model.Subject, len(items))
for _, item := range items {
sub := new(model.Subject)
if err = conn.Scan(item, sub); err != nil {
log.Error("conn.Scan(%s) error(%v)", item.Value, err)
continue
}
res[sub.Oid] = sub
delete(missKeys, item.Key)
}
missed = make([]int64, 0, len(missKeys))
for _, oid := range missKeys {
missed = append(missed, oid)
}
return
}
// DeleteSubject delete subject from memcache.
func (dao *MemcacheDao) DeleteSubject(c context.Context, oid int64, tp int8) (err error) {
key := keySub(oid, tp)
conn := dao.mc.Get(c)
if err = conn.Delete(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
} else {
log.Error("conn.Delete(%s) error(%v)", key, err)
}
}
conn.Close()
return
}
// AddSubject add subject into memcache.
func (dao *MemcacheDao) AddSubject(c context.Context, subs ...*model.Subject) (err error) {
if len(subs) == 0 {
return
}
conn := dao.mc.Get(c)
for _, sub := range subs {
exp := dao.expire
if sub.ID == -1 {
exp = dao.emptyExpire
}
key := keySub(sub.Oid, sub.Type)
item := &memcache.Item{Key: key, Object: sub, Expiration: exp, Flags: memcache.FlagJSON}
if err = conn.Set(item); err != nil {
log.Error("conn.Set(%s,%v) error(%v)", key, sub, err)
}
}
conn.Close()
return
}
// AddReply add reply into memcache.
func (dao *MemcacheDao) AddReply(c context.Context, rs ...*model.Reply) (err error) {
if len(rs) == 0 {
return
}
conn := dao.mc.Get(c)
for _, r := range rs {
if r == nil {
continue
}
key := keyRp(r.RpID)
item := &memcache.Item{Key: key, Object: r, Expiration: dao.expire, Flags: memcache.FlagJSON}
if err = conn.Set(item); err != nil {
log.Error("conn.Set(%s,%v) error(%v)", key, r, err)
}
}
conn.Close()
return
}
// AddTop add top reply into memcache.
func (dao *MemcacheDao) AddTop(c context.Context, oid int64, tp int8, rp *model.Reply) (err error) {
if rp == nil {
return
}
var key string
if rp.AttrVal(model.ReplyAttrAdminTop) == 1 {
key = keyAdminTop(oid, tp)
} else if rp.AttrVal(model.ReplyAttrUpperTop) == 1 {
key = keyUpperTop(oid, tp)
} else {
return
}
conn := dao.mc.Get(c)
defer conn.Close()
item := &memcache.Item{Key: key, Object: rp, Expiration: dao.expire, Flags: memcache.FlagJSON}
if err = conn.Set(item); err != nil {
log.Error("conn.Set(%s,%v) error(%v)", key, rp, err)
}
return
}
// DeleteReply delete reply from memcache.
func (dao *MemcacheDao) DeleteReply(c context.Context, rpID int64) (err error) {
key := keyRp(rpID)
conn := dao.mc.Get(c)
if err = conn.Delete(key); err != nil {
if err == memcache.ErrNotFound {
err = nil
} else {
log.Error("conn.Delete(%s) error(%v)", key, err)
}
}
conn.Close()
return
}
// GetTop get subject top reply from memcache
func (dao *MemcacheDao) GetTop(c context.Context, oid int64, tp int8, top uint32) (rp *model.Reply, err error) {
var key string
if top == model.ReplyAttrUpperTop {
key = keyUpperTop(oid, tp)
} else if top == model.ReplyAttrAdminTop {
key = keyAdminTop(oid, tp)
} else {
return
}
conn := dao.mc.Get(c)
defer conn.Close()
item, err := conn.Get(key)
if err != nil {
if err == memcache.ErrNotFound {
err = nil
}
return
}
rp = new(model.Reply)
if err = conn.Scan(item, &rp); err != nil {
log.Error("conn.Scan(%s) error(%v)", item.Value, err)
rp = nil
}
return
}
// GetReply get reply from memcache.
func (dao *MemcacheDao) GetReply(c context.Context, rpID int64) (rp *model.Reply, err error) {
key := keyRp(rpID)
conn := dao.mc.Get(c)
defer conn.Close()
item, err := conn.Get(key)
if err != nil {
if err == memcache.ErrNotFound {
err = nil
}
return
}
rp = new(model.Reply)
if err = conn.Scan(item, rp); err != nil {
log.Error("conn.Scan(%s) error(%v)", item.Value, err)
rp = nil
}
return
}
// GetMultiReply multi get replies from memcache.
func (dao *MemcacheDao) GetMultiReply(c context.Context, rpIDs []int64) (rpMap map[int64]*model.Reply, missed []int64, err error) {
if len(rpIDs) == 0 {
return
}
rpMap = make(map[int64]*model.Reply, len(rpIDs))
keys := make([]string, len(rpIDs))
mm := make(map[string]int64, len(rpIDs))
for i, rpID := range rpIDs {
key := keyRp(rpID)
keys[i] = key
mm[key] = rpID
}
conn := dao.mc.Get(c)
defer conn.Close()
items, err := conn.GetMulti(keys)
if err != nil {
if err == memcache.ErrNotFound {
err = nil
}
return
}
for _, item := range items {
rp := new(model.Reply)
if err = conn.Scan(item, rp); err != nil {
log.Error("conn.Scan(%s) error(%v)", item.Value, err)
continue
}
rpMap[mm[item.Key]] = rp
delete(mm, item.Key)
}
missed = make([]int64, 0, len(mm))
for _, valIn := range mm {
missed = append(missed, valIn)
}
return
}
// GetReplyConfig get reply configuration from memocache by oid and type value
func (dao *MemcacheDao) GetReplyConfig(c context.Context, oid int64, typ, category int8) (config *model.Config, err error) {
key := keyConfig(oid, typ, 1)
conn := dao.mc.Get(c)
defer conn.Close()
item, err := conn.Get(key)
if err != nil {
if err == memcache.ErrNotFound {
err = nil
}
return
}
config = new(model.Config)
if err = conn.Scan(item, config); err != nil {
log.Error("conn.Scan(%s) error(%v)", item.Value, err)
config = nil
}
return
}
// AddReplyConfigCache add/update reply configuration cache from memcache
func (dao *MemcacheDao) AddReplyConfigCache(c context.Context, m *model.Config) (err error) {
key := keyConfig(m.Oid, m.Type, m.Category)
conn := dao.mc.Get(c)
item := &memcache.Item{Key: key, Object: m, Expiration: dao.expire, Flags: memcache.FlagJSON}
if err = conn.Set(item); err != nil {
log.Error("conn.Set(%s,%v) error(%v)", key, m, err)
}
conn.Close()
return
}

View File

@@ -0,0 +1,356 @@
package reply
import (
"context"
"go-common/app/interface/main/reply/conf"
model "go-common/app/interface/main/reply/model/reply"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestReplyNewMemcacheDao(t *testing.T) {
convey.Convey("NewMemcacheDao", t, func(ctx convey.C) {
var (
c = conf.Conf.Memcache
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := NewMemcacheDao(c)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestReplykeyCaptcha(t *testing.T) {
convey.Convey("keyCaptcha", t, func(ctx convey.C) {
var (
mid = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := keyCaptcha(mid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestReplykeyAdminTop(t *testing.T) {
convey.Convey("keyAdminTop", t, func(ctx convey.C) {
var (
oid = int64(0)
tp = int8(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := keyAdminTop(oid, tp)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestReplykeyUpperTop(t *testing.T) {
convey.Convey("keyUpperTop", t, func(ctx convey.C) {
var (
oid = int64(0)
tp = int8(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := keyUpperTop(oid, tp)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestReplykeySub(t *testing.T) {
convey.Convey("keySub", t, func(ctx convey.C) {
var (
oid = int64(0)
tp = int8(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := keySub(oid, tp)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestReplykeyRp(t *testing.T) {
convey.Convey("keyRp", t, func(ctx convey.C) {
var (
rpID = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := keyRp(rpID)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestReplykeyConfig(t *testing.T) {
convey.Convey("keyConfig", t, func(ctx convey.C) {
var (
oid = int64(0)
typ = int8(0)
category = int8(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := keyConfig(oid, typ, category)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestReplyMcPing(t *testing.T) {
convey.Convey("Ping", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.Mc.Ping(c)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestReplyMcCaptchaToken(t *testing.T) {
convey.Convey("CaptchaToken", t, func(ctx convey.C) {
var (
c = context.Background()
mid = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1, err := d.Mc.CaptchaToken(c, mid)
ctx.Convey("Then err should be nil.p1 should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestReplySetCaptchaToken(t *testing.T) {
convey.Convey("SetCaptchaToken", t, func(ctx convey.C) {
var (
c = context.Background()
mid = int64(0)
token = ""
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.Mc.SetCaptchaToken(c, mid, token)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestReplyGetSubject(t *testing.T) {
convey.Convey("GetSubject", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
tp = int8(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
sub, err := d.Mc.GetSubject(c, oid, tp)
ctx.Convey("Then err should be nil.sub should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(sub, convey.ShouldNotBeNil)
})
})
})
}
func TestReplyGetMultiSubject(t *testing.T) {
convey.Convey("GetMultiSubject", t, func(ctx convey.C) {
var (
c = context.Background()
oids = []int64{1322313213123}
tp = int8(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
res, missed, err := d.Mc.GetMultiSubject(c, oids, tp)
ctx.Convey("Then err should be nil.res,missed should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(missed, convey.ShouldNotBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
})
})
}
func TestReplyDeleteSubject(t *testing.T) {
convey.Convey("DeleteSubject", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
tp = int8(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.Mc.DeleteSubject(c, oid, tp)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestReplyAddSubject(t *testing.T) {
convey.Convey("AddSubject", t, func(ctx convey.C) {
var (
c = context.Background()
subs = &model.Subject{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.Mc.AddSubject(c, subs)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestReplyAddReply(t *testing.T) {
convey.Convey("AddReply", t, func(ctx convey.C) {
var (
c = context.Background()
rs = &model.Reply{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.Mc.AddReply(c, rs)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestReplyAddTop(t *testing.T) {
convey.Convey("AddTop", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
tp = int8(0)
rp = &model.Reply{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.Mc.AddTop(c, oid, tp, rp)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestReplyDeleteReply(t *testing.T) {
convey.Convey("DeleteReply", t, func(ctx convey.C) {
var (
c = context.Background()
rpID = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.Mc.DeleteReply(c, rpID)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestReplyGetTop(t *testing.T) {
convey.Convey("GetTop", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
tp = int8(0)
top = uint32(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
rp, err := d.Mc.GetTop(c, oid, tp, top)
ctx.Convey("Then err should be nil.rp should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(rp, convey.ShouldBeNil)
})
})
})
}
func TestReplyGetReply(t *testing.T) {
convey.Convey("GetReply", t, func(ctx convey.C) {
var (
c = context.Background()
rpID = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
rp, err := d.Mc.GetReply(c, rpID)
ctx.Convey("Then err should be nil.rp should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(rp, convey.ShouldBeNil)
})
})
})
}
func TestReplyGetMultiReply(t *testing.T) {
convey.Convey("GetMultiReply", t, func(ctx convey.C) {
var (
c = context.Background()
rpIDs = []int64{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
rpMap, missed, err := d.Mc.GetMultiReply(c, rpIDs)
ctx.Convey("Then err should be nil.rpMap,missed should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(missed, convey.ShouldBeNil)
ctx.So(rpMap, convey.ShouldBeNil)
})
})
})
}
func TestReplyGetReplyConfig(t *testing.T) {
convey.Convey("GetReplyConfig", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
typ = int8(0)
category = int8(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
config, err := d.Mc.GetReplyConfig(c, oid, typ, category)
ctx.Convey("Then err should be nil.config should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(config, convey.ShouldBeNil)
})
})
})
}
func TestReplyAddReplyConfigCache(t *testing.T) {
convey.Convey("AddReplyConfigCache", t, func(ctx convey.C) {
var (
c = context.Background()
m = &model.Config{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.Mc.AddReplyConfigCache(c, m)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,52 @@
package reply
import (
"context"
"time"
"go-common/app/interface/main/reply/model/reply"
"go-common/library/database/sql"
"go-common/library/log"
)
const (
_selAllNoticeSQL = `SELECT id,plat,condi,build,title,content,link,client_type FROM notice WHERE stime <? and etime> ? and status=1 `
)
// NoticeDao notice dao.
type NoticeDao struct {
db *sql.DB
}
// NewNoticeDao new a notice dao and return.
func NewNoticeDao(db *sql.DB) (dao *NoticeDao) {
dao = &NoticeDao{
db: db,
}
return
}
// ReplyNotice get reply notice infos from db
func (dao *NoticeDao) ReplyNotice(c context.Context) (nts []*reply.Notice, err error) {
now := time.Now()
rows, err := dao.db.Query(c, _selAllNoticeSQL, now, now)
if err != nil {
log.Error("dao.selAllResStmt query error (%v)", err)
return
}
defer rows.Close()
nts = make([]*reply.Notice, 0)
for rows.Next() {
nt := &reply.Notice{}
if err = rows.Scan(&nt.ID, &nt.Plat, &nt.Condition, &nt.Build, &nt.Title, &nt.Content, &nt.Link, &nt.ClientType); err != nil {
log.Error("rows.Scan err (%v)", err)
return
}
nts = append(nts, nt)
}
if err = rows.Err(); err != nil {
log.Error("rows.err error(%v)", err)
return
}
return
}

View File

@@ -0,0 +1,38 @@
package reply
import (
"context"
"go-common/library/database/sql"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestReplyNewNoticeDao(t *testing.T) {
convey.Convey("NewNoticeDao", t, func(ctx convey.C) {
var (
db = &sql.DB{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
dao := NewNoticeDao(db)
ctx.Convey("Then dao should not be nil.", func(ctx convey.C) {
ctx.So(dao, convey.ShouldNotBeNil)
})
})
})
}
func TestReplyReplyNotice(t *testing.T) {
convey.Convey("ReplyNotice", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
nts, err := d.Notice.ReplyNotice(c)
ctx.Convey("Then err should be nil.nts should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(nts, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,813 @@
package reply
import (
"context"
"fmt"
"strconv"
"time"
"go-common/app/interface/main/reply/conf"
"go-common/app/interface/main/reply/model/reply"
"go-common/app/interface/main/reply/model/xreply"
"go-common/library/cache/redis"
"go-common/library/log"
)
const (
_prefixIdx = "i_"
_prefixRtIdx = "ri_"
_prefixRpt = "rt_"
_prefixLike = "l_"
_prefixAuditIdx = "ai_%d_%d"
_prefixDialogIdx = "d_%d"
// f_{折叠类型,根评论还是评论区}_{评论区ID或者根评论ID}
_foldedReplyFmt = "f_%s_%d"
_prefixSpamRec = "sr_"
_prefixSpamDaily = "sd_"
_prefixSpamAct = "sa_"
_prefixTopOid = "tro_"
)
const (
_oidOverflow = 1 << 48
)
// RedisDao RedisDao
type RedisDao struct {
redis *redis.Pool
expireRdsIdx int
expireRdsRpt int
expireRdsUC int
expireUserAct int
}
// NewRedisDao NewRedisDao
func NewRedisDao(c *conf.Redis) *RedisDao {
r := &RedisDao{
redis: redis.NewPool(c.Config),
expireRdsIdx: int(time.Duration(c.IndexExpire) / time.Second),
expireRdsRpt: int(time.Duration(c.ReportExpire) / time.Second),
expireRdsUC: int(time.Duration(c.UserCntExpire) / time.Second),
expireUserAct: int(time.Duration(c.UserActExpire) / time.Second),
}
return r
}
func keyRcntCnt(mid int64) string {
return "rc_" + strconv.FormatInt(mid, 10)
}
func keyUpRcntCnt(mid int64) string {
return "urc_" + strconv.FormatInt(mid, 10)
}
func keyDialogIdx(dialogID int64) string {
return fmt.Sprintf(_prefixDialogIdx, dialogID)
}
func keyFolderIdx(kind string, ID int64) string {
return fmt.Sprintf(_foldedReplyFmt, kind, ID)
}
func keyIdx(oid int64, tp, sort int8) string {
if oid > _oidOverflow {
return fmt.Sprintf("%s_%d_%d_%d", _prefixIdx, oid, tp, sort)
}
return _prefixIdx + strconv.FormatInt((oid<<16)|(int64(tp)<<8)|int64(sort), 10)
}
func keyAuditIdx(oid int64, tp int8) string {
return fmt.Sprintf(_prefixAuditIdx, oid, tp)
}
func keyRtIdx(rpID int64) string {
return _prefixRtIdx + strconv.FormatInt(rpID, 10)
}
func keyRpt(mid int64, now time.Time) string {
return _prefixRpt + strconv.FormatInt(mid, 10) + "_" + strconv.Itoa(now.Day())
}
func keyLike(rpID int64) string {
return _prefixLike + strconv.FormatInt(rpID, 10)
}
func keySpamRpRec(mid int64) string {
return _prefixSpamRec + strconv.FormatInt(mid, 10)
}
func keySpamRpDaily(mid int64) string {
return _prefixSpamDaily + strconv.FormatInt(mid, 10)
}
func keySpamActRec(mid int64) string {
return _prefixSpamAct + strconv.FormatInt(mid, 10)
}
func keyTopOid(tp int8) string {
return _prefixTopOid + strconv.FormatInt(int64(tp), 10)
}
// Ping check connection success.
func (dao *RedisDao) Ping(c context.Context) (err error) {
conn := dao.redis.Get(c)
defer conn.Close()
_, err = conn.Do("GET", "PING")
return
}
// AddFloorIndex add index by floor.
func (dao *RedisDao) AddFloorIndex(c context.Context, oid int64, tp int8, rs ...*reply.Reply) (err error) {
if len(rs) == 0 {
return
}
key := keyIdx(oid, tp, reply.SortByFloor)
conn := dao.redis.Get(c)
defer conn.Close()
for _, r := range rs {
if err = conn.Send("ZADD", key, r.Floor, r.RpID); err != nil {
log.Error("conn.Send error(%v)", err)
return
}
}
if err = conn.Send("EXPIRE", key, dao.expireRdsIdx); err != nil {
log.Error("conn.Send error(%v)", err)
return
}
if err = conn.Flush(); err != nil {
log.Error("conn.Flush error(%v)", err)
return
}
for i := 0; i < len(rs)+1; i++ {
if _, err = conn.Receive(); err != nil {
log.Error("conn.Receive() error(%v)", err)
return
}
}
return
}
// AddCountIndex add index by count.
func (dao *RedisDao) AddCountIndex(c context.Context, oid int64, tp int8, rs ...*reply.Reply) (err error) {
if len(rs) == 0 {
return
}
key := keyIdx(oid, tp, reply.SortByCount)
conn := dao.redis.Get(c)
defer conn.Close()
for _, r := range rs {
if err = conn.Send("ZADD", key, int64(r.RCount)<<32|(int64(r.Floor)&0xFFFFFFFF), r.RpID); err != nil {
log.Error("conn.Send error(%v)", err)
return
}
}
if err = conn.Send("EXPIRE", key, dao.expireRdsIdx); err != nil {
log.Error("conn.Send error(%v)", err)
return
}
if err = conn.Flush(); err != nil {
log.Error("conn.Flush error(%v)", err)
return
}
for i := 0; i < len(rs)+1; i++ {
if _, err = conn.Receive(); err != nil {
log.Error("conn.Receive() error(%v)", err)
return
}
}
return
}
// AddLikeIndex add index by like.
func (dao *RedisDao) AddLikeIndex(c context.Context, oid int64, tp int8, r *reply.Reply, rpt *reply.Report) (err error) {
var (
count int
rptCnt int
)
key := keyIdx(oid, tp, reply.SortByLike)
conn := dao.redis.Get(c)
defer conn.Close()
if r.Like >= 3 && (r.Attr&0x3 == 0) {
if rpt != nil {
rptCnt = rpt.Count
}
score := int64((float32(r.Like+2) / float32(r.Hate+rptCnt+4)) * 100)
if err = conn.Send("ZADD", key, score<<32|(int64(r.RCount)&0xFFFFFFFF), r.RpID); err != nil {
log.Error("conn.Send(ZADD %s,%d) error(%v)", key, r.RpID, err)
return
}
count++
} else if r.Like < 3 {
if err = conn.Send("ZREM", key, r.RpID); err != nil {
log.Error("conn.Send(ZREM %s,%d) error(%v)", key, r.RpID, err)
return
}
count++
}
if err = conn.Send("EXPIRE", key, dao.expireRdsIdx); err != nil {
log.Error("conn.Send error(%v)", err)
return
}
if err = conn.Flush(); err != nil {
log.Error("conn.Flush error(%v)", err)
return
}
for i := 0; i < count+1; i++ {
if _, err = conn.Receive(); err != nil {
log.Error("conn.Receive() error(%v)", err)
return
}
}
return
}
// DelIndex delete reply index.
func (dao *RedisDao) DelIndex(c context.Context, rp *reply.Reply) (err error) {
conn := dao.redis.Get(c)
defer conn.Close()
if rp.Root == 0 {
key := keyIdx(rp.Oid, rp.Type, reply.SortByFloor)
err = conn.Send("ZREM", key, rp.RpID)
key = keyIdx(rp.Oid, rp.Type, reply.SortByCount)
err = conn.Send("ZREM", key, rp.RpID)
key = keyIdx(rp.Oid, rp.Type, reply.SortByLike)
err = conn.Send("ZREM", key, rp.RpID)
} else {
key := keyRtIdx(rp.Root)
err = conn.Send("ZREM", key, rp.RpID)
}
if err != nil {
log.Error("conn.Send error(%v)", err)
return
}
if err = conn.Flush(); err != nil {
log.Error("conn.Flush error(%v)", err)
return
}
if rp.Root == 0 {
for i := 0; i < 3; i++ {
if _, err = conn.Receive(); err != nil {
log.Error("conn.Receive error(%v)", err)
return
}
}
} else {
if _, err = conn.Receive(); err != nil {
log.Error("conn.Receive error(%v)", err)
}
}
return
}
// AddFloorIndexByRoot add root reply index by floor.
func (dao *RedisDao) AddFloorIndexByRoot(c context.Context, root int64, rs ...*reply.Reply) (err error) {
if len(rs) == 0 {
return
}
key := keyRtIdx(root)
conn := dao.redis.Get(c)
defer conn.Close()
for _, r := range rs {
if err = conn.Send("ZADD", key, r.CTime, r.RpID); err != nil {
log.Error("conn.Send error(%v)", err)
return
}
}
if err = conn.Send("EXPIRE", key, dao.expireRdsIdx); err != nil {
log.Error("conn.Send error(%v)", err)
return
}
if err = conn.Flush(); err != nil {
log.Error("conn.Flush error(%v)", err)
return
}
for i := 0; i < len(rs)+1; i++ {
if _, err = conn.Receive(); err != nil {
log.Error("conn.Receive() error(%v)", err)
return
}
}
return
}
// AddLike add actions into redis
func (dao *RedisDao) AddLike(c context.Context, rpID int64, ras ...*reply.Action) (err error) {
if len(ras) == 0 {
return
}
key := keyLike(rpID)
conn := dao.redis.Get(c)
defer conn.Close()
for _, r := range ras {
if err = conn.Send("ZADD", key, r.CTime, r.Mid); err != nil {
log.Error("conn.Send error(%v)", err)
return
}
}
if err = conn.Send("EXPIRE", key, dao.expireRdsIdx); err != nil {
log.Error("conn.Send error(%v)", err)
return
}
if err = conn.Flush(); err != nil {
log.Error("conn.Flush error(%v)", err)
return
}
for i := 0; i < len(ras)+1; i++ {
if _, err = conn.Receive(); err != nil {
log.Error("conn.Receive() error(%v)", err)
return
}
}
return
}
// DelLike add actions into redis
func (dao *RedisDao) DelLike(c context.Context, rpID int64, ra *reply.Action) (err error) {
conn := dao.redis.Get(c)
defer conn.Close()
if _, err = conn.Do("ZREM", keyLike(rpID), ra.Mid); err != nil {
log.Error("conn.Receive() error(%v)", err)
}
return
}
// ExpireLike set expire time for action.
func (dao *RedisDao) ExpireLike(c context.Context, rpID int64) (ok bool, err error) {
conn := dao.redis.Get(c)
defer conn.Close()
if ok, err = redis.Bool(conn.Do("EXPIRE", keyLike(rpID), dao.expireRdsIdx)); err != nil {
log.Error("conn.Receive() error(%v)", err)
}
return
}
func (dao *RedisDao) Range(c context.Context, oid int64, tp, sort int8, start, end int) (rpIds []int64, isEnd bool, err error) {
key := keyIdx(oid, tp, sort)
conn := dao.redis.Get(c)
defer conn.Close()
values, err := redis.Values(conn.Do("ZREVRANGE", key, start, end))
if err != nil {
log.Error("conn.Do(ZREVRANGE, %s) error(%v)", key, err)
return
}
if len(values) == 0 {
return
}
err = redis.ScanSlice(values, &rpIds)
if len(rpIds) > 0 && rpIds[len(rpIds)-1] == -1 {
rpIds = rpIds[:len(rpIds)-1]
isEnd = true
}
return
}
// CountReplies CountReplies
func (dao *RedisDao) CountReplies(c context.Context, oid int64, tp, sort int8) (count int, err error) {
key := keyIdx(oid, tp, sort)
conn := dao.redis.Get(c)
defer conn.Close()
if count, err = redis.Int(conn.Do("ZCARD", key)); err != nil {
log.Error("conn.Do(ZCARD, %s) error(%v)", key, err)
}
return
}
// UserAuditReplies return user audit replies.
func (dao *RedisDao) UserAuditReplies(c context.Context, mid, oid int64, tp int8) (rpIds []int64, err error) {
key := keyAuditIdx(oid, tp)
conn := dao.redis.Get(c)
defer conn.Close()
values, err := redis.Values(conn.Do("ZRANGEBYSCORE", key, mid, mid))
if err != nil {
log.Error("conn.Do(RANGE, %s) error(%v)", key, err)
return
}
if len(values) == 0 {
return
}
err = redis.ScanSlice(values, &rpIds)
return
}
// RangeByRoot range root's replyies.
func (dao *RedisDao) RangeByRoot(c context.Context, root int64, start, end int) (rpIds []int64, err error) {
key := keyRtIdx(root)
conn := dao.redis.Get(c)
defer conn.Close()
values, err := redis.Values(conn.Do("ZRANGE", key, start, end))
if err != nil {
log.Error("conn.Do(ZRANGE, %s) error(%v)", key, err)
return
}
if len(values) == 0 {
return
}
err = redis.ScanSlice(values, &rpIds)
return
}
// RangeByOids range oids
func (dao *RedisDao) RangeByOids(c context.Context, oids []int64, tp, sort, start, end int8) (oidMap map[int64][]int64, miss []int64, err error) {
oidMap = make(map[int64][]int64)
conn := dao.redis.Get(c)
defer conn.Close()
for _, oid := range oids {
if err = conn.Send("EXPIRE", keyIdx(oid, tp, sort), dao.expireRdsIdx); err != nil {
log.Error("conn.Send(EXPIRE) err(%v)", err)
return
}
if err = conn.Send("ZREVRANGE", keyIdx(oid, tp, sort), start, end-1); err != nil {
log.Error("conn.Send(ZREVRANGE) err(%v)", err)
return
}
}
if err = conn.Flush(); err != nil {
log.Error("conn.SEND(FLUSH) err(%v)", err)
return
}
for _, oid := range oids {
var (
rpids []int64
values []interface{}
)
if _, err = conn.Receive(); err != nil {
log.Error("redis.Bool() err(%v)", err)
return
}
if values, err = redis.Values(conn.Receive()); err != nil {
log.Error("redis.Values() err(%v)", err)
return
}
if len(values) == 0 {
miss = append(miss, oid)
continue
}
if err = redis.ScanSlice(values, &rpids); err != nil {
log.Error("redis.ScanSlice() err(%v) ", err)
return
}
oidMap[oid] = rpids
}
return
}
// RangeByRoots range roots's replyies.
func (dao *RedisDao) RangeByRoots(c context.Context, roots []int64, start, end int) (mrpids map[int64][]int64, idx, miss []int64, err error) {
conn := dao.redis.Get(c)
defer conn.Close()
for _, root := range roots {
// if exist delay expire time
if err = conn.Send("EXPIRE", keyRtIdx(root), dao.expireRdsIdx); err != nil {
log.Error("conn.Send(EXPIRE) err(%v)", err)
return
}
if err = conn.Send("ZRANGE", keyRtIdx(root), start, end); err != nil {
log.Error("conn.Send(ZRANGE) err(%v)", err)
return
}
}
if err = conn.Flush(); err != nil {
log.Error("conn.SEND(FLUSH) err(%v)", err)
return
}
mrpids = make(map[int64][]int64, len(roots))
for _, root := range roots {
var (
rpids []int64
values []interface{}
)
if _, err = conn.Receive(); err != nil {
log.Error("redis.Bool() err(%v)", err)
return
}
if values, err = redis.Values(conn.Receive()); err != nil {
log.Error("redis.Values() err(%v)", err)
return
}
if len(values) == 0 {
miss = append(miss, root)
continue
}
if err = redis.ScanSlice(values, &rpids); err != nil {
log.Error("redis.ScanSlice() err(%v) ", err)
return
}
idx = append(idx, rpids...)
mrpids[root] = rpids
}
return
}
// ExpireIndex set expire time for index.
func (dao *RedisDao) ExpireIndex(c context.Context, oid int64, tp, sort int8) (ok bool, err error) {
conn := dao.redis.Get(c)
defer conn.Close()
if ok, err = redis.Bool(conn.Do("EXPIRE", keyIdx(oid, tp, sort), dao.expireRdsIdx)); err != nil {
log.Error("conn.Do(EXPIRE) error(%v)", err)
}
return
}
// ExpireIndexByRoot set expire time for root's index.
func (dao *RedisDao) ExpireIndexByRoot(c context.Context, root int64) (ok bool, err error) {
conn := dao.redis.Get(c)
defer conn.Close()
if ok, err = redis.Bool(conn.Do("EXPIRE", keyRtIdx(root), dao.expireRdsIdx)); err != nil {
log.Error("conn.Do(EXPIRE) error(%v)", err)
}
return
}
// SetUserReportCnt set user report count.
func (dao *RedisDao) SetUserReportCnt(c context.Context, mid int64, count int, now time.Time) (err error) {
key := keyRpt(mid, now)
conn := dao.redis.Get(c)
defer conn.Close()
if _, err = conn.Do("SETEX", key, dao.expireRdsRpt, count); err != nil {
log.Error("conn.Do(SETEX) error(%v)", err)
}
return
}
// GetUserReportCnt get user report count.
func (dao *RedisDao) GetUserReportCnt(c context.Context, mid int64, now time.Time) (count int, err error) {
key := keyRpt(mid, now)
conn := dao.redis.Get(c)
defer conn.Close()
if count, err = redis.Int(conn.Do("GET", key)); err != nil {
if err == redis.ErrNil {
err = nil
} else {
log.Error("conn.Do(GET) error(%v)", err)
}
}
return
}
// GetUserReportTTL get TTL of user report count redis.
func (dao *RedisDao) GetUserReportTTL(c context.Context, mid int64, now time.Time) (ttl int, err error) {
key := keyRpt(mid, now)
conn := dao.redis.Get(c)
defer conn.Close()
if ttl, err = redis.Int(conn.Do("TTL", key)); err != nil {
log.Error("conn.Do(TTl) error(%v)", err)
}
return
}
// RankIndex get rank from reply index.
func (dao *RedisDao) RankIndex(c context.Context, oid int64, tp int8, rpID int64, sort int8) (rank int, err error) {
key := keyIdx(oid, tp, sort)
conn := dao.redis.Get(c)
defer conn.Close()
if rank, err = redis.Int(conn.Do("ZREVRANK", key, rpID)); err != nil {
if err == redis.ErrNil {
rank = -1
err = nil
} else {
log.Error("conn.Do(ZREVRANK) error(%v)", err)
}
}
return
}
// RankIndexByRoot get rank from root reply index.
func (dao *RedisDao) RankIndexByRoot(c context.Context, root int64, rpID int64) (rank int, err error) {
key := keyRtIdx(root)
conn := dao.redis.Get(c)
defer conn.Close()
if rank, err = redis.Int(conn.Do("ZRANK", key, rpID)); err != nil {
if err == redis.ErrNil {
rank = -1
err = nil
} else {
log.Error("conn.Do(ZRANK) error(%v)", err)
}
}
return
}
// OidHaveTop OidHaveTop
func (dao *RedisDao) OidHaveTop(c context.Context, oid int64, tp int8) (ok bool, err error) {
key := keyTopOid(tp)
conn := dao.redis.Get(c)
defer conn.Close()
if ok, err = redis.Bool(conn.Do("SISMEMBER", key, oid)); err != nil {
log.Error("OidHavaTop.Do error(%v)", err)
}
return
}
// DelReplyIncr reply cd key
func (dao *RedisDao) DelReplyIncr(c context.Context, mid int64, isUp bool) (err error) {
key := keyRcntCnt(mid)
if isUp {
key = keyUpRcntCnt(mid)
}
conn := dao.redis.Get(c)
defer conn.Close()
_, err = conn.Do("DEL", key)
if err != nil {
log.Error("DelReplyIncr redis failed!err:=%v key:%s", err, key)
}
return
}
// DelReplyIncr reply cd key
func (dao *RedisDao) DelReplySpam(c context.Context, mid int64) (err error) {
key := keySpamRpRec(mid)
conn := dao.redis.Get(c)
defer conn.Close()
_, err = conn.Do("DEL", key)
if err != nil {
log.Error("DelReplySpam redis failed!err:=%v key:%s", err, key)
}
return
}
// SpamReply SpamReply
func (dao *RedisDao) SpamReply(c context.Context, mid int64) (recent, daily int, err error) {
rkey, dkey := keySpamRpRec(mid), keySpamRpDaily(mid)
conn := dao.redis.Get(c)
defer conn.Close()
ii, err := redis.Ints(conn.Do("MGET", rkey, dkey))
if err != nil {
log.Error("conn.Do(MGET, %s, %s) error(%v)", rkey, dkey, err)
// no need for redis.ErrNil check
return
}
if len(ii) != 2 {
err = fmt.Errorf("ReplySpam redis result: %v, len not 2", ii)
log.Error("%v", err)
return
}
recent = ii[0]
daily = ii[1]
return
}
// SpamAction SpamAction
func (dao *RedisDao) SpamAction(c context.Context, mid int64) (code int, err error) {
key := keySpamActRec(mid)
conn := dao.redis.Get(c)
defer conn.Close()
if code, err = redis.Int(conn.Do("GET", key)); err != nil {
if err == redis.ErrNil {
err = nil
} else {
log.Error("conn.Do(GET, %s, ), err (%v)", key, err)
}
}
return
}
// ExpireDialogIndex expire time for dialog index
func (dao *RedisDao) ExpireDialogIndex(c context.Context, dialogID int64) (ok bool, err error) {
conn := dao.redis.Get(c)
defer conn.Close()
if ok, err = redis.Bool(conn.Do("EXPIRE", keyDialogIdx(dialogID), dao.expireRdsIdx)); err != nil {
log.Error("conn.Do(EXPIRE) error(%v)", err)
}
return
}
// RangeRpsByDialog return replies by dialog ID
func (dao *RedisDao) RangeRpsByDialog(c context.Context, dialog int64, start, end int) (rpIDs []int64, err error) {
key := keyDialogIdx(dialog)
conn := dao.redis.Get(c)
defer conn.Close()
values, err := redis.Values(conn.Do("ZRANGE", key, start, end))
if err != nil {
log.Error("conn.Do(ZRANGE, %s) error(%v)", key, err)
return
}
if len(values) == 0 {
return
}
err = redis.ScanSlice(values, &rpIDs)
if err != nil {
log.Error("redis.ScanSlice Error (%v)", err)
}
return
}
// DialogBySide ...
func (dao *RedisDao) DialogDesc(c context.Context, dialog int64, floor, size int) (rpIDs []int64, err error) {
var vals []interface{}
key := keyDialogIdx(dialog)
conn := dao.redis.Get(c)
defer conn.Close()
vals, err = redis.Values(conn.Do("ZREVRANGEBYSCORE", key, floor, "-inf", "LIMIT", 0, size))
if err = redis.ScanSlice(vals, &rpIDs); err != nil {
log.Error("redis.ScanSlice Error (%v)", err)
return nil, err
}
return
}
// DialogMaxMinFloor return min and max floor
func (dao *RedisDao) DialogMinMaxFloor(c context.Context, dialog int64) (minFloor, maxFloor int, err error) {
var RpID int64
key := keyDialogIdx(dialog)
conn := dao.redis.Get(c)
defer conn.Close()
err = conn.Send("ZRANGE", key, 0, 0, "WITHSCORES")
if err != nil {
log.Error("redis.Send key(%s) error(%v)", key, err)
return
}
err = conn.Send("ZRANGE", key, -1, -1, "WITHSCORES")
if err != nil {
log.Error("redis.Send key(%s) error(%v)", key, err)
return
}
err = conn.Flush()
if err != nil {
log.Error("redis.Flush (%s) error(%v)", key, err)
return
}
minValue, err := redis.Values(conn.Receive())
if err != nil {
log.Error("redis.Values key(%s) error(%v)", key, err)
return
}
if _, err = redis.Scan(minValue, &RpID, &minFloor); err != nil {
log.Error("redis.Scan() error(%v)", err)
return
}
maxValue, err := redis.Values(conn.Receive())
if err != nil {
log.Error("redis.Values key(%s) error(%v)", key, err)
return
}
if _, err = redis.Scan(maxValue, &RpID, &maxFloor); err != nil {
log.Error("redis.Scan() error(%v)", err)
return
}
return
}
// DialogByCursor return replies by dialog
func (dao *RedisDao) DialogByCursor(c context.Context, dialog int64, cursor *reply.Cursor) (rpIDs []int64, err error) {
var vals []interface{}
key := keyDialogIdx(dialog)
conn := dao.redis.Get(c)
defer conn.Close()
if cursor.Latest() {
vals, err = redis.Values(conn.Do("ZRANGEBYSCORE", key, 0, "+inf", "LIMIT", 0, cursor.Len()))
} else if cursor.Descrease() {
vals, err = redis.Values(conn.Do("ZREVRANGEBYSCORE", key, cursor.Current(), "-inf", "LIMIT", 0, cursor.Len()))
} else if cursor.Increase() {
vals, err = redis.Values(conn.Do("ZRANGEBYSCORE", key, cursor.Current(), "+inf", "LIMIT", 0, cursor.Len()))
} else {
err = ErrCursorDirection
}
if err = redis.ScanSlice(vals, &rpIDs); err != nil {
log.Error("redis.ScanSlice() error(%v)", err)
return nil, err
}
return
}
// ExpireFolder ...
func (dao *RedisDao) ExpireFolder(c context.Context, kind string, ID int64) (ok bool, err error) {
var (
conn = dao.redis.Get(c)
key = keyFolderIdx(kind, ID)
)
defer conn.Close()
if ok, err = redis.Bool(conn.Do("EXPIRE", key, dao.expireRdsIdx)); err != nil {
log.Error("redis EXPIRE(%s) error(%v)", key, err)
}
return
}
// FolderByCursor ...
func (dao *RedisDao) FolderByCursor(c context.Context, kind string, ID int64, cursor *xreply.Cursor) (rpIDs []int64, err error) {
var (
conn = dao.redis.Get(c)
key = keyFolderIdx(kind, ID)
vals []interface{}
)
defer conn.Close()
if cursor.Latest() {
vals, err = redis.Values(conn.Do("ZREVRANGEBYSCORE", key, "+inf", "-inf", "LIMIT", 0, cursor.Ps))
} else if cursor.Forward() {
vals, err = redis.Values(conn.Do("ZREVRANGEBYSCORE", key, fmt.Sprintf("(%d", cursor.Next), "-inf", "LIMIT", 0, cursor.Ps))
} else {
vals, err = redis.Values(conn.Do("ZRANGEBYSCORE", key, fmt.Sprintf("(%d", cursor.Prev), "+inf", "LIMIT", 0, cursor.Ps))
// 这里保持一致都是降序的输出
for left, right := 0, len(vals)-1; left < right; left, right = left+1, right-1 {
vals[left], vals[right] = vals[right], vals[left]
}
}
if err = redis.ScanSlice(vals, &rpIDs); err != nil {
log.Error("redis.ScanSlice() error(%v)", err)
}
return
}

View File

@@ -0,0 +1,692 @@
package reply
import (
"context"
"testing"
"time"
"go-common/app/interface/main/reply/conf"
"go-common/app/interface/main/reply/model/reply"
"github.com/smartystreets/goconvey/convey"
)
func TestReplyNewRedisDao(t *testing.T) {
convey.Convey("NewRedisDao", t, func(ctx convey.C) {
var (
c = conf.Conf.Redis
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := NewRedisDao(c)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestReplykeyDialogIdx(t *testing.T) {
convey.Convey("keyDialogIdx", t, func(ctx convey.C) {
var (
dialogID = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := keyDialogIdx(dialogID)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestReplykeyIdx(t *testing.T) {
convey.Convey("keyIdx", t, func(ctx convey.C) {
var (
oid = int64(0)
tp = int8(0)
sort = int8(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := keyIdx(oid, tp, sort)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestReplykeyAuditIdx(t *testing.T) {
convey.Convey("keyAuditIdx", t, func(ctx convey.C) {
var (
oid = int64(0)
tp = int8(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := keyAuditIdx(oid, tp)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestReplykeyRtIdx(t *testing.T) {
convey.Convey("keyRtIdx", t, func(ctx convey.C) {
var (
rpID = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := keyRtIdx(rpID)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestReplykeyRpt(t *testing.T) {
convey.Convey("keyRpt", t, func(ctx convey.C) {
var (
mid = int64(0)
now = time.Now()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := keyRpt(mid, now)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestReplykeyLike(t *testing.T) {
convey.Convey("keyLike", t, func(ctx convey.C) {
var (
rpID = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := keyLike(rpID)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestReplykeySpamRpRec(t *testing.T) {
convey.Convey("keySpamRpRec", t, func(ctx convey.C) {
var (
mid = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := keySpamRpRec(mid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestReplykeySpamRpDaily(t *testing.T) {
convey.Convey("keySpamRpDaily", t, func(ctx convey.C) {
var (
mid = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := keySpamRpDaily(mid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestReplykeySpamActRec(t *testing.T) {
convey.Convey("keySpamActRec", t, func(ctx convey.C) {
var (
mid = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := keySpamActRec(mid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestReplykeyTopOid(t *testing.T) {
convey.Convey("keyTopOid", t, func(ctx convey.C) {
var (
tp = int8(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := keyTopOid(tp)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestReplyPing(t *testing.T) {
convey.Convey("Ping", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.Redis.Ping(c)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestReplyAddFloorIndex(t *testing.T) {
convey.Convey("AddFloorIndex", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
tp = int8(0)
rs = &reply.Reply{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.Redis.AddFloorIndex(c, oid, tp, rs)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestReplyAddCountIndex(t *testing.T) {
convey.Convey("AddCountIndex", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
tp = int8(0)
rs = &reply.Reply{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.Redis.AddCountIndex(c, oid, tp, rs)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestReplyAddLikeIndex(t *testing.T) {
convey.Convey("AddLikeIndex", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
tp = int8(0)
r = &reply.Reply{}
rpt = &reply.Report{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.Redis.AddLikeIndex(c, oid, tp, r, rpt)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestReplyDelIndex(t *testing.T) {
convey.Convey("DelIndex", t, func(ctx convey.C) {
var (
c = context.Background()
rp = &reply.Reply{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.Redis.DelIndex(c, rp)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestReplyAddFloorIndexByRoot(t *testing.T) {
convey.Convey("AddFloorIndexByRoot", t, func(ctx convey.C) {
var (
c = context.Background()
root = int64(0)
rs = &reply.Reply{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.Redis.AddFloorIndexByRoot(c, root, rs)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestReplyAddLike(t *testing.T) {
convey.Convey("AddLike", t, func(ctx convey.C) {
var (
c = context.Background()
rpID = int64(0)
ras = &reply.Action{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.Redis.AddLike(c, rpID, ras)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestReplyDelLike(t *testing.T) {
convey.Convey("DelLike", t, func(ctx convey.C) {
var (
c = context.Background()
rpID = int64(0)
ra = &reply.Action{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.Redis.DelLike(c, rpID, ra)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestReplyExpireLike(t *testing.T) {
convey.Convey("ExpireLike", t, func(ctx convey.C) {
var (
c = context.Background()
rpID = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
ok, err := d.Redis.ExpireLike(c, rpID)
ctx.Convey("Then err should be nil.ok should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(ok, convey.ShouldNotBeNil)
})
})
})
}
func TestReplyRange(t *testing.T) {
convey.Convey("Range", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
tp = int8(0)
sort = int8(0)
start = int(0)
end = int(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
rpIds, isEnd, err := d.Redis.Range(c, oid, tp, sort, start, end)
ctx.Convey("Then err should be nil.rpIds,isEnd should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(isEnd, convey.ShouldNotBeNil)
if len(rpIds) <= 0 {
ctx.So(rpIds, convey.ShouldBeEmpty)
}
})
})
})
}
func TestReplyCountReplies(t *testing.T) {
convey.Convey("CountReplies", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
tp = int8(0)
sort = int8(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
count, err := d.Redis.CountReplies(c, oid, tp, sort)
ctx.Convey("Then err should be nil.count should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(count, convey.ShouldNotBeNil)
})
})
})
}
func TestReplyUserAuditReplies(t *testing.T) {
convey.Convey("UserAuditReplies", t, func(ctx convey.C) {
var (
c = context.Background()
mid = int64(1)
oid = int64(1)
tp = int8(1)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
rpIds, err := d.Redis.UserAuditReplies(c, mid, oid, tp)
ctx.Convey("Then err should be nil.rpIds should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(rpIds, convey.ShouldBeEmpty)
})
})
})
}
func TestReplyRangeByRoot(t *testing.T) {
convey.Convey("RangeByRoot", t, func(ctx convey.C) {
var (
c = context.Background()
root = int64(0)
start = int(0)
end = int(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
rpIds, err := d.Redis.RangeByRoot(c, root, start, end)
ctx.Convey("Then err should be nil.rpIds should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(rpIds, convey.ShouldNotBeNil)
})
})
})
}
func TestReplyRangeByRoots(t *testing.T) {
convey.Convey("RangeByRoots", t, func(ctx convey.C) {
var (
c = context.Background()
roots = []int64{}
start = int(0)
end = int(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
mrpids, idx, miss, err := d.Redis.RangeByRoots(c, roots, start, end)
ctx.Convey("Then err should be nil.mrpids,idx,miss should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(miss, convey.ShouldBeNil)
ctx.So(idx, convey.ShouldBeNil)
ctx.So(mrpids, convey.ShouldNotBeNil)
})
})
})
}
func TestReplyExpireIndex(t *testing.T) {
convey.Convey("ExpireIndex", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
tp = int8(0)
sort = int8(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
ok, err := d.Redis.ExpireIndex(c, oid, tp, sort)
ctx.Convey("Then err should be nil.ok should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(ok, convey.ShouldNotBeNil)
})
})
})
}
func TestReplyExpireIndexByRoot(t *testing.T) {
convey.Convey("ExpireIndexByRoot", t, func(ctx convey.C) {
var (
c = context.Background()
root = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
ok, err := d.Redis.ExpireIndexByRoot(c, root)
ctx.Convey("Then err should be nil.ok should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(ok, convey.ShouldNotBeNil)
})
})
})
}
func TestReplySetUserReportCnt(t *testing.T) {
convey.Convey("SetUserReportCnt", t, func(ctx convey.C) {
var (
c = context.Background()
mid = int64(0)
count = int(0)
now = time.Now()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.Redis.SetUserReportCnt(c, mid, count, now)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestReplyGetUserReportCnt(t *testing.T) {
convey.Convey("GetUserReportCnt", t, func(ctx convey.C) {
var (
c = context.Background()
mid = int64(0)
now = time.Now()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
count, err := d.Redis.GetUserReportCnt(c, mid, now)
ctx.Convey("Then err should be nil.count should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(count, convey.ShouldNotBeNil)
})
})
})
}
func TestReplyGetUserReportTTL(t *testing.T) {
convey.Convey("GetUserReportTTL", t, func(ctx convey.C) {
var (
c = context.Background()
mid = int64(0)
now = time.Now()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
ttl, err := d.Redis.GetUserReportTTL(c, mid, now)
ctx.Convey("Then err should be nil.ttl should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(ttl, convey.ShouldNotBeNil)
})
})
})
}
func TestReplyRankIndex(t *testing.T) {
convey.Convey("RankIndex", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
tp = int8(0)
rpID = int64(0)
sort = int8(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
rank, err := d.Redis.RankIndex(c, oid, tp, rpID, sort)
ctx.Convey("Then err should be nil.rank should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(rank, convey.ShouldNotBeNil)
})
})
})
}
func TestReplyRankIndexByRoot(t *testing.T) {
convey.Convey("RankIndexByRoot", t, func(ctx convey.C) {
var (
c = context.Background()
root = int64(0)
rpID = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
rank, err := d.Redis.RankIndexByRoot(c, root, rpID)
ctx.Convey("Then err should be nil.rank should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(rank, convey.ShouldNotBeNil)
})
})
})
}
func TestReplyOidHaveTop(t *testing.T) {
convey.Convey("OidHaveTop", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
tp = int8(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
ok, err := d.Redis.OidHaveTop(c, oid, tp)
ctx.Convey("Then err should be nil.ok should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(ok, convey.ShouldNotBeNil)
})
})
})
}
func TestReplySpamReply(t *testing.T) {
convey.Convey("SpamReply", t, func(ctx convey.C) {
var (
c = context.Background()
mid = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
recent, daily, err := d.Redis.SpamReply(c, mid)
ctx.Convey("Then err should be nil.recent,daily should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(daily, convey.ShouldNotBeNil)
ctx.So(recent, convey.ShouldNotBeNil)
})
})
})
}
func TestReplySpamAction(t *testing.T) {
convey.Convey("SpamAction", t, func(ctx convey.C) {
var (
c = context.Background()
mid = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
code, err := d.Redis.SpamAction(c, mid)
ctx.Convey("Then err should be nil.code should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(code, convey.ShouldNotBeNil)
})
})
})
}
func TestReplyExpireDialogIndex(t *testing.T) {
convey.Convey("ExpireDialogIndex", t, func(ctx convey.C) {
var (
c = context.Background()
dialogID = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
ok, err := d.Redis.ExpireDialogIndex(c, dialogID)
ctx.Convey("Then err should be nil.ok should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(ok, convey.ShouldNotBeNil)
})
})
})
}
func TestReplyRangeRpsByDialog(t *testing.T) {
convey.Convey("RangeRpsByDialog", t, func(ctx convey.C) {
var (
c = context.Background()
dialog = int64(0)
start = int(0)
end = int(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
rpIDs, err := d.Redis.RangeRpsByDialog(c, dialog, start, end)
ctx.Convey("Then err should be nil.rpIDs should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(rpIDs, convey.ShouldBeNil)
})
})
})
}
func TestReplyDialogDesc(t *testing.T) {
convey.Convey("DialogDesc", t, func(ctx convey.C) {
var (
c = context.Background()
dialog = int64(0)
floor = int(0)
size = int(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
rpIDs, err := d.Redis.DialogDesc(c, dialog, floor, size)
ctx.Convey("Then err should be nil.rpIDs should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(rpIDs, convey.ShouldBeNil)
})
})
})
}
func TestReplyDialogMinMaxFloor(t *testing.T) {
convey.Convey("DialogMinMaxFloor", t, func(ctx convey.C) {
var (
c = context.Background()
dialog = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
minFloor, maxFloor, err := d.Redis.DialogMinMaxFloor(c, dialog)
ctx.Convey("Then err should be nil.minFloor,maxFloor should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
ctx.So(maxFloor, convey.ShouldBeZeroValue)
ctx.So(minFloor, convey.ShouldBeZeroValue)
})
})
})
}
func TestReplyDialogByCursor(t *testing.T) {
convey.Convey("DialogByCursor", t, func(ctx convey.C) {
var (
c = context.Background()
dialog = int64(0)
cursor = &reply.Cursor{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
rpIDs, err := d.Redis.DialogByCursor(c, dialog, cursor)
ctx.Convey("Then err should be nil.rpIDs should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(rpIDs, convey.ShouldBeNil)
})
})
})
}
func TestDelReplyIncr(t *testing.T) {
convey.Convey("test DelReplyIncr", t, func(ctx convey.C) {
var (
mid = int64(2233)
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.Redis.DelReplyIncr(c, mid, true)
ctx.Convey("d.Redis.DelReplyIncr up error should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
err = d.Redis.DelReplyIncr(c, mid, false)
ctx.Convey("d.Redis.DelReplyIncr error should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
err = d.Redis.DelReplySpam(c, mid)
ctx.Convey("d.Redis.DelReplySpam error should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,444 @@
package reply
import (
"context"
"fmt"
"time"
"go-common/app/interface/main/reply/model/reply"
"go-common/app/interface/main/reply/model/xreply"
"go-common/library/database/sql"
"go-common/library/log"
"go-common/library/xstr"
)
const (
_replySharding int64 = 200
)
const (
_selByIdsSQL = "SELECT id,oid,type,mid,root,parent,dialog,count,rcount,`like`,hate,floor,state,attr,ctime,mtime FROM reply_%d WHERE id IN (%s)"
_selSQL = "SELECT id,oid,type,mid,root,parent,dialog,count,rcount,`like`,hate,floor,state,attr,ctime,mtime FROM reply_%d WHERE id=?"
_selByDialogSQL = "SELECT id FROM reply_%d WHERE oid=? AND type=? AND root=? AND state IN (0,1,2,5,6) AND dialog=? ORDER BY floor ASC limit ?,?"
_selByDialogDescSQL = "SELECT id FROM reply_%d WHERE oid=? AND type=? AND root=? AND state IN (0,1,2,5,6) AND dialog=? AND floor<=? ORDER BY floor DESC limit ?"
_selByDialogAscSQL = "SELECT id FROM reply_%d WHERE oid=? AND type=? AND root=? AND state IN (0,1,2,5,6) AND dialog=? AND floor>=? ORDER BY floor ASC limit ?"
_selMinMaxFloorDialogSQL = "SELECT IFNULL(MIN(floor),0), IFNULL(MAX(floor),0) FROM reply_%d WHERE dialog=? AND oid=? AND type=? AND root=? AND state IN (0,1,2,5,6)"
_selIdsByFloorSQL = "SELECT id FROM reply_%d WHERE oid=? AND type=? AND root=0 AND state in (0,1,2,5,6) ORDER BY floor DESC limit ?,?"
_selIdsByCountSQL = "SELECT id FROM reply_%d WHERE oid=? AND type=? AND root=0 AND state in (0,1,2,5,6) ORDER BY rcount DESC limit ?,?"
_selIdsByLikeSQL = "SELECT id FROM reply_%d WHERE oid=? AND type=? AND root=0 AND state in (0,1,2,5,6) ORDER BY `like` DESC limit ?,?" // like >= 3
_selCountByLikeSQL = "SELECT COUNT(*) FROM reply_%d WHERE oid=? AND type=? AND root=0 AND state in (0,1,2,5,6) AND attr&1!=1 AND attr>>1&1!=1" // like >= 3
_selIdsByRootStateSQL = "SELECT id FROM reply_%d WHERE oid=? AND type=? AND root=? AND state in (0,1,2,5,6) ORDER BY floor limit ?,?"
_selIdsByRootSQL = "SELECT id FROM reply_%d WHERE oid=? AND type=? AND root=? ORDER BY floor limit ?,?"
_selIdsByFloorOffsetSQL = "SELECT id FROM reply_%d WHERE oid=? AND type=? AND root=0 AND state in (0,1,2,3,4,5,6,7,8,9,10,11) AND floor >= ? AND floor <= ? ORDER BY floor"
_setHateSQL = "UPDATE reply_%d SET `hate`=?,mtime=? WHERE id=?"
_setLikeSQL = "UPDATE reply_%d SET `like`=?,mtime=? WHERE id=?"
_insFilteredReply = "INSERT INTO reply_filtered (rpid, oid, mid, type, message, level, ctime, mtime) VALUES (?,?,?,?,?,?,?,?)"
_selFilteredReply = "select rpid,message FROM reply_filtered WHERE rpid in (%s)"
// 针对折叠评论
_foldedReplyLatest = "SELECT id FROM reply_%d WHERE oid=? AND type=? AND root=? AND state=12 ORDER BY floor DESC LIMIT ?"
_foldedReplyDesc = "SELECT id FROM reply_%d WHERE oid=? AND type=? AND root=? AND state=12 AND floor<? ORDER BY floor DESC LIMIT ?"
_foldedReplyAsc = "SELECT id FROM reply_%d WHERE oid=? AND type=? AND root=? AND state=12 AND floor>? ORDER BY floor DESC LIMIT ?"
)
// RpDao reply dao.
type RpDao struct {
db *sql.DB
dbSlave *sql.DB
}
// NewReplyDao new replyDao and return.
func NewReplyDao(db, dbSlave *sql.DB) (dao *RpDao) {
dao = &RpDao{
db: db,
dbSlave: dbSlave,
}
return
}
func (dao *RpDao) hit(oid int64) int64 {
return oid % _replySharding
}
// FilterContents get filtered contents from db
func (d *Dao) FilterContents(ctx context.Context, rpMaps map[int64]string) error {
if len(rpMaps) == 0 {
return nil
}
var rpids []int64
for k := range rpMaps {
rpids = append(rpids, k)
}
rows, err := d.dbSlave.Query(ctx, fmt.Sprintf(_selFilteredReply, xstr.JoinInts(rpids)))
if err != nil {
log.Error("mysql.Query error(%v)", err)
return err
}
defer rows.Close()
for rows.Next() {
var id int64
var message string
if err = rows.Scan(&id, &message); err != nil {
if err == sql.ErrNoRows {
continue
} else {
log.Error("row.Scan error(%v)", err)
return err
}
}
rpMaps[id] = message
}
if err = rows.Err(); err != nil {
log.Error("rows.err error(%v)", err)
return err
}
return nil
}
// CountLike get count of reply like
func (dao *RpDao) CountLike(c context.Context, oid int64, tp int8) (count int, err error) {
row := dao.dbSlave.QueryRow(c, fmt.Sprintf(_selCountByLikeSQL, dao.hit(oid)), oid, tp)
if err = row.Scan(&count); err != nil {
log.Error("row.scan err(%v)", err)
return
}
return
}
// Get get reply.
func (dao *RpDao) Get(c context.Context, oid, rpID int64) (r *reply.Reply, err error) {
r = &reply.Reply{}
row := dao.db.QueryRow(c, fmt.Sprintf(_selSQL, dao.hit(oid)), rpID)
if err = row.Scan(&r.RpID, &r.Oid, &r.Type, &r.Mid, &r.Root, &r.Parent, &r.Dialog, &r.Count, &r.RCount, &r.Like, &r.Hate, &r.Floor, &r.State, &r.Attr, &r.CTime, &r.MTime); err != nil {
if err == sql.ErrNoRows {
r = nil
err = nil
} else {
log.Error("row.Scan error(%v)", err)
}
}
return
}
// GetIDsByDialogAsc ...
func (dao *RpDao) GetIDsByDialogAsc(c context.Context, oid int64, tp int8, root, dialog, maxFloor int64, count int) (rpIDs []int64, err error) {
query := fmt.Sprintf(_selByDialogAscSQL, dao.hit(oid))
rows, err := dao.dbSlave.Query(c, query, oid, tp, root, dialog, maxFloor, count)
if err != nil {
log.Error("mysql.Query error(%v)", err)
return
}
defer rows.Close()
for rows.Next() {
var id int64
if err = rows.Scan(&id); err != nil {
log.Error("row.Scan error(%v)", err)
return
}
rpIDs = append(rpIDs, id)
}
if err = rows.Err(); err != nil {
log.Error("rows.err error(%v)", err)
return
}
return
}
// GetDialogMinMaxFloor ...
func (dao *RpDao) GetDialogMinMaxFloor(c context.Context, oid int64, tp int8, root, dialog int64) (minFloor, maxFloor int, err error) {
query := fmt.Sprintf(_selMinMaxFloorDialogSQL, dao.hit(oid))
err = dao.dbSlave.QueryRow(c, query, dialog, oid, tp, root).Scan(&minFloor, &maxFloor)
if err != nil {
log.Error("row.scan err(%v)", err)
return
}
return
}
// GetIDsByDialogDesc ...
func (dao *RpDao) GetIDsByDialogDesc(c context.Context, oid int64, tp int8, root, dialog, minFloor int64, count int) (rpIDs []int64, err error) {
query := fmt.Sprintf(_selByDialogDescSQL, dao.hit(oid))
rows, err := dao.dbSlave.Query(c, query, oid, tp, root, dialog, minFloor, count)
if err != nil {
log.Error("mysql.Query error(%v)", err)
return
}
defer rows.Close()
for rows.Next() {
var id int64
if err = rows.Scan(&id); err != nil {
log.Error("row.Scan error(%v)", err)
return
}
rpIDs = append(rpIDs, id)
}
if err = rows.Err(); err != nil {
log.Error("rows.err error(%v)", err)
return
}
return
}
// GetIDsByDialog get replies by dialog
func (dao *RpDao) GetIDsByDialog(c context.Context, oid int64, tp int8, root, dialog int64, offset, count int) (rpIDs []int64, err error) {
query := fmt.Sprintf(_selByDialogSQL, dao.hit(oid))
rows, err := dao.dbSlave.Query(c, query, oid, tp, root, dialog, offset, count)
if err != nil {
log.Error("mysql.Query error(%v)", err)
return
}
defer rows.Close()
for rows.Next() {
var id int64
if err = rows.Scan(&id); err != nil {
log.Error("row.Scan error(%v)", err)
return
}
rpIDs = append(rpIDs, id)
}
if err = rows.Err(); err != nil {
log.Error("rows.err error(%v)", err)
return
}
return
}
// GetByIds get replies by reply ids.
func (dao *RpDao) GetByIds(c context.Context, oid int64, tp int8, rpIds []int64) (rpMap map[int64]*reply.Reply, err error) {
if len(rpIds) == 0 {
return
}
rows, err := dao.dbSlave.Query(c, fmt.Sprintf(_selByIdsSQL, dao.hit(oid), xstr.JoinInts(rpIds)))
if err != nil {
log.Error("mysql.Query error(%v)", err)
return
}
defer rows.Close()
rpMap = make(map[int64]*reply.Reply, len(rpIds))
for rows.Next() {
r := &reply.Reply{}
if err = rows.Scan(&r.RpID, &r.Oid, &r.Type, &r.Mid, &r.Root, &r.Parent, &r.Dialog, &r.Count, &r.RCount, &r.Like, &r.Hate, &r.Floor, &r.State, &r.Attr, &r.CTime, &r.MTime); err != nil {
if err == sql.ErrNoRows {
r = nil
} else {
log.Error("row.Scan error(%v)", err)
return
}
}
rpMap[r.RpID] = r
}
if err = rows.Err(); err != nil {
log.Error("rows.err error(%v)", err)
return
}
return
}
// GetIdsSortFloor limit get reply ids and order by floor desc.
func (dao *RpDao) GetIdsSortFloor(c context.Context, oid int64, tp int8, offset, count int) (res []int64, err error) {
rows, err := dao.dbSlave.Query(c, fmt.Sprintf(_selIdsByFloorSQL, dao.hit(oid)), oid, tp, offset, count)
if err != nil {
log.Error("dao.selIdsByFloorStmt query err(%v)", err)
return
}
defer rows.Close()
var id int64
res = make([]int64, 0, count)
for rows.Next() {
if err = rows.Scan(&id); err != nil {
log.Error("rows.scan err is (%v)", err)
return
}
res = append(res, id)
}
if err = rows.Err(); err != nil {
log.Error("rows.err error(%v)", err)
return
}
return
}
// GetIdsSortCount limit get reply ids and order by rcount desc.
func (dao *RpDao) GetIdsSortCount(c context.Context, oid int64, tp int8, offset, count int) (res []int64, err error) {
rows, err := dao.dbSlave.Query(c, fmt.Sprintf(_selIdsByCountSQL, dao.hit(oid)), oid, tp, offset, count)
if err != nil {
log.Error("dao.selIdsByCountStmt query err(%v)", err)
return
}
defer rows.Close()
var id int64
res = make([]int64, 0, count)
for rows.Next() {
if err = rows.Scan(&id); err != nil {
log.Error("rows.scan err is (%v)", err)
return
}
res = append(res, id)
}
if err = rows.Err(); err != nil {
log.Error("rows.err error(%v)", err)
return
}
return
}
// GetIdsSortLike limit get reply ids and order by like desc.
func (dao *RpDao) GetIdsSortLike(c context.Context, oid int64, tp int8, offset, count int) (res []int64, err error) {
rows, err := dao.dbSlave.Query(c, fmt.Sprintf(_selIdsByLikeSQL, dao.hit(oid)), oid, tp, offset, count)
if err != nil {
log.Error(" dao.selIdsByLikeStmt query err(%v)", err)
return
}
defer rows.Close()
var id int64
res = make([]int64, 0, count)
for rows.Next() {
if err = rows.Scan(&id); err != nil {
log.Error("rows.scan err is (%v)", err)
return
}
res = append(res, id)
}
if err = rows.Err(); err != nil {
log.Error("rows.err error(%v)", err)
return
}
return
}
// GetIdsByRoot limit get reply ids of root reply and order by floor.
func (dao *RpDao) GetIdsByRoot(c context.Context, oid, root int64, tp int8, offset, count int) (res []int64, err error) {
rows, err := dao.dbSlave.Query(c, fmt.Sprintf(_selIdsByRootStateSQL, dao.hit(oid)), oid, tp, root, offset, count)
if err != nil {
log.Error("dao.selIdsByRtStmt,oid(%d),root(%d),tp(%d),offset(%d),query err(%v)", oid, root, tp, offset, err)
return
}
defer rows.Close()
var id int64
res = make([]int64, 0, count)
for rows.Next() {
if err = rows.Scan(&id); err != nil {
log.Error("rows.scan err is (%v,%v,%v,%v,%v)", oid, root, offset, count, err)
return
}
res = append(res, id)
}
if err = rows.Err(); err != nil {
log.Error("rows.err error(%v)", err)
return
}
return
}
// GetIDsByRootWithoutState limit get reply ids of root reply and order by floor.
func (dao *RpDao) GetIDsByRootWithoutState(c context.Context, oid, root int64, tp int8, offset, count int) (res []int64, err error) {
rows, err := dao.dbSlave.Query(c, fmt.Sprintf(_selIdsByRootSQL, dao.hit(oid)), oid, tp, root, offset, count)
if err != nil {
log.Error("dao.selIdsByRtStmt,oid(%d),root(%d),tp(%d),offset(%d),query err(%v)", oid, root, tp, offset, err)
return
}
defer rows.Close()
var id int64
res = make([]int64, 0, count)
for rows.Next() {
if err = rows.Scan(&id); err != nil {
log.Error("rows.scan err is (%v,%v,%v,%v,%v)", oid, root, offset, count, err)
return
}
res = append(res, id)
}
if err = rows.Err(); err != nil {
log.Error("rows.err error(%v)", err)
return
}
return
}
// GetIDsByFloorOffset get reply ids in floor range
func (dao *RpDao) GetIDsByFloorOffset(c context.Context, oid int64, tp int8, start, end int) (res []int64, err error) {
rows, err := dao.dbSlave.Query(c, fmt.Sprintf(_selIdsByFloorOffsetSQL, dao.hit(oid)), oid, tp, start, end)
if err != nil {
log.Error(" dao.db.Query err(%v)", err)
return
}
defer rows.Close()
var id int64
res = make([]int64, 0, end-start)
for rows.Next() {
if err = rows.Scan(&id); err != nil {
log.Error("rows.scan err is (%v)", err)
return
}
res = append(res, id)
}
if err = rows.Err(); err != nil {
log.Error("rows.err error(%v)", err)
return
}
return
}
// SetHateCount set a reply hate count.
func (dao *RpDao) SetHateCount(c context.Context, oid, rpID int64, count int32, now time.Time) (rows int64, err error) {
res, err := dao.db.Exec(c, fmt.Sprintf(_setHateSQL, dao.hit(oid)), count, now, rpID)
if err != nil {
log.Error("db.Exec error(%v)", err)
return
}
return res.RowsAffected()
}
// SetLikeCount set a reply hate count.
func (dao *RpDao) SetLikeCount(c context.Context, oid, rpID int64, count int32, now time.Time) (rows int64, err error) {
res, err := dao.db.Exec(c, fmt.Sprintf(_setLikeSQL, dao.hit(oid)), count, now, rpID)
if err != nil {
log.Error("db.Exec error(%v)", err)
return
}
return res.RowsAffected()
}
// AddFilteredReply AddFilteredReply
func (dao *RpDao) AddFilteredReply(c context.Context, rpID, oid, mid int64, tp, level int8, message string, now time.Time) (err error) {
_, err = dao.db.Exec(c, _insFilteredReply, rpID, oid, mid, tp, message, level, now, now)
if err != nil {
log.Error("db.Exec error(%v)", err)
return
}
return
}
// FoldedRepliesCursor ...
func (dao *RpDao) FoldedRepliesCursor(c context.Context, oid int64, tp int8, root int64, cursor *xreply.Cursor) (ids []int64, err error) {
var (
rows *sql.Rows
)
if cursor.Latest() {
rows, err = dao.dbSlave.Query(c, fmt.Sprintf(_foldedReplyLatest, dao.hit(oid)), oid, tp, root, cursor.Ps)
} else if cursor.Forward() {
rows, err = dao.dbSlave.Query(c, fmt.Sprintf(_foldedReplyDesc, dao.hit(oid)), oid, tp, root, cursor.Next, cursor.Ps)
} else {
rows, err = dao.dbSlave.Query(c, fmt.Sprintf(_foldedReplyAsc, dao.hit(oid)), oid, tp, root, cursor.Prev, cursor.Ps)
return
}
if err != nil {
log.Error("mysql Query() error(%v)", err)
return
}
defer rows.Close()
for rows.Next() {
var id int64
if err = rows.Scan(&id); err != nil {
log.Error("mysql Scan() error(%v)", err)
return
}
ids = append(ids, id)
}
if err = rows.Err(); err != nil {
log.Error("mysql rows.Err() error(%v)", err)
}
return
}

View File

@@ -0,0 +1,350 @@
package reply
import (
"context"
"go-common/library/database/sql"
"testing"
"time"
"github.com/smartystreets/goconvey/convey"
)
func TestReplyNewReplyDao(t *testing.T) {
convey.Convey("NewReplyDao", t, func(ctx convey.C) {
var (
db = &sql.DB{}
dbSlave = &sql.DB{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
dao := NewReplyDao(db, dbSlave)
ctx.Convey("Then dao should not be nil.", func(ctx convey.C) {
ctx.So(dao, convey.ShouldNotBeNil)
})
})
})
}
func TestReplyReplyhit(t *testing.T) {
convey.Convey("hit", t, func(ctx convey.C) {
var (
oid = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := d.Reply.hit(oid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestReplyCountLike(t *testing.T) {
convey.Convey("CountLike", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
tp = int8(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
count, err := d.Reply.CountLike(c, oid, tp)
ctx.Convey("Then err should be nil.count should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(count, convey.ShouldNotBeNil)
})
})
})
}
func TestReplyReplyGet(t *testing.T) {
convey.Convey("Get", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
rpID = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
r, err := d.Reply.Get(c, oid, rpID)
ctx.Convey("Then err should be nil.r should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(r, convey.ShouldBeNil)
})
})
})
}
func TestReplyGetIDsByDialogAsc(t *testing.T) {
convey.Convey("GetIDsByDialogAsc", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
tp = int8(0)
root = int64(0)
dialog = int64(0)
maxFloor = int64(0)
count = int(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
rpIDs, err := d.Reply.GetIDsByDialogAsc(c, oid, tp, root, dialog, maxFloor, count)
ctx.Convey("Then err should be nil.rpIDs should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(rpIDs, convey.ShouldBeNil)
})
})
})
}
func TestReplyGetDialogMinMaxFloor(t *testing.T) {
convey.Convey("GetDialogMinMaxFloor", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
tp = int8(0)
root = int64(0)
dialog = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
minFloor, maxFloor, err := d.Reply.GetDialogMinMaxFloor(c, oid, tp, root, dialog)
ctx.Convey("Then err should be nil.minFloor,maxFloor should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(maxFloor, convey.ShouldNotBeNil)
ctx.So(minFloor, convey.ShouldNotBeNil)
})
})
})
}
func TestReplyGetIDsByDialogDesc(t *testing.T) {
convey.Convey("GetIDsByDialogDesc", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
tp = int8(0)
root = int64(0)
dialog = int64(0)
minFloor = int64(0)
count = int(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
rpIDs, err := d.Reply.GetIDsByDialogDesc(c, oid, tp, root, dialog, minFloor, count)
ctx.Convey("Then err should be nil.rpIDs should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(rpIDs, convey.ShouldBeNil)
})
})
})
}
func TestReplyGetIDsByDialog(t *testing.T) {
convey.Convey("GetIDsByDialog", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
tp = int8(0)
root = int64(0)
dialog = int64(0)
offset = int(0)
count = int(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
rpIDs, err := d.Reply.GetIDsByDialog(c, oid, tp, root, dialog, offset, count)
ctx.Convey("Then err should be nil.rpIDs should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(rpIDs, convey.ShouldBeNil)
})
})
})
}
func TestReplyGetByIds(t *testing.T) {
convey.Convey("GetByIds", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
tp = int8(0)
rpIds = []int64{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
rpMap, err := d.Reply.GetByIds(c, oid, tp, rpIds)
ctx.Convey("Then err should be nil.rpMap should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(rpMap, convey.ShouldBeNil)
})
})
})
}
func TestReplyGetIdsSortFloor(t *testing.T) {
convey.Convey("GetIdsSortFloor", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
tp = int8(0)
offset = int(0)
count = int(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
res, err := d.Reply.GetIdsSortFloor(c, oid, tp, offset, count)
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)
})
})
})
}
func TestReplyGetIdsSortCount(t *testing.T) {
convey.Convey("GetIdsSortCount", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
tp = int8(0)
offset = int(0)
count = int(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
res, err := d.Reply.GetIdsSortCount(c, oid, tp, offset, count)
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)
})
})
})
}
func TestReplyGetIdsSortLike(t *testing.T) {
convey.Convey("GetIdsSortLike", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
tp = int8(0)
offset = int(0)
count = int(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
res, err := d.Reply.GetIdsSortLike(c, oid, tp, offset, count)
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)
})
})
})
}
func TestReplyGetIdsByRoot(t *testing.T) {
convey.Convey("GetIdsByRoot", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
root = int64(0)
tp = int8(0)
offset = int(0)
count = int(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
res, err := d.Reply.GetIdsByRoot(c, oid, root, tp, offset, count)
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)
})
})
})
}
func TestReplyGetIDsByRootWithoutState(t *testing.T) {
convey.Convey("GetIDsByRootWithoutState", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
root = int64(0)
tp = int8(0)
offset = int(0)
count = int(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
res, err := d.Reply.GetIDsByRootWithoutState(c, oid, root, tp, offset, count)
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)
})
})
})
}
func TestReplyGetIDsByFloorOffset(t *testing.T) {
convey.Convey("GetIDsByFloorOffset", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
tp = int8(0)
start = int(0)
end = int(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
res, err := d.Reply.GetIDsByFloorOffset(c, oid, tp, start, end)
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)
})
})
})
}
func TestReplySetHateCount(t *testing.T) {
convey.Convey("SetHateCount", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
rpID = int64(0)
count = int32(0)
now = time.Now()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
rows, err := d.Reply.SetHateCount(c, oid, rpID, count, now)
ctx.Convey("Then err should be nil.rows should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(rows, convey.ShouldNotBeNil)
})
})
})
}
func TestReplySetLikeCount(t *testing.T) {
convey.Convey("SetLikeCount", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
rpID = int64(0)
count = int32(0)
now = time.Now()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
rows, err := d.Reply.SetLikeCount(c, oid, rpID, count, now)
ctx.Convey("Then err should be nil.rows should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(rows, convey.ShouldNotBeNil)
})
})
})
}
func TestReplyAddFilteredReply(t *testing.T) {
convey.Convey("AddFilteredReply", t, func(ctx convey.C) {
var (
c = context.Background()
rpID = int64(-1)
oid = int64(0)
mid = int64(0)
tp = int8(0)
level = int8(0)
message = ""
now = time.Now()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.Reply.AddFilteredReply(c, rpID, oid, mid, tp, level, message, now)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
d.mysql.Exec(context.Background(), "DELETE FROM reply_filtered WHERE rpid=-1")
})
}

View File

@@ -0,0 +1,83 @@
package reply
import (
"context"
"fmt"
model "go-common/app/interface/main/reply/model/reply"
"go-common/library/database/sql"
"go-common/library/log"
)
const (
_repSharding int64 = 200
)
const (
// report
_inRptSQL = "INSERT INTO reply_report_%d (oid,type,rpid,mid,reason,content,count,score,state,ctime,mtime) VALUES(?,?,?,?,?,?,?,?,?,?,?) ON DUPLICATE KEY UPDATE count=count+1, score=score+?, mtime=?"
_selRptSQL = "SELECT oid,type,rpid,mid,reason,content,count,state,ctime,mtime,attr FROM reply_report_%d WHERE rpid=?"
// report user
_inRptUserSQL = "INSERT IGNORE INTO reply_report_user_%d (oid,type,rpid,mid,reason,content,state,ctime,mtime) VALUES(?,?,?,?,?,?,?,?,?)"
)
// ReportDao report dao.
type ReportDao struct {
inStmts []*sql.Stmt
inUserStmts []*sql.Stmt
db *sql.DB
}
// NewReportDao new ReplyReportDao and return.
func NewReportDao(db *sql.DB) (dao *ReportDao) {
dao = &ReportDao{
db: db,
inStmts: make([]*sql.Stmt, _repSharding),
inUserStmts: make([]*sql.Stmt, _repSharding),
}
for i := int64(0); i < _repSharding; i++ {
dao.inStmts[i] = dao.db.Prepared(fmt.Sprintf(_inRptSQL, i))
dao.inUserStmts[i] = dao.db.Prepared(fmt.Sprintf(_inRptUserSQL, i))
}
return
}
func (dao *ReportDao) hit(oid int64) int64 {
return oid % _repSharding
}
// Insert insert a report to mysql.
func (dao *ReportDao) Insert(c context.Context, rpt *model.Report) (id int64, err error) {
res, err := dao.inStmts[dao.hit(rpt.Oid)].Exec(c, rpt.Oid, rpt.Type, rpt.RpID, rpt.Mid, rpt.Reason, rpt.Content, rpt.Count, rpt.Score, rpt.State, rpt.CTime, rpt.MTime, rpt.Score, rpt.MTime)
if err != nil {
log.Error("db.Exec error(%v)", err)
return
}
return res.LastInsertId()
}
// Get return a report from mysql.
func (dao *ReportDao) Get(c context.Context, oid, rpID int64) (rpt *model.Report, err error) {
row := dao.db.QueryRow(c, fmt.Sprintf(_selRptSQL, dao.hit(oid)), rpID)
rpt = &model.Report{}
err = row.Scan(&rpt.Oid, &rpt.Type, &rpt.RpID, &rpt.Mid, &rpt.Reason, &rpt.Content, &rpt.Count, &rpt.State, &rpt.CTime, &rpt.MTime, &rpt.Attr)
if err != nil {
if err == sql.ErrNoRows {
rpt = nil
err = nil
} else {
log.Error("Mysql error(%v)", err)
}
}
return
}
// InsertUser inser a report user to mysql.
func (dao *ReportDao) InsertUser(c context.Context, ru *model.ReportUser) (id int64, err error) {
res, err := dao.inUserStmts[dao.hit(ru.Oid)].Exec(c, ru.Oid, ru.Type, ru.RpID, ru.Mid, ru.Reason, ru.Content, ru.State, ru.CTime, ru.MTime)
if err != nil {
log.Error("db.Exec error(%v)", err)
return
}
return res.LastInsertId()
}

View File

@@ -0,0 +1,88 @@
package reply
import (
"context"
"go-common/app/interface/main/reply/conf"
model "go-common/app/interface/main/reply/model/reply"
"go-common/library/database/sql"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestReplyNewReportDao(t *testing.T) {
convey.Convey("NewReportDao", t, func(ctx convey.C) {
var (
db = sql.NewMySQL(conf.Conf.MySQL.Reply)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
dao := NewReportDao(db)
ctx.Convey("Then dao should not be nil.", func(ctx convey.C) {
ctx.So(dao, convey.ShouldNotBeNil)
})
})
})
}
func TestReplyReporthit(t *testing.T) {
convey.Convey("hit", t, func(ctx convey.C) {
var (
oid = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := d.Report.hit(oid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestReplyReportInsert(t *testing.T) {
convey.Convey("Insert", t, func(ctx convey.C) {
var (
c = context.Background()
rpt = &model.Report{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
id, err := d.Report.Insert(c, rpt)
ctx.Convey("Then err should be nil.id should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(id, convey.ShouldNotBeNil)
})
})
})
}
func TestReplyReportGet(t *testing.T) {
convey.Convey("Get", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
rpID = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
rpt, err := d.Report.Get(c, oid, rpID)
ctx.Convey("Then err should be nil.rpt should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(rpt, convey.ShouldNotBeNil)
})
})
})
}
func TestReplyInsertUser(t *testing.T) {
convey.Convey("InsertUser", t, func(ctx convey.C) {
var (
c = context.Background()
ru = &model.ReportUser{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
id, err := d.Report.InsertUser(c, ru)
ctx.Convey("Then err should be nil.id should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(id, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,136 @@
package reply
import (
"context"
"fmt"
"time"
"go-common/app/interface/main/reply/model/reply"
"go-common/library/database/sql"
"go-common/library/log"
"go-common/library/xstr"
)
const (
_subSharding int64 = 50
)
const (
_inSubSQL = "INSERT IGNORE INTO reply_subject_%d (oid,type,mid,state,ctime,mtime) VALUES(?,?,?,?,?,?)"
_upSubStateSQL = "UPDATE reply_subject_%d SET state=?,mtime=? WHERE oid=? AND type=?"
_upSubMidSQL = "UPDATE reply_subject_%d SET mid=?,mtime=? WHERE oid=? AND type=?"
_selSubjectSQL = "SELECT oid,type,mid,count,rcount,acount,state,attr,ctime,mtime,meta FROM reply_subject_%d WHERE oid=? AND type=?"
_selSubjectsSQL = "SELECT oid,type,mid,count,rcount,acount,state,attr,ctime,mtime,meta FROM reply_subject_%d WHERE type=? AND oid IN(%s)"
_setSubjectSQL = "INSERT INTO reply_subject_%d (oid,type,mid,state,ctime,mtime) VALUES(?,?,?,?,?,?) ON DUPLICATE KEY UPDATE state=?,mid=?,mtime=?"
)
// SubjectDao subject dao.
type SubjectDao struct {
db *sql.DB
}
// NewSubjectDao new ReplySubjectDao and return.
func NewSubjectDao(db *sql.DB) (dao *SubjectDao) {
dao = &SubjectDao{
db: db,
}
return
}
func (dao *SubjectDao) hit(oid int64) int64 {
return oid % _subSharding
}
// Set insert or update subject state.
func (dao *SubjectDao) Set(c context.Context, sub *reply.Subject) (id int64, err error) {
res, err := dao.db.Exec(c, fmt.Sprintf(_setSubjectSQL, dao.hit(sub.Oid)), sub.Oid, sub.Type, sub.Mid, sub.State, sub.CTime, sub.MTime, sub.State, sub.Mid, sub.MTime)
if err != nil {
log.Error("mysqlDB.Exec error(%v)", err)
return
}
return res.LastInsertId()
}
// Insert insert a reply subject.
func (dao *SubjectDao) Insert(c context.Context, sub *reply.Subject) (id int64, err error) {
res, err := dao.db.Exec(c, fmt.Sprintf(_inSubSQL, dao.hit(sub.Oid)), sub.Oid, sub.Type, sub.Mid, sub.State, sub.CTime, sub.MTime)
if err != nil {
log.Error("mysqlDB.Exec error(%v)", err)
return
}
return res.LastInsertId()
}
// UpState update subject state.
func (dao *SubjectDao) UpState(c context.Context, oid int64, tp int8, state int8, now time.Time) (rows int64, err error) {
res, err := dao.db.Exec(c, fmt.Sprintf(_upSubStateSQL, dao.hit(oid)), state, now, oid, tp)
if err != nil {
log.Error("mysqlDB.Exec error(%v)", err)
return
}
return res.RowsAffected()
}
// UpMid update subject mid.
func (dao *SubjectDao) UpMid(c context.Context, mid, oid int64, tp int8, now time.Time) (rows int64, err error) {
res, err := dao.db.Exec(c, fmt.Sprintf(_upSubMidSQL, dao.hit(oid)), mid, now, oid, tp)
if err != nil {
log.Error("mysqlDB.Exec error(%v)", err)
return
}
return res.RowsAffected()
}
// Get get a subject.
func (dao *SubjectDao) Get(c context.Context, oid int64, tp int8) (sub *reply.Subject, err error) {
sub = &reply.Subject{}
row := dao.db.QueryRow(c, fmt.Sprintf(_selSubjectSQL, dao.hit(oid)), oid, tp)
if err = row.Scan(&sub.Oid, &sub.Type, &sub.Mid, &sub.Count, &sub.RCount, &sub.ACount, &sub.State, &sub.Attr, &sub.CTime, &sub.MTime, &sub.Meta); err != nil {
if err == sql.ErrNoRows {
sub = nil
err = nil
} else {
log.Error("row.Scan error(%v)", err)
}
}
return
}
// Gets get a subject.
func (dao *SubjectDao) Gets(c context.Context, oids []int64, tp int8) (res map[int64]*reply.Subject, err error) {
hits := make(map[int64][]int64)
for _, oid := range oids {
hit := dao.hit(oid)
hits[hit] = append(hits[hit], oid)
}
res = make(map[int64]*reply.Subject, len(oids))
for hit, oids := range hits {
var rows *sql.Rows
if rows, err = dao.db.Query(c, fmt.Sprintf(_selSubjectsSQL, hit, xstr.JoinInts(oids)), tp); err != nil {
log.Error("dao.db.Query error(%v)", err)
return
}
for rows.Next() {
sub := new(reply.Subject)
if err = rows.Scan(&sub.Oid, &sub.Type, &sub.Mid, &sub.Count, &sub.RCount, &sub.ACount, &sub.State, &sub.Attr, &sub.CTime, &sub.MTime, &sub.Meta); err != nil {
if err == sql.ErrNoRows {
sub = nil
err = nil
continue
} else {
log.Error("row.Scan error(%v)", err)
rows.Close()
return
}
}
res[sub.Oid] = sub
}
if err = rows.Err(); err != nil {
log.Error("rows.err error(%v)", err)
rows.Close()
return
}
rows.Close()
}
return
}

View File

@@ -0,0 +1,143 @@
package reply
import (
"context"
"go-common/app/interface/main/reply/model/reply"
"go-common/library/database/sql"
"testing"
"time"
"github.com/smartystreets/goconvey/convey"
)
func TestReplyNewSubjectDao(t *testing.T) {
convey.Convey("NewSubjectDao", t, func(ctx convey.C) {
var (
db = &sql.DB{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
dao := NewSubjectDao(db)
ctx.Convey("Then dao should not be nil.", func(ctx convey.C) {
ctx.So(dao, convey.ShouldNotBeNil)
})
})
})
}
func TestReplySubjecthit(t *testing.T) {
convey.Convey("hit", t, func(ctx convey.C) {
var (
oid = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := d.Subject.hit(oid)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestReplySet(t *testing.T) {
convey.Convey("Set", t, func(ctx convey.C) {
var (
c = context.Background()
sub = &reply.Subject{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
id, err := d.Subject.Set(c, sub)
ctx.Convey("Then err should be nil.id should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(id, convey.ShouldNotBeNil)
})
})
})
}
func TestReplyInsert(t *testing.T) {
convey.Convey("Insert", t, func(ctx convey.C) {
var (
c = context.Background()
sub = &reply.Subject{}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
id, err := d.Subject.Insert(c, sub)
ctx.Convey("Then err should be nil.id should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(id, convey.ShouldNotBeNil)
})
})
})
}
func TestReplyUpState(t *testing.T) {
convey.Convey("UpState", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
tp = int8(0)
state = int8(0)
now = time.Now()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
rows, err := d.Subject.UpState(c, oid, tp, state, now)
ctx.Convey("Then err should be nil.rows should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(rows, convey.ShouldNotBeNil)
})
})
})
}
func TestReplyUpMid(t *testing.T) {
convey.Convey("UpMid", t, func(ctx convey.C) {
var (
c = context.Background()
mid = int64(0)
oid = int64(0)
tp = int8(0)
now = time.Now()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
rows, err := d.Subject.UpMid(c, mid, oid, tp, now)
ctx.Convey("Then err should be nil.rows should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(rows, convey.ShouldNotBeNil)
})
})
})
}
func TestReplyGet(t *testing.T) {
convey.Convey("Get", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
tp = int8(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
sub, err := d.Subject.Get(c, oid, tp)
ctx.Convey("Then err should be nil.sub should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(sub, convey.ShouldNotBeNil)
})
})
})
}
func TestReplyGets(t *testing.T) {
convey.Convey("Gets", t, func(ctx convey.C) {
var (
c = context.Background()
oids = []int64{}
tp = int8(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
res, err := d.Subject.Gets(c, oids, tp)
ctx.Convey("Then err should be nil.res should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(res, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,58 @@
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",
"log_test.go",
"record_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/reply/conf:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"dao.go",
"log.go",
"record.go",
],
importpath = "go-common/app/interface/main/reply/dao/search",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/reply/conf:go_default_library",
"//app/interface/main/reply/model/adminlog:go_default_library",
"//app/interface/main/reply/model/reply:go_default_library",
"//library/database/elastic:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/xstr: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,31 @@
package search
import (
"go-common/app/interface/main/reply/conf"
es "go-common/library/database/elastic"
bm "go-common/library/net/http/blademaster"
)
const (
_searchURL = "/x/internal/search/reply"
_searchLogURL = "/api/reply/external/search"
)
// Dao search dao.
type Dao struct {
logURL string
searchURL string
httpCli *bm.Client
es *es.Elastic
}
// New new a dao and return.
func New(c *conf.Config) *Dao {
d := &Dao{
logURL: c.Host.Search + _searchLogURL,
searchURL: c.Host.API + _searchURL,
httpCli: bm.NewClient(c.HTTPClient),
es: es.NewElastic(c.Es),
}
return d
}

View File

@@ -0,0 +1,33 @@
package search
import (
"os"
"flag"
"testing"
"go-common/app/interface/main/reply/conf"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "")
flag.Set("conf_token", "")
flag.Set("tree_id", "")
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/reply-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,65 @@
package search
import (
"context"
"net/url"
"strconv"
"time"
"go-common/app/interface/main/reply/model/adminlog"
"go-common/library/log"
"go-common/library/xstr"
)
type searchAdminLog struct {
ReplyID int64 `json:"rpid"` // 评论id
AdminID int64 `json:"adminid"` // 操作人
State int32 `json:"state"` // 操作人身份
ReplyMid int64 `json:"replymid"` // 评论人
CTime string `json:"ctime"` // 删除时间
}
// LogPaginate paginating the admin logs for size of 'pageSize', and returning the number of reporting, the number of admin logs delete by administrator
func (dao *Dao) LogPaginate(c context.Context, oid int64, tp int, states []int64, curPage, pageSize int, startTime string, now time.Time) (logs []*adminlog.AdminLog, replyCount, reportCount, pageCount, total int64, err error) {
params := url.Values{}
params.Set("appid", "replylog")
params.Set("oid", strconv.FormatInt(oid, 10))
params.Set("type", strconv.Itoa(tp))
params.Set("delstats", xstr.JoinInts(states))
params.Set("start_time", startTime)
params.Set("pagesize", strconv.Itoa(pageSize))
params.Set("page", strconv.Itoa(curPage))
var res struct {
Code int `json:"code"`
Logs []*searchAdminLog `json:"result"`
ReplyCount int64 `json:"adminDeletedNum"`
ReportCount int64 `json:"reportNum"`
Page int64 `json:"page"`
PageSize int64 `json:"pagesize"`
PageCount int64 `json:"pagecount"`
Total int64 `json:"total"`
}
if err = dao.httpCli.Get(c, dao.logURL, "", params, &res); err != nil {
log.Error("adminlog url(%v),err (%v)", dao.logURL+"?"+params.Encode(), err)
return
}
if res.Logs == nil {
logs = make([]*adminlog.AdminLog, 0)
}
for _, log := range res.Logs {
var (
tmp = &adminlog.AdminLog{}
)
tmp.ReplyID = log.ReplyID
tmp.State = log.State
tmp.AdminID = log.AdminID
tmp.CTime = log.CTime
tmp.ReplyMid = log.ReplyMid
logs = append(logs, tmp)
}
replyCount = res.ReplyCount
reportCount = res.ReportCount
pageCount = res.PageCount
total = res.Total
return
}

View File

@@ -0,0 +1,35 @@
package search
import (
"context"
"testing"
"time"
"github.com/smartystreets/goconvey/convey"
)
func TestSearchLogPaginate(t *testing.T) {
convey.Convey("LogPaginate", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
tp = int(0)
states = []int64{}
curPage = int(0)
pageSize = int(0)
startTime = ""
now = time.Now()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
logs, replyCount, reportCount, pageCount, total, err := d.LogPaginate(c, oid, tp, states, curPage, pageSize, startTime, now)
ctx.Convey("Then err should be nil.logs,replyCount,reportCount,pageCount,total should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
ctx.So(total, convey.ShouldNotBeNil)
ctx.So(pageCount, convey.ShouldNotBeNil)
ctx.So(reportCount, convey.ShouldNotBeNil)
ctx.So(replyCount, convey.ShouldNotBeNil)
ctx.So(logs, convey.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,45 @@
package search
import (
"context"
"time"
"fmt"
model "go-common/app/interface/main/reply/model/reply"
es "go-common/library/database/elastic"
"go-common/library/log"
)
var (
recordStates = []int64{0, 1, 2, 5, 6, 7, 9, 11}
)
type recordResult struct {
Page struct {
Num int32 `json:"num"`
Size int32 `json:"size"`
Total int32 `json:"total"`
} `json:"page"`
Result []*model.Record `json:"result"`
}
// RecordPaginate return a page of records from es.
func (d *Dao) RecordPaginate(c context.Context, types []int64, mid, stime, etime int64, order, sort string, pn, ps int32) (records []*model.Record, total int32, err error) {
r := d.es.NewRequest("reply_record").Index(fmt.Sprintf("%s_%d", "replyrecord", mid%100)).
WhereRange("ctime", time.Unix(stime, 0).Format(model.RecordTimeLayout), time.Unix(etime, 0).Format(model.RecordTimeLayout), es.RangeScopeLcRc).
WhereIn("state", recordStates).
WhereEq("mid", mid).
Order(order, sort).Pn(int(pn)).Ps(int(ps))
if len(types) > 0 {
r = r.WhereIn("type", types)
}
var res recordResult
err = r.Scan(c, &res)
if err != nil {
log.Error("r.Scan(%v) error(%v)", c, err)
return
}
records = res.Result
total = int32(res.Page.Total)
return
}

View File

@@ -0,0 +1,32 @@
package search
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestSearchRecordPaginate(t *testing.T) {
convey.Convey("RecordPaginate", t, func(ctx convey.C) {
var (
c = context.Background()
types = []int64{}
mid = int64(0)
stime = int64(0)
etime = int64(0)
order = ""
sort = ""
pn = int32(0)
ps = int32(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
records, total, err := d.RecordPaginate(c, types, mid, stime, etime, order, sort, pn, ps)
ctx.Convey("Then err should be nil.records,total should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
ctx.So(total, convey.ShouldNotBeNil)
ctx.So(records, convey.ShouldBeNil)
})
})
})
}

View File

@@ -0,0 +1,47 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = ["vip_test.go"],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/reply/conf:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = ["vip.go"],
importpath = "go-common/app/interface/main/reply/dao/vip",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/reply/conf:go_default_library",
"//app/interface/main/reply/model/vip: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,87 @@
package vip
import (
"context"
"net/url"
"go-common/app/interface/main/reply/conf"
"go-common/app/interface/main/reply/model/vip"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
)
const (
_emojiURL = "/internal/v1/emoji/list"
)
type result struct {
Code int `json:"code"`
Data []*struct {
ID int64 `json:"id"`
Name string `json:"name"`
URL string `json:"path"`
State int8 `json:"deleted"`
Emojis []*struct {
ID int64 `json:"id"`
Name string `json:"name"`
URL string `json:"path"`
State int8 `json:"deleted"`
Remark string `json:"remark"`
} `json:"emojiList"`
} `json:"data"`
}
// Dao dao.
type Dao struct {
emojiURL string
httpClient *bm.Client
}
// New new a dao and return.
func New(c *conf.Config) *Dao {
d := &Dao{
httpClient: bm.NewClient(c.HTTPClient),
emojiURL: c.Reply.VipURL + _emojiURL,
}
return d
}
// Emoji return emojis to cache
func (dao *Dao) Emoji(c context.Context) (emjs []*vip.Emoji, emjM map[string]int64, err error) {
var res result
params := url.Values{}
if err = dao.httpClient.Get(c, dao.emojiURL, "", params, &res); err != nil {
log.Error("vip url(%s) error(%v)", dao.emojiURL+"?"+params.Encode(), err)
return
}
if res.Code != 0 {
log.Error("vip url(%s) error(%v)", dao.emojiURL+"?"+params.Encode(), res.Code)
return
}
emjs = make([]*vip.Emoji, 0, len(res.Data))
emjM = make(map[string]int64)
for _, d := range res.Data {
var tmp = &vip.Emoji{
Pid: d.ID,
Pname: d.Name,
Purl: d.URL,
Pstate: d.State,
}
emoTmps := make([]*vip.Face, 0, len(d.Emojis))
for _, e := range d.Emojis {
var emoTmp = &vip.Face{
ID: e.ID,
Name: e.Name,
URL: e.URL,
State: e.State,
}
emoTmps = append(emoTmps, emoTmp)
if d.State == 0 && e.State == 0 {
emjM[e.Name] = e.ID
}
}
tmp.Emojis = emoTmps
emjs = append(emjs, tmp)
}
return
}

View File

@@ -0,0 +1,67 @@
package vip
import (
"context"
"flag"
"go-common/app/interface/main/reply/conf"
"os"
"testing"
"github.com/smartystreets/goconvey/convey"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "")
flag.Set("conf_token", "")
flag.Set("tree_id", "")
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/reply-test.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
os.Exit(m.Run())
}
func TestVipNew(t *testing.T) {
convey.Convey("New", t, func(ctx convey.C) {
var (
c = conf.Conf
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := New(c)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestVipEmoji(t *testing.T) {
convey.Convey("Emoji", t, func(ctx convey.C) {
var (
c = context.Background()
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
emjs, emjM, err := d.Emoji(c)
ctx.Convey("Then err should be nil.emjs,emjM should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(emjM, convey.ShouldNotBeNil)
ctx.So(emjs, convey.ShouldNotBeNil)
})
})
})
}

View File

@@ -0,0 +1,48 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = ["workflow.go"],
importpath = "go-common/app/interface/main/reply/dao/workflow",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/reply/conf:go_default_library",
"//app/interface/main/reply/model/reply:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/xstr: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 = ["workflow_test.go"],
embed = [":go_default_library"],
tags = ["automanaged"],
deps = [
"//app/interface/main/reply/conf:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)

View File

@@ -0,0 +1,454 @@
package workflow
import (
"context"
"encoding/json"
"fmt"
"net/url"
"strconv"
"go-common/app/interface/main/reply/conf"
model "go-common/app/interface/main/reply/model/reply"
"go-common/library/ecode"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/xstr"
)
const (
workflowHost = "api.bilibili.co"
_apiTopics = "http://matsuri.bilibili.co/activity/pages"
_apiActivitySub = "http://matsuri.bilibili.co//activity/subject/url"
_apiLiveActivity = "http://api.live.bilibili.co/comment/v1/relation/get_by_id"
_apiNotice = "http://api.bilibili.co/x/internal/credit/publish/infos"
_apiBan = "http://api.bilibili.co/x/internal/credit/blocked/infos"
_apiCredit = "http://api.bilibili.co/x/internal/credit/blocked/cases"
_apiLiveVideo = "http://api.vc.bilibili.co/clip/v1/video/detail"
_apiLiveNotice = "http://api.vc.bilibili.co/news/v1/notice/info"
_apiLivePicture = "http://api.vc.bilibili.co/link_draw/v1/doc/detail"
_apiTopic = "http://matsuri.bilibili.co/activity/page/one/%d"
_apiDynamic = "http://api.vc.bilibili.co/dynamic_repost/v0/dynamic_repost/ftch_rp_cont?dynamic_ids[]=%d"
_apiHuoniao = "http://manga.bilibili.co/twirp/verify.v0.Verify/InfoC"
// link
_linkBan = "https://www.bilibili.com/blackroom/ban/%d"
_linkNotice = "https://www.bilibili.com/blackroom/notice/%d"
_linkCredit = "https://www.bilibili.com/judgement/case/%d"
_linkLiveVideo = "http://vc.bilibili.com/video/%d"
_linkLiveNotice = "http://link.bilibili.com/p/eden/news#/newsdetail?id=%d"
_linkLivePicture = "http://h.bilibili.com/ywh/%d"
_linkDynamic = "http://t.bilibili.com/%d"
_urlLiveNotice = "http://api.vc.bilibili.co/news/v1/notice/info"
_linkHuoniao = "http://manga.bilibili.com/m/detail/mc%d"
)
type result struct {
Code int `json:"code"`
Message string `json:"message"`
Data struct {
ChallengeNo int64 `json:"challengeNo"`
}
}
// Dao dao.
type Dao struct {
httpClient *bm.Client
}
// New new a dao and return.
func New(c *conf.Config) *Dao {
d := &Dao{
httpClient: bm.NewClient(c.HTTPClient),
}
return d
}
type extra struct {
Like int `json:"like"`
Link string `json:"link"`
Title string `json:"title"`
}
func (dao *Dao) AddReport(c context.Context, oid int64, typ int8, typeid int32, rpid int64, score int, reason int8, reporter int64, reported int64, like int, content string, link string, title string) (err error) {
var res result
rid := "1"
params := url.Values{}
params.Add("business", "13")
params.Add("fid", strconv.FormatInt(int64(typ), 10))
if model.GetReportType(reason) == model.ReportStateNewTwo {
rid = "2"
}
params.Add("rid", rid)
params.Add("eid", strconv.FormatInt(int64(rpid), 10))
params.Add("score", strconv.FormatInt(int64(score), 10))
params.Add("tid", strconv.FormatInt(int64(reason), 10))
params.Add("oid", strconv.FormatInt(int64(oid), 10))
params.Add("mid", strconv.FormatInt(int64(reporter), 10))
params.Add("business_typeid", strconv.FormatInt(int64(typeid), 10))
params.Add("business_title", content)
params.Add("business_mid", strconv.FormatInt(int64(reported), 10))
var ex extra
ex.Like = like
ex.Link = link
ex.Title = title
businessExtra, _ := json.Marshal(&ex)
params.Add("business_extra", string(businessExtra))
url := fmt.Sprintf("http://%s/%s", workflowHost, "x/internal/workflow/appeal/v3/add")
if err = dao.httpClient.Post(c, url, "", params, &res); err != nil {
log.Error("AddReport url(%s,%s) error(%v)", url, params.Encode(), err)
return
}
if res.Code != 0 {
log.Error("AddReport url(%s,%s) error(%v)", url, params.Encode(), res.Code)
err = ecode.Int(res.Code)
return
}
return
}
// TopicsLink get topic info.
func (d *Dao) TopicsLink(c context.Context, links map[int64]string, isTopic bool) (err error) {
if len(links) == 0 {
return
}
var res struct {
Code int `json:"code"`
Data *struct {
List []struct {
ID int64 `json:"id"`
PCURL string `json:"pc_url"`
H5URL string `json:"h5_url"`
} `json:"list"`
} `json:"data"`
}
var ids []int64
for oid := range links {
ids = append(ids, oid)
}
params := url.Values{}
params.Set("pids", xstr.JoinInts(ids))
params.Set("all", "isOne")
if isTopic {
params.Set("mold", "1")
}
if err = d.httpClient.Get(c, _apiTopics, "", params, &res); err != nil {
log.Error("TopicsTitle(%s) error(%v)", _apiTopics, err)
return
}
if res.Data == nil {
err = fmt.Errorf("url:%s code:%d", _apiTopics, res.Code)
return
}
for _, data := range res.Data.List {
if data.PCURL != "" {
links[data.ID] = data.PCURL
} else {
links[data.ID] = data.H5URL
}
}
return
}
// ActivitySub return activity sub link.
func (d *Dao) ActivitySub(c context.Context, oid int64) (title, link string, err error) {
params := url.Values{}
params.Set("oid", strconv.FormatInt(oid, 10))
var res struct {
Code int `json:"code"`
Data *struct {
Title string `json:"name"`
Link string `json:"act_url"`
} `json:"data"`
}
if err = d.httpClient.Get(c, _apiActivitySub, "", params, &res); err != nil {
log.Error("d.httpClient.Get(%s?%s) error(%v)", _apiActivitySub, params.Encode(), err)
return
}
if res.Data == nil {
err = fmt.Errorf("url:%s code:%d", _apiActivitySub, res.Code)
return
}
title = res.Data.Title
link = res.Data.Link
return
}
// LiveNotice return link.
func (d *Dao) LiveNotice(c context.Context, oid int64) (title string, err error) {
params := url.Values{}
params.Set("id", strconv.FormatInt(oid, 10))
var res struct {
Code int `json:"code"`
Data *struct {
Title string `json:"title"`
} `json:"data"`
}
if err = d.httpClient.Get(c, _urlLiveNotice, "", params, &res); err != nil {
log.Error("d.httpClient.Get(%s?%s) error(%v)", _urlLiveNotice, params.Encode(), err)
return
}
if res.Code != 0 || res.Data == nil {
err = fmt.Errorf("url:%s?%s code:%d", _urlLiveNotice, params.Encode(), res.Code)
return
}
title = res.Data.Title
return
}
// LiveActivityTitle get live activity info.
func (d *Dao) LiveActivityTitle(c context.Context, oid int64) (title, link string, err error) {
params := url.Values{}
params.Set("id", strconv.FormatInt(oid, 10))
var res struct {
Code int `json:"code"`
Data *struct {
Name string `json:"name"`
URL string `json:"url"`
} `json:"data"`
}
if err = d.httpClient.Get(c, _apiLiveActivity, "", params, &res); err != nil {
log.Error("httpLiveActivityTitle(%s?%s) error(%v)", _apiLiveActivity, params.Encode(), err)
return
}
if res.Code != 0 || res.Data == nil {
err = fmt.Errorf("url:%s?%s code:%d", _apiLiveActivity, params.Encode(), res.Code)
return
}
title = res.Data.Name
link = res.Data.URL
return
}
type notice struct {
Title string `json:"title"`
}
type ban struct {
Title string `json:"punishTitle"`
}
type credit struct {
Title string `json:"punishTitle"`
}
// NoticeTitle get blackromm notice info.
func (d *Dao) NoticeTitle(c context.Context, oid int64) (title, link string, err error) {
params := url.Values{}
params.Set("ids", strconv.FormatInt(oid, 10))
var res struct {
Code int `json:"code"`
Data map[int64]*notice `json:"data"`
}
if err = d.httpClient.Get(c, _apiNotice, "", params, &res); err != nil {
log.Error("httpNotice(%s) error(%v)", _apiNotice, err)
return
}
if r := res.Data[oid]; r != nil {
title = r.Title
}
link = fmt.Sprintf(_linkNotice, oid)
return
}
// BanTitle get ban info.
func (d *Dao) BanTitle(c context.Context, oid int64) (title, link string, err error) {
params := url.Values{}
params.Set("ids", strconv.FormatInt(oid, 10))
var res struct {
Code int `json:"code"`
Data map[int64]*ban `json:"data"`
}
if err = d.httpClient.Get(c, _apiBan, "", params, &res); err != nil {
log.Error("httpBan(%s) error(%v)", _apiBan, err)
return
}
if r := res.Data[oid]; r != nil {
title = r.Title
}
link = fmt.Sprintf(_linkBan, oid)
return
}
// CreditTitle return link.
func (d *Dao) CreditTitle(c context.Context, oid int64) (title, link string, err error) {
params := url.Values{}
params.Set("ids", strconv.FormatInt(oid, 10))
var res struct {
Code int `json:"code"`
Data map[int64]*credit `json:"data"`
}
if err = d.httpClient.Get(c, _apiCredit, "", params, &res); err != nil {
log.Error("d.httpClient.Get(%s?%s) error(%v)", _apiCredit, params.Encode(), err)
return
}
if res.Code != 0 || res.Data == nil {
err = fmt.Errorf("url:%s?%s code:%d", _apiCredit, params.Encode(), res.Code)
return
}
if r := res.Data[oid]; r != nil {
title = r.Title
}
link = fmt.Sprintf(_linkCredit, oid)
return
}
// LiveVideoTitle get live video title.
func (d *Dao) LiveVideoTitle(c context.Context, oid int64) (title, link string, err error) {
params := url.Values{}
params.Set("video_id", strconv.FormatInt(oid, 10))
var res struct {
Code int `json:"code"`
Data *struct {
Item *struct {
Description string `json:"description"`
} `json:"item"`
} `json:"data"`
}
if err = d.httpClient.Get(c, _apiLiveVideo, "", params, &res); err != nil {
log.Error("httpLiveVideoTitle(%s?%s) error(%v)", _apiLiveVideo, params.Encode(), err)
return
}
if res.Code != 0 || res.Data == nil || res.Data.Item == nil {
err = fmt.Errorf("url:%s?%s code:%d", _apiLiveVideo, params.Encode(), res.Code)
return
}
title = res.Data.Item.Description
link = fmt.Sprintf(_linkLiveVideo, oid)
return
}
// LiveNoticeTitle get live notice info.
func (d *Dao) LiveNoticeTitle(c context.Context, oid int64) (title, link string, err error) {
params := url.Values{}
params.Set("id", strconv.FormatInt(oid, 10))
var res struct {
Code int `json:"code"`
Data *struct {
Title string `json:"title"`
} `json:"data"`
}
if err = d.httpClient.Get(c, _apiLiveNotice, "", params, &res); err != nil {
log.Error("LiveNoticeTitle(%s?%s) error(%v)", _apiLiveNotice, params.Encode(), err)
return
}
if res.Code != 0 || res.Data == nil {
err = fmt.Errorf("url:%s?%s code:%d", _apiLiveNotice, params.Encode(), res.Code)
return
}
title = res.Data.Title
link = fmt.Sprintf(_linkLiveNotice, oid)
return
}
// LivePictureTitle get live picture info.
func (d *Dao) LivePictureTitle(c context.Context, oid int64) (title, link string, err error) {
params := url.Values{}
params.Set("doc_id", strconv.FormatInt(oid, 10))
var res struct {
Code int `json:"code"`
Data *struct {
Item *struct {
Title string `json:"title"`
Desc string `json:"description"`
} `json:"item"`
} `json:"data"`
}
if err = d.httpClient.Get(c, _apiLivePicture, "", params, &res); err != nil {
log.Error("LivePictureTitle(%s?%s) error(%v)", _apiLivePicture, params.Encode(), err)
return
}
if res.Code != 0 || res.Data == nil || res.Data.Item == nil {
err = fmt.Errorf("url:%s?%s code:%d", _apiLivePicture, params.Encode(), res.Code)
return
}
title = res.Data.Item.Title
if title == "" {
title = res.Data.Item.Desc
}
link = fmt.Sprintf(_linkLivePicture, oid)
return
}
// TopicTitle get topic info.
func (d *Dao) TopicTitle(c context.Context, oid int64) (title, link string, err error) {
var res struct {
Code int `json:"code"`
Data *struct {
Title string `json:"name"`
PCLink string `json:"pc_url"`
H5Link string `json:"h5_url"`
} `json:"data"`
}
if err = d.httpClient.Get(c, fmt.Sprintf(_apiTopic, oid), "", nil, &res); err != nil {
log.Error("TopicTitle(%s) error(%v)", fmt.Sprintf(_apiTopic, oid), err)
return
}
if res.Data == nil {
err = fmt.Errorf("url:%s code:%d", fmt.Sprintf(_apiTopic, oid), res.Code)
return
}
title = res.Data.Title
link = res.Data.PCLink
if link == "" {
link = res.Data.H5Link
}
return
}
// DynamicTitle return link and title.
func (d *Dao) DynamicTitle(c context.Context, oid int64) (title, link string, err error) {
params := url.Values{}
uri := fmt.Sprintf(_apiDynamic, oid)
var res struct {
Code int `json:"code"`
Data *struct {
Pairs []struct {
DynamicID int64 `json:"dynamic_id"`
Content string `json:"rp_cont"`
Type int32 `json:"type"`
} `json:"pairs"`
TotalCount int64 `json:"total_count"`
} `json:"data,omitempty"`
Message string `json:"message"`
}
if err = d.httpClient.Get(c, uri, "", params, &res); err != nil {
log.Error("d.httpClient.Get(%s?%s) error(%v)", uri, params.Encode(), err)
return
}
if res.Code != 0 || res.Data == nil || len(res.Data.Pairs) == 0 {
err = fmt.Errorf("get dynamic failed!url:%s?%s code:%d message:%s pairs:%v", uri, params.Encode(), res.Code, res.Message, res.Data.Pairs)
return
}
title = res.Data.Pairs[0].Content
link = fmt.Sprintf(_linkDynamic, oid)
return
}
// HuoniaoTitle title and link
func (d *Dao) HuoniaoTitle(c context.Context, oid int64) (title, link string, err error) {
params := url.Values{}
params.Set("id", strconv.FormatInt(oid, 10))
var res struct {
Code int `json:"code"`
Data *struct {
Title string `json:"title"`
JumpURL string `json:"jump_url"`
} `json:"data,omitempty"`
Message string `json:"msg"`
}
if err = d.httpClient.Post(c, _apiHuoniao, "", params, &res); err != nil {
log.Error("httpClient.Post(%s) error(%v)", params.Encode(), err)
return
}
if res.Code != ecode.OK.Code() {
err = ecode.Int(res.Code)
return
}
if res.Data != nil {
title = res.Data.Title
link = res.Data.JumpURL
}
return
}

View File

@@ -0,0 +1,260 @@
package workflow
import (
"context"
"flag"
"os"
"testing"
"go-common/app/interface/main/reply/conf"
"github.com/smartystreets/goconvey/convey"
)
var (
d *Dao
)
func TestMain(m *testing.M) {
if os.Getenv("DEPLOY_ENV") != "" {
flag.Set("app_id", "main.community.reply")
flag.Set("conf_token", "54e85e3ab609f79ae908b9ea3e3f0775")
flag.Set("tree_id", "2125")
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/reply-test.toml")
}
flag.Parse()
if err := conf.Init(); err != nil {
panic(err)
}
d = New(conf.Conf)
os.Exit(m.Run())
}
func TestWorkflowNew(t *testing.T) {
convey.Convey("New", t, func(ctx convey.C) {
var (
c = conf.Conf
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
p1 := New(c)
ctx.Convey("Then p1 should not be nil.", func(ctx convey.C) {
ctx.So(p1, convey.ShouldNotBeNil)
})
})
})
}
func TestWorkflowAddReport(t *testing.T) {
convey.Convey("AddReport", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
typ = int8(0)
typeid = int32(0)
rpid = int64(0)
score = int(0)
reason = int8(0)
reporter = int64(0)
reported = int64(0)
like = int(0)
content = ""
link = ""
title = ""
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.AddReport(c, oid, typ, typeid, rpid, score, reason, reporter, reported, like, content, link, title)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
})
})
})
}
func TestWorkflowTopicsLink(t *testing.T) {
convey.Convey("TopicsLink", t, func(ctx convey.C) {
var (
c = context.Background()
links map[int64]string
isTopic bool
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := d.TopicsLink(c, links, isTopic)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestWorkflowActivitySub(t *testing.T) {
convey.Convey("ActivitySub", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
title, link, err := d.ActivitySub(c, oid)
ctx.Convey("Then err should be nil.title,link should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
ctx.So(link, convey.ShouldNotBeNil)
ctx.So(title, convey.ShouldNotBeNil)
})
})
})
}
func TestWorkflowLiveNotice(t *testing.T) {
convey.Convey("LiveNotice", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
title, err := d.LiveNotice(c, oid)
ctx.Convey("Then err should be nil.title should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
ctx.So(title, convey.ShouldNotBeNil)
})
})
})
}
func TestWorkflowLiveActivityTitle(t *testing.T) {
convey.Convey("LiveActivityTitle", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
title, link, err := d.LiveActivityTitle(c, oid)
ctx.Convey("Then err should be nil.title,link should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
ctx.So(link, convey.ShouldNotBeNil)
ctx.So(title, convey.ShouldNotBeNil)
})
})
})
}
func TestWorkflowNoticeTitle(t *testing.T) {
convey.Convey("NoticeTitle", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
title, link, _ := d.NoticeTitle(c, oid)
ctx.Convey("Then err should be nil.title,link should not be nil.", func(ctx convey.C) {
ctx.So(link, convey.ShouldNotBeNil)
ctx.So(title, convey.ShouldNotBeNil)
})
})
})
}
func TestWorkflowBanTitle(t *testing.T) {
convey.Convey("BanTitle", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
title, link, _ := d.BanTitle(c, oid)
ctx.Convey("Then err should be nil.title,link should not be nil.", func(ctx convey.C) {
ctx.So(link, convey.ShouldNotBeNil)
ctx.So(title, convey.ShouldNotBeNil)
})
})
})
}
func TestWorkflowCreditTitle(t *testing.T) {
convey.Convey("CreditTitle", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
title, link, _ := d.CreditTitle(c, oid)
ctx.Convey("Then err should be nil.title,link should not be nil.", func(ctx convey.C) {
ctx.So(link, convey.ShouldNotBeNil)
ctx.So(title, convey.ShouldNotBeNil)
})
})
})
}
func TestWorkflowLiveNoticeTitle(t *testing.T) {
convey.Convey("LiveNoticeTitle", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
title, link, err := d.LiveNoticeTitle(c, oid)
ctx.Convey("Then err should be nil.title,link should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
ctx.So(link, convey.ShouldNotBeNil)
ctx.So(title, convey.ShouldNotBeNil)
})
})
})
}
func TestWorkflowLivePictureTitle(t *testing.T) {
convey.Convey("LivePictureTitle", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
title, link, err := d.LivePictureTitle(c, oid)
ctx.Convey("Then err should be nil.title,link should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
ctx.So(link, convey.ShouldNotBeNil)
ctx.So(title, convey.ShouldNotBeNil)
})
})
})
}
func TestWorkflowDynamicTitle(t *testing.T) {
convey.Convey("DynamicTitle", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
title, link, err := d.DynamicTitle(c, oid)
ctx.Convey("Then err should be nil.title,link should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
ctx.So(link, convey.ShouldNotBeNil)
ctx.So(title, convey.ShouldNotBeNil)
})
})
})
}
func TestWorkflowHuoniaoTitle(t *testing.T) {
convey.Convey("HuoniaoTitle", t, func(ctx convey.C) {
var (
c = context.Background()
oid = int64(0)
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
title, link, err := d.HuoniaoTitle(c, oid)
ctx.Convey("Then err should be nil.title,link should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldNotBeNil)
ctx.So(link, convey.ShouldNotBeNil)
ctx.So(title, convey.ShouldNotBeNil)
})
})
})
}