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