advance.go 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. package service
  2. import (
  3. "context"
  4. "fmt"
  5. "go-common/app/interface/main/dm2/model"
  6. account "go-common/app/service/main/account/api"
  7. arcMdl "go-common/app/service/main/archive/model/archive"
  8. coinmdl "go-common/app/service/main/coin/model"
  9. relation "go-common/app/service/main/relation/model"
  10. "go-common/library/ecode"
  11. "go-common/library/log"
  12. )
  13. // BuyAdvance 购买高级弹幕
  14. func (s *Service) BuyAdvance(c context.Context, mid, cid int64, mode string) (err error) {
  15. var (
  16. refund = int64(1)
  17. coin = model.AdvSPCoin
  18. reason = model.AdvSPCoinReason
  19. advPermit int8
  20. )
  21. if !s.dao.AddAdvanceLock(c, cid, mid) {
  22. return
  23. }
  24. defer s.dao.DelAdvanceLock(c, cid, mid)
  25. reply, err := s.accountRPC.Info3(c, &account.MidReq{Mid: mid})
  26. if err != nil {
  27. log.Error("s.accRPC.Info3(%d) error(%v)", mid, err)
  28. return
  29. }
  30. if s.isSuperUser(reply.GetInfo().GetRank()) {
  31. return
  32. }
  33. if mode != model.AdvSpeMode { // pool=2 弹幕
  34. coin = model.AdvCoin
  35. reason = model.AdvCoinReason
  36. }
  37. typ, err := s.dao.AdvanceType(c, cid, mid, mode)
  38. if err != nil {
  39. log.Error("dao.AdvanceType(%d,%d,%s) error(%v)", cid, mid, mode, err)
  40. return
  41. }
  42. sub, err := s.subject(c, model.SubTypeVideo, cid)
  43. if err != nil {
  44. return
  45. }
  46. if typ != "" { // 已有购买记录
  47. if typ == model.AdvTypeRequest && mid != sub.Mid {
  48. err = ecode.DMAdvConfirm
  49. } else {
  50. err = ecode.DMAdvBought
  51. }
  52. return
  53. }
  54. if mid != sub.Mid {
  55. advPermit, err = s.dao.UpperConfig(c, sub.Mid)
  56. if err != nil {
  57. return
  58. }
  59. if err = s.checkAdvancePermit(c, advPermit, sub.Mid, mid); err != nil {
  60. return
  61. }
  62. }
  63. typ = model.AdvTypeRequest
  64. if sub.Mid == mid {
  65. typ = model.AdvTypeBuy
  66. }
  67. coins, err := s.coinRPC.UserCoins(c, &coinmdl.ArgCoinInfo{Mid: mid})
  68. if err != nil {
  69. log.Error("coinRPC.UserCoins(%v) error(%v)", mid, err)
  70. return
  71. }
  72. if coins < float64(coin) {
  73. err = ecode.LackOfCoins
  74. return
  75. }
  76. if _, err = s.dao.BuyAdvance(c, mid, cid, sub.Mid, refund, typ, mode); err != nil {
  77. return
  78. }
  79. if _, err = s.coinRPC.ModifyCoin(c, &coinmdl.ArgModifyCoin{Mid: mid, Count: -float64(coin), Reason: reason, CheckZero: 1}); err != nil {
  80. log.Error("coinRPC.ModifyCoin(%v,%v,%v) error(%v)", mid, coin, reason, err)
  81. return
  82. }
  83. if err = s.dao.DelAdvCache(c, mid, cid, mode); err != nil {
  84. return
  85. }
  86. s.cache.Do(c, func(ctx context.Context) {
  87. arc, err := s.arcRPC.Archive3(ctx, &arcMdl.ArgAid2{Aid: sub.Pid})
  88. if err != nil {
  89. log.Error("s.arcRPC.Archive3(aid:%d) error(%v)", sub.Pid, err)
  90. return
  91. }
  92. title := "您收到了一条高级弹幕请求"
  93. content := fmt.Sprintf(`您的稿件《%s》收到了一条高级弹幕请求,#{立即处理}{"https://member.bilibili.com/v/#/danmu/report/advance"}`, arc.Title)
  94. s.dao.SendNotify(ctx, title, content, "4", []int64{sub.Mid})
  95. })
  96. return
  97. }
  98. func (s *Service) checkAdvancePermit(c context.Context, advPermit int8, upid, mid int64) (err error) {
  99. switch advPermit {
  100. case model.AdvPermitAll:
  101. return
  102. case model.AdvPermitFollower, model.AdvPermitAttention:
  103. var (
  104. arg = &relation.ArgMid{Mid: upid}
  105. res = make([]*relation.Following, 0)
  106. follower *relation.Following
  107. )
  108. if res, err = s.relRPC.Followers(c, arg); err != nil {
  109. log.Error("relRPC.Followers(%+v) error(%v)", arg, err)
  110. return
  111. }
  112. for _, v := range res {
  113. if v.Mid == mid {
  114. follower = v
  115. break
  116. }
  117. }
  118. if follower == nil {
  119. err = ecode.DMAdvNotAllow
  120. return
  121. }
  122. if advPermit == model.AdvPermitAttention && follower.Attribute != 6 { // Attribute=6为相互关注
  123. err = ecode.DMAdvNotAllow
  124. return
  125. }
  126. case model.AdvPermitForbid:
  127. err = ecode.DMAdvNotAllow
  128. return
  129. }
  130. return
  131. }
  132. // AdvanceState 高级弹幕状态
  133. func (s *Service) AdvanceState(c context.Context, mid, cid int64, mode string) (state *model.AdvState, err error) {
  134. state = &model.AdvState{
  135. Accept: true,
  136. Coins: model.AdvSPCoin,
  137. Confirm: model.AdvStatConfirmDefault,
  138. }
  139. if mode == model.AdvMode { // pool=2 弹幕
  140. state.Coins = model.AdvCoin
  141. }
  142. reply, err := s.accountRPC.Info3(c, &account.MidReq{Mid: mid})
  143. if err != nil {
  144. log.Error("s.accRPC.Info3(%d) error(%v)", mid, err)
  145. return
  146. }
  147. if s.isSuperUser(reply.GetInfo().GetRank()) {
  148. state.HasBuy = true
  149. state.Confirm = model.AdvStatConfirmAgree
  150. return
  151. }
  152. typ, err := s.dao.AdvanceType(c, cid, mid, mode)
  153. if err != nil {
  154. return
  155. }
  156. switch typ {
  157. case model.AdvTypeAccept, model.AdvTypeBuy: // 已通过
  158. state.Confirm = model.AdvStatConfirmAgree
  159. state.HasBuy = true
  160. case model.AdvTypeRequest: // 正在确认中
  161. state.Confirm = model.AdvStatConfirmRequest
  162. state.HasBuy = true
  163. case model.AdvTypeDeny: // up 主拒绝
  164. state.Confirm = model.AdvStatConfirmDeny
  165. state.HasBuy = true
  166. }
  167. return
  168. }
  169. // Advances 高级弹幕申请列表
  170. func (s *Service) Advances(c context.Context, mid int64) (res []*model.Advance, err error) {
  171. var (
  172. cidMap = make(map[int64]bool)
  173. midMap = make(map[int64]bool)
  174. mids = make([]int64, 0)
  175. cidAidMap = make(map[int64]int64)
  176. aids = make([]int64, 0)
  177. )
  178. list, err := s.dao.Advances(c, mid)
  179. if err != nil {
  180. log.Error("dao.Advances(%d) error(%v)", mid, err)
  181. return
  182. }
  183. if len(list) == 0 {
  184. return
  185. }
  186. res = make([]*model.Advance, 0, len(list))
  187. for _, l := range list {
  188. if _, ok := midMap[l.Mid]; !ok {
  189. midMap[l.Mid] = true
  190. mids = append(mids, l.Mid)
  191. }
  192. cidMap[l.Cid] = true
  193. }
  194. for cid := range cidMap { // get cids->aids
  195. var sub *model.Subject
  196. if sub, err = s.subject(c, model.SubTypeVideo, cid); err != nil {
  197. log.Error("s.subject(%d) error(%v)", cid, err)
  198. return
  199. }
  200. if sub == nil {
  201. err = ecode.NothingFound
  202. continue
  203. }
  204. if _, ok := cidAidMap[sub.Oid]; !ok {
  205. cidAidMap[sub.Oid] = sub.Pid
  206. aids = append(aids, sub.Pid)
  207. }
  208. }
  209. arcs, err := s.archiveInfos(c, aids) // get archiveinfos
  210. if err != nil {
  211. return
  212. }
  213. reply, err := s.accountRPC.Infos3(c, &account.MidsReq{
  214. Mids: mids,
  215. })
  216. if err != nil {
  217. log.Error("s.accRPC.Infos3(%v) error(%v)", mids, err)
  218. return
  219. }
  220. for _, v := range list {
  221. if aid, ok := cidAidMap[v.Cid]; ok {
  222. v.Aid = aid
  223. } else {
  224. continue
  225. }
  226. if archive, ok := arcs[v.Aid]; ok {
  227. v.Title = archive.Title
  228. v.Cover = archive.Pic
  229. }
  230. if user, ok := reply.GetInfos()[v.Mid]; ok {
  231. v.Uname = user.Name
  232. }
  233. res = append(res, v)
  234. }
  235. return
  236. }
  237. // PassAdvance 通过高级弹幕申请
  238. func (s *Service) PassAdvance(c context.Context, mid, id int64) (err error) {
  239. adv, err := s.dao.Advance(c, mid, id)
  240. if err != nil {
  241. log.Error("dao.Advance(%d,%d) error(%v)", mid, id, err)
  242. return
  243. }
  244. if adv == nil || adv.Type == model.AdvTypeDeny {
  245. err = ecode.DMAdvNoFound
  246. return
  247. }
  248. if adv.Type == model.AdvTypeAccept {
  249. return
  250. }
  251. if _, err = s.dao.UpdateAdvType(c, id, model.AdvTypeAccept); err != nil {
  252. log.Error("dao.UpdateAdvType(%d,%d,%s) error(%v)", mid, id, model.AdvTypeAccept, err)
  253. return
  254. }
  255. if err = s.dao.DelAdvCache(c, adv.Mid, adv.Cid, adv.Mode); err != nil {
  256. log.Error("dao.DelAdvCache(%+v) error(%v)", adv, err)
  257. }
  258. return
  259. }
  260. // DenyAdvance 拒绝高级弹幕申请
  261. func (s *Service) DenyAdvance(c context.Context, mid, id int64) (err error) {
  262. var (
  263. coin float64
  264. reason string
  265. af int64
  266. )
  267. adv, err := s.dao.Advance(c, mid, id)
  268. if err != nil {
  269. log.Error("dao.Advance(%d,%d) error(%v)", mid, id, err)
  270. return
  271. }
  272. if adv == nil {
  273. return
  274. }
  275. if len(adv.Type) == 0 || adv.Type == model.AdvTypeDeny {
  276. err = ecode.DMAdvNoFound
  277. return
  278. }
  279. if af, err = s.dao.UpdateAdvType(c, id, model.AdvTypeDeny); err != nil {
  280. log.Error("dao.UpdateAdvType(%d) error(%v)", id, err)
  281. return
  282. }
  283. if err = s.dao.DelAdvCache(c, adv.Mid, adv.Cid, adv.Mode); err != nil {
  284. log.Error("dao.DelAdvCache(%+v) error(%v)", adv, err)
  285. return
  286. }
  287. if af < 1 {
  288. err = ecode.DMAdvNoFound
  289. return
  290. }
  291. if adv.Refund == 0 {
  292. return
  293. }
  294. coin = model.AdvSPCoin
  295. reason = model.AdvSPCoinCancelReason
  296. if adv.Mode == model.AdvMode {
  297. coin = model.AdvCoin
  298. reason = model.AdvCoinCancelReason
  299. }
  300. if _, err = s.coinRPC.ModifyCoin(c, &coinmdl.ArgModifyCoin{Mid: adv.Mid, Count: coin, Reason: reason}); err != nil {
  301. log.Error("s.accRPC.AddCoin2(%v,%v,%v) error(%v)", adv.Mid, coin, reason, err)
  302. }
  303. return
  304. }
  305. // CancelAdvance 取消高级弹幕申请
  306. func (s *Service) CancelAdvance(c context.Context, mid, id int64) (err error) {
  307. var (
  308. adv *model.Advance
  309. coin float64
  310. reason string
  311. af int64
  312. )
  313. if adv, err = s.dao.Advance(c, mid, id); err != nil {
  314. log.Error("s.dao.Advance(%d,%d) error(%v)", mid, id, err)
  315. return
  316. }
  317. if adv == nil {
  318. err = ecode.DMAdvNoFound
  319. return
  320. }
  321. if af, err = s.dao.DelAdvance(c, id); err != nil {
  322. log.Error("s.dao.DelAdvance(%d) error(%v)", id, err)
  323. return
  324. }
  325. if err = s.dao.DelAdvCache(c, adv.Mid, adv.Cid, adv.Mode); err != nil {
  326. log.Error("s.dao.DelAdvCache(%+v) error(%v)", adv, err)
  327. return
  328. }
  329. if af < 1 {
  330. err = ecode.DMAdvNoFound
  331. return
  332. }
  333. if adv.Refund == 0 || adv.Type == model.AdvTypeDeny {
  334. return
  335. }
  336. coin = model.AdvSPCoin
  337. reason = model.AdvSPCoinCancelReason
  338. if adv.Mode == model.AdvMode {
  339. coin = model.AdvCoin
  340. reason = model.AdvCoinCancelReason
  341. }
  342. if _, err = s.coinRPC.ModifyCoin(c, &coinmdl.ArgModifyCoin{Mid: adv.Mid, Count: coin, Reason: reason}); err != nil {
  343. log.Error("s.accRPC.AddCoin2(%v,%v,%v) error(%v)", adv.Mid, coin, reason, err)
  344. }
  345. return
  346. }
  347. // UpdateAdvancePermit update advance permit.
  348. func (s *Service) UpdateAdvancePermit(c context.Context, mid int64, advPermit int8) (err error) {
  349. _, err = s.dao.AddUpperConfig(c, mid, advPermit)
  350. return
  351. }
  352. // AdvancePermit get advance permission.
  353. func (s *Service) AdvancePermit(c context.Context, mid int64) (advPermit int8, err error) {
  354. advPermit, err = s.dao.UpperConfig(c, mid)
  355. return
  356. }