admin.go 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894
  1. package service
  2. import (
  3. "context"
  4. "encoding/json"
  5. "fmt"
  6. "strconv"
  7. "time"
  8. "go-common/app/job/main/reply/model/reply"
  9. model "go-common/app/job/main/reply/model/reply"
  10. xsql "go-common/library/database/sql"
  11. "go-common/library/log"
  12. xtime "go-common/library/time"
  13. )
  14. const (
  15. _eventReportAdd = "report_add"
  16. _eventReportDel = "report_del"
  17. _eventReportIgnore = "report_ignore"
  18. _eventReportRecover = "report_recover"
  19. )
  20. func (s *Service) actionAdmin(c context.Context, msg *consumerMsg) {
  21. var d struct {
  22. Op string `json:"op"`
  23. Adid int64 `json:"adid"`
  24. AdName string `json:"adname"`
  25. Oid int64 `json:"oid"`
  26. RpID int64 `json:"rpid"`
  27. Mid int64 `json:"mid"`
  28. Tp int8 `json:"tp"`
  29. Action uint32 `json:"action"`
  30. Moral int `json:"moral"`
  31. Notify bool `json:"notify"`
  32. Remark string `json:"remark"`
  33. MTime xtime.Time `json:"mtime"`
  34. Ftime int64 `json:"ftime"`
  35. Audit int8 `json:"audit"`
  36. Reason int8 `json:"reason"`
  37. Content string `json:"content"`
  38. FReason int8 `json:"freason"`
  39. Assist bool `json:"assist"`
  40. State int8 `json:"state"`
  41. }
  42. if err := json.Unmarshal([]byte(msg.Data), &d); err != nil {
  43. log.Error("json.Unmarshal() error(%v)", err)
  44. return
  45. }
  46. if d.Oid <= 0 || d.RpID <= 0 {
  47. log.Error("The structure of msg.Data(%s) was wrong", msg.Data)
  48. return
  49. }
  50. rp, err := s.getReply(c, d.Oid, d.RpID)
  51. if err != nil {
  52. log.Error("s.getReply failed , oid(%d), RpID(%d) err(%v)", d.Oid, d.RpID, err)
  53. return
  54. }
  55. if rp == nil {
  56. log.Error("getReply nil oid(%d) RpID(%d)", d.Oid, d.RpID)
  57. return
  58. }
  59. switch {
  60. case d.Op == "del":
  61. s.adminDel(c, rp, d.Adid, d.Mid, d.Ftime, d.Moral, d.AdName, d.Remark, d.MTime, d.Notify, d.Reason, d.FReason)
  62. case d.Op == "del_rpt":
  63. s.reportDel(c, rp, d.Adid, d.Mid, d.Ftime, d.Moral, d.AdName, d.Remark, d.MTime, d.Notify, d.Audit, d.Reason, d.Content, d.FReason)
  64. case d.Op == "del_up":
  65. s.userDel(c, rp, d.Mid, d.MTime, d.Remark, d.Assist)
  66. case d.Op == "re", d.Op == "pass":
  67. s.passReply(c, rp, d.MTime, d.Adid, d.Remark, d.Op)
  68. case d.Op == "edit":
  69. s.addSearchUp(c, rp.State, rp, nil)
  70. case d.Op == "ignore":
  71. s.reportIgnore(c, rp, d.Audit, d.MTime, d.Adid, d.Remark)
  72. case d.Op == "transfer":
  73. s.reportTransfer(c, rp, d.Audit, d.MTime, d.Adid, d.Remark)
  74. case d.Op == "stateset":
  75. s.reportStateSet(c, rp, d.State, d.MTime, d.Adid, d.Remark)
  76. case d.Op == "top_add":
  77. err := s.topAdd(c, rp, d.MTime, d.Action, model.SubAttrAdminTop)
  78. if err != nil {
  79. log.Error("s.topAdd(oid:%d,tp:%d err(%v))", rp.Oid, rp.Type, err)
  80. return
  81. }
  82. // s.dao.Redis.AddTopOid(c, rp.Oid, rp.Type)
  83. s.adminLog(c, rp, d.Adid, model.AdminIsReport, model.AdminOperSubTop, "管理员置顶评论", d.Remark)
  84. s.addSearchUp(c, rp.State, rp, nil)
  85. case d.Op == "rpt_re":
  86. s.reportRecover(c, rp, d.Audit, d.MTime, d.Adid, d.Remark)
  87. }
  88. }
  89. func (s *Service) reportStateSet(c context.Context, rp *model.Reply, state int8, mtime xtime.Time, adid int64, remark string) (err error) {
  90. var (
  91. op int8
  92. result string
  93. oldState = rp.State
  94. )
  95. rpt, err := s.dao.Report.Get(c, rp.Oid, rp.RpID)
  96. if err != nil || rpt == nil {
  97. log.Error("dao.Report.GetReport(%d, %d) met error (%v)", rp.Oid, rp.RpID, err)
  98. return
  99. }
  100. rpt.State = state
  101. rpt.MTime = mtime
  102. op = model.AdminOperRptTransferArbitration
  103. if adid == 0 {
  104. result = "系统自动移交至风纪委"
  105. } else {
  106. result = "管理员移交至风纪委"
  107. }
  108. if _, err = s.dao.Report.Update(c, rpt); err != nil {
  109. log.Error("dao.Report.Update(%v) error(%v)", rpt, err)
  110. return
  111. }
  112. // admin log
  113. s.adminLog(c, rp, adid, model.AdminIsReport, op, result, remark)
  114. s.addSearchUp(c, oldState, rp, rpt)
  115. return
  116. }
  117. func (s *Service) reportTransfer(c context.Context, rp *model.Reply, audit int8, mtime xtime.Time, adid int64, remark string) (err error) {
  118. var (
  119. op int8
  120. result string
  121. oldState = rp.State
  122. )
  123. rpt, err := s.dao.Report.Get(c, rp.Oid, rp.RpID)
  124. if err != nil || rpt == nil {
  125. log.Error("dao.Report.GetReport(%d, %d) met error (%v)", rp.Oid, rp.RpID, err)
  126. return
  127. }
  128. if rpt.IsTransferred() {
  129. log.Error("report(%v) has been transfferd before!", *rpt)
  130. return
  131. }
  132. if audit == model.AuditTypeOne {
  133. rpt.State = model.ReportStateNew
  134. op = model.AdminOperRptTransfer1
  135. result = "二审转一审"
  136. } else if audit == model.AuditTypeTwo {
  137. rpt.State = model.ReportStateNewTwo
  138. op = model.AdminOperRptTransfer2
  139. result = "一审转二审"
  140. }
  141. rpt.MTime = mtime
  142. rpt.SetTransferred()
  143. if _, err = s.dao.Report.Update(c, rpt); err != nil {
  144. log.Error("dao.Report.Update(%v) error(%v)", rpt, err)
  145. return
  146. }
  147. // admin log
  148. s.adminLog(c, rp, adid, model.AdminIsReport, op, result, remark)
  149. s.addSearchUp(c, oldState, rp, rpt)
  150. return
  151. }
  152. func (s *Service) reportIgnore(c context.Context, rp *model.Reply, audit int8, mtime xtime.Time, adid int64, remark string) (err error) {
  153. var (
  154. op int8
  155. result string
  156. oldState = rp.State
  157. )
  158. rpt, err := s.dao.Report.Get(c, rp.Oid, rp.RpID)
  159. if err != nil || rpt == nil {
  160. log.Error("dao.Report.GetReport(%d, %d) met error (%v)", rp.Oid, rp.RpID, err)
  161. return
  162. }
  163. if audit == model.AuditTypeOne {
  164. rpt.State = model.ReportStateIgnoreOne
  165. op = model.AdminOperRptIgnore1
  166. result = "一审忽略"
  167. } else if audit == model.AuditTypeTwo {
  168. rpt.State = model.ReportStateIgnoreTwo
  169. op = model.AdminOperRptIgnore2
  170. result = "二审忽略"
  171. } else {
  172. if rpt.State == model.ReportStateNew {
  173. rpt.State = model.ReportStateIgnoreOne
  174. } else {
  175. rpt.State = model.ReportStateIgnoreTwo
  176. }
  177. op = model.AdminOperIgnoreReport
  178. result = "已忽略举报"
  179. }
  180. rpt.MTime = mtime
  181. if _, err = s.dao.Report.Update(c, rpt); err != nil {
  182. log.Error("dao.Report.Update(%v) error(%v)", rpt, err)
  183. return
  184. }
  185. // admin log
  186. s.adminLog(c, rp, adid, model.AdminIsReport, op, result, remark)
  187. s.addSearchUp(c, oldState, rp, rpt)
  188. sub, err := s.getSubject(c, rp.Oid, rp.Type)
  189. if err != nil || sub == nil {
  190. log.Error("s.getSubject(%v,%v) err(%v) or sub nil", sub.Oid, sub.Type, err)
  191. return
  192. }
  193. if err = s.dao.PubEvent(c, _eventReportIgnore, rpt.Mid, sub, rp, rpt); err != nil {
  194. return
  195. }
  196. return
  197. }
  198. func (s *Service) reportRecover(c context.Context, rp *model.Reply, audit int8, mtime xtime.Time, adid int64, remark string) (err error) {
  199. var (
  200. ok bool
  201. op int8
  202. result string
  203. rootRp *model.Reply
  204. oldState = rp.State
  205. )
  206. isRoot := rp.Root == 0 && rp.Parent == 0
  207. rpt, _ := s.dao.Report.Get(c, rp.Oid, rp.RpID)
  208. if err != nil || rpt == nil {
  209. log.Error("dao.Report.GetReport(%d, %d) met error (%v)", rp.Oid, rp.RpID, err)
  210. return
  211. }
  212. sub, err := s.getSubject(c, rp.Oid, rp.Type)
  213. if err != nil || sub == nil {
  214. log.Error("s.getSubject(%v,%v) err(%v) or sub nil", sub.Oid, sub.Type, err)
  215. return
  216. }
  217. if audit == model.AuditTypeOne {
  218. // 一审移除,恢复到待一审忽略,评论正常
  219. rpt.State = model.ReportStateIgnoreOne
  220. op = model.AdminOperRptRecover1
  221. result = "一审恢复评论"
  222. } else if audit == model.AuditTypeTwo {
  223. // 二审移除,恢复到二审忽略,评论正常
  224. rpt.State = model.ReportStateIgnoreTwo
  225. op = model.AdminOperRptRecover2
  226. result = "二审恢复评论"
  227. } else {
  228. log.Error("reportRecover unsupport audit: %d", audit)
  229. return
  230. }
  231. rpt.MTime = mtime
  232. if _, err = s.dao.Report.Update(c, rpt); err != nil {
  233. log.Error("dao.Report.Update(%v) error(%v) or row==0", rpt, err)
  234. return
  235. }
  236. // 只恢复管理员删除的评论,不恢复用户删除的
  237. if rp.State == model.ReplyStateAdminDel {
  238. rp.MTime = mtime
  239. rp.State = model.ReplyStateNormal
  240. if err = s.tranRecover(c, rp, model.ReplyStateNormal, isRoot); err != nil {
  241. log.Error("Transaction recover reply failed err(%v)", err)
  242. return
  243. }
  244. }
  245. // add cache
  246. if isRoot {
  247. if err = s.dao.Mc.AddReply(c, rp); err != nil {
  248. log.Error("s.dao.Mc.AddReply failed , RpID(%d), err(%v)", rp.RpID, err)
  249. }
  250. if err = s.dao.Redis.AddIndex(c, rp.Oid, rp.Type, rpt, rp, true); err != nil {
  251. log.Error("s.dao.Redis.AddIndex(%d, %d) error(%v)", rp.Oid, rp.Type, err)
  252. }
  253. } else {
  254. if ok, err = s.dao.Redis.ExpireNewChildIndex(c, rp.Root); err == nil && ok {
  255. if err = s.dao.Redis.AddNewChildIndex(c, rp.Root, rp); err != nil {
  256. log.Error("s.dao.Redis.AddFloorIndexByRoot failed , rproot(%d), err(%v)", rp.Root, err)
  257. }
  258. }
  259. if rootRp, err = s.getReplyCache(c, rp.Oid, rp.Root); err != nil {
  260. log.Error("s.getReply failed , oid(%d), root(%d) err(%v)", rp.Oid, rp.Root, err)
  261. } else if rootRp != nil {
  262. rootRp.RCount++
  263. if err = s.dao.Mc.AddReply(c, rootRp); err != nil {
  264. log.Error("s.dao.Mc.AddReply failed , RpID(%d) err(%v)", rootRp.RpID, err)
  265. }
  266. }
  267. }
  268. // log
  269. s.adminLog(c, rp, adid, model.AdminIsReport, op, result, remark)
  270. // notify
  271. s.addSearchUp(c, oldState, rp, rpt)
  272. s.upAcount(c, sub.Oid, sub.Type, sub.ACount, rp.CTime.Time())
  273. if err = s.dao.PubEvent(c, _eventReportRecover, rpt.Mid, sub, rp, rpt); err != nil {
  274. return
  275. }
  276. return
  277. }
  278. // topAdd add top reply
  279. func (s *Service) topAdd(c context.Context, rp *model.Reply, ts xtime.Time, act uint32, tp uint32) (err error) {
  280. sub, err := s.getSubject(c, rp.Oid, rp.Type)
  281. if err != nil || sub == nil {
  282. log.Error("s.getsubject(%v,%v) err(%v) or sub nil", rp.Oid, rp.Type, err)
  283. return
  284. }
  285. if act == 1 && sub.AttrVal(tp) == 1 {
  286. log.Error("Repeat to add top reply(%d,%d,%d,%d) ", rp.RpID, rp.Oid, tp, sub.Attr)
  287. return
  288. }
  289. err = sub.TopSet(rp.RpID, tp, act)
  290. if err != nil {
  291. log.Error("sub.TopSet(%d,%d,%d) failed!err:=%v ", rp.RpID, rp.Oid, tp, err)
  292. return
  293. }
  294. sub.AttrSet(act, tp)
  295. rp.AttrSet(act, tp)
  296. tx, err := s.beginTran(c)
  297. if err != nil {
  298. log.Error("s.beginTran() err(%v)", err)
  299. return
  300. }
  301. var rows int64
  302. //rp.State = model.ReplyStateTop
  303. if rows, err = s.dao.Reply.TxUpAttr(tx, rp.Oid, rp.RpID, rp.Attr, ts.Time()); err != nil || rows == 0 {
  304. tx.Rollback()
  305. log.Error("dao.Reply.UpState(%v, %d) error(%v) or row==0", rp, rp.State, err)
  306. return
  307. }
  308. if rows, err = s.dao.Subject.TxUpMeta(tx, sub.Oid, sub.Type, sub.Meta, ts.Time()); err != nil || rows == 0 {
  309. tx.Rollback()
  310. log.Error("dao.TxUpMeta(oid:%d,tp:%d) err(%v) rows(%d)", sub.Oid, sub.Type, err, rows)
  311. return
  312. }
  313. if rows, err = s.dao.Subject.TxUpAttr(tx, sub.Oid, sub.Type, sub.Attr, ts.Time()); err != nil || rows == 0 {
  314. tx.Rollback()
  315. log.Error("dao.Upattr(oid:%d,tp:%d) err(%v) rows(%d)", sub.Oid, sub.Type, err, rows)
  316. return
  317. }
  318. tx.Commit()
  319. s.dao.Mc.AddSubject(c, sub)
  320. if act == 1 {
  321. s.dao.Redis.DelIndexBySortType(c, rp, reply.SortByCount)
  322. s.dao.Redis.DelIndexBySortType(c, rp, reply.SortByLike)
  323. } else if rp.IsNormal() {
  324. if ok, err := s.dao.Redis.ExpireIndex(c, sub.Oid, sub.Type, model.SortByCount); err == nil && ok {
  325. if err = s.dao.Redis.AddCountIndex(c, sub.Oid, sub.Type, rp); err != nil {
  326. log.Error("s.dao.Redis.AddCountIndex failed , oid(%d) type(%d) err(%v)", sub.Oid, sub.Type, err)
  327. }
  328. }
  329. if ok, err := s.dao.Redis.ExpireIndex(c, sub.Oid, sub.Type, model.SortByLike); err == nil && ok {
  330. rpts := make(map[int64]*reply.Report, 1)
  331. if rpt, _ := s.dao.Report.Get(c, rp.Oid, rp.RpID); rpt != nil {
  332. rpts[rp.RpID] = rpt
  333. }
  334. if err = s.dao.Redis.AddLikeIndex(c, sub.Oid, sub.Type, rpts, rp); err != nil {
  335. log.Error("s.dao.Redis.AddLikeIndex failed , oid(%d) type(%d) err(%v)", sub.Oid, sub.Type, err)
  336. }
  337. }
  338. }
  339. s.dao.Mc.AddReply(c, rp)
  340. s.dao.Mc.AddTop(c, rp)
  341. if act == 1 {
  342. s.dao.PubEvent(c, "top", 0, sub, rp, nil)
  343. } else if act == 0 {
  344. s.dao.PubEvent(c, "untop", 0, sub, rp, nil)
  345. }
  346. // 折叠评论被置顶自动取消折叠
  347. if rp.IsFolded() && act == 1 {
  348. rp.State = model.ReplyStateNormal
  349. s.marker.Do(c, func(ctx context.Context) {
  350. if _, err := s.dao.Reply.UpState(ctx, rp.Oid, rp.RpID, rp.State, time.Now()); err == nil {
  351. if ok, err := s.dao.Redis.ExpireIndex(c, rp.Oid, rp.Type, model.SortByFloor); err == nil && ok {
  352. s.dao.Redis.AddFloorIndex(c, rp.Oid, rp.Type, rp)
  353. }
  354. s.handleFolded(ctx, rp)
  355. }
  356. })
  357. }
  358. return
  359. }
  360. func (s *Service) userDel(c context.Context, rp *model.Reply, mid int64, mtime xtime.Time, remark string, assist bool) (err error) {
  361. var (
  362. state int8
  363. sub *model.Subject
  364. oldState = rp.State
  365. isRoot = rp.Root == 0 && rp.Parent == 0
  366. isFolded = rp.IsFolded()
  367. )
  368. if rp.IsDeleted() {
  369. s.addSearchUp(c, oldState, rp, nil)
  370. return
  371. }
  372. if sub, err = s.dao.Subject.Get(c, rp.Oid, rp.Type); err != nil || sub == nil {
  373. log.Error("s.dao.Subject.Get(%d,%d) error(%v)", rp.Oid, rp.Type, err)
  374. return
  375. }
  376. if rp.Mid == mid {
  377. state = model.ReplyStateUserDel
  378. } else if assist {
  379. state = model.ReplyStateAssistDel
  380. } else if mid > 0 {
  381. state = model.ReplyStateUpDel
  382. } else {
  383. state = model.ReplyStateAdminDel
  384. }
  385. rp.MTime = mtime
  386. if err = s.tranDel(c, rp, state, sub, isRoot); err != nil {
  387. log.Error("reportDel tranDel(%d, %d) error(%v)", rp.Oid, rp.RpID, err)
  388. return
  389. }
  390. if isFolded {
  391. s.marker.Do(c, func(ctx context.Context) {
  392. s.handleFolded(ctx, rp)
  393. })
  394. }
  395. if err = s.clearReplyCache(c, rp); err != nil {
  396. log.Error("reportDel clearReplyCache(%d, %d) error(%v)", rp.Oid, rp.RpID, err)
  397. }
  398. rp.State = state
  399. if rp.Mid == mid {
  400. s.adminLog(c, rp, mid, model.AdminIsNotReport, model.AdminOperDeleteUser, "由本人删除", remark)
  401. s.searchDao.DelReply(c, rp.RpID, sub.Oid, mid, state)
  402. } else if assist {
  403. s.adminLog(c, rp, mid, model.AdminIsNotReport, model.AdminOperDeleteAssist, "由UP主协管员删除", remark)
  404. s.addAssistLog(c, sub.Mid, mid, sub.Oid, 1, 1, strconv.FormatInt(rp.RpID, 10), rp.Content.Message)
  405. } else if mid > 0 {
  406. s.adminLog(c, rp, mid, model.AdminIsNotReport, model.AdminOperDeleteUp, "由up主删除", remark)
  407. } else {
  408. s.adminLog(c, rp, 0, model.AdminIsNotReport, model.AdminOperDelete, "由系统删除", remark)
  409. }
  410. s.dao.PubEvent(c, "reply_del", rp.Mid, sub, rp, nil)
  411. return
  412. }
  413. func (s *Service) adminDel(c context.Context, rp *model.Reply, adid, mid, ftime int64, moral int, adName, remark string, mtime xtime.Time, notify bool, reason, freason int8) (err error) {
  414. var (
  415. sub *model.Subject
  416. report *model.Report
  417. oldState = rp.State
  418. isRoot = rp.Root == 0 && rp.Parent == 0
  419. isFolded = rp.IsFolded()
  420. )
  421. if rp.IsDeleted() {
  422. s.addSearchUp(c, oldState, rp, nil)
  423. return
  424. }
  425. if sub, err = s.dao.Subject.Get(c, rp.Oid, rp.Type); err != nil || sub == nil {
  426. log.Error("s.dao.Subject.Get(%d,%d) error(%v)", rp.Oid, rp.Type, err)
  427. return
  428. }
  429. rp.MTime = mtime
  430. if err = s.tranDel(c, rp, model.ReplyStateAdminDel, sub, isRoot); err != nil {
  431. log.Error("reportDel tranDel(%d, %d) error(%v)", rp.Oid, rp.RpID, err)
  432. return
  433. }
  434. if isFolded {
  435. s.marker.Do(c, func(ctx context.Context) {
  436. s.handleFolded(ctx, rp)
  437. })
  438. }
  439. if err = s.clearReplyCache(c, rp); err != nil {
  440. log.Error("reportDel clearReplyCache(%d, %d) error(%v)", rp.Oid, rp.RpID, err)
  441. }
  442. if report, err = s.dao.Report.Get(c, rp.Oid, rp.RpID); err != nil {
  443. log.Error("reportDel getReport(%d,%d) error(%v)", rp.Oid, rp.RpID, err)
  444. return
  445. }
  446. if report != nil {
  447. if report.State == model.ReportStateNew || report.State == model.ReportStateNewTwo {
  448. if report.State == model.ReportStateNew {
  449. report.State = model.ReportStateDeleteOne
  450. } else if report.State == model.ReportStateNewTwo {
  451. report.State = model.ReportStateDeleteTwo
  452. }
  453. report.MTime = mtime
  454. if _, err = s.dao.Report.Update(c, report); err != nil {
  455. log.Error("reportDel updateReport(%d, %d) error(%v)", report.Oid, report.ID, err)
  456. return
  457. }
  458. s.addSearchUp(c, oldState, rp, report)
  459. s.dao.PubEvent(c, _eventReportDel, 0, sub, rp, report)
  460. }
  461. }
  462. rp.State = model.ReplyStateAdminDel
  463. // add moral and notify
  464. s.moralAndNotify(c, rp, moral, notify, mid, adid, adName, remark, reason, freason, ftime, false)
  465. // forbidden tip
  466. forbidDay := strconv.FormatInt(ftime, 10) + "天"
  467. if ftime == -1 {
  468. forbidDay = "永久"
  469. }
  470. s.adminLog(c, rp, adid, model.AdminIsNotReport, model.AdminOperDelete, fmt.Sprintf("已删除并封禁%s/扣除%d节操", forbidDay, moral), remark)
  471. s.addSearchUp(c, oldState, rp, nil)
  472. if report == nil {
  473. s.dao.PubEvent(c, "reply_del", 0, sub, rp, nil)
  474. }
  475. return
  476. }
  477. func (s *Service) reportDel(c context.Context, rp *model.Reply, adid, mid, ftime int64, moral int, adName, remark string, mtime xtime.Time, notify bool, audit int8, reason int8, content string, freason int8) (err error) {
  478. var (
  479. op int8
  480. isPunish bool
  481. sub *model.Subject
  482. report *model.Report
  483. oldState = rp.State
  484. )
  485. if sub, err = s.dao.Subject.Get(c, rp.Oid, rp.Type); err != nil || sub == nil {
  486. log.Error("s.dao.Subject.Get(%d,%d) error(%v)", rp.Oid, rp.Type, err)
  487. return
  488. }
  489. if report, err = s.dao.Report.Get(c, rp.Oid, rp.RpID); err != nil || report == nil {
  490. log.Error("reportDel getReport(%d,%d) error(%v)", rp.Oid, rp.RpID, err)
  491. return
  492. }
  493. report.MTime = mtime
  494. // 一审、二审操作
  495. switch audit {
  496. case model.AuditTypeOne:
  497. report.State = model.ReportStateDeleteOne
  498. op = model.AdminOperRptDel1
  499. case model.AuditTypeTwo:
  500. report.State = model.ReportStateDeleteTwo
  501. op = model.AdminOperRptDel2
  502. default:
  503. report.State = model.ReportStateDelete
  504. op = model.AdminOperDeleteByReport
  505. }
  506. report.Reason = reason
  507. report.Content = content
  508. if _, err = s.dao.Report.Update(c, report); err != nil {
  509. log.Error("reportDel updateReport(%d, %d) error(%v)", report.Oid, report.ID, err)
  510. return
  511. }
  512. if !rp.IsDeleted() {
  513. isRoot := rp.Root == 0 && rp.Parent == 0
  514. rp.MTime = mtime
  515. if err = s.tranDel(c, rp, model.ReplyStateAdminDel, sub, isRoot); err != nil {
  516. log.Error("reportDel tranDel(%d, %d) error(%v)", rp.Oid, rp.RpID, err)
  517. return
  518. }
  519. if err = s.clearReplyCache(c, rp); err != nil {
  520. log.Error("reportDel clearReplyCache(%d, %d) error(%v)", rp.Oid, rp.RpID, err)
  521. }
  522. rp.State = model.ReplyStateAdminDel
  523. } else {
  524. isPunish = true
  525. }
  526. // add moral and notify
  527. s.moralAndNotify(c, rp, moral, notify, mid, adid, adName, remark, reason, freason, ftime, isPunish)
  528. // forbidden tip
  529. forbidDay := strconv.FormatInt(ftime, 10) + "天"
  530. if ftime == -1 {
  531. forbidDay = "永久"
  532. }
  533. s.adminLog(c, rp, adid, model.AdminIsReport, op, fmt.Sprintf("已通过举报删除并封禁%s/扣除%d节操", forbidDay, moral), remark)
  534. s.addSearchUp(c, oldState, rp, report)
  535. if err = s.dao.PubEvent(c, _eventReportDel, report.Mid, sub, rp, report); err != nil {
  536. return
  537. }
  538. return
  539. }
  540. func (s *Service) clearReplyCache(c context.Context, rp *model.Reply) (err error) {
  541. var (
  542. sub *model.Subject
  543. rootRp *model.Reply
  544. isRoot = rp.Root == 0 && rp.Parent == 0
  545. )
  546. if !isRoot && rp.IsNormal() {
  547. // update root cache for count.
  548. if rootRp, err = s.getReplyCache(c, rp.Oid, rp.Root); err != nil {
  549. return
  550. }
  551. if rootRp != nil {
  552. rootRp.RCount--
  553. if err = s.addReplyCache(c, rootRp); err != nil {
  554. log.Error("s.dao.Mc.addReplyCache(%d,%d,%d) error(%v)", rp.Oid, rp.Type, rp.RpID, err)
  555. }
  556. }
  557. }
  558. if rp.IsAdminTop() {
  559. s.dao.Mc.DeleteTop(c, rp, model.ReplyAttrAdminTop)
  560. }
  561. if rp.IsUpTop() {
  562. s.dao.Mc.DeleteTop(c, rp, model.ReplyAttrUpperTop)
  563. }
  564. if err = s.dao.Mc.DeleteReply(c, rp.RpID); err != nil {
  565. log.Error("s.dao.Mc.DeleteReply failed , RpID(%d), err(%v)", rp.RpID, err)
  566. }
  567. if err = s.dao.Redis.DelIndex(c, rp); err != nil {
  568. log.Error("s.dao.Redis.DelIndex failed , RpID(%d), err(%v)", rp.RpID, err)
  569. }
  570. if rp.State == model.ReplyStateAudit {
  571. s.eraseAuditIndex(c, rp)
  572. }
  573. // update reply count
  574. sub, err = s.dao.Subject.Get(c, rp.Oid, rp.Type)
  575. if err != nil || sub == nil {
  576. log.Error("s.dao.Subject.Get(%d,%d) error(%v)", rp.Oid, rp.Type, err)
  577. return
  578. }
  579. if err = s.dao.Mc.AddSubject(c, sub); err != nil {
  580. log.Error("s.dao.Mc.AddSubject failed , oid(%d), err(%v)", sub.Oid, err)
  581. }
  582. s.upAcount(c, sub.Oid, sub.Type, sub.ACount, rp.CTime.Time())
  583. return
  584. }
  585. func (s *Service) passReply(c context.Context, rp *model.Reply, mtime xtime.Time, adid int64, remark, op string) {
  586. var (
  587. err error
  588. ok bool
  589. rootRp *model.Reply
  590. oldState = rp.State
  591. isRoot = rp.Root == 0 && rp.Parent == 0
  592. )
  593. sub, err := s.dao.Subject.Get(c, rp.Oid, rp.Type)
  594. if err != nil || sub == nil {
  595. log.Error("s.dao.Subject.Get(%d,%d) error(%v)", rp.Oid, rp.Type, err)
  596. return
  597. }
  598. if rp.State <= model.ReplyStateHidden {
  599. s.addSearchUp(c, oldState, rp, nil)
  600. return
  601. }
  602. rp.MTime = mtime
  603. rp.State = model.ReplyStateNormal
  604. if op == "re" || oldState == model.ReplyStateAudit {
  605. if err = s.tranRecover(c, rp, model.ReplyStateNormal, isRoot); err != nil {
  606. log.Error("Transaction recover reply failed err(%v)", err)
  607. return
  608. }
  609. } else if op == "pass" {
  610. var row int64
  611. var tx *xsql.Tx
  612. tx, err = s.dao.BeginTran(c)
  613. if err != nil {
  614. return
  615. }
  616. if row, err = s.dao.Reply.TxUpState(tx, rp.Oid, rp.RpID, model.ReplyStateNormal, mtime.Time()); err != nil || row == 0 {
  617. tx.Rollback()
  618. log.Error("dao.Reply.TxUpState(%v, %d) error(%v) or row==0", rp, model.ReplyStateNormal, err)
  619. return
  620. }
  621. if rp.State == model.ReplyStateAudit || rp.State == model.ReplyStateMonitor {
  622. if _, err = s.dao.Subject.TxDecrMCount(tx, rp.Oid, rp.Type, mtime.Time()); err != nil {
  623. tx.Rollback()
  624. log.Error("dao.Reply.TxDecrMCount(%v) error(%v)", rp, err)
  625. return
  626. }
  627. }
  628. if err = tx.Commit(); err != nil {
  629. log.Error("tx.Commit error(%v)", err)
  630. return
  631. }
  632. }
  633. if isRoot {
  634. if ok, err = s.dao.Redis.ExpireIndex(c, rp.Oid, rp.Type, model.SortByFloor); err == nil && ok {
  635. var min int
  636. min, err = s.dao.Redis.MinScore(c, rp.Oid, rp.Type, reply.SortByFloor)
  637. if err != nil {
  638. log.Error("s.dao.Redis.AddFloorIndex failed , oid(%d) type(%d) err(%v)", rp.Oid, rp.Type, err)
  639. } else if rp.Floor > min {
  640. if err = s.dao.Redis.AddFloorIndex(c, rp.Oid, rp.Type, rp); err != nil {
  641. log.Error("s.dao.Redis.AddFloorIndex failed , RpID(%d), err(%v)", rp.RpID, err)
  642. }
  643. }
  644. }
  645. if ok, err = s.dao.Redis.ExpireIndex(c, rp.Oid, rp.Type, model.SortByCount); err == nil && ok {
  646. if err = s.dao.Redis.AddCountIndex(c, rp.Oid, rp.Type, rp); err != nil {
  647. log.Error("s.dao.Redis.AddCountIndex failed , RpID(%d), err(%v)", rp.RpID, err)
  648. }
  649. }
  650. if ok, err = s.dao.Redis.ExpireIndex(c, rp.Oid, rp.Type, model.SortByLike); err == nil && ok {
  651. rpts := make(map[int64]*reply.Report, 1)
  652. if rpt, _ := s.dao.Report.Get(c, rp.Oid, rp.RpID); rpt != nil {
  653. rpts[rp.RpID] = rpt
  654. }
  655. if err = s.dao.Redis.AddLikeIndex(c, rp.Oid, rp.Type, rpts, rp); err != nil {
  656. log.Error("s.dao.Redis.AddLikeIndex failed , RpID(%d), err(%v)", rp.RpID, err)
  657. }
  658. }
  659. } else {
  660. if ok, err = s.dao.Redis.ExpireDialogIndex(c, rp.Dialog); err == nil && ok {
  661. if err = s.dao.Redis.AddDialogIndex(c, rp.Dialog, []*model.Reply{rp}); err != nil {
  662. log.Error("s.dao.Redis.AddDialogINdex Error (%v)", err)
  663. }
  664. }
  665. if ok, err = s.dao.Redis.ExpireNewChildIndex(c, rp.Root); err == nil && ok {
  666. if err = s.dao.Redis.AddNewChildIndex(c, rp.Root, rp); err != nil {
  667. log.Error("s.dao.Redis.AddFloorIndexByRoot failed , rproot(%d), err(%v)", rp.Root, err)
  668. }
  669. }
  670. if op == "re" || oldState == model.ReplyStateAudit {
  671. if rootRp, err = s.getReplyCache(c, rp.Oid, rp.Root); err != nil {
  672. log.Error("s.getReply failed , oid(%d), root(%d) err(%v)", rp.Oid, rp.Root, err)
  673. } else if rootRp != nil {
  674. rootRp.RCount++
  675. if err = s.addReplyCache(c, rootRp); err != nil {
  676. log.Error("s.addReplyCache oid(%d), rpid(%d) err(%v)", rootRp.Oid, rootRp.RpID, err)
  677. }
  678. }
  679. }
  680. }
  681. if err = s.addReplyCache(c, rp); err != nil {
  682. log.Error("s.addReplyCache oid(%d), rpid(%d) err(%v)", rp.Oid, rp.RpID, err)
  683. }
  684. if oldState == model.ReplyStateAudit {
  685. s.dao.Redis.DelAuditIndexs(c, rp)
  686. }
  687. // update reply count
  688. s.upAcount(c, sub.Oid, sub.Type, sub.ACount, rp.CTime.Time())
  689. if err = s.dao.Mc.AddSubject(c, sub); err != nil {
  690. log.Error("s.dao.Mc.AddSubject failed , oid(%d) err(%v)", sub.Oid, err)
  691. }
  692. // admin log
  693. if op == "re" {
  694. s.adminLog(c, rp, adid, model.AdminIsNotReport, model.AdminOperRecover, "已恢复评论", remark)
  695. } else if op == "pass" {
  696. s.adminLog(c, rp, adid, model.AdminIsNotReport, model.AdminOperPass, "已通过评论", remark)
  697. }
  698. s.addSearchUp(c, oldState, rp, nil)
  699. }
  700. func (s *Service) tranRecover(c context.Context, rp *model.Reply, state int8, isRoot bool) error {
  701. var (
  702. err error
  703. rootReply *model.Reply
  704. count int
  705. rows int64
  706. tx *xsql.Tx
  707. )
  708. if tx, err = s.beginTran(c); err != nil {
  709. return err
  710. }
  711. mtime := rp.MTime
  712. if rp, err = s.dao.Reply.GetForUpdate(tx, rp.Oid, rp.RpID); err != nil || rp == nil {
  713. tx.Rollback()
  714. return fmt.Errorf("s.dao.Reply.GetForUpdate(%d,%d) error(%v) or is nil)", rp.Oid, rp.RpID, err)
  715. }
  716. if mtime != 0 {
  717. rp.MTime = mtime
  718. }
  719. if rp.IsNormal() {
  720. tx.Rollback()
  721. return fmt.Errorf("reply(%d,%d) already is normal", rp.Oid, rp.RpID)
  722. }
  723. rows, err = s.dao.Reply.TxUpState(tx, rp.Oid, rp.RpID, state, rp.MTime.Time())
  724. if err != nil || rows == 0 {
  725. tx.Rollback()
  726. return fmt.Errorf("TxUpState error(%v) or rows(%d)", err, rows)
  727. }
  728. if isRoot {
  729. count = rp.RCount + 1
  730. } else {
  731. rootReply, err = s.dao.Reply.Get(c, rp.Oid, rp.Root)
  732. if err != nil {
  733. tx.Rollback()
  734. return err
  735. }
  736. count = 1
  737. }
  738. if isRoot {
  739. rows, err = s.dao.Subject.TxIncrRCount(tx, rp.Oid, rp.Type, rp.MTime.Time())
  740. } else {
  741. rows, err = s.dao.Reply.TxIncrRCount(tx, rp.Oid, rp.Root, rp.MTime.Time())
  742. }
  743. if err != nil || rows == 0 {
  744. tx.Rollback()
  745. return fmt.Errorf("TxIncrRCount error(%v) or rows(%d)", err, rows)
  746. }
  747. if isRoot || rootReply != nil && rootReply.IsNormal() {
  748. rows, err = s.dao.Subject.TxIncrACount(tx, rp.Oid, rp.Type, count, rp.MTime.Time())
  749. if err != nil || rows == 0 {
  750. tx.Rollback()
  751. return fmt.Errorf("TxIncrACount error(%v) or rows(%d)", err, rows)
  752. }
  753. }
  754. return tx.Commit()
  755. }
  756. func (s *Service) tranDel(c context.Context, rp *model.Reply, state int8, sub *model.Subject, isRoot bool) error {
  757. var (
  758. count int
  759. rows int64
  760. rootReply *model.Reply
  761. err error
  762. tx *xsql.Tx
  763. )
  764. if tx, err = s.beginTran(c); err != nil {
  765. return err
  766. }
  767. mtime := rp.MTime
  768. if rp, err = s.dao.Reply.GetForUpdate(tx, rp.Oid, rp.RpID); err != nil || rp == nil {
  769. tx.Rollback()
  770. return fmt.Errorf("s.dao.Reply.GetForUpdate(%d,%d) error(%v) or is nil)", rp.Oid, rp.RpID, err)
  771. }
  772. if mtime != 0 {
  773. rp.MTime = mtime
  774. }
  775. if rp.IsDeleted() || rp.AttrVal(reply.ReplyAttrAdminTop) == 1 {
  776. tx.Rollback()
  777. return fmt.Errorf("reply(%d,%d) already deleted", rp.Oid, rp.RpID)
  778. }
  779. rows, err = s.dao.Reply.TxUpState(tx, rp.Oid, rp.RpID, state, rp.MTime.Time())
  780. if err != nil || rows == 0 {
  781. tx.Rollback()
  782. return fmt.Errorf("error(%v) or rows(%d)", err, rows)
  783. }
  784. if rp.IsNormal() {
  785. if isRoot {
  786. count = rp.RCount + 1
  787. rows, err = s.dao.Subject.TxDecrACount(tx, rp.Oid, rp.Type, count, rp.MTime.Time())
  788. if err != nil || rows == 0 {
  789. tx.Rollback()
  790. return fmt.Errorf("error(%v) or rows(%d)", err, rows)
  791. }
  792. rows, err = s.dao.Subject.TxDecrCount(tx, rp.Oid, rp.Type, rp.MTime.Time())
  793. if err != nil || rows == 0 {
  794. tx.Rollback()
  795. return fmt.Errorf("SubjectTxDecrCount error(%v) or rows(%d)", err, rows)
  796. }
  797. } else {
  798. if rootReply, err = s.dao.Reply.GetForUpdate(tx, rp.Oid, rp.Root); err != nil {
  799. tx.Rollback()
  800. return err
  801. }
  802. if rootReply != nil {
  803. if rootReply.IsNormal() {
  804. rows, err = s.dao.Subject.TxDecrACount(tx, rp.Oid, rp.Type, 1, rp.MTime.Time())
  805. if err != nil || rows == 0 {
  806. tx.Rollback()
  807. return fmt.Errorf("error(%v) or rows(%d)", err, rows)
  808. }
  809. }
  810. rows, err = s.dao.Reply.TxDecrCount(tx, rp.Oid, rp.Root, rp.MTime.Time())
  811. if err != nil || rows == 0 {
  812. tx.Rollback()
  813. return fmt.Errorf("ReplyTxDecrCount error(%v) or rows(%d)", err, rows)
  814. }
  815. }
  816. }
  817. }
  818. if rp.AttrVal(model.ReplyAttrUpperTop) == 1 {
  819. rp.AttrSet(0, model.ReplyAttrUpperTop)
  820. sub.AttrSet(0, model.SubAttrUpperTop)
  821. sub.TopSet(0, model.SubAttrUpperTop, 0)
  822. if rows, err = s.dao.Subject.TxUpMeta(tx, sub.Oid, sub.Type, sub.Meta, rp.MTime.Time()); err != nil || rows == 0 {
  823. tx.Rollback()
  824. log.Error("dao.TxUpMeta(oid:%d,tp:%d) err(%v) rows(%d)", sub.Oid, sub.Type, err, rows)
  825. return fmt.Errorf("dao.TxUpMeta(oid:%d,tp:%d) err(%v) rows(%d)", sub.Oid, sub.Type, err, rows)
  826. }
  827. if rows, err = s.dao.Subject.TxUpAttr(tx, sub.Oid, sub.Type, sub.Attr, rp.MTime.Time()); err != nil || rows == 0 {
  828. tx.Rollback()
  829. return fmt.Errorf("dao.Upattr(oid:%d,tp:%d) err(%v) rows(%d)", sub.Oid, sub.Type, err, rows)
  830. }
  831. //rp.State = model.ReplyStateTop
  832. if rows, err = s.dao.Reply.TxUpAttr(tx, rp.Oid, rp.RpID, rp.Attr, rp.MTime.Time()); err != nil || rows == 0 {
  833. tx.Rollback()
  834. return fmt.Errorf("dao.Reply.UpState(%v, %d) error(%v) or rows(%d)", rp, rp.State, err, rows)
  835. }
  836. }
  837. if rp.State == model.ReplyStateMonitor || rp.State == model.ReplyStateAudit {
  838. if _, err = s.dao.Subject.TxDecrMCount(tx, rp.Oid, rp.Type, rp.MTime.Time()); err != nil {
  839. tx.Rollback()
  840. log.Error("dao.Reply.TxDecrMCount(%v) error(%v)", rp, err)
  841. return fmt.Errorf("dao.Reply.TxDecrMCount error(%v)", err)
  842. }
  843. }
  844. return tx.Commit()
  845. }
  846. func (s *Service) eraseAuditIndex(c context.Context, rp *model.Reply) (err error) {
  847. var rs []*model.Reply
  848. if rp.Root == 0 && rp.Parent == 0 {
  849. if rs, err = s.dao.Reply.GetsByRoot(c, rp.Oid, rp.RpID, rp.Type, model.ReplyStateAudit); err != nil {
  850. return
  851. }
  852. }
  853. if err = s.dao.Redis.DelAuditIndexs(c, append(rs, rp)...); err != nil {
  854. return
  855. }
  856. return
  857. }
  858. func (s *Service) addReplyCache(c context.Context, rp *model.Reply) (err error) {
  859. var isRoot = rp.Root == 0 && rp.Parent == 0
  860. if err = s.dao.Mc.AddReply(c, rp); err != nil {
  861. log.Error("s.dao.Mc.AddReply(%d,%d,%d) error(%v)", rp.Oid, rp.RpID, rp.Type, err)
  862. }
  863. if isRoot && rp.IsTop() {
  864. if err = s.dao.Mc.AddTop(c, rp); err != nil {
  865. log.Error("s.dao.Mc.AddTop(%d,%d,%d) error(%v)", rp.Oid, rp.RpID, rp.Type, err)
  866. }
  867. }
  868. return
  869. }