report.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  1. package service
  2. import (
  3. "context"
  4. "fmt"
  5. "time"
  6. "go-common/app/interface/main/dm/model"
  7. "go-common/app/interface/main/dm2/model/oplog"
  8. arcMdl "go-common/app/service/main/archive/model/archive"
  9. "go-common/library/ecode"
  10. "go-common/library/log"
  11. )
  12. const (
  13. _reportLock = 1800
  14. _reportLimit = 10
  15. _rptAutoDelCnt = 3
  16. )
  17. // AddReport add dm report.
  18. func (s *Service) AddReport(c context.Context, cid, dmid, uid int64, reason int8, content string) (id int64, err error) {
  19. var (
  20. needDelete, needHide bool
  21. state int8
  22. score int32
  23. )
  24. t, err := s.dao.RptBrigTime(c, uid)
  25. if err != nil {
  26. return
  27. }
  28. if time.Now().Unix()-t < _reportLock {
  29. err = ecode.DMReportLimit
  30. return
  31. }
  32. cnt, err := s.dao.RptCnt(c, uid)
  33. if err != nil {
  34. return
  35. }
  36. if cnt >= _reportLimit {
  37. if err = s.dao.AddRptBrig(c, uid); err != nil {
  38. log.Error("s.dao.AddRptBrig(%d) error(%v)", uid, err)
  39. }
  40. err = ecode.DMReportLimit
  41. return
  42. }
  43. dms, err := s.dms(c, model.SubTypeVideo, cid, []int64{dmid})
  44. if err != nil {
  45. return
  46. }
  47. if len(dms) == 0 || !dms[0].NeedDisplay() {
  48. err = ecode.DMReportNotExist
  49. return
  50. }
  51. if _, err = s.dao.UptRptCnt(c, uid); err != nil {
  52. log.Error("s.dao.UptRptCnt(%d) error(%v)", uid, err)
  53. err = nil
  54. }
  55. rpt, err := s.dao.Report(c, cid, dmid)
  56. if err != nil {
  57. log.Error("s.dao.Report(cid:%d,dmid:%d) error(%v)", cid, dmid, err)
  58. return
  59. }
  60. // score
  61. if score, err = s.dao.FigureInfo(c, uid); err != nil {
  62. log.Error("s.dao.FigureInfo(uid: %d) error(%v)", uid, err)
  63. return
  64. }
  65. if score < 0 || score > 100 {
  66. log.Error("s.AddReport.score illegal(uid: %d) score(%v)", uid, score)
  67. score = 0
  68. } else {
  69. score = 100 - score
  70. }
  71. if rpt != nil {
  72. state, err = s.checkReasonType(c, reason, cid, dmid, rpt)
  73. if err != nil {
  74. log.Error("s.checkReasonType(reason: %d) error(%v)", reason, err)
  75. return
  76. }
  77. /*
  78. 以下弹幕不能自动删除与隐藏
  79. 1. mode7、mode8、mode9弹幕
  80. 2. 字幕弹幕
  81. 3. 保护弹幕
  82. 4. up主在自己的视频下发送的弹幕
  83. */
  84. if state == model.StatSecondInit &&
  85. dms[0].Content.Mode != 7 &&
  86. dms[0].Content.Mode != 8 &&
  87. dms[0].Content.Mode != 9 &&
  88. dms[0].AttrVal(model.AttrProtect) != model.AttrYes &&
  89. dms[0].Pool == 0 &&
  90. !s.isUpper(c, cid, dms[0].Mid) {
  91. if (reason == model.ReportReasonAd && rpt.Reason == model.ReportReasonAd) || rpt.Count >= _rptAutoDelCnt-1 || rpt.Score+score >= 160 {
  92. needDelete = true
  93. } else {
  94. needHide = true
  95. }
  96. }
  97. } else {
  98. state = s.reasonType(reason)
  99. if state == model.StatSecondInit &&
  100. dms[0].Content.Mode != 7 &&
  101. dms[0].Content.Mode != 8 &&
  102. dms[0].Content.Mode != 9 &&
  103. dms[0].AttrVal(model.AttrProtect) != model.AttrYes &&
  104. dms[0].Pool == 0 &&
  105. !s.isUpper(c, cid, dms[0].Mid) {
  106. needHide = true
  107. }
  108. }
  109. nowTime := time.Now()
  110. r := &model.Report{
  111. Cid: cid,
  112. Did: dmid,
  113. UID: uid,
  114. Reason: reason,
  115. Content: content,
  116. Count: 1,
  117. State: state,
  118. UpOP: model.StatUpperInit,
  119. Score: score,
  120. RpTime: nowTime,
  121. Ctime: nowTime,
  122. Mtime: nowTime,
  123. }
  124. u := &model.User{
  125. Did: dmid,
  126. UID: uid,
  127. State: model.NoticeUnsend,
  128. Reason: reason,
  129. Content: content,
  130. Ctime: nowTime,
  131. Mtime: nowTime,
  132. }
  133. lastID, err := s.dao.AddReportUser(c, u)
  134. if err != nil {
  135. log.Error("s.dao.AddReportUser(%v) error(%v)", u, err)
  136. return
  137. }
  138. if lastID < 1 {
  139. err = ecode.DMReportExist
  140. return
  141. }
  142. if id, err = s.dao.AddReport(c, r); err != nil {
  143. log.Error("s.dao.AddReport(%v) error(%v)", r, err)
  144. return
  145. }
  146. if needDelete {
  147. select {
  148. case s.delDMReportChan <- rpt:
  149. default:
  150. log.Error("s.delDMReportChan.full(%v)", rpt)
  151. }
  152. }
  153. if needHide && !needDelete {
  154. select {
  155. case s.hideDMReportChan <- r:
  156. default:
  157. log.Error("s.hideDMReportChan.full(%v)", r)
  158. }
  159. }
  160. return
  161. }
  162. // EditReport edit report dm.
  163. func (s *Service) EditReport(c context.Context, tp int32, cid, mid, dmid int64, op int8) (affect int64, err error) {
  164. r, err := s.dao.Report(c, cid, dmid)
  165. if err != nil {
  166. log.Error("s.dao.Report(cid:%d, dmid:%d), error(%v)", cid, dmid, err)
  167. return
  168. }
  169. if r == nil {
  170. err = ecode.DMReportNotExist
  171. return
  172. }
  173. if !s.isUpper(c, cid, mid) {
  174. err = ecode.ArchiveOwnerErr
  175. return
  176. }
  177. if affect, err = s.dao.UpdateReportUPOp(c, cid, dmid, op); err != nil {
  178. log.Error("s.dao.UpdateReportUPOp(cid:%d, dmid:%d, op:%d) error(%v)", cid, dmid, op, err)
  179. }
  180. if op == model.StatUpperDelete {
  181. if err = s.EditDMState(c, tp, cid, mid, model.StateDelete, oplog.SourceUp, oplog.OperatorUp, dmid); err != nil {
  182. log.Error("s.EditDMStat(cid:%d,dmid:%d) error(%v)", cid, dmid, err)
  183. return
  184. }
  185. }
  186. v := &model.UptSearchReport{
  187. DMid: dmid,
  188. Upop: op,
  189. Ctime: r.Ctime.Format("2006-01-02 15:04:05"),
  190. Mtime: time.Now().Format("2006-01-02 15:04:05"),
  191. }
  192. err = s.dao.UpdateSearchReport(c, []*model.UptSearchReport{v})
  193. return
  194. }
  195. // ReportList 获取一个用户的所有被举报的弹幕
  196. func (s *Service) ReportList(c context.Context, mid, aid, page, size int64, upOp int8, states []int64) (res *model.RptSearchs, err error) {
  197. res = &model.RptSearchs{}
  198. var (
  199. aidsMap = make(map[int64]struct{})
  200. aids = []int64{}
  201. cidDMids = make(map[int64][]int64)
  202. stateMap = make(map[int64]int64)
  203. )
  204. rptSearch, err := s.dao.SearchReport(c, mid, aid, page, size, upOp, states)
  205. if err != nil || rptSearch == nil {
  206. return
  207. }
  208. for _, v := range rptSearch.Result {
  209. if _, ok := aidsMap[v.Aid]; !ok {
  210. aidsMap[v.Aid] = struct{}{}
  211. aids = append(aids, v.Aid)
  212. }
  213. cidDMids[v.Cid] = append(cidDMids[v.Cid], v.Did)
  214. }
  215. archives := s.archiveInfos(c, aids)
  216. if stateMap, err = s.dmState(c, cidDMids); err != nil {
  217. return
  218. }
  219. for _, v := range rptSearch.Result {
  220. if arc, ok := archives[v.Aid]; ok {
  221. v.Title = arc.Title
  222. v.Cover = arc.Pic
  223. }
  224. if state, ok := stateMap[v.Did]; ok {
  225. v.Deleted = state
  226. }
  227. }
  228. res = &model.RptSearchs{
  229. Page: rptSearch.Page.Num,
  230. PageSize: rptSearch.Page.Size,
  231. PageCount: (rptSearch.Page.Total-1)/rptSearch.Page.Size + 1,
  232. Total: rptSearch.Page.Total,
  233. Result: rptSearch.Result,
  234. }
  235. return
  236. }
  237. func (s *Service) isUpper(c context.Context, cid, mid int64) bool {
  238. sub, err := s.subject(c, 1, cid)
  239. if err != nil {
  240. return false
  241. }
  242. return sub.Mid == mid
  243. }
  244. // checkReasonType get state by report reason
  245. func (s *Service) checkReasonType(c context.Context, reason int8, cid, dmid int64, rpt *model.Report) (state int8, err error) {
  246. reportLog, err := s.dao.ReportLog(c, dmid)
  247. if err != nil {
  248. log.Error("s.dao.ReportLog(dmid:%d) error(%v)", dmid, err)
  249. return
  250. }
  251. if len(reportLog) > 0 { // 如果这个举报已经在后台被处理了,那就根据举报当前的状态返回对应的一二审状态
  252. if rpt.State == model.StatFirstInit ||
  253. rpt.State == model.StatFirstDelete ||
  254. rpt.State == model.StatFirstIgnore {
  255. state = model.StatFirstInit
  256. } else {
  257. state = model.StatSecondInit
  258. }
  259. } else { // 否则就根据举报理由来返回状态
  260. state = s.reasonType(reason)
  261. }
  262. return
  263. }
  264. // ReportArchives 获取一个用户的所有被举报的稿件
  265. func (s *Service) ReportArchives(c context.Context, mid int64, upOp int8, states []int8, pn, ps int64) (res *model.Archives, err error) {
  266. res = &model.Archives{}
  267. aids, err := s.dao.SearchReportAid(c, mid, upOp, states, pn, ps)
  268. if err != nil || len(aids) == 0 {
  269. return
  270. }
  271. archiveInfos := s.archiveInfos(c, aids)
  272. for aid, info := range archiveInfos {
  273. res.Result = append(res.Result, &struct {
  274. Aid int64 `json:"aid"`
  275. Title string `json:"title"`
  276. }{Aid: aid, Title: info.Title})
  277. }
  278. return
  279. }
  280. func (s *Service) reasonType(reason int8) (state int8) {
  281. if reason == model.ReportReasonProhibited ||
  282. reason == model.ReportReasonPorn ||
  283. reason == model.ReportReasonFraud ||
  284. reason == model.ReportReasonAttack ||
  285. reason == model.ReportReasonPrivate ||
  286. reason == model.ReportReasonTeenagers {
  287. state = model.StatFirstInit
  288. } else {
  289. state = model.StatSecondInit
  290. }
  291. return
  292. }
  293. // deleteDMReport delete dm report.
  294. func (s *Service) deleteDMReport(c context.Context, rpt *model.Report) (err error) {
  295. sub, err := s.subject(c, 1, rpt.Cid)
  296. if err != nil {
  297. return
  298. }
  299. rpt.State = model.StatSecondAutoDelete
  300. if err = s.EditDMState(c, 1, rpt.Cid, sub.Mid, model.StateScriptDelete, oplog.SourceUp, oplog.OperatorUp, rpt.Did); err != nil {
  301. log.Error("s.EditDMStat(cid:%d, state:%d, dmid:%d ) error(%v)", rpt.Cid, rpt.State, rpt.Did, err)
  302. return
  303. }
  304. if _, err = s.dao.UpdateReportStat(c, rpt.Cid, rpt.Did, rpt.State); err != nil {
  305. log.Error("s.dao.UpdateReportStat(cid:%d, state:%d, dmid:%d ) error(%v)", rpt.Cid, rpt.State, rpt.Did, err)
  306. return
  307. }
  308. lg := &model.RptLog{
  309. Did: rpt.Did,
  310. AdminID: 0,
  311. Reason: rpt.Reason,
  312. Result: rpt.State,
  313. Remark: "自动删除",
  314. Elapsed: int64(time.Since(rpt.Mtime).Seconds()),
  315. Ctime: time.Now(),
  316. Mtime: time.Now(),
  317. }
  318. if err = s.dao.AddReportLog(c, lg); err != nil {
  319. log.Error("s.dao.AddReportLog(log:%v) error(%v)", lg, err)
  320. return
  321. }
  322. users, err := s.dao.ReportUser(c, rpt.Did)
  323. if err != nil {
  324. log.Error("s.dao.ReportUser(dmid:%d) error(%v)", rpt.Did, err)
  325. return
  326. }
  327. if err = s.dao.SetReportUserFinished(c, rpt.Did); err != nil {
  328. log.Error("s.dao.SetReportUserFinished(dmid:%d) error(%v)", rpt.Did, err)
  329. return
  330. }
  331. ct, err := s.dao.Content(c, rpt.Cid, rpt.Did)
  332. if err != nil || ct == nil {
  333. return
  334. }
  335. arc, err := s.acvSvc.Archive3(c, &arcMdl.ArgAid2{Aid: sub.Pid})
  336. if err != nil {
  337. log.Error("s.acvSvc.Archive3(%d) error(%v)", sub.Pid, err)
  338. return
  339. }
  340. for _, u := range users {
  341. content := fmt.Sprintf(model.RptMsgTemplate, arc.Title, arc.Aid, ct.Msg, model.ReportReason[rpt.Reason])
  342. s.dao.SendNotify(c, model.RptMsgTitle, content, []int64{u.UID})
  343. }
  344. return
  345. }
  346. //hideDMReport hide reported dm
  347. func (s *Service) hideDMReport(c context.Context, rpt *model.Report) (err error) {
  348. dmids := []int64{rpt.Did}
  349. //change dm state to hide
  350. _, err = s.dao.UpdateDMStat(c, 1, rpt.Cid, model.StateHide, dmids)
  351. if err != nil {
  352. log.Error("s.dao.UpdateDMStat(oid:%d state:%d dmids:%v) error(%v)", rpt.Cid, model.StateHide, rpt.Did, err)
  353. return
  354. }
  355. // send hideTime to databus
  356. time := time.Now().Unix() + 72000
  357. act := &model.ReportAction{
  358. Cid: rpt.Cid,
  359. Did: rpt.Did,
  360. HideTime: time,
  361. }
  362. // make sure all the hided dms are in one partition
  363. if err = s.dao.SendAction(context.TODO(), "1", act); err != nil {
  364. log.Error("databus.Send(%+v) error(%v)", act, err)
  365. }
  366. return
  367. }
  368. func (s *Service) dmReportProc() {
  369. for {
  370. select {
  371. case rpt := <-s.delDMReportChan:
  372. if err := s.deleteDMReport(context.TODO(), rpt); err != nil {
  373. log.Error("s.deleteDMReport(rpt:%v) error(%v)", rpt, err)
  374. }
  375. case rpt := <-s.hideDMReportChan:
  376. if err := s.hideDMReport(context.TODO(), rpt); err != nil {
  377. log.Error("s.hideDMReport(rpt:%v) error(%v)", rpt, err)
  378. }
  379. }
  380. }
  381. }
  382. func (s *Service) dmState(c context.Context, cidDmids map[int64][]int64) (stateMap map[int64]int64, err error) {
  383. var (
  384. idxMap map[int64]*model.DM
  385. tp = int32(1)
  386. )
  387. stateMap = make(map[int64]int64)
  388. for oid, dmids := range cidDmids {
  389. if idxMap, _, err = s.dao.IndexsByID(c, tp, oid, dmids); err != nil {
  390. return
  391. }
  392. for dmid, dm := range idxMap {
  393. stateMap[dmid] = int64(dm.State)
  394. }
  395. }
  396. return
  397. }