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,92 @@
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",
"dm_test.go",
"filter_test.go",
"mask_test.go",
"monitor_test.go",
"report_test.go",
"service_test.go",
"subject_test.go",
"task_test.go",
"transfer_test.go",
],
embed = [":go_default_library"],
rundir = ".",
tags = ["automanaged"],
deps = [
"//app/admin/main/dm/conf:go_default_library",
"//app/admin/main/dm/model:go_default_library",
"//app/admin/main/dm/model/oplog:go_default_library",
"//library/log:go_default_library",
"//library/queue/databus/report:go_default_library",
"//vendor/github.com/davecgh/go-spew/spew:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"advance.go",
"dm.go",
"filter.go",
"mask.go",
"monitor.go",
"report.go",
"service.go",
"shield.go",
"subject.go",
"subtitle.go",
"subtitle_status.go",
"subtitle_subject.go",
"task.go",
"transfer.go",
],
importpath = "go-common/app/admin/main/dm/service",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/admin/main/dm/conf:go_default_library",
"//app/admin/main/dm/dao:go_default_library",
"//app/admin/main/dm/dao/oplog:go_default_library",
"//app/admin/main/dm/model:go_default_library",
"//app/admin/main/dm/model/oplog:go_default_library",
"//app/service/main/account/api:go_default_library",
"//app/service/main/account/model: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",
"//library/database/sql:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/log/infoc:go_default_library",
"//library/queue/databus/report:go_default_library",
"//library/sync/errgroup:go_default_library",
"//library/sync/pipeline/fanout: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,33 @@
package service
import (
"context"
"go-common/app/admin/main/dm/model"
accountApi "go-common/app/service/main/account/api"
"go-common/library/log"
)
// Advances 高级弹幕列表
func (s *Service) Advances(c context.Context, dmInid int64, typ, mode string, pn, ps int64) (res []*model.Advance, total int64, err error) {
var mids = make([]int64, 0)
if res, total, err = s.dao.Advances(c, dmInid, typ, mode, pn, ps); err != nil {
log.Error("dao.Advances(cid:%d, typ:%s, mode:%s, pn:%d,ps:%d) error(%v)", dmInid, typ, mode, pn, ps, err)
return
}
for _, r := range res {
mids = append(mids, r.Mid)
}
arg := &accountApi.MidsReq{Mids: mids}
uInfos, err := s.accountRPC.Infos3(c, arg)
if err != nil {
log.Error("s.accRPC.Infos3(%v) error(%v)", mids, err)
return
}
for _, r := range res {
if v, ok := uInfos.GetInfos()[r.Mid]; ok {
r.Name = v.Name
}
}
return
}

View File

@ -0,0 +1,16 @@
package service
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestAdvances(t *testing.T) {
Convey("test adv", t, func() {
res, _, err := svr.Advances(context.TODO(), 27515260, "all", "all", 1, 20)
So(err, ShouldBeNil)
So(res, ShouldNotBeEmpty)
})
}

View File

@ -0,0 +1,456 @@
package service
import (
"context"
"encoding/json"
"fmt"
"strconv"
"sync"
"go-common/app/admin/main/dm/model"
"go-common/app/admin/main/dm/model/oplog"
accountApi "go-common/app/service/main/account/api"
account "go-common/app/service/main/account/model"
"go-common/app/service/main/archive/model/archive"
"go-common/library/log"
"go-common/library/sync/errgroup"
)
const (
_pageSize = 50
)
// dms get dm list from database.
func (s *Service) dms(c context.Context, tp int32, oid int64, dmids []int64) (dms []*model.DM, err error) {
if len(dmids) == 0 {
return
}
contentSpe := make(map[int64]*model.ContentSpecial)
idxMap, special, err := s.dao.IndexsByID(c, tp, oid, dmids)
if err != nil || len(idxMap) == 0 {
return
}
contents, err := s.dao.Contents(c, oid, dmids)
if err != nil {
return
}
if len(special) > 0 {
if contentSpe, err = s.dao.SpecialContents(c, special); err != nil {
return
}
}
for _, content := range contents {
if idx, ok := idxMap[content.ID]; ok {
idx.Content = content
if idx.Pool == model.PoolSpecial {
if _, ok = contentSpe[idx.ID]; ok {
idx.ContentSpe = contentSpe[idx.ID]
}
}
dms = append(dms, idx)
}
}
return
}
// DMSearch danmu list from search.
func (s *Service) DMSearch(c context.Context, p *model.SearchDMParams) (res *model.SearchDMResult, err error) {
var (
mids, dmids []int64
sorted []*model.DM
protectCnt int64
dmMap = make(map[int64]*model.DM)
uidMap = make(map[int64]bool)
)
res = &model.SearchDMResult{}
sub, err := s.dao.Subject(c, p.Type, p.Oid)
if err != nil {
log.Error("s.dao.Subject(%d,%d) error(%v)", p.Type, p.Oid, err)
return
}
if sub == nil {
return
}
srchData, err := s.dao.SearchDM(c, p)
if err != nil {
log.Error("s.dao.SearchDM(%v) error(%v)", p, err)
return
}
if srchData == nil {
return
}
for _, v := range srchData.Result {
dmids = append(dmids, v.ID)
}
dms, err := s.dms(c, p.Type, p.Oid, dmids)
if err != nil {
log.Error("s.dms(%d,%v) error(%v)", p.Oid, dmids, err)
return
}
for _, dm := range dms {
dmMap[dm.ID] = dm
if _, ok := uidMap[dm.Mid]; !ok && dm.Mid > 0 {
uidMap[dm.Mid] = true
mids = append(mids, dm.Mid)
}
}
for _, dmid := range dmids {
if dm, ok := dmMap[dmid]; ok {
sorted = append(sorted, dm)
}
}
total := len(mids)
pageNum := total / _pageSize
if total%_pageSize != 0 {
pageNum++
}
var (
g errgroup.Group
lk sync.Mutex
infoMap = make(map[int64]*account.Info, total)
)
for i := 0; i < pageNum; i++ {
start := i * _pageSize
end := (i + 1) * _pageSize
if end > total {
end = total
}
g.Go(func() (err error) {
var (
arg = &accountApi.MidsReq{Mids: mids[start:end]}
res *accountApi.InfosReply
)
if res, err = s.accountRPC.Infos3(c, arg); err != nil {
log.Error("s.accRPC.Infos3(%v) error(%v)", arg, err)
} else {
for mid, info := range res.GetInfos() {
lk.Lock()
infoMap[mid] = info
lk.Unlock()
}
}
return
})
}
g.Go(func() (err error) {
if protectCnt, err = s.dao.SearchProtectCount(context.TODO(), p.Type, p.Oid); err != nil {
log.Error("s.dao.SearchProtectCount(%d,%d) error(%v)", p.Type, p.Oid, err)
}
return
})
if err = g.Wait(); err != nil {
return
}
for _, dm := range sorted {
msg := dm.Content.Msg
if dm.Pool == model.PoolSpecial && dm.ContentSpe != nil {
msg = dm.ContentSpe.Msg
}
item := &model.DMItem{
IDStr: strconv.FormatInt(dm.ID, 10),
ID: dm.ID,
Type: dm.Type,
Oid: dm.Oid,
Mid: dm.Mid,
Pool: dm.Pool,
State: dm.State,
Attrs: dm.AttrNtoA(),
Msg: msg,
Ctime: dm.Ctime,
Mode: dm.Content.Mode,
IP: dm.Content.IP,
Color: fmt.Sprintf("#%06X", dm.Content.Color),
Progress: dm.Progress,
Fontsize: dm.Content.FontSize,
}
if info, ok := infoMap[dm.Mid]; ok {
item.Uname = info.Name
}
res.Result = append(res.Result, item)
}
res.MaxLimit = sub.Maxlimit
res.Total = sub.ACount
res.Page = srchData.Page.Num
res.Pagesize = srchData.Page.Size
res.Deleted = sub.ACount - sub.Count
res.Protected = protectCnt
res.Count = srchData.Page.Total
return
}
// XMLCacheFlush 刷新弹幕缓存
func (s *Service) XMLCacheFlush(c context.Context, tp int32, oid int64) {
v := make(map[string]interface{})
v["type"] = tp
v["oid"] = oid
v["force"] = true
data, err := json.Marshal(v)
if err != nil {
log.Error("json.Marshal(%v) error(%v)", v, err)
return
}
action := &model.Action{Action: model.ActFlushDM, Data: data, Oid: oid}
s.addAction(action)
}
// EditDMState multi edit dm state.
func (s *Service) EditDMState(c context.Context, tp, state int32, oid int64, reason int8, dmids []int64, moral float64, adminID int64, operator, remark string) (err error) {
if err = s.editDmState(c, tp, state, oid, reason, dmids, moral, adminID, operator, remark); err != nil {
log.Error("s.dao.UpSearchDMState(%d,%d,%v) err (%v)", tp, oid, dmids, err)
return
}
// update dm search index
if err = s.uptSearchDmState(c, tp, state, map[int64][]int64{oid: dmids}); err != nil {
log.Error("s.dao.UpSearchDMState(%d,%d,%v) err (%v)", tp, oid, dmids, err)
}
return
}
// editDmState multi edit dm state.
func (s *Service) editDmState(c context.Context, tp, state int32, oid int64, reason int8, dmids []int64, moral float64, adminID int64, operator, remark string) (err error) {
sub, err := s.dao.Subject(c, tp, oid)
if err != nil || sub == nil {
return
}
dms, err := s.dms(c, tp, oid, dmids)
if err != nil {
return
}
count := countDMNum(dms, state)
affect, err := s.dao.SetStateByIDs(c, tp, oid, dmids, state)
if err != nil || affect == 0 {
return
}
if sub.Count+count < 0 {
count = -sub.Count
}
// update dm_index count
if _, err = s.dao.IncrSubjectCount(c, tp, oid, count); err != nil {
return
}
// write dm admin log
if affect > 0 {
if remark == "" {
remark = model.AdminRptReason[reason]
}
s.OpLog(c, oid, adminID, tp, dmids, "status", "", fmt.Sprint(state), remark, oplog.SourceManager, oplog.OperatorAdmin)
}
// update dm monitor count
if sub.IsMonitoring() {
s.oidLock.Lock()
s.moniOidMap[sub.Oid] = struct{}{}
s.oidLock.Unlock()
}
// flush xml cache
s.XMLCacheFlush(c, tp, oid)
// reduce moral
uidMap := make(map[int64]struct{})
for _, dm := range dms {
if _, ok := uidMap[dm.Mid]; !ok {
uidMap[dm.Mid] = struct{}{}
}
}
if len(uidMap) > 0 && moral > 0 {
for uid := range uidMap {
s.reduceMoral(c, uid, int64(-moral), reason, operator, "弹幕管理")
}
}
return
}
// EditDMPool edit dm pool.
func (s *Service) EditDMPool(c context.Context, tp int32, oid int64, pool int32, dmids []int64, adminID int64) (err error) {
sub, err := s.dao.Subject(c, tp, oid)
if err != nil || sub == nil {
return
}
if sub.Childpool < pool {
if _, err = s.dao.UpSubjectPool(c, tp, oid, pool); err != nil {
return
}
}
affect, err := s.dao.SetPoolIDByIDs(c, tp, oid, pool, dmids)
if err != nil {
return
}
if affect > 0 {
if pool == model.PoolNormal {
s.dao.IncrSubMoveCount(c, tp, oid, -affect) // NOTE update move_count,ignore error
} else {
s.dao.IncrSubMoveCount(c, tp, oid, affect) // NOTE update move_count,ignore error
}
s.OpLog(c, oid, adminID, tp, dmids, "pool", "", fmt.Sprint(pool), "弹幕池变更", oplog.SourceManager, oplog.OperatorAdmin)
}
if err = s.uptSearchDMPool(c, tp, oid, pool, dmids); err != nil {
log.Error("s.dao.UpSearchDMPool(%d,%d,%v) err (%v)", tp, oid, dmids, err)
}
return
}
// EditDMAttr change dm attr
func (s *Service) EditDMAttr(c context.Context, tp int32, oid int64, dmids []int64, bit uint, value int32, adminID int64) (err error) {
var (
eg = errgroup.Group{}
attrMap = make(map[int32][]int64)
)
dms, err := s.dms(c, tp, oid, dmids)
if err != nil {
log.Error("s.dms(oid:%d ids:%v) error(%v)", oid, dmids, err)
return
}
for _, dm := range dms {
dm.AttrSet(value, bit)
attrMap[dm.Attr] = append(attrMap[dm.Attr], dm.ID)
}
for k, v := range attrMap {
attr := k
ids := v
eg.Go(func() (err error) {
affect, err := s.dao.SetAttrByIDs(c, tp, oid, ids, attr)
if err != nil {
log.Error("s.dao.SetAttrByIDs(oid:%d ids:%v) error(%v)", oid, ids, err)
return
}
if affect > 0 {
s.OpLog(c, oid, adminID, tp, ids, "attribute", "", fmt.Sprint(attr), "弹幕保护状态变更", oplog.SourceManager, oplog.OperatorAdmin)
}
if err = s.uptSearchDMAttr(c, tp, oid, attr, dmids); err != nil {
log.Error("dao.UpSearchDMAttr(oid:%d,attr:%d) error(%v)", oid, attr, err)
}
return
})
}
return eg.Wait()
}
// DMIndexInfo get dm index info
func (s *Service) DMIndexInfo(c context.Context, cid int64) (info *model.DMIndexInfo, err error) {
info = new(model.DMIndexInfo)
sub, err := s.dao.Subject(c, model.SubTypeVideo, cid)
if err != nil || sub == nil {
return
}
argAid2 := &archive.ArgAid2{Aid: sub.Pid}
arc, err := s.arcRPC.Archive3(c, argAid2)
if err != nil {
log.Error("s.arcRPC.Archive3(%v) error(%v)", argAid2, err)
err = nil
} else {
info.Title = arc.Title
info.Cover = arc.Pic
}
argVideo := &archive.ArgVideo2{Aid: sub.Pid, Cid: cid}
video, err := s.arcRPC.Video3(c, argVideo)
if err != nil {
log.Error("s.arcRPC.Video3(%v) error(%v)", argVideo, err)
err = nil
} else {
info.Duration = video.Duration
info.ETitle = video.Part
}
argMid := &accountApi.MidReq{Mid: sub.Mid}
uInfo, err := s.accountRPC.Info3(c, argMid)
if err != nil {
log.Error("s.accRPC.Info3(%v) error(%v)", argMid, err)
err = nil
} else {
info.UName = uInfo.GetInfo().GetName()
}
info.AID = sub.Pid
info.CID = sub.Oid
info.MID = sub.Mid
info.Limit = sub.Maxlimit
if sub.State == model.SubStateOpen {
info.Active = 1
} else {
info.Active = 0
}
info.CTime = int64(sub.Ctime)
info.MTime = int64(sub.Mtime)
return
}
// countDMNum count state changed dm count
func countDMNum(dms []*model.DM, state int32) (count int64) {
for _, dm := range dms {
if model.DMVisible(dm.State) && !model.DMVisible(state) {
count--
} else if !model.DMVisible(dm.State) && model.DMVisible(state) {
count++
}
}
return count
}
// FixDMCount fix dm acount,count of aid.
func (s *Service) FixDMCount(c context.Context, aid int64) (err error) {
var (
arg = archive.ArgAid2{Aid: aid}
oids []int64
states = []int64{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13} // 弹幕所有状态
normalState = []int64{0, 2, 6} // 前台可能展示的弹幕状态
)
pages, err := s.arcRPC.Page3(c, &arg)
if err != nil {
log.Error("arcRPC.Page3(%v) error(%v)", arg, err)
return
}
if len(pages) == 0 {
log.Warn("aid:%d have no pages", aid)
return
}
for _, page := range pages {
oids = append(oids, page.Cid)
}
subs, err := s.dao.Subjects(c, model.SubTypeVideo, oids)
if err != nil {
return
}
for _, sub := range subs {
tp := sub.Type
oid := sub.Oid
s.cache.Do(c, func(ctx context.Context) {
acount, err := s.dao.DMCount(ctx, tp, oid, states)
if err != nil {
return
}
count, err := s.dao.DMCount(ctx, tp, oid, normalState)
if err != nil {
return
}
s.dao.UpSubjectCount(ctx, tp, oid, acount, count) // 更新新库dm_subject
log.Info("fix dm count,type:%d,oid:%d,acount:%d,count:%d", tp, oid, acount, count)
})
}
return
}
func (s *Service) uptSearchDmState(c context.Context, tp int32, state int32, dmidM map[int64][]int64) (err error) {
if err = s.dao.UpSearchDMState(c, tp, state, dmidM); err != nil {
return
}
if err = s.dao.UpSearchRecentDMState(c, tp, state, dmidM); err != nil {
return
}
return
}
func (s *Service) uptSearchDMPool(c context.Context, tp int32, oid int64, pool int32, dmids []int64) (err error) {
if err = s.dao.UpSearchDMPool(c, tp, oid, pool, dmids); err != nil {
return
}
if err = s.dao.UpSearchRecentDMPool(c, tp, oid, pool, dmids); err != nil {
return
}
return
}
func (s *Service) uptSearchDMAttr(c context.Context, tp int32, oid int64, attr int32, dmids []int64) (err error) {
if err = s.dao.UpSearchDMAttr(c, tp, oid, attr, dmids); err != nil {
return
}
if err = s.dao.UpSearchRecentDMAttr(c, tp, oid, attr, dmids); err != nil {
return
}
return
}

View File

@ -0,0 +1,72 @@
package service
import (
"context"
"testing"
"go-common/app/admin/main/dm/model"
"github.com/davecgh/go-spew/spew"
. "github.com/smartystreets/goconvey/convey"
)
func TestDMSearch(t *testing.T) {
d := &model.SearchDMParams{
Type: 1,
Oid: 1,
Mid: model.CondIntNil,
ProgressFrom: model.CondIntNil,
ProgressTo: model.CondIntNil,
CtimeFrom: model.CondIntNil,
CtimeTo: model.CondIntNil,
State: "",
Pool: "",
Page: 1,
Order: "id",
Sort: "asc",
}
Convey("test dm list", t, func() {
res, err := svr.DMSearch(context.TODO(), d)
So(err, ShouldBeNil)
So(res, ShouldNotBeNil)
spew.Dump(res)
So(res.Result, ShouldNotBeEmpty)
})
}
func TestEditDMPool(t *testing.T) {
Convey("test change pool id", t, func() {
err := svr.EditDMPool(context.TODO(), 1, 1, 1, []int64{1, 2}, 123)
So(err, ShouldBeNil)
})
}
func TestXMLCacheFlush(t *testing.T) {
Convey("test flush cache", t, func() {
svr.XMLCacheFlush(context.TODO(), 1, 1221)
})
}
func TestEditDMState(t *testing.T) {
dmids := []int64{1, 2}
Convey("test content status", t, func() {
res := svr.EditDMState(context.TODO(), 1, 1221, 1, 1, dmids, 10, 123, "admin", "test")
So(res, ShouldNotBeNil)
})
}
func TestEditDMAttr(t *testing.T) {
Convey("test change attr", t, func() {
err := svr.EditDMAttr(context.TODO(), 1, 1, []int64{1, 2}, model.AttrProtect, 1, 123)
So(err, ShouldBeNil)
})
}
func TestDMIndexInfo(t *testing.T) {
var cid int64 = 9967205
Convey("test dm index info", t, func() {
idx, err := svr.DMIndexInfo(context.TODO(), cid)
So(err, ShouldBeNil)
So(idx, ShouldNotBeNil)
})
}

View File

@ -0,0 +1,67 @@
package service
import (
"context"
"go-common/app/admin/main/dm/model"
"go-common/library/log"
)
// UpFilters return up filters
func (s *Service) UpFilters(c context.Context, mid, ftype, pn, ps int64) (res []*model.UpFilter, total int64, err error) {
//type all
if ftype == int64(model.FilterTypeAll) {
if res, total, err = s.dao.UpFiltersAll(c, mid, pn, ps); err != nil {
log.Error("s.dao.UpFiltersAll(mid:%d) error(%v)", mid, err)
}
return
}
if res, total, err = s.dao.UpFilters(c, mid, ftype, pn, ps); err != nil {
log.Error("s.dao.UpFilters(mid:%d, type:%d) error(%v)", mid, ftype, err)
}
return
}
// EditUpFilters edit up filters.
func (s *Service) EditUpFilters(c context.Context, id, mid int64, fType, active int8) (affect int64, err error) {
var limit int
tx, err := s.dao.BeginBiliDMTrans(c)
if err != nil {
log.Error("tx.BeginBiliDMTrans error(%v)", err)
return
}
defer func() {
if err != nil {
if err1 := tx.Rollback(); err1 != nil {
log.Error("tx.Rollback() error(%v)", err1)
}
return
}
if err = tx.Commit(); err != nil {
log.Error("tx.Commit() error(%v)", err)
}
}()
if affect, err = s.dao.UpdateUpFilter(tx, mid, id, active); err != nil {
return
}
switch fType {
case model.FilterTypeText:
limit = model.FilterMaxUpText
case model.FilterTypeRegex:
limit = model.FilterMaxUpReg
case model.FilterTypeID:
limit = model.FilterMaxUpID
}
if active == model.FilterUnActive {
affect = -affect
limit = 10000
}
if _, err = s.dao.UpdateUpFilterCnt(tx, mid, fType, int(affect), limit+1); err != nil {
return
}
s.cache.Do(c, func(ctx context.Context) {
s.dao.DelUpFilterCache(ctx, mid, 0)
})
return
}

View File

@ -0,0 +1,23 @@
package service
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestUpFilters(t *testing.T) {
Convey("test update user rule", t, func() {
rs, _, err := svr.UpFilters(context.TODO(), 27515615, 1, 1, 20)
So(err, ShouldBeNil)
So(rs, ShouldNotBeEmpty)
})
}
func TestEditUpFilters(t *testing.T) {
Convey("test edit user rule", t, func() {
_, err := svr.EditUpFilters(context.TODO(), 66, 27515256, 1, 0)
So(err, ShouldBeNil)
})
}

View File

@ -0,0 +1,160 @@
package service
import (
"context"
"go-common/app/admin/main/dm/model"
accountApi "go-common/app/service/main/account/api"
"go-common/app/service/main/archive/api"
arcMdl "go-common/app/service/main/archive/model/archive"
"go-common/library/ecode"
"go-common/library/log"
)
// MaskState get mask state
func (s *Service) MaskState(c context.Context, tp int32, oid int64) (open, mobile, web int32, err error) {
sub, err := s.dao.Subject(c, tp, oid)
if err != nil {
return
}
if sub == nil {
err = ecode.ArchiveNotExist
return
}
return sub.AttrVal(model.AttrSubMaskOpen), sub.AttrVal(model.AttrSubMblMaskReady), sub.AttrVal(model.AttrSubWebMaskReady), err
}
// UpdateMaskState update mask state
func (s *Service) UpdateMaskState(c context.Context, tp int32, oid int64, plat int8, state int32) (err error) {
var (
archive3 *api.Arc
err1 error
duration int64
typeID int32
)
sub, err := s.dao.Subject(c, tp, oid)
if err != nil {
return
}
if sub == nil {
err = ecode.ArchiveNotExist
return
}
if archive3, err1 = s.arcRPC.Archive3(c, &arcMdl.ArgAid2{Aid: sub.Pid}); err1 == nil && archive3 != nil {
duration = archive3.Duration
typeID = archive3.TypeID
}
if state == model.AttrYes {
switch plat {
case model.MaskPlatMbl:
if sub.AttrVal(model.AttrSubMblMaskReady) == model.AttrNo {
if err = s.dao.GenerateMask(c, oid, sub.Mid, plat, 0, sub.Pid, duration, typeID); err != nil {
return
}
}
case model.MaskPlatWeb:
if sub.AttrVal(model.AttrSubWebMaskReady) == model.AttrNo {
if err = s.dao.GenerateMask(c, oid, sub.Mid, plat, 0, sub.Pid, duration, typeID); err != nil {
return
}
}
default:
if sub.AttrVal(model.AttrSubMblMaskReady) == model.AttrNo || sub.AttrVal(model.AttrSubWebMaskReady) == model.AttrNo {
if err = s.dao.GenerateMask(c, oid, sub.Mid, plat, 0, sub.Pid, duration, typeID); err != nil {
return
}
}
}
}
sub.AttrSet(state, model.AttrSubMaskOpen)
_, err = s.dao.UpSubjectAttr(c, tp, oid, sub.Attr)
return
}
// GenerateMask generate mask
func (s *Service) GenerateMask(c context.Context, tp int32, oid int64, plat int8) (err error) {
var (
archive3 *api.Arc
err1 error
duration int64
typeID int32
)
sub, err := s.dao.Subject(c, tp, oid)
if err != nil {
return
}
if sub == nil {
err = ecode.ArchiveNotExist
return
}
if archive3, err1 = s.arcRPC.Archive3(c, &arcMdl.ArgAid2{Aid: sub.Pid}); err1 == nil && archive3 != nil {
duration = archive3.Duration
typeID = archive3.TypeID
}
err = s.dao.GenerateMask(c, oid, sub.Mid, plat, 1, sub.Pid, duration, typeID)
return
}
// MaskUps get mask up infos.
func (s *Service) MaskUps(c context.Context, pn, ps int64) (res *model.MaskUpRes, err error) {
MaskUps, total, err := s.dao.MaskUps(c, pn, ps)
if err != nil {
return
}
mids := make([]int64, 0, len(MaskUps))
for _, up := range MaskUps {
mids = append(mids, up.Mid)
}
arg := &accountApi.MidsReq{Mids: mids}
uInfos, err := s.accountRPC.Infos3(c, arg)
if err != nil {
log.Error("s.accRPC.Infos3(%v) error(%v)", mids, err)
return
}
for _, up := range MaskUps {
if info, ok := uInfos.GetInfos()[up.Mid]; ok {
up.Name = info.Name
}
}
res = &model.MaskUpRes{
Result: MaskUps,
Page: &model.PageInfo{
Num: pn,
Size: ps,
Total: total,
},
}
return
}
// MaskUpOpen add mask up
func (s *Service) MaskUpOpen(c context.Context, mids []int64, state int32, comment string) (err error) {
midMap := make(map[int64]struct{})
ids := make([]int64, 0, len(mids))
for _, mid := range mids {
if _, ok := midMap[mid]; !ok {
midMap[mid] = struct{}{}
ids = append(ids, mid)
}
}
// 验证mids
arg := &accountApi.MidsReq{Mids: ids}
uInfos, err := s.accountRPC.Infos3(c, arg)
if err != nil {
log.Error("s.accRPC.Infos3(%v) error(%v)", ids, err)
return
}
if len(uInfos.GetInfos()) < len(ids) {
err = ecode.AccountInexistence
log.Error("s.MaskUpOpen length diff(%d,%d)", len(ids), len(uInfos.GetInfos()))
return
}
for _, id := range ids {
if _, err = s.dao.MaskUpOpen(c, id, state, comment); err != nil {
return
}
}
return
}

View File

@ -0,0 +1,49 @@
package service
import (
"context"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestMaskState(t *testing.T) {
convey.Convey("mask state", t, func() {
open, mobile, web, err := svr.MaskState(context.TODO(), 1, 1352)
convey.So(err, convey.ShouldBeNil)
t.Logf("===%d,%d,%d", open, mobile, web)
})
}
func TestUpdateMaskState(t *testing.T) {
convey.Convey("open mask", t, func() {
err := svr.UpdateMaskState(context.TODO(), 1, 1352, 1, 0)
convey.So(err, convey.ShouldBeNil)
})
}
func TestGenerateMask(t *testing.T) {
convey.Convey("generate mask", t, func() {
err := svr.GenerateMask(context.TODO(), 1, 1352, 1)
convey.So(err, convey.ShouldBeNil)
})
}
func TestMaskUps(t *testing.T) {
convey.Convey("test mask ups", t, func() {
res, err := svr.MaskUps(context.Background(), 1, 50)
convey.So(err, convey.ShouldBeNil)
convey.So(res, convey.ShouldNotBeNil)
t.Log(res, res.Result, res.Page)
for _, v := range res.Result {
t.Log(v)
}
})
}
func TestMaskUpOpen(t *testing.T) {
convey.Convey("test mask up open", t, func() {
err := svr.MaskUpOpen(context.Background(), []int64{1111, 142341123}, 1, "")
convey.So(err, convey.ShouldBeNil)
})
}

View File

@ -0,0 +1,109 @@
package service
import (
"context"
"go-common/app/admin/main/dm/model"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/sync/errgroup"
)
// MonitorList get monitor list
func (s *Service) MonitorList(c context.Context, tp int32, pid, oid, mid int64, state int32, kw, sort, order string, page, size int64) (res *model.MonitorResult, err error) {
var attr int32
if state > 0 {
if state == model.MonitorBefore {
attr = int32(model.AttrSubMonitorBefore) + 1
} else {
attr = int32(model.AttrSubMonitorAfter) + 1
}
}
data, err := s.dao.SearchMonitor(c, tp, pid, oid, mid, attr, kw, sort, order, page, size)
if err != nil {
log.Error("dao.SearchMonitor(pid:%d,oid:%d) error(%v)", pid, oid, err)
return
}
res = &model.MonitorResult{
Order: data.Order,
Sort: data.Sort,
Page: data.Page.Num,
PageSize: data.Page.Size,
Total: data.Page.Total,
Result: make([]*model.Monitor, 0, len(data.Result)),
}
for _, v := range data.Result {
m := &model.Monitor{
ID: v.ID,
Type: v.Type,
Pid: v.Pid,
Oid: v.Oid,
MCount: v.MCount,
Ctime: v.Ctime,
Mtime: v.Mtime,
Mid: v.Mid,
Title: v.Title,
Author: v.Author,
}
if v.Attr>>model.AttrSubMonitorBefore&1 == model.AttrYes {
m.State = model.MonitorBefore
} else {
m.State = model.MonitorAfter
}
res.Result = append(res.Result, m)
}
return
}
// UpdateMonitor update monitor state of dm subject.
func (s *Service) UpdateMonitor(c context.Context, tp int32, oids []int64, state int32) (affect int64, err error) {
var wg errgroup.Group
subs, err := s.dao.Subjects(c, tp, oids)
if err != nil {
return
}
for _, v := range subs {
sub := v
switch state {
case model.MonitorClosed:
sub.AttrSet(model.AttrNo, model.AttrSubMonitorBefore)
sub.AttrSet(model.AttrNo, model.AttrSubMonitorAfter)
case model.MonitorBefore:
sub.AttrSet(model.AttrYes, model.AttrSubMonitorBefore)
sub.AttrSet(model.AttrNo, model.AttrSubMonitorAfter)
case model.MonitorAfter:
sub.AttrSet(model.AttrNo, model.AttrSubMonitorBefore)
sub.AttrSet(model.AttrYes, model.AttrSubMonitorAfter)
default:
err = ecode.RequestErr
return
}
wg.Go(func() (err error) {
aft, err := s.dao.UpSubjectAttr(context.TODO(), tp, sub.Oid, sub.Attr)
if err != nil {
return
}
affect = affect + aft
return
})
}
err = wg.Wait()
return
}
// updateMonitorCnt update mcount of subject.
func (s *Service) updateMonitorCnt(c context.Context, sub *model.Subject) (err error) {
var state, mcount int64
if sub.AttrVal(model.AttrSubMonitorBefore) == model.AttrYes {
state = int64(model.StateMonitorBefore)
} else if sub.AttrVal(model.AttrSubMonitorAfter) == model.AttrYes {
state = int64(model.StateMonitorAfter)
} else {
return
}
if mcount, err = s.dao.DMCount(c, sub.Type, sub.Oid, []int64{state}); err != nil {
return
}
_, err = s.dao.UpSubjectMCount(c, sub.Type, sub.Oid, mcount)
return
}

View File

@ -0,0 +1,38 @@
package service
import (
"context"
"testing"
"go-common/app/admin/main/dm/model"
. "github.com/smartystreets/goconvey/convey"
)
func TestMonitorList(t *testing.T) {
var (
c = context.TODO()
aid, cid, mid, p, ps int64 = 0, 0, 0, 1, 100
kw, sort, order = "", "", ""
state int32 = 1
tp int32 = 1
)
Convey("test monitor list from search", t, func() {
res, err := svr.MonitorList(c, tp, aid, cid, mid, state, kw, sort, order, p, ps)
So(res, ShouldNotBeEmpty)
So(err, ShouldBeNil)
})
}
func TestUpdateMonitor(t *testing.T) {
var (
c = context.TODO()
tp = model.SubTypeVideo
oids = []int64{2, 99}
)
Convey("update dm subject monitor", t, func() {
affect, err := svr.UpdateMonitor(c, tp, oids, 1)
So(affect, ShouldBeGreaterThan, 0)
So(err, ShouldBeNil)
})
}

View File

@ -0,0 +1,663 @@
package service
import (
"bytes"
"context"
"encoding/json"
"fmt"
"math"
"strconv"
"sync"
"time"
"go-common/app/admin/main/dm/dao"
"go-common/app/admin/main/dm/model"
"go-common/app/service/main/archive/api"
"go-common/app/service/main/archive/model/archive"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/sync/errgroup"
)
const (
_searchTimeFormat = "2006-01-02 15:04:05"
)
// ChangeReportStat set dm report status by mult dmid.
func (s *Service) ChangeReportStat(c context.Context, cidDmids map[int64][]int64, state, reason, notice int8, adminID, block, blockReason, moral int64, remark, operator string) (affect int64, err error) {
var (
optDur int64
dmids []int64
dmidList = make([]int64, 0)
nowTime = time.Now()
dmLogMap = make(map[int64][]*model.ReportLog)
rptsMap = make(map[int64]*model.Report)
uptRpts = make([]*model.UptSearchReport, 0)
)
for _, dmids2 := range cidDmids {
dmids = append(dmids, dmids2...)
}
if state == model.StatFirstInit || state == model.StatSecondInit || state == model.StatJudgeInit {
if rptsMap, err = s.reports(c, dmids); err != nil {
log.Error("s.reports(cidDmids:%v) error(%v)", cidDmids, err)
return
}
} else {
if rptsMap, err = s.reportsDetail(c, dmids); err != nil {
log.Error("s.reportsDetail(cidDmids:%v) error(%v)", cidDmids, err)
return
}
}
for cid, dmids := range cidDmids {
if state == model.StatSecondIgnore || state == model.StatFirstIgnore {
if err = s.dao.IgnoreReport(c, cid, dmids, state); err != nil {
log.Error("s.dao.IgnoreReport(cid:%d, dmid:%v) error(%v)", cid, dmids, err)
return 0, err
}
} else {
if err = s.dao.ChangeReportStat(c, cid, dmids, state); err != nil {
log.Error("s.dao.ChangeReportStat(cid:%d, dmid:%v) error(%v)", cid, dmids, err)
return 0, err
}
}
var rpts []*model.Report
if rpts, err = s.dao.Reports(c, cid, dmids); err != nil {
log.Error("s.dao.Reports(cid:%d, dmids:%v) error(%v)", cid, dmids, err)
err = nil
} else {
for _, rpt := range rpts {
var ctime, mtime time.Time
ctime, err = time.Parse(time.RFC3339, rpt.Ctime)
if err != nil {
log.Error("strconv.RarseInt(%s) error(%v)", rpt.Ctime, err)
err = nil
continue
}
mtime, err = time.Parse(time.RFC3339, rpt.Mtime)
if err != nil {
log.Error("strconv.RarseInt(%s) error(%v)", rpt.Mtime, err)
err = nil
continue
}
uptRpt := &model.UptSearchReport{
DMid: rpt.Did,
Ctime: ctime.Format("2006-01-02 15:04:05"),
Mtime: mtime.Format("2006-01-02 15:04:05"),
State: state,
}
uptRpts = append(uptRpts, uptRpt)
}
}
for _, dmid := range dmids {
rpt, ok := rptsMap[dmid]
if !ok {
err = fmt.Errorf("get report detail empty,dmid:%d", dmid)
log.Error("s.ReportsDetail(cid:%d, dmid:%v) error(%v)", cid, dmid, err)
continue
}
if isDeleteOperation(state) {
s.addRptDelAction(rpt)
}
rpt.State = state
var mtime time.Time
if mtime, err = time.ParseInLocation("2006-01-02 15:04:05", rpt.Mtime, time.Local); err == nil {
optDur = int64(time.Since(mtime).Seconds())
}
lg := &model.ReportLog{
Did: dmid,
AdminID: adminID,
Reason: reason,
Result: state,
Remark: remark,
Elapsed: optDur,
Ctime: nowTime,
Mtime: nowTime,
}
dmLogMap[dao.LogTable(rpt.Did)] = append(dmLogMap[dao.LogTable(rpt.Did)], lg)
dmidList = append(dmidList, rpt.Did)
// if moral > 0 {
// s.reduceMoral(c, rpt.UID, moral, reason, uname, fmt.Sprintf("%s, cid:%d, dmid:%d", model.CheckStateBelong(state), cid, dmid))
// }
if block != 0 {
s.blockUser(c, rpt, block, blockReason, moral, operator)
}
if notice == model.NoticeReporter || notice == model.NoticeAll { // 发送邮件给举报方
if len(rpt.RptUsers) > 0 {
s.sendMsgToReporter(c, rpt, block, blockReason, int64(reason))
}
}
if notice == model.NoticePoster || notice == model.NoticeAll {
if len(rpt.RptUsers) > 0 {
s.sendMsgToPoster(c, rpt, block, blockReason, int64(reason))
}
}
}
// if delete or recover this danmu
if isDeleteOperation(state) {
tmpRemark := model.AdminRptReason[reason] + "" + model.BlockReason[int8(blockReason)]
if len(remark) >= 0 {
tmpRemark = remark + "" + tmpRemark
}
// s.dao.SetStateByIDs(c, model.SubTypeVideo, cid, dmids, model.StateReportDelete)
// s.OpLog(c, cid, adminID, 1, dmids, "status", "", fmt.Sprint(model.StateReportDelete), tmpRemark, oplog.SourceManager, oplog.OperatorAdmin)
s.editDmState(c, model.SubTypeVideo, model.StateReportDelete, cid, reason, dmids, float64(moral), adminID, operator, tmpRemark)
}
}
if isDeleteOperation(state) {
// search update ignore error
s.uptSearchDmState(c, model.SubTypeVideo, model.StateReportDelete, cidDmids)
}
if !(state == model.StatSecondInit || state == model.StatFirstInit) {
if err = s.ChangeReportUserStat(c, dmidList); err != nil {
log.Error("s.ChangeReportUserStat(%v) error(%v)", dmidList, err)
}
}
if len(uptRpts) > 0 {
if err = s.dao.UptSearchReport(c, uptRpts); err != nil {
log.Error("s.dao.UpSearchReport(%v) error(%v)", uptRpts, err)
err = nil
}
}
for k, v := range dmLogMap {
if len(v) <= 0 {
continue
}
if err = s.dao.AddReportLog(c, k, v); err != nil {
log.Error("s.dao.AddReportLog(%v) error(%v)", v, err)
return
}
}
return
}
func isDeleteOperation(state int8) bool {
if state == model.StatSecondDelete || state == model.StatFirstDelete || state == model.StatSecondAutoDelete || state == model.StatJudgeDelete {
return true
}
return false
}
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 {
log.Error("s.dmState(oid:%v,dmids:%v) err(%v)", oid, dmids, err)
return
}
for dmid, dm := range idxMap {
stateMap[dmid] = int64(dm.State)
}
}
return
}
// ReportList2 .
func (s *Service) ReportList2(c context.Context, params *model.ReportListParams) (rtList *model.ReportList, err error) {
var (
aidMap = make(map[int64]bool)
aids []int64
cidDmids = make(map[int64][]int64)
stateMap = make(map[int64]int64)
)
if params.Start == "" {
now := time.Now()
params.Start = time.Date(now.Year(), now.Month(), now.Day()-3, 0, 0, 0, 0, now.Location()).Format(_searchTimeFormat)
}
if params.End == "" {
now := time.Now()
params.End = time.Date(now.Year(), now.Month(), now.Day()+1, 0, 0, 0, 0, now.Location()).Format(_searchTimeFormat)
}
rptSearch, err := s.dao.SearchReport2(c, params)
if err != nil {
log.Error("s.dao.SearchReport2(params:%+v) error(%v)", params, err)
return
}
for _, v := range rptSearch.Result {
aidMap[v.Aid] = true
cidDmids[v.Cid] = append(cidDmids[v.Cid], v.Did)
}
for aid := range aidMap {
aids = append(aids, aid)
}
archives, err := s.archiveInfos(c, aids)
if err != nil {
log.Error("s.archives(%v) error(%v)", aids, err)
return
}
if stateMap, err = s.dmState(c, cidDmids); err != nil {
return
}
for _, v := range rptSearch.Result {
v.DidStr = strconv.FormatInt(v.Did, 10)
if arc, ok := archives[v.Aid]; ok {
v.Title = arc.Title
}
if state, ok := stateMap[v.Did]; ok {
v.Deleted = state
}
}
rtList = &model.ReportList{
Code: rptSearch.Code,
Order: rptSearch.Order,
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
}
// ReportList get report list from search
func (s *Service) ReportList(c context.Context, page, size int64, start, end, order, sort, keyword string, tid, rpID, state, upOp []int64, rt *model.Report) (rtList *model.ReportList, err error) {
var (
aidMap = make(map[int64]bool)
aids []int64
cidDmids = make(map[int64][]int64)
stateMap = make(map[int64]int64)
)
rptSearch, err := s.dao.SearchReport(c, page, size, start, end, order, sort, keyword, tid, rpID, state, upOp, rt)
if err != nil {
log.Error("s.dao.SearchReport() error(%v)", err)
return
}
for _, v := range rptSearch.Result {
aidMap[v.Aid] = true
cidDmids[v.Cid] = append(cidDmids[v.Cid], v.Did)
}
for aid := range aidMap {
aids = append(aids, aid)
}
archives, err := s.archiveInfos(c, aids)
if err != nil {
log.Error("s.archives(%v) error(%v)", aids, err)
return
}
if stateMap, err = s.dmState(c, cidDmids); err != nil {
return
}
for _, v := range rptSearch.Result {
v.DidStr = strconv.FormatInt(v.Did, 10)
if arc, ok := archives[v.Aid]; ok {
v.Title = arc.Title
}
if state, ok := stateMap[v.Did]; ok {
v.Deleted = state
}
}
rtList = &model.ReportList{
Code: rptSearch.Code,
Order: rptSearch.Order,
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) archiveInfos(c context.Context, aids []int64) (archives map[int64]*api.Arc, err error) {
var (
g errgroup.Group
mu sync.Mutex
l = len(aids)
pagesize = 50
pagenum = int(math.Ceil(float64(l) / float64(pagesize)))
)
archives = make(map[int64]*api.Arc)
for i := 0; i < pagenum; i++ {
start := i * pagesize
end := (i + 1) * pagesize
if end > l {
end = l
}
g.Go(func() (err error) {
arg := &archive.ArgAids2{Aids: aids[start:end]}
res, err := s.arcRPC.Archives3(c, arg)
if err != nil {
log.Error("s.arcRPC.Archives3(%v) error(%v)", arg, err)
return
}
for aid, info := range res {
mu.Lock()
archives[aid] = info
mu.Unlock()
}
return
})
}
err = g.Wait()
return
}
// reportUsers get mult reports users
func (s *Service) reportUsers(c context.Context, dmids []int64) (rptUsers map[int64][]*model.ReportUser, err error) {
var (
g errgroup.Group
mu sync.Mutex
dmidsMap = map[int64][]int64{}
)
for _, dmid := range dmids {
dmidsMap[dao.UserTable(dmid)] = append(dmidsMap[dao.UserTable(dmid)], dmid)
}
rptUsers = make(map[int64][]*model.ReportUser)
for tableID, dmids := range dmidsMap {
key, value := tableID, dmids
g.Go(func() (err error) {
userTmp, err := s.dao.ReportUsers(c, key, value, model.NoticeUnsend)
if err != nil {
return
}
for dmid, users := range userTmp {
mu.Lock()
rptUsers[dmid] = users
mu.Unlock()
}
return
})
}
err = g.Wait()
return
}
// reportsDetail get report list from search and get user list、archive list、dm list.
func (s *Service) reportsDetail(c context.Context, dmids []int64) (res map[int64]*model.Report, err error) {
var (
aidMap = make(map[int64]bool)
aids, dmids2 []int64
)
reports, err := s.reports(c, dmids)
if err != nil {
return
}
for dmid, rpt := range reports {
if _, ok := aidMap[rpt.Aid]; !ok {
aidMap[rpt.Aid] = true
aids = append(aids, rpt.Aid)
}
dmids2 = append(dmids2, dmid)
}
archives, err := s.archiveInfos(c, aids)
if err != nil {
log.Error("s.archives(%v) error(%v)", aids, err)
return nil, err
}
rptUsers, err := s.reportUsers(c, dmids2)
if err != nil {
log.Error("s.rptUsers(%v) error(%v)", dmids2, err)
return nil, err
}
res = make(map[int64]*model.Report)
for dmid, rpt := range reports {
if arc, ok := archives[rpt.Aid]; ok {
rpt.Title = arc.Title
}
if users, ok := rptUsers[dmid]; ok {
rpt.RptUsers = users
} else {
rpt.RptUsers = make([]*model.ReportUser, 0)
}
res[dmid] = rpt
}
return
}
// reports get report list by cid and dmids from search.
func (s *Service) reports(c context.Context, dmids []int64) (res map[int64]*model.Report, err error) {
rptSearchList, err := s.dao.SearchReportByID(c, dmids)
if err != nil || len(rptSearchList.Result) <= 0 {
log.Error("dao.SearchReportByID(ids:%v) error(%v)", dmids, err)
return
}
res = make(map[int64]*model.Report)
for _, rpt := range rptSearchList.Result {
res[rpt.Did] = rpt
}
return
}
// ReportLog get report log by dmid.
func (s *Service) ReportLog(c context.Context, dmid int64) (res []*model.ReportLog, err error) {
if res, err = s.dao.ReportLog(c, dmid); err != nil {
log.Error("s.dao.ReportLog(dmid:%d) error(%v)", dmid, err)
}
return
}
// ChangeReportUserStat change report_user data
func (s *Service) ChangeReportUserStat(c context.Context, dmids []int64) (err error) {
var (
dmidMap = map[int64][]int64{}
)
for _, v := range dmids {
dmidMap[dao.UserTable(v)] = append(dmidMap[dao.UserTable(v)], v)
}
for k, v := range dmidMap {
if _, err = s.dao.UpReportUserState(c, k, v, model.NoticeSend); err != nil {
log.Error("s.dao.UpReportUserState(dmids:%v) error(%v)", v, err)
}
}
return
}
func (s *Service) sendMsgToReporter(c context.Context, rpt *model.Report, block, blockReason, rptReason int64) {
var (
buf bytes.Buffer
)
for _, user := range rpt.RptUsers {
buf.WriteString(fmt.Sprintf("%d,", user.UID))
}
buf.Truncate(buf.Len() - 1)
m := &model.ReportMsg{
Aid: rpt.Aid,
Did: rpt.Did,
Title: rpt.Title,
Msg: rpt.Msg,
RptReason: int8(rptReason),
Uids: buf.String(),
State: rpt.State,
Block: block,
BlockReason: int8(blockReason),
}
select {
case s.msgReporterChan <- m:
default:
log.Error("s.msgReporterChan err, channel full(msg:%v)", m)
}
}
func (s *Service) sendMsgToPoster(c context.Context, rpt *model.Report, block, blockReason, rptReason int64) {
m := &model.ReportMsg{
Aid: rpt.Aid,
Did: rpt.Did,
Title: rpt.Title,
Msg: rpt.Msg,
RptReason: int8(rptReason),
Uids: fmt.Sprint(rpt.UID),
Block: block,
BlockReason: int8(blockReason),
}
select {
case s.msgPosterChan <- m:
default:
log.Error("s.msgPosterChan err, channel full(msg:%v)", m)
}
}
func (s *Service) reduceMoral(c context.Context, uid, moral int64, reason int8, operator, remark string) {
m := &model.ReduceMoral{
UID: uid,
Moral: moral,
Origin: 2,
Reason: reason,
ReasonType: 1,
Operator: operator,
IsNotify: 0,
Remark: remark,
}
select {
case s.reduceMoralChan <- m:
default:
log.Error("s.reduceMoral err, channel full(msg:%v)", m)
}
}
func (s *Service) blockUser(c context.Context, rpt *model.Report, block, blockReason, moral int64, uname string) {
var (
blockEver int64
blockLength int64
)
if block == -1 {
blockEver = 1
} else {
blockLength = block
}
m := &model.BlockUser{
UID: rpt.UID,
BlockForever: blockEver,
BlockTimeLength: blockLength,
BlockRemark: fmt.Sprintf("%s, cid:%d, dmid:%d", model.CheckStateBelong(rpt.State), rpt.Cid, rpt.Did),
Operator: uname,
OriginType: 2,
Moral: moral,
ReasonType: blockReason,
OriginTitle: rpt.Title,
OriginContent: rpt.Msg,
OriginURL: fmt.Sprintf("http://www.bilibili.com/av%d", rpt.Aid),
IsNotify: 0,
}
select {
case s.blockUserChan <- m:
default:
log.Error("s.blockUserChan err, channel full(msg:%v)", m)
}
}
// DMReportJudge send report judge
func (s *Service) DMReportJudge(c context.Context, cidDmids map[int64][]int64, uid int64, uname string) (err error) {
var (
aids []int64
dmids []int64
rptJudges []*model.ReportJudge
)
for _, dmids2 := range cidDmids {
dmids = append(dmids, dmids2...)
}
rpts, err := s.reportsDetail(c, dmids) // get report detail by multi dmids
if len(rpts) == 0 {
log.Error("dmjudge error! id:%v not exist in search", dmids)
return
}
for _, rpt := range rpts {
aids = append(aids, rpt.Aid)
}
arg := &archive.ArgAids2{Aids: aids}
archs, err := s.arcRPC.Archives3(c, arg) // get archive info
if err != nil {
log.Error("s.arcSvc.Archives3(aids:%v) err(%v)", aids, err)
return
}
if len(archs) == 0 {
log.Error("dmjudge error! id:%v not exist in archive rpc", aids)
err = ecode.ArchiveNotExist
return
}
for _, rpt := range rpts {
j := &model.ReportJudge{}
arc, ok := archs[rpt.Aid]
if !ok {
continue
}
arg := &archive.ArgVideo2{
Aid: rpt.Aid,
Cid: rpt.Cid,
}
var vInfo *api.Page
if vInfo, err = s.arcRPC.Video3(c, arg); err != nil {
log.Error("s.arcSvc.Video3(arg:%v) err(%v)", arg, err)
j.Page = 1
} else {
j.Page = int64(vInfo.Page)
}
j.MID = rpt.UID
j.Operator = uname
j.OperID = uid
j.OContent = rpt.Msg
j.OTitle = arc.Title
j.OType = 2
j.OURL = fmt.Sprintf("http://www.bilibili.com/av%d", rpt.Aid)
j.ReasonType = int64(model.RpReasonToJudgeReason(int8(rpt.RpType)))
j.AID = rpt.Aid
j.OID = rpt.Cid
j.RPID = rpt.Did
sendTime, _ := time.Parse("2006-01-02 15:04:05", rpt.SendTime)
j.BTime = sendTime.Unix()
rptJudges = append(rptJudges, j)
}
if len(rptJudges) <= 0 {
return
}
if err = s.dao.SendJudgement(c, rptJudges); err != nil {
log.Error("s.dao.SendJudgement(data:%v) err (%v)", rptJudges, err)
}
_, err = s.ChangeReportStat(c, cidDmids, model.StatJudgeInit, 0, 0, uid, 0, 0, 0, "转风纪委", uname)
if err != nil {
log.Error("s.ChangeReportStat(id:%v) err(%v)", cidDmids, err)
return
}
return
}
// JudgeResult receive judge result
func (s *Service) JudgeResult(c context.Context, cid, dmid, result int64) (err error) {
var (
state int8
remark string
)
res, err := s.dao.Reports(c, cid, []int64{dmid})
if err != nil {
log.Error("s.dao.Reports(cid:%d,dmid:%d) err(%v)", cid, dmid, err)
return
}
if len(res) <= 0 {
log.Error("dmJudge: cid:%d,dmid:%d not found", cid, dmid)
err = ecode.RequestErr
return
}
m := map[int64][]int64{
res[0].Cid: {res[0].Did},
}
if result == 0 {
state = model.StatJudgeIgnore
remark = "风纪委处理:忽略"
} else {
state = model.StatJudgeDelete
remark = "风纪委处理:删除"
}
_, err = s.ChangeReportStat(c, m, state, int8(res[0].RpType), 0, 0, 0, 0, 0, remark, "")
if err != nil {
log.Error("s.ChangeReportStat(cid:%d,dmid:%d) err(%v)", cid, dmid, err)
return
}
return
}
func (s *Service) addRptDelAction(rpt *model.Report) (err error) {
data, err := json.Marshal(rpt)
if err != nil {
log.Error("json.Marshal(%v) error(%v)", rpt, err)
return
}
action := &model.Action{
Oid: rpt.Cid,
Action: model.ActReportDel,
Data: data,
}
s.addAction(action)
return
}

View File

@ -0,0 +1,94 @@
package service
import (
"context"
"testing"
"go-common/app/admin/main/dm/model"
. "github.com/smartystreets/goconvey/convey"
)
func TestChangeReportStat(t *testing.T) {
var (
c = context.TODO()
cidDmids = map[int64][]int64{
9968618: {
719923090, 719923092,
},
}
state = model.StatSecondDelete
reason int8 = 2
notice int8 = 3
adminID int64 = 222
remark = "二审删除"
block int64 = 3
blockReason int64
moral int64 = 10
uname = "zzz delete"
)
Convey("test change report stat", t, func() {
affect, err := svr.ChangeReportStat(c, cidDmids, state, reason, notice, adminID, block, blockReason, moral, remark, uname)
So(err, ShouldNotBeNil)
So(affect, ShouldBeGreaterThan, 0)
})
}
func TestReportLog(t *testing.T) {
var (
c = context.TODO()
dmid int64 = 2
)
Convey("test report log", t, func() {
lg, err := svr.ReportLog(c, dmid)
So(err, ShouldBeNil)
So(lg, ShouldNotBeEmpty)
})
}
func TestReportList(t *testing.T) {
var (
c = context.TODO()
page int64 = 1
size int64 = 100
start = "2017-05-10 00:00:00"
end = "2017-12-13 00:00:00"
order = "rp_time"
sort = "asc"
keyword = ""
tid = []int64{}
rpID = []int64{}
state = []int64{0, 1, 2, 3, 4, 5, 6, 7}
upOp = []int64{0, 1, 2}
rt = &model.Report{}
)
Convey("test report list", t, func() {
list, err := svr.ReportList(c, page, size, start, end, order, sort, keyword, tid, rpID, state, upOp, rt)
So(err, ShouldBeNil)
So(list, ShouldNotBeNil)
})
}
func TestDMReportJudge(t *testing.T) {
var (
err error
c = context.TODO()
cidDmids = map[int64][]int64{
9968618: {719923090}}
)
Convey("test report judge", t, func() {
err = svr.DMReportJudge(c, cidDmids, 122, "zhang1111")
So(err, ShouldBeNil)
})
}
func TestJudgeResult(t *testing.T) {
var (
c = context.TODO()
cid, dmid int64 = 10109084, 719213118
)
Convey("test judge result", t, func() {
err := svr.JudgeResult(c, cid, dmid, 1)
So(err, ShouldBeNil)
})
}

View File

@ -0,0 +1,247 @@
package service
import (
"context"
"fmt"
"strconv"
"strings"
"sync"
"time"
"go-common/app/admin/main/dm/conf"
"go-common/app/admin/main/dm/dao"
oplogDao "go-common/app/admin/main/dm/dao/oplog"
"go-common/app/admin/main/dm/model"
"go-common/app/admin/main/dm/model/oplog"
accountApi "go-common/app/service/main/account/api"
archive "go-common/app/service/main/archive/api/gorpc"
"go-common/library/log"
"go-common/library/log/infoc"
"go-common/library/sync/pipeline/fanout"
)
// Service define Service struct
type Service struct {
// dao
dao *dao.Dao
oplogDao *oplogDao.Dao
// rpc
accountRPC accountApi.AccountClient
arcRPC *archive.Service2
dmOperationLogSvc *infoc.Infoc
bakInfoc *infoc.Infoc
opsLogCh chan *oplog.Infoc
reduceMoralChan chan *model.ReduceMoral
blockUserChan chan *model.BlockUser
msgReporterChan chan *model.ReportMsg
msgPosterChan chan *model.ReportMsg
actionChan chan *model.Action
// async proc
cache *fanout.Fanout
moniOidMap map[int64]struct{}
oidLock sync.Mutex
}
// New new a Service and return.
func New(c *conf.Config) *Service {
s := &Service{
// dao
dao: dao.New(c),
oplogDao: oplogDao.New(c),
// rpc
arcRPC: archive.New2(c.ArchiveRPC),
dmOperationLogSvc: infoc.New(c.Infoc2),
bakInfoc: infoc.New(c.InfocBak),
reduceMoralChan: make(chan *model.ReduceMoral, 1024),
blockUserChan: make(chan *model.BlockUser, 1024),
msgReporterChan: make(chan *model.ReportMsg, 1024),
msgPosterChan: make(chan *model.ReportMsg, 1024),
actionChan: make(chan *model.Action, 1024),
opsLogCh: make(chan *oplog.Infoc, 1024),
cache: fanout.New("cache", fanout.Worker(1), fanout.Buffer(1024)),
moniOidMap: make(map[int64]struct{}),
}
accountRPC, err := accountApi.NewClient(c.AccountRPC)
if err != nil {
panic(err)
}
s.accountRPC = accountRPC
go s.changeReportStatProc()
go s.actionproc()
go s.oplogproc()
go s.monitorproc()
return s
}
// Ping check server ok
func (s *Service) Ping(c context.Context) (err error) {
if err = s.dao.Ping(c); err != nil {
return
}
return
}
func (s *Service) addAction(action *model.Action) {
select {
case s.actionChan <- action:
default:
log.Error("action channel is full,action(%v) is discard", action)
}
}
func (s *Service) actionproc() {
for action := range s.actionChan {
if err := s.dao.SendAction(context.TODO(), fmt.Sprint(action.Oid), action); err != nil {
log.Error("dao.SendAction(%v) error(%v)", action, err)
}
}
}
func (s *Service) changeReportStatProc() {
for {
select {
case msg := <-s.reduceMoralChan:
if err := s.dao.ReduceMoral(context.TODO(), msg); err != nil {
log.Error("s.dao.ReduceMoral(msg:%v) error(%v)", msg, err)
}
case msg := <-s.msgReporterChan:
if err := s.dao.SendMsgToReporter(context.TODO(), msg); err != nil {
log.Error("s.dao.SendMsgToReporter(msg:%v) error(%v)", msg, err)
}
case msg := <-s.msgPosterChan:
if err := s.dao.SendMsgToPoster(context.TODO(), msg); err != nil {
log.Error("s.dao.SendMsgToPoster(msg:%v) error(%v)", msg, err)
}
case msg := <-s.blockUserChan:
if err := s.dao.BlockUser(context.TODO(), msg); err != nil {
log.Error("s.dao.BlockUser(msg:%v) error(%v)", msg, err)
}
}
}
}
func (s *Service) oplogproc() {
for opLog := range s.opsLogCh {
if len(opLog.Subject) == 0 || len(opLog.CurrentVal) == 0 || opLog.Source <= 0 ||
opLog.Operator <= 0 || opLog.OperatorType <= 0 {
log.Warn("oplogproc() it is an illegal log, warn(%v, %v, %v)", opLog.Subject, opLog.Subject, opLog.CurrentVal)
continue
} else {
for _, dmid := range opLog.DMIds {
s.dmOperationLogSvc.Info(opLog.Subject, strconv.FormatInt(opLog.Oid, 10), fmt.Sprint(opLog.Type),
strconv.FormatInt(dmid, 10), opLog.Source.String(), opLog.OriginVal,
opLog.CurrentVal, strconv.FormatInt(opLog.Operator, 10), opLog.OperatorType.String(),
opLog.OperationTime, opLog.Remark)
// 将管理员操作日志额外上报一份(用于验证数据报表完整性)
s.bakInfoc.Info(opLog.Subject, strconv.FormatInt(opLog.Oid, 10), fmt.Sprint(opLog.Type),
strconv.FormatInt(dmid, 10), opLog.Source.String(), opLog.OriginVal,
opLog.CurrentVal, strconv.FormatInt(opLog.Operator, 10), opLog.OperatorType.String(),
opLog.OperationTime, opLog.Remark)
if strings.Contains(opLog.Subject, "\n") {
log.Error("\n found in opLog.Subject(%s)", opLog.Source)
}
}
}
}
}
// OpLog put a new infoc format operation log into the channel
func (s *Service) OpLog(c context.Context, cid, operator int64, typ int32, dmids []int64, subject, originVal, currentVal, remark string, source oplog.Source, operatorType oplog.OperatorType) (err error) {
infoLog := new(oplog.Infoc)
infoLog.Oid = cid
infoLog.Type = typ
infoLog.DMIds = dmids
infoLog.Subject = subject
infoLog.OriginVal = originVal
infoLog.CurrentVal = currentVal
infoLog.OperationTime = strconv.FormatInt(time.Now().Unix(), 10)
infoLog.Source = source
infoLog.OperatorType = operatorType
infoLog.Operator = operator
infoLog.Remark = remark
select {
case s.opsLogCh <- infoLog:
default:
err = fmt.Errorf("opsLogCh full")
log.Error("opsLogCh full (%v)", infoLog)
}
return
}
// QueryOpLogs query operation logs of damku equals dmid
func (s *Service) QueryOpLogs(c context.Context, dmid int64) (infos []*oplog.InfocResult, err error) {
result, err := s.oplogDao.QueryOpLogs(c, dmid)
if err != nil {
return
}
for _, logVal := range result {
var (
tmp = &oplog.InfocResult{}
)
val, err := strconv.Atoi(logVal.CurrentVal)
if err != nil {
err = nil
continue
}
switch logVal.Subject {
case "status":
tmp.Subject = model.StateDesc(int32(val))
case "pool":
if val == 0 {
tmp.Subject = "普通弹幕池"
} else if val == 1 {
tmp.Subject = "字幕弹幕池"
} else if val == 2 {
tmp.Subject = "特殊弹幕池"
}
case "attribute":
if val == 2 || (int32(val)>>model.AttrProtect)&int32(1) == 1 {
tmp.Subject = "弹幕保护"
} else if val == 3 || (int32(val)>>model.AttrProtect)&int32(1) == 0 {
tmp.Subject = "取消弹幕保护"
}
default:
tmp.Subject = logVal.Subject
}
tmp.CurrentVal = logVal.CurrentVal
tmp.OperatorType = logVal.OperatorType
if logVal.OperatorType == "用户" || logVal.OperatorType == "UP主" {
mid, _ := strconv.ParseInt(logVal.Operator, 10, 64)
arg3 := &accountApi.MidReq{Mid: mid}
uInfo, err := s.accountRPC.Info3(c, arg3)
if err != nil {
tmp.Operator = logVal.Operator
log.Error("s.accRPC.Info2(%v) error(%v)", arg3, err)
err = nil
} else {
tmp.Operator = uInfo.GetInfo().GetName()
}
} else {
tmp.Operator = logVal.Operator
}
OperationTimeStamp, _ := strconv.ParseInt(logVal.OperationTime, 10, 64)
tmp.OperationTime = time.Unix(OperationTimeStamp, 0).Format("2006-01-02 15:04:05")
tmp.Remark = "操作来源:" + logVal.Source + ";操作员身份:" + logVal.OperatorType + ";备注:" + logVal.Remark
infos = append(infos, tmp)
}
return
}
func (s *Service) monitorproc() {
for {
time.Sleep(3 * time.Second)
s.oidLock.Lock()
oidMap := s.moniOidMap
s.moniOidMap = make(map[int64]struct{})
s.oidLock.Unlock()
for oid := range oidMap {
sub, err := s.dao.Subject(context.TODO(), model.SubTypeVideo, oid)
if err != nil || sub == nil {
continue
}
if err := s.updateMonitorCnt(context.TODO(), sub); err != nil {
log.Error("s.updateMonitorCnt(%+v) error(%v)", sub, err)
}
}
}
}

View File

@ -0,0 +1,76 @@
package service
import (
"context"
"flag"
"os"
"path/filepath"
"testing"
"go-common/app/admin/main/dm/conf"
"go-common/app/admin/main/dm/model/oplog"
"go-common/library/log"
manager "go-common/library/queue/databus/report"
. "github.com/smartystreets/goconvey/convey"
)
var (
svr *Service
)
func TestMain(m *testing.M) {
var (
err error
)
dir, _ := filepath.Abs("../cmd/dm-admin-test.toml")
if err = flag.Set("conf", dir); err != nil {
panic(err)
}
if err = conf.Init(); err != nil {
panic(err)
}
// log.Init(nil)
svr = New(conf.Conf)
// manager log init
manager.InitManager(conf.Conf.ManagerLog)
os.Exit(m.Run())
}
func WithService(f func(s *Service)) func() {
return func() {
f(svr)
}
}
func TestOpLog(t *testing.T) {
var (
c = context.TODO()
cid int64 = 12
typ int32 = 1
operator int64 = 219
dmids = []int64{719150137}
subject = "status"
originVal = "1"
currentVal = "2"
remark = "备注"
source = oplog.SourceManager
operatorType = oplog.OperatorAdmin
)
Convey("OpLog", t, WithService(func(s *Service) {
err := svr.OpLog(c, cid, operator, typ, dmids, subject, originVal, currentVal, remark, source, operatorType)
So(err, ShouldBeNil)
}))
}
func TestQueryOpLogs(t *testing.T) {
var (
c = context.TODO()
dmid int64 = 719150137
)
Convey("QueryOpLogs", t, WithService(func(s *Service) {
objs, err := svr.QueryOpLogs(c, dmid)
log.Info("%v", objs)
So(err, ShouldBeNil)
}))
}

View File

@ -0,0 +1,21 @@
package service
import (
"context"
"go-common/library/log"
)
const (
_bnjShieldFileName = "bnj_shield.csv"
_bnjShieldBucket = "dm"
)
// DmShield .
func (s *Service) DmShield(c context.Context, bs []byte) (err error) {
if err = s.dao.Upload(c, _bnjShieldBucket, _bnjShieldFileName, "text/csv", bs); err != nil {
log.Error("DmShield(err:%v)", err)
return
}
return
}

View File

@ -0,0 +1,167 @@
package service
import (
"context"
"time"
"go-common/app/admin/main/dm/model"
"go-common/app/service/main/archive/api"
"go-common/app/service/main/archive/model/archive"
"go-common/library/log"
manager "go-common/library/queue/databus/report"
)
// ArchiveList get archive list.
func (s *Service) ArchiveList(c context.Context, req *model.ArchiveListReq) (res *model.ArchiveResult, err error) {
var (
oids, aids []int64
aidMap = make(map[int64]struct{})
arcMap = make(map[int64]*model.ArcVideo)
archiveTypes = make(map[int64]*model.ArchiveType)
subs map[int64]*model.Subject
r = &model.SearchSubjectReq{
State: req.State,
Attrs: req.Attrs,
Pn: req.Pn,
Ps: req.Ps,
Sort: req.Sort,
Order: req.Order,
}
)
res = &model.ArchiveResult{}
res.Page = &model.Page{}
if req.ID > 0 {
switch req.IDType {
case "oid":
r.Oids = append(r.Oids, req.ID)
case "mid":
r.Mids = append(r.Mids, req.ID)
case "aid":
r.Aids = append(r.Aids, req.ID)
case "ep", "ss":
if r.Aids, r.Oids, err = s.dao.SeasonInfos(c, req.IDType, req.ID); err != nil {
err = nil
return
}
}
}
data := make([]*model.DMSubject, 0)
if len(r.Aids) > 0 && req.Page >= 1 {
var (
pages []*api.Page
arg = archive.ArgAid2{Aid: r.Aids[0]}
)
if pages, err = s.arcRPC.Page3(c, &arg); err != nil {
log.Error("arcRPC.Page3(%v) error(%v)", arg, err)
return
}
if len(pages) < int(req.Page) {
log.Error("req.Page too big(%d) error(%v)", req.Page, err)
return
}
r.Oids = append(r.Oids, pages[req.Page-1].Cid)
}
res = new(model.ArchiveResult)
if oids, res.Page, err = s.dao.SearchSubject(c, r); err != nil {
return
}
if subs, err = s.dao.Subjects(c, model.SubTypeVideo, oids); err != nil {
return
}
for _, oid := range oids {
if sub, ok := subs[oid]; ok {
s := &model.DMSubject{
OID: sub.Oid,
Type: sub.Type,
AID: sub.Pid,
ACount: sub.ACount,
Limit: sub.Maxlimit,
CTime: sub.Ctime,
MTime: sub.Mtime,
MID: sub.Mid,
State: sub.State,
}
data = append(data, s)
}
}
if len(data) <= 0 {
return
}
for _, idx := range data {
if _, ok := aidMap[idx.AID]; !ok {
aidMap[idx.AID] = struct{}{}
aids = append(aids, idx.AID)
}
}
if arcMap, err = s.dao.ArchiveVideos(c, aids); err != nil {
return
}
if archiveTypes, err = s.dao.TypeInfo(c); err != nil {
return
}
for _, idx := range data {
info, ok := arcMap[idx.AID] // get archive info
if !ok {
continue
}
idx.Title = info.Archive.Title
idx.TID = info.Archive.TID
if v, ok := archiveTypes[idx.TID]; ok {
idx.TName = v.Name
}
if len(info.Videos) > 0 { // get ep_title name
for _, video := range info.Videos {
if video.CID == idx.OID {
idx.ETitle = video.Title
}
}
}
}
res.ArcLists = data
return
}
// UptSubjectsState change oids subject state and send manager log.
func (s *Service) UptSubjectsState(c context.Context, tp int32, uid int64, uname string, oids []int64, state int32, comment string) (err error) {
var affect int64
for _, oid := range oids {
if affect, err = s.dao.UpSubjectState(c, tp, oid, state); err != nil {
return
}
if affect == 0 {
log.Info("s.UpSubjectState affect=0 oid(%d)", oid)
continue
}
managerInfo := &manager.ManagerInfo{
UID: uid,
Uname: uname,
Business: model.DMLogBizID,
Type: int(tp),
Oid: oid,
Ctime: time.Now(),
Content: map[string]interface{}{
"comment": comment,
},
}
if state == model.SubStateOpen {
managerInfo.Action = "开启弹幕池"
} else {
managerInfo.Action = "关闭弹幕池"
}
manager.Manager(managerInfo)
log.Info("s.managerLogSend(%+v)", managerInfo)
}
return
}
// UpSubjectMaxLimit update maxlimit in dm subject.
func (s *Service) UpSubjectMaxLimit(c context.Context, tp int32, oid, maxlimit int64) (err error) {
_, err = s.dao.UpSubjectMaxlimit(c, tp, oid, maxlimit)
return
}
// SubjectLog get subject log
func (s *Service) SubjectLog(c context.Context, tp int32, oid int64) (data []*model.SubjectLog, err error) {
data, err = s.dao.SearchSubjectLog(c, tp, oid)
return
}

View File

@ -0,0 +1,57 @@
package service
import (
"context"
"go-common/app/admin/main/dm/model"
"testing"
"github.com/smartystreets/goconvey/convey"
)
func TestArchiveList(t *testing.T) {
req := &model.ArchiveListReq{
ID: 34261,
IDType: "oid",
Sort: "desc",
Order: "mtime",
Pn: 1,
Ps: 50,
Page: int64(model.CondIntNil),
State: int64(model.CondIntNil),
}
convey.Convey("test last archive list", t, func() {
res, err := svr.ArchiveList(context.TODO(), req)
convey.So(err, convey.ShouldBeNil)
convey.So(res, convey.ShouldNotBeEmpty)
t.Logf("===%+v", res.Page)
for _, v := range res.ArcLists {
t.Logf("===%+v", v)
}
})
}
func TestServiceUptSubjectsState(t *testing.T) {
convey.Convey("UptSubjectsState", t, func() {
err := svr.UptSubjectsState(context.TODO(), 1, 111, "test", []int64{1221}, 1, "aaaaa")
convey.So(err, convey.ShouldBeNil)
})
}
func TestServiceUpSubjectMaxLimit(t *testing.T) {
convey.Convey("UpSubjectMaxLimit", t, func() {
err := svr.UpSubjectMaxLimit(context.TODO(), 1, 10131812, 333)
convey.So(err, convey.ShouldBeNil)
})
}
func TestServiceSubjectLog(t *testing.T) {
convey.Convey("SubjectLog", t, func() {
data, err := svr.SubjectLog(context.TODO(), 1, 1221)
convey.So(err, convey.ShouldBeNil)
convey.So(data, convey.ShouldNotBeNil)
for _, v := range data {
t.Logf("====%+v", v)
}
})
}

View File

@ -0,0 +1,357 @@
package service
import (
"context"
"fmt"
"sync"
"time"
"go-common/app/admin/main/dm/model"
accountApi "go-common/app/service/main/account/api"
"go-common/app/service/main/archive/api"
archiveMdl "go-common/app/service/main/archive/model/archive"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/sync/errgroup"
)
const (
_workFlowSubtitleBid = 14
)
// SubtitleLanList .
func (s *Service) SubtitleLanList(c context.Context) (res map[int64]string, err error) {
var (
sLans []*model.SubtitleLan
)
if sLans, err = s.dao.SubtitleLans(c); err != nil {
return
}
res = make(map[int64]string)
for _, sLan := range sLans {
res[sLan.Code] = sLan.DocZh
}
return
}
// WorkFlowEditSubtitle .
func (s *Service) WorkFlowEditSubtitle(c context.Context, arg *model.WorkFlowSubtitleArg) (err error) {
var (
argEdit *model.EditSubtitleArg
status model.SubtitleStatus
)
if arg == nil || arg.Object == nil || len(arg.Object.Ids) == 0 || len(arg.Targets) == 0 {
err = ecode.RequestErr
return
}
switch arg.Object.DisposeMode {
case model.WorkFlowSubtitleDisposeManagerBack:
status = model.SubtitleStatusManagerBack
case model.WorkFlowSubtitleDisposeManagerDelete:
status = model.SubtitleStatusManagerRemove
default:
return
}
for _, target := range arg.Targets {
if target == nil {
continue
}
argEdit = &model.EditSubtitleArg{
Oid: target.Oid,
SubtileID: target.Eid,
Status: uint8(status),
}
// 容错
if argEdit.Oid == 0 {
continue
}
if err = s.editSubtitle(c, argEdit, false); err != nil {
log.Error("s.EditSubtitle(arg:%+v),error(%v)", argEdit, err)
err = nil // ignore error
return
}
}
return
}
// EditSubtitle .
func (s *Service) EditSubtitle(c context.Context, arg *model.EditSubtitleArg) (err error) {
return s.editSubtitle(c, arg, true)
}
func (s *Service) editSubtitle(c context.Context, arg *model.EditSubtitleArg, removeWorkFlow bool) (err error) {
// 更新表
var (
subtitle *model.Subtitle
argStatus = model.SubtitleStatus(arg.Status)
subtitleLans model.SubtitleLans
sLans []*model.SubtitleLan
err1 error
lanDoc string
archiveInfo *api.Arc
archiveName string
)
if subtitle, err = s.dao.GetSubtitle(c, arg.Oid, arg.SubtileID); err != nil {
log.Error("params(oid:%v,subtitleID:%v),error(%v)", arg.Oid, arg.SubtileID, err)
return
}
if subtitle == nil {
err = ecode.NothingFound
return
}
if argStatus == subtitle.Status {
err = ecode.SubtitleStatusUnValid
return
}
if subtitle.Status != model.SubtitleStatusPublish && argStatus != model.SubtitleStatusPublish {
arg.NotifyUpper = false
}
switch argStatus {
case model.SubtitleStatusDraft, model.SubtitleStatusToAudit,
model.SubtitleStatusAuditBack, model.SubtitleStatusRemove,
model.SubtitleStatusPublish, model.SubtitleStatusManagerBack,
model.SubtitleStatusManagerRemove:
default:
err = ecode.SubtitleStatusUnValid
return
}
if err = s.changeSubtitleStatus(c, subtitle, argStatus); err != nil {
log.Error("params(subtitle:%+v,status:%v),error(%v)", subtitle, arg.Status, err)
return
}
if arg.NotifyAuthor || arg.NotifyUpper {
if sLans, err1 = s.dao.SubtitleLans(c); err1 == nil {
subtitleLans = model.SubtitleLans(sLans)
}
_, lanDoc = subtitleLans.GetByID(int64(subtitle.Lan))
if archiveInfo, err1 = s.arcRPC.Archive3(c, &archiveMdl.ArgAid2{
Aid: subtitle.Aid,
}); err1 != nil {
log.Error("s.arcRPC.Archive3(aid:%v),error(%v)", subtitle.Aid, err1)
err1 = nil
} else {
archiveName = archiveInfo.Title
}
}
if arg.NotifyAuthor {
argUser := &model.NotifySubtitleUser{
Mid: subtitle.Mid,
Aid: subtitle.Aid,
Oid: subtitle.Oid,
SubtitleID: subtitle.ID,
ArchiveName: archiveName,
LanDoc: lanDoc,
Status: model.StatusContent[uint8(subtitle.Status)],
}
if err1 = s.dao.SendMsgToSubtitleUser(c, argUser); err1 != nil {
log.Error("SendMsgToSubtitleUser(argUser:%+v),error(%v)", argUser, err1)
err1 = nil
}
}
if arg.NotifyUpper {
var (
accountInfo *accountApi.InfoReply
authorName string
)
if accountInfo, err1 = s.accountRPC.Info3(c, &accountApi.MidReq{
Mid: subtitle.Mid,
}); err1 != nil {
log.Error("s.accRPC.Info3(mid:%v),error(%v)", subtitle.Mid, err1)
err1 = nil
} else {
authorName = accountInfo.GetInfo().GetName()
}
argUp := &model.NotifySubtitleUp{
Mid: subtitle.UpMid,
AuthorID: subtitle.Mid,
AuthorName: authorName,
Aid: subtitle.Aid,
Oid: subtitle.Oid,
SubtitleID: subtitle.ID,
ArchiveName: archiveName,
LanDoc: lanDoc,
Status: model.StatusContent[uint8(subtitle.Status)],
}
if err1 = s.dao.SendMsgToSubtitleUp(c, argUp); err1 != nil {
log.Error("SendMsgToSubtitleUp(argUp:%+v),error(%v)", argUp, err1)
err1 = nil
}
}
if removeWorkFlow && (argStatus == model.SubtitleStatusRemove || argStatus == model.SubtitleStatusManagerRemove) {
if err1 := s.dao.WorkFlowAppealDelete(c, _workFlowSubtitleBid, subtitle.Oid, subtitle.ID); err1 != nil {
log.Error("s.dao.WorkFlowAppealDelete(oid:%v,subtitleID:%v),error(%v)", subtitle.Oid, subtitle.ID, err1)
return
}
}
return
}
// TODO 确认状态扭转
func (s *Service) changeSubtitleStatus(c context.Context, subtitle *model.Subtitle, status model.SubtitleStatus) (err error) {
var (
sc *model.SubtitleContext
hasDraft bool
)
sc = &model.SubtitleContext{}
sc.Build(subtitle.Status, status)
subtitle.PubTime = time.Now().Unix()
if sc.CheckHasDraft {
if hasDraft, err = s.CheckHasDraft(c, subtitle); err != nil {
log.Error("params(subtitle:%+v),error(%v)", subtitle, err)
return
}
if hasDraft {
err = ecode.SubtitleAlreadyHasDraft
return
}
subtitle.PubTime = 0
}
subtitle.Status = status
if sc.RebuildPub {
if err = s.RebuildSubtitle(c, subtitle); err != nil {
log.Error("RebuildSubtitle.params(subtitle:%+v),error(%v)", subtitle, err)
return
}
} else {
if err = s.dao.UpdateSubtitle(c, subtitle); err != nil {
log.Error("UpdateSubtitle.params(subtitle:%+v),error(%v)", subtitle, err)
return
}
}
if sc.DraftCache {
s.dao.DelSubtitleDraftCache(c, subtitle.Oid, subtitle.Type, subtitle.Mid, subtitle.Lan)
}
if sc.SubtitleCache {
s.dao.DelSubtitleCache(c, subtitle.Oid, subtitle.ID)
}
if sc.RebuildPub {
s.dao.DelVideoSubtitleCache(c, subtitle.Oid, subtitle.Type)
}
return
}
// SubtitleList .
func (s *Service) SubtitleList(c context.Context, arg *model.SubtitleArg) (res *model.SubtitleList, err error) {
var (
searchResult *model.SearchSubtitleResult
oidSubtitleIds map[int64][]int64
eg errgroup.Group
lock sync.Mutex
subtitleMap map[string]*model.Subtitle
searchSubtitles []*model.SearchSubtitle
searchSubtitle *model.SearchSubtitle
subtitle *model.Subtitle
ok bool
aids []int64
aidMap map[int64]struct{}
archives map[int64]*api.Arc
archive *api.Arc
archiveVideo *api.Page
subtitleLans model.SubtitleLans
searchArg *model.SubtitleSearchArg
)
if arg.Ps > 100 {
err = ecode.RequestErr
return
}
key := func(oid, subtitleID int64) string {
return fmt.Sprintf("%d_%d", oid, subtitleID)
}
if sLans, err1 := s.dao.SubtitleLans(c); err1 == nil {
subtitleLans = model.SubtitleLans(sLans)
}
lanCode := subtitleLans.GetByLan(arg.Lan)
searchArg = &model.SubtitleSearchArg{
Aid: arg.Aid,
Oid: arg.Oid,
Mid: arg.Mid,
UpperMid: arg.UpperMid,
Status: arg.Status,
Lan: uint8(lanCode),
Ps: arg.Ps,
Pn: arg.Pn,
}
if searchResult, err = s.dao.SearchSubtitle(c, searchArg); err != nil {
log.Error("params(arg:%+v).error(%v)", arg, err)
return
}
if searchResult == nil || len(searchResult.Result) == 0 {
err = ecode.NothingFound
return
}
oidSubtitleIds = make(map[int64][]int64)
subtitleMap = make(map[string]*model.Subtitle)
aidMap = make(map[int64]struct{})
for _, r := range searchResult.Result {
oidSubtitleIds[r.Oid] = append(oidSubtitleIds[r.Oid], r.ID)
}
for oid, subtitleIds := range oidSubtitleIds {
tempOid := oid
tempSubtitleIds := subtitleIds
eg.Go(func() (err error) {
var subtitles []*model.Subtitle
if subtitles, err = s.dao.GetSubtitles(context.Background(), tempOid, tempSubtitleIds); err != nil {
log.Error("params(oid:%v,subtitleIds:%+v).error(%v)", tempOid, tempSubtitleIds, err)
return
}
for _, subtitle := range subtitles {
lock.Lock()
aidMap[subtitle.Aid] = struct{}{}
subtitleMap[key(subtitle.Oid, subtitle.ID)] = subtitle
lock.Unlock()
}
return
})
}
if err = eg.Wait(); err != nil {
return
}
for aid := range aidMap {
aids = append(aids, aid)
}
if archives, err = s.arcRPC.Archives3(c, &archiveMdl.ArgAids2{
Aids: aids,
}); err != nil {
log.Error("prams(aid:%v),error(%v)", aids, err)
archives = make(map[int64]*api.Arc)
err = nil
}
searchSubtitles = make([]*model.SearchSubtitle, 0, len(searchResult.Result))
for _, r := range searchResult.Result {
if subtitle, ok = subtitleMap[key(r.Oid, r.ID)]; !ok {
continue
}
lan, lanDoc := subtitleLans.GetByID(int64(subtitle.Lan))
searchSubtitle = &model.SearchSubtitle{
ID: subtitle.ID,
Oid: subtitle.Oid,
Aid: subtitle.Aid,
AuthorID: subtitle.Mid,
Status: uint8(subtitle.Status),
Lan: lan,
LanDoc: lanDoc,
IsSign: subtitle.IsSign,
IsLock: subtitle.IsLock,
Mtime: subtitle.Mtime,
SubtitleURL: subtitle.SubtitleURL,
}
if archive, ok = archives[subtitle.Aid]; ok {
searchSubtitle.ArchiveName = archive.Title
}
if archiveVideo, err = s.arcRPC.Video3(c, &archiveMdl.ArgVideo2{
Aid: subtitle.Aid,
Cid: subtitle.Oid,
}); err != nil {
log.Error("params(aid:%v,oid:%v) error(%v)", subtitle.Aid, subtitle.Oid, err)
err = nil
} else {
searchSubtitle.VideoName = archiveVideo.Part
}
searchSubtitles = append(searchSubtitles, searchSubtitle)
}
res = &model.SubtitleList{
Page: searchResult.Page,
}
res.Subtitles = searchSubtitles
return
}

View File

@ -0,0 +1,82 @@
package service
import (
"context"
"time"
"go-common/app/admin/main/dm/model"
"go-common/library/database/sql"
"go-common/library/log"
)
// SubtitleStatusList .
func (s *Service) SubtitleStatusList(c context.Context) (res map[uint8]string, err error) {
return model.StatusContent, nil
}
// CheckHasDraft .
func (s *Service) CheckHasDraft(c context.Context, subtitle *model.Subtitle) (ok bool, err error) {
var (
draftCount int64
)
if draftCount, err = s.dao.CountSubtitleDraft(c, subtitle.Oid, subtitle.Mid, subtitle.Lan, subtitle.Type); err != nil {
log.Error("CheckHasDraft,params(subtitle:%+v),error(%v)", subtitle, err)
return
}
if draftCount > 0 {
ok = true
}
return
}
// RebuildSubtitle .
// need transtaion
// 1、更新自身状态
// 2、重新查询发布的字幕id插入到发布表
// 3、删除缓存
func (s *Service) RebuildSubtitle(c context.Context, subtitle *model.Subtitle) (err error) {
var (
tx *sql.Tx
subtitlePublishID int64
subtitlePub *model.SubtitlePub
)
switch subtitle.Status {
case model.SubtitleStatusDraft, model.SubtitleStatusToAudit:
subtitle.PubTime = 0
default:
subtitle.PubTime = time.Now().Unix()
}
if tx, err = s.dao.BeginBiliDMTrans(c); err != nil {
return
}
defer func() {
if err != nil {
tx.Rollback()
}
if err = tx.Commit(); err != nil {
return
}
}()
if err = s.dao.TxUpdateSubtitle(tx, subtitle); err != nil {
log.Error("RebuildSubtitle.TxUpdateSubtitle(subtitle:%+v),error(%v)", subtitle, err)
return
}
if subtitlePublishID, err = s.dao.TxGetSubtitleID(tx, subtitle.Oid, subtitle.Type, subtitle.Lan); err != nil {
log.Error("RebuildSubtitle.TxGetSubtitleID(params:%+v),error(%v)", subtitle, err)
return
}
subtitlePub = &model.SubtitlePub{
Oid: subtitle.Oid,
Type: subtitle.Type,
Lan: subtitle.Lan,
SubtitleID: subtitlePublishID,
}
if subtitlePublishID <= 0 {
subtitlePub.IsDelete = true
}
if err = s.dao.TxUpdateSubtitlePub(tx, subtitlePub); err != nil {
log.Error("RebuildSubtitle.TxUpdateSubtitlePub(subtitlePub:%+v),error(%v)", subtitlePub, err)
return
}
return
}

View File

@ -0,0 +1,52 @@
package service
import (
"context"
"go-common/app/admin/main/dm/model"
"go-common/library/log"
)
// SubtitleSwitch .
func (s *Service) SubtitleSwitch(c context.Context, aid int64, allow bool, closed bool) (err error) {
var (
subtitleSubject *model.SubtitleSubject
attr = model.AttrNo
)
if subtitleSubject, err = s.getSubtitleSubject(c, aid); err != nil {
log.Error("SubtitleSwitch(aid:%v) error(%v)", aid, err)
return
}
if subtitleSubject == nil {
subtitleSubject = &model.SubtitleSubject{
Aid: aid,
}
}
subtitleSubject.Allow = allow
if closed {
attr = model.AttrYes
}
subtitleSubject.AttrSet(attr, model.AttrSubtitleClose)
if err = s.addSubtitleSubject(c, subtitleSubject); err != nil {
log.Error("SubtitleSwitch(subtitleSubject:%+v) error(%v)", subtitleSubject, err)
return
}
return
}
func (s *Service) getSubtitleSubject(c context.Context, aid int64) (subtitleSubject *model.SubtitleSubject, err error) {
if subtitleSubject, err = s.dao.GetSubtitleSubject(c, aid); err != nil {
return
}
return
}
func (s *Service) addSubtitleSubject(c context.Context, subtitleSubject *model.SubtitleSubject) (err error) {
if err = s.dao.AddSubtitleSubject(c, subtitleSubject); err != nil {
return
}
if err = s.dao.DelSubtitleSubjectCache(c, subtitleSubject.Aid); err != nil {
return
}
return
}

View File

@ -0,0 +1,261 @@
package service
import (
"bytes"
"context"
"encoding/csv"
"fmt"
"io/ioutil"
"math/big"
"net"
"net/http"
"regexp"
"strings"
"time"
"go-common/app/admin/main/dm/model"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/xstr"
)
var (
_csvTaskTitle = []string{"dmid", "oid", "mid", "state", "msg", "ip", "ctime"}
)
// TaskList .
func (s *Service) TaskList(c context.Context, v *model.TaskListArg) (res *model.TaskList, err error) {
taskSQL := make([]string, 0)
if v.Creator != "" {
taskSQL = append(taskSQL, fmt.Sprintf("creator LIKE %q", "%"+v.Creator+"%"))
}
if v.Reviewer != "" {
taskSQL = append(taskSQL, fmt.Sprintf("reviewer LIKE %q", "%"+v.Reviewer+"%"))
}
if v.State >= 0 {
taskSQL = append(taskSQL, fmt.Sprintf("state=%d", v.State))
}
if v.Title != "" {
taskSQL = append(taskSQL, fmt.Sprintf("title LIKE %q", "%"+v.Title+"%"))
}
if v.Ctime != "" {
taskSQL = append(taskSQL, fmt.Sprintf("ctime>=%q", v.Ctime))
}
tasks, total, err := s.dao.TaskList(c, taskSQL, v.Pn, v.Ps)
if err != nil {
return
}
res = &model.TaskList{
Result: tasks,
Page: &model.PageInfo{
Num: v.Pn,
Size: v.Ps,
Total: total,
},
}
return
}
// AddTask .
func (s *Service) AddTask(c context.Context, v *model.AddTaskArg) (err error) {
var taskID int64
var sub int32
tx, err := s.dao.BeginBiliDMTrans(c)
if err != nil {
log.Error("tx.BeginBiliDMTrans error(%v)", err)
return
}
defer func() {
if err != nil {
if err1 := tx.Rollback(); err1 != nil {
log.Error("tx.Rollback() error(%v)", err1)
}
return
}
if err = tx.Commit(); err != nil {
log.Error("tx.Commit() error(%v)", err)
}
}()
if v.Regex != "" {
if len([]rune(v.Regex)) > model.TaskRegexLen {
err = ecode.DMTaskRegexTooLong
return
}
if _, err = regexp.Compile(v.Regex); err != nil {
log.Error("regexp.Compile(v.Regex:%s) error(%v)", v.Regex, err)
err = ecode.DMTaskRegexIllegal
return
}
}
if v.Operation >= 0 {
sub = 1
}
if taskID, err = s.dao.AddTask(tx, v, sub); err != nil {
return
}
if sub > 0 {
_, err = s.dao.AddSubTask(tx, taskID, v.Operation, v.OpTime, v.OpRate)
}
return
}
// ReviewTask .
func (s *Service) ReviewTask(c context.Context, v *model.ReviewTaskArg) (err error) {
if v.State == model.TaskReviewPass {
var (
task *model.TaskView
sTime, eTime time.Time
)
if task, err = s.dao.TaskView(c, v.ID); err != nil {
return
}
taskSQL := make([]string, 0)
if task.Regex != "" {
taskSQL = append(taskSQL, fmt.Sprintf("content.msg regexp %q", task.Regex))
}
if task.KeyWords != "" {
taskSQL = append(taskSQL, fmt.Sprintf("content.msg like %q", "%"+task.KeyWords+"%"))
}
if task.IPs != "" {
ips := xstr.JoinInts(ipsToInts(task.IPs))
taskSQL = append(taskSQL, fmt.Sprintf("content.ip in (%s)", ips))
}
if task.Mids != "" {
taskSQL = append(taskSQL, fmt.Sprintf("index.mid in (%s)", task.Mids))
}
if task.Cids != "" {
taskSQL = append(taskSQL, fmt.Sprintf("index.oid in (%s)", task.Cids))
}
if task.Start != "" {
if sTime, err = time.ParseInLocation("2006-01-02 15:04:05", task.Start, time.Local); err != nil {
return
}
taskSQL = append(taskSQL, fmt.Sprintf("content.log_date>=%s", sTime.Format("20060102")))
taskSQL = append(taskSQL, fmt.Sprintf("content.ctime>=%q", task.Start))
}
if task.End != "" {
if eTime, err = time.ParseInLocation("2006-01-02 15:04:05", task.End, time.Local); err != nil {
return
}
taskSQL = append(taskSQL, fmt.Sprintf("content.log_date<=%s", eTime.Format("20060102")))
taskSQL = append(taskSQL, fmt.Sprintf("content.ctime<=%q", task.End))
}
if v.Topic, err = s.dao.SendTask(c, taskSQL); err != nil {
// err = nil
// v.State = model.TaskStateFailed
return
}
}
_, err = s.dao.ReviewTask(c, v)
return
}
// EditTaskState .
func (s *Service) EditTaskState(c context.Context, v *model.EditTasksStateArg) (err error) {
if _, err = s.dao.EditTaskState(c, v); err != nil {
return
}
if v.State == model.TaskStateRun {
_, err = s.dao.EditTaskPriority(c, v.IDs, time.Now().Unix())
}
return
}
// TaskView .
func (s *Service) TaskView(c context.Context, v *model.TaskViewArg) (task *model.TaskView, err error) {
if task, err = s.dao.TaskView(c, v.ID); err != nil || task == nil {
return
}
if task.SubTask, err = s.dao.SubTask(c, task.ID); err != nil || task.SubTask == nil {
return
}
task.Tcount = task.SubTask.Tcount
return
}
// TaskCsv .
func (s *Service) TaskCsv(c context.Context, id int64) (bs []byte, err error) {
var (
task *model.TaskView
buf *bytes.Buffer
csvWriter *csv.Writer
)
if task, err = s.dao.TaskView(c, id); err != nil {
return
}
if task == nil || len(task.Result) == 0 {
err = ecode.NothingFound
return
}
res, err := http.Get(task.Result)
if err != nil {
log.Error("s.HttpGet(%s) error(%v)", task.Result, err)
return
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
err = ecode.NothingFound
return
}
resp, err := ioutil.ReadAll(res.Body)
if err != nil {
log.Error("s.ioutilRead error(%v)", err)
return
}
buf = &bytes.Buffer{}
csvWriter = csv.NewWriter(buf)
if err = csvWriter.Write(_csvTaskTitle); err != nil {
log.Error("csvWriter.Write(%v) erorr(%v)", _csvTaskTitle, err)
return
}
lines := bytes.Split(resp, []byte("\n"))
if len(lines) == 0 {
err = ecode.NothingFound
return
}
for _, line := range lines {
var (
items []string
)
fields := bytes.Split(line, []byte("\001"))
if len(fields) < 7 {
log.Error("fields lenth too small:%d", len(fields))
continue
}
for _, field := range fields {
items = append(items, string(field))
}
if err = csvWriter.Write(items); err != nil {
log.Error("csvWriter.Write(%v) erorr(%v)", items, err)
return
}
}
csvWriter.Flush()
if err = csvWriter.Error(); err != nil {
log.Error("csvWriter.Error(%v)", err)
return
}
bs = buf.Bytes()
if len(bs) == 0 {
err = ecode.NothingFound
}
return
}
func ipsToInts(ips string) (ipInts []int64) {
ipStrs := strings.Split(ips, ",")
ipInts = make([]int64, 0, len(ipStrs))
for _, ipStr := range ipStrs {
ipInts = append(ipInts, ipToInt(ipStr))
}
return
}
func ipToInt(ip string) (ipInt int64) {
ret := big.NewInt(0)
if net.ParseIP(ip) == nil {
return
}
ret.SetBytes(net.ParseIP(ip).To4())
return ret.Int64()
}

View File

@ -0,0 +1,108 @@
package service
import (
"context"
"testing"
"go-common/app/admin/main/dm/model"
"github.com/smartystreets/goconvey/convey"
)
func TestServiceTaskList(t *testing.T) {
convey.Convey("TaskList", t, func(ctx convey.C) {
var (
c = context.Background()
v = &model.TaskListArg{
Pn: 1,
Ps: 10,
}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
res, err := svr.TaskList(c, v)
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)
for _, v := range res.Result {
t.Logf("=====%+v", v)
}
})
})
})
}
func TestServiceAddTask(t *testing.T) {
convey.Convey("AddTask", t, func(ctx convey.C) {
var (
c = context.Background()
v = &model.AddTaskArg{
IPs: "172.1.1.1",
Start: "2016-10-30 16:12:21",
End: "2018-10-30 16:12:21",
OpTime: "2018-10-30 16:12:21",
}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := svr.AddTask(c, v)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestServiceEditTaskState(t *testing.T) {
convey.Convey("EditTaskState", t, func(ctx convey.C) {
var (
c = context.Background()
v = &model.EditTasksStateArg{
IDs: "7",
State: 3,
}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := svr.EditTaskState(c, v)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}
func TestServiceTaskView(t *testing.T) {
convey.Convey("TaskView", t, func(ctx convey.C) {
var (
c = context.Background()
v = &model.TaskViewArg{
ID: int64(7),
}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
task, err := svr.TaskView(c, v)
ctx.Convey("Then err should be nil.task should not be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
ctx.So(task, convey.ShouldNotBeNil)
t.Logf("====%+v\n", task)
t.Logf("====%+v", task.SubTask)
})
})
})
}
func TestServiceReviewTask(t *testing.T) {
convey.Convey("ReviewTask", t, func(ctx convey.C) {
var (
c = context.Background()
v = &model.ReviewTaskArg{
ID: 21,
}
)
ctx.Convey("When everything goes positive", func(ctx convey.C) {
err := svr.ReviewTask(c, v)
ctx.Convey("Then err should be nil.", func(ctx convey.C) {
ctx.So(err, convey.ShouldBeNil)
})
})
})
}

View File

@ -0,0 +1,78 @@
package service
import (
"context"
"go-common/app/admin/main/dm/model"
"go-common/library/ecode"
"go-common/library/log"
)
// AddTransferJob add job
func (s *Service) AddTransferJob(c context.Context, from, to, mid int64, offset float64, state int8) (err error) {
_, err = s.dao.InsertTransferJob(c, from, to, mid, offset, 0)
if err != nil {
log.Error("s.dao.InsertTransferJob(%d, %d %d %f) error(%v)", from, to, mid, offset, err)
}
return
}
// TransferList transfer list
func (s *Service) TransferList(c context.Context, cid, state, pn, ps int64) (res []*model.TransList, total int64, err error) {
var (
aids []int64
cids []int64
)
if res, total, err = s.dao.TransferList(c, cid, state, pn, ps); err != nil {
log.Error("s.dao.TransferList(%d, %d) error(%v)", cid, state, err)
return
}
if len(res) <= 0 {
return
}
for _, idx := range res {
cids = append(cids, idx.From)
}
subs, err := s.dao.Subjects(c, model.SubTypeVideo, cids)
if err != nil {
return
}
for _, idx := range subs {
aids = append(aids, idx.Pid)
}
avm, err := s.dao.ArchiveVideos(c, aids)
if err != nil {
log.Error("s.dao.ArchiveInfo(aid:%v) error(%v)", aids, err)
return
}
for _, idx := range res {
sub, ok := subs[idx.From]
if !ok {
continue
}
info, ok := avm[sub.Pid] // get archive info
if !ok {
continue
}
idx.Title = info.Archive.Title
}
return
}
// ReTransferJob retransfer job
func (s *Service) ReTransferJob(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.SetTransferState(id:%d,state:%d) err(%v)", id, model.TransferJobStatInit, err)
}
return
}

View File

@ -0,0 +1,41 @@
package service
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestAddTransferJob(t *testing.T) {
var (
mid int64 = 27515615
from int64 = 10108765
to int64 = 10108763
offset = 1.01
state int8
)
Convey("test TransferJob", t, func() {
err := svr.AddTransferJob(context.TODO(), from, to, mid, offset, state)
So(err, ShouldBeNil)
})
}
func TestTransferList(t *testing.T) {
Convey("test transfer list", t, func() {
res, _, err := svr.TransferList(context.TODO(), 10109082, 3, 1, 20)
So(err, ShouldBeNil)
So(res, ShouldNotBeEmpty)
})
}
func TestReTransferJob(t *testing.T) {
Convey("test transfer retry", t, func() {
err := svr.ReTransferJob(context.TODO(), 256, 1)
So(err, ShouldBeNil)
})
Convey("test transfer retry fail", t, func() {
err := svr.ReTransferJob(context.TODO(), 256, 1)
So(err, ShouldNotBeNil)
})
}