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,79 @@
package(default_visibility = ["//visibility:public"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"advance_test.go",
"assist_test.go",
"dm_test.go",
"filter_test.go",
"protect_test.go",
"report_test.go",
"service_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/interface/main/dm/conf:go_default_library",
"//app/interface/main/dm/model:go_default_library",
"//library/ecode:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"advance.go",
"archive.go",
"assist.go",
"dm.go",
"filter.go",
"protect.go",
"report.go",
"service.go",
"subject.go",
],
importpath = "go-common/app/interface/main/dm/service",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/interface/main/dm/conf:go_default_library",
"//app/interface/main/dm/dao:go_default_library",
"//app/interface/main/dm/model:go_default_library",
"//app/interface/main/dm2/model:go_default_library",
"//app/interface/main/dm2/model/oplog:go_default_library",
"//app/interface/main/dm2/rpc/client:go_default_library",
"//app/service/main/account/api:go_default_library",
"//app/service/main/archive/api:go_default_library",
"//app/service/main/archive/api/gorpc:go_default_library",
"//app/service/main/archive/model/archive:go_default_library",
"//app/service/main/assist/model/assist:go_default_library",
"//app/service/main/assist/rpc/client:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/xstr:go_default_library",
"//vendor/github.com/zhenjl/cityhash: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,81 @@
package service
import (
"context"
dm2Mdl "go-common/app/interface/main/dm2/model"
"go-common/library/log"
)
// BuyAdvance 购买高级弹幕
func (s *Service) BuyAdvance(c context.Context, mid, cid int64, mode string) (err error) {
arg := &dm2Mdl.ArgAdvance{
Mid: mid,
Cid: cid,
Mode: mode,
}
if err = s.dmRPC.BuyAdvance(c, arg); err != nil {
log.Error("dmRPC.BuyAdvance(%v) error(%v)")
}
return
}
// AdvanceState 高级弹幕状态
func (s *Service) AdvanceState(c context.Context, mid, cid int64, mode string) (state *dm2Mdl.AdvState, err error) {
arg := &dm2Mdl.ArgAdvance{
Mid: mid,
Cid: cid,
Mode: mode,
}
if state, err = s.dmRPC.AdvanceState(c, arg); err != nil {
log.Error("dmRPC.AdvanceState(%v) error(%v)", arg, err)
}
return
}
// Advances 高级弹幕申请列表
func (s *Service) Advances(c context.Context, mid int64) (res []*dm2Mdl.Advance, err error) {
arg := &dm2Mdl.ArgMid{
Mid: mid,
}
if res, err = s.dmRPC.Advances(c, arg); err != nil {
log.Error("dmRPC.Advances(%v) error(%v)", arg, err)
}
return
}
// PassAdvance 通过高级弹幕申请
func (s *Service) PassAdvance(c context.Context, mid, id int64) (err error) {
arg := &dm2Mdl.ArgUpAdvance{
Mid: mid,
ID: id,
}
if err = s.dmRPC.PassAdvance(c, arg); err != nil {
log.Error("dmRPC.PassAdvance(%v) error(%v)", arg, err)
}
return
}
// DenyAdvance 拒绝高级弹幕申请
func (s *Service) DenyAdvance(c context.Context, mid, id int64) (err error) {
arg := &dm2Mdl.ArgUpAdvance{
Mid: mid,
ID: id,
}
if err = s.dmRPC.DenyAdvance(c, arg); err != nil {
log.Error("dmRPC.DenyAdvance(%v) error(%v)", arg, err)
}
return
}
// CancelAdvance 取消高级弹幕申请
func (s *Service) CancelAdvance(c context.Context, mid, id int64) (err error) {
arg := &dm2Mdl.ArgUpAdvance{
Mid: mid,
ID: id,
}
if err = s.dmRPC.CancelAdvance(c, arg); err != nil {
log.Error("dmRPC.CancelAdvance(%v) error(%v)", arg, err)
}
return
}

View File

@@ -0,0 +1,51 @@
package service
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestBuyAdvance(t *testing.T) {
Convey("test adv State", t, func() {
err := svr.BuyAdvance(c, 27515330, 10107292, "sp")
So(err, ShouldBeNil)
})
}
func TestAdvanceState(t *testing.T) {
Convey("test adv State", t, func() {
_, err := svr.AdvanceState(c, 27515330, 10107292, "sp")
So(err, ShouldBeNil)
})
}
func TestAdvances(t *testing.T) {
Convey("test adv", t, func() {
res, err := svr.Advances(context.TODO(), 27515260)
So(err, ShouldBeNil)
So(res, ShouldNotBeEmpty)
})
}
func TestPassAdvance(t *testing.T) {
Convey("test pass adv", t, func() {
err := svr.PassAdvance(context.TODO(), 7158471, 2)
So(err, ShouldBeNil)
})
}
func TestDenyAdvance(t *testing.T) {
Convey("test deny adv", t, func() {
err := svr.DenyAdvance(context.TODO(), 27515615, 107)
So(err, ShouldBeNil)
})
}
func TestCancelAdvance(t *testing.T) {
Convey("test cancel adv", t, func() {
err := svr.CancelAdvance(context.TODO(), 27515615, 122)
So(err, ShouldBeNil)
})
}

View File

@@ -0,0 +1,38 @@
package service
import (
"context"
"math"
"go-common/app/service/main/archive/api"
arcMdl "go-common/app/service/main/archive/model/archive"
"go-common/library/log"
)
func (s *Service) archiveInfos(c context.Context, aids []int64) (archiveInfos map[int64]*api.Arc) {
var (
start, end int
)
archiveInfos = map[int64]*api.Arc{}
if len(aids) <= 0 {
return
}
page := int(math.Ceil(float64(len(aids)) / float64(100)))
for i := 0; i < page; i++ {
start = i * 100
end = (i + 1) * 100
if end > len(aids) {
end = len(aids)
}
arg := &arcMdl.ArgAids2{Aids: aids[start:end]}
infos, err := s.acvSvc.Archives3(c, arg)
if err != nil {
log.Error("s.arcRPC.Archives3(%v) error(%v)", arg, err)
return
}
for _, info := range infos {
archiveInfos[info.Aid] = info
}
}
return
}

View File

@@ -0,0 +1,122 @@
package service
import (
"context"
dm2Mdl "go-common/app/interface/main/dm2/model"
"go-common/app/interface/main/dm2/model/oplog"
arcMdl "go-common/app/service/main/archive/model/archive"
"go-common/app/service/main/assist/model/assist"
"go-common/library/ecode"
"go-common/library/log"
)
// assist
func (s *Service) assist(c context.Context, mid int64, aid int64) (upID int64, isUp bool, err error) {
var ares *assist.AssistRes
arc, err := s.acvSvc.Archive3(c, &arcMdl.ArgAid2{Aid: aid})
if err != nil {
log.Error("s.acvSvc.Archive3(%d) error(%v)", aid, err)
return
}
upID = arc.Author.Mid
isUp = upID == mid
if isUp {
return
}
arg := &assist.ArgAssist{Mid: upID, AssistMid: mid, Type: assist.TypeDm}
if ares, err = s.astSvc.Assist(c, arg); err != nil {
log.Error("s.astSvc.Assist(%v) error(%v)", arg, err)
return
}
if ares.Assist == 0 {
err = ecode.DMAssistNo
return
}
if ares.Allow < 1 {
err = ecode.DMAssistLimit
}
return
}
// AssistBanned up主屏蔽
func (s *Service) AssistBanned(c context.Context, mid, cid int64, dmids []int64) (err error) {
arg := &dm2Mdl.ArgBanUsers{
Mid: mid,
Oid: cid,
DMIDs: dmids,
}
if err = s.dmRPC.BanUsers(c, arg); err != nil {
log.Error("dmRPC.BanUsers(%+v) error(%v)", arg, err)
}
return
}
// AssistUptBanned 更新up主屏蔽
func (s *Service) AssistUptBanned(c context.Context, mid int64, hash string, active int8) (err error) {
arg := &dm2Mdl.ArgEditUpFilters{
Mid: mid,
Type: dm2Mdl.FilterTypeID,
Active: active,
Filters: []string{hash},
}
if _, err = s.dmRPC.EditUpFilters(c, arg); err != nil {
log.Error("dmRPC.EditUpFilters(%+v) error(%v)", arg, err)
}
return
}
// AssistDelBanned2 批量撤销up主屏蔽
func (s *Service) AssistDelBanned2(c context.Context, mid, aid int64, hashes []string) (err error) {
arg := &dm2Mdl.ArgCancelBanUsers{
Mid: mid,
Aid: aid,
Filters: hashes,
}
if err = s.dmRPC.CancelBanUsers(c, arg); err != nil {
log.Error("dmRPC.CancelBanUsers(%+v) error(%v)", arg, err)
}
return
}
// AssistBannedUsers 获取up主屏蔽列表
func (s *Service) AssistBannedUsers(c context.Context, mid, aid int64) (hashes []string, err error) {
upID, _, err := s.assist(c, mid, aid)
if err != nil {
if err == ecode.DMAssistLimit {
err = nil
} else {
log.Error("s.assist(%d,%d) error(%v)", mid, aid, err)
return
}
}
arg := &dm2Mdl.ArgUpFilters{Mid: upID}
res, err := s.dmRPC.UpFilters(c, arg)
if err != nil {
log.Error("dmRPC.UpFilters(%+v) error(%v)", arg, err)
return
}
for _, v := range res {
if v.Type == dm2Mdl.FilterTypeID {
hashes = append(hashes, v.Filter)
}
}
return
}
// AssistDeleteDM assist delete dm.
func (s *Service) AssistDeleteDM(c context.Context, mid, oid int64, dmids []int64) (err error) {
arg := &dm2Mdl.ArgEditDMState{
Type: dm2Mdl.SubTypeVideo,
Oid: oid,
Mid: mid,
State: dm2Mdl.StateDelete, // must be this value
Dmids: dmids,
Source: oplog.SourcePlayer,
OperatorType: oplog.OperatorMember,
}
if err = s.dmRPC.EditDMState(c, arg); err != nil {
log.Error("dmRPC.EditDMState(%v) error(%v)", arg, err)
}
return
}

View File

@@ -0,0 +1,73 @@
package service
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestAssist(t *testing.T) {
var (
upID int64
isUp bool
err error
)
Convey("test assist not up", t, func() {
upID, isUp, err = svr.assist(context.Background(), int64(27515406), int64(10097377))
So(err, ShouldBeNil)
So(upID, ShouldBeGreaterThan, 1)
So(isUp, ShouldBeFalse)
})
Convey("test assist is up", t, func() {
upID, isUp, err = svr.assist(context.Background(), int64(27515256), int64(10097377))
So(err, ShouldBeNil)
So(upID, ShouldBeGreaterThan, 1)
So(isUp, ShouldBeTrue)
})
}
func TestAssistBanned(t *testing.T) {
Convey("test assist banned", t, func() {
err := svr.AssistBanned(context.TODO(), 27515256, 9967830, []int64{719926094, 719926092})
So(err, ShouldBeNil)
})
}
func TestAssistUptBanned(t *testing.T) {
Convey("test assist upt banned", t, func() {
err := svr.AssistUptBanned(context.TODO(), 27515256, "hash1", 0)
So(err, ShouldBeNil)
err = svr.AssistUptBanned(context.TODO(), 27515256, "hash1", 1)
So(err, ShouldBeNil)
})
}
func TestAssistDelBanned2(t *testing.T) {
Convey("test assist banned2", t, func() {
err := svr.AssistDelBanned2(context.TODO(), 27515256, 10097377, []string{"hash1", "hash2"})
So(err, ShouldBeNil)
err = svr.AssistUptBanned(context.TODO(), 27515256, "hash1", 1)
So(err, ShouldBeNil)
err = svr.AssistUptBanned(context.TODO(), 27515256, "hash2", 1)
So(err, ShouldBeNil)
})
}
func TestAssistBannedUsers(t *testing.T) {
Convey("test assist banned users", t, func() {
rs, err := svr.AssistBannedUsers(context.TODO(), 27515256, 10097377)
So(err, ShouldBeNil)
So(rs, ShouldBeGreaterThan, 1)
})
}
func TestAssistDelete(t *testing.T) {
Convey("test assist delete dm", t, func() {
err := svr.AssistDeleteDM(context.TODO(), 27515256, 10108163, []int64{719925514, 719925516})
So(err, ShouldBeNil)
})
}

View File

@@ -0,0 +1,202 @@
package service
import (
"context"
"fmt"
"strconv"
"time"
"go-common/app/interface/main/dm/model"
dm2Mdl "go-common/app/interface/main/dm2/model"
"go-common/app/interface/main/dm2/model/oplog"
account "go-common/app/service/main/account/api"
"go-common/library/ecode"
"go-common/library/log"
)
const (
_recallLt = 5 //普通用户每天可以撤回几个
_recallTO = 120 //多久以前的弹幕可以撤回
_recallCap = 20000 // 字幕君
_recallOK = "撤回成功,你还有%s次撤回机会" // 弹幕撤回成功提示
)
// Recall 撤回弹幕
func (s *Service) Recall(c context.Context, mid, cid int64, id int64) (msg string, err error) {
var (
card *account.CardReply
cnt int
ts string
isSuper bool
)
if card, err = s.accountSvc.Card3(c, &account.MidReq{Mid: mid}); err != nil {
log.Error("s.actSvc.Card3(%d) error(%v)", mid, err)
return
}
ts = "无限"
isSuper = card.GetCard().GetRank() >= _recallCap
if !isSuper {
if cnt, err = s.dao.RecallCnt(c, mid); err != nil {
log.Error("s.dao.RecallCnt(%d) error(%v)", mid, err)
return
}
if cnt >= _recallLt {
err = ecode.DMRecallLimit
return
}
ts = strconv.Itoa(_recallLt - cnt - 1)
}
dm, err := s.dao.Index(c, model.SubTypeVideo, cid, id)
if err != nil {
return
}
if dm == nil || !dm.NeedDisplay() || dm.Mid != mid {
err = ecode.DMRecallDeleted
return
}
if (time.Now().Unix()-int64(dm.Ctime)) > _recallTO && !(isSuper && (dm.Pool == 1 || dm.Pool == 2)) {
err = ecode.DMRecallTimeout
return
}
if err = s.EditDMState(c, 1, cid, mid, dm2Mdl.StateUserDelete, oplog.SourcePlayer, oplog.OperatorMember, id); err != nil {
log.Error("s.EditDMStat(%d,%d) error(%v)", cid, id, err)
err = ecode.DMRecallError
return
}
if err = s.dao.UptRecallCnt(c, mid); err != nil {
log.Error("s.dao.Item(%d,%d) error(%v)", cid, mid, err)
err = nil
}
msg = fmt.Sprintf(_recallOK, ts)
return
}
// EditDMState edit dm state used rpc method in dm2.
func (s *Service) EditDMState(c context.Context, tp int32, oid, mid int64, state int32, source oplog.Source, operatorType oplog.OperatorType, dmids ...int64) (err error) {
arg := &dm2Mdl.ArgEditDMState{
Type: tp,
Oid: oid,
Mid: mid,
State: state,
Dmids: dmids,
Source: source,
OperatorType: operatorType,
}
if err = s.dmRPC.EditDMState(c, arg); err != nil {
log.Error("dmRPC.EditDMState(%v) error(%v)", arg, err)
}
return
}
// MidHash 弹幕发送者mid hash.
func (s *Service) MidHash(c context.Context, mid int64) (hash string, err error) {
hash = model.Hash(mid, 0)
return
}
// TransferJob set task to db
func (s *Service) TransferJob(c context.Context, mid, fromCid, toCid int64, offset float64) (err error) {
job, err := s.dao.CheckTransferJob(c, fromCid, toCid)
if err != nil {
log.Error("dao.CheckTransferJob(from:%d,to:%d) err(%v)", fromCid, toCid, err)
return
}
if job != nil && job.FromCID == fromCid && job.ToCID == toCid && job.State != model.TransferJobStatFailed {
err = ecode.DMTransferRepet
return
}
_, err = s.dao.AddTransferJob(c, fromCid, toCid, mid, offset, model.TransferJobStatInit)
if err != nil {
log.Error("dao.AddTransferJob(from:%d,to:%d) err(%v)", fromCid, toCid, err)
}
return
}
// TransferList service
func (s *Service) TransferList(c context.Context, cid int64) (hiss []*model.TransferHistory, err error) {
hiss, err = s.dao.TransferList(c, cid)
if err != nil || len(hiss) == 0 {
return
}
for _, his := range hiss {
cidInfo, err := s.dao.CidInfo(c, his.CID)
if err != nil {
log.Error("dao.CidInfo(%d) err(%v)", cid, err)
continue
}
his.Title = cidInfo.Title
his.PartID = int32(cidInfo.Index)
}
return
}
// TransferRetry change transferjob state
func (s *Service) TransferRetry(c context.Context, id, mid int64) (err error) {
job, err := s.dao.CheckTransferID(c, id)
if err != nil {
log.Error("dao.CheckTransferID(%d) err(%v)", id, err)
return
}
if job.State != model.TransferJobStatFailed || job.MID != mid {
err = ecode.RequestErr
return
}
_, err = s.dao.SetTransferState(c, id, model.TransferJobStatInit)
if err != nil {
log.Error("dao.TransferList(%d %d %d) err(%v)", id, err)
}
return
}
// CheckExist check exit of up id.
func (s *Service) CheckExist(c context.Context, mid, cid int64) (err error) {
sub, err := s.subject(c, 1, cid)
if err != nil {
if ecode.Cause(err) == ecode.NothingFound {
err = ecode.DMTransferNotFound
}
return
}
if sub.Mid == 0 {
err = ecode.DMTransferNotFound
return
}
if sub.Mid != mid {
err = ecode.DMTransferNotBelong
return
}
return
}
// dms get dm list by dmid from database
func (s *Service) dms(c context.Context, tp int32, oid int64, ids []int64) (dms []*model.DM, err error) {
var (
idxMap = make(map[int64]*model.DM)
contentSpe = make(map[int64]*model.ContentSpecial)
special []int64
contents []*model.Content
)
if idxMap, special, err = s.dao.IndexsByID(c, tp, oid, ids); err != nil || len(idxMap) == 0 {
return
}
if contents, err = s.dao.Contents(c, oid, ids); err != nil {
return
}
if len(special) > 0 {
if contentSpe, err = s.dao.ContentsSpecial(c, special); err != nil {
return
}
}
for _, content := range contents {
if dm, ok := idxMap[content.ID]; ok {
dm.Content = content
if dm.Pool == model.PoolSpecial {
if _, ok = contentSpe[dm.ID]; ok {
dm.ContentSpe = contentSpe[dm.ID]
}
}
dms = append(dms, dm)
}
}
return
}

View File

@@ -0,0 +1,61 @@
package service
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestDMS(t *testing.T) {
Convey("test dm list by dmids", t, func() {
rs, err := svr.dms(context.TODO(), 1, 10108013, []int64{719925639, 719925638})
So(err, ShouldBeNil)
So(rs, ShouldNotBeEmpty)
for _, r := range rs {
t.Logf("%+v", r)
t.Logf("%+v", r.Content)
}
})
}
func TestMidHash(t *testing.T) {
Convey("test mid hash", t, func() {
hash, err := svr.MidHash(context.TODO(), 27515256)
So(err, ShouldBeNil)
So(hash, ShouldNotBeBlank, hash)
})
}
func TestTransferJob(t *testing.T) {
Convey("test TransferJob", t, func() {
err := svr.TransferJob(context.TODO(), 27515615, 10108765, 10108763, 1.00)
So(err, ShouldBeNil)
})
}
func TestTransferList(t *testing.T) {
var (
cid int64 = 10109082
)
Convey("test transfer list", t, func() {
l, err := svr.TransferList(c, cid)
So(err, ShouldBeNil)
So(l, ShouldNotBeEmpty)
})
}
func TestTransferRetry(t *testing.T) {
var (
id, mid int64 = 265, 1
)
Convey("test transfer retry", t, func() {
err := svr.TransferRetry(c, id, mid)
So(err, ShouldBeNil)
})
Convey("test transfer retry fail", t, func() {
err := svr.TransferRetry(c, id, mid)
So(err, ShouldNotBeNil)
})
}

View File

@@ -0,0 +1,162 @@
package service
import (
"context"
"encoding/json"
"math"
"sync/atomic"
"time"
"go-common/app/interface/main/dm/model"
dm2Mdl "go-common/app/interface/main/dm2/model"
"go-common/library/log"
"github.com/zhenjl/cityhash"
)
var (
_defaultVersion = uint64(0)
globalRuleVersion = uint64(time.Now().Nanosecond())
)
// AddUserRule add user rule
func (s *Service) AddUserRule(c context.Context, fType int8, mid int64, filters []string, comment string) (res []*dm2Mdl.UserFilter, err error) {
arg := &dm2Mdl.ArgAddUserFilters{
Type: fType,
Mid: mid,
Filters: filters,
Comment: comment,
}
if res, err = s.dmRPC.AddUserFilters(c, arg); err != nil {
log.Error("dmRPC.AddUserFilters(%+v) error(%v)", arg, err)
}
return
}
// UserRules return user rules
func (s *Service) UserRules(c context.Context, mid int64) (res []*dm2Mdl.UserFilter, err error) {
arg := &dm2Mdl.ArgMid{Mid: mid}
if res, err = s.dmRPC.UserFilters(c, arg); err != nil {
log.Error("dmRPC.UserFilters(%+v) error(%v)", arg, err)
}
return
}
// DelUserRules delete user rules
func (s *Service) DelUserRules(c context.Context, mid int64, idss []int64) (affect int64, err error) {
arg := &dm2Mdl.ArgDelUserFilters{Mid: mid, IDs: idss}
if affect, err = s.dmRPC.DelUserFilters(c, arg); err != nil {
log.Error("dmRPC.DelUserFilters(%+v) error(%v)", arg, err)
}
return
}
// GlobalRuleVersion return global rule version
func (s *Service) GlobalRuleVersion() uint64 {
return globalRuleVersion
}
// AddGlobalRule add global rule
func (s *Service) AddGlobalRule(c context.Context, fType int8, filter string) (res *dm2Mdl.GlobalFilter, err error) {
arg := &dm2Mdl.ArgAddGlobalFilter{Type: fType, Filter: filter}
if res, err = s.dmRPC.AddGlobalFilter(c, arg); err != nil {
log.Error("dmRPC.AddGlobalFilter(%+v) error(%v)", arg, err)
return
}
atomic.StoreUint64(&globalRuleVersion, _defaultVersion)
return
}
// GlobalRules return global rules
func (s *Service) GlobalRules(c context.Context) (res []*dm2Mdl.GlobalFilter, err error) {
arg := &dm2Mdl.ArgGlobalFilters{}
if res, err = s.dmRPC.GlobalFilters(c, arg); err != nil {
log.Error("dmRPC.GlobalFilters(%+v) error(%v)", arg, err)
return
}
if len(res) == 0 {
atomic.StoreUint64(&globalRuleVersion, _defaultVersion)
} else {
var buf []byte
if buf, err = json.Marshal(res); err != nil {
log.Error("json.Marshal() error(%v)", err)
return
}
atomic.StoreUint64(&globalRuleVersion, cityhash.CityHash64(buf, 16)%math.MaxInt64)
}
return
}
// DelGlobalRules delete global rules
func (s *Service) DelGlobalRules(c context.Context, ids []int64) (affect int64, err error) {
arg := &dm2Mdl.ArgDelGlobalFilters{IDs: ids}
if affect, err = s.dmRPC.DelGlobalFilters(c, arg); err != nil {
log.Error("dmRPC.DelGlobalFilters(%+v) error(%v)", arg, err)
return
}
// update global rule version
atomic.StoreUint64(&globalRuleVersion, _defaultVersion)
return
}
// FilterList get user filter list
func (s *Service) FilterList(c context.Context, mid, cid int64) (l *model.UserFilterList, err error) {
l = new(model.UserFilterList)
arg := &dm2Mdl.ArgUpFilters{Mid: mid}
res, err := s.dmRPC.UpFilters(c, arg)
if err != nil {
log.Error("dmRPC.UpFilters(%v) error(%v)", arg, err)
return
}
if len(res) == 0 {
return
}
for _, f := range res {
switch f.Type {
case dm2Mdl.FilterTypeBottom:
l.Bottom = f.Active
continue
case dm2Mdl.FilterTypeTop:
l.Top = f.Active
continue
case dm2Mdl.FilterTypeRev:
l.Reverse = f.Active
continue
}
filter := &model.IndexFilter{
ID: f.ID,
MID: f.Mid,
Filter: f.Filter,
Activate: f.Active,
Regex: f.Type,
Ctime: int64(f.Ctime),
}
l.Filter = append(l.Filter, filter)
}
return
}
// EditFilter edit up filter from creative center.
func (s *Service) EditFilter(c context.Context, cid, mid int64, filter string, fType, state int8) (err error) {
if state == dm2Mdl.FilterActive {
arg := &dm2Mdl.ArgAddUpFilters{
Mid: mid,
Type: fType,
Filters: []string{filter},
}
if err = s.dmRPC.AddUpFilters(c, arg); err != nil {
log.Error("dmRPC.AddUpFilters(%v) error(%v)", arg, err)
}
} else {
arg := &dm2Mdl.ArgEditUpFilters{
Type: fType,
Mid: mid,
Active: dm2Mdl.FilterUnActive,
Filters: []string{filter},
}
if _, err = s.dmRPC.EditUpFilters(c, arg); err != nil {
log.Error("dmRPC.EditUpFilters(%v) error(%v)", arg, err)
}
}
return
}

View File

@@ -0,0 +1,83 @@
package service
import (
"context"
"testing"
"go-common/library/ecode"
. "github.com/smartystreets/goconvey/convey"
)
// )
func TestAddUserRule(t *testing.T) {
Convey("test add user rule", t, func() {
_, err := svr.AddUserRule(context.TODO(), 1, 150781, []string{"aa", "bb"}, "comment")
So(err, ShouldBeNil)
})
}
func TestUserRules(t *testing.T) {
Convey("test get user rule", t, func() {
rs, err := svr.UserRules(context.TODO(), 27515256)
So(err, ShouldBeNil)
So(rs, ShouldNotBeEmpty)
})
}
func TestDelUserRules(t *testing.T) {
Convey("test del user rule", t, func() {
_, err := svr.DelUserRules(context.TODO(), 27515256, []int64{12, 3, 4})
So(err, ShouldBeNil)
})
}
func TestAddGlobalRule(t *testing.T) {
Convey("test add global rule", t, func() {
_, err := svr.AddGlobalRule(context.TODO(), 1, "aa")
So(err, ShouldBeNil)
})
}
func TestGlobalRules(t *testing.T) {
Convey("test global rule", t, func() {
rs, err := svr.GlobalRules(context.TODO())
So(err, ShouldBeNil)
So(rs, ShouldNotBeEmpty)
})
}
func TestDelGlobalRules(t *testing.T) {
Convey("test del global rule", t, func() {
_, err := svr.DelGlobalRules(context.TODO(), []int64{12, 3, 4})
So(err, ShouldBeNil)
})
}
func TestServiceFilterList(t *testing.T) {
var (
c = context.TODO()
cid, mid int64 = 0, 150781
)
Convey("test filter list", t, func() {
f, err := svr.FilterList(c, mid, cid)
So(err, ShouldBeNil)
So(f, ShouldNotBeNil)
})
}
func TestEditFilter(t *testing.T) {
Convey("test insert regex filter", t, func() {
err := svr.EditFilter(c, 0, 150781, ".*", 1, 1)
So(err, ShouldBeNil)
})
Convey("test insert wrong regex filter", t, func() {
err := svr.EditFilter(c, 0, 150781, ".[*", 1, 1)
So(err, ShouldEqual, ecode.DMFitlerIllegalRegex)
})
Convey("test update filter", t, func() {
err := svr.EditFilter(c, 0, 150781, ".*", 1, 1)
So(err, ShouldBeNil)
})
}

View File

@@ -0,0 +1,363 @@
package service
import (
"context"
"fmt"
"time"
"go-common/app/interface/main/dm/model"
dm2Mdl "go-common/app/interface/main/dm2/model"
"go-common/app/interface/main/dm2/model/oplog"
account "go-common/app/service/main/account/api"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/xstr"
)
const (
_notifyUpTitle = "有新的弹幕保护申请"
_notifyUpContent = `您今天新增了一些未处理弹幕保护申请,前去 #{创作中心 - 哔哩哔哩弹幕视频网 - ( ゜- ゜)つロ 乾杯~}{"http://member.bilibili.com/v/#/danmu/report/save"} 处理吧`
_notifyUsrTitle = "弹幕保护申请情况更新~"
_pa48 = "由于up主日理万机您之前申请的%d条弹幕暂未受理请稍后再次申请"
_paa = `您在视频 #{%s}{"http://www.bilibili.com/video/av%d/"} 已被全部保护`
_pap = `您在视频 #{%s}{"http://www.bilibili.com/video/av%d/"} 已被部分保护`
_protectApplyLevel = 4
_maxProtectApply = 100
_paExpire = 48 * 3600
)
// AddProtectApply 批量申请保护弹幕
func (s *Service) AddProtectApply(c context.Context, uid, cid int64, dmids []int64) (err error) {
if len(dmids) == 0 {
err = ecode.DMNotFound
return
}
count, err := s.dao.PaUsrCnt(c, uid)
if err != nil {
log.Error("s.dao.PaUsrCnt(%d) error(%v)", uid, err)
return
}
if (count + len(dmids)) > _maxProtectApply {
err = ecode.DMPAUserLimit
return
}
cardReply, err := s.accountSvc.Card3(c, &account.MidReq{Mid: uid})
if err != nil {
log.Error("s.actSvc.Card3(%d) error(%v)", uid, err)
return
}
if cardReply.GetCard().GetLevel() < _protectApplyLevel {
err = ecode.DMPAUserLevel
return
}
dms, err := s.dms(c, model.SubTypeVideo, cid, dmids)
if err != nil {
return
}
dc := len(dmids)
if len(dms) < 1 && dc == 1 {
err = ecode.DMNotFound
return
}
sub, err := s.subject(c, 1, cid)
if err != nil {
return
}
aps := make([]*model.Pa, 0, len(dms))
now := time.Now().Unix()
var ctime time.Time
for _, dm := range dms {
if dm.Mid != uid && dc == 1 {
err = ecode.DMPADMNotOwner
return
}
if dm.AttrVal(model.AttrProtect) == model.AttrYes && dc == 1 {
err = ecode.DMPADMProtected
return
}
if !dm.NeedDisplay() && dc == 1 {
err = ecode.DMNotFound
return
}
ctime, err = s.dao.ProtectApplyTime(c, dm.ID)
if err != nil {
log.Error("dao.ProtectApplyTime(%d) error(%v)", uid, err)
continue
}
if now-ctime.Unix() < _paExpire {
if dc == 1 {
err = ecode.DMPADMLimit
return
}
continue
}
ap := &model.Pa{
CID: cid,
UID: sub.Mid,
ApplyUID: dm.Mid,
AID: sub.Pid,
Playtime: float32(dm.Progress) / 1000,
DMID: dm.ID,
Msg: dm.Content.Msg,
Status: -1,
Ctime: time.Now(),
Mtime: time.Now(),
}
aps = append(aps, ap)
}
if len(aps) < 1 {
err = ecode.DMPAFailed
return
}
affect, err := s.dao.AddProtectApply(c, aps)
if err != nil {
log.Error("dao.AddProtectApply(%v) error(%v)", aps, err)
return
}
if err = s.dao.UptUsrPaCnt(c, uid, affect); err != nil {
log.Error("s.dao.UptUsrPaCnt(%d,%d) error(%v)", uid, affect, err)
}
return
}
// UptPaSwitch 保护弹幕申请开关
func (s *Service) UptPaSwitch(c context.Context, uid int64, status int) (err error) {
if status != 1 {
status = 0
}
_, err = s.dao.UptPaNoticeSwitch(c, uid, status)
return
}
// UptPaStatus 审核保护弹幕申请
func (s *Service) UptPaStatus(c context.Context, mid int64, ids []int64, status int) (err error) {
dmids, err := s.dao.ProtectApplyByIDs(c, mid, xstr.JoinInts(ids))
if err != nil {
log.Error("s.dao.ProtectApplyByIDs(%d,%s) error(%v)", mid, xstr.JoinInts(ids), err)
return
}
if status != 1 {
status = 0
}
if _, err = s.dao.UptPaStatus(c, mid, xstr.JoinInts(ids), status); err != nil {
log.Error("s.dao.UptPaStatus(%d,%v,%d) error(%v)", mid, ids, status, err)
return
}
if status == 0 {
return
}
for oid, ids := range dmids {
arg := &dm2Mdl.ArgEditDMAttr{
Type: 1,
Oid: oid,
Mid: mid,
Bit: dm2Mdl.AttrProtect,
Value: dm2Mdl.AttrYes,
Dmids: ids,
Source: oplog.SourceUp,
OperatorType: oplog.OperatorUp,
}
if err = s.dmRPC.EditDMAttr(c, arg); err != nil {
log.Error("s.dmRPC.EditDMAttr(%+v) error(%v)", arg, err)
return
}
}
return
}
// ProtectApplies 保护弹幕申请列表
func (s *Service) ProtectApplies(c context.Context, uid, aid int64, page int, sort string) (res *model.ApplyListResult, err error) {
var (
count int
start int
)
if page < 1 {
page = 1
}
res = &model.ApplyListResult{
Pager: &model.Pager{},
List: make([]*model.Apply, 0, model.ProtectApplyLimit),
}
res.List, err = s.dao.ProtectApplies(c, uid, aid, sort)
if err != nil {
log.Error("s.dao.PaLs(%d) error(%v)", uid, err)
return
}
count = len(res.List)
res.Pager.Current = page
res.Pager.Total = count / model.ProtectApplyLimit
res.Pager.Size = model.ProtectApplyLimit
res.Pager.TotalCount = count
if count%model.ProtectApplyLimit != 0 {
res.Pager.Total++
}
if count == 0 {
res.List = make([]*model.Apply, 0, 1)
return
}
start = (page - 1) * model.ProtectApplyLimit
if start > count {
start = 0
}
end := start + model.ProtectApplyLimit
if end > count {
end = count
}
res.List = res.List[start:end]
aids := make([]int64, 0, len(res.List))
uids := make([]int64, 0, len(res.List))
for _, a := range res.List {
aids = append(aids, a.AID)
uids = append(uids, a.ApplyUID)
}
infosReply, err := s.accountSvc.Infos3(c, &account.MidsReq{
Mids: uids,
})
if err != nil {
log.Error("s.actSvc.Infos2(%v) error(%v)", uids, err)
err = nil
}
archives := s.archiveInfos(c, aids)
for _, a := range res.List {
v, ok := archives[a.AID]
if ok {
a.Pic = v.Pic
a.Title = v.Title
}
u, ok := infosReply.GetInfos()[a.ApplyUID]
if ok {
a.Uname = u.GetName()
}
}
return
}
// PaVideoLs 被申请保护弹幕的视频列表
func (s *Service) PaVideoLs(c context.Context, uid int64) (res []*model.Video, err error) {
aids, err := s.dao.ProtectAids(c, uid)
if err != nil {
log.Error("s.dao.ProtectArchives(%d) error(%v)", uid, err)
return
}
archives := s.archiveInfos(c, aids)
res = make([]*model.Video, 0, len(aids))
for _, aid := range aids {
a := new(model.Video)
v, ok := archives[aid]
a.Aid = aid
if ok {
a.Title = v.Title
} else {
a.Title = ""
}
res = append(res, a)
}
return
}
// sendProtectNotifyToUp 发送申请保护弹幕通知给up主
func (s *Service) sendProtectNotifyToUp(c context.Context) (err error) {
if time.Now().Format("15") != "20" {
return
}
lk, err := s.dao.PaLock(c, "up")
if err != nil {
log.Error("s.dao.PaLock() error(%v)", err)
return
}
if lk != 1 {
return
}
uids, err := s.dao.ProtectApplyStatistics(c)
if err != nil {
log.Error("s.dao.PaStat() error(%v)", err)
return
}
if len(uids) < 1 {
return
}
m, err := s.dao.PaNoticeClose(c, uids)
if err != nil {
log.Error("s.dao.PaNoticeClose(%v) error(%v)", uids, err)
return
}
if len(m) > 0 {
for k, v := range uids {
if _, ok := m[v]; ok {
uids = append(uids[:k], uids[k+1:]...)
}
}
}
s.dao.SendNotify(c, _notifyUpTitle, _notifyUpContent, uids)
return
}
// sendProtectNotifyToUser 发送申请保护弹幕处理结果给申请用户
func (s *Service) sendProtectNotifyToUser(c context.Context) {
if time.Now().Format("15") != "22" {
return
}
incr, err := s.dao.PaLock(c, "user")
if err != nil {
log.Error("s.dao.PaLock() error(%v)", err)
return
}
if incr != 1 {
return
}
stats, err := s.dao.PaUsrStat(c)
if err != nil {
log.Error("s.dao.PaStat() error(%v)", err)
return
}
aids := make([]int64, 0, len(stats))
for _, stat := range stats {
aids = append(aids, stat.Aid)
}
archives := s.archiveInfos(c, aids)
userStats := make(map[int64]map[int64]*model.ApplyUserNotify)
now := time.Now().Unix()
untreated := make(map[int64]int)
for _, stat := range stats {
m, ok := userStats[stat.Aid]
if !ok {
m = make(map[int64]*model.ApplyUserNotify)
userStats[stat.Aid] = m
}
n, ok := m[stat.UID]
if !ok {
n = &model.ApplyUserNotify{}
m[stat.UID] = n
}
if stat.Status == 1 {
n.Protect++
} else {
n.Unprotect++
if stat.Status == -1 && (now-stat.Ctime.Unix()) > 2*24*3600 {
untreated[stat.UID]++
}
}
}
for k, v := range untreated {
s.dao.SendNotify(c, _notifyUsrTitle, fmt.Sprintf(_pa48, v), []int64{k})
}
for aid, m := range userStats {
archive, ok := archives[aid]
if !ok {
continue
}
for uid, stat := range m {
var content string
if stat.Protect > 0 && stat.Unprotect == 0 {
content = fmt.Sprintf(_paa, archive.Title, archive.Aid)
}
if stat.Protect > 0 && stat.Unprotect > 0 {
content = fmt.Sprintf(_pap, archive.Title, archive.Aid)
}
if content == "" {
continue
}
s.dao.SendNotify(c, _notifyUsrTitle, content, []int64{uid})
}
}
}

View File

@@ -0,0 +1,48 @@
package service
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestAddProtectApply(t *testing.T) {
Convey("test add protect apply", t, func() {
err := svr.AddProtectApply(context.TODO(), 27515256, 10108163, []int64{719925843, 719925844})
So(err, ShouldBeNil)
})
}
func TestUptPaSwitch(t *testing.T) {
Convey("test upt pa switch", t, func() {
err := svr.UptPaSwitch(context.TODO(), 27515256, 1)
So(err, ShouldBeNil)
err = svr.UptPaSwitch(context.TODO(), 27515256, 0)
So(err, ShouldBeNil)
})
}
func TestUptPaStatus(t *testing.T) {
Convey("test upt pa status", t, func() {
err := svr.UptPaStatus(context.TODO(), 27515256, []int64{541, 542}, 1)
So(err, ShouldBeNil)
err = svr.UptPaStatus(context.TODO(), 27515256, []int64{541, 542}, -1)
So(err, ShouldBeNil)
})
}
func TestProtectApplies(t *testing.T) {
Convey("test protect applies", t, func() {
res, err := svr.ProtectApplies(context.TODO(), 27515256, 10097377, 1, "playtime")
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
})
}
func TestPaVideoLs(t *testing.T) {
Convey("test pa video ls", t, func() {
_, err := svr.PaVideoLs(context.TODO(), 27515256)
So(err, ShouldBeNil)
})
}

View File

@@ -0,0 +1,412 @@
package service
import (
"context"
"fmt"
"time"
"go-common/app/interface/main/dm/model"
"go-common/app/interface/main/dm2/model/oplog"
arcMdl "go-common/app/service/main/archive/model/archive"
"go-common/library/ecode"
"go-common/library/log"
)
const (
_reportLock = 1800
_reportLimit = 10
_rptAutoDelCnt = 3
)
// AddReport add dm report.
func (s *Service) AddReport(c context.Context, cid, dmid, uid int64, reason int8, content string) (id int64, err error) {
var (
needDelete, needHide bool
state int8
score int32
)
t, err := s.dao.RptBrigTime(c, uid)
if err != nil {
return
}
if time.Now().Unix()-t < _reportLock {
err = ecode.DMReportLimit
return
}
cnt, err := s.dao.RptCnt(c, uid)
if err != nil {
return
}
if cnt >= _reportLimit {
if err = s.dao.AddRptBrig(c, uid); err != nil {
log.Error("s.dao.AddRptBrig(%d) error(%v)", uid, err)
}
err = ecode.DMReportLimit
return
}
dms, err := s.dms(c, model.SubTypeVideo, cid, []int64{dmid})
if err != nil {
return
}
if len(dms) == 0 || !dms[0].NeedDisplay() {
err = ecode.DMReportNotExist
return
}
if _, err = s.dao.UptRptCnt(c, uid); err != nil {
log.Error("s.dao.UptRptCnt(%d) error(%v)", uid, err)
err = nil
}
rpt, err := s.dao.Report(c, cid, dmid)
if err != nil {
log.Error("s.dao.Report(cid:%d,dmid:%d) error(%v)", cid, dmid, err)
return
}
// score
if score, err = s.dao.FigureInfo(c, uid); err != nil {
log.Error("s.dao.FigureInfo(uid: %d) error(%v)", uid, err)
return
}
if score < 0 || score > 100 {
log.Error("s.AddReport.score illegal(uid: %d) score(%v)", uid, score)
score = 0
} else {
score = 100 - score
}
if rpt != nil {
state, err = s.checkReasonType(c, reason, cid, dmid, rpt)
if err != nil {
log.Error("s.checkReasonType(reason: %d) error(%v)", reason, err)
return
}
/*
以下弹幕不能自动删除与隐藏
1. mode7、mode8、mode9弹幕
2. 字幕弹幕
3. 保护弹幕
4. up主在自己的视频下发送的弹幕
*/
if state == model.StatSecondInit &&
dms[0].Content.Mode != 7 &&
dms[0].Content.Mode != 8 &&
dms[0].Content.Mode != 9 &&
dms[0].AttrVal(model.AttrProtect) != model.AttrYes &&
dms[0].Pool == 0 &&
!s.isUpper(c, cid, dms[0].Mid) {
if (reason == model.ReportReasonAd && rpt.Reason == model.ReportReasonAd) || rpt.Count >= _rptAutoDelCnt-1 || rpt.Score+score >= 160 {
needDelete = true
} else {
needHide = true
}
}
} else {
state = s.reasonType(reason)
if state == model.StatSecondInit &&
dms[0].Content.Mode != 7 &&
dms[0].Content.Mode != 8 &&
dms[0].Content.Mode != 9 &&
dms[0].AttrVal(model.AttrProtect) != model.AttrYes &&
dms[0].Pool == 0 &&
!s.isUpper(c, cid, dms[0].Mid) {
needHide = true
}
}
nowTime := time.Now()
r := &model.Report{
Cid: cid,
Did: dmid,
UID: uid,
Reason: reason,
Content: content,
Count: 1,
State: state,
UpOP: model.StatUpperInit,
Score: score,
RpTime: nowTime,
Ctime: nowTime,
Mtime: nowTime,
}
u := &model.User{
Did: dmid,
UID: uid,
State: model.NoticeUnsend,
Reason: reason,
Content: content,
Ctime: nowTime,
Mtime: nowTime,
}
lastID, err := s.dao.AddReportUser(c, u)
if err != nil {
log.Error("s.dao.AddReportUser(%v) error(%v)", u, err)
return
}
if lastID < 1 {
err = ecode.DMReportExist
return
}
if id, err = s.dao.AddReport(c, r); err != nil {
log.Error("s.dao.AddReport(%v) error(%v)", r, err)
return
}
if needDelete {
select {
case s.delDMReportChan <- rpt:
default:
log.Error("s.delDMReportChan.full(%v)", rpt)
}
}
if needHide && !needDelete {
select {
case s.hideDMReportChan <- r:
default:
log.Error("s.hideDMReportChan.full(%v)", r)
}
}
return
}
// EditReport edit report dm.
func (s *Service) EditReport(c context.Context, tp int32, cid, mid, dmid int64, op int8) (affect int64, err error) {
r, err := s.dao.Report(c, cid, dmid)
if err != nil {
log.Error("s.dao.Report(cid:%d, dmid:%d), error(%v)", cid, dmid, err)
return
}
if r == nil {
err = ecode.DMReportNotExist
return
}
if !s.isUpper(c, cid, mid) {
err = ecode.ArchiveOwnerErr
return
}
if affect, err = s.dao.UpdateReportUPOp(c, cid, dmid, op); err != nil {
log.Error("s.dao.UpdateReportUPOp(cid:%d, dmid:%d, op:%d) error(%v)", cid, dmid, op, err)
}
if op == model.StatUpperDelete {
if err = s.EditDMState(c, tp, cid, mid, model.StateDelete, oplog.SourceUp, oplog.OperatorUp, dmid); err != nil {
log.Error("s.EditDMStat(cid:%d,dmid:%d) error(%v)", cid, dmid, err)
return
}
}
v := &model.UptSearchReport{
DMid: dmid,
Upop: op,
Ctime: r.Ctime.Format("2006-01-02 15:04:05"),
Mtime: time.Now().Format("2006-01-02 15:04:05"),
}
err = s.dao.UpdateSearchReport(c, []*model.UptSearchReport{v})
return
}
// ReportList 获取一个用户的所有被举报的弹幕
func (s *Service) ReportList(c context.Context, mid, aid, page, size int64, upOp int8, states []int64) (res *model.RptSearchs, err error) {
res = &model.RptSearchs{}
var (
aidsMap = make(map[int64]struct{})
aids = []int64{}
cidDMids = make(map[int64][]int64)
stateMap = make(map[int64]int64)
)
rptSearch, err := s.dao.SearchReport(c, mid, aid, page, size, upOp, states)
if err != nil || rptSearch == nil {
return
}
for _, v := range rptSearch.Result {
if _, ok := aidsMap[v.Aid]; !ok {
aidsMap[v.Aid] = struct{}{}
aids = append(aids, v.Aid)
}
cidDMids[v.Cid] = append(cidDMids[v.Cid], v.Did)
}
archives := s.archiveInfos(c, aids)
if stateMap, err = s.dmState(c, cidDMids); err != nil {
return
}
for _, v := range rptSearch.Result {
if arc, ok := archives[v.Aid]; ok {
v.Title = arc.Title
v.Cover = arc.Pic
}
if state, ok := stateMap[v.Did]; ok {
v.Deleted = state
}
}
res = &model.RptSearchs{
Page: rptSearch.Page.Num,
PageSize: rptSearch.Page.Size,
PageCount: (rptSearch.Page.Total-1)/rptSearch.Page.Size + 1,
Total: rptSearch.Page.Total,
Result: rptSearch.Result,
}
return
}
func (s *Service) isUpper(c context.Context, cid, mid int64) bool {
sub, err := s.subject(c, 1, cid)
if err != nil {
return false
}
return sub.Mid == mid
}
// checkReasonType get state by report reason
func (s *Service) checkReasonType(c context.Context, reason int8, cid, dmid int64, rpt *model.Report) (state int8, err error) {
reportLog, err := s.dao.ReportLog(c, dmid)
if err != nil {
log.Error("s.dao.ReportLog(dmid:%d) error(%v)", dmid, err)
return
}
if len(reportLog) > 0 { // 如果这个举报已经在后台被处理了,那就根据举报当前的状态返回对应的一二审状态
if rpt.State == model.StatFirstInit ||
rpt.State == model.StatFirstDelete ||
rpt.State == model.StatFirstIgnore {
state = model.StatFirstInit
} else {
state = model.StatSecondInit
}
} else { // 否则就根据举报理由来返回状态
state = s.reasonType(reason)
}
return
}
// ReportArchives 获取一个用户的所有被举报的稿件
func (s *Service) ReportArchives(c context.Context, mid int64, upOp int8, states []int8, pn, ps int64) (res *model.Archives, err error) {
res = &model.Archives{}
aids, err := s.dao.SearchReportAid(c, mid, upOp, states, pn, ps)
if err != nil || len(aids) == 0 {
return
}
archiveInfos := s.archiveInfos(c, aids)
for aid, info := range archiveInfos {
res.Result = append(res.Result, &struct {
Aid int64 `json:"aid"`
Title string `json:"title"`
}{Aid: aid, Title: info.Title})
}
return
}
func (s *Service) reasonType(reason int8) (state int8) {
if reason == model.ReportReasonProhibited ||
reason == model.ReportReasonPorn ||
reason == model.ReportReasonFraud ||
reason == model.ReportReasonAttack ||
reason == model.ReportReasonPrivate ||
reason == model.ReportReasonTeenagers {
state = model.StatFirstInit
} else {
state = model.StatSecondInit
}
return
}
// deleteDMReport delete dm report.
func (s *Service) deleteDMReport(c context.Context, rpt *model.Report) (err error) {
sub, err := s.subject(c, 1, rpt.Cid)
if err != nil {
return
}
rpt.State = model.StatSecondAutoDelete
if err = s.EditDMState(c, 1, rpt.Cid, sub.Mid, model.StateScriptDelete, oplog.SourceUp, oplog.OperatorUp, rpt.Did); err != nil {
log.Error("s.EditDMStat(cid:%d, state:%d, dmid:%d ) error(%v)", rpt.Cid, rpt.State, rpt.Did, err)
return
}
if _, err = s.dao.UpdateReportStat(c, rpt.Cid, rpt.Did, rpt.State); err != nil {
log.Error("s.dao.UpdateReportStat(cid:%d, state:%d, dmid:%d ) error(%v)", rpt.Cid, rpt.State, rpt.Did, err)
return
}
lg := &model.RptLog{
Did: rpt.Did,
AdminID: 0,
Reason: rpt.Reason,
Result: rpt.State,
Remark: "自动删除",
Elapsed: int64(time.Since(rpt.Mtime).Seconds()),
Ctime: time.Now(),
Mtime: time.Now(),
}
if err = s.dao.AddReportLog(c, lg); err != nil {
log.Error("s.dao.AddReportLog(log:%v) error(%v)", lg, err)
return
}
users, err := s.dao.ReportUser(c, rpt.Did)
if err != nil {
log.Error("s.dao.ReportUser(dmid:%d) error(%v)", rpt.Did, err)
return
}
if err = s.dao.SetReportUserFinished(c, rpt.Did); err != nil {
log.Error("s.dao.SetReportUserFinished(dmid:%d) error(%v)", rpt.Did, err)
return
}
ct, err := s.dao.Content(c, rpt.Cid, rpt.Did)
if err != nil || ct == nil {
return
}
arc, err := s.acvSvc.Archive3(c, &arcMdl.ArgAid2{Aid: sub.Pid})
if err != nil {
log.Error("s.acvSvc.Archive3(%d) error(%v)", sub.Pid, err)
return
}
for _, u := range users {
content := fmt.Sprintf(model.RptMsgTemplate, arc.Title, arc.Aid, ct.Msg, model.ReportReason[rpt.Reason])
s.dao.SendNotify(c, model.RptMsgTitle, content, []int64{u.UID})
}
return
}
//hideDMReport hide reported dm
func (s *Service) hideDMReport(c context.Context, rpt *model.Report) (err error) {
dmids := []int64{rpt.Did}
//change dm state to hide
_, err = s.dao.UpdateDMStat(c, 1, rpt.Cid, model.StateHide, dmids)
if err != nil {
log.Error("s.dao.UpdateDMStat(oid:%d state:%d dmids:%v) error(%v)", rpt.Cid, model.StateHide, rpt.Did, err)
return
}
// send hideTime to databus
time := time.Now().Unix() + 72000
act := &model.ReportAction{
Cid: rpt.Cid,
Did: rpt.Did,
HideTime: time,
}
// make sure all the hided dms are in one partition
if err = s.dao.SendAction(context.TODO(), "1", act); err != nil {
log.Error("databus.Send(%+v) error(%v)", act, err)
}
return
}
func (s *Service) dmReportProc() {
for {
select {
case rpt := <-s.delDMReportChan:
if err := s.deleteDMReport(context.TODO(), rpt); err != nil {
log.Error("s.deleteDMReport(rpt:%v) error(%v)", rpt, err)
}
case rpt := <-s.hideDMReportChan:
if err := s.hideDMReport(context.TODO(), rpt); err != nil {
log.Error("s.hideDMReport(rpt:%v) error(%v)", rpt, err)
}
}
}
}
func (s *Service) dmState(c context.Context, cidDmids map[int64][]int64) (stateMap map[int64]int64, err error) {
var (
idxMap map[int64]*model.DM
tp = int32(1)
)
stateMap = make(map[int64]int64)
for oid, dmids := range cidDmids {
if idxMap, _, err = s.dao.IndexsByID(c, tp, oid, dmids); err != nil {
return
}
for dmid, dm := range idxMap {
stateMap[dmid] = int64(dm.State)
}
}
return
}

View File

@@ -0,0 +1,70 @@
package service
import (
"context"
"testing"
"go-common/app/interface/main/dm/model"
. "github.com/smartystreets/goconvey/convey"
)
var (
c = context.TODO()
cid = int64(10106598)
dmid = int64(719918177)
uid = int64(1234567)
reason = int8(1)
content = "aaaaaa"
)
func TestAddReport(t *testing.T) {
Convey("test add report", t, func() {
id, err := svr.AddReport(c, cid, dmid, uid, reason, content)
So(err, ShouldBeNil)
So(id, ShouldBeGreaterThan, 0)
})
}
func TestReportList(t *testing.T) {
var (
mid, aid, page, size int64 = 27515615, 0, 1, 100
upOp int8
state = []int64{0, 2}
)
Convey("test report list", t, func() {
list, err := svr.ReportList(c, mid, aid, page, size, upOp, state)
So(err, ShouldBeNil)
So(list, ShouldNotBeNil)
})
}
func TestReportArchives(t *testing.T) {
var (
mid, pn, ps int64 = 27515256, 1, 20
upOp int8
states = []int8{0, 2}
)
Convey("test report archive list", t, func() {
res, err := svr.ReportArchives(c, mid, upOp, states, pn, ps)
So(err, ShouldBeNil)
if res != nil {
for _, v := range res.Result {
t.Logf("%+v", v)
}
}
})
}
func TestEditReport(t *testing.T) {
var (
cid int64 = 10114205
dmid int64 = 719218893
mid int64 = 27515615
upOp = int8(model.StateDelete)
)
Convey("test edit report", t, func() {
_, err := svr.EditReport(c, 1, cid, mid, dmid, upOp)
So(err, ShouldBeNil)
})
}

View File

@@ -0,0 +1,67 @@
package service
import (
"context"
"time"
"go-common/app/interface/main/dm/conf"
"go-common/app/interface/main/dm/dao"
"go-common/app/interface/main/dm/model"
dmCli "go-common/app/interface/main/dm2/rpc/client"
accoutCli "go-common/app/service/main/account/api"
arcCli "go-common/app/service/main/archive/api/gorpc"
assCli "go-common/app/service/main/assist/rpc/client"
)
// Service define Service struct
type Service struct {
c *conf.Config
// dao
dao *dao.Dao
// rpc
acvSvc *arcCli.Service2
accountSvc accoutCli.AccountClient
astSvc *assCli.Service
dmRPC *dmCli.Service
//proc
delDMReportChan chan *model.Report
hideDMReportChan chan *model.Report
}
// New new a Service and return.cdfg
func New(c *conf.Config) *Service {
s := &Service{
c: c,
// dmDao
dao: dao.New(c),
// archive rpc service
acvSvc: arcCli.New2(c.ArchiveRPC),
astSvc: assCli.New(c.AssistRPC),
dmRPC: dmCli.New(c.DMRPC),
//proc
delDMReportChan: make(chan *model.Report, 1024),
hideDMReportChan: make(chan *model.Report, 1024),
}
accountSvc, err := accoutCli.NewClient(c.AccountRPC)
if err != nil {
panic(err)
}
s.accountSvc = accountSvc
go s.dmReportProc()
go s.cronproc()
return s
}
// Ping check server ok
func (s *Service) Ping(c context.Context) (err error) {
return s.dao.Ping(c)
}
// cronproc 一分钟执行一次
func (s *Service) cronproc() {
for {
<-time.After(time.Minute)
go s.sendProtectNotifyToUp(context.Background())
go s.sendProtectNotifyToUser(context.Background())
}
}

View File

@@ -0,0 +1,29 @@
package service
import (
"flag"
"os"
"path/filepath"
"testing"
"go-common/app/interface/main/dm/conf"
)
var (
svr *Service
)
func TestMain(m *testing.M) {
var (
err error
)
dir, _ := filepath.Abs("../cmd/dm-test.toml")
if err = flag.Set("conf", dir); err != nil {
panic(err)
}
if err = conf.Init(); err != nil {
panic(err)
}
svr = New(conf.Conf)
os.Exit(m.Run())
}

View File

@@ -0,0 +1,18 @@
package service
import (
"context"
"go-common/app/interface/main/dm/model"
"go-common/library/ecode"
)
func (s *Service) subject(c context.Context, tp int32, oid int64) (sub *model.Subject, err error) {
if sub, err = s.dao.Subject(c, tp, oid); err != nil {
return
}
if sub == nil {
err = ecode.NothingFound
}
return
}