task.go 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093
  1. package service
  2. import (
  3. "context"
  4. "encoding/json"
  5. "fmt"
  6. "strconv"
  7. "time"
  8. "go-common/app/admin/main/workflow/model"
  9. "go-common/app/admin/main/workflow/model/param"
  10. credit "go-common/app/job/main/credit/model"
  11. "go-common/library/log"
  12. "go-common/library/queue/databus/report"
  13. xtime "go-common/library/time"
  14. )
  15. func (s *Service) afterSetGrpResult(grp *param.GroupResParam, g *model.Group, tinyChalls map[int64]*model.TinyChall) {
  16. logging := func() {
  17. // write group log
  18. l := &model.WLog{
  19. AdminID: grp.AdminID,
  20. Admin: grp.AdminName,
  21. Oid: g.Oid,
  22. Business: g.Business,
  23. Target: g.ID,
  24. Module: model.WLogModuleGroup,
  25. Remark: fmt.Sprintf(`“工单编号 %d” %s 理由:%s`, g.ID, s.StateDescr(grp.Business, 0, grp.State), grp.Reason),
  26. Note: grp.Reason,
  27. }
  28. s.writeAuditLog(l)
  29. // write challenge log
  30. for _, c := range tinyChalls {
  31. l := &model.WLog{
  32. AdminID: grp.AdminID,
  33. Admin: grp.AdminName,
  34. Oid: g.Oid,
  35. Business: g.Business,
  36. Target: c.Cid,
  37. Module: model.WLogModuleChallenge,
  38. Remark: fmt.Sprintf(`“工单详情编号 %d” %s 理由:%s`, c.Cid, s.StateDescr(grp.Business, 0, grp.State), grp.Reason),
  39. Note: grp.Reason,
  40. }
  41. s.writeAuditLog(l)
  42. }
  43. }
  44. callback := func() {
  45. metas := s.dao.AllMetas(context.Background())
  46. meta, ok := metas[grp.Business]
  47. if !ok || meta.ItemType != "group" {
  48. return
  49. }
  50. // handle callback
  51. cb, ok := s.callbackCache[grp.Business]
  52. if !ok || cb == nil {
  53. return
  54. }
  55. mids := make([]int64, 0, len(tinyChalls))
  56. for _, c := range tinyChalls {
  57. mids = append(mids, c.Mid)
  58. }
  59. // origin callback
  60. if cb.URL != "" && cb.State == model.CallbackEnable {
  61. payload := &model.Payload{
  62. Verb: model.GroupSetResult,
  63. Actor: model.Actor{
  64. AdminID: grp.AdminID,
  65. },
  66. CTime: xtime.Time(time.Now().Unix()),
  67. Object: grp,
  68. Target: g,
  69. Influence: map[string]interface{}{
  70. "mids": mids,
  71. },
  72. }
  73. if err := s.SendCallbackRetry(context.Background(), cb, payload); err != nil {
  74. log.Error("Failed to s.SendCallbackRetry(%+v, %+v): %v", cb, payload, err)
  75. // continue
  76. }
  77. }
  78. }
  79. extra := func() {
  80. // extra condition
  81. switch grp.Business {
  82. case model.ArchiveComplain:
  83. s.notifyUsers(grp.Business, grp.Oid, grp.AdminID, tinyChalls, grp.IsMessage)
  84. default:
  85. }
  86. }
  87. logging()
  88. callback()
  89. extra()
  90. }
  91. func (s *Service) afterBatchSetGrpResult(bgrp *param.BatchGroupResParam, groups map[int64]*model.Group, tinyChalls map[int64]*model.TinyChall) {
  92. // record log
  93. logging := func() {
  94. for _, g := range groups {
  95. l := &model.WLog{
  96. AdminID: bgrp.AdminID,
  97. Admin: bgrp.AdminName,
  98. Oid: g.Oid,
  99. Business: g.Business,
  100. Target: g.ID,
  101. Module: model.WLogModuleGroup,
  102. Remark: fmt.Sprintf(`“工单编号 %d” %s 理由:%s`, g.ID, s.StateDescr(bgrp.Business, 0, bgrp.State), bgrp.Reason),
  103. Note: bgrp.Reason,
  104. }
  105. s.writeAuditLog(l)
  106. }
  107. for _, c := range tinyChalls {
  108. g, ok := groups[c.Gid]
  109. if !ok {
  110. log.Warn("Failed to retrive group by gid %d", c.Gid)
  111. continue
  112. }
  113. l := &model.WLog{
  114. AdminID: bgrp.AdminID,
  115. Admin: bgrp.AdminName,
  116. Oid: g.Oid,
  117. Business: g.Business,
  118. Target: c.Cid,
  119. Module: model.WLogModuleChallenge,
  120. Remark: fmt.Sprintf(`“工单详情编号 %d” 状态从 %s 修改为 %s 理由:%s`, c.Cid, s.StateDescr(bgrp.Business, 0, c.State), s.StateDescr(bgrp.Business, 0, bgrp.State), bgrp.Reason),
  121. Note: bgrp.Reason,
  122. }
  123. s.writeAuditLog(l)
  124. }
  125. }
  126. // origin callback
  127. callback := func() {
  128. metas := s.dao.AllMetas(context.Background())
  129. meta, ok := metas[bgrp.Business]
  130. if !ok || meta.ItemType != "group" {
  131. return
  132. }
  133. cb, ok := s.callbackCache[bgrp.Business]
  134. if !ok || cb == nil {
  135. return
  136. }
  137. toids := make([]int64, 0, len(groups))
  138. for _, g := range groups {
  139. toids = append(toids, g.Oid)
  140. }
  141. bgrp.Oids = toids
  142. gmids := make(map[int64][]int64, len(groups))
  143. for _, c := range tinyChalls {
  144. if _, ok := gmids[c.Gid]; !ok {
  145. gmids[c.Gid] = make([]int64, 0)
  146. }
  147. gmids[c.Gid] = append(gmids[c.Gid], c.Mid)
  148. }
  149. if cb.URL != "" && cb.State == model.CallbackEnable {
  150. for _, g := range groups {
  151. payload := &model.Payload{
  152. Verb: model.BatchGroupSetResult,
  153. Actor: model.Actor{
  154. AdminID: bgrp.AdminID,
  155. },
  156. CTime: xtime.Time(time.Now().Unix()),
  157. Object: bgrp,
  158. Target: g,
  159. Influence: map[string]interface{}{
  160. "mids": gmids[g.ID],
  161. },
  162. }
  163. if err := s.SendCallbackRetry(context.Background(), cb, payload); err != nil {
  164. log.Error("Failed to s.SendCallbackRetry(%+v, %+v): %v", cb, payload, err)
  165. // continue
  166. }
  167. }
  168. }
  169. }
  170. // extra condition
  171. extra := func() {
  172. switch bgrp.Business {
  173. case model.ArchiveComplain:
  174. oidToChalls := make(map[int64]map[int64]*model.TinyChall, len(groups))
  175. for _, c := range tinyChalls {
  176. g, ok := groups[c.Gid]
  177. if !ok {
  178. continue
  179. }
  180. if _, ok := oidToChalls[g.Oid]; !ok {
  181. oidToChalls[g.Oid] = make(map[int64]*model.TinyChall)
  182. }
  183. oidToChalls[g.Oid][c.Cid] = c
  184. }
  185. for oid, cs := range oidToChalls {
  186. s.notifyUsers(bgrp.Business, oid, bgrp.AdminID, cs, bgrp.IsMessage)
  187. }
  188. default:
  189. }
  190. }
  191. logging()
  192. callback()
  193. extra()
  194. }
  195. func (s *Service) afterSetChallResult(crp *param.ChallResParam, c *model.Chall) {
  196. logging := func() {
  197. // write challenge log
  198. l := &model.WLog{
  199. AdminID: crp.AdminID,
  200. Admin: crp.AdminName,
  201. Oid: c.Oid,
  202. Business: c.Business,
  203. Target: c.Cid,
  204. Module: model.WLogModuleChallenge,
  205. Remark: fmt.Sprintf(`“工单详情编号 %d” 处理状态从 %s 修改为 %s 理由:%s`, c.Cid, s.StateDescr(c.Business, 0, c.State), s.StateDescr(c.Business, 0, crp.State), crp.Reason),
  206. Note: crp.Reason,
  207. }
  208. s.writeAuditLog(l)
  209. }
  210. callback := func() {
  211. metas := s.dao.AllMetas(context.Background())
  212. meta, ok := metas[c.Business]
  213. if !ok || meta.ItemType != "challenge" {
  214. log.Warn("item type not exist or is not challenge, meta(%+v)", meta)
  215. return
  216. }
  217. // handle callback
  218. cb, ok := s.callbackCache[c.Business]
  219. if !ok || cb == nil {
  220. log.Error("can not find callback func, business(%d)", c.Business)
  221. return
  222. }
  223. mids := []int64{c.Mid}
  224. if cb.URL != "" && cb.State == model.CallbackEnable {
  225. payload := &model.Payload{
  226. Verb: model.ChallSetResult,
  227. Actor: model.Actor{
  228. AdminID: crp.AdminID,
  229. },
  230. CTime: xtime.Time(time.Now().Unix()),
  231. Object: crp,
  232. Target: c,
  233. Influence: map[string]interface{}{
  234. "mids": mids,
  235. },
  236. }
  237. if err := s.SendCallbackRetry(context.Background(), cb, payload); err != nil {
  238. log.Error("Failed to s.SendCallbackRetry(%+v, %+v): %v", cb, payload, err)
  239. // continue
  240. }
  241. }
  242. }
  243. extra := func() {
  244. // extra condition
  245. }
  246. logging()
  247. callback()
  248. extra()
  249. }
  250. func (s *Service) afterBatchSetChallResult(bcrp *param.BatchChallResParam, challs map[int64]*model.Chall) {
  251. // Record Log
  252. logging := func() {
  253. for _, c := range challs {
  254. l := &model.WLog{
  255. AdminID: bcrp.AdminID,
  256. Admin: bcrp.AdminName,
  257. Oid: c.Oid,
  258. Business: c.Business,
  259. Target: c.Cid,
  260. Module: model.WLogModuleChallenge,
  261. Remark: fmt.Sprintf(`“工单详情编号 %d” 状态从 %s 修改为 %s 理由:%s`, c.Cid, s.StateDescr(c.Business, 0, c.State), s.StateDescr(c.Business, 0, bcrp.State), bcrp.Reason),
  262. Note: bcrp.Reason,
  263. }
  264. s.writeAuditLog(l)
  265. }
  266. }
  267. // origin callback
  268. callback := func() {
  269. metas := s.dao.AllMetas(context.Background())
  270. for _, c := range challs {
  271. meta, ok := metas[c.Business]
  272. if !ok || meta.ItemType != "challenge" {
  273. return
  274. }
  275. cb, ok := s.callbackCache[c.Business]
  276. if !ok || cb == nil {
  277. return
  278. }
  279. mids := []int64{c.Mid}
  280. // origin callback
  281. if cb.URL != "" && cb.State == model.CallbackEnable {
  282. payload := &model.Payload{
  283. Verb: model.BatchChallSetResult,
  284. Actor: model.Actor{
  285. AdminID: bcrp.AdminID,
  286. },
  287. CTime: xtime.Time(time.Now().Unix()),
  288. Object: bcrp,
  289. Target: c,
  290. Influence: map[string]interface{}{
  291. "mids": mids,
  292. },
  293. }
  294. if err := s.SendCallbackRetry(context.Background(), cb, payload); err != nil {
  295. log.Error("Failed to s.SendCallbackRetry(%+v, %+v): %v", cb, payload, err)
  296. // continue
  297. }
  298. }
  299. }
  300. }
  301. extra := func() {
  302. // extra condition
  303. }
  304. logging()
  305. callback()
  306. extra()
  307. }
  308. func (s *Service) afterSetGroupRole(grsp *param.GroupRoleSetParam, groups map[int64]*model.Group) {
  309. // Record Log
  310. logging := func() {
  311. logs, err := s.LastLogStat(context.Background(), grsp.GID, []int{model.WLogModuleRoleShift}, []string{"int_1", "ctime", "int_2", "uid"})
  312. if err != nil {
  313. log.Error("s.LastLogStat() failed error:%v", err)
  314. return
  315. }
  316. for _, g := range groups {
  317. var (
  318. preTag *model.TagMeta
  319. newTag *model.TagMeta
  320. err error
  321. )
  322. if preTag, err = s.tag(g.Business, g.Tid); err != nil {
  323. log.Warn("s.tag(%d,%d) error(%v)", g.Business, g.Tid, err)
  324. err = nil
  325. preTag.Bid = g.Business
  326. preTag.Tid = g.Tid
  327. preTag.RID = g.Rid
  328. }
  329. if newTag, err = s.tag(g.Business, grsp.TID); err != nil {
  330. log.Warn("s.tag(%d,%d) error(%v)", g.Business, g.Tid, err)
  331. err = nil
  332. newTag.Bid = g.Business
  333. newTag.Tid = g.Tid
  334. }
  335. l := &model.WLog{
  336. AdminID: grsp.AdminID,
  337. Admin: grsp.AdminName,
  338. Oid: g.Oid,
  339. Business: g.Business,
  340. Target: g.ID,
  341. Module: model.WLogModuleRoleShift,
  342. Remark: fmt.Sprintf(`“工单编号 %d” 业务角色流转从 %d:%s 到 %d:%s, 管理 tag 从 %d:%s 变更到 %d:%s, 备注: %s`,
  343. g.ID, g.Rid, s.RidDesc(g.Business, g.Rid), grsp.RID, s.RidDesc(g.Business, grsp.RID), g.Tid, preTag.Name, grsp.TID, newTag.Name, grsp.Note),
  344. Note: grsp.Note,
  345. OpType: strconv.Itoa(int(model.RoleShift)),
  346. PreRid: strconv.Itoa(int(preTag.RID)),
  347. }
  348. if roleLog, ok := logs[g.ID]; !ok {
  349. l.TimeConsume = int64(time.Since(g.LastTime.Time()) / time.Second)
  350. } else {
  351. lastRoleTime, _ := time.ParseInLocation("2006-01-02 15:04:05", roleLog.CTime, time.Local)
  352. if lastRoleTime.After(g.LastTime.Time()) {
  353. l.TimeConsume = int64(time.Since(lastRoleTime) / time.Second)
  354. } else {
  355. l.TimeConsume = int64(time.Since(g.LastTime.Time()) / time.Second)
  356. }
  357. }
  358. s.writeAuditLog(l)
  359. }
  360. }
  361. logging()
  362. }
  363. // set state v3
  364. func (s *Service) afterSetGroupState(gssp *param.GroupStateSetParam, groups map[int64]*model.Group, tinyChalls map[int64]*model.TinyChall) {
  365. // record log
  366. logging := func() {
  367. logs, err := s.LastLogStat(context.Background(), gssp.ID, []int{model.WLogModuleRoleShift}, []string{"int_1", "ctime", "int_2", "uid"})
  368. if err != nil {
  369. log.Error("s.LastLogStat() failed error:%v", err)
  370. return
  371. }
  372. for _, g := range groups {
  373. l := &model.WLog{
  374. AdminID: gssp.AdminID,
  375. Admin: gssp.AdminName,
  376. Oid: g.Oid,
  377. Business: g.Business,
  378. Target: g.ID,
  379. Module: model.WLogModuleGroup,
  380. Remark: fmt.Sprintf(`“工单编号 %d” %s 理由:%s`, g.ID, s.StateDescr(g.Business, 0, gssp.State), gssp.Reason),
  381. Note: gssp.Reason,
  382. OpType: strconv.Itoa(int(gssp.State)),
  383. PreRid: strconv.Itoa(int(gssp.Rid)),
  384. Param: gssp,
  385. }
  386. if roleLog, ok := logs[g.ID]; !ok {
  387. l.TimeConsume = int64(time.Since(g.LastTime.Time()) / time.Second)
  388. } else {
  389. lastRoleTime, _ := time.ParseInLocation("2006-01-02 15:04:05", roleLog.CTime, time.Local)
  390. if lastRoleTime.After(g.LastTime.Time()) {
  391. l.TimeConsume = int64(time.Since(lastRoleTime) / time.Second)
  392. } else {
  393. l.TimeConsume = int64(time.Since(g.LastTime.Time()) / time.Second)
  394. }
  395. }
  396. if g.BusinessObject != nil {
  397. l.Mid = g.BusinessObject.Mid
  398. }
  399. s.writeAuditLog(l)
  400. }
  401. for _, c := range tinyChalls {
  402. g, ok := groups[c.Gid]
  403. if !ok {
  404. log.Warn("Failed to retrive group by gid %d", c.Gid)
  405. continue
  406. }
  407. l := &model.WLog{
  408. AdminID: gssp.AdminID,
  409. Admin: gssp.AdminName,
  410. Oid: g.Oid,
  411. Business: g.Business,
  412. Target: c.Cid,
  413. Module: model.WLogModuleChallenge,
  414. Remark: fmt.Sprintf(`“工单详情编号 %d” 状态从 %s 修改为 %s 理由:%s`, c.Cid, s.StateDescr(g.Business, 0, c.State), s.StateDescr(g.Business, 0, gssp.State), gssp.Reason),
  415. Note: gssp.Reason,
  416. Mid: c.Mid,
  417. }
  418. s.writeAuditLog(l)
  419. }
  420. }
  421. // origin callback
  422. callback := func() {
  423. cb, ok := s.callbackCache[gssp.Business]
  424. if !ok || cb == nil {
  425. return
  426. }
  427. gmids := make(map[int64][]int64, len(groups))
  428. for _, c := range tinyChalls {
  429. if _, ok := gmids[c.Gid]; !ok {
  430. gmids[c.Gid] = make([]int64, 0)
  431. }
  432. gmids[c.Gid] = append(gmids[c.Gid], c.Mid)
  433. }
  434. if cb.URL != "" && cb.State == model.CallbackEnable {
  435. //common
  436. payload := &model.Payload{
  437. Bid: int(gssp.Business),
  438. Verb: model.GroupSetState,
  439. Actor: model.Actor{
  440. AdminID: gssp.AdminID,
  441. AdminName: gssp.AdminName,
  442. },
  443. CTime: xtime.Time(time.Now().Unix()),
  444. Object: gssp,
  445. }
  446. // influence
  447. // 长短评
  448. if gssp.Business == model.ReviewShortComplain || gssp.Business == model.ReviewLongComplain {
  449. var reportMids = make([]int64, len(tinyChalls))
  450. for _, tc := range tinyChalls {
  451. reportMids = append(reportMids, tc.Mid)
  452. }
  453. payload.Influence = map[string]interface{}{
  454. "mids": reportMids,
  455. }
  456. }
  457. // target
  458. for _, g := range groups {
  459. payload.Targets = append(payload.Targets, g)
  460. }
  461. //todo: extra
  462. if err := s.SendCallbackRetry(context.Background(), cb, payload); err != nil {
  463. log.Error("Failed to s.SendCallbackRetry(%+v, %+v): %v", cb, payload, err)
  464. // continue
  465. }
  466. }
  467. }
  468. // notify user
  469. notify := func() {
  470. s.notifyUsersV4(gssp, groups, tinyChalls)
  471. }
  472. // 扣节操
  473. decreaseMoral := func() {
  474. if gssp.DecreaseMoral == 0 {
  475. return
  476. }
  477. var (
  478. gids []int64
  479. mids []int64
  480. )
  481. for _, g := range groups {
  482. gids = append(gids, g.ID)
  483. }
  484. // 被举报人 mid
  485. var (
  486. bus map[int64]*model.Business
  487. err error
  488. )
  489. if bus, err = s.dao.BusObjectByGids(context.Background(), gids); err != nil {
  490. log.Error("s.dao.BusObjectByGids(%v) error(%v)", gids, err)
  491. return
  492. }
  493. for _, b := range bus {
  494. mids = append(mids, b.Mid)
  495. }
  496. if err := s.dao.AddMoral(context.Background(), mids, gssp); err != nil {
  497. log.Error("s.dao.AddMoral(%v,%d) error(%v)", mids, gssp.DecreaseMoral, err)
  498. return
  499. }
  500. l := &model.WLog{
  501. AdminID: gssp.AdminID,
  502. Admin: gssp.AdminName,
  503. Module: model.WLogModuleAddMoral,
  504. Mids: mids,
  505. Param: gssp,
  506. }
  507. s.writeAuditLog(l)
  508. }
  509. // 封禁账号
  510. block := func() {
  511. if gssp.BlockDay == 0 {
  512. return
  513. }
  514. var (
  515. gids []int64
  516. mids []int64
  517. )
  518. for _, g := range groups {
  519. gids = append(gids, g.ID)
  520. }
  521. // 被举报人 mid
  522. var (
  523. bus map[int64]*model.Business
  524. err error
  525. )
  526. if bus, err = s.dao.BusObjectByGids(context.Background(), gids); err != nil {
  527. log.Error("s.dao.BusObjectByGids(%v) error(%v)", gids, err)
  528. return
  529. }
  530. for _, b := range bus {
  531. mids = append(mids, b.Mid)
  532. }
  533. if err := s.dao.AddBlock(context.Background(), mids, gssp); err != nil {
  534. log.Error("s.dao.AddBlock(%d,%v) error(%v)", mids, gssp, err)
  535. return
  536. }
  537. if err := s.dao.AddCreditBlockInfo(context.Background(), bus, gssp); err != nil {
  538. log.Error("s.dao.AddCreditBlockInfo(%d,%v) error(%v)", mids, gssp, err)
  539. return
  540. }
  541. l := &model.WLog{
  542. AdminID: gssp.AdminID,
  543. Admin: gssp.AdminName,
  544. Module: model.WLogModuleBlock,
  545. Mids: mids,
  546. Param: gssp,
  547. }
  548. s.writeAuditLog(l)
  549. }
  550. logging()
  551. callback()
  552. notify()
  553. decreaseMoral()
  554. block()
  555. }
  556. // only set group state
  557. func (s *Service) afterSimpleSetState(gspr *param.GroupStatePublicReferee, groups map[int64]*model.Group) {
  558. // record log
  559. logging := func() {
  560. for _, g := range groups {
  561. l := &model.WLog{
  562. AdminID: gspr.AdminID,
  563. Admin: gspr.AdminName,
  564. Oid: g.Oid,
  565. Business: g.Business,
  566. Target: g.ID,
  567. Module: model.WLogModulePublicReferee,
  568. Remark: fmt.Sprintf(`“工单编号 %d” %s 理由:%s`, g.ID, s.StateDescr(g.Business, 0, gspr.State), ""),
  569. OpType: strconv.Itoa(int(gspr.State)),
  570. }
  571. s.writeAuditLog(l)
  572. }
  573. }
  574. // callback
  575. callback := func() {
  576. cb, ok := s.callbackCache[gspr.Business]
  577. if !ok || cb == nil {
  578. return
  579. }
  580. gssp := &param.GroupStateSetParam{
  581. ID: gspr.ID,
  582. Business: gspr.Business,
  583. AdminID: gspr.AdminID,
  584. AdminName: gspr.AdminName,
  585. State: gspr.State,
  586. }
  587. if cb.URL != "" && cb.State == model.CallbackEnable {
  588. //common
  589. payload := &model.Payload{
  590. Bid: int(gssp.Business),
  591. Verb: model.GroupSetPublicReferee,
  592. Actor: model.Actor{
  593. AdminID: gssp.AdminID,
  594. AdminName: gssp.AdminName,
  595. },
  596. CTime: xtime.Time(time.Now().Unix()),
  597. Object: gssp,
  598. }
  599. // target
  600. for _, g := range groups {
  601. payload.Targets = append(payload.Targets, g)
  602. }
  603. if err := s.SendCallbackRetry(context.Background(), cb, payload); err != nil {
  604. log.Error("Failed to s.SendCallbackRetry(%+v, %+v): %v", cb, payload, err)
  605. // continue
  606. }
  607. }
  608. }
  609. logging()
  610. callback()
  611. }
  612. func (s *Service) afterSetBusinessState(challs []*model.Chall) {
  613. // todo: after set business state
  614. logging := func() {
  615. for _, c := range challs {
  616. l := &model.WLog{
  617. AdminID: c.AssigneeAdminID,
  618. Admin: c.AssigneeAdminName,
  619. Oid: c.Oid,
  620. Business: c.Business,
  621. Target: c.Cid,
  622. Module: model.WLogModuleReply,
  623. Mid: c.Mid,
  624. TypeID: c.TypeID,
  625. }
  626. s.writeAuditLog(l)
  627. }
  628. }
  629. logging()
  630. }
  631. func (s *Service) afterAddReply(ep *param.EventParam, c *model.Chall) {
  632. logging := func() {
  633. l := &model.WLog{
  634. AdminID: ep.AdminID,
  635. Admin: ep.AdminName,
  636. Oid: c.Oid,
  637. Business: c.Business,
  638. Target: c.Cid,
  639. Module: model.FeedBackTypeReply,
  640. Mid: c.Mid,
  641. Remark: ep.Content,
  642. Note: strconv.Itoa(int(ep.Event)),
  643. Meta: map[string]interface{}{
  644. "ep": ep,
  645. "challenge": c,
  646. },
  647. }
  648. s.writeReplyLog(l)
  649. }
  650. logging()
  651. }
  652. func (s *Service) afterAddMultiReply(bep *param.BatchEventParam, cs map[int64]*model.Chall) {
  653. loggin := func() {
  654. for _, cid := range bep.Cids {
  655. var (
  656. c *model.Chall
  657. ok bool
  658. )
  659. if c, ok = cs[cid]; !ok {
  660. continue
  661. }
  662. l := &model.WLog{
  663. AdminID: bep.AdminID,
  664. Admin: bep.AdminName,
  665. Oid: c.Oid,
  666. Business: c.Business,
  667. Target: c.Cid,
  668. Module: model.FeedBackTypeReply,
  669. Mid: c.Mid,
  670. Remark: bep.Content,
  671. Note: strconv.Itoa(int(bep.Event)),
  672. Meta: map[string]interface{}{
  673. "bep": bep,
  674. "challenge": cs,
  675. },
  676. }
  677. s.writeReplyLog(l)
  678. }
  679. }
  680. loggin()
  681. }
  682. func (s *Service) notifyUsers(business int8, oid int64, adminid int64, challs map[int64]*model.TinyChall, isDisposeMsg bool) (err error) {
  683. var makeDealMsgParam = model.DealArcComplainMsg
  684. var makeReceivedMsgParam = model.ReceivedArcComplainMsg
  685. mids := make([]int64, 0, len(challs))
  686. for _, c := range challs {
  687. mids = append(mids, int64(c.Mid))
  688. }
  689. if business == int8(model.ArchiveComplain) {
  690. // if challenge ctime < 10min, report appeal received
  691. var rChall = make([]*model.TinyChall, 0)
  692. var rMids = make([]int64, 0)
  693. for _, c := range challs {
  694. if time.Since(c.CTime.Time()) < time.Minute*10 {
  695. //todo: rmids send message archive complain received
  696. rChall = append(rChall, c)
  697. rMids = append(rMids, c.Mid)
  698. }
  699. }
  700. if len(rChall) > 0 {
  701. rmp := makeReceivedMsgParam(oid, rMids)
  702. if err = s.dao.SendMessage(context.Background(), rmp); err != nil {
  703. log.Error("Failed to s.dao.SendMessage(%v, %v, %+v): %v", oid, mids, rmp, err)
  704. err = nil
  705. }
  706. log.Info("send archive complain received message business(%d) oid(%d) mids(%v) mc(%s) message(%+v)", business, oid, mids, rmp.MC, rmp)
  707. // report archive complain received msg
  708. for _, tc := range rChall {
  709. report.Manager(&report.ManagerInfo{
  710. Uname: "",
  711. UID: 0,
  712. Business: 11,
  713. Type: 2,
  714. Oid: oid,
  715. Action: "notify_users_received",
  716. Ctime: time.Now(),
  717. Index: []interface{}{tc.Cid, tc.Gid, tc.Mid},
  718. Content: map[string]interface{}{
  719. "mid": tc.Mid,
  720. "message": rmp,
  721. },
  722. })
  723. }
  724. }
  725. }
  726. if !isDisposeMsg {
  727. return
  728. }
  729. time.Sleep(500 * time.Millisecond)
  730. mdmp := makeDealMsgParam(oid, mids)
  731. if err = s.dao.SendMessage(context.Background(), mdmp); err != nil {
  732. log.Error("Failed to s.dao.SendMessage(%v, %v, %+v): %v", oid, mids, mdmp, err)
  733. return
  734. }
  735. // group dispose report
  736. report.Manager(&report.ManagerInfo{
  737. Uname: "",
  738. UID: adminid,
  739. Business: 11,
  740. Type: 3,
  741. Oid: oid,
  742. Action: "notify_users_dispose",
  743. Ctime: time.Now(),
  744. Index: []interface{}{business},
  745. Content: map[string]interface{}{
  746. "mid": mids,
  747. "message": mdmp,
  748. },
  749. })
  750. log.Info("send message business(%d) oid(%d) mids(%v) mc(%s) message(%+v)", business, oid, mids, mdmp.MC, mdmp)
  751. return
  752. }
  753. func (s *Service) notifyUsersV4(gssp *param.GroupStateSetParam, groups map[int64]*model.Group, tinyChalls map[int64]*model.TinyChall) (err error) {
  754. // 稿件投诉补发已收到消息
  755. if gssp.Business == model.ArchiveComplain {
  756. for _, g := range groups {
  757. // if challenge ctime < 10min, report appeal received
  758. var rMids = make([]int64, 0)
  759. for _, c := range tinyChalls {
  760. if time.Since(c.CTime.Time()) < time.Minute*10 && c.Gid == g.ID {
  761. //todo: rmids send message archive complain received
  762. rMids = append(rMids, c.Mid)
  763. }
  764. }
  765. if len(rMids) > 0 {
  766. rmp := &param.MessageParam{
  767. Type: "json",
  768. Source: 1,
  769. DataType: 4,
  770. MC: model.ArcComplainRevMC,
  771. Title: "您的投诉已收到",
  772. Context: fmt.Sprintf("您对稿件(av%d)的举报我们已经收到。感谢您对 bilibili 社区秩序的维护,哔哩哔哩 (゜-゜)つロ 干杯~", g.Oid),
  773. MidList: rMids,
  774. }
  775. if err = s.dao.SendMessage(context.Background(), rmp); err != nil {
  776. log.Error("Failed to s.dao.SendMessage(%+v) mid(%v): %v", rmp, rMids, err)
  777. err = nil
  778. }
  779. log.Info("send archive complain received message gid(%d) oid(%d) mids(%v) message(%+v)", g.ID, g.Oid, rMids, rmp)
  780. // report archive complain received msg
  781. report.Manager(&report.ManagerInfo{
  782. Uname: "",
  783. UID: 0,
  784. Business: 11,
  785. Type: model.FeedBackTypeNotifyUserReceived,
  786. Oid: g.Oid,
  787. Action: "notify_users_received_v4",
  788. Ctime: time.Now(),
  789. Index: []interface{}{g.ID},
  790. Content: map[string]interface{}{
  791. "message": rmp,
  792. },
  793. })
  794. }
  795. }
  796. }
  797. time.Sleep(500 * time.Millisecond)
  798. // 通知举报人
  799. if gssp.IsMessage {
  800. mps := make(map[int64]*param.MessageParam) // map[oid]*mp or map[eid]*mp
  801. // all mids need to report
  802. cmids := make(map[int64][]int64) //map[gid][]mids
  803. for _, c := range tinyChalls {
  804. if _, ok := cmids[c.Gid]; !ok {
  805. cmids[c.Gid] = make([]int64, 0)
  806. }
  807. cmids[c.Gid] = append(cmids[c.Gid], c.Mid)
  808. }
  809. switch gssp.Business {
  810. case model.ArchiveComplain:
  811. for _, g := range groups {
  812. reportMids, ok := cmids[g.ID]
  813. if !ok {
  814. log.Warn("report mid not found gid(%d)", g.ID)
  815. continue
  816. }
  817. mp := &param.MessageParam{
  818. Type: "json",
  819. Source: 1,
  820. DataType: 4,
  821. MC: model.ArcComplainDealMC,
  822. Title: "您的投诉已被受理",
  823. Context: fmt.Sprintf("您对稿件(av%d)的投诉已被受理。感谢您对 bilibili 社区秩序的维护,哔哩哔哩 (゜-゜)つロ 干杯~ ", g.Oid),
  824. MidList: reportMids,
  825. }
  826. mps[g.ID] = mp
  827. }
  828. case model.ChannelComplain:
  829. for _, g := range groups {
  830. reportMids, ok := cmids[g.ID]
  831. if !ok {
  832. log.Warn("report mid not found gid(%d)", g.ID)
  833. continue
  834. }
  835. mp := &param.MessageParam{
  836. Type: "json",
  837. Source: 1,
  838. DataType: 4,
  839. MC: model.WkfNotifyMC,
  840. Title: "你的举报已成功处理",
  841. Context: fmt.Sprintf(`您在稿件【#{av%d}{"https://www.bilibili.com/video/av%d"}】举报的频道【%s】已处理,感谢反馈,点击进去查看`,
  842. g.Oid, g.Oid, g.BusinessObject.Title),
  843. MidList: reportMids,
  844. }
  845. mps[g.ID] = mp
  846. }
  847. case model.CommentComplain: // 评论举报
  848. var blockStr, isDel string
  849. if gssp.BlockDay == -1 {
  850. blockStr = "该用户已被永久封禁。"
  851. } else if gssp.BlockDay > 0 {
  852. blockStr = fmt.Sprintf("并被封禁%d天。", gssp.BlockDay)
  853. }
  854. if gssp.DisposeMode == 1 {
  855. isDel = "已被移除"
  856. } else {
  857. isDel = "已被处罚"
  858. }
  859. tMeta, _ := s.tag(gssp.Business, gssp.Tid)
  860. tName := tMeta.Name // 举报理由
  861. for _, g := range groups {
  862. if g.Fid == model.ReplyFidManga {
  863. continue
  864. }
  865. var extMap map[string]interface{}
  866. reportMids, ok := cmids[g.ID]
  867. if !ok {
  868. log.Warn("report mid not found gid(%d)", g.ID)
  869. continue
  870. }
  871. json.Unmarshal([]byte(g.BusinessObject.Extra), &extMap)
  872. extTitle, _ := extMap["title"].(string)
  873. extTitle = subString(extTitle, 0, 40)
  874. extLink, _ := extMap["link"].(string)
  875. content := fmt.Sprintf(`您好,您在#{%s}{%s}下举报的评论『%s』%s,%s 理由:%s。`+model.NotifyComRulesReport,
  876. extTitle, extLink, pretreat(g.BusinessObject.Title), isDel, blockStr, tName)
  877. mp := &param.MessageParam{
  878. Type: "json",
  879. Source: 1,
  880. DataType: 4,
  881. MC: model.WkfNotifyMC,
  882. Title: "举报处理结果通知",
  883. Context: content,
  884. MidList: reportMids,
  885. }
  886. mps[g.ID] = mp
  887. }
  888. }
  889. for gid, mp := range mps {
  890. if err = s.dao.SendMessage(context.Background(), mp); err != nil {
  891. log.Error("Failed to s.dao.SendMessage(%+v) mids(%v): %v", mp, err)
  892. continue
  893. }
  894. // group dispose report
  895. report.Manager(&report.ManagerInfo{
  896. Uname: gssp.AdminName,
  897. UID: gssp.AdminID,
  898. Business: 11,
  899. Type: model.FeedBackTypeNotifyUserDisposed,
  900. Action: "notify_users_v4_reporters",
  901. Ctime: time.Now(),
  902. Index: []interface{}{gssp.Business},
  903. Content: map[string]interface{}{
  904. "message": mp,
  905. },
  906. })
  907. log.Info("notifyUsersV4 success send to reporters message(%+v) gid(%d)", mp, gid)
  908. }
  909. }
  910. // 通知被举报人(up主)
  911. if gssp.IsMessageUper {
  912. mps := make(map[int64]*param.MessageParam) // map[oid]*mp or map[eid]*mp
  913. switch gssp.Business {
  914. case model.CommentComplain: //评论举报
  915. var (
  916. blockStr string
  917. disposeStr string
  918. )
  919. if gssp.BlockDay == -1 {
  920. blockStr = "本帐号已被永久封禁。"
  921. } else if gssp.BlockDay > 0 {
  922. blockStr = fmt.Sprintf("并被封禁%d天。", gssp.BlockDay)
  923. }
  924. if gssp.DisposeMode == 1 {
  925. disposeStr = "已被举报并移除"
  926. } else {
  927. disposeStr = "已被举报并处罚"
  928. }
  929. tMeta, _ := s.tag(gssp.Business, gssp.Tid)
  930. tName := tMeta.Name // 举报理由
  931. for _, g := range groups {
  932. if g.Fid == model.ReplyFidManga {
  933. continue
  934. }
  935. var extMap map[string]interface{}
  936. json.Unmarshal([]byte(g.BusinessObject.Extra), &extMap)
  937. extTitle, _ := extMap["title"].(string)
  938. extTitle = subString(extTitle, 0, 40)
  939. extLink, _ := extMap["link"].(string)
  940. content := fmt.Sprintf(`您好,您在#{%s}{%s}下发布的评论『%s』%s,%s 理由:%s。`, extTitle, extLink, pretreat(g.BusinessObject.Title), disposeStr, blockStr, tName)
  941. content = suffixContent(content, gssp)
  942. mp := &param.MessageParam{
  943. Type: "json",
  944. Source: 1,
  945. DataType: 4,
  946. MC: model.WkfNotifyMC,
  947. Title: "评论违规处理通知",
  948. Context: content,
  949. MidList: []int64{g.BusinessObject.Mid},
  950. }
  951. mps[g.ID] = mp
  952. }
  953. }
  954. for gid, mp := range mps {
  955. if err = s.dao.SendMessage(context.Background(), mp); err != nil {
  956. log.Error("Failed to s.dao.SendMessage(%+v) gid(%d): %v", mp, gid, err)
  957. continue
  958. }
  959. // group dispose report
  960. report.Manager(&report.ManagerInfo{
  961. Uname: gssp.AdminName,
  962. UID: gssp.AdminID,
  963. Business: 11,
  964. Type: 3,
  965. Action: "notify_users_v4_upers",
  966. Ctime: time.Now(),
  967. Index: []interface{}{gssp.Business},
  968. Content: map[string]interface{}{
  969. "mid": mp.MidList,
  970. "message": *mp,
  971. },
  972. })
  973. log.Info("notifyUsersV4 success send to uper message(%+v) gid(%d)", mp, gid)
  974. }
  975. }
  976. return
  977. }
  978. // 站内信评论内容预处理
  979. func pretreat(str string) string {
  980. str = subString(str, 0, 40)
  981. str = filterViolationMsg(str)
  982. return str
  983. }
  984. // 字符串截断
  985. func subString(str string, begin, length int) string {
  986. rs := []rune(str)
  987. lth := len(rs)
  988. if begin < 0 {
  989. begin = 0
  990. }
  991. if begin >= lth {
  992. begin = lth
  993. }
  994. end := begin + length
  995. if end > lth {
  996. end = lth
  997. }
  998. return string(rs[begin:end])
  999. }
  1000. // 字符串加*
  1001. func filterViolationMsg(msg string) string {
  1002. s := []rune(msg)
  1003. for i := 0; i < len(s); i++ {
  1004. if i%3 != 0 {
  1005. s[i] = '*'
  1006. }
  1007. }
  1008. return string(s)
  1009. }
  1010. // 评论站内信后缀(被举报人)
  1011. func suffixContent(content string, gssp *param.GroupStateSetParam) string {
  1012. switch gssp.BlockReason {
  1013. // 剧透, 广告, 抢楼, 刷屏
  1014. case credit.ReasonSpoiler, credit.ReasonGarbageAds, credit.ReasonGrabFloor, credit.ReasonBrushScreen:
  1015. content += model.NotifyComRules
  1016. // 引战, 人身攻击
  1017. case credit.ReasonLeadBattle, credit.ReasonPersonalAttacks:
  1018. content += model.NotifyComProvoke
  1019. default:
  1020. content += model.NofityComProhibited
  1021. }
  1022. return content
  1023. }