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,126 @@
load(
"@io_bazel_rules_go//go:def.bzl",
"go_test",
"go_library",
)
go_test(
name = "go_default_test",
srcs = [
"archive_test.go",
"extra_func_test.go",
"flow_test.go",
"history_test.go",
"monitor_test.go",
"pgc_test.go",
"search_test.go",
"service_test.go",
"task_qa_video_test.go",
"task_test.go",
"track_test.go",
"util_test.go",
"video_test.go",
],
embed = [":go_default_library"],
tags = ["automanaged"],
deps = [
"//app/admin/main/videoup/conf:go_default_library",
"//app/admin/main/videoup/model/archive:go_default_library",
"//app/admin/main/videoup/model/monitor:go_default_library",
"//app/admin/main/videoup/model/search:go_default_library",
"//app/admin/main/videoup/model/utils:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/queue/databus/report:go_default_library",
"//vendor/github.com/smartystreets/goconvey/convey:go_default_library",
],
)
go_library(
name = "go_default_library",
srcs = [
"archive.go",
"databus.go",
"extra_func.go",
"flow.go",
"history.go",
"log.go",
"monitor.go",
"mult_sync.go",
"oper.go",
"oversea.go",
"pgc.go",
"porder.go",
"search.go",
"service.go",
"staff.go",
"stats.go",
"task.go",
"task_consumer.go",
"task_dispatch.go",
"task_qa_video.go",
"task_role.go",
"task_weight.go",
"track.go",
"tx.go",
"util.go",
"video.go",
],
importpath = "go-common/app/admin/main/videoup/service",
tags = ["automanaged"],
visibility = ["//visibility:public"],
deps = [
"//app/admin/main/videoup/conf:go_default_library",
"//app/admin/main/videoup/dao/archive:go_default_library",
"//app/admin/main/videoup/dao/data:go_default_library",
"//app/admin/main/videoup/dao/databus:go_default_library",
"//app/admin/main/videoup/dao/manager:go_default_library",
"//app/admin/main/videoup/dao/monitor:go_default_library",
"//app/admin/main/videoup/dao/music:go_default_library",
"//app/admin/main/videoup/dao/oversea:go_default_library",
"//app/admin/main/videoup/dao/search:go_default_library",
"//app/admin/main/videoup/dao/staff:go_default_library",
"//app/admin/main/videoup/dao/tag:go_default_library",
"//app/admin/main/videoup/dao/task:go_default_library",
"//app/admin/main/videoup/dao/track:go_default_library",
"//app/admin/main/videoup/model/archive:go_default_library",
"//app/admin/main/videoup/model/manager:go_default_library",
"//app/admin/main/videoup/model/message:go_default_library",
"//app/admin/main/videoup/model/monitor:go_default_library",
"//app/admin/main/videoup/model/music:go_default_library",
"//app/admin/main/videoup/model/oversea:go_default_library",
"//app/admin/main/videoup/model/search:go_default_library",
"//app/admin/main/videoup/model/track:go_default_library",
"//app/admin/main/videoup/model/up:go_default_library",
"//app/admin/main/videoup/model/utils:go_default_library",
"//app/interface/main/tag/model:go_default_library",
"//app/service/main/account/api:go_default_library",
"//app/service/main/up/api/v1:go_default_library",
"//library/database/elastic:go_default_library",
"//library/database/sql:go_default_library",
"//library/ecode:go_default_library",
"//library/log:go_default_library",
"//library/net/http/blademaster:go_default_library",
"//library/net/http/blademaster/middleware/permit:go_default_library",
"//library/queue/databus:go_default_library",
"//library/queue/databus/report:go_default_library",
"//library/sync/errgroup:go_default_library",
"//library/time:go_default_library",
"//library/xstr:go_default_library",
"//vendor/github.com/jinzhu/gorm:go_default_library",
"//vendor/github.com/pkg/errors:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@@ -0,0 +1,973 @@
package service
import (
"context"
"fmt"
"strconv"
"strings"
"go-common/app/admin/main/videoup/model/archive"
"go-common/app/admin/main/videoup/model/manager"
"go-common/app/admin/main/videoup/model/oversea"
tagrpc "go-common/app/interface/main/tag/model"
"go-common/library/database/sql"
"go-common/library/ecode"
"go-common/library/log"
"go-common/library/sync/errgroup"
"go-common/library/time"
"go-common/library/xstr"
)
// Submit second_round submit,update archive_addit\archive_delay\archive.
func (s *Service) Submit(c context.Context, ap *archive.ArcParam) (err error) {
var (
tx *sql.Tx
a *archive.Archive
addit *archive.Addit
operConts, flowConts []string
oldMissionID, missionID, descFormatID int64
mUser *manager.User
porderConts []string
porder = &archive.Porder{}
rel = &oversea.ArchiveRelation{}
)
if a, err = s.arc.Archive(c, ap.Aid); err != nil || a == nil {
log.Error("s.arc.Archive(%d) error(%v) or a==nil", ap.Aid, err)
return
}
if addit, _ = s.arc.Addit(c, ap.Aid); addit != nil {
missionID = addit.MissionID
descFormatID = addit.DescFormatID
}
forbid, _ := s.arc.Forbid(c, ap.Aid)
if tx, err = s.arc.BeginTran(c); err != nil {
log.Error("s.arc.BeginTran() error(%v)", err)
return
}
defer func() {
if r := recover(); r != nil {
tx.Rollback()
log.Error("wocao jingran recover le error(%v)", r)
}
}()
//私单稿件 审核后台允许 私单只填写 流量TAG
if ap.GroupID > 0 {
porderConts, porder = s.diffPorder(c, a.Aid, ap)
operConts = append(operConts, porderConts...)
if err = s.TxUpPorder(tx, ap); err != nil {
tx.Rollback()
return
}
//自动匹配流量tag
ap.OnFlowID = ap.GroupID
if err = s.txUpFlowID(tx, ap); err != nil {
tx.Rollback()
return
}
}
s.sendPorderLog(c, ap, porderConts, porder, a)
//流量属性控制,比如:频道禁止
if flowConts, err = s.txBatchUpFlowsState(c, tx, a.Aid, ap.UID, ap.FlowAttribute); err != nil {
log.Error("s.txBatchUpFlowsState error(%v)", err)
tx.Rollback()
return
}
if len(flowConts) > 0 {
operConts = append(operConts, flowConts...)
}
//审核更换流量TAG 或者新增私单 私单二期 flow_design.pool=2 聚合到 archive_forbid + archive.attr 由前端merge
var delayCont string
if ap.State, delayCont, err = s.txUpArcDelay(c, tx, ap.Aid, ap.Mid, ap.State, ap.Delay, ap.DTime); err != nil {
tx.Rollback()
log.Error("s.arc.txUpArcDelay(%d,%d,%d,%d,%v,%d) error(%v)", ap.Aid, ap.Mid, ap.TypeID, ap.State, ap.Delay, ap.DTime, err)
return
}
if delayCont != "" {
operConts = append(operConts, delayCont)
}
ap.Round = s.archiveRound(c, a, ap.Aid, a.Mid, a.TypeID, a.Round, ap.State, ap.CanCelMission)
if ap.Access, err = s.txUpArcMainState(c, tx, ap.Aid, ap.Forward, ap.TypeID, ap.Access, ap.State, ap.Round, ap.RejectReason); err != nil {
tx.Rollback()
log.Error("s.arc.txUpArcMainState(%d,%d,%d,%d,%d,%d,%s) error(%v)", ap.Aid, ap.Forward, ap.TypeID, ap.Access, ap.State, ap.Round, ap.RejectReason, err)
return
}
ap.PTime = s.archivePtime(c, ap.Aid, ap.State, ap.PTime)
// access、cancel_mission、cover、reject_reason、attr、source、redirecturl、forward、state、pubtime、copyright、mtime、round、title、typeid、content、delay
if _, err = s.arc.TxUpArchive(tx, ap.Aid, ap.Title, ap.Content, ap.Cover, ap.Note, ap.Copyright, ap.PTime); err != nil {
tx.Rollback()
log.Error("s.arc.TxUpArchive(%d,%s,%s,%s,%s,%d,%d) error(%v)", ap.Aid, ap.Title, ap.Content, ap.Cover, ap.Note, ap.Copyright, ap.PTime, err)
return
}
log.Info("aid(%d) update archive title(%s) content(%s) cover(%s) copyright(%d) ,ptime(%d), round(%d), state(%d)", ap.Aid, ap.Title, ap.Content, ap.Cover, ap.Copyright, ap.PTime, ap.Round, ap.State)
// cancel activity
if ap.CanCelMission {
oldMissionID = missionID
missionID = 0
}
desc := ""
if descFormatID > 0 {
desc = ap.Content
}
if _, err = s.arc.TxUpAddit(tx, ap.Aid, missionID, ap.Source, desc, ap.Dynamic); err != nil {
tx.Rollback()
log.Error("s.arc.TxUpAddit(%d,%d,%s,%s,%s) error(%v)", ap.Aid, missionID, ap.Source, desc, ap.Dynamic, err)
return
}
if ap.PolicyID > 1 {
ap.Attrs.LimitArea = 1
} else {
ap.Attrs.LimitArea = 0
}
attrs, forbidAttrs := s.archiveAttr(c, ap, true)
var attrConts []string
if attrConts, err = s.TxUpArchiveAttr(c, tx, a, ap.Aid, ap.UID, attrs, forbidAttrs, ap.URL); err != nil {
tx.Rollback()
log.Error("s.TxUpArchiveAttr(%d) error(%v)", ap.Aid, err)
return
}
operConts = append(operConts, attrConts...)
log.Info("aid(%d) update archive attribute(%+v)", ap.Aid, attrs)
if err = tx.Commit(); err != nil {
log.Error("tx.Commit() error(%v)", err)
return
}
if ap.PolicyID != 0 {
if rel, err = s.oversea.PolicyRelation(c, ap.Aid); err != nil {
log.Error("s.oversea.PolicyRelation(%d) error(%v)", ap.Aid, err)
return
}
if rel == nil || rel.GroupID != ap.PolicyID {
if _, err = s.oversea.UpPolicyRelation(c, ap.Aid, ap.PolicyID); err != nil {
log.Error("s.oversea.UpPolicyRelation(%d,%d) error(%v)", ap.Aid, ap.PolicyID, err)
return
}
operConts = append(operConts, fmt.Sprintf("[地区展示]应用策略组ID[%d]", ap.PolicyID))
}
}
log.Info("aid(%d) end second_round submit pro", ap.Aid)
// is send email
var isChanged = true
if (((ap.State == archive.StateOpen && ap.Access == archive.AccessDefault) || ap.State == archive.StateForbidUserDelay) && !ap.AdminChange) ||
(ap.State == archive.StateForbidWait) {
isChanged = false
}
archiveOperConts, changeTypeID, changeCopyright, changeTitle, changeCover := s.diffArchiveOper(ap, a, addit, forbid)
operConts = append(operConts, archiveOperConts...)
oper := &archive.ArcOper{Aid: ap.Aid, UID: ap.UID, TypeID: ap.TypeID, State: archive.AccessState(ap.State, ap.Access), Round: ap.Round, Attribute: a.Attribute, Remark: ap.Note}
oper.Content = strings.Join(operConts, "")
if ap.ApplyUID != 0 {
mUser, _ = s.mng.User(c, ap.ApplyUID)
oper.Content = "[通过" + mUser.NickName + "(" + strconv.FormatInt(ap.ApplyUID, 10) + ")申请的工单]" + oper.Content
}
s.addArchiveOper(c, oper)
// databus
s.busSecondRound(ap.Aid, oldMissionID, ap.Notify, isChanged, changeTypeID, changeCopyright, changeTitle, changeCover, ap.FromList, ap)
go s.busSecondRoundUpCredit(ap.Aid, 0, ap.Mid, ap.UID, ap.State, ap.Round, ap.ReasonID, ap.RejectReason)
// log
s.sendArchiveLog(c, ap, operConts, a)
return
}
// BatchArchive batch async archive audit.
func (s *Service) BatchArchive(c context.Context, aps []*archive.ArcParam, action string) (err error) {
var mp = &archive.MultSyncParam{}
var ok bool
for _, ap := range aps {
mp.Action = action
mp.ArcParam = ap
if ok, err = s.busCache.PushMultSync(c, mp); err != nil {
log.Error("s.busCache.PushMultSync(ap(%+v)) error(%v)", ap, err)
return
}
if !ok {
log.Warn("s.busCache.PushMultSync(ap(%+v))", ap)
continue
}
}
return
}
func (s *Service) dealArchive(c context.Context, ap *archive.ArcParam) (err error) {
var a *archive.Archive
if a, err = s.arc.Archive(c, ap.Aid); err != nil || a == nil {
log.Error("s.arc.Archive(%d) error(%v) or a==nil", ap.Aid, err)
return
}
var tx *sql.Tx
if tx, err = s.arc.BeginTran(c); err != nil {
log.Error("s.arc.BeginTran() error(%v)", err)
return
}
defer func() {
if r := recover(); r != nil {
tx.Rollback()
log.Error("wocao jingran recover le error(%v)", r)
}
}()
log.Info("aid(%d) start BatchSubmit pro params is (%+v)", ap.Aid, ap)
if ap.State, _, err = s.txUpArcDelay(c, tx, ap.Aid, ap.Mid, ap.State, true, ap.DTime); err != nil {
tx.Rollback()
log.Error("s.arc.txUpArcDelay(%d,%d,%d,%d,%v,%d) error(%v)", ap.Aid, ap.Mid, ap.TypeID, ap.State, true, ap.DTime, err)
return
}
ap.Round = s.archiveRound(c, a, ap.Aid, a.Mid, a.TypeID, a.Round, ap.State, ap.CanCelMission)
if ap.Access, err = s.txUpArcMainState(c, tx, ap.Aid, ap.Forward, ap.TypeID, ap.Access, ap.State, ap.Round, ap.RejectReason); err != nil {
tx.Rollback()
log.Error("s.arc.txUpArcMainState(%d,%d,%d,%d,%d,%d,%s) error(%v)", ap.Aid, ap.Forward, ap.TypeID, ap.Access, ap.State, ap.Round, ap.RejectReason, err)
return
}
ap.PTime = s.archivePtime(c, ap.Aid, ap.State, a.PTime) // NOTE: for batch no ptime...
if _, err = s.arc.TxUpArcPTime(tx, ap.Aid, ap.PTime); err != nil {
tx.Rollback()
log.Error("s.arc.TxUpArcPTime(%d,%d) error(%v)", ap.Aid, ap.PTime, err)
return
}
log.Info("aid(%d) update archive pubtime(%d)", ap.Aid, ap.PTime)
if _, err = s.arc.TxUpArcNote(tx, ap.Aid, ap.Note); err != nil {
tx.Rollback()
log.Error("s.arc.TxUpArcNote(%d,%s) error(%v)", ap.Aid, ap.Note, err)
return
}
log.Info("aid(%d) update archive note(%s)", ap.Aid, ap.Note)
if ap.FlagCopyright {
if _, err = s.arc.TxUpArcCopyRight(tx, ap.Aid, ap.Copyright); err != nil {
tx.Rollback()
log.Error("s.arc.TxUpArcCopyRight(%d,%d) error(%v)", ap.Aid, ap.Copyright, err)
return
}
log.Info("aid(%d) update archive Copyright(%d)", ap.Aid, ap.Copyright)
}
if err = tx.Commit(); err != nil {
log.Error("tx.Commit() error(%v)", err)
return
}
log.Info("aid(%d) end BatchSubmit pro", ap.Aid)
var isChanged = true
if (((ap.State == archive.StateOpen && ap.Access == archive.AccessDefault) || ap.State == archive.StateForbidUserDelay) && !ap.AdminChange) ||
(ap.State == archive.StateForbidWait) {
isChanged = false
}
oper := &archive.ArcOper{Aid: ap.Aid, UID: ap.UID, TypeID: ap.TypeID, State: archive.AccessState(ap.State, ap.Access), Round: ap.Round, Attribute: a.Attribute, Remark: ap.Note}
operConts := s.diffBatchArchiveOper(ap, a)
oper.Content = strings.Join(operConts, "")
s.addArchiveOper(c, oper)
s.busSecondRound(ap.Aid, 0, ap.Notify, isChanged, false, false, false, false, ap.FromList, ap)
go s.busSecondRoundUpCredit(ap.Aid, 0, ap.Mid, ap.UID, ap.State, ap.Round, ap.ReasonID, ap.RejectReason)
// log
ap.CTime = a.CTime
s.sendArchiveLog(c, ap, operConts, a)
return
}
func (s *Service) dealAttrs(c context.Context, ap *archive.ArcParam) (err error) {
var a *archive.Archive
if a, err = s.arc.Archive(c, ap.Aid); err != nil || a == nil {
log.Error("s.arc.Archive(%d) error(%v) or a==nil", ap.Aid, err)
return
}
//付费稿件不支持批量属性修改 因为涉及到价格设置一致性问题
if s.isUGCPay(a) {
log.Info("dealAttrs skip UGCPay(%d) error(%v)", ap.Aid, err)
return
}
var tx *sql.Tx
if tx, err = s.arc.BeginTran(c); err != nil {
log.Error("s.arc.BeginTran() error(%v)", err)
return
}
defer func() {
if r := recover(); r != nil {
tx.Rollback()
log.Error("wocao jingran recover le error(%v)", r)
}
}()
log.Info("aid(%d) start BatchAttr pro", ap.Aid)
var operConts, flowConts []string
attrs, forbidAttrs := s.archiveAttr(c, ap, false)
if operConts, err = s.TxUpArchiveAttr(c, tx, a, ap.Aid, ap.UID, attrs, forbidAttrs, ""); err != nil {
tx.Rollback()
log.Error("s.arc.txUpArcAttrs(%d) error(%v)", ap.Aid, err)
return
}
log.Info("aid(%d) update archive attribute( %+v )", ap.Aid, attrs)
if _, err = s.arc.TxUpArcNote(tx, ap.Aid, ap.Note); err != nil {
tx.Rollback()
log.Error("s.arc.TxUpArcNote(%d,%s) error(%v)", ap.Aid, ap.Note, err)
return
}
log.Info("aid(%d) update archive note(%s)", ap.Aid, ap.Note)
//流量属性控制,比如:频道禁止
if flowConts, err = s.txBatchUpFlowsState(c, tx, a.Aid, ap.UID, ap.FlowAttribute); err != nil {
log.Error("s.txBatchUpFlowsState error(%v)", err)
tx.Rollback()
return
}
if len(flowConts) > 0 {
operConts = append(operConts, flowConts...)
}
if err = tx.Commit(); err != nil {
log.Error("tx.Commit() error(%v)", err)
return
}
log.Info("aid(%d) end BatchAttr pro", ap.Aid)
oper := &archive.ArcOper{Aid: ap.Aid, UID: ap.UID, TypeID: a.TypeID, State: archive.AccessState(a.State, a.Access), Round: a.Round, Attribute: a.Attribute, Remark: ap.Note}
oper.Content = strings.Join(operConts, "")
s.addArchiveOper(c, oper)
s.busSecondRound(ap.Aid, 0, ap.Notify, ap.AdminChange, false, false, false, false, ap.FromList, ap)
// log
ap.CTime = a.CTime
s.sendArchiveLog(c, ap, operConts, a)
return
}
func (s *Service) dealArchiveSecondRound(c context.Context, ap *archive.ArcParam) (err error) {
s.busSecondRound(ap.Aid, 0, false, false, false, false, false, false, ap.FromList, ap)
return
}
func (s *Service) dealTypeID(c context.Context, ap *archive.ArcParam) (err error) {
var a *archive.Archive
if a, err = s.arc.Archive(c, ap.Aid); err != nil || a == nil {
log.Error("s.arc.Archive(%d) error(%v) or a==nil", ap.Aid, err)
return
}
var tx *sql.Tx
if tx, err = s.arc.BeginTran(c); err != nil {
log.Error("s.arc.BeginTran() error(%v)", err)
return
}
defer func() {
if r := recover(); r != nil {
tx.Rollback()
log.Error("wocao jingran recover le error(%v)", r)
}
}()
log.Info("aid(%d) start BatchType pro", ap.Aid)
if _, err = s.arc.TxUpArcTypeID(tx, ap.Aid, ap.TypeID); err != nil {
tx.Rollback()
log.Error("s.arc.TxUpArcTypeID(%d,%d) error(%v)", ap.Aid, ap.TypeID, err)
return
}
log.Info("aid(%d) update archive type_id(%d)", ap.Aid, ap.TypeID)
if _, err = s.arc.TxUpArcNote(tx, ap.Aid, ap.Note); err != nil {
tx.Rollback()
log.Error("s.arc.TxUpArcNote(%d,%s) error(%v)", ap.Aid, ap.Note, err)
return
}
log.Info("aid(%d) update archive note(%s)", ap.Aid, ap.Note)
if err = tx.Commit(); err != nil {
log.Error("tx.Commit() error(%v)", err)
return
}
log.Info("aid(%d) end BatchType pro", ap.Aid)
var changeTypeID bool
oper := &archive.ArcOper{Aid: ap.Aid, UID: ap.UID, TypeID: ap.TypeID, State: archive.AccessState(a.State, a.Access), Round: a.Round, Attribute: a.Attribute, Remark: ap.Note}
oper.Content, changeTypeID = s.diffTypeID(ap.TypeID, a.TypeID, a.State)
var operConts []string
operConts = append(operConts, oper.Content)
s.addArchiveOper(c, oper)
if ap.ForceSync {
s.busArchiveForceSync(ap.Aid)
} else {
s.busSecondRound(ap.Aid, 0, ap.Notify, ap.AdminChange, changeTypeID, false, false, false, ap.FromList, ap)
}
// log
ap.CTime = a.CTime
s.sendArchiveLog(c, ap, operConts, a)
return
}
// // BatchZlimit batche modify zlimit.
// func (s *Service) BatchZlimit(c context.Context, ap *archive.ArcParam) (err error) {
// var (
// tx *sql.Tx
// aps []*archive.ArcParam
// aids = xstr.JoinInts(ap.Aids)
// )
// if tx, err = s.mng.BeginTran(c); err != nil {
// log.Error("s.arc.BeginTran() error(%v)", err)
// return
// }
// defer func() {
// if r := recover(); r != nil {
// tx.Rollback()
// log.Error("wocao jingran recover le error(%v)", r)
// }
// }()
// log.Info("aids(%s) start BatchZlimit pro", aids)
// for _, aid := range ap.Aids {
// if _, err = s.mng.TxAddUpArea(tx, aid, ap.GroupID); err != nil {
// tx.Rollback()
// log.Error("s.arc.TxAddUpArea(%d,%d) error(%v)", aid, ap.GroupID, err)
// return
// }
// log.Info("aid(%d) update archive gid(%d)", aid, ap.GroupID)
// ap.Aid = aid
// aps = append(aps, ap)
// }
// if err = tx.Commit(); err != nil {
// log.Error("tx.Commit() error(%v)", err)
// return
// }
// log.Info("aids(%s) end BatchZlimit pro", aids)
// s.busSecondRound(aps)
// return
// }
// UpAuther update owner.
func (s *Service) UpAuther(c context.Context, ap *archive.ArcParam) (err error) {
var tx *sql.Tx
if tx, err = s.arc.BeginTran(c); err != nil {
log.Error("s.arc.BeginTran() error(%v)", err)
return
}
defer func() {
if r := recover(); r != nil {
tx.Rollback()
log.Error("wocao jingran recover le error(%v)", r)
}
}()
log.Info("aid(%d) start up author", ap.Aid)
if _, err = s.arc.TxUpArcAuthor(tx, ap.Aid, ap.Mid, ap.Author); err != nil {
tx.Rollback()
log.Error("s.Auther s.dede.TxUpArcAuthor(%d,%d,%s) error(%v)", ap.Aid, ap.Mid, ap.Author, err)
return
}
log.Info("aid(%d) update archive mid(%d) author(%s)", ap.Aid, ap.Mid, ap.Author)
if err = tx.Commit(); err != nil {
log.Error("tx.Commit() error(%v)", err)
return
}
log.Info("aid(%d) end up author", ap.Aid)
// databus
s.busSecondRound(ap.Aid, 0, ap.Notify, false, false, false, false, false, ap.FromList, ap)
return
}
// UpAccess update access.
func (s *Service) UpAccess(c context.Context, ap *archive.ArcParam) (err error) {
var tx *sql.Tx
if tx, err = s.arc.BeginTran(c); err != nil {
log.Error("s.arc.BeginTran() error(%v)", err)
return
}
defer func() {
if r := recover(); r != nil {
tx.Rollback()
log.Error("wocao jingran recover le error(%v)", r)
}
}()
log.Info("aid(%d) start up access", ap.Aid)
if _, err = s.arc.TxUpArcAccess(tx, ap.Aid, ap.Access); err != nil {
tx.Rollback()
log.Error("s.Access s.dede.TxUpArcAccess(%d,%d) error(%v)", ap.Aid, ap.Access, err)
return
}
log.Info("aid(%d) update archive access(%d)", ap.Aid, ap.Access)
if err = tx.Commit(); err != nil {
log.Error("tx.Commit() error(%v)", err)
return
}
log.Info("aid(%d) end up access", ap.Aid)
// databus
s.busSecondRound(ap.Aid, 0, ap.Notify, ap.AdminChange, false, false, false, false, ap.FromList, ap)
return
}
// UpArchiveAttr update archive attr by aid.
func (s *Service) UpArchiveAttr(c context.Context, aid, uid int64, attrs map[uint]int32, forbidAttrs map[string]map[uint]int32, redirectURL string) (err error) {
var a *archive.Archive
if a, err = s.arc.Archive(c, aid); err != nil || a == nil {
log.Error("s.arc.Archive(%d) error(%v) or a==nil", aid, err)
return
}
log.Info("aid(%d) begin tran change attribute", aid)
var tx *sql.Tx
if tx, err = s.arc.BeginTran(c); err != nil {
log.Error("begin tran error(%v)", err)
return
}
defer func() {
if r := recover(); r != nil {
tx.Rollback()
log.Error("wocao jingran recover le error(%v)", r)
}
}()
var conts []string
if conts, err = s.txUpArcAttrs(tx, a, attrs, redirectURL); err != nil {
tx.Rollback()
return
}
var tmpCs []string
if tmpCs, err = s.txUpArcForbidAttrs(c, tx, a, forbidAttrs); err != nil {
tx.Rollback()
return
}
conts = append(conts, tmpCs...)
if err = tx.Commit(); err != nil {
log.Error("tx.Commit error(%v)", err)
return
}
log.Info("aid(%d) end tran change attribute", aid)
if len(conts) > 0 {
s.arc.AddArcOper(c, a.Aid, uid, a.Attribute, a.TypeID, int16(a.State), a.Round, 1, strings.Join(conts, ""), "")
}
// NOTE: send modify_archive for sync dede.
s.busModifyArchive(aid, false, false)
return
}
// UpArcDtime update archive dtime by aid.
func (s *Service) UpArcDtime(c context.Context, aid int64, dtime time.Time) (err error) {
if delay, _ := s.arc.Delay(c, aid, archive.DelayTypeForUser); delay == nil {
err = ecode.NothingFound
return
}
log.Info("aid(%d) dtime(%d) begin tran change archive delaytime", aid, dtime)
var tx *sql.Tx
if tx, err = s.arc.BeginTran(c); err != nil {
log.Error("begin tran error(%v)", err)
return
}
if _, err = s.arc.TxUpDelayDtime(tx, aid, archive.DelayTypeForUser, dtime); err != nil {
tx.Rollback()
log.Error("s.arc.TxUpDelayDtime() error(%v)", err)
return
}
if _, err = s.arc.TxUpArcMtime(tx, aid); err != nil {
tx.Rollback()
log.Error("s.arc.TxUpArcMtime() error(%v)", err)
return
}
if err = tx.Commit(); err != nil {
log.Error("tx.Commit error(%v)", err)
return
}
log.Info("aid(%d) dtime(%d) end tran change archive delaytime", aid, dtime)
return
}
/**
* archive map
* return map[int64]*archive.ChannelReviewInfo, error/nil
*/
func (s *Service) checkChannelReview(c context.Context, arcs map[int64]*archive.Archive) (res map[int64]*archive.ChannelReviewInfo, err error) {
var reviewRes map[int64]*tagrpc.ResChannelCheckBack
res = map[int64]*archive.ChannelReviewInfo{}
aids := []int64{}
//检查是否开放浏览
for _, a := range arcs {
if a == nil {
continue
}
if archive.NormalState(a.State) {
aids = append(aids, a.Aid)
}
res[a.Aid] = &archive.ChannelReviewInfo{AID: a.Aid}
}
if len(aids) <= 0 {
return
}
//检查是否有回查数据
if _, aids, err = s.arc.RecheckIDByAID(c, archive.TypeChannelRecheck, aids); err != nil || len(aids) <= 0 {
return
}
//实时查询是否变更了频道,频道是否需要回查
if reviewRes, err = s.tag.CheckChannelReview(c, aids); err != nil {
log.Error("checkChannelReview s.arc.CheckChannelReview error(%v) aids(%v)", err, aids)
err = nil
}
for _, aid := range aids {
res[aid].CanOperRecheck = true
if reviewRes != nil && reviewRes[aid] != nil {
res[aid].NeedReview = reviewRes[aid].CheckBack == 1
cids := []int64{}
for chid := range reviewRes[aid].Channels {
cids = append(cids, chid)
}
res[aid].ChannelIDs = xstr.JoinInts(cids)
}
}
return
}
//UpArcTag 保存tag
func (s *Service) UpArcTag(c context.Context, uid int64, pm *archive.TagParam) (err error) {
var (
arc *archive.Archive
checkRes map[int64]*archive.ChannelReviewInfo
needReview, fromChannel bool
canOperRecheck bool
)
//archive check
if arc, err = s.arc.Archive(c, pm.AID); err != nil {
log.Error("UpArcTag s.arc.Archive(%d) error(%v) params(%+v)", pm.AID, err, pm)
return
}
if arc == nil {
err = ecode.NothingFound
return
}
//check whether need channel review: channel changes every 3h, used to notice
fromChannel = strings.TrimSpace(pm.FromChannelReview) == "1"
if fromChannel {
if checkRes, err = s.checkChannelReview(c, map[int64]*archive.Archive{pm.AID: arc}); err != nil {
log.Error("UpArcTag s.checkChannelReview(%d) error(%v) params(%+v)", pm.AID, err, pm)
return
}
if checkRes != nil && checkRes[pm.AID] != nil {
needReview = checkRes[pm.AID].NeedReview
canOperRecheck = checkRes[pm.AID].CanOperRecheck
}
}
if err = s.saveTag(c, uid, arc, pm.Tags, "", canOperRecheck, nil); err != nil {
log.Error("UpArcTag s.saveTag error(%v) uid(%d) canoperrecheck(%v) params(%+v)", err, uid, canOperRecheck, pm)
return
}
if fromChannel && !needReview {
err = ecode.VideoupChannelReviewNotTrigger
}
return
}
//saveTag 更新tag可能触发频道回查
func (s *Service) saveTag(c context.Context, uid int64, arc *archive.Archive, tags, note string, canOperRecheck bool, ap *archive.ArcParam) (err error) {
var (
tx *sql.Tx
tagChange bool
remark, flowDiff string
content []string
)
//compare tag
aid := arc.Aid
arc.Tag = strings.Join(Slice2String(SliceUnique(Slice2Interface(strings.Split(arc.Tag, ",")))), ",")
tags = strings.Join(Slice2String(SliceUnique(Slice2Interface(strings.Split(tags, ",")))), ",")
tagChange = arc.Tag != tags
//update db by transaction
if tx, err = s.arc.BeginTran(c); err != nil {
log.Error("saveTag s.arc.BeginTran error(%v)", err)
return
}
if tagChange {
if _, err = s.arc.TxUpTag(tx, aid, tags); err != nil {
log.Error("saveTag s.arc.TxUpTag(%d,%s) error(%v)", aid, tags, err)
tx.Rollback()
return
}
content = append(content, archive.Operformat(archive.OperTypeTag, arc.Tag, tags, archive.OperStyleOne))
}
if canOperRecheck {
if err = s.arc.TxUpRecheckState(tx, archive.TypeChannelRecheck, aid, archive.RecheckStateDone); err != nil {
log.Error("saveTag s.arc.TxUpRecheckState(%d) error(%v)", aid, err)
tx.Rollback()
return
}
if _, flowDiff, err = s.txAddOrUpdateFlowState(c, tx, aid, archive.FlowGroupNoChannel, uid, archive.PoolArcForbid, archive.FlowDelete, "频道回查取消频道禁止"); err != nil {
log.Error("saveTag s.txAddOrUpdateFlowState(%d,%d) error(%v)", aid, uid, err)
tx.Rollback()
return
}
if flowDiff != "" {
content = append(content, flowDiff)
}
remark = "频道已回查"
}
if err = tx.Commit(); err != nil {
log.Error("saveTag tx.Commit error(%v)", err)
return
}
log.Info("saveTag aid(%d) origin old-tags(%s) new-tags(%s) canoperrecheck(%v)", aid, arc.Tag, tags, canOperRecheck)
//log tag change/channel review history
remark = remark + note
if len(content) > 0 || remark != "" {
oper := &archive.ArcOper{
Aid: aid,
UID: uid,
TypeID: arc.TypeID,
State: archive.AccessState(arc.State, arc.Access),
Round: arc.Round,
Content: strings.Join(content, ","),
Attribute: arc.Attribute,
Remark: remark,
}
s.arc.AddArcOper(c, oper.Aid, oper.UID, oper.Attribute, oper.TypeID, oper.State, oper.Round, 0, oper.Content, oper.Remark)
}
//同步tag服务
if tagChange {
if ap != nil && ap.IsUpBind {
err = s.upBind(c, aid, arc.Mid, tags, arc.TypeID)
} else {
err = s.adminBind(c, aid, arc.Mid, tags, arc.TypeID)
}
}
//仅同步隐藏tag
if !tagChange && ap != nil && ap.SyncHiddenTag {
err = s.upBind(c, aid, arc.Mid, arc.Tag, arc.TypeID)
}
return
}
//BatchUpTag batch update archive tag
func (s *Service) BatchUpTag(c context.Context, uid int64, pm *archive.BatchTagParam) (warning string, err error) {
var (
arcList map[int64]*archive.Archive
reviewResp map[int64]*archive.ChannelReviewInfo
ok, fromChannel bool
warningID []int64
originTag string
)
//get archive list
if arcList, err = s.arc.Archives(c, pm.AIDs); err != nil {
log.Error("batchTag vdaSvc.GetArchives error(%v) params(%+v)", err, pm)
return
}
fromChannel = strings.TrimSpace(pm.FromList) == archive.FromListChannelReview
//batch check whether need channel review, if not mark aid to noneedaids
if fromChannel {
if reviewResp, err = s.checkChannelReview(c, arcList); err != nil {
log.Error("batchTag s.checkChannelReview error(%v) params(%+v)", err, pm)
return
}
}
//save each archive tag
mp := &archive.MultSyncParam{
ArcParam: &archive.ArcParam{
UID: uid,
Note: pm.Note,
FromList: pm.FromList,
IsUpBind: pm.IsUpBind,
SyncHiddenTag: pm.SyncHiddenTag,
},
}
for id, arc := range arcList {
if fromChannel && (reviewResp == nil || reviewResp[id] == nil || !reviewResp[id].NeedReview) {
warningID = append(warningID, id)
}
originTag = arc.Tag
//tag change
if pm.Action != "" {
arc.Tag = StringHandler(arc.Tag, pm.Tags, ",", pm.Action == "delete")
}
//批量修改tag
mp.Action = archive.ActionArchiveTag
//频道回查逻辑
if reviewResp != nil && reviewResp[id] != nil && reviewResp[id].CanOperRecheck {
mp.Action = archive.ActionArchiveTagRecheck
}
//非频道回查的tag未变更/频道回查tag未变更且无回查记录提前返回
if originTag == arc.Tag && ((!fromChannel && !pm.SyncHiddenTag) || (fromChannel && mp.Action == archive.ActionArchiveTag)) {
continue
}
mp.ArcParam.Aid = id
mp.ArcParam.Tag = arc.Tag
log.Info("BatchUpTag begin to pushmultsync action(%s) arcparam(%+v)", mp.Action, mp.ArcParam)
if ok, err = s.busCache.PushMultSync(c, mp); err != nil {
log.Error("BatchUpTag s.busCache.PushMultSync(%d,%s,%s,%v) error(%v)", id, arc.Tag, pm.Note, pm.FromList, err)
return
}
if !ok {
log.Warn("BatchUpTag s.busCache.PushMultSync(%d,%s,%s,%v)", id, arc.Tag, pm.Note, pm.FromList)
continue
}
}
if len(warningID) > 0 {
warning = fmt.Sprintf("稿件 %s 不需要频道回查", xstr.JoinInts(warningID))
}
return
}
func (s *Service) dealTag(c context.Context, canOperRecheck bool, ap *archive.ArcParam) (err error) {
var arc *archive.Archive
if arc, err = s.arc.Archive(c, ap.Aid); err != nil {
log.Error(" UpArcTag s.arc.Archive(%d) error(%v)", ap.Aid, err)
return
}
if arc == nil {
err = ecode.NothingFound
return
}
if err = s.saveTag(c, ap.UID, arc, ap.Tag, ap.Note, canOperRecheck, ap); err != nil {
log.Error("dealTag s.saveTag(%d,%d,%s,%s,%v) error(%v)", ap.UID, ap.Aid, ap.Tag, ap.Note, canOperRecheck, err)
}
return
}
func (s *Service) adminBind(c context.Context, aid, mid int64, tags string, typeID int16) (err error) {
log.Info("before sync tag for aid(%d) tags(%s)", aid, tags)
typeName := ""
if tp, ok := s.typeCache[typeID]; ok && tp != nil {
typeName = tp.Name
if tp, err = s.TypeTopParent(typeID); err != nil {
log.Error("adminBind s.TypeTopParent(%d) error(%v) aid(%d)", typeID, err, aid)
err = nil
} else if tp != nil {
typeName = fmt.Sprintf("%s,%s", typeName, tp.Name)
}
}
if err = s.tag.AdminBind(c, aid, mid, tags, typeName, ""); err != nil {
log.Error("adminBind sync tag error(%v) aid(%+v) tags(%s) typename(%s)", err, aid, tags, typeName)
return
}
log.Info("end sync tag for aid(%d) tags(%s) successfully", aid, tags)
return
}
func (s *Service) upBind(c context.Context, aid, mid int64, tags string, typeID int16) (err error) {
log.Info("upBind before sync tag for aid(%d) tags(%s)", aid, tags)
typeName := ""
if tp, ok := s.typeCache[typeID]; ok && tp != nil {
typeName = tp.Name
if tp, err = s.TypeTopParent(typeID); err != nil {
log.Error("upBind s.TypeTopParent(%d) error(%v) aid(%d)", typeID, err, aid)
err = nil
} else if tp != nil {
typeName = fmt.Sprintf("%s,%s", typeName, tp.Name)
}
}
if err = s.tag.UpBind(c, aid, mid, tags, typeName, ""); err != nil {
log.Error("upBind sync tag error(%v) aid(%+v) tags(%s) typename(%s)", err, aid, tags, typeName)
return
}
log.Info("upBind end sync tag for aid(%d) tags(%s) successfully", aid, tags)
return
}
//GetChannelInfo get channel info & hit_rules & need review
func (s *Service) GetChannelInfo(c context.Context, aids []int64) (info map[int64]*archive.ChannelInfo, err error) {
info = make(map[int64]*archive.ChannelInfo, len(aids))
for _, aid := range aids {
info[aid] = &archive.ChannelInfo{}
}
res, err := s.tag.CheckChannelReview(c, aids)
if err != nil || res == nil {
log.Error("GetChannelInfo s.tag.GetChannelInfo error(%v)/resp=nil aids(%v)", err, aids)
return
}
if len(res) <= 0 {
return
}
for aid := range info {
if res[aid] == nil {
continue
}
chs := []*archive.Channel{}
for _, ch := range res[aid].Channels {
if ch == nil {
continue
}
chs = append(chs, &archive.Channel{
TID: ch.Tid,
Tname: ch.TName,
HitRules: ch.HitRules,
HitTagNames: ch.HitTNames,
})
}
info[aid].Channels = chs
info[aid].CheckBack = res[aid].CheckBack
}
return
}
// AITrack .
func (s *Service) AITrack(c context.Context, aid []int64) (aids string, err error) {
return s.data.ArchiveRelated(c, aid)
}
//ChannelNamesByAids .
func (s *Service) ChannelNamesByAids(c context.Context, aids []int64) (aidMap map[int64][]string) {
var (
size = len(aids)
maxSize = 1000
sliceLimit = 50
cnt = 0
aidSli = [][]int64{}
sli = []int64{}
grp = errgroup.Group{}
chlist chan map[int64][]string
)
if size > maxSize {
size = maxSize
}
aidMap = make(map[int64][]string, size)
//去重分组
for _, aid := range aids {
if _, exist := aidMap[aid]; exist {
continue
}
aidMap[aid] = []string{}
if cnt >= sliceLimit {
cnt = 0
aidSli = append(aidSli, sli)
sli = []int64{}
}
cnt++
sli = append(sli, aid)
}
if cnt > 0 {
aidSli = append(aidSli, sli)
}
chlist = make(chan map[int64][]string, size)
//batch get channel names
for i, aids := range aidSli {
if i >= maxSize {
break
}
aidtmp := aids
grp.Go(func() error {
resp, err := s.tag.CheckChannelReview(context.TODO(), aidtmp)
if err != nil {
log.Error("ChannelNamesByAids s.tag.CheckChannelReview error(%v) aids(%v)", err, aidtmp)
return nil
}
tnames := map[int64][]string{}
for aid, rp := range resp {
if rp == nil && rp.Channels == nil {
continue
}
if _, exist := tnames[aid]; !exist {
tnames[aid] = []string{}
}
for _, ch := range rp.Channels {
if ch == nil {
continue
}
tnames[aid] = append(tnames[aid], ch.TName)
}
}
chlist <- tnames
return nil
})
}
grp.Wait()
close(chlist)
for tnames := range chlist {
for aid, tname := range tnames {
aidMap[aid] = tname
}
}
return
}

View File

@@ -0,0 +1,135 @@
package service
import (
"context"
. "github.com/smartystreets/goconvey/convey"
"testing"
"go-common/app/admin/main/videoup/model/archive"
)
func TestService_Submit(t *testing.T) {
var (
c = context.TODO()
ap = &archive.ArcParam{}
)
Convey("Submit", t, WithService(func(s *Service) {
err := svr.Submit(c, ap)
So(err, ShouldBeNil)
}))
}
func TestService_UpAccess(t *testing.T) {
var (
c = context.TODO()
ap = &archive.ArcParam{}
)
Convey("UpAccess", t, WithService(func(s *Service) {
err := svr.UpAccess(c, ap)
So(err, ShouldBeNil)
}))
}
func TestService_UpArcDtime(t *testing.T) {
var (
c = context.TODO()
)
Convey("UpArcDtime", t, WithService(func(s *Service) {
err := svr.UpArcDtime(c, 1, 12345)
So(err, ShouldNotBeNil)
}))
}
func TestService_UpAuther(t *testing.T) {
var (
c = context.TODO()
ap = &archive.ArcParam{}
)
Convey("UpAuther", t, WithService(func(s *Service) {
err := svr.UpAuther(c, ap)
So(err, ShouldBeNil)
}))
}
func TestService_UpArchiveAttr(t *testing.T) {
var (
c = context.TODO()
)
attrs := make(map[uint]int32, 6)
attrs[archive.AttrBitNoRank] = 0
attrs[archive.AttrBitNoDynamic] = 0
attrs[archive.AttrBitNoRecommend] = 0
// forbid
forbidAttrs := make(map[string]map[uint]int32, 3)
forbidAttrs[archive.ForbidRank] = map[uint]int32{
archive.ForbidRankMain: 0,
archive.ForbidRankRecentArc: 0,
archive.ForbidRankAllArc: 0,
}
forbidAttrs[archive.ForbidDynamic] = map[uint]int32{
archive.ForbidDynamicMain: 0,
}
forbidAttrs[archive.ForbidRecommend] = map[uint]int32{
archive.ForbidRecommendMain: 0,
}
Convey("UpArchiveAttr", t, WithService(func(s *Service) {
err := svr.UpArchiveAttr(c, 1, 2, attrs, forbidAttrs, "")
So(err, ShouldBeNil)
}))
}
func TestService_Next(t *testing.T) {
var (
c = context.TODO()
)
Convey("Next", t, WithService(func(s *Service) {
task, err := svr.Next(c, 6)
So(task, ShouldNotBeNil)
So(err, ShouldBeNil)
}))
}
func TestService_UpArcTag(t *testing.T) {
Convey("UpArcTag", t, WithService(func(s *Service) {
//a.频道回查列表进入并提交的 b.tag改变
c := context.TODO()
//pm1(~a && b) -- archive_oper新增记录
pm1 := &archive.TagParam{AID: 6, Tags: "haha1,haha2", FromChannelReview: ""}
//pm2 (~a && ~b) -- 啥都没有
pm2 := &archive.TagParam{AID: 6, Tags: "haha1,haha2", FromChannelReview: ""}
//pm1(a && ~b) -- 新增flow_design
pm3 := &archive.TagParam{AID: 6, Tags: "haha1,haha2", FromChannelReview: "1"}
//pm2 (a && b) -- archive_oper新增
pm4 := &archive.TagParam{AID: 6, Tags: "haha", FromChannelReview: "1"}
err := svr.UpArcTag(c, 421, pm1)
So(err, ShouldBeNil)
err = svr.UpArcTag(c, 421, pm2)
So(err, ShouldBeNil)
err = svr.UpArcTag(c, 421, pm3)
So(err, ShouldNotBeNil)
err = svr.UpArcTag(c, 421, pm4)
So(err, ShouldNotBeNil)
}))
}
func TestService_GetChannelInfo(t *testing.T) {
Convey("GetChannelInfo", t, WithService(func(s *Service) {
info, err := s.GetChannelInfo(context.TODO(), []int64{10110255, 10110250})
for aid, in := range info {
channes := []*archive.Channel{}
if in != nil {
channes = in.Channels
}
t.Logf("aid=%d, in=%+v list the channels\r\n", aid, in)
for _, ch := range channes {
t.Logf("channel(%+v)\r\n", ch)
}
}
So(err, ShouldBeNil)
}))
}

View File

@@ -0,0 +1,229 @@
package service
import (
"context"
"strconv"
"time"
"go-common/app/admin/main/videoup/model/archive"
"go-common/app/admin/main/videoup/model/message"
"go-common/app/admin/main/videoup/model/up"
"go-common/library/log"
)
func (s *Service) busFirstRound(aid int64, fn, encodePurpose string, videoDesign *message.VideoDesign, status int16, encoding int8, regionID, typeID int16, fans int64, adminChange bool) (err error) {
var msg = &message.Videoup{
Route: message.RouteFirstRound,
Fans: fans,
Timestamp: time.Now().Unix(),
Aid: aid,
Filename: fn,
Status: status,
Xcode: encoding,
EncodeRegionID: regionID,
VideoDesign: videoDesign,
AdminChange: adminChange,
EncodeTypeID: typeID,
}
if len(encodePurpose) != 0 {
msg.EncodePurpose = encodePurpose
}
log.Info("filename(%s) start to send firstRound(%+v) to databus", fn, msg)
if err = s.busSendMsg(msg); err != nil {
s.msgCh <- msg
}
return
}
func (s *Service) busUGCFirstRound(aid int64, fn, encodePurpose string, videoDesign *message.VideoDesign, status int16, encoding int8, regionID, typeID int16, fans int64, adminChange bool) (err error) {
var msg = &message.Videoup{
Route: message.RouteUGCFirstRound,
Fans: fans,
Timestamp: time.Now().Unix(),
Aid: aid,
Filename: fn,
Status: status,
Xcode: encoding,
EncodeRegionID: regionID,
VideoDesign: videoDesign,
AdminChange: adminChange,
EncodeTypeID: typeID,
}
if len(encodePurpose) != 0 {
msg.EncodePurpose = encodePurpose
}
log.Info("filename(%s) start to send UGCFirstRound(%+v) to databus", fn, msg)
if err = s.busSendMsg(msg); err != nil {
s.msgCh <- msg
}
return
}
func (s *Service) busArchiveForceSync(aid int64) (err error) {
var msg = &message.Videoup{
Route: message.RouteForceSync,
Timestamp: time.Now().Unix(),
Aid: aid,
}
log.Info("aid(%d) send busArchiveForceSync to databus ", aid)
if err = s.busSendMsg(msg); err != nil {
s.msgCh <- msg
}
return
}
func (s *Service) busModifyArchive(aid int64, aChange, vChange bool) (err error) {
var msg = &message.Videoup{
Route: message.RouteModifyArchive,
Timestamp: time.Now().Unix(),
Aid: aid,
EditArchive: aChange,
EditVideo: vChange,
}
log.Info("aid(%d) send modifyArchive to databus by EditArchive(%v) EditVideo(%v)", aid, aChange, vChange)
if err = s.busSendMsg(msg); err != nil {
s.msgCh <- msg
}
return
}
func (s *Service) busSecondRound(aid, missionID int64, notify bool, email, changeTypeID, changeCopyright, changeTitle, ChangeCover bool, fromList string, ap *archive.ArcParam) (err error) {
sendEmail := true
if ap != nil {
sendEmail = !ap.NoEmail
}
var msg = &message.Videoup{
Route: message.RouteSecondRound,
Aid: aid,
Notify: notify,
MissionID: missionID,
Timestamp: time.Now().Unix(),
AdminChange: email,
ChangeTypeID: changeTypeID,
ChangeCopyright: changeCopyright,
ChangeTitle: changeTitle,
ChangeCover: ChangeCover,
FromList: fromList,
SendEmail: sendEmail,
}
log.Info("aid(%d) start to send secondRound msg(%+v) to databus", aid, msg)
if err = s.busSendMsg(msg); err != nil {
s.msgCh <- msg
}
return
}
func (s *Service) busSecondRoundUpCredit(aid, cid, mid, uid int64, state, round int8, reasonID int64, reason string) (err error) {
if mid == 0 || aid == 0 {
return
}
var msg = &up.CreditLog{
Type: round,
Optyte: state,
Reason: reasonID,
BusinessType: up.CreditBusinessTypeArchive,
MID: mid,
OID: aid,
UID: uid,
Content: reason,
Ctime: time.Now().Unix(),
Extra: map[string]interface{}{"cid": cid},
}
var c = context.TODO()
log.Info("aid(%d) start to send busSecondRoundUpCredit msg(%+v) to databus", aid, msg)
if err = s.upCreditPub.Send(c, string(msg.OID)+string(msg.UID), msg); err != nil {
log.Error("aid(%d) s.upCreditPub.Send(%+v) error(%v)", msg.OID, msg, err)
}
return
}
//func (s *Service) busDeleteVideo(aid int64, filename string) (err error) {
// var msg = &message.Videoup{
// Route: message.RouteDeleteVideo,
// Timestamp: time.Now().Unix(),
// Aid: aid,
// Filename: filename,
// }
// log.Info("aid(%d) filename(%s) start to send deleteVideo to databus", aid, filename)
// if err = s.busSendMsg(msg); err != nil {
// s.msgCh <- msg
// }
// return
//}
func (s *Service) busSendMsg(msg *message.Videoup) (err error) {
var c = context.TODO()
switch msg.Route {
case message.RouteFirstRound, message.RouteUGCFirstRound, message.RouteDeleteVideo:
if err = s.videoupPub.Send(c, msg.Filename, msg); err != nil {
log.Error("filename(%s) %s s.videoupPub.Send(%+v) error(%v)", msg.Filename, msg.Route, msg, err)
}
case message.RouteSecondRound, message.RouteModifyArchive, message.RouteForceSync:
if err = s.videoupPub.Send(c, strconv.FormatInt(msg.Aid, 10), msg); err != nil {
log.Error("aid(%d) %s s.videoupPub.Send(%+v) error(%v)", msg.Aid, msg.Route, msg, err)
}
default:
log.Warn("databuserr can't process the type (%s)", msg.Route)
}
return
}
// databus err proc
func (s *Service) msgproc() {
// NOTE: chan
s.wg.Add(1)
go func() {
var (
c = context.TODO()
msg *message.Videoup
ok bool
err error
)
defer s.wg.Done()
for {
if msg, ok = <-s.msgCh; !ok {
log.Info("msgproc s.msgCh stop")
return
}
log.Info("aid(%d) filename(%s) get msg(%+v) from s.msgCh", msg.Aid, msg.Filename, msg)
if err = s.busSendMsg(msg); err != nil {
s.busCache.PushMsgCache(c, msg)
time.Sleep(100 * time.Millisecond)
}
}
}()
// NOTE: from redis list when chan error
s.wg.Add(1)
go func() {
var (
c = context.TODO()
msg *message.Videoup
err error
)
defer s.wg.Done()
for {
if s.closed {
log.Info("second msgproc service is close")
return
}
if msg, err = s.busCache.PopMsgCache(c); err != nil {
log.Error("msgproc s.busCache.PopMsgCache() error(%v)", err)
time.Sleep(100 * time.Millisecond)
continue
}
if msg == nil {
select {
case <-time.After(3 * time.Minute):
continue
case <-s.stop:
return
}
}
log.Info("aid(%d) filename(%s) get msg(%+v) from redis", msg.Aid, msg.Filename, msg)
if err = s.busSendMsg(msg); err != nil {
s.busCache.PushMsgCache(c, msg)
time.Sleep(100 * time.Millisecond)
}
}
}()
}

View File

@@ -0,0 +1,533 @@
package service
import (
"context"
"errors"
"hash/crc32"
"strconv"
"strings"
"time"
"go-common/app/admin/main/videoup/model/archive"
mngmdl "go-common/app/admin/main/videoup/model/manager"
accApi "go-common/app/service/main/account/api"
upsrpc "go-common/app/service/main/up/api/v1"
"go-common/library/log"
"go-common/library/sync/errgroup"
xtime "go-common/library/time"
"go-common/library/xstr"
)
//ERROR
var (
ErrRPCEmpty = errors.New("rpc reply empty")
)
func (s *Service) archiveRound(c context.Context, a *archive.Archive, aid, mid int64, typeID int16, nowRound, newState int8, cancelMission bool) (round int8) {
//非特殊分区私单定时发布时,稿件进入四审
//一个私单且定时发布的稿件 应该是先通过待审 传递到 私单四审 ,私单四审开放浏览后到达设置的定时时间最后再自动发布
if s.isPorder(a) && newState == archive.StateForbidUserDelay && !s.isAuditType(typeID) {
round = archive.RoundReviewFlow
return
}
//定时发布的付费稿件 投上来就是round24 admin提交不需要再走付费审核
//定时发布
if newState == archive.StateForbidAdminDelay || newState == archive.StateForbidUserDelay {
round = nowRound
return
}
var addit *archive.Addit
//活动稿件(非私单且非付费) | pgc 稿件 up_from(1,5,6) 直接round 99 简单流程业务
if addit, _ = s.arc.Addit(c, aid); addit != nil && (addit.UpFrom == archive.UpFromPGC || addit.UpFrom == archive.UpFromSecretPGC || addit.UpFrom == archive.UpFromCoopera || (addit.MissionID > 0 && !s.isPorder(a) && !s.isUGCPay(a))) {
if addit.UpFrom == archive.UpFromSecretPGC && newState == archive.StateForbidWait {
//pgc 机密待审state=-1 不变更round
round = nowRound
return
}
if archive.NormalState(newState) {
//pgc 生产组机密稿件(番剧、付费版权,严格要求时效和保密性) up_from=5 开放回查流程 90
if addit.UpFrom == archive.UpFromSecretPGC && nowRound < archive.RoundTriggerClick {
//三查
round = archive.RoundTriggerClick
return
}
}
//pgc 生产组常规稿件(片包等其他内容) up_from=1 进三审
if addit.UpFrom == archive.UpFromPGC && nowRound < archive.RoundAuditThird {
round = archive.RoundAuditThird
return
}
//pgc 合作方嵌套,终结
if addit.UpFrom == archive.UpFromCoopera && nowRound < archive.RoundAuditThird {
round = archive.RoundEnd
return
}
round = archive.RoundEnd
return
}
//其他稿件 非定时活动pgc
if nowRound == archive.RoundAuditSecond {
//二审阶段
if newState == archive.StateForbidWait {
//1、非特殊分区私单进入私单四审2、私单活动稿件进入私单四审
if (s.isPorder(a) && !s.isAuditType(typeID)) || (s.isPorder(a) && !cancelMission && addit.MissionID > 0) {
//私单四审
round = archive.RoundReviewFlow
} else if s.isUGCPay(a) && (!s.isAuditType(typeID) || !s.isPorder(a) || (!cancelMission && addit.MissionID > 0)) {
//付费稿件 非特殊分区 非私单
round = archive.RoundAuditUGCPayFlow
} else if s.isAuditType(typeID) || (addit != nil && addit.OrderID > 0) {
//特殊分区 ,商单到三审 二审到三审
round = archive.RoundAuditThird
} else {
//不变
round = archive.RoundAuditSecond
}
} else if archive.NormalState(newState) {
//回查控制
round = s.normalRound(c, aid, mid, typeID, nowRound, newState)
} else if newState == archive.StateForbidFixed {
//1、非特殊分区私单进入私单四审修复待审2、私单+活动稿件进入私单四审修复待审
if (s.isPorder(a) && !s.isAuditType(typeID)) || (s.isPorder(a) && !cancelMission && addit.MissionID > 0) {
round = archive.RoundReviewFlow
} else if s.isAuditType(typeID) && !(!cancelMission && addit.MissionID > 0) {
//特殊分区 二审到三审
round = archive.RoundAuditThird
} else if s.isUGCPay(a) && (!s.isAuditType(typeID) || !s.isPorder(a) || (!cancelMission && addit.MissionID > 0)) {
//付费稿件 非特殊分区 非私单
round = archive.RoundAuditUGCPayFlow
} else {
//不变
round = archive.RoundAuditSecond
}
} else {
round = archive.RoundEnd
}
} else if nowRound == archive.RoundReviewFlow {
//私单四审21
if archive.NormalState(newState) {
if s.isAuditType(typeID) || addit.MissionID > 0 {
round = archive.RoundEnd
} else {
round = s.normalRound(c, aid, mid, typeID, nowRound, newState)
}
} else {
round = archive.RoundEnd
}
} else if nowRound == archive.RoundAuditUGCPayFlow {
//付费待审 24
if archive.NormalState(newState) {
if s.isAuditType(typeID) || addit.MissionID > 0 {
round = archive.RoundEnd
} else {
round = s.normalRound(c, aid, mid, typeID, nowRound, newState)
}
} else {
round = archive.RoundEnd
}
} else if nowRound == archive.RoundReviewFirst {
//一查
if archive.NormalState(newState) {
round = archive.RoundReviewFirstWaitTrigger
} else {
round = archive.RoundEnd
}
} else if nowRound == archive.RoundAuditThird {
//三审
if s.isPorder(a) {
//私单四审
round = archive.RoundReviewFlow
} else if s.isUGCPay(a) {
round = archive.RoundAuditUGCPayFlow
} else {
round = archive.RoundEnd
}
} else if nowRound == archive.RoundReviewSecond || nowRound == archive.RoundTriggerClick {
//二查 三查
round = archive.RoundEnd
} else {
round = nowRound
}
return
}
//normalRound 回查逻辑
func (s *Service) normalRound(c context.Context, aid, mid int64, typeID int16, nowRound, newState int8) (round int8) {
if s.isWhite(mid) || s.isBlack(mid) {
round = archive.RoundReviewSecond
} else if plf, _ := s.profile(c, mid); plf != nil && plf.Follower >= s.fansCache {
//社区回查 粉丝阈值
round = archive.RoundReviewSecond
} else if plf != nil && plf.Follower < s.fansCache && s.isRoundType(typeID) {
//回查分区
round = archive.RoundReviewFirst // NOTE: if audit type, state must not open!!! so cannot execute here...
} else {
//点击量回查
round = archive.RoundReviewFirstWaitTrigger
if plf == nil {
log.Info("archive(%d) card(%d) is nil", aid, mid)
} else {
log.Info("archive(%d) card(%d) fans(%d) little than config(%d)", aid, mid, plf.Follower, s.fansCache)
}
}
return
}
func (s *Service) hadPassed(c context.Context, aid int64) (had bool) {
id, err := s.arc.GetFirstPassByAID(c, aid)
if err != nil {
log.Error("hadPassed s.arc.GetFirstPassByAID error(%v) aid(%d)", err, aid)
return
}
had = id > 0
return
}
func (s *Service) isPorder(a *archive.Archive) bool {
if a == nil {
return false
}
return a.AttrVal(archive.AttrBitIsPorder) == archive.AttrYes
}
//ugc pay only
func (s *Service) isUGCPay(a *archive.Archive) bool {
if a == nil {
return false
}
return a.AttrVal(archive.AttrBitUGCPay) == archive.AttrYes
}
func (s *Service) profile(c context.Context, mid int64) (card *accApi.ProfileStatReply, err error) {
if card, err = s.accRPC.ProfileWithStat3(c, &accApi.MidReq{Mid: mid}); err != nil {
log.Error("s.accRPC.ProfileWithStat3(%d) error(%v)", mid, err)
}
return
}
func (s *Service) upCards(c context.Context, mids []int64) (p map[int64]*accApi.Card, err error) {
p = make(map[int64]*accApi.Card)
if len(mids) == 0 {
return
}
var res *accApi.CardsReply
if res, err = s.accRPC.Cards3(c, &accApi.MidsReq{Mids: mids}); err != nil {
p = nil
log.Error("s.accRPC.Cards3(%v) error(%v)", mids, err)
return
}
p = res.Cards
return
}
func (s *Service) archivePtime(c context.Context, aid int64, newState int8, newPtime xtime.Time) (ptime xtime.Time) {
if newState >= archive.StateOpen {
if !s.hadPassed(c, aid) {
ptime = xtime.Time(time.Now().Unix())
return
}
}
ptime = newPtime
return
}
func (s *Service) archiveAttr(c context.Context, ap *archive.ArcParam, isExt bool) (attrs map[uint]int32, forbidAttrs map[string]map[uint]int32) {
//批量和单个提交都需要补全对应属性值
attrs = make(map[uint]int32)
attrs[archive.AttrBitNoRank] = ap.Attrs.NoRank
attrs[archive.AttrBitNoDynamic] = ap.Attrs.NoDynamic
attrs[archive.AttrBitNoWeb] = ap.Attrs.NoWeb
attrs[archive.AttrBitNoMobile] = ap.Attrs.NoMobile
attrs[archive.AttrBitNoSearch] = ap.Attrs.NoSearch
attrs[archive.AttrBitOverseaLock] = ap.Attrs.OverseaLock
attrs[archive.AttrBitNoRecommend] = ap.Attrs.NoRecommend
attrs[archive.AttrBitNoReprint] = ap.Attrs.NoReprint
attrs[archive.AttrBitHasHD5] = ap.Attrs.HasHD5
attrs[archive.AttrBitAllowBp] = ap.Attrs.AllowBp
attrs[archive.AttrBitIsPorder] = ap.Attrs.IsPorder
attrs[archive.AttrBitLimitArea] = ap.Attrs.LimitArea
attrs[archive.AttrBitPushBlog] = ap.Attrs.PushBlog
attrs[archive.AttrBitUGCPay] = ap.Attrs.UGCPay
attrs[archive.AttrBitParentMode] = ap.Attrs.ParentMode
// pgc
attrs[archive.AttrBitIsMovie] = ap.Attrs.IsMovie
attrs[archive.AttrBitBadgepay] = ap.Attrs.BadgePay
attrs[archive.AttrBitIsBangumi] = ap.Attrs.IsBangumi
attrs[archive.AttrBitIsPGC] = ap.Attrs.IsPGC
if isExt {
attrs[archive.AttrBitAllowTag] = ap.Attrs.AllowTag
attrs[archive.AttrBitJumpURL] = ap.Attrs.JumpURL
}
forbidAttrs = make(map[string]map[uint]int32, 4)
forbidAttrs[archive.ForbidRank] = map[uint]int32{
archive.ForbidRankMain: ap.Forbid.Rank.Main,
archive.ForbidRankRecentArc: ap.Forbid.Rank.RecentArc,
archive.ForbidRankAllArc: ap.Forbid.Rank.AllArc,
}
forbidAttrs[archive.ForbidDynamic] = map[uint]int32{
archive.ForbidDynamicMain: ap.Forbid.Dynamic.Main,
}
forbidAttrs[archive.ForbidRecommend] = map[uint]int32{
archive.ForbidRecommendMain: ap.Forbid.Recommend.Main,
}
forbidAttrs[archive.ForbidShow] = map[uint]int32{
archive.ForbidShowMain: ap.Forbid.Show.Main,
archive.ForbidShowMobile: ap.Forbid.Show.Mobile,
archive.ForbidShowWeb: ap.Forbid.Show.Web,
archive.ForbidShowOversea: ap.Forbid.Show.Oversea,
archive.ForbidShowOnline: ap.Forbid.Show.Online,
}
return
}
func (s *Service) isAccess(c context.Context, aid int64) (wm bool) {
var vs []*archive.Video
if vs, _ = s.arc.NewVideosByAid(c, aid); len(vs) <= 0 {
return
}
for _, v := range vs {
if v.Status == 10000 {
wm = true
return
}
}
return
}
// CheckArchive check typeid
func (s *Service) CheckArchive(aps []*archive.ArcParam) bool {
for _, ap := range aps {
if ap.Aid == 0 || ap.UID == 0 {
return false
}
}
return true
}
// CheckVideo check video
func (s *Service) CheckVideo(vps []*archive.VideoParam) bool {
for _, vp := range vps {
if vp.ID == 0 || vp.Aid == 0 || vp.Filename == "" || vp.Cid == 0 || vp.UID == 0 {
return false
}
}
return true
}
// CheckStaff check
func (s *Service) CheckStaff(vps []*archive.StaffParam) bool {
//允许为空 不允许为Nil
if len(vps) == 0 {
return true
}
for _, vp := range vps {
if vp.MID == 0 || vp.Title == "" {
return false
}
}
return true
}
// TypeTopParent get archive type's first level type
func (s *Service) TypeTopParent(tid int16) (tp *archive.Type, err error) {
if _, ok := s.typeCache[tid]; !ok {
err = errors.New("archive type id not exist. id:" + strconv.Itoa(int(tid)))
return
}
if s.typeCache[tid].PID == 0 {
tp = s.typeCache[tid]
} else {
tp, err = s.TypeTopParent(s.typeCache[tid].PID)
if err != nil {
return
}
}
return
}
//StringHandler handle two strings 以s1顺序为准
func StringHandler(s1 string, s2 string, delimiter string, subtraction bool) string {
if strings.TrimSpace(s2) == "" {
return s1
}
var (
res []string
duplicate []int
)
s1Arr := strings.Split(s1, delimiter)
s2Arr := strings.Split(s2, delimiter)
for _, s1Item := range s1Arr {
dupIndex := -1
for k, s2Item := range s2Arr {
if s1Item == s2Item {
dupIndex = k
break
}
}
if dupIndex >= 0 && subtraction {
continue
}
if dupIndex >= 0 {
duplicate = append(duplicate, dupIndex)
}
res = append(res, s1Item)
}
if !subtraction {
for k, s2Item := range s2Arr {
s2Item = strings.TrimSpace(s2Item)
if s2Item == "" {
continue
}
add := true
for _, dup := range duplicate {
if k == dup {
add = false
break
}
}
if add {
res = append(res, s2Item)
}
}
}
return strings.Join(res, delimiter)
}
// SplitInts 去掉id字符串中的空白字符
func (s *Service) SplitInts(str string) ([]int64, error) {
empties := []string{" ", "\n", "\t", "\r"}
for _, v := range empties {
str = strings.Replace(str, v, "", -1)
}
str = strings.Trim(str, ",")
return xstr.SplitInts(str)
}
// coverURL convert cover url to full url.
func coverURL(uri string) (cover string) {
if uri == "" {
cover = "http://static.hdslb.com/images/transparent.gif"
return
}
cover = uri
if strings.Index(uri, "http://") == 0 {
return
}
if len(uri) >= 10 && uri[:10] == "/templets/" {
return
}
if strings.HasPrefix(uri, "group1") {
cover = "http://i0.hdslb.com/" + uri
return
}
if pos := strings.Index(uri, "/uploads/"); pos != -1 && (pos == 0 || pos == 3) {
cover = uri[pos+8:]
}
cover = strings.Replace(cover, "{IMG}", "", -1)
cover = "http://i" + strconv.FormatInt(int64(crc32.ChecksumIEEE([]byte(cover)))%3, 10) + ".hdslb.com" + cover
return
}
func (s *Service) upGroupMids(c context.Context, gid int64) (mids []int64, err error) {
var (
total int
maxps = 10000
req = &upsrpc.UpGroupMidsReq{
Pn: 1,
GroupID: gid,
Ps: maxps,
}
reply *upsrpc.UpGroupMidsReply
)
for {
reply, err = s.upsRPC.UpGroupMids(c, req)
if err == nil && (reply == nil || reply.Mids == nil) {
err = ErrRPCEmpty
}
if err != nil {
log.Error("UpGroupMids req(%+v) error(%v)", req, err)
return
}
total = reply.Total
mids = append(mids, reply.Mids...)
if reply.Size() != maxps {
break
}
req.Pn++
}
log.Info("upGroupMids(%d) reply total(%d) len(%d)", gid, total, len(mids))
return
}
func (s *Service) upSpecial(c context.Context) (ups map[int8]map[int64]struct{}, err error) {
var (
g errgroup.Group
whitegroup, blackgroup, pgcgroup, ugcxgroup, policygroup, dangergroup, twoforbidgroup, pgcwhitegroup map[int64]struct{}
)
ups = make(map[int8]map[int64]struct{})
f := func(gid int8) (map[int64]struct{}, error) {
group := make(map[int64]struct{})
mids, e := s.upGroupMids(c, int64(gid))
if e != nil {
return group, e
}
for _, mid := range mids {
group[mid] = struct{}{}
}
return group, nil
}
g.Go(func() error {
whitegroup, err = f(mngmdl.UpperTypeWhite)
return err
})
g.Go(func() error {
blackgroup, err = f(mngmdl.UpperTypeBlack)
return err
})
g.Go(func() error {
pgcgroup, err = f(mngmdl.UpperTypePGC)
return err
})
g.Go(func() error {
ugcxgroup, err = f(mngmdl.UpperTypeUGCX)
return err
})
g.Go(func() error {
policygroup, err = f(mngmdl.UpperTypePolity)
return err
})
g.Go(func() error {
dangergroup, err = f(mngmdl.UpperTypeDanger)
return err
})
g.Go(func() error {
twoforbidgroup, err = f(mngmdl.UpperTypeTwoForbid)
return err
})
g.Go(func() error {
pgcwhitegroup, err = f(mngmdl.UpperTypePGCWhite)
return err
})
if err = g.Wait(); err != nil {
return
}
ups[mngmdl.UpperTypeWhite] = whitegroup
ups[mngmdl.UpperTypeBlack] = blackgroup
ups[mngmdl.UpperTypePGC] = pgcgroup
ups[mngmdl.UpperTypeUGCX] = ugcxgroup
ups[mngmdl.UpperTypePolity] = policygroup
ups[mngmdl.UpperTypeDanger] = dangergroup
ups[mngmdl.UpperTypeTwoForbid] = twoforbidgroup
ups[mngmdl.UpperTypePGCWhite] = pgcwhitegroup
return
}

View File

@@ -0,0 +1,100 @@
package service
import (
"context"
"fmt"
. "github.com/smartystreets/goconvey/convey"
"go-common/app/admin/main/videoup/conf"
"testing"
)
func TestTypeTopParent(t *testing.T) {
err := conf.Init()
if err != nil {
return
}
s := New(conf.Conf)
Convey("test TypeTopParent", t, func() {
_, err := s.TypeTopParent(int16(1808))
So(err, ShouldNotBeNil)
})
}
// TestArchiveRound 测试商单稿件round
func TestPorderArchiveRound(t *testing.T) {
var (
c = context.TODO()
aid int64 = 5464730 //稿件id
mid int64 = 254386 //up主id
typeID int16 = 22 //分区id
nowRound int8 = 10 //二审提交
newState int8 = -40 //定时发布
resRound = 21 //最终返回的round结果
)
err := conf.Init()
if err != nil {
return
}
s := New(conf.Conf)
Convey("test TestPorderArchiveRound", t, func() {
round := s.archiveRound(c, nil, aid, mid, typeID, nowRound, newState, false)
//round == 21
So(round, ShouldEqual, resRound)
})
}
func TestStringHandler(t *testing.T) {
var res string
delimiter := ","
s1 := "t1,t2"
s2 := "t1"
s3 := "t2"
s4 := "t3"
s5 := "t1,t2,t3"
s6 := "t1,t3,t4,t5"
s7 := "t1,t2,t3,t4,t5"
Convey("StringHandler", t, func() {
//增删空字符串
res = StringHandler(s1, "", delimiter, false)
So(res, ShouldEqual, s1)
res = StringHandler(s1, "", delimiter, true)
So(res, ShouldEqual, s1)
//增删重复字符串
res = StringHandler(s1, s2, delimiter, false)
So(res, ShouldEqual, s1)
res = StringHandler(s1, s2, delimiter, true)
So(res, ShouldEqual, s3)
//增删不重复字符串
res = StringHandler(s1, s4, delimiter, false)
So(res, ShouldEqual, s5)
res = StringHandler(s1, s4, delimiter, true)
So(res, ShouldEqual, s1)
//增删多个重复,且多个不重复字符串
res = StringHandler(s5, s6, delimiter, false)
So(res, ShouldEqual, s7)
res = StringHandler(s5, s6, delimiter, true)
So(res, ShouldEqual, s3)
})
}
// TestSplitInts
func TestSplitInts(t *testing.T) {
var (
str = " 123,334343\n,\t1\r11"
)
err := conf.Init()
if err != nil {
return
}
s := New(conf.Conf)
Convey("test TestSplitInts", t, func() {
ids, err := s.SplitInts(str)
fmt.Print(ids)
So(ids, ShouldNotBeNil)
So(err, ShouldBeNil)
})
}

View File

@@ -0,0 +1,230 @@
package service
import (
"context"
"encoding/json"
"strings"
"go-common/app/admin/main/videoup/model/archive"
"go-common/library/database/sql"
"go-common/library/log"
)
// txUpFlowID update flow_id by videoParam.
func (s *Service) txUpFlowID(tx *sql.Tx, ap *archive.ArcParam) (err error) {
if _, err = s.arc.TxUpFlowID(tx, ap.Aid, ap.OnFlowID); err != nil {
log.Error("archive_forbid.on_flow_id s.TxUpFlowID(%d,%d) error(%v)", ap.Aid, ap.OnFlowID, err) // NOTE: update es index question , if after update archive table
return
}
var flowID int64
if flowID, err = s.arc.FlowByPool(archive.PoolPrivateOrder, ap.Aid); err != nil {
log.Error("flow_design s.arc.FlowByPool(%d,%d,%d) error(%v)", ap.Aid, ap.UID, ap.OnFlowID, err)
return
}
if flowID > 0 {
if _, err = s.arc.TxUpFlow(tx, flowID, ap.OnFlowID, ap.UID); err != nil {
log.Error("flow_design s.arc.TxUpFlow(%d,%d,%d) error(%v)", ap.Aid, ap.UID, ap.OnFlowID, err)
return
}
if _, err = s.arc.TxAddFlowLog(tx, archive.PoolPrivateOrder, archive.FlowLogUpdate, ap.Aid, ap.UID, ap.OnFlowID, "审核后台修改稿件私单类型"); err != nil {
log.Error("s.arc.TxAddFlowLog(%d,%d,%d) error(%v)", ap.Aid, ap.UID, ap.OnFlowID, err)
return
}
} else {
if _, err = s.txAddFlow(tx, archive.PoolPrivateOrder, ap.Aid, ap.OnFlowID, ap.UID, "审核后台添加稿件私单类型"); err != nil {
log.Error("flow_design s.arc.TxAddFlow(%d,%d,%d) error(%v)", ap.Aid, ap.UID, ap.OnFlowID, err)
return
}
}
log.Info("aid(%d) flowid(%d)", ap.Aid, ap.OnFlowID)
return
}
/**
* txAddFlow 新增流量套餐的记录
* return int64, error/nil
*/
func (s *Service) txAddFlow(tx *sql.Tx, pool int8, oid, groupID, uid int64, remark string) (id int64, err error) {
if id, err = s.arc.TxAddFlow(tx, pool, oid, uid, groupID, remark); err != nil {
log.Error("txAddFlow s.arc.TxAddFlow(%d,%d,%d,%d,%s) error(%v)", pool, oid, uid, groupID, remark, err)
return
}
if id <= 0 {
return
}
if _, err = s.arc.TxAddFlowLog(tx, pool, archive.FlowLogAdd, oid, uid, groupID, remark); err != nil {
log.Error("txAddFlow s.arc.TxAddFlowLog(%d,%d,%d,%d,%s) error(%v)", pool, oid, uid, groupID, remark, err)
return
}
return
}
/**
* txUpFlowState 更新流量套餐的状态
* return error/nil
*/
func (s *Service) txUpFlowState(tx *sql.Tx, state int8, uid int64, f *archive.FlowData) (err error) {
if f == nil {
return
}
var rows int64
if rows, err = s.arc.TxUpFlowState(tx, f.ID, state); err != nil {
log.Error("updateFlowState s.arc.TxUpFlowState error(%v) id(%d) state(%d)", err, f.ID, state)
return
}
if rows <= 0 {
return
}
action := archive.FlowLogUpdate
if state == archive.FlowDelete {
action = archive.FlowLogDel
}
if _, err = s.arc.TxAddFlowLog(tx, f.Pool, action, f.OID, uid, f.GroupID, "审核后台修改状态"); err != nil {
log.Error("updateFlowState s.arc.TxAddFlowLog error(%v) pool(%d) oid(%d) uid(%d) state(%d)", err, f.Pool, f.OID, uid, state)
return
}
return
}
/**
* getFlowsByOID 命中哪些流量套餐
* return []*archive.FlowData, error/nil
*/
func (s *Service) getFlowsByOID(c context.Context, oid int64) (flows []*archive.FlowData, err error) {
if flows, err = s.arc.FlowsByOID(c, oid); err != nil {
log.Error("getFlowsByOID s.arc.FlowsByOID error(%v) oid(%d)", err, oid)
return
}
return
}
/**
* txAddOrUpdateFlowState 新增或更新流量套餐的状态
* return *archive.FlowData/nil, bool, error/nil
*/
func (s *Service) txAddOrUpdateFlowState(c context.Context, tx *sql.Tx, oid, groupID, uid int64, pool, state int8, remark string) (flow *archive.FlowData, diff string, err error) {
var (
old, nw int8
)
defer func() {
if err == nil && old != nw {
tagID := archive.FlowOperType[groupID]
if tagID > 0 {
stateMap := map[int8]string{archive.FlowOpen: "是", archive.FlowDelete: "否"}
diff = strings.TrimSpace(archive.Operformat(tagID, stateMap[old], stateMap[nw], archive.OperStyleOne))
}
}
}()
if flow, err = s.arc.FlowUnique(c, oid, groupID, pool); err != nil {
log.Error("txAddOrUpdateFlowState s.arc.FlowUnique(%d,%d,%d) error(%v) state(%d)", oid, groupID, pool, err, state)
return
}
//无数据前提下,新状态=state就没必要添加数据啦
if flow == nil && state == archive.FlowDelete {
return
}
if flow == nil {
flow = &archive.FlowData{Pool: pool, OID: oid, GroupID: groupID, State: archive.FlowOpen}
if flow.ID, err = s.txAddFlow(tx, flow.Pool, flow.OID, flow.GroupID, uid, remark); err != nil {
log.Error("txAddOrUpdateFlowState s.txAddFlow error(%v) flow(%+v) state(%d)", err, flow, state)
return
}
old = archive.FlowDelete
nw = archive.FlowOpen
} else {
old = flow.State
nw = state
}
if flow.State == state {
return
}
if err = s.txUpFlowState(tx, state, uid, flow); err != nil {
log.Error("txAddOrUpdateFlowState s.txUpdateFlowState error(%v) flow(%+v) state(%d) ", err, flow, state)
return
}
flow.State = state
nw = state
return
}
//HitFlowGroups 命中哪些指定的流量套餐
func (s *Service) HitFlowGroups(c context.Context, oid int64, includePools []int8) (res map[string]int, err error) {
var (
flows []*archive.FlowData
)
res = map[string]int{}
includes := map[int8]int8{}
if flows, err = s.getFlowsByOID(c, oid); err != nil {
return
}
for _, p := range includePools {
includes[p] = 1
}
for _, f := range flows {
if includes[f.Pool] != 1 {
continue
}
//merge their values
value := map[string]int{}
if err = json.Unmarshal(f.GroupValue, &value); err != nil {
log.Error("HitFlowGroups json.Unmarshal error(%v) value(%s) oid(%d) flow.id(%d)", err, string(f.GroupValue), oid, f.ID)
return
}
for attr, val := range value {
if val == 1 {
res[attr] = val
}
}
}
log.Info("HitFlowGroups oid(%d) includepools(%v) res(%+v)", oid, includePools, res)
return
}
func (s *Service) txBatchUpFlowsState(c context.Context, tx *sql.Tx, aid, uid int64, pm map[string]int32) (conts []string, err error) {
var (
diff string
groups []int64
pools map[int64]int8
)
groupStates := map[int64]int8{}
for attr, state := range pm {
groupID := archive.FlowAttrMap[attr]
if groupID <= 0 {
continue
}
groups = append(groups, groupID)
if state == 0 {
groupStates[groupID] = archive.FlowDelete
} else {
groupStates[groupID] = archive.FlowOpen
}
}
if len(groups) <= 0 {
return
}
if pools, err = s.arc.FlowGroupPools(c, groups); err != nil {
log.Error("txBatchUpFlowsState s.arc.FlowGroupPools(%v) error(%v) params(%+v)", groups, err, pm)
return
}
for groupID, pool := range pools {
if _, diff, err = s.txAddOrUpdateFlowState(c, tx, aid, groupID, uid, pool, groupStates[groupID], "审核后台修改"); err != nil {
log.Error("txBatchUpFlowsState s.txAddOrUpdateFlowState(%d,%d,%d,%d,%d) error(%v) params(%+v)", aid, groupID, uid, pool, groupStates[groupID], err, pm)
return
}
if diff != "" {
conts = append(conts, diff)
}
}
log.Info("txBatchUpFlowsState aid(%d) params(%+v) conts(%v)", aid, pm, conts)
return
}

View File

@@ -0,0 +1,102 @@
package service
import (
"context"
. "github.com/smartystreets/goconvey/convey"
"go-common/app/admin/main/videoup/model/archive"
"testing"
)
func TestService_GetFlowsByOID(t *testing.T) {
Convey("getFlowsByOID", t, WithService(func(s *Service) {
var (
c = context.TODO()
oid = int64(2222)
res []*archive.FlowData
err error
)
res, err = s.getFlowsByOID(c, oid)
t.Logf("res(%+v) error(%v)", res, err)
So(err, ShouldBeNil)
}))
}
func TestService_TxAddFlow(t *testing.T) {
var (
id int64
err error
)
Convey("txAddFlow", t, WithService(func(s *Service) {
c := context.TODO()
tx, _ := s.arc.BeginTran(c)
id, err = s.txAddFlow(tx, archive.PoolArcForbid, 1, archive.FlowGroupNoChannel, 421, "测试-频道禁止-添加")
tx.Commit()
So(id, ShouldBeGreaterThan, 0)
So(err, ShouldBeNil)
}))
}
func TestService_TxUpFlowState(t *testing.T) {
var (
err error
)
Convey("TxUpFlowState", t, WithService(func(s *Service) {
c := context.TODO()
f := &archive.FlowData{ID: 540, Pool: archive.PoolArcForbid, OID: 1, GroupID: archive.FlowGroupNoChannel}
tx, _ := s.arc.BeginTran(c)
err = s.txUpFlowState(tx, archive.FlowDelete, 421, f)
tx.Commit()
So(err, ShouldBeNil)
}))
}
func TestService_txAddOrUpdateFlowState(t *testing.T) {
Convey("txAddOrUpdateFlowState", t, WithService(func(s *Service) {
var (
c = context.TODO()
group = archive.FlowGroupNoChannel
pool = archive.PoolArcForbid
err error
diff string
res *archive.FlowData
)
tx, _ := s.arc.BeginTran(c)
res, diff, err = s.txAddOrUpdateFlowState(c, tx, 16, group, 421, pool, archive.FlowDelete, "新增测试啦")
t.Logf("res(%+v) diff(%s) error(%v)", res, diff, err)
So(err, ShouldBeNil)
tx.Commit()
tx, _ = s.arc.BeginTran(c)
res, diff, err = s.txAddOrUpdateFlowState(c, tx, 16, group, 421, pool, archive.FlowOpen, "修改state测试啦")
t.Logf("res(%+v) diff(%s) error(%v)", res, diff, err)
So(err, ShouldBeNil)
tx.Commit()
}))
}
func TestService_HitFlowGroups(t *testing.T) {
Convey("HitFlowGroups", t, WithService(func(s *Service) {
var (
c = context.TODO()
oid = int64(2222)
res map[string]int
err error
)
res, err = s.HitFlowGroups(c, oid, []int8{})
t.Logf("res(%+v) error(%v)", res, err)
So(err, ShouldBeNil)
res, err = s.HitFlowGroups(c, oid, []int8{archive.PoolUp})
t.Logf("res(%+v) error(%v)", res, err)
So(err, ShouldBeNil)
}))
}

View File

@@ -0,0 +1,70 @@
package service
import (
"context"
"go-common/app/admin/main/videoup/model/archive"
"go-common/library/log"
"time"
)
//EditHistory 根据稿件的某条编辑历史id获取当时完整的稿件、分p视频编辑历史
func (s *Service) EditHistory(c context.Context, hid int64) (h *archive.EditHistory, err error) {
arcHistory, err := s.arc.HistoryByID(c, hid)
if err != nil {
log.Error("EditHistory s.arc.HistoryByID(hid(%d)) error(%v)", hid, err)
return nil, err
}
vHistory, err := s.arc.VideoHistoryByHID(c, hid)
if err != nil {
log.Error("EditHistory s.arc.VideoHistoryByHID(hid(%d)) error(%v)", hid, err)
return nil, err
}
h = &archive.EditHistory{
ArcHistory: arcHistory,
VHistory: vHistory,
}
return
}
//AllEditHistory 根据aid获取 其所有的用户编辑历史
func (s *Service) AllEditHistory(c context.Context, aid int64) (hs []*archive.EditHistory, err error) {
stime := time.Now().Add(time.Hour * 720 * -1)
arcHistory, err := s.arc.HistoryByAID(c, aid, stime)
if err != nil {
log.Error("AllEditHistory s.arc.HistoryByAID(aid(%d)) error(%v)", aid, err)
hs = []*archive.EditHistory{}
return
}
var (
videoHistory []*archive.VideoHistory
prev *archive.EditHistory
total int
)
total = len(arcHistory)
hs = make([]*archive.EditHistory, total)
for i := total - 1; i >= 0; i-- {
h := arcHistory[i]
videoHistory, err = s.arc.VideoHistoryByHID(c, h.ID)
if err != nil {
log.Error("AllEditHistory s.arc.VideoHistoryByHID(hid(%d), aid(%d)) error(%v)", h.ID, aid, err)
return
}
one := &archive.EditHistory{
ArcHistory: h,
VHistory: videoHistory,
}
//only show diff between next edit archive
show, diff := one.Diff(prev)
hs[i] = show
if diff {
prev = one
}
}
return
}

View File

@@ -0,0 +1,43 @@
package service
import (
"context"
"github.com/smartystreets/goconvey/convey"
"testing"
)
func Test_trackArchiveInfo(t *testing.T) {
convey.Convey("稿件编辑历史和track信息合并", t, WithService(func(s *Service) {
c := context.TODO()
aid := int64(1)
inf, err := s.TrackArchiveInfo(c, aid)
convey.So(err, convey.ShouldBeNil)
convey.So(len(inf.Relation), convey.ShouldBeGreaterThanOrEqualTo, len(inf.EditHistory))
for k, it := range inf.Relation {
t.Logf("relation k(%d) it(%v)", k, it)
}
t.Logf("tr len(%d)", len(inf.Track))
}))
}
func Test_editHistory(t *testing.T) {
convey.Convey("hid获取稿件+分P编辑历史", t, WithService(func(s *Service) {
c := context.TODO()
hid := int64(1)
_, err := s.EditHistory(c, hid)
convey.So(err, convey.ShouldBeNil)
}))
}
func Test_allEditHistory(t *testing.T) {
convey.Convey("稿件编辑历史和track信息合并", t, WithService(func(s *Service) {
c := context.TODO()
aid := int64(10107879)
h, err := s.AllEditHistory(c, aid)
for _, o := range h {
t.Logf("ah(%+v) vh(%+v)", o.ArcHistory, o.VHistory)
}
convey.So(err, convey.ShouldBeNil)
}))
}

View File

@@ -0,0 +1,218 @@
package service
import (
"context"
"encoding/json"
"strconv"
"strings"
"time"
"go-common/app/admin/main/videoup/model/archive"
"go-common/app/admin/main/videoup/model/music"
"go-common/app/admin/main/videoup/model/oversea"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/queue/databus/report"
)
// send to log service
func (s *Service) sendVideoLog(c context.Context, vp *archive.VideoParam, others string) (err error) {
var (
v *archive.Video
a *archive.Archive
)
if vp.Cid != 0 {
v, err = s.arc.VideoByCID(c, vp.Cid)
} else if vp.ID != 0 {
v, err = s.arc.NewVideoByID(c, vp.ID)
}
if err != nil || v == nil {
v = &archive.Video{} // ignore err
}
a, err = s.arc.Archive(c, vp.Aid)
if err != nil || a == nil {
a = &archive.Archive{} // ignore err
}
// send
logData := &report.ManagerInfo{
Uname: vp.Oname,
UID: vp.UID,
Business: archive.LogClientVideo,
Type: archive.LogClientTypeVideo,
Oid: vp.Cid,
Action: strconv.Itoa(int(vp.Status)),
Ctime: time.Now(),
Index: []interface{}{int64(vp.Attribute), v.CTime.Time().Unix(), vp.TagID, a.Title, vp.Note},
Content: map[string]interface{}{
"content": vp,
"others": others,
},
}
report.Manager(logData)
return
}
// send to log service
func (s *Service) sendArchiveLog(c context.Context, ap *archive.ArcParam, diff []string, a *archive.Archive) (err error) {
// fmt
ap.CTime = a.CTime
if ap.Title == "" {
ap.Title = a.Title
}
if ap.Attrs == nil {
ap.Attrs = &archive.AttrParam{}
}
diffStr := strings.Join(diff, "\n")
// log
logData := &report.ManagerInfo{
Uname: ap.UName,
UID: ap.UID,
Business: archive.LogClientArchive,
Type: archive.LogClientTypeArchive,
Oid: ap.Aid,
Action: strconv.Itoa(int(ap.State) + int(ap.Access)),
Ctime: time.Now(),
Index: []interface{}{a.Attribute, ap.CTime.Time().Unix(), ap.ReasonID, ap.Title, ap.Note},
Content: map[string]interface{}{
"content": ap,
"diff": diffStr,
},
}
report.Manager(logData)
extra, _ := json.Marshal(logData.Content)
log.Info("sendArchiveLog json.Marshal(%s) logData(%+v) ap(%+v)", extra, logData, ap)
return
}
//SendMusicLog send to log archive music
func (s *Service) SendMusicLog(c *bm.Context, clientType int, ap *music.LogParam) (err error) {
if s.c.Env == "dev" {
return
}
logData := &report.ManagerInfo{
Uname: ap.UName,
UID: ap.UID,
Business: archive.LogClientArchiveMusic,
Type: clientType,
Oid: ap.ID,
Action: ap.Action,
Ctime: time.Now(),
Index: []interface{}{ap.ID},
Content: map[string]interface{}{
"object": ap,
},
}
log.Info("sendMusicLog logData(%+v) ap(%+v)", logData, ap)
report.Manager(logData)
return
}
// sendPorderLog send porder modify log
func (s *Service) sendPorderLog(c context.Context, ap *archive.ArcParam, diff []string, porder *archive.Porder, a *archive.Archive) (err error) {
if a.AttrVal(archive.AttrBitIsPorder) != 1 && ap.Attrs.IsPorder != 1 {
log.Info("sendPorderLog ignore archive.is_porder(%d) ap.is_porder(%d) aid(%d)", a.AttrVal(archive.AttrBitIsPorder), ap.Attrs.IsPorder, a.Aid)
return
}
// fmt
var (
oldP = map[string]interface{}{
"is_porder": a.AttrVal(archive.AttrBitIsPorder),
"brand_id": porder.BrandID,
"brand_name": porder.BrandName,
"show_type": porder.ShowType,
"industry_id": porder.IndustryID,
"official": porder.Official,
"allow_tag": a.AttrVal(archive.AttrBitAllowTag),
}
newP = map[string]interface{}{
"is_porder": ap.Attrs.IsPorder,
"brand_id": ap.BrandID,
"brand_name": ap.BrandName,
"show_type": ap.ShowType,
"industry_id": ap.IndustryID,
"official": ap.Official,
"allow_tag": ap.Attrs.AllowTag,
}
)
ap.CTime = a.CTime
if ap.Title == "" {
ap.Title = a.Title
}
if ap.Attrs == nil {
ap.Attrs = &archive.AttrParam{}
}
diffStr := strings.Join(diff, "\n")
// log
logData := &report.ManagerInfo{
Uname: ap.UName,
UID: ap.UID,
Business: archive.LogClientPorder,
Type: archive.LogClientTypePorderLog,
Oid: ap.Aid,
Action: strconv.Itoa(int(ap.State) + int(ap.Access)),
Ctime: time.Now(),
Index: []interface{}{a.Attribute, ap.CTime.Time().Unix(), ap.ReasonID, ap.Title, ap.Note, ap.Porder.IndustryID, ap.Porder.Official, ap.Porder.GroupID},
Content: map[string]interface{}{
"content": ap,
"diff": diffStr,
"old": oldP,
"new": newP,
},
}
report.Manager(logData)
log.Info("sendPorderLog logData(%+v)", logData.Content)
return
}
// sendConsumerLog send consumer log
func (s *Service) sendConsumerLog(c context.Context, cl *archive.ConsumerLog) (err error) {
logData := &report.ManagerInfo{
Uname: cl.Uname,
UID: cl.UID,
Business: archive.LogClientConsumer,
Type: archive.LogClientTypeConsumer,
Oid: cl.UID,
Action: strconv.Itoa(int(cl.Action)),
Ctime: time.Now(),
Index: []interface{}{cl.UID, cl.Action, cl.Ctime},
Content: map[string]interface{}{
"content": cl,
},
}
report.Manager(logData)
log.Info("sendConsumerLog logData(%+v)", cl)
return
}
// sendPolicyLog send policy modify log
func (s *Service) sendPolicyLog(c context.Context, old, new *oversea.PolicyGroup) (err error) {
var (
action string
)
if new.ID == 0 {
action = "add"
} else if new.State == oversea.StateDeleted {
action = "del"
} else {
action = "update"
}
// log
logData := &report.ManagerInfo{
Uname: new.UserName,
UID: new.UID,
Business: archive.LogClientPolicy,
Type: archive.LogClientTypePolicy,
Oid: new.ID,
Action: action,
Ctime: time.Now(),
Index: []interface{}{new.Type},
Content: map[string]interface{}{
"old": old,
"new": new,
},
}
report.Manager(logData)
log.Info("sendPolicyLog logData(%+v)", logData)
return
}

View File

@@ -0,0 +1,278 @@
package service
import (
"context"
"go-common/app/admin/main/videoup/model/archive"
"go-common/app/admin/main/videoup/model/manager"
"go-common/app/admin/main/videoup/model/monitor"
"go-common/library/log"
"strconv"
"strings"
"time"
"github.com/pkg/errors"
)
// MonitorResult 获取监控业务的统计结果列表
func (s *Service) MonitorResult(c context.Context, p *monitor.RuleResultParams) (res []*monitor.RuleResultData, err error) {
var (
rules []*monitor.Rule
mUser *manager.User
)
res = []*monitor.RuleResultData{}
if rules, err = s.monitor.GetRules(c, p.Type, p.Business, true); err != nil {
return
}
for _, v := range rules {
var stats *monitor.Stats
if stats, err = s.MonitorStats(c, v); err != nil {
return
}
if mUser, err = s.mng.User(c, v.UID); err != nil {
mUser = &manager.User{
ID: v.UID,
}
err = nil
}
tmp := &monitor.RuleResultData{
Stats: stats,
User: mUser,
Rule: v,
}
res = append(res, tmp)
}
return
}
// MonitorStats 根据business和rule获取统计结果
func (s *Service) MonitorStats(c context.Context, rule *monitor.Rule) (stats *monitor.Stats, err error) {
var (
qualiKeys []string //符合条件的统计redis key
)
qualiKeys, err = s.RuleQualifiedKeys(c, rule)
//根据符合条件的redis key qualiKeys获取数据
stats = &monitor.Stats{}
for _, k := range qualiKeys {
var res *monitor.Stats
if res, err = s.monitor.StatsResult(c, k, rule.RuleConf); err != nil {
return
}
stats.TotalCount += res.TotalCount
stats.MoniCount += res.MoniCount
if res.MaxTime > stats.MaxTime {
stats.MaxTime = res.MaxTime
}
}
return
}
// MonitorRuleUpdate 更新监控规则
func (s *Service) MonitorRuleUpdate(c context.Context, rule *monitor.Rule) (err error) {
rule.CTime = time.Now().Format("2006-01-02 15:04:05")
err = s.monitor.SetRule(c, rule)
return
}
// RuleQualifiedKeys 获取监控业务中符合监控条件的Redis key
func (s *Service) RuleQualifiedKeys(c context.Context, rule *monitor.Rule) (qualiKeys []string, err error) {
var (
allKeys []string //当前业务的所有统计redis key
//qualiKeys []string //符合条件的统计redis key
prefix string //当前业务redis 可以前缀
keyConf *monitor.KeyConf //当前业务redis key 的字段配置信息
moniCdt = rule.RuleConf.MoniCdt //当前业务中,需要统计的条件
ok bool
)
qualiKeys = []string{}
if keyConf, ok = monitor.RedisKeyConf[rule.Business]; !ok {
err = errors.New("Business Not Exists")
return
}
prefix, allKeys, err = s.monitor.BusStatsKeys(c, rule.Business)
kFields := keyConf.KFields //Redis key中的字段
for _, fullK := range allKeys {
k := strings.Replace(fullK, prefix, "", 1) //去掉redis key 中的前缀monitor_stats_{business}_
ks := strings.Split(k, "_") //redis key 的切割,格式:%d_%d
if len(ks) != len(kFields) { //KFields中的字段数必须与redis key中数量一致
err = errors.New("KeyConf 中 KFields 的字段配置错误")
return
}
//把满足条件的Redis key找出来
qualified := true //当前key是否满足条件
i := -1
for kf := range kFields {
i++
var (
fv int64
)
fv, err = strconv.ParseInt(ks[i], 10, 64) //Redis key 中第i位的值
if err != nil {
return
}
if _, ok = moniCdt[kf]; !ok {
err = errors.New("配置的 moniCdt 中不存在: " + kf)
return
}
switch moniCdt[kf].Comp {
case monitor.CompE:
if fv != moniCdt[kf].Value {
qualified = false
}
case monitor.CompNE:
if fv == moniCdt[kf].Value {
qualified = false
}
case monitor.CompGET:
if fv < moniCdt[kf].Value {
qualified = false
}
case monitor.CompLET:
if fv > moniCdt[kf].Value {
qualified = false
}
case monitor.CompGT:
if fv <= moniCdt[kf].Value {
qualified = false
}
case monitor.CompLT:
if fv >= moniCdt[kf].Value {
qualified = false
}
default:
err = errors.New("配置的 MoniCdt 中 comparison 不合法: " + moniCdt[kf].Comp)
return
}
}
if qualified {
qualiKeys = append(qualiKeys, fullK)
}
}
return
}
// MoniStayOids 获取监控范围内滞留的oids
func (s *Service) MoniStayOids(c context.Context, tp, bid int8, id int64) (total int, oidMap map[int64]int, qualiKeys []string, err error) {
var (
rule *monitor.Rule
)
if rule, err = s.monitor.GetRule(c, tp, bid, id); err != nil {
return
}
//查找符合条件的统计redis key
if qualiKeys, err = s.RuleQualifiedKeys(c, rule); err != nil {
return
}
oidMap, total, err = s.monitor.StayOids(c, rule, qualiKeys)
log.Info("MoniStayOids(%d,%d,%d) oidMap(%v)", tp, bid, id, oidMap)
return
}
// MonitorStayOids 获取监控范围内滞留的oids
func (s *Service) MonitorStayOids(c context.Context, id int64) (oidMap map[int64]int, err error) {
return s.data.MonitorOids(c, id)
}
// MonitorNotifyResult 获取达到了报警阀值的数据
func (s *Service) MonitorNotifyResult(c context.Context) (res []*monitor.RuleResultData, err error) {
var (
rules []*monitor.Rule
stats *monitor.Stats
)
res = []*monitor.RuleResultData{}
if rules, err = s.monitor.GetAllRules(c, false); err != nil {
log.Error("MonitorNotifyCheck() error(%v)", err)
return
}
for _, v := range rules {
if v.Business == monitor.BusVideo {
s.MonitorCheckVideoStatus(c, v.Type, v.ID)
}
if stats, err = s.MonitorStats(c, v); err != nil {
log.Error("MonitorNotifyCheck() error(%v)", err)
err = nil
continue
}
notify := true
//暂时只有time、count这两个报警条件
if _, ok := v.RuleConf.NotifyCdt["time"]; ok {
threshold := v.RuleConf.NotifyCdt["time"].Value
comp := v.RuleConf.NotifyCdt["time"].Comp
switch comp {
case monitor.CompGT:
if int64(stats.MaxTime) < threshold {
notify = false
}
case monitor.CompLT:
if int64(stats.MaxTime) > threshold {
notify = false
}
}
}
if _, ok := v.RuleConf.NotifyCdt["count"]; ok {
threshold := v.RuleConf.NotifyCdt["count"].Value
comp := v.RuleConf.NotifyCdt["count"].Comp
switch comp {
case monitor.CompGT:
if int64(stats.MoniCount) < threshold {
notify = false
}
case monitor.CompLT:
if int64(stats.MoniCount) > threshold {
notify = false
}
}
}
if notify {
tmp := &monitor.RuleResultData{
Stats: stats,
Rule: v,
}
res = append(res, tmp)
}
}
return
}
// MonitorCheckVideoStatus 检查视频的稿件状态,如果是-100则剔除SortedSet的数据
func (s *Service) MonitorCheckVideoStatus(c context.Context, tp int8, id int64) (err error) {
var (
vidMap map[int64]int
vidAidMap map[int64]int64
arcStates map[int64]int
vids, aids []int64
bid = monitor.BusVideo
keys []string
)
if _, vidMap, keys, err = s.MoniStayOids(c, tp, bid, id); err != nil {
log.Error("s.MoniStayOids(%d,%d,%d) error(%v)", tp, bid, id, err)
return
}
for vid := range vidMap {
vids = append(vids, vid)
}
if vidAidMap, err = s.arc.VideoAidMap(c, vids); err != nil {
log.Error("s.VideoAidMap(%d) error(%v)", vids, err)
return
}
for _, aid := range vidAidMap {
aids = append(aids, aid)
}
if arcStates, err = s.arc.ArcStateMap(c, aids); err != nil {
log.Error("s.ArcStateMap(%d) error(%v)", aids, err)
return
}
for vid, aid := range vidAidMap {
if _, ok := arcStates[aid]; !ok {
continue
}
if arcStates[aid] != int(archive.StateForbidUpDelete) && arcStates[aid] != int(archive.StateForbidLock) && arcStates[aid] != int(archive.StateForbidRecycle) {
continue
}
for _, k := range keys {
if err = s.monitor.RemMonitorStats(c, k, vid); err != nil {
log.Error("s.monitor.RemMonitorStats(%s,%d) error(%v)", k, vid, err)
}
}
}
return
}

View File

@@ -0,0 +1,33 @@
package service
import (
"context"
. "github.com/smartystreets/goconvey/convey"
"go-common/app/admin/main/videoup/model/monitor"
"testing"
)
func TestService_MonitorResult(t *testing.T) {
var (
c = context.TODO()
)
Convey("MonitorResult", t, WithService(func(s *Service) {
p := &monitor.RuleResultParams{
Type: 1,
Business: 1,
}
data, err := svr.MonitorResult(c, p)
So(err, ShouldBeNil)
So(data, ShouldNotBeNil)
}))
}
func TestService_MonitorCheckVideoStatus(t *testing.T) {
var (
c = context.TODO()
)
Convey("MonitorCheckVideoStatus", t, WithService(func(s *Service) {
err := svr.MonitorCheckVideoStatus(c, 1, 1)
So(err, ShouldBeNil)
}))
}

View File

@@ -0,0 +1,74 @@
package service
import (
"context"
"time"
"go-common/app/admin/main/videoup/model/archive"
"go-common/library/log"
)
func (s *Service) multSyncProc() {
defer s.wg.Done()
for {
if s.closed {
return
}
var (
c = context.TODO()
err error
sync *archive.MultSyncParam
)
if sync, err = s.busCache.PopMultSync(c); err != nil || sync == nil || sync.Action == "" {
time.Sleep(5 * time.Second)
continue
}
log.Info("sync_action %s %+v", sync.Action, sync)
switch sync.Action {
case archive.ActionVideoSubmit:
if err = s.dealVideo(c, sync.VideoParam); err != nil {
s.busCache.PushMultSync(c, sync)
log.Error("s.dealVideo() error(%v)", err)
continue
}
case archive.ActionArchiveSubmit:
if err = s.dealArchive(c, sync.ArcParam); err != nil {
s.busCache.PushMultSync(c, sync)
log.Error("s.dealArchive() error(%v)", err)
continue
}
case archive.ActionArchiveSecondRound:
if err = s.dealArchiveSecondRound(c, sync.ArcParam); err != nil {
s.busCache.PushMultSync(c, sync)
log.Error("s.dealArchive() error(%v)", err)
continue
}
case archive.ActionArchiveAttr:
if err = s.dealAttrs(c, sync.ArcParam); err != nil {
s.busCache.PushMultSync(c, sync)
log.Error("s.dealAttrs() error(%v)", err)
continue
}
case archive.ActionArchiveTypeID:
if err = s.dealTypeID(c, sync.ArcParam); err != nil {
s.busCache.PushMultSync(c, sync)
log.Error("s.dealTypeID() error(%v)", err)
continue
}
case archive.ActionArchiveTag:
if err = s.dealTag(c, false, sync.ArcParam); err != nil {
s.busCache.PushMultSync(c, sync)
log.Error("s.dealTag() error(%v)", err)
continue
}
case archive.ActionArchiveTagRecheck:
if err = s.dealTag(c, true, sync.ArcParam); err != nil {
s.busCache.PushMultSync(c, sync)
log.Error("s.dealTag() error(%v)", err)
continue
}
default:
log.Info("s.multSyncProc() default action(%s)", sync.Action)
}
}
}

View File

@@ -0,0 +1,190 @@
package service
import (
"context"
"fmt"
"strconv"
"time"
"go-common/app/admin/main/videoup/model/archive"
"strings"
)
func (s *Service) addVideoOper(c context.Context, oper *archive.VideoOper) (err error) {
if oldOper, _ := s.arc.VideoOper(c, oper.VID); oldOper != nil && oldOper.LastID == 1 {
oper.LastID = oldOper.ID
s.arc.AddVideoOper(c, oper.AID, oper.UID, oper.VID, oper.Attribute, oper.Status, oper.LastID, oper.Content, oper.Remark)
return
}
if lastID, _ := s.arc.AddVideoOper(c, oper.AID, oper.UID, oper.VID, oper.Attribute, oper.Status, oper.LastID, oper.Content, oper.Remark); lastID > 0 {
s.arc.UpVideoOper(c, lastID, lastID)
return
}
return
}
func (s *Service) addArchiveOper(c context.Context, oper *archive.ArcOper) (err error) {
if oldOper, _ := s.arc.ArchiveOper(c, oper.Aid); oldOper != nil && oldOper.LastID == 1 {
oper.LastID = oldOper.ID
}
s.arc.AddArcOper(c, oper.Aid, oper.UID, oper.Attribute, oper.TypeID, oper.State, oper.Round, oper.LastID, oper.Content, oper.Remark)
return
}
func (s *Service) diffVideoOper(vp *archive.VideoParam) (conts []string) {
if vp.TagID > 0 {
var operType int8
if vp.Status >= archive.VideoStatusOpen {
operType = archive.OperTypeOpenTag
} else {
operType = archive.OperTypeRecicleTag
}
conts = append(conts, archive.Operformat(operType, "tagid", vp.TagID, archive.OperStyleTwo))
}
if vp.Reason != "" {
conts = append(conts, archive.Operformat(archive.OperTypeAduitReason, "reason", vp.Reason, archive.OperStyleTwo))
}
if vp.TaskID > 0 {
conts = append(conts, archive.Operformat(archive.OperTypeTaskID, "task", vp.TaskID, archive.OperStyleTwo))
}
return
}
func (s *Service) diffArchiveOper(ap *archive.ArcParam, a *archive.Archive, addit *archive.Addit, forbid *archive.ForbidAttr) (conts []string, changeTypeID, changeCopyright, changeTitle, changeCover bool) {
if ap.CanCelMission {
conts = append(conts, archive.Operformat(archive.OperTypeMission, addit.MissionID, 0, archive.OperStyleOne))
}
if ap.Cover != a.Cover {
if strings.HasPrefix(a.Cover, "http://") && strings.Contains(a.Cover, ap.Cover) {
changeCover = false
} else {
changeCover = true
}
}
if ap.Title != a.Title {
changeTitle = true
}
if ap.Copyright != a.Copyright {
changeCopyright = true
conts = append(conts, archive.Operformat(archive.OperTypeCopyright, archive.CopyrightsDesc(a.Copyright), archive.CopyrightsDesc(ap.Copyright), archive.OperStyleOne))
}
if cont, _ := s.diffTypeID(ap.TypeID, a.TypeID, ap.State); cont != "" {
changeTypeID = true
conts = append(conts, cont)
}
if ap.RejectReason != "" && ap.RejectReason != a.RejectReason {
if a.RejectReason == "" {
a.RejectReason = "无"
}
var operType int8
if a.Round > 20 {
operType = archive.OperTypeRejectReason
} else {
operType = archive.OperTypeAduitReason
}
conts = append(conts, archive.Operformat(operType, a.RejectReason, ap.RejectReason, archive.OperStyleOne))
}
if ap.Forward != a.Forward {
conts = append(conts, archive.Operformat(archive.OperTypeForwardID, a.Forward, ap.Forward, archive.OperStyleOne))
}
if ap.Notify {
conts = append(conts, archive.Operformat(archive.OperNotify, "无", "发送通知", archive.OperStyleOne))
}
if forbid == nil || (forbid.OnFlowID != ap.OnFlowID) {
if forbid != nil {
conts = append(conts, archive.Operformat(archive.OperTypeFlowID, s.flowsCache[forbid.OnFlowID], s.flowsCache[ap.OnFlowID], archive.OperStyleOne))
} else {
conts = append(conts, archive.Operformat(archive.OperTypeFlowID, "无", s.flowsCache[ap.OnFlowID], archive.OperStyleOne))
}
}
if ap.PTime != a.PTime {
conts = append(conts, archive.Operformat(archive.OperTypePtime, time.Unix(int64(a.PTime), 0).Format("2006-01-02 15:04:05"), time.Unix(int64(ap.PTime), 0).Format("2006-01-02 15:04:05"), archive.OperStyleOne))
}
if ap.Access != a.Access {
conts = append(conts, archive.Operformat(archive.OperTypeAccess, archive.AccessDesc(a.Access), archive.AccessDesc(ap.Access), archive.OperStyleOne))
}
if ap.Dynamic != addit.Dynamic {
conts = append(conts, archive.Operformat(archive.OperTypeDynamic, addit.Dynamic, ap.Dynamic, archive.OperStyleOne))
}
return
}
func (s *Service) diffBatchArchiveOper(ap *archive.ArcParam, a *archive.Archive) (conts []string) {
if ap.Access != a.Access {
conts = append(conts, archive.Operformat(archive.OperTypeAccess, archive.AccessDesc(a.Access), archive.AccessDesc(ap.Access), archive.OperStyleOne))
}
if ap.PTime != a.PTime {
conts = append(conts, archive.Operformat(archive.OperTypePtime, time.Unix(int64(a.PTime), 0).Format("2006-01-02 15:04:05"), time.Unix(int64(ap.PTime), 0).Format("2006-01-02 15:04:05"), archive.OperStyleOne))
}
if ap.FlagCopyright && ap.Copyright != a.Copyright {
conts = append(conts, archive.Operformat(archive.OperTypeCopyright, archive.CopyrightsDesc(a.Copyright), archive.CopyrightsDesc(ap.Copyright), archive.OperStyleOne))
}
if ap.RejectReason != "" && ap.RejectReason != a.RejectReason {
if a.RejectReason == "" {
a.RejectReason = "无"
}
var operType int8
if a.Round > 20 {
operType = archive.OperTypeRejectReason
} else {
operType = archive.OperTypeAduitReason
}
conts = append(conts, archive.Operformat(operType, a.RejectReason, ap.RejectReason, archive.OperStyleOne))
}
return
}
func (s *Service) diffTypeID(newTypeID, oldTypeID int16, state int8) (cont string, changeTypeID bool) {
if newTypeID != oldTypeID {
changeTypeID = true
var oldCont, newCont string
if ok := s.isTypeID(oldTypeID); ok {
oldCont = s.typeCache[oldTypeID].Name
} else {
oldCont = strconv.Itoa(int(oldTypeID))
}
if ok := s.isTypeID(newTypeID); ok {
newCont = s.typeCache[newTypeID].Name
} else {
newCont = strconv.Itoa(int(newTypeID))
}
cont = archive.Operformat(archive.OperTypeTypeID, oldCont, newCont, archive.OperStyleOne)
if state < 0 {
cont = fmt.Sprintf("%s,过审后生效", cont)
}
}
return
}
//私单修改日志
func (s *Service) diffPorder(c context.Context, aid int64, ap *archive.ArcParam) (conts []string, porder *archive.Porder) {
porder, _ = s.arc.Porder(c, aid)
if porder.IndustryID > 0 {
var yesOrNo = map[int8]string{int8(1): "是", int8(0): "否"}
if porder.IndustryID != ap.IndustryID {
conts = append(conts, archive.Operformat(archive.OperPorderIndustryID, s.porderConfigCache[porder.IndustryID].Name, s.porderConfigCache[ap.IndustryID].Name, archive.OperStyleOne))
}
if porder.Official != ap.Official {
conts = append(conts, archive.Operformat(archive.OperPorderOfficial, yesOrNo[porder.Official], yesOrNo[ap.Official], archive.OperStyleOne))
}
//game ID
if porder.BrandID != ap.BrandID {
conts = append(conts, archive.Operformat(archive.OperPorderBrandID, porder.BrandID, ap.BrandID, archive.OperStyleOne))
}
//custom brandName
if porder.BrandName != ap.BrandName {
conts = append(conts, archive.Operformat(archive.OperPorderBrandName, porder.BrandName, ap.BrandName, archive.OperStyleOne))
}
//porderConfigCache
if porder.ShowType != ap.ShowType {
conts = append(conts, archive.Operformat(archive.OperPorderShowType, porder.ShowType, ap.ShowType, archive.OperStyleOne))
}
if porder.Advertiser != ap.Advertiser {
conts = append(conts, archive.Operformat(archive.OperPorderAdvertiser, porder.Advertiser, ap.Advertiser, archive.OperStyleOne))
}
if porder.Agent != ap.Agent {
conts = append(conts, archive.Operformat(archive.OperPorderAgent, porder.Agent, ap.Agent, archive.OperStyleOne))
}
}
return
}

View File

@@ -0,0 +1,159 @@
package service
import (
"go-common/app/admin/main/videoup/model/oversea"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/xstr"
)
// PolicyGroups get policy group
func (s *Service) PolicyGroups(c *bm.Context, uid, groupID int64, gType, state int8, count, page int64, order, sort string) (data *oversea.PolicyGroupData, err error) {
groups, total, err := s.oversea.PolicyGroups(c, uid, groupID, gType, state, count, page, order, sort)
if len(groups) != 0 {
s.mulIDtoName(c, groups, s.mng.GetNameByUID, "UID", "UserName")
}
data = &oversea.PolicyGroupData{
Items: groups,
Pager: &oversea.Pager{
Num: page,
Size: count,
Total: total,
},
}
return
}
// ArchiveGroups get policy group by archive id
func (s *Service) ArchiveGroups(c *bm.Context, aid int64) (groups []*oversea.PolicyGroup, err error) {
groups, err = s.oversea.ArchiveGroups(c, aid)
return
}
// AddPolicyGroup add policy group
func (s *Service) AddPolicyGroup(c *bm.Context, group *oversea.PolicyGroup) (err error) {
if err = s.oversea.AddPolicyGroup(c, group); err != nil {
return
}
s.sendPolicyLog(c, &oversea.PolicyGroup{}, group)
return
}
// UpdatePolicyGroup update policy group
func (s *Service) UpdatePolicyGroup(c *bm.Context, id int64, attrs map[string]interface{}) (err error) {
var (
oldG = &oversea.PolicyGroup{}
newG = &oversea.PolicyGroup{}
)
if oldG, err = s.oversea.PolicyGroup(c, id); err != nil {
return
}
if err = s.oversea.UpdatePolicyGroup(c, id, attrs); err != nil {
return
}
if newG, err = s.oversea.PolicyGroup(c, id); err != nil {
log.Error("s.oversea.PolicyGroup(%d) err(%v)", id, err)
err = nil
} else {
s.sendPolicyLog(c, oldG, newG)
}
return
}
// UpdatePolicyGroups multi update policy group
func (s *Service) UpdatePolicyGroups(c *bm.Context, ids []int64, attrs map[string]interface{}) (err error) {
var (
oldGs []*oversea.PolicyGroup
newGs []*oversea.PolicyGroup
newMap = make(map[int64]*oversea.PolicyGroup)
)
if oldGs, err = s.oversea.PolicyGroupsByIds(c, ids); err != nil {
return
}
if err = s.oversea.UpdatePolicyGroups(c, ids, attrs); err != nil {
return
}
if newGs, err = s.oversea.PolicyGroupsByIds(c, ids); err != nil {
log.Error("s.oversea.PolicyGroupsByIds(%d) err(%v)", ids, err)
err = nil
} else {
for _, v := range newGs {
newMap[v.ID] = v
}
for _, oldG := range oldGs {
newG := &oversea.PolicyGroup{}
if _, ok := newMap[oldG.ID]; ok {
newG = newMap[oldG.ID]
}
s.sendPolicyLog(c, oldG, newG)
}
}
return
}
// PolicyItems get polices by group id
func (s *Service) PolicyItems(c *bm.Context, gid int64) (items []*oversea.PolicyItem, err error) {
return s.oversea.PolicyItems(c, gid)
}
// AddPolicies add policies
func (s *Service) AddPolicies(c *bm.Context, uid, gid int64, items []*oversea.PolicyParams) (err error) {
var (
zids []int64
oldG = &oversea.PolicyGroup{}
newG = &oversea.PolicyGroup{}
)
if oldG, err = s.oversea.PolicyGroup(c, gid); err != nil {
return
}
policies := make([]oversea.PolicyItem, len(items))
for i, v := range items {
policies[i].ID = v.ID
policies[i].GroupID = gid
policies[i].PlayAuth = v.PlayAuth
policies[i].DownAuth = v.DownAuth
policies[i].AreaID = xstr.JoinInts(v.AreaIds)
policies[i].State = oversea.StateOK
zids, _ = s.oversea.ZoneIDs(c, v.AreaIds)
policies[i].ZoneID = xstr.JoinInts(zids)
}
if err = s.oversea.AddPolicies(c, policies); err != nil {
return
}
if err = s.oversea.UpdatePolicyGroup(c, gid, map[string]interface{}{"uid": uid}); err != nil {
log.Error("s.oversea.UpdatePolicyGroup(%d) err(%v)", gid, err)
err = nil
}
if newG, err = s.oversea.PolicyGroup(c, gid); err != nil {
log.Error("s.oversea.PolicyGroup(%d) err(%v)", gid, err)
err = nil
} else {
s.sendPolicyLog(c, oldG, newG)
}
return
}
// DelPolices soft delete policies
func (s *Service) DelPolices(c *bm.Context, uid, gid int64, ids []int64) (err error) {
var (
oldG = &oversea.PolicyGroup{}
newG = &oversea.PolicyGroup{}
)
if oldG, err = s.oversea.PolicyGroup(c, gid); err != nil {
return
}
if err = s.oversea.DelPolices(c, gid, ids); err != nil {
return
}
if err = s.oversea.UpdatePolicyGroup(c, gid, map[string]interface{}{"uid": uid}); err != nil {
log.Error("s.oversea.UpdatePolicyGroup(%d) err(%v)", gid, err)
err = nil
}
if newG, err = s.oversea.PolicyGroup(c, gid); err != nil {
log.Error("s.oversea.PolicyGroup(%d) err(%v)", gid, err)
err = nil
} else {
s.sendPolicyLog(c, oldG, newG)
}
return
}

View File

@@ -0,0 +1,169 @@
package service
import (
"context"
"fmt"
"strings"
"time"
"go-common/app/admin/main/videoup/model/archive"
"go-common/library/database/sql"
"go-common/library/log"
xtime "go-common/library/time"
)
// PassByPGC update pgc archive state to StateOpen.
func (s *Service) PassByPGC(c context.Context, aid int64, gid int64, attrs map[uint]int32, redirectURL string, now time.Time) (err error) {
// archive
var a *archive.Archive
if a, err = s.arc.Archive(c, aid); err != nil || a == nil {
log.Error("s.arc.Archive(%d) error(%v) or a==nil", aid, err)
return
}
log.Info("aid(%d) begin tran pass pgc", aid)
// begin tran
var tx *sql.Tx
if tx, err = s.arc.BeginTran(c); err != nil {
log.Error("s.arc.BeginTran() error(%v)", err)
return
}
defer func() {
if r := recover(); r != nil {
tx.Rollback()
log.Error("wocao jingran recover le error(%v)", r)
}
}()
if a.State != archive.StateOpen {
var firstPass bool
if firstPass, err = s.txUpArcState(c, tx, a.Aid, archive.StateOpen); err != nil {
tx.Rollback()
log.Error("PassByPGC s.txUpArcState(aid(%d),state(%d)) error(%v)", aid, archive.StateOpen, err)
return
}
a.State = archive.StateOpen
log.Info("archive(%d) update archive state(%d)", a.Aid, a.State)
// archive ptime
if firstPass {
pTime := xtime.Time(now.Unix())
if _, err = s.arc.TxUpArcPTime(tx, a.Aid, pTime); err != nil {
tx.Rollback()
log.Error("s.arc.TxUpArcPTime(%d, %d) error(%v)", a.Aid, pTime, err)
return
}
a.PTime = pTime
log.Info("archive(%d) second_round upPTime(%d)", a.Aid, a.PTime)
}
var round = s.archiveRound(c, a, a.Aid, a.Mid, a.TypeID, a.Round, a.State, false)
if _, err = s.arc.TxUpArcRound(tx, a.Aid, round); err != nil {
tx.Rollback()
log.Error("s.arc.TxUpArcRound(%d, %d) error(%v)", a.Aid, round, err)
return
}
a.Round = round
log.Info("archive(%d) second_round upRound(%d)", a.Aid, a.Round)
}
var conts []string
if conts, err = s.txUpArcAttrs(tx, a, attrs, redirectURL); err != nil {
tx.Rollback()
return
}
if err = tx.Commit(); err != nil {
log.Error("tx.Commit() error(%v)", err)
return
}
log.Info("aid(%d) end tran pass pgc", aid)
if _, err := s.oversea.UpPolicyRelation(c, aid, gid); err != nil {
conts = append(conts, fmt.Sprintf("[地区展示]应用策略组ID[%d]", gid))
}
if len(conts) > 0 {
s.arc.AddArcOper(c, a.Aid, 221, a.Attribute, a.TypeID, int16(a.State), a.Round, 1, strings.Join(conts, ""), "")
}
// NOTE: send second_round for sync dede.
s.busSecondRound(aid, 0, false, false, false, false, false, false, "", nil)
return
}
// ModifyByPGC update pgc archive attributes.
func (s *Service) ModifyByPGC(c context.Context, aid int64, gid int64, attrs map[uint]int32, redirectURL string) (err error) {
// archive
var a *archive.Archive
if a, err = s.arc.Archive(c, aid); err != nil || a == nil {
log.Error("s.arc.Archive(%d) error(%v) or a==nil", aid, err)
return
}
log.Info("aid(%d) begin tran modify pgc", aid)
// begin tran
var tx *sql.Tx
if tx, err = s.arc.BeginTran(c); err != nil {
log.Error("s.arc.BeginTran() error(%v)", err)
return
}
defer func() {
if r := recover(); r != nil {
tx.Rollback()
log.Error("wocao jingran recover le error(%v)", r)
}
}()
var conts []string
if conts, err = s.txUpArcAttrs(tx, a, attrs, redirectURL); err != nil {
tx.Rollback()
return
}
if err = tx.Commit(); err != nil {
log.Error("tx.Commit() error(%v)", err)
return
}
log.Info("aid(%d) end tran modify pgc", aid)
if _, err := s.oversea.UpPolicyRelation(c, aid, gid); err != nil {
conts = append(conts, fmt.Sprintf("[地区展示]应用策略组ID[%d]", gid))
}
if len(conts) > 0 {
s.arc.AddArcOper(c, a.Aid, 221, a.Attribute, a.TypeID, int16(a.State), a.Round, 1, strings.Join(conts, ""), "")
}
// NOTE: send second_round for sync dede.
s.busSecondRound(aid, 0, false, false, false, false, false, false, "", nil)
return
}
// LockByPGC update pgc archive state to StateForbidLock.
func (s *Service) LockByPGC(c context.Context, aid int64) (err error) {
// archive
var a *archive.Archive
if a, err = s.arc.Archive(c, aid); err != nil || a == nil {
log.Error("s.arc.Archive(%d) error(%v) or a==nil", aid, err)
return
}
if a.State == archive.StateForbidLock {
return
}
log.Info("aid(%d) begin tran lock pgc", aid)
// begin tran
var tx *sql.Tx
if tx, err = s.arc.BeginTran(c); err != nil {
log.Error("s.arc.BeginTran() error(%v)", err)
return
}
defer func() {
if r := recover(); r != nil {
tx.Rollback()
log.Error("wocao jingran recover le error(%v)", r)
}
}()
if _, err = s.txUpArcState(c, tx, a.Aid, archive.StateForbidLock); err != nil {
tx.Rollback()
log.Error("s.txUpArcState(aid(%d),state(%d)) error(%v)", aid, archive.StateForbidLock, err)
return
}
a.State = archive.StateForbidLock
log.Info("archive(%d) update archive state(%d)", a.Aid, a.State)
if err = tx.Commit(); err != nil {
log.Error("tx.Commit() error(%v)", err)
return
}
log.Info("aid(%d) end tran lock pgc", aid)
s.arc.AddArcOper(c, a.Aid, 221, a.Attribute, a.TypeID, int16(a.State), a.Round, 1, "", "")
// NOTE: send second_round for sync dede.
s.busSecondRound(aid, 0, false, false, false, false, false, false, "", nil)
return
}

View File

@@ -0,0 +1,38 @@
package service
import (
"context"
"testing"
"go-common/app/admin/main/videoup/model/archive"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_ModifyByPGC(t *testing.T) {
var (
c = context.TODO()
)
attrs := make(map[uint]int32, 7)
attrs[archive.AttrBitJumpURL] = 1
attrs[archive.AttrBitAllowBp] = 1
attrs[archive.AttrBitIsBangumi] = 1
attrs[archive.AttrBitIsMovie] = 1
attrs[archive.AttrBitBadgepay] = 1
attrs[archive.AttrBitIsPGC] = 1
attrs[archive.AttrBitLimitArea] = 0
Convey("ModifyByPGC", t, WithService(func(s *Service) {
err := svr.ModifyByPGC(c, 1, 1, attrs, "")
So(err, ShouldBeNil)
}))
}
func TestService_LockByPGC(t *testing.T) {
var (
c = context.TODO()
)
Convey("LockByPGC", t, WithService(func(s *Service) {
err := svr.LockByPGC(c, 12345)
So(err, ShouldBeNil)
}))
}

View File

@@ -0,0 +1,18 @@
package service
import (
"go-common/app/admin/main/videoup/model/archive"
"go-common/library/database/sql"
"go-common/library/log"
)
// TxUpPorder .
func (s *Service) TxUpPorder(tx *sql.Tx, ap *archive.ArcParam) (err error) {
//区分自首还是审核回查添加
if _, err = s.arc.TxUpPorder(tx, ap.Aid, ap); err != nil {
log.Error("s.arc.TxUpPorder(%d,%+v) error(%v)", ap.Aid, ap, err)
return
}
log.Info("TxUpPorder aid(%d) update archive_porder", ap.Aid)
return
}

View File

@@ -0,0 +1,925 @@
package service
import (
"context"
"github.com/pkg/errors"
"go-common/app/admin/main/videoup/model/archive"
"go-common/app/admin/main/videoup/model/manager"
"go-common/app/admin/main/videoup/model/search"
accApi "go-common/app/service/main/account/api"
"go-common/library/database/elastic"
"go-common/library/ecode"
"go-common/library/log"
bm "go-common/library/net/http/blademaster"
"go-common/library/xstr"
"strconv"
"strings"
"sync"
)
// SearchVideo search video
func (s *Service) SearchVideo(c context.Context, p *search.VideoParams) (result *search.VideoResultData, err error) {
var (
aids, cids,
vids, mids,
tids, tagIds,
xcodes []int64
fNames []string
ps = 30
sort string
order string
isMonitor bool //是否查看监控列表
moniTotal int //监控列表的总数量
moniMap map[int64]int //监控列表的视频id map。键vidtime进入监控的时间
tags map[int64]string
aStates, vStates map[int64]int
members map[int64]*accApi.Info
eReq *elastic.Request
wg sync.WaitGroup
)
es := elastic.NewElastic(nil)
//Page
if p.Ps != 0 {
ps = p.Ps
}
if p.Pn == 0 {
p.Pn = 1
}
if p.OrderType == "1" {
eReq = es.NewRequest("archive_video_score")
} else {
eReq = es.NewRequest("archive_video")
}
eReq.Index("archive_video")
if p.Keywords != "" {
eReq.WhereLike([]string{"arc_title", "arc_author"}, []string{p.Keywords}, true, elastic.LikeLevelLow)
}
if p.ArcTitle != "" {
eReq.WhereLike([]string{"arc_title"}, []string{p.ArcTitle}, false, elastic.LikeLevelLow)
}
if p.Aids != "" {
p.Aids = strings.Join(Slice2String(SliceUnique(Slice2Interface(strings.Split(p.Aids, ",")))), ",")
if aids, err = s.SplitInts(p.Aids); err != nil {
err = ecode.RequestErr
return
}
if len(aids) > ps {
ps = len(aids)
}
eReq.WhereIn("aid", aids)
}
//监控结果列表逻辑
if p.MonitorList != "" {
isMonitor = true
var (
rid int
)
moniP := strings.Split(p.MonitorList, "_")
if len(moniP) != 3 {
err = errors.New("监控列表标识字段格式错误")
return
}
if rid, err = strconv.Atoi(moniP[2]); err != nil {
return
}
if moniMap, err = s.MonitorStayOids(c, int64(rid)); err != nil {
return
}
moniTotal = len(moniMap)
for vid := range moniMap {
vids = append(vids, vid)
}
if len(vids) == 0 {
result = &search.VideoResultData{
Result: []*search.Video{},
}
return
}
if len(vids) > ps {
ps = len(vids)
}
eReq.WhereIn("vid", vids)
}
if p.Cids != "" {
p.Cids = strings.Join(Slice2String(SliceUnique(Slice2Interface(strings.Split(p.Cids, ",")))), ",")
if cids, err = s.SplitInts(p.Cids); err != nil {
err = ecode.RequestErr
return
}
if len(cids) > ps {
ps = len(cids)
}
eReq.WhereIn("cid", cids)
}
if p.Vids != "" {
if vids, err = s.SplitInts(p.Vids); err != nil {
err = ecode.RequestErr
return
}
if len(vids) > ps {
ps = len(vids)
}
eReq.WhereIn("vid", vids)
}
if p.ArcMids != "" {
if mids, err = s.SplitInts(p.ArcMids); err != nil {
err = ecode.RequestErr
return
}
if len(mids) > ps {
ps = len(mids)
}
eReq.WhereIn("arc_mid", mids)
}
if p.Xcode != "" {
if xcodes, err = s.SplitInts(p.Xcode); err != nil {
err = ecode.RequestErr
return
}
eReq.WhereIn("xcode_state", xcodes)
}
if p.TypeID != "" {
if tids, err = s.SplitInts(p.TypeID); err != nil {
err = ecode.RequestErr
return
}
for _, tid := range tids {
if ids, ok := s.typeCache2[int16(tid)]; ok {
tids = append(tids, ids...)
}
}
eReq.WhereIn("arc_typeid", tids)
}
if p.Filename != "" {
if fNames = strings.Split(p.Filename, ","); err != nil {
err = ecode.RequestErr
return
}
eReq.WhereIn("filename", fNames)
}
if p.TagID != "" {
eReq.WhereEq("tag_id", p.TagID)
}
if p.Status != "" {
if p.Status == "-100" {
eReq.WhereEq("relation_state", "-100")
p.Status = ""
} else {
eReq.WhereEq("relation_state", "0")
eReq.WhereEq("status", p.Status)
}
}
if p.UserType != "" {
eReq.WhereEq("user_type", p.UserType)
}
if p.DurationFrom != "" && p.DurationTo != "" {
eReq.WhereRange("duration", p.DurationFrom, p.DurationTo, elastic.RangeScopeLcRc)
} else if p.DurationFrom != "" && p.DurationTo == "" {
eReq.WhereRange("duration", p.DurationFrom, "", elastic.RangeScopeLcRc)
} else if p.DurationFrom == "" && p.DurationTo != "" {
eReq.WhereRange("duration", "", p.DurationTo, elastic.RangeScopeLcRc)
}
//Order by
if p.Order != "" {
order = p.Order
} else if p.Action == "trash" {
order = "v_mtime"
} else {
order = "arc_senddate"
}
if p.Sort == 1 {
sort = "asc"
} else {
sort = "desc"
}
eReq.Order(order, sort)
//Page
eReq.Ps(ps)
eReq.Pn(p.Pn)
//Execute
log.Info("s.SearchVideo(%+v) SearchVideoQuery(%s)", p, eReq.Params())
if err = eReq.Scan(c, &result); err != nil {
log.Error("SearchVideoScan() error(%v)", err)
return
}
if result == nil {
log.Error("s.SearchVideo(%+v) search return nil result", p)
result = &search.VideoResultData{
Result: []*search.Video{},
}
return
}
if result.Result == nil {
log.Error("s.SearchVideo(%+v) search return nil video", p)
result.Result = []*search.Video{}
return
}
if len(result.Result) == 0 {
return
}
if isMonitor {
result.Page.Total = moniTotal
}
aids = []int64{}
vids = []int64{}
mids = []int64{}
for _, v := range result.Result {
if v.TagID != 0 {
tagIds = append(tagIds, v.TagID)
}
aids = append(aids, v.Aid)
vids = append(vids, v.Vid)
if v.ArcMid != 0 {
mids = append(mids, v.ArcMid)
}
}
//获取Tag名称
wg.Add(1)
go func(tags *map[int64]string) {
defer wg.Done()
if *tags, err = s.arc.TagNameMap(c, tagIds); err != nil {
log.Error("s.arc.TagNameMap(%v) error(%v)", tagIds, err)
err = nil
}
log.Info("s.arc.TagNameMap(%v) result(%v)", tagIds, tags)
}(&tags)
//获取数据库中的稿件状态
wg.Add(1)
go func(aStates *map[int64]int) {
defer wg.Done()
if *aStates, err = s.arc.ArcStateMap(c, aids); err != nil {
log.Error("s.arc.ArcStateMap(%v) error(%v)", aids, err)
err = nil
}
}(&aStates)
//获取数据库中视频的状态
wg.Add(1)
go func(vStates *map[int64]int) {
defer wg.Done()
if *vStates, err = s.arc.VideoStateMap(c, vids); err != nil {
log.Error("s.arc.VideoStateMap(%v) error(%v)", vids, err)
err = nil
}
}(&vStates)
//获取UP主信息
wg.Add(1)
go func(members *map[int64]*accApi.Info) {
defer wg.Done()
var infosReply *accApi.InfosReply
if infosReply, err = s.accRPC.Infos3(c, &accApi.MidsReq{Mids: mids}); err != nil {
log.Error("s.accRPC.Infos3(%v) error(%v)", mids, err)
err = nil
return
}
*members = infosReply.Infos
}(&members)
wg.Wait()
sInt, _ := strconv.Atoi(p.Status)
for i := 0; i < len(result.Result); i++ {
v := result.Result[i]
result.Result[i].ID = v.Vid
if vs, ok := vStates[v.Vid]; ok {
result.Result[i].Status = vs
}
//需要将status与查询条件中status不一致的视频剔除
if p.Status != "" && v.Status != sInt {
result.Result = append(result.Result[:i], result.Result[i+1:]...)
i--
continue
}
if tn, ok := tags[v.TagID]; ok {
result.Result[i].TagName = tn
}
if as, ok := aStates[v.Aid]; ok {
result.Result[i].ArcState = as
}
if m, ok := members[v.ArcMid]; ok {
result.Result[i].ArcAuthor = m.Name
}
if v.UserType == nil {
v.UserType = []int64{}
}
if v.UserGroup == nil {
v.UserGroup = []*manager.UpGroup{}
}
for _, tp := range v.UserType {
if up, ok := s.allUpGroupCache[tp]; ok {
result.Result[i].UserGroup = append(result.Result[i].UserGroup, up)
}
}
}
return
}
// SearchCopyright search video copyright
func (s *Service) SearchCopyright(c context.Context, kw string) (result *search.CopyrightResultData, err error) {
return s.search.SearchCopyright(c, kw)
}
// SearchArchive 稿件搜索列表
func (s *Service) SearchArchive(c *bm.Context, p *search.ArchiveParams) (result *search.ArchiveResultData, err error) {
var (
round int
aids []int64
froms []int8
forbid string
tids []int64
pn = 1
ps = 30
isMonitor bool //是否查看监控列表
moniMap map[int64]int //监控列表的视频id map。键vidtime进入监控的时间
nPGCAids, sPGCAids, cPGCAids, misAids []int64
additMap map[int64]*archive.Addit
tips string
orders = map[string]string{
"mtime": "",
"pubtime": "",
"ctime": "",
"dm_count": "",
"fav_count": "",
}
eReq *elastic.Request
)
es := elastic.NewElastic(nil)
if p.OrderType != "" {
eReq = es.NewRequest("archive_score")
} else {
eReq = es.NewRequest("archive")
}
eReq.Index("archive")
if p.Ps != 0 {
ps = p.Ps
}
if ps > 1000 {
ps = 1000
}
//分区 逻辑
if p.TypeID != "" {
if tids, err = s.SplitInts(p.TypeID); err != nil {
return
}
for _, tid := range tids {
if ids, ok := s.typeCache2[int16(tid)]; ok {
tids = append(tids, ids...)
}
}
}
//特殊分区逻辑
if p.SpecialType != "" {
for i := 0; i < len(tids); i++ { //剔除特殊/普通分区id
_, ok := s.adtTpsCache[int16(tids[i])]
if (ok && p.SpecialType == "0") || (!ok && p.SpecialType == "1") {
tids = append(tids, tids...)
i--
continue
}
}
}
if len(tids) > 0 {
eReq.WhereIn("typeid", tids)
if len(tids) > ps {
ps = len(tids)
}
}
if p.UserType != "" && p.UserType != "0" {
eReq.WhereEq("user_type", p.UserType)
}
//up_from 逻辑
if p.UpFroms != "" {
var upFroms []int64
if upFroms, err = s.SplitInts(p.UpFroms); err != nil {
return
}
eReq.WhereIn("up_from", upFroms)
} else { //默认去除PGC稿件
eReq.WhereIn("up_from", []int8{archive.UpFromPGC, archive.UpFromSecretPGC, archive.UpFromCoopera})
eReq.WhereNot(elastic.NotTypeIn, "up_from")
}
//Round 逻辑
if p.Round != "" {
if round, err = strconv.Atoi(p.Round); err != nil {
log.Warn("http.searchArchive() http.PGCListLogic() err(%v)", err)
return
}
if round == 1 {
eReq.WhereIn("round", []int8{1, archive.RoundReviewSecond})
} else if round == 2 {
eReq.WhereIn("round", []int8{2, archive.RoundEnd})
} else {
eReq.WhereIn("round", []int{round})
}
}
//Aid 逻辑
if p.Aids != "" {
p.Aids = strings.Replace(p.Aids, "\n", ",", -1)
p.Aids = strings.Join(Slice2String(SliceUnique(Slice2Interface(strings.Split(p.Aids, ",")))), ",")
if aids, err = s.SplitInts(p.Aids); err != nil {
return
}
eReq.WhereIn("id", aids)
}
//Mid 逻辑
if p.Mids != "" {
var mids []int64
p.Mids = strings.Replace(p.Mids, "\n", ",", -1)
if mids, err = s.SplitInts(p.Mids); err != nil {
return
}
eReq.WhereIn("mid", mids)
if len(mids) > ps {
ps = len(mids)
}
}
if p.State != "" {
states := strings.Split(p.State, ",")
eReq.WhereIn("state", states)
}
if p.Access != "" {
eReq.WhereEq("access", p.Access)
}
if p.Copyright != "" {
eReq.WhereEq("copyright", p.Copyright)
}
if p.IsFirst != "" {
eReq.WhereEq("is_first", p.IsFirst)
}
//PGC 列表逻辑
if p.PGCList != "" {
if err = s.PGCListLogic(c, p.PGCList, p.State, froms, eReq); err != nil {
return
}
if c.IsAborted() { //检查鉴权
return
}
}
//搜索关键字逻辑
if p.Keywords != "" {
fields := []string{"title", "content", "tag"}
if p.KwFields != "" {
fields = strings.Split(p.KwFields, ",")
for i := 0; i < len(fields); i++ {
if fields[i] == "channel" {
fields[i] = "tid_names"
break
}
}
}
eReq.WhereLike(fields, []string{p.Keywords}, true, elastic.LikeLevelLow)
}
if p.NoMission == "" { //默认去掉活动稿件
p.NoMission = "1"
}
//禁止项逻辑
if p.Attr == strconv.Itoa(archive.ForbidAttrChannel) {
forbid = "channel"
eReq.WhereEq("channel_group_id", archive.FlowGroupNoChannel)
eReq.WhereEq("channel_pool", archive.PoolArcForbid)
eReq.WhereEq("channel_state", archive.FlowOpen)
} else if p.Attr == strconv.Itoa(archive.ForbidAttrHot) {
forbid = "hot"
eReq.WhereEq("hot_group_id", archive.FlowGroupNoHot)
eReq.WhereEq("hot_pool", archive.PoolArcForbid)
eReq.WhereEq("hot_state", archive.FlowOpen)
} else if p.Attr != "" {
attr := 0
attr, err = strconv.Atoi(p.Attr)
if err != nil {
return
}
if (uint(attr-1) == archive.AttrBitIsPorder) && int8(round) != archive.RoundReviewFlow {
s.auth.Permit("PRIVATE_ORDER_ALL")(c) //鉴权
if c.IsAborted() {
return
}
p.NoMission = "" //不做活动稿件剔除
}
eReq.WhereEq("attribute", attr)
}
//回查列表逻辑
if p.Review != "" {
if p.ReviewState == "" {
p.ReviewState = strconv.Itoa(archive.RecheckStateWait)
}
switch p.Review {
case strconv.Itoa(archive.TypeChannelRecheck):
s.auth.Permit("CHANNEL_REVIEW")(c)
eReq.WhereEq("recheck_ch_type", p.Review)
eReq.WhereEq("recheck_ch_staten", p.ReviewState)
case strconv.Itoa(archive.TypeHotRecheck):
p.NoMission = ""
s.auth.Permit("ARC_HOT_REVIEW")(c)
eReq.WhereEq("recheck_hot_type", p.Review)
eReq.WhereEq("recheck_hot_staten", p.ReviewState)
case strconv.Itoa(archive.TypeInspireRecheck):
p.NoMission = ""
s.auth.Permit("ARC_INSPIRE_REVIEW")(c)
eReq.WhereEq("recheck_inspire_type", p.Review)
eReq.WhereEq("recheck_inspire_staten", p.ReviewState)
}
if c.IsAborted() {
return
}
p.IsOrder = 0
} else if p.Round == strconv.Itoa(int(archive.RoundAuditUGCPayFlow)) { //付费列表需要展示活动稿件
p.NoMission = ""
}
//活动逻辑
if p.MissionID != "" {
eReq.WhereEq("mission_id", p.MissionID)
}
if p.MissionID != "" || p.NoMission == "0" { //需要活动稿件
eReq.WhereRange("mission_id", 1, nil, elastic.RangeScopeLcRo)
} else if p.NoMission == "1" { //不需要活动稿件
eReq.WhereRange("mission_id", 0, nil, elastic.RangeScopeLoRo)
eReq.WhereNot(elastic.NotTypeRange, "mission_id")
}
//商单逻辑
if p.IsOrder == 1 { //商单 order_id 大于0
eReq.WhereRange("order_id", 0, nil, elastic.RangeScopeLoRo)
if p.OrderId != "" {
eReq.WhereEq("order_id", p.OrderId)
}
} else if forbid == "" && p.Review == "" { //除了禁止列表和回查列表都要去除商单order_id <= 0
eReq.WhereRange("order_id", 0, nil, elastic.RangeScopeLoRo)
eReq.WhereNot(elastic.NotTypeRange, "order_id")
}
//监控结果列表逻辑
if p.MonitorList != "" {
eReq = es.NewRequest("archive_score") //去掉其它条件
eReq.Index("archive")
isMonitor = true
var (
rid int
)
moniP := strings.Split(p.MonitorList, "_")
if len(moniP) != 3 {
err = errors.New("监控列表标识字段格式错误")
return
}
if rid, err = strconv.Atoi(moniP[2]); err != nil {
return
}
if moniMap, err = s.MonitorStayOids(c, int64(rid)); err != nil {
return
}
for aid := range moniMap {
aids = append(aids, aid)
}
if len(aids) == 0 {
result = &search.ArchiveResultData{
Result: []*search.Archive{},
}
return
}
/*if len(aids) > ps {
ps = len(aids)
}*/
eReq.WhereIn("id", aids)
}
//分页、排序
if p.Pn > 0 {
pn = p.Pn
}
if _, ok := orders[p.Order]; !ok {
p.Order = "ctime"
}
if p.Order == "" {
p.Order = "ctime"
}
eReq.OrderScoreFirst(p.ScoreFirst != "0")
if p.Sort == "" {
p.Sort = "desc"
}
eReq.Order(p.Order, p.Sort)
eReq.Pn(pn)
eReq.Ps(ps)
log.Info("SearchArchiveQuery(%s)", eReq.Params())
if err = eReq.Scan(c, &result); err != nil {
log.Error("SearchArchiveQuery() error(%v)", err)
return
}
if isMonitor {
result.MoniAids = moniMap
}
if len(aids) > 0 && !isMonitor {
//获取稿件addit
if additMap, err = s.arc.AdditBatch(c, aids); err != nil {
log.Error("s.arc.AdditBatch(%v) error(%v) additMap(%v)", aids, err, additMap)
err = nil
}
for _, v := range aids {
if _, ok := additMap[v]; ok {
switch additMap[v].UpFrom {
case archive.UpFromPGC:
nPGCAids = append(nPGCAids, v)
case archive.UpFromSecretPGC:
sPGCAids = append(sPGCAids, v)
case archive.UpFromCoopera:
cPGCAids = append(cPGCAids, v)
}
if additMap[v].MissionID > 0 {
misAids = append(misAids, v)
}
}
}
if len(nPGCAids) > 0 {
tips += "PGC稿件" + xstr.JoinInts(nPGCAids)
}
if len(sPGCAids) > 0 {
tips += "PGC机密" + xstr.JoinInts(sPGCAids)
}
if len(cPGCAids) > 0 {
tips += "PGC嵌套" + xstr.JoinInts(cPGCAids)
}
if len(misAids) > 0 {
tips += "活动稿件:" + xstr.JoinInts(misAids)
}
result.Tips = tips
}
if err = s.KneadArchiveResult(c, result, p, additMap); err != nil {
return
}
return
}
// PGCListLogic PGC列表查询相关逻辑
func (s *Service) PGCListLogic(c *bm.Context, lnStr string, pState string, froms []int8, eReq *elastic.Request) (err error) {
var (
state int ////临时存储PGC列表中查询的state状态需要和pState字符串配合使用
lni int
ln int8
pgcConfig map[int8]*search.ArcPGCConfig
)
if lni, err = strconv.Atoi(lnStr); err != nil {
log.Warn("s.PGCListLogic() err(%v)", err)
return
}
ln = int8(lni)
if state, err = strconv.Atoi(pState); err != nil {
err = errors.New("PGC列表中的state参数错误")
return
}
if len(froms) != 0 {
for _, v := range froms {
if v != archive.UpFromPGC && v != archive.UpFromSecretPGC && v != archive.UpFromCoopera {
err = errors.New("PGC列表中的from参数错误")
break
}
}
}
pgcConfig = make(map[int8]*search.ArcPGCConfig)
//PGC常规二审列表 round=10 state=-1,-30,-40,-6 upfrom=1
pgcConfig[1] = &search.ArcPGCConfig{
UPFrom: []int8{archive.UpFromPGC},
Rounds: []int8{
archive.RoundBegin,
archive.RoundAuditSecond,
},
States: []int8{
archive.RecheckStateWait,
archive.StateForbidSubmit,
archive.StateForbidUserDelay,
archive.StateForbidFixed,
},
InState: pState != "" && state < 0,
Auth: "PGC_NORMAL_2",
}
//PGC常规三审列表 round=20 state=-1,-30,-40,-6 upfrom=1
pgcConfig[2] = &search.ArcPGCConfig{
UPFrom: []int8{archive.UpFromPGC},
Rounds: []int8{archive.RoundAuditThird},
States: []int8{
archive.RecheckStateWait,
archive.StateForbidSubmit,
archive.StateForbidUserDelay,
archive.StateForbidFixed,
},
InState: pState != "" && state < 0,
Auth: "PGC_NORMAL_3",
}
//PGC机密待审列表 state=-1,-30,-40,-6 upfrom=5
pgcConfig[3] = &search.ArcPGCConfig{
UPFrom: []int8{archive.UpFromSecretPGC},
Rounds: []int8{},
States: []int8{
archive.RecheckStateWait,
archive.StateForbidSubmit,
archive.StateForbidUserDelay,
archive.StateForbidFixed,
},
InState: pState != "" && state < 0,
Auth: "PGC_SECRET_WAIT",
}
//PGC机密回查列表 round=90 state≥0 upfrom=5
pgcConfig[4] = &search.ArcPGCConfig{
UPFrom: []int8{archive.UpFromSecretPGC},
Rounds: []int8{archive.RoundTriggerClick},
States: []int8{
archive.StateOpen,
archive.StateOrange,
},
InState: pState != "" && state >= 0,
Auth: "PGC_SECRET_RECHECK",
}
//PGC全部已过审 round=99 state≥0 upfrom=1,5,6
pgcConfig[5] = &search.ArcPGCConfig{
UPFrom: []int8{archive.UpFromPGC, archive.UpFromSecretPGC, archive.UpFromCoopera},
Rounds: []int8{archive.RoundEnd},
States: []int8{
archive.StateOpen,
archive.StateOrange,
},
InState: pState != "" && state >= 0,
Auth: "PGC_OPEN",
}
//全部打回列表 state=-2,-3,-4,-7,-11,-16,-100 up_from=1,5,6
pgcConfig[6] = &search.ArcPGCConfig{
UPFrom: []int8{archive.UpFromPGC, archive.UpFromSecretPGC, archive.UpFromCoopera},
Rounds: []int8{},
States: []int8{
archive.StateForbidRecycle,
archive.StateForbidPolice,
archive.StateForbidLock,
archive.StateForbidLater,
archive.StateForbidFixing,
archive.StateForbidXcodeFail,
archive.StateForbidUpDelete,
},
InState: pState != "" && state < 0,
Auth: "PGC_RECICLE",
}
//合作方嵌套列表 state=-1,-30,-6,-40 up_from=6
pgcConfig[7] = &search.ArcPGCConfig{
UPFrom: []int8{archive.UpFromCoopera},
Rounds: []int8{},
States: []int8{
archive.StateForbidWait,
archive.StateForbidSubmit,
archive.StateForbidFixed,
archive.StateForbidUserDelay,
},
InState: pState != "" && state < 0,
Auth: "PGC_PARTNER",
}
if _, ok := pgcConfig[ln]; !ok || pgcConfig[ln] == nil {
err = errors.New("PGC列表不存在")
return
}
if !pgcConfig[ln].InState { //如果前端传了合法的state则加上state条件
pgcConfig[ln].States = []int8{int8(state)}
}
if len(froms) != 0 { //如果前端传了up_from则加上up_from条件
pgcConfig[ln].UPFrom = froms
}
if len(pgcConfig[ln].UPFrom) == 0 {
err = errors.New("PGC列表中的UPFrom不能设置为空")
return
}
s.auth.Permit(pgcConfig[ln].Auth)(c) //鉴权
eReq.WhereIn("up_from", pgcConfig[ln].UPFrom)
eReq.WhereIn("state", pgcConfig[ln].States)
eReq.WhereIn("round", pgcConfig[ln].Rounds)
return
}
// KneadArchiveResult 拼接稿件数据
func (s *Service) KneadArchiveResult(c *bm.Context, result *search.ArchiveResultData, p *search.ArchiveParams, additMap map[int64]*archive.Addit) (err error) {
var (
mids, aids []int64
ups map[int64]*accApi.Card
rStates map[int64]int8
chNames map[int64][]string
archives = result.Result
dbArchives map[int64]*archive.Archive
wg sync.WaitGroup
)
for _, v := range archives {
if v.Mid != 0 {
mids = append(mids, v.Mid)
}
aids = append(aids, v.ID)
}
//获取频道信息
wg.Add(1)
go func(chNames *map[int64][]string) {
defer wg.Done()
*chNames = s.ChannelNamesByAids(c, aids)
}(&chNames)
wg.Add(1)
go func(dbArchives *map[int64]*archive.Archive) {
defer wg.Done()
if *dbArchives, err = s.arc.Archives(c, aids); err != nil || dbArchives == nil {
log.Error("s.arc.Archives(%v) error(%v) archives(%v)", mids, err, dbArchives)
err = nil
}
}(&dbArchives)
//获取UP主信息
wg.Add(1)
go func(ups *map[int64]*accApi.Card) {
defer wg.Done()
if *ups, err = s.upCards(c, mids); err != nil || ups == nil {
log.Error("s.upCards(%v) error(%v) ups(%v)", mids, err, ups)
err = nil
*ups = make(map[int64]*accApi.Card)
}
}(&ups)
//获取回查稿件实时状态
if p.Review != "" && p.ReviewState != "" {
wg.Add(1)
go func(rStates *map[int64]int8) {
defer wg.Done()
tp, _ := strconv.Atoi(p.Review)
if *rStates, err = s.arc.RecheckStateMap(c, tp, aids); err != nil || rStates == nil {
log.Error("s.arc.RecheckStateMap(%v,%v) error(%v) rStates(%v)", tp, aids, err, rStates)
err = nil
}
}(&rStates)
}
wg.Wait()
for i := 0; i < len(archives); i++ {
v := archives[i]
if a, ok := dbArchives[v.ID]; ok && a.Cover != "" {
archives[i].Cover = coverURL(a.Cover)
}
if m, ok := ups[v.Mid]; ok {
archives[i].Official = m.Official
archives[i].Author = m.Name
}
if p.Review != "" && p.ReviewState != "" {
if state, ok := rStates[v.ID]; ok { //将与查询条件中回查状态不一致的稿件剔除
rState, err := strconv.Atoi(p.ReviewState)
if err != nil {
log.Error("s.KneadArchive() error(%v) reviewState(%v)", err, p.ReviewState)
err = nil
continue
}
if state != int8(rState) {
archives = append(archives[:i], archives[i+1:]...)
i--
continue
}
}
}
if _, ok := additMap[v.ID]; ok {
archives[i].UpFrom = additMap[v.ID].UpFrom
if additMap[v.ID].MissionID > 0 {
archives[i].MissionID = additMap[v.ID].MissionID
}
}
if names, ok := chNames[v.ID]; ok {
archives[i].TagNames = names
}
if archives[i].TagNames == nil {
archives[i].TagNames = []string{}
}
if archives[i].UserType == nil {
archives[i].UserType = []int64{}
}
if v.UserGroup == nil {
v.UserGroup = []*manager.UpGroup2{}
}
if v.Attribute == nil {
v.Attribute = []int{}
}
v.Attrs = v.Attribute
for _, tp := range v.UserType {
if up, ok := s.allUpGroupCache[tp]; ok {
//因为前端希望稿件列表返回的up_group与任务质检结构一致所以在这做一次转换
gp := &manager.UpGroup2{
GroupID: up.ID,
GroupName: up.Name,
GroupTag: up.ShortTag,
}
result.Result[i].UserGroup = append(result.Result[i].UserGroup, gp)
}
}
}
result.Result = archives
return
}

View File

@@ -0,0 +1,24 @@
package service
import (
"context"
. "github.com/smartystreets/goconvey/convey"
"go-common/app/admin/main/videoup/model/search"
bm "go-common/library/net/http/blademaster"
"testing"
)
func TestService_SearchArchive(t *testing.T) {
var (
c = &bm.Context{
Context: context.Background(),
}
ap = &search.ArchiveParams{
Aids: "35084740,35088598,35088785,35084740,35010110,35088598,35088785,29398125,35089978,35091989,35066022,35093090,35093223,35066022,35089909,35089586,35093908,35093223,35089909,13654260,35095497,35094073,35095209,35095209,13654260,35094073,35097561,35097561,35097561,35099099,35078689,35099099,33764038,35100034,35100034,35101407,35102575,35102934,35103059,35104205,35105495,35081994,35106475,35101407,35103059,35105495,35081994,35102934,35106475,35107286,35106731,35060418,35108599,35108463,35109748,35111706,35110453,35113524,35113604,35111549,35114277,35114010,35114736,35114637,35116637,35116836,35114534,35117091,32831400,35118300,35119337,9286322,35107286,35060418,35106731,35108463,35109748,35111706,35110453,35113524,35113604,35111549,35114736,32831400,35114277,35114637,35118300,35119337,35118873,35052973,35118873,35052973,35122858,35122995,35097561,35097561,35125531,35126909,35126641,35126651,35127290,35126553,35127729,35128312,35127395,35127569,21342393,35127488,35129538,34881916,35127290,35075183,23584443,35130428,23191210,35129543,35132998,35133396,35134689",
}
)
Convey("SearchArchive", t, WithService(func(s *Service) {
_, err := svr.SearchArchive(c, ap)
So(err, ShouldBeNil)
}))
}

View File

@@ -0,0 +1,320 @@
package service
import (
"context"
"go-common/app/admin/main/videoup/dao/monitor"
"math"
"sync"
"time"
"go-common/app/admin/main/videoup/conf"
arcdao "go-common/app/admin/main/videoup/dao/archive"
datadao "go-common/app/admin/main/videoup/dao/data"
busdao "go-common/app/admin/main/videoup/dao/databus"
mngdao "go-common/app/admin/main/videoup/dao/manager"
musicdao "go-common/app/admin/main/videoup/dao/music"
overseadao "go-common/app/admin/main/videoup/dao/oversea"
searchdao "go-common/app/admin/main/videoup/dao/search"
staffdao "go-common/app/admin/main/videoup/dao/staff"
tagDao "go-common/app/admin/main/videoup/dao/tag"
taskdao "go-common/app/admin/main/videoup/dao/task"
trackdao "go-common/app/admin/main/videoup/dao/track"
arcmdl "go-common/app/admin/main/videoup/model/archive"
"go-common/app/admin/main/videoup/model/manager"
mngmdl "go-common/app/admin/main/videoup/model/manager"
msgmdl "go-common/app/admin/main/videoup/model/message"
accApi "go-common/app/service/main/account/api"
upsrpc "go-common/app/service/main/up/api/v1"
"go-common/library/log"
"go-common/library/queue/databus"
"github.com/jinzhu/gorm"
"go-common/library/net/http/blademaster/middleware/permit"
)
// Service is service.
type Service struct {
c *conf.Config
arc *arcdao.Dao
busCache *busdao.Dao
mng *mngdao.Dao
oversea *overseadao.Dao
track *trackdao.Dao
music *musicdao.Dao
tag *tagDao.Dao
DB *gorm.DB
search *searchdao.Dao
staff *staffdao.Dao
overseaDB *gorm.DB
data *datadao.Dao
monitor *monitor.Dao
task *taskdao.Dao
// acc rpc
accRPC accApi.AccountClient
upsRPC upsrpc.UpClient
// databus
videoupPub *databus.Databus
upCreditPub *databus.Databus
// cache: upper
adtTpsCache map[int16]struct{}
thrTpsCache map[int16]int
thrMin, thrMax int
upperCache map[int8]map[int64]struct{} //TODO 这个缓存需要从up服务里取
allUpGroupCache map[int64]*manager.UpGroup //UP主分组列表
fansCache int64
roundTpsCache map[int16]struct{}
typeCache map[int16]*arcmdl.Type
typeCache2 map[int16][]int64 // 记录每个一级分区下的二级分区
flowsCache map[int64]string
porderConfigCache map[int64]*arcmdl.PorderConfig
twConCache map[int8]map[int64]*arcmdl.WCItem
// error chan
msgCh chan *msgmdl.Videoup
// wait
wg sync.WaitGroup
closed bool
stop chan struct{}
auth *permit.Permit
}
// New is videoup-admin service implementation.
func New(c *conf.Config) (s *Service) {
s = &Service{
c: c,
arc: arcdao.New(c),
mng: mngdao.New(c),
oversea: overseadao.New(c),
music: musicdao.New(c),
track: trackdao.New(c),
busCache: busdao.New(c),
search: searchdao.New(c),
staff: staffdao.New(c),
tag: tagDao.New(c),
data: datadao.New(c),
monitor: monitor.New(c),
task: taskdao.New(c),
// pub
videoupPub: databus.New(c.VideoupPub),
upCreditPub: databus.New(c.UpCreditPub),
// chan
msgCh: make(chan *msgmdl.Videoup, c.ChanSize),
// map
stop: make(chan struct{}),
auth: permit.New(c.Auth),
}
var err error
if s.accRPC, err = accApi.NewClient(c.AccountRPC); err != nil {
panic(err)
}
if s.upsRPC, err = upsrpc.NewClient(c.UpsRPC); err != nil {
panic(err)
}
s.DB = s.music.DB
s.overseaDB = s.oversea.OverseaDB
// load cache.
s.loadType()
s.loadUpGroups()
s.loadUpper()
s.loadConf()
go s.cacheproc()
go s.msgproc()
s.wg.Add(1) // NOTE: sync add wait group
go s.multSyncProc()
return s
}
func (s *Service) isWhite(mid int64) bool {
if ups, ok := s.upperCache[mngmdl.UpperTypeWhite]; ok {
_, is := ups[mid]
return is
}
return false
}
//PGCWhite whether mid in pgcwhite list
func (s *Service) PGCWhite(mid int64) bool {
if ups, ok := s.upperCache[mngmdl.UpperTypePGCWhite]; ok {
_, is := ups[mid]
return is
}
return false
}
func (s *Service) isBlack(mid int64) bool {
if ups, ok := s.upperCache[mngmdl.UpperTypeBlack]; ok {
_, is := ups[mid]
return is
}
return false
}
func (s *Service) getAllUPGroups(mid int64) (gs []int64) {
gs = []int64{}
for tp, item := range s.upperCache {
if _, exist := item[mid]; !exist {
continue
}
gs = append(gs, int64(tp))
}
return
}
func (s *Service) isAuditType(tpID int16) bool {
_, isAt := s.adtTpsCache[tpID]
return isAt
}
func (s *Service) isRoundType(tpID int16) bool {
_, in := s.roundTpsCache[tpID]
return in
}
func (s *Service) isTypeID(tpID int16) bool {
_, in := s.typeCache[tpID]
return in
}
func (s *Service) loadType() {
// TODO : audit types
// threshold
thr, err := s.arc.ThresholdConf(context.TODO())
if err != nil {
log.Error("s.arc.ThresholdConf error(%v)", err)
return
}
s.thrTpsCache = thr
var min, max = math.MaxInt32, 0
for _, t := range thr {
if min > t {
min = t
}
if max < t {
max = t
}
}
s.thrMin = min
s.thrMax = max
}
func (s *Service) loadUpper() {
upm, err := s.upSpecial(context.Background())
if err != nil {
log.Error("s.upSpecial error(%v)", err)
return
}
s.upperCache = upm
}
// loadUpGroups 加载所有UP分组列表
func (s *Service) loadUpGroups() {
groups, err := s.mng.UpGroups(context.TODO())
if err != nil {
log.Error("s.mng.UpGroups() error(%v)", err)
return
}
s.allUpGroupCache = groups
}
func (s *Service) loadConf() {
var (
fans int64
err error
auditTypes map[int16]struct{}
roundTypes map[int16]struct{}
flows map[int64]string
tpm map[int16]*arcmdl.Type
porderConfigs map[int64]*arcmdl.PorderConfig
twConCache map[int8]map[int64]*arcmdl.WCItem
tpm2 map[int16][]int64
)
if fans, err = s.arc.FansConf(context.TODO()); err != nil {
log.Error("s.arc.FansConf error(%v)", err)
return
}
s.fansCache = fans
if auditTypes, err = s.arc.AuditTypesConf(context.TODO()); err != nil {
log.Error("s.arc.AuditTypesConf error(%v)", err)
return
}
s.adtTpsCache = auditTypes
if roundTypes, err = s.arc.RoundTypeConf(context.TODO()); err != nil {
log.Error("s.arc.RoundTypeConf error(%v)", err)
return
}
s.roundTpsCache = roundTypes
if flows, err = s.arc.Flows(context.TODO()); err != nil {
log.Error("s.arc.Flows error(%v)", err)
return
}
s.flowsCache = flows
if tpm, err = s.arc.TypeMapping(context.TODO()); err != nil {
log.Error("s.arc.TypeMapping error(%v)", err)
return
}
s.typeCache = tpm
tpm2 = make(map[int16][]int64)
for id, tmod := range tpm {
if tmod.PID == 0 {
if _, ok := tpm2[id]; !ok {
tpm2[id] = []int64{}
}
continue
}
arrid, ok := tpm2[tmod.PID]
if !ok {
tpm2[tmod.PID] = []int64{int64(id)}
} else {
tpm2[tmod.PID] = append(arrid, int64(id))
}
}
s.typeCache2 = tpm2
if porderConfigs, err = s.arc.PorderConfig(context.TODO()); err != nil {
log.Error("s.arc.PorderConfig error(%v)", err)
return
}
s.porderConfigCache = porderConfigs
if twConCache, err = s.weightConf(context.TODO()); err != nil {
log.Error("s.weightConf error(%v)", err)
return
}
s.twConCache = twConCache
}
func (s *Service) cacheproc() {
for {
time.Sleep(3 * time.Minute)
s.loadType()
s.loadUpper()
s.loadUpGroups()
s.loadConf()
s.lockVideo()
go s.MonitorNotifyResult(context.TODO())
}
}
// Close consumer close.
func (s *Service) Close() {
s.arc.Close()
s.mng.Close()
s.music.Close()
s.busCache.Close()
time.Sleep(1 * time.Second)
close(s.stop)
close(s.msgCh)
s.closed = true
s.wg.Wait()
}
// Ping check server ok.
func (s *Service) Ping(c context.Context) (err error) {
if err = s.arc.Ping(c); err != nil {
return
}
if err = s.mng.Ping(c); err != nil {
return
}
return s.busCache.Ping(c)
}

View File

@@ -0,0 +1,58 @@
package service
import (
"context"
"flag"
"path/filepath"
"testing"
"time"
"go-common/app/admin/main/videoup/conf"
"go-common/library/queue/databus/report"
. "github.com/smartystreets/goconvey/convey"
)
var (
svr *Service
)
func init() {
dir, _ := filepath.Abs("../cmd/videoup-admin.toml")
flag.Set("conf", dir)
conf.Init()
svr = New(conf.Conf)
time.Sleep(time.Second)
report.InitManager(conf.Conf.ManagerReport)
}
func WithService(f func(s *Service)) func() {
return func() {
f(svr)
}
}
func TestService_Ping(t *testing.T) {
var (
c = context.TODO()
)
Convey("Ping", t, WithService(func(s *Service) {
err := svr.Ping(c)
So(err, ShouldBeNil)
}))
}
func TestService_PGCWhite(t *testing.T) {
Convey("PGCWhite", t, WithService(func(s *Service) {
data := svr.PGCWhite(1)
So(data, ShouldBeFalse)
}))
}
func TestService_getallupgroups(t *testing.T) {
Convey("getallupgroups", t, WithService(func(s *Service) {
gs := s.getAllUPGroups(27515615)
t.Logf("UPGroups(%+v)\r\n", gs)
So(len(gs), ShouldBeGreaterThan, 0)
}))
}

View File

@@ -0,0 +1,16 @@
package service
import (
"context"
"go-common/app/admin/main/videoup/model/archive"
)
// Staffs fn
func (s *Service) Staffs(c context.Context, aid int64) (data []*archive.Staff, err error) {
return s.staff.Staffs(c, aid)
}
// StaffApplyBatchSubmit func
func (s *Service) StaffApplyBatchSubmit(c context.Context, ap *archive.StaffBatchParam) (err error) {
return s.staff.StaffApplyBatchSubmit(c, ap)
}

View File

@@ -0,0 +1,17 @@
package service
import (
"context"
"go-common/app/admin/main/videoup/model/archive"
"go-common/library/log"
"time"
)
// StatsPoints get stats point
func (s *Service) StatsPoints(c context.Context, stime, etime time.Time, typeInt int8) (points []*archive.StatsPoint, err error) {
if points, err = s.arc.StatsPoints(c, stime, etime, typeInt); err != nil {
log.Error("s.arc.TaskTooksByHalfHour(%v,%v)", stime, etime)
return
}
return
}

View File

@@ -0,0 +1,291 @@
package service
import (
"context"
"fmt"
"reflect"
"strconv"
"time"
"go-common/app/admin/main/videoup/model/archive"
"go-common/app/admin/main/videoup/model/manager"
xsql "go-common/library/database/sql"
"go-common/library/log"
)
// TaskTooksByHalfHour get task books by ctime
func (s *Service) TaskTooksByHalfHour(c context.Context, stime, etime time.Time) (tooks []*archive.TaskTook, err error) {
if tooks, err = s.arc.TaskTooksByHalfHour(c, stime, etime); err != nil {
log.Error("s.arc.TaskTooksByHalfHour(%v,%v)", stime, etime)
return
}
return
}
//lockVideo Lock specified category videos
func (s *Service) lockVideo() {
//TODO It's a temporary function to lock videos. When no longer needed, remove it.
var (
c = context.TODO()
adminID int64 = 399 //Temporary task admin id for lock video.
uname = "videoupjob" //Temporary task admin name for lock video.
reason = "版权原因,该视频不予审核通过"
reasonID int64 = 197
rCateID int64 = 76
tagID int64 = 7 //版权tag
note = "自动锁定分区视频【欧美电影】,【日本电影】,【其他国家】,【港台剧】,【海外剧】"
ctime = time.Now()
mtime = ctime
err error
tx *xsql.Tx
)
//Note: check if another instance is locking video
locking, err := s.arc.IsLockingVideo(c)
if err != nil {
log.Error("s.lockVideo() s.arc.IsLockingVideo() err(%v)", err)
return
}
if locking {
log.Info("s.lockVideo() another instance is locking video")
return
}
//Set locking video redis
if err = s.arc.LockingVideo(c, 1); err != nil {
log.Error("s.lockVideo() s.arc.LockingVideo() err(%v)", err)
return
}
defer func() {
//Unlock locking video redis
if err = s.arc.LockingVideo(c, 0); err != nil {
log.Error("s.lockVideo() s.arc.LockingVideo() err(%v)", err)
}
}()
if _, err = s.arc.TaskUserCheckIn(c, adminID); err != nil {
log.Error("s.lockVideo() s.arc.TaskUserCheckIn(%d) error(%v)", adminID, err)
return
}
tasks, err := s.arc.UserUndoneSpecTask(c, adminID)
if err != nil {
log.Error("s.lockVideo() error(%v)", err)
return
}
if len(tasks) == 0 {
log.Info("s.lockVideo() no task.")
return
}
var vps = []*archive.VideoParam{}
for _, t := range tasks {
if t.State == archive.TypeFinished {
continue
}
v, err := s.arc.VideoByCID(c, t.Cid)
if err != nil {
log.Error("s.lockVideo() s.arc.VideoByCID(%d) error(%v)", t.Cid, err)
continue
}
arc, err := s.arc.Archive(c, t.Aid)
if err != nil {
log.Error("s.lockVideo() s.arc.Archive(%d) error(%v)", v.Aid, err)
continue
}
//If archive's mid in white list, release task and continue
if s.PGCWhite(arc.Mid) {
log.Info("s.lockVideo() mid in white list, release task(%d)", t.ID)
//Begin update task state and add task history
if tx, err = s.arc.BeginTran(c); err != nil {
log.Error("s.arc.BeginTran error(%v)", err)
continue
}
if _, err = s.arc.TxReleaseByID(tx, t.ID); err != nil {
log.Error("s.lockVideo() s.arc.TxReleaseByID(%d) error(%v)", t.ID, err)
tx.Rollback()
continue
}
if _, err = s.arc.TxAddTaskHis(tx, 0, archive.ActionRelease /*action*/, t.ID /*task_id*/, t.Cid /*cid*/, 0, 0, 0, "lockVideo release" /*reason*/); err != nil {
log.Error("s.lockVideo() s.arc.TxAddTaskHis error(%v)", err)
tx.Rollback()
continue
}
if err = tx.Commit(); err != nil {
log.Error("tx.Commit error(%v)", err)
}
continue
}
//Get archive's top type id
rTp, err := s.TypeTopParent(arc.TypeID)
if err != nil {
log.Error("s.lockVideo() s.arc.TypeTopParent(%d) error(%v)", arc.TypeID, err)
continue
}
//Add video lock reason log
if _, err = s.mng.AddReasonLog(c, v.Cid, manager.ReasonLogTypeVideo, rCateID, reasonID, adminID, arc.TypeID, ctime, mtime); err != nil {
log.Error("s.lockVideo() s.arc.AddReasonLog(%d,%d,%d,%d,%d,%d,%v,%v) error(%v)", v.Cid, manager.ReasonLogTypeVideo, rCateID, reasonID, adminID, arc.TypeID, ctime, mtime, err)
}
//Begin update task state and add task history
if tx, err = s.arc.BeginTran(c); err != nil {
log.Error("s.arc.BeginTran error(%v)", err)
continue
}
if _, err = s.arc.TxUpTaskByID(tx, t.ID, map[string]interface{}{"state": archive.TypeFinished, "utime": 0}); err != nil {
log.Error("s.lockVideo() s.arc.TxUpTaskByID(%d) error(%v)", t.ID, err)
tx.Rollback()
continue
}
if _, err = s.arc.TxAddTaskHis(tx, archive.PoolForFirst, archive.TypeFinished, t.ID, t.Cid, adminID, 0, archive.VideoStatusLock, reason); err != nil {
log.Error("s.lockVideo() s.arc.SubmitTask(%d) error(%v)", t.ID, err)
tx.Rollback()
continue
}
if err = tx.Commit(); err != nil {
log.Error("tx.Commit error(%v)", err)
continue
}
//Set video param
vp := &archive.VideoParam{}
vp.ID = v.ID
vp.Aid = v.Aid
vp.Cid = v.Cid
vp.Filename = v.Filename
vp.RegionID = rTp.ID
vp.Status = archive.VideoStatusLock
vp.UID = adminID
vp.Oname = uname
vp.Note = note + " [任务ID]task:" + strconv.Itoa(int(t.ID))
vp.Reason = reason
vp.TagID = tagID
vp.Encoding = 0
vps = append(vps, vp)
log.Info("s.lockVideo() add video. cid(%d)", v.Cid)
}
if len(vps) == 0 {
log.Info("s.lockVideo() no belongs to 399 task.")
return
}
//Add videos to batch list
s.BatchVideo(c, vps, archive.ActionVideoSubmit)
}
/* 批量查询,批量转换
* list []*struct{}
* multrans 转化器根据ID查出其他值
* ID id字段名称id字段类型必须是int64
* Names 查出来的各个字段名称
*/
func (s *Service) mulIDtoName(c context.Context, list interface{}, multrans func(context.Context, []int64) (map[int64][]interface{}, error), ID string, Names ...string) (err error) {
var (
lV, itemI, itemIE, idFiled, nameFiled, valueField reflect.Value
id int64
ids []int64
hashIDName = make(map[int64][]interface{})
)
if lV = reflect.ValueOf(list); !lV.IsValid() || lV.IsNil() || lV.Kind() != reflect.Slice {
return fmt.Errorf("invalid list")
}
count := lV.Len()
for i := 0; i < count; i++ {
if itemI = lV.Index(i); !itemI.IsValid() || itemI.IsNil() || itemI.Kind() != reflect.Ptr {
return fmt.Errorf("invalid itemI")
}
if itemIE = itemI.Elem(); !itemIE.IsValid() || itemIE.Kind() != reflect.Struct {
return fmt.Errorf("invalid itemIE")
}
if idFiled = itemIE.FieldByName(ID); !idFiled.IsValid() || idFiled.Kind() != reflect.Int64 {
return fmt.Errorf("invalid idFiled")
}
for _, name := range Names {
if nameFiled = itemIE.FieldByName(name); !nameFiled.IsValid() || !nameFiled.CanSet() {
return fmt.Errorf("invalid nameFiled")
}
}
if id = idFiled.Int(); id != 0 {
if _, ok := hashIDName[id]; !ok {
hashIDName[id] = []interface{}{}
ids = append(ids, id)
}
}
}
if hashIDName, err = multrans(c, ids); err != nil {
log.Error("multrans error(%v)", ids)
return
}
for i := 0; i < count; i++ {
itemIE = lV.Index(i).Elem()
id = itemIE.FieldByName(ID).Int()
if names, ok := hashIDName[id]; ok && len(names) == len(Names) {
for i, name := range names {
nameFiled = itemIE.FieldByName(Names[i])
valueField = reflect.ValueOf(name)
if nameFiled.Kind() != valueField.Kind() {
log.Error("multrans return %v while need ", ids)
continue
}
itemIE.FieldByName(Names[i]).Set(reflect.ValueOf(name))
}
}
}
return
}
// 每个ID单独查询 strict严格模式下一次错误直接返回
func (s *Service) singleIDtoName(c context.Context, list interface{}, singletrans func(context.Context, int64) ([]interface{}, error), strict bool, ID string, Names ...string) (err error) {
var (
lV, itemI, itemIE, idFiled, nameFiled, valueField reflect.Value
id int64
values []interface{}
)
if lV = reflect.ValueOf(list); !lV.IsValid() || lV.IsNil() || lV.Kind() != reflect.Slice {
return fmt.Errorf("invalid list")
}
count := lV.Len()
for i := 0; i < count; i++ {
if itemI = lV.Index(i); !itemI.IsValid() || itemI.IsNil() || itemI.Kind() != reflect.Ptr {
return fmt.Errorf("invalid itemI")
}
if itemIE = itemI.Elem(); !itemIE.IsValid() || itemIE.Kind() != reflect.Struct {
return fmt.Errorf("invalid itemIE")
}
if idFiled = itemIE.FieldByName(ID); !idFiled.IsValid() || idFiled.Kind() != reflect.Int64 {
return fmt.Errorf("invalid idFiled")
}
for _, Name := range Names {
if nameFiled = itemIE.FieldByName(Name); !nameFiled.IsValid() || !nameFiled.CanSet() {
return fmt.Errorf("invalid nameFiled")
}
}
if id = idFiled.Int(); id != 0 {
if values, err = singletrans(c, id); err != nil || len(values) != len(Names) {
log.Error("s.sigleIDtoName error(%v) len(values)=%d len(Names)=%d", err, len(values), len(Names))
if strict {
return
}
err = nil
continue
}
for i, value := range values {
nameFiled = itemIE.FieldByName(Names[i])
valueField = reflect.ValueOf(value)
if nameFiled.Kind() != valueField.Kind() {
log.Error("singletrans return %s while need %s", valueField.Kind().String(), nameFiled.Kind().String())
continue
}
nameFiled.Set(valueField)
}
}
}
return
}
// GetUID 获取uid有时候cookie没有uid
func (s *Service) GetUID(c context.Context, name string) (uid int64, err error) {
return s.mng.GetUIDByName(c, name)
}

View File

@@ -0,0 +1,159 @@
package service
import (
"context"
"fmt"
"go-common/library/sync/errgroup"
"strings"
"time"
"go-common/app/admin/main/videoup/model/archive"
"go-common/library/log"
)
// HandsUp 签入
func (s *Service) HandsUp(c context.Context, uid int64, uname string) (err error) {
if s.CheckOnline(c, uid) {
log.Info("已经登入(%d)", uid)
return
}
_, err = s.arc.TaskUserCheckIn(c, uid)
if err != nil {
log.Error("s.arc.TaskUserCheckIn(%d) error(%v)", uid, err)
return
}
s.sendConsumerLog(c, &archive.ConsumerLog{
UID: uid,
Uname: uname,
Action: archive.ActionHandsUP,
Ctime: time.Now().Format(archive.TimeFormatSec),
Desc: "checkin",
})
mapParas := map[string]interface{}{
"action": archive.ActionHandsUP,
"uid": uid,
}
if _, err = s.arc.AddTaskHis(c, 0, archive.ActionHandsUP, 0, 0, uid, 0, 0, "checkin"); err != nil {
log.Error("s.arc.AddTaskLog(%v) error(%v)", mapParas, uid)
return
}
log.Info("用户签入(%d)", uid)
return
}
// HandsOff 签出
func (s *Service) HandsOff(c context.Context, uid int64, fuid int64) (err error) {
if fuid != 0 { //管理员强制踢出组员
if !s.isLeader(c, uid) {
return fmt.Errorf("只有组长能强制踢出")
}
log.Info("管理员%d踢出组员%d", uid, fuid)
uid = fuid
}
err = s.checkOut(c, uid)
if err != nil {
log.Error("s.checkOut(%d) error(%v)", uid, err)
return
}
s.sendConsumerLog(c, &archive.ConsumerLog{
UID: uid,
Uname: "",
Action: archive.ActionHandsOFF,
Ctime: time.Now().Format(archive.TimeFormatSec),
Desc: "checkout",
})
s.Free(c, uid)
return
}
// Online 用户列表
func (s *Service) Online(c context.Context) (cms []*archive.Consumers, err error) {
cms, err = s.arc.Consumers(c)
if err != nil {
log.Error("s.arc.Consumers error(%v)", err)
return
}
if len(cms) > 0 {
var wg errgroup.Group
wg.Go(func() error {
if err := s.mulIDtoName(c, cms, s.mng.GetNameByUID, "UID", "UserName"); err != nil {
log.Error("mulIDtoName s.mng.GetNameByUID error(%v)", err)
}
return nil
})
wg.Go(func() error {
if err := s.mulIDtoName(c, cms, s.search.OutTime, "UID", "LastOut"); err != nil {
log.Error("mulIDtoName s.search.OutTime error(%v)", err)
}
return nil
})
wg.Wait()
}
return
}
// InOutList 用户登入登出历史
func (s *Service) InOutList(c context.Context, unames string, bt, et string) (l []*archive.InQuit, err error) {
uids := []int64{}
if len(unames) > 0 {
if res, err := s.mng.Uids(c, strings.Split(unames, ",")); err == nil {
for _, uid := range res {
uids = append(uids, uid)
}
}
}
// 前端参数是日期,搜索参数必须到秒
if len(bt) > 0 && len(et) > 0 {
bt = bt + " 00:00:00"
et = et + " 23:59:59"
}
return s.search.InQuitList(c, uids, bt, et)
}
// CheckOnline 检查在线状态
func (s *Service) CheckOnline(c context.Context, uid int64) (on bool) {
if s.arc.IsConsumerOn(c, uid) == 1 {
on = true
}
return
}
// CheckGroup 检查用户组权限
func (s *Service) CheckGroup(c context.Context, uid int64) (role int8, err error) {
role, err = s.mng.GetUserRole(c, uid)
if err != nil || role == 0 {
log.Error("非法用户(%d) error(%v)", uid, err)
return
}
return
}
func (s *Service) checkOut(c context.Context, uid int64) (err error) {
if s.arc.IsConsumerOn(c, uid) == 0 {
log.Info("已经签出(%d)", uid)
return
}
_, err = s.arc.TaskUserCheckOff(c, uid)
if err != nil {
log.Error("s.arc.TaskUserCheckOff(%d) error(%v)", uid, err)
return
}
mapParas := map[string]interface{}{
"action": archive.ActionHandsOFF,
"uid": uid,
}
if _, err = s.arc.AddTaskHis(c, 0, archive.ActionHandsOFF, 0, 0, uid, 0, 0, "checkOut"); err != nil {
log.Error("s.arc.AddTaskLog(%v) error(%v)", mapParas, uid)
}
return
}

View File

@@ -0,0 +1,337 @@
package service
import (
"context"
"fmt"
"time"
"go-common/app/admin/main/videoup/model/archive"
"go-common/app/admin/main/videoup/model/manager"
"go-common/app/admin/main/videoup/model/utils"
"go-common/library/database/sql"
"go-common/library/log"
"go-common/library/xstr"
)
// List 查看任务列表
func (s *Service) List(c context.Context, uid int64, pn, ps int, ltype, leader int8) (tasks []*archive.Task, err error) {
return s.arc.ListByCondition(c, uid, pn, ps, ltype, leader)
}
// Delay 申请延迟
func (s *Service) Delay(c context.Context, id, uid int64, reason string) (err error) {
tx, err := s.arc.BeginTran(c)
if err != nil {
log.Error("s.arc.BeginTran() error(%v)", err)
return
}
rows, err := s.arc.TxUpTaskByID(tx, id, map[string]interface{}{"state": archive.TypeDelay, "dtime": time.Now()})
if err != nil {
log.Error("s.arc.TxUpTaskByID(%d) error(%v)", id, err)
tx.Rollback()
return
}
if rows > 0 {
if _, err = s.arc.TxAddTaskHis(tx, 0, archive.ActionDelay /*action*/, id /*task_id*/, 0, uid /*uid*/, 0, 0, reason /*reason*/); err != nil {
log.Error("s.arc.AddTaskLog(%d) error(%v)", id, err)
tx.Rollback()
return
}
}
return tx.Commit()
}
// TaskSubmit 提交审核结果
func (s *Service) TaskSubmit(c context.Context, id int64, uid int64, status int64) (err error) {
var utime int64
t, err := s.arc.TaskByID(c, id)
if err != nil {
log.Error(" s.arc.TaskByID(%d) error(%v)", id, err)
return
}
switch {
case t.State == archive.TypeDelay:
utime = 0
case t.GTime.TimeValue().IsZero():
utime = int64(time.Since(t.MTime.TimeValue()).Seconds())
default:
utime = int64(time.Since(t.GTime.TimeValue()).Seconds())
}
tx, err := s.arc.BeginTran(c)
if err != nil {
log.Error("s.arc.BeginTran error(%v)", err)
return
}
rows, err := s.arc.TxUpTaskByID(tx, id, map[string]interface{}{"state": archive.TypeFinished, "utime": utime})
if err != nil {
log.Error("s.arc.TxUpTaskByID(%d) error(%v)", id, err)
tx.Rollback()
return
}
if rows > 0 {
if _, err = s.arc.TxAddTaskHis(tx, 0, archive.ActionSubmit /*action*/, id /*task_id*/, t.Cid /*cid*/, uid /*uid*/, utime /*utime*/, int16(status) /*result*/, "TaskSubmit" /*reason*/); err != nil {
log.Error("s.arc.AddTaskLog(%d) error(%v)", id, err)
tx.Rollback()
return
}
}
return tx.Commit()
}
// Next 领取任务
func (s *Service) Next(c context.Context, uid int64) (task *archive.Task, err error) {
var rows int64
task, err = s.arc.GetNextTask(c, uid)
if err != nil {
log.Error("d.getTask(%d) error(%v)", uid, err)
return
}
if task != nil {
return
}
// 释放超时任务
s.Free(c, 0)
// 从实时任务池抢占
if rows, err = s.dispatchTask(c, uid); err != nil {
return
} else if rows > 0 {
return s.arc.GetNextTask(c, uid)
}
return
}
// Info 查询任务信息
func (s *Service) Info(c context.Context, tid int64) (task *archive.Task, err error) {
return s.arc.TaskByID(c, tid)
}
// 抢占任务(先抢占再查,避免重复下发)
func (s *Service) dispatchTask(c context.Context, uid int64) (rows int64, err error) {
var (
tls []*archive.TaskForLog
arrid []int64
)
if tls, err = s.arc.GetDispatchTask(c, uid); err != nil {
log.Error("s.arc.GetDispatchTask(%d) error(%v)", uid, err)
return
}
for _, item := range tls {
arrid = append(arrid, item.ID)
}
if len(arrid) > 0 {
if rows, err = s.arc.UpDispatchTask(c, uid, arrid); err != nil {
log.Error("s.arc.UpDispatchTask(%d,%v) error(%v)", uid, arrid, err)
return
}
// 日志允许错误
if int(rows) == len(arrid) {
log.Info("UpDispatchTask 更新数量(%d)", rows)
} else {
log.Warn("UpDispatchTask 更新数量(%d) 日志数量(%d)", rows, len(arrid))
}
s.arc.MulAddTaskHis(c, tls, archive.ActionDispatch, uid)
}
return
}
// Free 任务释放(有uid为主动释放没有uid为被动释放)(先查再释放,有可能记录冗余释放信息)
func (s *Service) Free(c context.Context, uid int64) (rows int64) {
var (
rts []*archive.TaskForLog
ids, rtids []int64
lastid int64
err error
mtime = time.Now()
)
if uid == 0 {
if rts, err = s.arc.GetTimeOutTask(c); err != nil {
log.Error("s.Free s.arc.GetTimeOutTask error(%v)", err)
return
}
} else {
if rts, lastid, err = s.arc.GetRelTask(c, uid); err != nil {
log.Error("s.Free s.arc.GetRelTask(%d) error(%v)", uid, err)
return
}
}
mcases := make(map[int64]*archive.WCItem)
for _, rt := range rts {
ids = append(ids, rt.ID)
if rt.Subject == 1 { //指派任务回流
rtids = append(rtids, rt.ID)
mcases[rt.ID] = &archive.WCItem{Radio: 4, Weight: archive.WLVConf.SubRelease, Mtime: utils.NewFormatTime(time.Now()), Desc: "指派回流权重"}
}
}
if len(ids) > 0 {
if rows, err = s.arc.MulReleaseMtime(c, ids, mtime); err != nil {
log.Error("s.arc.MulReleaseMtime(%v, %v) error(%v)", ids, mtime, err)
return
}
if rows > 0 {
s.arc.MulAddTaskHis(c, rts, archive.ActionRelease, uid)
}
}
if lastid > 0 {
s.arc.UpGtimeByID(c, lastid, "0000-00-00 00:00:00")
timelogout := time.Now()
log.Info("添加延时释放任务(%d %v)", lastid, timelogout)
time.AfterFunc(5*time.Minute, func() {
s.releaseSpecial(timelogout, lastid, uid)
})
}
if len(rtids) > 0 {
s.setWeightConf(c, xstr.JoinInts(rtids), mcases)
}
return
}
func (s *Service) releaseSpecial(tout time.Time, taskid, uid int64) {
tx, err := s.arc.BeginTran(context.TODO())
if err != nil {
log.Error(" s.arc.BeginTran error(%v)", err)
return
}
rows, err := s.arc.TxReleaseSpecial(tx, tout, 1, taskid, uid)
if err != nil {
log.Error("s.arc.TxReleaseSpecial error(%v)", err)
tx.Rollback()
return
}
if rows > 0 {
log.Info("s.arc.TxReleaseSpecial 释放任务(%d)", taskid)
if _, err = s.arc.TxAddTaskHis(tx, 0, archive.ActionRelease, taskid, 0, uid, 0, 0, "登出延时释放"); err != nil {
log.Error("s.arc.TxAddTaskHis error(%v)", err)
tx.Rollback()
return
}
}
tx.Commit()
}
func (s *Service) getTWCache(c context.Context, ids []int64) (mcases map[int64]*archive.TaskPriority, err error) {
if mcases, err = s.task.GetWeightRedis(c, ids); len(mcases) != len(ids) {
mcases, err = s.arc.GetWeightDB(c, ids)
}
return
}
func (s *Service) judge(c context.Context, tid, aid, cid, uid int64) (err error) {
var (
rows int64
tx *sql.Tx
v *archive.Video
a *archive.Archive
)
// 1.校验视频
if v, err = s.arc.VideoByCID(c, cid); err != nil {
log.Error("s.arc.VideoByCID(%d) error(%v)", cid, err)
return
}
if v == nil || v.Status == archive.VideoStatusDelete {
err = fmt.Errorf("视频(cid=%d)被删除", cid)
goto DELETE
}
// 2.校验稿件
if a, err = s.arc.Archive(c, aid); err != nil {
log.Error("s.arc.Archive(%d) error(%v)", aid, err)
return
}
if a == nil || a.State == archive.StateForbidUpDelete {
err = fmt.Errorf("稿件(aid=%d)被删除", aid)
}
DELETE:
if err != nil {
if tx, err = s.arc.BeginTran(c); err != nil {
log.Error("s.arc.BeginTran() error(%v)", err)
return
}
if rows, err = s.arc.TxUpTaskByID(tx, tid, map[string]interface{}{"state": archive.TypeFinished, "utime": 0}); err != nil {
log.Error("s.arc.TxUpTaskByID(%d) error(%v)", tid, err)
tx.Rollback()
return
}
if rows > 0 {
if _, err = s.arc.TxAddTaskHis(tx, 0 /*pool*/, archive.ActionTaskDelete /*action*/, tid /*task_id*/, cid /*cid*/, uid /*uid*/, 0 /*utime*/, archive.VideoStatusDelete /*result*/, "judge delete" /*reason*/); err != nil {
log.Error("s.arc.AddTaskLog(%d) error(%v)", tid, err)
tx.Rollback()
return
}
}
return tx.Commit()
}
return
}
// CheckOwner 检查任务状态修改权限
func (s *Service) CheckOwner(c context.Context, tid, uid int64) (err error) {
var role int8
var rows int64
task, err := s.arc.TaskByID(c, tid)
if task == nil || err != nil {
log.Error("s.arc.TaskByID(%d) error(%v)", tid, err)
return
}
if err = s.judge(c, task.ID, task.Aid, task.Cid, uid); err != nil {
log.Error("s.judge(%+v) error(%v)", task, err)
return
}
if role, err = s.mng.GetUserRole(c, uid); err != nil || role == 0 {
err = fmt.Errorf("非法用户(%d)", uid)
return
}
if task.State == archive.TypeDelay || task.State == archive.TypeSpecial {
return
}
if !s.CheckOnline(c, uid) {
err = fmt.Errorf("请先签到(%d)", uid)
return
}
if role == manager.TaskLeader {
return
}
if task.UID != uid {
err = fmt.Errorf("没有权限处理该任务")
return
}
// 普通用户处理超时了,将任务释放掉
if task.State == archive.TypeDispatched && time.Since(task.GTime.TimeValue()).Minutes() > 10.0 {
var tx *sql.Tx
if tx, err = s.arc.BeginTran(c); err != nil {
log.Error("s.arc.BeginTran() error(%v)", err)
return
}
if rows, err = s.arc.TxUpTaskByID(tx, tid, map[string]interface{}{"state": archive.TypeRealTime, "uid": 0, "gtime": "0000-00-00 00:00:00"}); err != nil {
log.Error("s.arc.TxUpTaskByID(%d) error(%v)", tid, err)
tx.Rollback()
return
}
if rows > 0 {
if _, err = s.arc.TxAddTaskHis(tx, 0 /*pool*/, archive.ActionRelease /*action*/, tid /*task_id*/, 0 /*cid*/, uid /*uid*/, 0 /*utime*/, 0 /*result*/, "timeout release" /*reason*/); err != nil {
log.Error("s.arc.AddTaskLog(%d) error(%v)", tid, err)
tx.Rollback()
return
}
}
return tx.Commit()
}
return
}

View File

@@ -0,0 +1,130 @@
package service
import (
"context"
"encoding/json"
"strconv"
"go-common/app/admin/main/videoup/model/archive"
"go-common/library/log"
)
func (s *Service) fetchQAVideo(c context.Context, vp *archive.VideoParam) (task *archive.QAVideo, err error) {
auditDetails, err := s.fetchVideoAuditDetail(c, vp.ID, vp.Aid, vp.Cid, vp.TaskID)
if err != nil || auditDetails == nil {
return nil, err
}
fans := int64(0)
if auditDetails.UserInfo != nil && auditDetails.UserInfo["fans"] != nil {
fanss := strconv.FormatFloat(auditDetails.UserInfo["fans"].(float64), 'f', 0, 64)
if fans, err = strconv.ParseInt(fanss, 10, 64); err != nil {
log.Error("fetchQAVideo strconv.ParseInt(%v) error(%v)", auditDetails.UserInfo["fans"], err)
return
}
}
video := auditDetails.Video
details, err := json.Marshal(auditDetails)
if err != nil {
log.Error("fetchQAVideo json.Marshal(auditdetails) error(%v) aid(%d) cid(%d) details(%v)", err, vp.Aid, vp.Cid, auditDetails)
return
}
auditSubmit := &archive.AuditSubmit{
Encoding: strconv.Itoa(int(vp.Encoding)),
Reason: vp.Reason,
ReasonID: strconv.Itoa(int(vp.RegionID)),
Note: vp.Note,
}
submit, err := json.Marshal(auditSubmit)
if err != nil {
log.Error("fetchQAVideo json.Marshal(auditsubmit) error(%v) aid(%d) cid(%d) submit(%s)", err, vp.Aid, vp.Cid, auditSubmit)
return
}
task = &archive.QAVideo{
UID: vp.UID,
Oname: vp.Oname,
AID: vp.Aid,
CID: vp.Cid,
TaskID: vp.TaskID,
TagID: vp.TagID,
ArcTitle: video.Title,
ArcTypeid: video.Typeid,
AuditStatus: vp.Status,
AuditSubmit: string(submit),
AuditDetails: string(details),
MID: video.MID,
UPGroups: s.getAllUPGroups(video.MID),
Fans: fans,
}
return
}
func (s *Service) fetchVideoAuditDetail(c context.Context, vid, aid, cid, taskID int64) (dt *archive.AuditDetails, err error) {
video, err := s.arc.VideoInfo(c, aid, cid)
if err != nil {
return nil, err
}
if video == nil {
log.Error("fetchVideoAuditDetail video not exist, aid(%d) cid(%d)", aid, cid)
return
}
video.XcodeStateName = archive.XcodeStateNames[video.XcodeState]
if tp, exist := s.typeCache[int16(video.Typeid)]; exist {
video.Typename = tp.Name
}
video.Cover = coverURL(video.Cover)
relationVideo, err := s.arc.VideoRelated(c, aid)
if err != nil {
return nil, err
}
task, err := s.arc.TaskDispatchByID(c, taskID)
if err != nil {
return nil, err
}
userInfo, err := s.arc.GetUserCard(c, video.MID)
if err != nil || len(userInfo) <= 0 {
return nil, err
}
mosaic, err := s.arc.Mosaic(c, cid)
if err != nil {
return nil, err
}
watermark, err := s.arc.Watermark(c, video.MID)
if err != nil {
return nil, err
}
dt = &archive.AuditDetails{
UserInfo: userInfo,
RelationVideos: relationVideo,
Task: []*archive.Task{task},
Video: video,
Watermark: watermark,
Mosaic: mosaic,
}
return
}
func (s *Service) addQAVideo(c context.Context, task *archive.QAVideo) (err error) {
if task == nil {
return
}
var bs []byte
if bs, err = json.Marshal(task); err != nil {
log.Error("addQAVideo json.Marshal error(%v) task(%+v)", err, task)
return
}
err = s.arc.SendQAVideoAdd(c, bs)
return
}

View File

@@ -0,0 +1,64 @@
package service
import (
"context"
"encoding/json"
"go-common/app/admin/main/videoup/model/archive"
"testing"
)
func getQAVideo(s *Service) (qav *archive.QAVideo, err error) {
vp := &archive.VideoParam{
ID: 10005358,
Aid: 10098493,
Cid: 10109201,
Status: 0,
Encoding: 1,
UID: 521,
Oname: "chenxi01",
Title: "测试添加qavideo",
Filename: "j180311at3c5g5me6nt4h3zkbiltif35",
RegionID: 23,
Attrs: &archive.AttrParam{
NoRank: 1,
NoDynamic: 1,
NoRecommend: 1,
NoSearch: 1,
OverseaLock: 1,
PushBlog: 1,
},
}
qav, err = s.fetchQAVideo(context.TODO(), vp)
return
}
func Test_qavideoaddsingle(t *testing.T) {
WithService(func(s *Service) {
qav, err := getQAVideo(s)
t.Logf("qavideo(%+v) err(%v)\r\n", qav, err)
ctx := context.TODO()
err = s.addQAVideo(ctx, qav)
t.Logf("error(%v)", err)
})()
}
func Test_qavideoadd(t *testing.T) {
WithService(func(s *Service) {
qav, err := getQAVideo(s)
t.Logf("qavideo(%+v) error(%v)", qav, err)
ctx := context.TODO()
task, _ := json.Marshal(qav)
err = s.arc.SendQAVideoAdd(ctx, task)
if err != nil {
t.Logf("s.arc.SendQAVideoAdd error(%v)", err)
} else {
t.Logf("s.arc.SendQAVideoAdd success")
}
})()
}

View File

@@ -0,0 +1,20 @@
package service
import (
"context"
"go-common/app/admin/main/videoup/model/manager"
"go-common/library/log"
)
func (s *Service) isLeader(c context.Context, uid int64) bool {
role, e := s.mng.GetUserRole(c, uid)
if e != nil {
log.Error("s.mng.GetUserRole(%d) error(%v)", uid, e)
return false
}
if role == manager.TaskLeader {
return true
}
return false
}

View File

@@ -0,0 +1,127 @@
package service
import (
"context"
"fmt"
"sync"
"testing"
"time"
"go-common/app/admin/main/videoup/model/archive"
"go-common/app/admin/main/videoup/model/utils"
)
func TestLockVideo(t *testing.T) {
svr.lockVideo()
}
func TestConsumer(t *testing.T) {
var c = context.TODO()
e := svr.HandsUp(c, 10, "10")
if e != nil {
t.Fatal(e)
}
e = svr.HandsUp(c, 20, "20")
if e != nil {
t.Fatal(e)
}
e = svr.HandsOff(c, 10, 20)
if e != nil {
t.Fatal(e)
}
e = svr.HandsUp(c, 20, "20")
if e != nil {
t.Fatal(e)
}
e = svr.HandsOff(c, 20, 10)
if e == nil {
t.Fatal("只有组长能强制踢出")
}
cms, err := svr.Online(c)
if err != nil {
t.Fatal(err)
}
if len(cms) != 2 {
t.Fatal("在线人数错误")
}
for _, v := range cms {
if (v.UID != 10 && v.UID != 20) || v.State != 1 {
t.Fatal("在线人信息错误")
}
}
}
func BenchmarkMultiGetNextTask(b *testing.B) {
var (
mux sync.RWMutex
wg = sync.WaitGroup{}
ConMap = make(map[int64]struct{})
)
Audit := func(w *sync.WaitGroup, uid int64) {
defer w.Done()
for {
tl, err := svr.Next(context.TODO(), uid)
if err != nil {
panic(err)
}
if tl == nil {
fmt.Println("任务领取完成")
return
}
mux.RLock()
_, ok := ConMap[tl.ID]
mux.RUnlock()
if ok {
panic(fmt.Sprintf("%d 重复下发:%d", uid, tl.ID))
} else {
mux.Lock()
ConMap[tl.ID] = struct{}{}
mux.Unlock()
}
fmt.Printf("uid=%d 领取任务:%d, weight=%d\n", uid, tl.ID, tl.Weight)
time.Sleep(time.Millisecond * 50)
if err = svr.Delay(context.TODO(), tl.ID, uid, "test-reson"); err != nil {
panic(err)
}
}
}
for i := 1; i <= 10; i++ {
wg.Add(1)
go Audit(&wg, int64(i))
}
wg.Wait()
}
func TestFree(t *testing.T) {
var c = context.TODO()
rows := svr.Free(c, 481)
if rows == 0 {
t.Fail()
}
t.Fail()
}
func Test_setWeightConf(t *testing.T) {
err := svr.setWeightConf(context.TODO(), "7", map[int64]*archive.WCItem{
7: {
Radio: 4,
Weight: 18,
Mtime: utils.NewFormatTime(time.Now()),
Desc: "指派回流任务",
},
})
if err != nil {
t.Fatal(err)
}
}

View File

@@ -0,0 +1,315 @@
package service
import (
"context"
"encoding/json"
"fmt"
"go-common/app/admin/main/videoup/model/utils"
"go-common/library/sync/errgroup"
"go-common/library/xstr"
"time"
"go-common/app/admin/main/videoup/model/archive"
accApi "go-common/app/service/main/account/api"
"go-common/library/log"
)
// weightConf 所有激活的配置项
func (s *Service) weightConf(c context.Context) (wconfs map[int8]map[int64]*archive.WCItem, err error) {
items, err := s.arc.WeightConf(c)
if err != nil {
log.Error("WeightConf error(%v)", err)
return
}
wconfs = map[int8]map[int64]*archive.WCItem{}
for _, item := range items {
conf, ok := wconfs[item.Radio]
if !ok {
conf = make(map[int64]*archive.WCItem)
}
conf[item.CID] = item
wconfs[item.Radio] = conf
}
return
}
// 同一类型的同id配置只能有一个
func (s *Service) checkConflict(c context.Context, mcases map[int64]*archive.WCItem) (err error) {
wcf, err := s.weightConf(c)
if err != nil {
log.Error("s.weightConf error(%v)", err)
return
}
s.twConCache = wcf
for _, item := range mcases {
if cfgs, ok := s.twConCache[item.Radio]; ok {
if cfg, ok := cfgs[item.CID]; ok {
return fmt.Errorf("config(%d) conflict with (id=%d,desc=%s)", item.CID, cfg.ID, cfg.Desc)
}
}
}
return
}
// AddWeightConf 配置权重
func (s *Service) AddWeightConf(c context.Context, cfg *archive.WeightConf, uid int64, uname string) (err error) {
//0. 一级分区转化为二级分区
if cfg.Radio == archive.WConfType {
cfg.Ids = s.tarnsType(c, cfg.Ids)
}
//1. 解析表单提交的配置
mcases, istaskid, err := archive.ParseWeightConf(cfg, uid, uname)
if err != nil {
log.Error("archive.ParseWeightConf(%v, %v) error(%v)", cfg, uname, err)
return
}
//2. 检查是否互相冲突
if err = s.checkConflict(c, mcases); err != nil {
log.Error("s.checkConflict error(%v)", err)
return
}
//3. 更新任务的权重配置
if istaskid {
if err = s.setWeightConf(c, cfg.Ids, mcases); err != nil {
log.Error("s.setWeightConf error(%v)", err)
return
}
}
//4. 将配置存储到数据库表
if err = s.arc.InWeightConf(c, mcases); err != nil {
log.Error("s.arc.InWeightConf(%v) error(%v)", mcases, err)
return
}
return
}
// DelWeightConf 删除配置项
func (s *Service) DelWeightConf(c context.Context, id int64) (err error) {
if _, err = s.arc.DelWeightConf(c, id); err != nil {
log.Error("s.DelWeightConf(%d) error(%v)", id, err)
}
return
}
// ListWeightConf 列出配置
func (s *Service) ListWeightConf(c context.Context, v *archive.Confs) (cfg []*archive.WCItem, err error) {
if cfg, err = s.arc.ListWeightConf(c, v); err != nil {
log.Error("s.ListWeightConf(%+v) error(%v)", v, err)
return
}
// 根据taskid补充filename和title
switch v.Radio {
case archive.WConfMid: // 补充昵称和粉丝数
s.singleIDtoName(c, cfg, func(c context.Context, cid int64) (res []interface{}, err error) {
stat, err := s.profile(c, cid)
if err != nil {
log.Error("s.profile(%d) error(%v)", cid, err)
return
}
res = []interface{}{stat.Profile.Name, stat.Follower}
return
}, false, "CID", "Creator", "Fans")
case archive.WConfTaskID: //补充title和filename
s.mulIDtoName(c, cfg, s.arc.LWConfigHelp, "CID", "FileName", "Title", "Vid")
case archive.WConfType: //补充分区名称
s.singleIDtoName(c, cfg, func(c context.Context, cid int64) (res []interface{}, err error) {
if item, ok := s.typeCache[int16(cid)]; ok {
res = []interface{}{item.Name}
}
return
}, false, "CID", "TypeName")
case archive.WConfUpFrom: //补充投稿来源
s.singleIDtoName(c, cfg, func(c context.Context, cid int64) (res []interface{}, err error) {
res = []interface{}{archive.UpFrom(int8(cid))}
return
}, false, "CID", "UpFrom")
default:
}
return
}
// ListWeightLogs 权重变更日志
func (s *Service) ListWeightLogs(c context.Context, taskid int64, page int) (cfg []*archive.TaskWeightLog, items int64, err error) {
cfg, err = s.arc.WeightLog(c, taskid)
if err != nil {
log.Info("s.ListWeightLogs(%d) error(%v)", taskid, err)
return
}
cfg, items, err = s.weightLogHelp(c, taskid, cfg, page)
return
}
// MaxWeight 当前的权重最大值, 供用户配置做参考
func (s *Service) MaxWeight(c context.Context) (max int64, err error) {
return s.arc.GetMaxWeight(c)
}
// 补充查询日志需要的信息
func (s *Service) weightLogHelp(c context.Context, taskid int64, twl []*archive.TaskWeightLog, page int) (retwl []*archive.TaskWeightLog, items int64, err error) {
var (
mid int64
ps *accApi.ProfileStatReply
name string
fans int
upspecial []int8
)
task, err := s.arc.TaskByID(c, taskid)
if task == nil {
log.Error("s.arc.TaskByID(%d) err(%v)", taskid, err)
return
}
// 1.获取用户信息
items = int64(len(twl))
if items == 0 {
return
}
mid = twl[items-1].Mid
if mid == 0 {
log.Error("weightLogHelp taskid=%d miss mid", taskid)
goto EMPTYMID
}
ps, err = s.profile(c, mid)
if err != nil || ps == nil {
log.Error("can't get Account.Card(%d) err(%v)", mid, err)
err = nil
} else {
name = ps.Profile.Name
fans = int(ps.Follower)
}
upspecial = s.getSpecial(mid)
EMPTYMID:
retwl = []*archive.TaskWeightLog{}
// 反转日志顺序
var count int
for i := len(twl) - 1 - (page-1)*20; i >= 0 && count <= 20; func() { i--; count++ }() {
twl[i].Creator = name
twl[i].UpSpecial = upspecial
twl[i].Fans = int64(fans)
twl[i].Wait = twl[i].Uptime.TimeValue().Sub(task.CTime.TimeValue()).Seconds() * 1000.0
if !task.PTime.TimeValue().IsZero() {
twl[i].Ptime = string(task.PTime)
}
if len(twl[i].CfItems) > 0 {
for _, item := range twl[i].CfItems {
var desc = item.Desc
var v = new(archive.WCItem)
if err = json.Unmarshal([]byte(item.Desc), v); err == nil { //兼容新旧日志格式
desc = v.Desc
}
err = nil
twl[i].Desc += fmt.Sprintf("%s:%s; ", archive.CfWeightDesc(item.Radio), desc)
}
}
retwl = append(retwl, twl[i])
}
return
}
func (s *Service) getSpecial(mid int64) []int8 {
upspecial := []int8{}
for k, v := range s.upperCache {
if _, ok := v[mid]; ok {
upspecial = append(upspecial, k)
}
}
return upspecial
}
func (s *Service) setWeightConf(c context.Context, ids string, mcases map[int64]*archive.WCItem) (err error) {
var mitems map[int64]*archive.TaskPriority
arrid, _ := xstr.SplitInts(ids)
// 1. 获取旧的配置
if mitems, err = s.getTWCache(c, arrid); err != nil {
log.Error("s.getTWCache(%v) error(%v)", arrid, err)
return
}
if len(mitems) == 0 {
return fmt.Errorf("没有找到任务(%v)", arrid)
}
// 2. 将新加配置加入
for _, item := range mitems {
if one, ok := mcases[item.TaskID]; ok && one != nil {
one.Mtime = utils.NewFormatTime(time.Now())
item.CfItems = append(item.CfItems, one)
}
}
// 3. 更新配置到redis和数据库
var wg errgroup.Group
wg.Go(func() (err error) {
return s.task.SetWeightRedis(c, mitems)
})
for _, item := range mitems {
var descb []byte
v := item
wg.Go(func() (err error) {
if descb, err = json.Marshal(v.CfItems); err != nil {
return
}
_, err = s.arc.UpCwAfterAdd(c, v.TaskID, string(descb))
return
})
}
err = wg.Wait()
return
}
// ShowWeightVC 展示权重配置值
func (s *Service) ShowWeightVC(c context.Context) (wvc *archive.WeightVC, err error) {
if wvc, err = s.arc.WeightVC(c); err != nil {
log.Error("s.arc.WeightVC error(%v)", err)
return
}
if wvc == nil {
wvc = archive.WLVConf
s.arc.InWeightVC(c, wvc, "默认权重配置")
}
return
}
// SetWeightVC 设置权重配置
func (s *Service) SetWeightVC(c context.Context, wvc *archive.WeightVC) (err error) {
_, err = s.arc.SetWeightVC(c, wvc, "设置权重配置")
return
}
// 处理一级分区转二级分区
func (s *Service) tarnsType(c context.Context, ids string) (res string) {
var (
mapNoNeed = make(map[int16]struct{}) // 不需要的一级分区
mapNeed = make(map[int16]struct{}) // 需要的一级分区
idres = []int64{}
)
arrid, _ := xstr.SplitInts(ids)
for _, id := range arrid {
if mod, ok := s.typeCache[int16(id)]; ok {
if mod.PID == 0 {
mapNeed[int16(id)] = struct{}{}
} else {
mapNoNeed[mod.PID] = struct{}{}
idres = append(idres, id)
}
}
}
for k := range mapNoNeed {
delete(mapNeed, k)
}
for k := range mapNeed {
idres = append(idres, s.typeCache2[k]...)
}
return xstr.JoinInts(idres)
}

View File

@@ -0,0 +1,138 @@
package service
import (
"context"
"sort"
"go-common/app/admin/main/videoup/model/archive"
"go-common/app/admin/main/videoup/model/track"
"go-common/library/log"
)
const (
historyTimeMin = 0
historyTimeMax = 0x7fffffffffffffff
)
// TrackArchive get archive list.
func (s *Service) TrackArchive(c context.Context, aid int64) (archive []*track.Archive, err error) {
if archive, err = s.track.ArchiveTrack(c, aid); err != nil {
log.Error("s.track.ArchiveTrack(%d) error(%v)", aid, err)
return
}
sort.Sort(track.Archives(archive))
return
}
//TrackArchiveInfo 稿件信息追踪
func (s *Service) TrackArchiveInfo(c context.Context, aid int64) (info *track.ArcTrackInfo, err error) {
relation := [][]int{}
editHistory, err := s.AllEditHistory(c, aid)
if err != nil {
log.Error("TrackArchiveInfo s.AllEditHistory(aid(%d)) error(%v)", aid, err)
return
}
tr, err := s.TrackArchive(c, aid)
if err != nil {
log.Error("TrackArchiveInfo s.TrackArchive(aid(%d)) error(%v)", aid, err)
return
}
//2个降序数组track根据history聚合
cpHistoryTime := []int64{historyTimeMax}
for _, h := range editHistory {
cpHistoryTime = append(cpHistoryTime, int64(h.ArcHistory.CTime))
}
cpHistoryTime = append(cpHistoryTime, historyTimeMin)
index := 0
histlen := len(cpHistoryTime) - 1
for i := 1; i <= histlen; i++ {
rela := []int{}
for ; index < len(tr); index++ {
t := int64(tr[index].Timestamp)
if t >= cpHistoryTime[i] && t < cpHistoryTime[i-1] {
rela = append(rela, index)
continue
}
break
}
if i == histlen && len(rela) == 0 {
continue
}
relation = append(relation, rela)
}
info = &track.ArcTrackInfo{
EditHistory: editHistory,
Track: tr,
Relation: relation,
}
return
}
//TrackHistoryDetail 稿件某条编辑历史的详细情况
func (s *Service) TrackHistoryDetail(c context.Context, hid int64) (h *archive.EditHistory, err error) {
if h, err = s.EditHistory(c, hid); err != nil {
log.Error("TrackHistoryDetail s.EditHistory(hid(%d)) error(%v)", hid, err)
return
}
if h == nil {
return
}
//获取最新的src_type
cids := []int64{}
for _, vh := range h.VHistory {
cids = append(cids, vh.CID)
}
srcTypes, err := s.arc.VideoSrcTypeByIDs(c, cids)
if err != nil {
log.Error("TrackHistoryDetail s.arc.VideoSrcTypeByID(hid(%d)) error(%v)", hid, err)
return
}
for _, vh := range h.VHistory {
vh.SRCType = srcTypes[vh.CID]
}
return
}
// TrackVideo get video process.
func (s *Service) TrackVideo(c context.Context, filename string, aid int64) (video []*track.Video, err error) {
if video, err = s.track.VideoTrack(c, filename, aid); err != nil {
log.Error("s.track.VideoTrack(%s) error(%v)", filename, err)
return
}
//以下努力均为获取当时视频审核的属性
vid, err := s.arc.VIDByAIDFilename(c, aid, filename)
if err != nil {
log.Error("s.arc.VIDByAIDFilename error(%v), filename(%s)", err, filename)
return
}
if vid <= 0 {
return
}
attrs, ctimes, err := s.arc.VideoOperAttrsCtimes(c, vid)
if err != nil {
log.Error("s.arc.VideoOperAttrsCtimes error(%v) vid(%d)", err, vid)
return
}
for _, tk := range video {
i := 0
for ; i < len(attrs); i++ {
if ctimes[i] > int64(tk.Timestamp) {
continue
}
tk.Attribute = attrs[i]
break
}
}
return
}

View File

@@ -0,0 +1,28 @@
package service
import (
"context"
"testing"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_trackArchive(t *testing.T) {
var (
c = context.TODO()
)
Convey("TrackArchive", t, WithService(func(s *Service) {
_, err := svr.TrackArchive(c, 1)
So(err, ShouldBeNil)
}))
}
func TestService_TrackVideo(t *testing.T) {
var (
c = context.TODO()
)
Convey("TrackVideo", t, WithService(func(s *Service) {
_, err := svr.TrackVideo(c, "11111", 111)
So(err, ShouldBeNil)
}))
}

View File

@@ -0,0 +1,332 @@
package service
import (
"context"
"fmt"
"go-common/app/admin/main/videoup/model/archive"
"go-common/library/database/sql"
"go-common/library/log"
xtime "go-common/library/time"
)
// txUpArcAttrs update archive attrs
func (s *Service) txUpArcAttrs(tx *sql.Tx, a *archive.Archive, attrs map[uint]int32, redirectURL string) (cont []string, err error) {
const template = "[%s]从[%s]设为[%s]"
var yesOrNo = map[int32]string{archive.AttrYes: "是", archive.AttrNo: "否"}
for bit, attr := range attrs {
if bit == archive.AttrBitJumpURL && (attr == archive.AttrNo || redirectURL == "") {
redirectURL = ""
attr = archive.AttrNo
}
var arcRows int64
if arcRows, err = s.arc.TxUpArcAttr(tx, a.Aid, bit, attr); err != nil {
log.Error("s.arc.TxUpArcAttr(%d,%d,%d) error(%v)", a.Aid, bit, attr, err)
return
}
if bit == archive.AttrBitJumpURL {
var additRows int64
if additRows, err = s.arc.TxUpAdditRedirect(tx, a.Aid, redirectURL); err != nil {
log.Error("s.arc.TxUpAddit(%d,%s) error(%v)", a.Aid, redirectURL, err)
return
}
if arcRows != 0 || additRows != 0 {
log.Info("aid(%d) update addit redirectURL(%s)", a.Aid, redirectURL)
var desc = redirectURL
if desc == "" {
desc = "空"
}
cont = append(cont, fmt.Sprintf("[%s]设为[%s]", "跳转地址", desc))
}
}
a.AttrSet(attr, bit)
if arcRows <= 0 {
continue
}
cont = append(cont, fmt.Sprintf(template, archive.BitDesc(bit), yesOrNo[^attr&1], yesOrNo[attr]))
log.Info("aid(%d) update archive bit(%d) bitdesc(%s) attrs(%d)", a.Aid, bit, archive.BitDesc(bit), attr)
}
return
}
// txUpArcForbidAttrs update archive forbid attrs
func (s *Service) txUpArcForbidAttrs(c context.Context, tx *sql.Tx, a *archive.Archive, forbidAttrs map[string]map[uint]int32) (conts []string, err error) {
const template = "[%s]从[%s]设为[%s]"
var (
yesOrNo = map[int32]string{archive.AttrYes: "是", archive.AttrNo: "否"}
forbid *archive.ForbidAttr
change bool
)
// forbid
if forbid, err = s.arc.Forbid(c, a.Aid); err != nil {
log.Error("s.arc.Forbid(%d) error(%v)", a.Aid, err)
return
}
for name, attrs := range forbidAttrs {
for bit, attr := range attrs {
if change = forbid.SetAttr(name, attr, bit); change {
conts = append(conts, fmt.Sprintf(template, archive.ForbidBitDesc(name, bit), yesOrNo[^attr&1], yesOrNo[attr]))
log.Info("aid(%d) update archive forbid name(%s) bit(%d) bitdesc(%s) attrs(%d)", a.Aid, name, bit, archive.ForbidBitDesc(name, bit), attr)
}
}
}
forbid.Convert()
if _, err = s.arc.TxUpForbid(tx, forbid); err != nil {
log.Error("s.arc.TxUpForbid(%+v) error(%v)", forbid, err)
}
return
}
//txAddFirstPass 添加稿件第一次过审的记录
func (s *Service) txAddFirstPass(c context.Context, tx *sql.Tx, aid int64, state int8) (firstPass bool, err error) {
if !archive.NormalState(state) || s.hadPassed(c, aid) {
return
}
if err = s.arc.AddFirstPass(tx, aid); err != nil {
log.Error("txUpArcState s.arc.AddFirstPass error(%v) aid(%d)", err, aid)
return
}
firstPass = true
return
}
//txUpArcState 更新稿件属性时,联动添加第一次过审记录
func (s *Service) txUpArcState(c context.Context, tx *sql.Tx, aid int64, state int8) (firstPass bool, err error) {
if _, err = s.arc.TxUpArcState(tx, aid, state); err != nil {
log.Error("txUpArcState s.arc.TxUpArcState error(%v) aid(%d) state(%d)", err, aid, state)
return
}
if firstPass, err = s.txAddFirstPass(c, tx, aid, state); err != nil {
log.Error("txUpArcState s.txAddFirstPass error(%v) aid(%d) state(%d)", err, aid, state)
return
}
return
}
// txUpArcMainState update archive states
func (s *Service) txUpArcMainState(c context.Context, tx *sql.Tx, aid, forward int64, typeID, access int16, state, round int8, reason string) (racs int16, err error) {
log.Info("aid(%d) get archive state(%d)", aid, state)
if ok := s.isAccess(c, aid); ok && access == archive.AccessDefault {
access = archive.AccessMember
}
if _, err = s.txUpArcState(c, tx, aid, state); err != nil {
log.Error("txUpArcMainState s.txUpArcState error(%v) aid(%d) state(%d)", err, aid, state)
return
}
log.Info("aid(%d) update archive state(%d)", aid, state)
if _, err = s.arc.TxUpArcAccess(tx, aid, access); err != nil {
log.Error("s.arc.TxUpArcAccess(%d,%d) error(%v)", aid, access, err)
return
}
racs = access
log.Info("aid(%d) update archive access(%d)", aid, access)
if typeID != 0 {
if _, err = s.arc.TxUpArcTypeID(tx, aid, typeID); err != nil {
log.Error("s.arc.TxUpArcTypeID(%d,%d) error(%v)", aid, typeID, err)
return
}
log.Info("aid(%d) update archive type_id(%d)", aid, typeID)
}
if _, err = s.arc.TxUpArcRound(tx, aid, round); err != nil {
log.Error("s.arc.TxUpArcRound(%d,%d) error(%v)", aid, round, err)
return
}
log.Info("aid(%d) update archive round(%d)", aid, round)
if _, err = s.arc.TxUpArcReason(tx, aid, forward, reason); err != nil {
log.Error("s.arc.TxUpArcReason(%d,%d,%s) error(%v)", aid, forward, reason, err)
return
}
log.Info("aid(%d) update archive reason(%s) forward_id(%d)", aid, reason, forward)
return
}
// txUpArcDelay update archive delay
func (s *Service) txUpArcDelay(c context.Context, tx *sql.Tx, aid, mid int64, state int8, isDelay bool, dTime xtime.Time) (rs int8, cont string, err error) {
rs = state
var delay *archive.Delay
if delay, _ = s.arc.Delay(c, aid, archive.DelayTypeForUser); delay == nil && dTime <= 0 {
return
}
if !isDelay || archive.NotAllowDelay(state) {
if _, err = s.arc.TxDelDelay(tx, aid, archive.DelayTypeForUser); err != nil {
log.Error("s.arc.TxDelDelay(%d) error(%v)", aid, err)
return
}
cont = archive.Operformat(archive.OperTypeDelay, dTime.Time().Format("2006-01-02 15:04:05"), "无", archive.OperStyleOne)
log.Info("aid(%d) err delay time delete archive_delay", aid)
return
}
if dTime <= 0 && delay != nil {
dTime = delay.DTime
}
if _, err = s.arc.TxUpDelay(tx, mid, aid, state, archive.DelayTypeForUser, dTime); err != nil {
log.Error("s.arc.TxUpDelay(%d%d,%d,%d,%d) error(%v)", aid, mid, state, archive.DelayTypeForUser, dTime, err)
return
}
if archive.NormalState(state) {
rs = archive.StateForbidUserDelay
}
if delay != nil && dTime != delay.DTime {
cont = archive.Operformat(archive.OperTypeDelay, delay.DTime.Time().Format("2006-01-02 15:04:05"), dTime.Time().Format("2006-01-02 15:04:05"), archive.OperStyleOne)
} else if delay == nil {
cont = archive.Operformat(archive.OperTypeDelay, "无", dTime.Time().Format("2006-01-02 15:04:05"), archive.OperStyleOne)
}
log.Info("aid(%d) second_round submit update archive_delay mid(%d) state(%d) type(%d) dtime(%v)", aid, mid, state, archive.DelayTypeForUser, dTime)
return
}
// TxUpArchiveAttr update archive attr by aid.
func (s *Service) TxUpArchiveAttr(c context.Context, tx *sql.Tx, a *archive.Archive, aid, uid int64, attrs map[uint]int32, forbidAttrs map[string]map[uint]int32, redirectURL string) (conts []string, err error) {
var cont []string
log.Info("aid(%d) begin tran change attribute", aid)
if cont, err = s.txUpArcAttrs(tx, a, attrs, redirectURL); err != nil {
log.Error("s.txUpArcAttrs(%d) error(%v)", aid, err)
return
}
conts = append(conts, cont...)
if _, err = s.txUpArcForbidAttrs(c, tx, a, forbidAttrs); err != nil {
log.Error("s.txUpArcForbidAttrs(%d) error(%v)", aid, err)
return
}
log.Info("aid(%d) end tran change attribute", aid)
return
}
// txUpVideoStatus update video status by vid and cid.
func (s *Service) txUpVideoStatus(tx *sql.Tx, vid, cid int64, status int16) (err error) {
//update archive_video
if _, err = s.arc.TxUpVideoStatus(tx, vid, status); err != nil {
log.Error("s.arc.TxUpVideoStatus vid(%d) status(%d) error(%v)", vid, status, err)
return
}
//update video
if _, err = s.arc.TxUpStatus(tx, cid, status); err != nil {
log.Error("s.arc.TxUpStatus cid(%d) status(%d) error(%v)", cid, status, err)
return
}
//update archive_video_relation to 0
if _, err = s.arc.TxUpRelationState(tx, vid, archive.VideoStatusOpen); err != nil {
log.Error("s.arc.TxUpRelationState cid(%d) status(%d) error(%v)", cid, archive.VideoStatusOpen, err)
return
}
log.Info("vid(%d) cid(%d) update video status(%d)", vid, cid, status)
return
}
// txAddVideo insert video get vid.
func (s *Service) txAddVideo(tx *sql.Tx, v *archive.Video) (vid int64, err error) {
if vid, err = s.arc.TxAddVideo(tx, v); err != nil {
log.Error("s.arc.TxAddVideo video(%+v) error(%v)", v, err)
return
}
v.ID = vid
if _, err = s.arc.TxAddRelation(tx, v); err != nil {
log.Error("s.arc.TxAddRelation video(%+v) error(%v)", v, err)
return
}
log.Info("aid(%d) update video vid(%d) cid(%d) index(%d) title(%s) desc(%s) filename(%s) srctype(%s)", v.Aid, vid, v.Cid, v.Index, v.Title, v.Desc, v.Filename, v.SrcType)
return
}
// txUpVideo update video title and desc by vid.
func (s *Service) txUpVideo(tx *sql.Tx, vid int64, title, desc string) (err error) {
if _, err = s.arc.TxUpVideo(tx, vid, title, desc); err != nil {
log.Error("s.arc.TxUpVideo vid(%d) title(%s) desc(%s) error(%v)", vid, title, desc, err)
return
}
if _, err = s.arc.TxUpRelation(tx, vid, title, desc); err != nil {
log.Error("s.arc.TxUpRelation vid(%d) title(%s) desc(%s) error(%v)", vid, title, desc, err)
return
}
log.Info("vid(%d) update video title(%s) desc(%s)", vid, title, desc)
return
}
// txUpVideoLink update video weblink by vid and cid.
func (s *Service) txUpVideoLink(tx *sql.Tx, vid, cid int64, webLink string) (err error) {
if _, err = s.arc.TxUpVideoLink(tx, vid, webLink); err != nil {
log.Error("s.arc.TxUpVideoLink(%d,%s)", vid, webLink)
return
}
if _, err = s.arc.TxUpWebLink(tx, cid, webLink); err != nil {
log.Error("s.arc.TxUpWebLink(%d,%s)", cid, webLink)
return
}
log.Info("vid(%d) cid(%d) update webLink(%s)", vid, cid, webLink)
return
}
// txDelVideo delete video by vid.
func (s *Service) txDelVideo(tx *sql.Tx, vp *archive.VideoParam) (err error) {
if _, err = s.arc.TxUpVideoStatus(tx, vp.ID, archive.VideoStatusDelete); err != nil {
log.Error("s.arc.TxUpVideoStatus(%d,%d)", vp.ID, archive.VideoStatusDelete)
return
}
if _, err = s.arc.TxUpRelationState(tx, vp.ID, archive.VideoStatusDelete); err != nil {
log.Error("s.arc.TxUpRelationState(%d,%d)", vp.ID, archive.VideoStatusDelete)
return
}
log.Info("del video cid(%d) vid(%d)", vp.Cid, vp.ID)
return
}
// txUpVideoIndex update video index by vid.
func (s *Service) txUpVideoIndex(tx *sql.Tx, vid int64, index int) (err error) {
if _, err = s.arc.TxUpVideoIndex(tx, vid, index); err != nil {
log.Error("s.arc.TxUpVideoIndex(%d,%d)", vid, index)
return
}
if _, err = s.arc.TxUpRelationOrder(tx, vid, index); err != nil {
log.Error("s.arc.TxUpRelationOrder(%d,%d)", vid, index)
return
}
log.Info("vid(%d) update index(%d)", vid, index)
return
}
func (s *Service) txUpVideoAttr(c context.Context, tx *sql.Tx, vid, cid int64, attrs map[uint]int32) (conts []string, attribute int32, err error) {
var v *archive.Video
if v, err = s.arc.NewVideoByID(c, vid); err != nil || v == nil {
log.Error("s.arc.VideoByID(%d) error(%v)", vid, err)
return
}
const template = "[%s]从[%s]设为[%s]"
var yesOrNo = map[int32]string{archive.AttrYes: "是", archive.AttrNo: "否"}
for bit, attr := range attrs {
var rows int64
if rows, err = s.arc.TxUpVideoAttr(tx, vid, bit, attr); err != nil {
log.Error("s.arc.TxUpVideoAttr id(%d) bit(%d) attr(%d) error(%v)", vid, bit, attr, err)
return
}
if _, err = s.arc.TxUpAttr(tx, cid, bit, attr); err != nil {
log.Error("s.arc.TxUpAttr cid(%d) bit(%d) attr(%d) error(%v)", cid, bit, attr, err)
return
}
v.AttrSet(attr, bit)
if rows <= 0 {
continue
}
conts = append(conts, fmt.Sprintf(template, archive.BitDesc(bit), yesOrNo[^attr&1], yesOrNo[attr]))
log.Info("vid(%d) update video bit(%d) bitdesc(%s) attrs(%d)", vid, bit, archive.BitDesc(bit), attr)
}
attribute = v.Attribute
return
}
// txUpVideoAudit update video audit by videoParam.
func (s *Service) txUpVideoAudit(tx *sql.Tx, vp *archive.VideoParam) (err error) {
if err = s.txUpVideoStatus(tx, vp.ID, vp.Cid, vp.Status); err != nil {
log.Error("s.arc.TxUpVideoStatus id(%d) cid(%d) status(%d) error(%v)", vp.ID, vp.Cid, vp.Status, err)
return
}
log.Info("aid(%d) vid(%d) update video status(%d)", vp.Aid, vp.ID, vp.Status)
if _, err = s.arc.TxAddAudit(tx, vp.Aid, vp.ID, vp.TagID, vp.Oname, vp.Note, vp.Reason); err != nil {
log.Error("s.arc.TxAddAudit(%d,%d,%d,%s,%s,%s)", vp.Aid, vp.ID, vp.TagID, vp.Oname, vp.Note, vp.Reason)
return
}
log.Info("aid(%d) vid(%d) audit log tag(%d) oname(%s) note(%s) reason(%s)", vp.Aid, vp.ID, vp.TagID, vp.Oname, vp.Note, vp.Reason)
return
}

View File

@@ -0,0 +1,37 @@
package service
// InSliceIface checks given interface in interface slice.
func InSliceIface(v interface{}, sl []interface{}) bool {
for _, vv := range sl {
if vv == v {
return true
}
}
return false
}
// SliceUnique cleans repeated values in slice.
func SliceUnique(slice []interface{}) (uniqueslice []interface{}) {
for _, v := range slice {
if !InSliceIface(v, uniqueslice) {
uniqueslice = append(uniqueslice, v)
}
}
return
}
// Slice2String convert slice to string
func Slice2String(slice []interface{}) (uniqueslice []string) {
for _, v := range slice {
uniqueslice = append(uniqueslice, v.(string))
}
return
}
// Slice2Interface convert slice to interface
func Slice2Interface(slice []string) (uniqueslice []interface{}) {
for _, v := range slice {
uniqueslice = append(uniqueslice, v)
}
return
}

View File

@@ -0,0 +1,14 @@
package service
import (
"strings"
"testing"
)
func TestSliceUnique(t *testing.T) {
var slice1 = []string{"绘画", "哈哈", "22", "2223", "绘画"}
t.Logf("unique : %v", SliceUnique(Slice2Interface(slice1)))
tag := "绘画, 哈哈, 22, 2223, 绘画"
t.Logf("unique : %v", strings.Join(Slice2String(SliceUnique(Slice2Interface(strings.Split(tag, ",")))), ","))
}

View File

@@ -0,0 +1,332 @@
package service
import (
"context"
"runtime"
"strings"
"time"
"fmt"
"go-common/app/admin/main/videoup/model/archive"
"go-common/library/database/sql"
"go-common/library/ecode"
"go-common/library/log"
xtime "go-common/library/time"
)
// VideoAudit upload first_round info.
func (s *Service) VideoAudit(c context.Context, vp *archive.VideoParam, attrs map[uint]int32) (err error) {
var (
tx *sql.Tx
qaVideo *archive.QAVideo
qaErr error
)
defer func() {
if r := recover(); r != nil {
if tx != nil {
tx.Rollback()
}
var buf [4096]byte
n := runtime.Stack(buf[:], false)
log.Error("wocao jingran recover le error(%v) panic stack(%s)", r, string(buf[:n]))
}
}()
//只有一审任务会去新增质检任务
if vp.TaskID > 0 {
qaVideo, qaErr = s.fetchQAVideo(c, vp)
if qaErr != nil {
log.Error("VideoAudit s.fetchQAVideo error(%v) aid(%d) cid(%d)", qaErr, vp.Aid, vp.Cid)
}
}
if tx, err = s.arc.BeginTran(c); err != nil {
log.Error("s.arc.BeginTran() error(%v)", err)
return
}
if err = s.txUpVideo(tx, vp.ID, vp.Title, vp.Desc); err != nil {
tx.Rollback()
log.Error("s.txUpVideo(%d,%s,%s) error(%v)", vp.ID, vp.Title, vp.Desc, err)
return
}
log.Info("aid(%d) update video vid(%d) Title(%s) Desc(%s) status(%d) ", vp.Aid, vp.ID, vp.Title, vp.Desc, vp.Status)
var (
operConts []string
attr int32
attrChanged bool
)
if operConts, attr, err = s.txUpVideoAttr(c, tx, vp.ID, vp.Cid, attrs); err != nil {
tx.Rollback()
return
}
if len(operConts) > 0 {
attrChanged = true
}
if err = s.txUpVideoAudit(tx, vp); err != nil {
tx.Rollback()
log.Error("s.txUpVideoAudit(vp(%+v)) error(%v)", vp, err)
return
}
if err = tx.Commit(); err != nil {
log.Error("tx.Commit() error(%v)", err)
return
}
oper := &archive.VideoOper{AID: vp.Aid, UID: vp.UID, VID: vp.ID, Attribute: attr, Status: vp.Status, Remark: vp.Note}
operConts = append(operConts, s.diffVideoOper(vp)...)
oper.Content = strings.Join(operConts, "")
s.addVideoOper(c, oper)
// databus
s.busFirstRoundByPlayurl(c, vp, attrChanged)
go s.busSecondRoundUpCredit(vp.Aid, vp.Cid, vp.Mid, vp.UID, int8(vp.Status), 0, vp.ReasonID, vp.Reason)
// log set attr
vp.Attribute = attr
s.sendVideoLog(c, vp, oper.Content)
if qaVideo != nil && qaErr == nil {
qaVideo.Attribute = attr
s.addQAVideo(c, qaVideo)
}
return
}
func (s *Service) busFirstRoundByPlayurl(c context.Context, vp *archive.VideoParam, attrChanged bool) (err error) {
arc, err := s.arc.Archive(c, vp.Aid)
if err != nil {
log.Error("s.arc.Archive() (%d) error(%v)", vp.Aid, err)
return
}
playurl := vp.Playurl
if len(playurl) == 0 {
playurl, err = s.arc.VideoPlayurl(c, vp.Cid)
if err != nil {
log.Error("s.busfirstroundbyplayurl get playurl by vid(%d) error(%v)", vp.ID, err)
return
}
if len(playurl) == 0 {
err = fmt.Errorf("video(%d) not exist", vp.ID)
log.Error("s.busfirstroundbyplayurl get playurl by vid(%d) error(%v)", vp.ID, err)
return
}
}
log.Info("begin to bus first round by playurl(%s) vp(%v) err(%v)", playurl, vp, err)
//adminChange=true发送报备邮件
adminChange := false
if vp.Status == archive.VideoStatusRecycle || vp.Status == archive.VideoStatusLock || attrChanged {
adminChange = true
}
//get fans
fans := int64(0)
if pfl, _ := s.profile(c, arc.Mid); pfl != nil {
fans = pfl.Follower
}
if strings.Contains(playurl, "/ugc/") {
err = s.busUGCFirstRound(vp.Aid, vp.Filename, vp.EncodePurpose, vp.VideoDesign, vp.Status, vp.Encoding, vp.RegionID, arc.TypeID, fans, adminChange)
} else {
err = s.busFirstRound(vp.Aid, vp.Filename, vp.EncodePurpose, vp.VideoDesign, vp.Status, vp.Encoding, vp.RegionID, arc.TypeID, fans, adminChange)
}
return
}
// BatchVideo batch async video audit.
func (s *Service) BatchVideo(c context.Context, vps []*archive.VideoParam, action string) (err error) {
var mp = &archive.MultSyncParam{}
var ok bool
for _, vp := range vps {
mp.Action = action
mp.VideoParam = vp
if ok, err = s.busCache.PushMultSync(c, mp); err != nil {
log.Error("s.busCache.PushMultSync(vp(%+v)) error(%v)", vp, err)
return
}
if !ok {
log.Warn("s.busCache.PushMultSync(vp(%+v))", vp)
continue
}
}
return
}
func (s *Service) dealVideo(c context.Context, vp *archive.VideoParam) (err error) {
var tx *sql.Tx
var attrChanged bool
if tx, err = s.arc.BeginTran(c); err != nil {
log.Error("s.arc.BeginTran() error(%v)", err)
return
}
defer func() {
if r := recover(); r != nil {
tx.Rollback()
log.Error("wocao jingran recover le error(%v)", r)
}
}()
if err = s.txUpVideoAudit(tx, vp); err != nil {
tx.Rollback()
log.Error("s.txUpVideoAudit(vp(%+v)) error(%v)", vp, err)
return
}
//todo 批量支持家长模式 级联通过类tag逻辑
if err = tx.Commit(); err != nil {
log.Error("tx.Commit() error(%v)", err)
return
}
oper := &archive.VideoOper{AID: vp.Aid, UID: vp.UID, VID: vp.ID, Attribute: vp.Attribute, Status: vp.Status, Remark: vp.Note}
operConts := s.diffVideoOper(vp)
oper.Content = strings.Join(operConts, "")
s.addVideoOper(c, oper)
s.busFirstRoundByPlayurl(c, vp, attrChanged)
s.sendVideoLog(c, vp, oper.Content)
return
}
// UpVideo update archive_video title && desc
func (s *Service) UpVideo(c context.Context, vp *archive.VideoParam) (err error) {
var tx *sql.Tx
if tx, err = s.arc.BeginTran(c); err != nil {
log.Error("s.arc.BeginTran() error(%v)", err)
return
}
defer func() {
if r := recover(); r != nil {
tx.Rollback()
log.Error("wocao jingran recover le error(%v)", r)
}
}()
if vp.ID != 0 {
if err = s.txUpVideo(tx, vp.ID, vp.Title, vp.Desc); err != nil {
tx.Rollback()
log.Error("s.txUpVideo(%d,%s,%s) error(%v)", vp.ID, vp.Title, vp.Desc, err)
return
}
vp.Note = "审核人员修改分P标题和简介!"
} else {
var (
v *archive.Video
ctime = xtime.Time(time.Now().Unix())
)
v = &archive.Video{Aid: vp.Aid, Title: vp.Title, Desc: vp.Desc, Filename: vp.Filename, SrcType: vp.SrcType, Cid: vp.Cid,
Duration: vp.Duration, Filesize: vp.Filesize, Resolutions: vp.Resolutions, Index: vp.Index, Status: vp.Status, Playurl: vp.Playurl,
Attribute: vp.Attribute, FailCode: vp.FailCode, XcodeState: vp.XcodeState, WebLink: vp.WebLink, CTime: ctime, MTime: ctime}
if vp.ID, err = s.txAddVideo(tx, v); err != nil {
tx.Rollback()
log.Error("s.arc.txAddVideo(%+v) error(%v)", v, err)
return
}
vp.Note = "审核人员添加分P!"
}
if _, err = s.arc.TxAddAudit(tx, vp.Aid, vp.ID, vp.TagID, vp.Oname, vp.Note, vp.Reason); err != nil {
tx.Rollback()
log.Error("s.arc.TxAddAudit(%d,%d,%d,%s,%s,%s)", vp.Aid, vp.ID, vp.TagID, vp.Oname, vp.Note, vp.Reason)
return
}
if err = tx.Commit(); err != nil {
log.Error("tx.Commit() error(%v)", err)
return
}
s.busSecondRound(vp.Aid, 0, false, false, false, false, false, false, "", nil)
s.sendVideoLog(c, vp, vp.Note)
return
}
// UpWebLink update archive_video weblink
func (s *Service) UpWebLink(c context.Context, vp *archive.VideoParam) (err error) {
var tx *sql.Tx
if tx, err = s.arc.BeginTran(c); err != nil {
log.Error("s.arc.BeginTran() error(%v)", err)
return
}
defer func() {
if r := recover(); r != nil {
tx.Rollback()
log.Error("wocao jingran recover le error(%v)", r)
}
}()
if err = s.txUpVideoLink(tx, vp.ID, vp.Cid, vp.WebLink); err != nil {
tx.Rollback()
log.Error("s.txUpVideoLink(%d,%d,%s)", vp.ID, vp.Cid, vp.WebLink)
return
}
if err = tx.Commit(); err != nil {
log.Error("tx.Commit() error(%v)", err)
return
}
s.busSecondRound(vp.Aid, 0, false, false, false, false, false, false, "", nil)
s.sendVideoLog(c, vp, "更新weblink")
return
}
// DelVideo delete archive_video.
func (s *Service) DelVideo(c context.Context, vp *archive.VideoParam) (err error) {
var vs []*archive.Video
if vs, _ = s.arc.NewVideosByAid(c, vp.Aid); len(vs) <= 0 {
err = ecode.ArchiveNotExist
return
}
var tx *sql.Tx
if tx, err = s.arc.BeginTran(c); err != nil {
log.Error("s.arc.BeginTran() error(%v)", err)
return
}
defer func() {
if r := recover(); r != nil {
tx.Rollback()
log.Error("wocao jingran recover le error(%v)", r)
}
}()
if err = s.txDelVideo(tx, vp); err != nil {
tx.Rollback()
log.Error("s.txDelVideo(%d)", vp.ID)
return
}
indexOrder := 1
for _, v := range vs {
if v.ID == vp.ID {
continue
}
if err = s.txUpVideoIndex(tx, v.ID, indexOrder); err != nil {
tx.Rollback()
log.Error("s.txUpVideoIndex(%d,%d)", v.ID, indexOrder)
return
}
indexOrder++
}
if err = tx.Commit(); err != nil {
log.Error("tx.Commit() error(%v)", err)
return
}
s.busSecondRound(vp.Aid, 0, false, false, false, false, false, false, "", nil)
s.sendVideoLog(c, vp, "删除视频")
return
}
// ChangeIndex change archive_video index.
func (s *Service) ChangeIndex(c context.Context, lo *archive.IndexParam) (err error) {
if vs, _ := s.arc.NewVideosByAid(c, lo.Aid); len(vs) <= 0 {
err = ecode.ArchiveNotExist
return
}
var tx *sql.Tx
if tx, err = s.arc.BeginTran(c); err != nil {
log.Error("s.arc.BeginTran() error(%v)", err)
return
}
defer func() {
if r := recover(); r != nil {
tx.Rollback()
log.Error("wocao jingran recover le error(%v)", r)
}
}()
for _, v := range lo.ListOrder {
if err = s.txUpVideoIndex(tx, v.ID, v.Index); err != nil {
tx.Rollback()
log.Error("s.arc.TxUpVideoIndex(%d,%d)", v.ID, v.Index)
return
}
}
if err = tx.Commit(); err != nil {
log.Error("tx.Commit() error(%v)", err)
return
}
s.busSecondRound(lo.Aid, 0, false, false, false, false, false, false, "", nil)
return
}

View File

@@ -0,0 +1,75 @@
package service
import (
"context"
"testing"
"go-common/app/admin/main/videoup/model/archive"
. "github.com/smartystreets/goconvey/convey"
)
func TestService_VideoAudit(t *testing.T) {
var (
c = context.TODO()
vp = &archive.VideoParam{}
)
attrs := make(map[uint]int32, 5)
attrs[archive.AttrBitNoRank] = 1
attrs[archive.AttrBitNoDynamic] = 1
attrs[archive.AttrBitNoSearch] = 1
attrs[archive.AttrBitNoRecommend] = 1
attrs[archive.AttrBitOverseaLock] = 1
Convey("VideoAudit", t, WithService(func(s *Service) {
err := svr.VideoAudit(c, vp, attrs)
So(err, ShouldBeNil)
}))
}
func TestService_UpVideo(t *testing.T) {
var (
c = context.TODO()
vp = &archive.VideoParam{}
)
Convey("UpVideo", t, WithService(func(s *Service) {
err := svr.UpVideo(c, vp)
So(err, ShouldNotBeNil)
}))
}
func TestService_UpWebLink(t *testing.T) {
var (
c = context.TODO()
vp = &archive.VideoParam{}
)
Convey("UpWebLink", t, WithService(func(s *Service) {
err := svr.UpWebLink(c, vp)
So(err, ShouldBeNil)
}))
}
func TestService_DelVideo(t *testing.T) {
var (
c = context.TODO()
vp = &archive.VideoParam{}
)
Convey("DelVideo", t, WithService(func(s *Service) {
err := svr.DelVideo(c, vp)
So(err, ShouldNotBeNil)
}))
}
func TestService_ChangeIndex(t *testing.T) {
var (
c = context.TODO()
vp = &archive.IndexParam{}
)
Convey("ChangeIndex", t, WithService(func(s *Service) {
err := svr.ChangeIndex(c, vp)
So(err, ShouldNotBeNil)
}))
}