123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442 |
- package service
- import (
- "context"
- "fmt"
- "time"
- model "go-common/app/interface/main/reply/model/reply"
- artmdl "go-common/app/interface/openplatform/article/model"
- "go-common/app/service/main/archive/api"
- arcmdl "go-common/app/service/main/archive/model/archive"
- figmdl "go-common/app/service/main/figure/model"
- "go-common/library/ecode"
- "go-common/library/log"
- "go-common/library/net/metadata"
- "go-common/library/queue/databus/report"
- xtime "go-common/library/time"
- )
- const (
- _reportNormalCnt = 5
- _reportAddSecs = 5
- _reportMaxSecs = 180
- )
- // AddReport report a reply.
- func (s *Service) AddReport(c context.Context, mid, oid, rpID int64, tp, reason int8, cont, platform string, build int64, buvid string) (cd int, err error) {
- var (
- r *model.Reply
- now = time.Now()
- ip = metadata.String(c, metadata.RemoteIP)
- )
- // check subject
- if !model.LegalSubjectType(tp) {
- err = ecode.ReplyIllegalSubType
- return
- }
- if err = model.CheckReportReason(reason); err != nil {
- return
- }
- cnt, err := s.dao.Redis.GetUserReportCnt(c, mid, now)
- if err != nil {
- log.Error("AddReport failed, replyCacheDao.GetUserReportCnt(%d), err is (%v)", mid, err)
- return
- }
- if cnt > _reportNormalCnt {
- var ttl int
- // When report count max 5 at one day, extra add 5s to user TTL at a time, and the max user TTL is 180s.
- // The last report time, we set Redis key TTL for one day seconds, use one day seconds sub current TTL value is user TTL.
- if ttl, err = s.dao.Redis.GetUserReportTTL(c, mid, now); err != nil {
- log.Error("AddReport failed, replyCacheDao.GetUserReportTTL(%d), err is (%v)", mid, err)
- return
- }
- if ttl >= 0 {
- uttl := s.oneDaySec - ttl
- maxttl := (cnt - _reportNormalCnt) * _reportAddSecs
- if maxttl > _reportMaxSecs {
- maxttl = _reportMaxSecs
- }
- if uttl < maxttl {
- cd = maxttl - uttl
- err = ecode.ReplyReportDeniedAsCD
- return
- }
- }
- }
- if r, err = s.Reply(c, oid, tp, rpID); err != nil || r == nil || r.Content == nil || r.IsDeleted() {
- return
- }
- // upper report reply of self in upper's arc ,treat it as del
- if s.isUpper(c, mid, oid, tp) && r.Mid == mid {
- s.dao.Databus.Delete(c, mid, oid, rpID, now.Unix(), tp, false)
- report.User(&report.UserInfo{
- Mid: mid,
- Platform: platform,
- Build: build,
- Buvid: buvid,
- Business: 41,
- Type: int(r.Type),
- Oid: r.Oid,
- Action: model.ReportReplyDel,
- Ctime: time.Now(),
- IP: ip,
- Index: []interface{}{
- r.RpID,
- r.State,
- model.ReplyStateUpDel,
- },
- })
- return
- }
- // 信用评分获取,用于优先举报排序处理
- var score int
- arg := &figmdl.ArgUserFigure{Mid: mid}
- fig, err := s.figure.UserFigure(c, arg)
- if err != nil {
- log.Error("s.figure.UserFigure(mid:%d) error(%v)", mid, err)
- err = nil
- } else {
- score = 100 - int(fig.Percentage)
- }
- ctime := xtime.Time(now.Unix())
- rpt := &model.Report{
- RpID: rpID,
- Oid: oid,
- Type: tp,
- Mid: mid,
- Reason: reason,
- Count: 1,
- Content: cont,
- Score: score,
- State: model.GetReportType(reason),
- CTime: ctime,
- MTime: ctime,
- }
- rptUser := &model.ReportUser{
- Oid: oid,
- Type: tp,
- RpID: rpID,
- Mid: mid,
- Reason: reason,
- Content: cont,
- State: model.ReportUserStateNew,
- CTime: ctime,
- MTime: ctime,
- }
- if rpt.ID, err = s.dao.Report.InsertUser(c, rptUser); err != nil {
- return
- }
- if rpt.ID == 0 {
- err = ecode.ReplyReported
- return
- }
- if tp != model.SubTypeActArc && tp != model.SubTypePlaylist && tp != model.SubTypeComicSeason && tp != model.SubTypeComicEpisode {
- var (
- m = make(map[int64]string)
- title, link string
- typeid int32
- )
- m[rpID] = ""
- message := r.Content.Message
- s.dao.FilterContents(c, m)
- if m[rpID] != "" {
- message = m[rpID]
- }
- title, link, typeid, _ = s.TitleLink(c, oid, tp)
- if link != "" {
- link = fmt.Sprintf("%s#reply%d", link, rpID)
- }
- err = s.workflow.AddReport(c, oid, tp, typeid, rpID, score, reason, mid, r.Mid, r.Like, message, link, title)
- if err != nil {
- return
- }
- }
- if rpt.ID, err = s.dao.Report.Insert(c, rpt); err != nil {
- return
- }
- // set report count and set user report dao.Redis key TTL for one day seconds.
- if err = s.dao.Redis.SetUserReportCnt(c, mid, cnt+1, now); err != nil {
- log.Error("s.redis.SetUserReportCnt(%v) error(%v) or row==0", rpt, err)
- return
- }
- s.dao.Databus.AddReport(c, oid, rpID, tp)
- report.User(&report.UserInfo{
- Mid: rptUser.Mid,
- Platform: platform,
- Build: build,
- Buvid: buvid,
- Business: 41,
- Type: int(tp),
- Oid: oid,
- Action: model.ReportReplyReport,
- Ctime: now,
- IP: ip,
- Index: []interface{}{
- r.Mid,
- r.RpID,
- r.State,
- fmt.Sprint(reason),
- },
- Content: map[string]interface{}{
- "count": cnt,
- "score": score,
- "content": cont,
- },
- })
- log.Info("AddReport(%d) oid:%d mid:%d score:%d percentage:%v", rpt.ID, oid, mid, score, fig)
- return
- }
- // ReportRelated get related replies of report.
- func (s *Service) ReportRelated(c context.Context, mid, oid, rpid int64, tp int8, escape bool) (sub *model.Subject, root *model.Reply, related []*model.Reply, err error) {
- if !model.LegalSubjectType(tp) {
- err = ecode.ReplyIllegalSubType
- return
- }
- // root reply
- sub, root, snds, err := s.ReportReply(c, mid, oid, rpid, tp, 1, s.sndDefCnt, escape)
- if err != nil {
- return
- }
- root.Replies = snds
- // related reply
- start := root.Floor - 6
- end := root.Floor + 6
- relIDs, err := s.dao.Reply.GetIDsByFloorOffset(c, oid, tp, start, end)
- if err != nil {
- return
- }
- relMap, err := s.repliesMap(c, oid, tp, relIDs)
- if err != nil {
- return
- }
- related = make([]*model.Reply, 0, len(relMap))
- bs := make([]*model.Reply, 0, len(relMap))
- for _, rpID := range relIDs {
- rp, ok := relMap[rpID]
- if ok && rp.RpID != root.RpID {
- if rp.Replies, err = s.reportReplies(c, rp, 1, s.sndDefCnt); err != nil {
- return
- }
- related = append(related, rp)
- // to build replies
- bs = append(bs, rp)
- bs = append(bs, rp.Replies...)
- }
- }
- if err = s.buildReply(c, sub, bs, mid, escape); err != nil {
- return
- }
- return
- }
- // ReportReply get report reply.
- func (s *Service) ReportReply(c context.Context, mid, oid, rpid int64, tp int8, pn, ps int, escape bool) (sub *model.Subject, root *model.Reply, seconds []*model.Reply, err error) {
- if !model.LegalSubjectType(tp) {
- err = ecode.ReplyIllegalSubType
- return
- }
- if sub, err = s.subject(c, oid, tp); err != nil {
- return
- }
- if root, err = s.ReplyContent(c, oid, rpid, tp); err != nil {
- return
- }
- if root.Root != 0 {
- if root, err = s.ReplyContent(c, root.Oid, root.Root, root.Type); err != nil {
- return
- }
- }
- if seconds, err = s.reportReplies(c, root, pn, ps); err != nil {
- return
- }
- bs := make([]*model.Reply, 0, len(seconds)+1)
- bs = append(bs, root)
- bs = append(bs, seconds...)
- if err = s.buildReply(c, sub, bs, mid, escape); err != nil {
- return
- }
- return
- }
- func (s *Service) reportReplies(c context.Context, rp *model.Reply, pn, ps int) (rs []*model.Reply, err error) {
- var (
- start = (pn - 1) * ps
- )
- rs = _emptyReplies
- if start >= rp.Count {
- return
- }
- sndIDs, err := s.dao.Reply.GetIDsByRootWithoutState(c, rp.Oid, rp.RpID, rp.Type, start, ps)
- if err != nil {
- return
- }
- sndMap, err := s.repliesMap(c, rp.Oid, rp.Type, sndIDs)
- if err != nil {
- return
- }
- rs = make([]*model.Reply, 0, len(sndMap))
- for _, rpID := range sndIDs {
- rp, ok := sndMap[rpID]
- if ok {
- rs = append(rs, rp)
- }
- }
- return
- }
- func (s *Service) linkByOids(c context.Context, oids map[int64]string, typ int8) (err error) {
- if len(oids) == 0 {
- return
- }
- if typ == model.SubTypeActivity {
- err = s.workflow.TopicsLink(c, oids, false)
- } else {
- for oid := range oids {
- var link string
- switch typ {
- case model.SubTypeTopic:
- link = fmt.Sprintf("https://www.bilibili.com/topic/%d.html", oid)
- case model.SubTypeArchive:
- link = fmt.Sprintf("https://www.bilibili.com/video/av%d", oid)
- case model.SubTypeForbiden:
- link = fmt.Sprintf("https://www.bilibili.com/blackroom/ban/%d", oid)
- case model.SubTypeNotice:
- link = fmt.Sprintf("https://www.bilibili.com/blackroom/notice/%d", oid)
- case model.SubTypeActArc:
- _, link, err = s.workflow.ActivitySub(c, oid)
- if err != nil {
- return
- }
- case model.SubTypeArticle:
- link = fmt.Sprintf("https://www.bilibili.com/read/cv%d", oid)
- case model.SubTypeMusic:
- link = fmt.Sprintf("https://www.bilibili.com/audio/au%d", oid)
- case model.SubTypeMusicList:
- link = fmt.Sprintf("https://www.bilibili.com/audio/am%d", oid)
- case model.SubTypeLive:
- link = fmt.Sprintf("https://vc.bilibili.com/video/%d", oid)
- case model.SubTypeLiveAct:
- _, link, err = s.workflow.LiveActivityTitle(c, oid)
- if err != nil {
- return
- }
- case model.SubTypeLivePicture:
- link = fmt.Sprintf("https://h.bilibili.com/ywh/%d", oid)
- case model.SubTypeCredit:
- link = fmt.Sprintf("https://www.bilibili.com/judgement/case/%d", oid)
- case model.SubTypeDynamic:
- link = fmt.Sprintf("https://t.bilibili.com/%d", oid)
- case model.SubTypeLiveNotice:
- link = fmt.Sprintf("http://link.bilibili.com/p/eden/news#/newsdetail?id=%d", oid)
- default:
- return
- }
- oids[oid] = link
- }
- }
- return
- }
- // TitleLink TitleLink
- func (s *Service) TitleLink(c context.Context, oid int64, typ int8) (title, link string, typeId int32, err error) {
- switch typ {
- case model.SubTypeArchive:
- arg := &arcmdl.ArgAid2{
- Aid: oid,
- }
- var m *api.Arc
- m, err = s.arcSrv.Archive3(c, arg)
- if err != nil || m == nil {
- log.Error("s.arcSrv.Archive3(%v) ret:%v error(%v)", arg, m, err)
- return
- }
- link = fmt.Sprintf("http://www.bilibili.com/video/av%d/", oid)
- title = m.Title
- typeId = m.TypeID
- case model.SubTypeTopic:
- if title, link, err = s.workflow.TopicTitle(c, oid); err != nil {
- log.Error("s.noticeDao.Topic(%d) error(%v)", oid, err)
- return
- }
- case model.SubTypeMusic:
- link = fmt.Sprintf("https://www.bilibili.com/audio/au%d", oid)
- case model.SubTypeMusicList:
- link = fmt.Sprintf("https://www.bilibili.com/audio/am%d", oid)
- case model.SubTypeActivity:
- if title, link, err = s.workflow.TopicTitle(c, oid); err != nil {
- log.Error("s.noticeDao.Activity(%d) error(%v)", oid, err)
- return
- }
- case model.SubTypeForbiden:
- title, link, err = s.workflow.BanTitle(c, oid)
- if err != nil {
- return
- }
- case model.SubTypeNotice:
- title, link, err = s.workflow.NoticeTitle(c, oid)
- if err != nil {
- return
- }
- case model.SubTypeActArc:
- if title, link, err = s.workflow.TopicTitle(c, oid); err != nil {
- log.Error("s.noticeDao.ActivitySub(%d) error(%v)", oid, err)
- return
- }
- case model.SubTypeArticle:
- arg := &artmdl.ArgAids{
- Aids: []int64{oid},
- }
- var m map[int64]*artmdl.Meta
- m, err = s.articleSrv.ArticleMetas(c, arg)
- if err != nil || m == nil {
- log.Error("s.articleSrv.ArticleMetas(%v) ret:%v error(%v)", arg, m, err)
- return
- }
- if meta, ok := m[oid]; ok {
- title = meta.Title
- link = fmt.Sprintf("http://www.bilibili.com/read/cv%d", oid)
- }
- case model.SubTypeLive:
- if title, link, err = s.workflow.LiveVideoTitle(c, oid); err != nil {
- log.Error("s.noticeDao.LiveSmallVideo(%d) error(%v)", oid, err)
- return
- }
- case model.SubTypeLiveAct:
- if title, link, err = s.workflow.LiveActivityTitle(c, oid); err != nil {
- log.Error("s.noticeDao.LiveActivity(%d) error(%v)", oid, err)
- return
- }
- case model.SubTypeLiveNotice:
- if title, err = s.workflow.LiveNotice(c, oid); err != nil {
- log.Error("s.noticeDao.LiveNotice(%d) error(%v)", oid, err)
- return
- }
- link = fmt.Sprintf("http://link.bilibili.com/p/eden/news#/newsdetail?id=%d", oid)
- return
- case model.SubTypeLivePicture:
- if title, link, err = s.workflow.LivePictureTitle(c, oid); err != nil {
- log.Error("s.noticeDao.LivePiture(%d) error(%v)", oid, err)
- return
- }
- case model.SubTypeCredit:
- if title, link, err = s.workflow.CreditTitle(c, oid); err != nil {
- log.Error("s.noticeDao.Credit(%d) error(%v)", oid, err)
- return
- }
- case model.SubTypeDynamic:
- if title, link, err = s.workflow.DynamicTitle(c, oid); err != nil {
- log.Error("s.noticeDao.Dynamic(%d) error(%v)", oid, err)
- return
- }
- case model.SubTypeHuoniao:
- if title, link, err = s.workflow.HuoniaoTitle(c, oid); err != nil {
- log.Error("s.workflow.HuoniaoTitle(%d) error(%v)", oid, err)
- return
- }
- default:
- return
- }
- return
- }
|