check_staff.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. package service
  2. import (
  3. "context"
  4. "fmt"
  5. "go-common/app/interface/main/videoup/model/archive"
  6. accapi "go-common/app/service/main/account/api"
  7. "go-common/library/ecode"
  8. "go-common/library/log"
  9. "go-common/library/sync/errgroup"
  10. "strings"
  11. "sync"
  12. "unicode/utf8"
  13. )
  14. // checkAddStaff 新增稿件:检查联合投稿参数
  15. func (s *Service) checkAddStaff(c context.Context, ap *archive.ArcParam, mid int64, ip string) (err error) {
  16. var (
  17. _logs []string
  18. _logs2 []string
  19. )
  20. defer func() {
  21. logStr := strings.Join(_logs, "\n")
  22. if err != nil {
  23. log.Error("s.checkAddStaff ap: %+v \nmid: %d \nlogs\n:%s", ap, mid, logStr)
  24. } else {
  25. log.Info("s.checkAddStaff ap: %+v \nmid: %d \nlogs\n%s", ap, mid, logStr)
  26. }
  27. }()
  28. ap.HandleStaff = false
  29. //新增稿件时,如果没填写Staffs,则不是联合投稿,跳过检查
  30. if len(ap.Staffs) == 0 {
  31. ap.Staffs = make([]*archive.Staff, 0)
  32. _logs = append(_logs, "INFO:非联合投稿,忽略")
  33. return
  34. }
  35. //如果不是自制稿件,不允许传Staffs
  36. if ap.Copyright != archive.CopyrightOriginal && len(ap.Staffs) != 0 {
  37. _logs = append(_logs, "ERR:非自制稿件,不允许传Staffs。")
  38. err = ecode.VideoupStaffCopyright
  39. return
  40. }
  41. //非全量的情况下,检查当前UP主是在白名单中
  42. _logs = append(_logs, fmt.Sprintf("INFO:灰度开关 %v。分区配置 %v 注意:这里打出的数据可能不是最新的,有可能后面重新Load了", s.staffGary, s.staffTypeCache))
  43. if err = s.checkStaffGray(ap.TypeID, mid); err != nil {
  44. _logs = append(_logs, fmt.Sprintf("INFO:UP主(%d)不在灰度名单中。", mid))
  45. return
  46. }
  47. _logs2, err = s.checkStaffData(c, ap.TypeID, ap.Staffs, []*archive.Staff{}, ip)
  48. _logs = append(_logs, _logs2...)
  49. if err != nil {
  50. return
  51. }
  52. //检查拉黑情况
  53. _logs2, _, err = s.checkStaffRelation(c, mid, ap.Staffs, ip)
  54. _logs = append(_logs, _logs2...)
  55. if err != nil {
  56. return
  57. }
  58. ap.HandleStaff = true
  59. _logs = append(_logs, "INFO:通过")
  60. return
  61. }
  62. // checkEditStaff 稿件编辑:检查联合投稿相关参数
  63. func (s *Service) checkEditStaff(c context.Context, ap *archive.ArcParam, mid int64, a *archive.Archive, ip string) (err error) {
  64. var (
  65. cStaffs []*archive.Staff //当前稿件的联合投稿人
  66. diffStaffs []*archive.Staff //变更的联合投稿人
  67. _logs []string
  68. _logs2 []string
  69. )
  70. defer func() {
  71. logStr := strings.Join(_logs, "\n")
  72. if err != nil {
  73. log.Error("s.checkEditStaff ap: %+v \nmid: %d \narchive:%+v \nlogs:\n%v", ap, mid, a, logStr)
  74. } else {
  75. log.Info("s.checkEditStaff ap: %+v \nmid: %d \narchive:%+v \nlogs\n%v", ap, mid, a, logStr)
  76. }
  77. }()
  78. ap.HandleStaff = false
  79. //如果UP主不在白名单中,不修改Staff数据
  80. _logs = append(_logs, fmt.Sprintf("INFO:灰度开关 %v,分区配置 %v 注意:这里打出的数据可能不是最新的,有可能后面重新Load了", s.staffGary, s.staffTypeCache))
  81. if err = s.checkStaffGray(ap.TypeID, mid); err != nil {
  82. _logs = append(_logs, fmt.Sprintf("INFO:UP主(%d)不在灰度中", mid))
  83. //如果UP主不在白名单中,则将staff置空,不修改staff
  84. ap.Staffs = []*archive.Staff{}
  85. ap.HandleStaff = false
  86. err = nil
  87. return
  88. }
  89. //获取当前稿件的Staff信息
  90. if cStaffs, err = s.arc.ApplyStaffs(c, a.Aid, ip); err != nil {
  91. _logs = append(_logs, fmt.Sprintf("ERR:获取线上Staffs失败,err:%v", err))
  92. return
  93. }
  94. if len(ap.Staffs) == 0 { //删除Staffs
  95. _logs2, _, err = s.checkStaffRelation(c, mid, cStaffs, ip)
  96. _logs = append(_logs, _logs2...)
  97. if err != nil {
  98. return
  99. }
  100. _logs = append(_logs, "INFO:UP主删除所有Staff")
  101. ap.HandleStaff = true
  102. return
  103. }
  104. //preEdit()的时候已经加上了以下"移区"、"换类型"的判断逻辑,这里冗余一下
  105. //联合投稿不允许自制稿件改成非自制
  106. if a.Copyright == archive.CopyrightOriginal && ap.Copyright != archive.CopyrightOriginal && a.AttrVal(archive.AttrBitStaff) == archive.AttrYes {
  107. _logs = append(_logs, "ERROR:联合投稿不允许自制稿件改成非自制")
  108. err = ecode.VideoupStaffChangeCopyright
  109. return
  110. }
  111. _logs2, err = s.checkStaffData(c, ap.TypeID, ap.Staffs, cStaffs, ip)
  112. _logs = append(_logs, _logs2...)
  113. if err != nil {
  114. return
  115. }
  116. //只验证修改过的Staff信息
  117. changes, _logs2 := s.getStaffChanges(cStaffs, ap.Staffs)
  118. _logs = append(_logs, _logs2...)
  119. _logs = append(_logs, fmt.Sprintf("INFO:当前Staffs:%+v 提交Staffs:%+v 修改的Staffs:%+v", cStaffs, ap.Staffs, changes))
  120. for _, v := range changes {
  121. for _, m := range v {
  122. diffStaffs = append(diffStaffs, m)
  123. }
  124. }
  125. _logs2, _, err = s.checkStaffRelation(c, mid, diffStaffs, ip)
  126. _logs = append(_logs, _logs2...)
  127. if err != nil {
  128. return
  129. }
  130. ap.HandleStaff = true
  131. _logs = append(_logs, "INFO:通过")
  132. return
  133. }
  134. // checkStaffGray
  135. func (s *Service) checkStaffGray(typeid int16, mid int64) (err error) {
  136. if s.staffGary {
  137. if _, ok := s.staffUps[mid]; !ok {
  138. log.Error("当前Up主(%d)不在联合投稿白名单中。", mid)
  139. err = ecode.VideoupStaffAuth
  140. return
  141. }
  142. var ok1, ok2 bool
  143. _, ok1 = s.staffTypeCache[typeid]
  144. _, ok2 = s.staffTypeCache[0]
  145. if ok1 && s.staffTypeCache[typeid].MaxStaff <= 0 {
  146. log.Error("当前分区(%d)在联合投稿黑名单中。", typeid)
  147. err = ecode.VideoupStaffTypeNotExists
  148. return
  149. }
  150. if !ok1 && !ok2 {
  151. log.Error("当前分区(%d)不在联合投稿白名单中。", typeid)
  152. err = ecode.VideoupStaffTypeNotExists
  153. return
  154. }
  155. }
  156. return
  157. }
  158. // checkStaffData 检查联合投稿人的数据格式(全量验证,不管UP主有没有编辑,都会走这个验证)
  159. func (s *Service) checkStaffData(c context.Context, typeid int16, staffs, cStaffs []*archive.Staff, ip string) (_logs []string, err error) {
  160. var (
  161. titles []string
  162. cards map[int64]*accapi.Card
  163. staffMids []int64
  164. staffMap, cStaffMap map[int64]string
  165. maxStaff int
  166. )
  167. staffMap = make(map[int64]string)
  168. cStaffMap = make(map[int64]string)
  169. if len(cStaffs) != 0 {
  170. for _, v := range cStaffs {
  171. cStaffMap[v.Mid] = v.Title
  172. }
  173. }
  174. //检查分区的配置
  175. if conf, ok := s.staffTypeCache[typeid]; ok {
  176. maxStaff = conf.MaxStaff
  177. } else if conf, ok := s.staffTypeCache[0]; ok {
  178. maxStaff = conf.MaxStaff
  179. } else {
  180. _logs = append(_logs, fmt.Sprintf("ERR:分区%d不在配置里。配置:%v", typeid, s.staffTypeCache))
  181. err = ecode.VideoupStaffTypeNotExists
  182. return
  183. }
  184. if maxStaff == 0 {
  185. _logs = append(_logs, fmt.Sprintf("ERR:分区%d是黑名单。配置:%v", typeid, s.staffTypeCache))
  186. err = ecode.VideoupStaffTypeNotExists
  187. return
  188. }
  189. //检查Staff数量
  190. if len(staffs) > maxStaff {
  191. _logs = append(_logs, fmt.Sprintf("ERR:Staff数量超限。最多:%d;传递:%d", maxStaff, len(staffs)))
  192. err = ecode.VideoupStaffCountLimit
  193. return
  194. }
  195. //检查Staff职能、Mid
  196. for i, v := range staffs {
  197. staffs[i].Title = strings.TrimSpace(v.Title)
  198. v.Title = staffs[i].Title
  199. if v.Mid == 0 {
  200. _logs = append(_logs, "ERR:Staff Mid为0。")
  201. err = ecode.VideoupStaffMidInvalid
  202. return
  203. }
  204. tl := utf8.RuneCountInString(v.Title)
  205. if tl < 2 {
  206. _logs = append(_logs, fmt.Sprintf("ERR:职能(%v)长度不合法,长度:%d。", v.Title, tl))
  207. err = ecode.VideoupStaffTitleShort
  208. return
  209. }
  210. if tl > 4 {
  211. _logs = append(_logs, fmt.Sprintf("ERR:职能(%v)长度不合法,长度:%d。", v.Title, tl))
  212. err = ecode.VideoupStaffTitleLength
  213. return
  214. }
  215. if !_staffNameReg.MatchString(v.Title) {
  216. _logs = append(_logs, fmt.Sprintf("ERR:职能(%v)字符不合法。", v.Title))
  217. err = ecode.VideoupStaffTitleChar
  218. return
  219. }
  220. //不校验未修改的职能
  221. if cTitle, ok := cStaffMap[v.Mid]; !ok || cTitle != v.Title {
  222. titles = append(titles, v.Title)
  223. }
  224. staffMap[v.Mid] = v.Title
  225. staffMids = append(staffMids, v.Mid)
  226. }
  227. if len(staffMap) != len(staffs) {
  228. _logs = append(_logs, fmt.Sprintf("ERR:Staff存在重复。传递:%v;去重后:%v", staffs, staffMap))
  229. err = ecode.VideoupStaffMidRepeat
  230. return
  231. }
  232. //职能名称敏感词
  233. _, hit, err := s.filter.VideoMultiFilter(c, titles, ip)
  234. if err != nil {
  235. _logs = append(_logs, fmt.Sprintf("ERR:职能敏感词接口失败。error:%v", err))
  236. return
  237. }
  238. if len(hit) > 0 {
  239. _logs = append(_logs, fmt.Sprintf("ERR:职能存在敏感词。敏感词:%v", hit))
  240. err = ecode.VideoupStaffTitleFilter
  241. return
  242. }
  243. //Staff Mid合法性检查
  244. if cards, err = s.acc.Cards(c, staffMids, ip); err != nil {
  245. _logs = append(_logs, fmt.Sprintf("ERR:Staff账号信息获取失败。error:%v", err))
  246. return
  247. }
  248. for _, v := range staffMids {
  249. if _, ok := cards[v]; !ok {
  250. _logs = append(_logs, fmt.Sprintf("ERR:Staff Mid(%d)不存在。", v))
  251. err = ecode.VideoupStaffMidInvalid
  252. return
  253. }
  254. }
  255. return
  256. }
  257. // checkStaffRelation 检查联合投稿人拉黑关系
  258. func (s *Service) checkStaffRelation(c context.Context, mid int64, staffs []*archive.Staff, ip string) (_logs []string, blocked []*archive.Staff, err error) {
  259. var (
  260. mids []int64
  261. rels map[int64]int //relations
  262. pass = true
  263. staffMap map[int64]*archive.Staff
  264. cards map[int64]*accapi.Card
  265. )
  266. blocked = make([]*archive.Staff, 0)
  267. staffMap = make(map[int64]*archive.Staff)
  268. for _, v := range staffs {
  269. mids = append(mids, v.Mid)
  270. staffMap[v.Mid] = v
  271. }
  272. if rels, err = s.FRelations(c, mid, mids, ip); err != nil {
  273. _logs = append(_logs, fmt.Sprintf("ERR:获取拉黑信息失败,error:%v", err))
  274. return
  275. }
  276. for k, v := range rels {
  277. if v >= 128 {
  278. _logs = append(_logs, fmt.Sprintf("ERR:Staff(%d)在黑名单中", k))
  279. pass = false
  280. blocked = append(blocked, staffMap[k])
  281. continue
  282. }
  283. }
  284. cards, err = s.acc.Cards(c, mids, ip)
  285. if !pass {
  286. if err != nil {
  287. _logs = append(_logs, fmt.Sprintf("ERR:账号(%v)信息获取失败 error:%v", mids, err))
  288. err = ecode.Errorf(ecode.VideoupStaffBlocked, ecode.VideoupStaffBlocked.Message(), "")
  289. return
  290. }
  291. var bNames []string
  292. for _, v := range blocked {
  293. if _, ok := cards[v.Mid]; ok {
  294. bNames = append(bNames, cards[v.Mid].Name)
  295. } else {
  296. _logs = append(_logs, fmt.Sprintf("ERR:账号(%d)信息获取失败 error:%v", v.Mid, err))
  297. }
  298. }
  299. err = ecode.Errorf(ecode.VideoupStaffBlocked, ecode.VideoupStaffBlocked.Message(), strings.Join(bNames, "、"))
  300. }
  301. for _, staff := range staffs {
  302. if _, ok := cards[staff.Mid]; !ok {
  303. _logs = append(_logs, fmt.Sprintf("ERR:账号(%d)信息获取失败 error:%v", staff.Mid, err))
  304. err = ecode.Errorf(ecode.CreativeAccServiceErr, "参与者(%d)信息获取失败", staff.Mid)
  305. return
  306. }
  307. if cards[staff.Mid].Silence == 1 {
  308. _logs = append(_logs, fmt.Sprintf("ERR:Staff Mid(%d)被封禁。", staff.Mid))
  309. err = ecode.Errorf(ecode.VideoupStaffUpSilence, ecode.VideoupStaffUpSilence.Message(), cards[staff.Mid].Name)
  310. return
  311. }
  312. }
  313. return
  314. }
  315. // getStaffChanges 获取联合投稿人的变更
  316. func (s *Service) getStaffChanges(oS, nS []*archive.Staff) (changes map[string]map[int64]*archive.Staff, _logs []string) {
  317. var (
  318. allS = make([]*archive.Staff, 0)
  319. oMap = make(map[int64]*archive.Staff)
  320. nMap = make(map[int64]*archive.Staff)
  321. )
  322. str := ""
  323. for _, v := range oS {
  324. str += fmt.Sprintf("%d %s;", v.Mid, v.Title)
  325. oMap[v.Mid] = v
  326. }
  327. _logs = append(_logs, " 原Staffs:"+str)
  328. str = ""
  329. for _, v := range nS {
  330. str += fmt.Sprintf("%d %s;", v.Mid, v.Title)
  331. nMap[v.Mid] = v
  332. }
  333. _logs = append(_logs, " 提交Staffs:"+str)
  334. changes = make(map[string]map[int64]*archive.Staff)
  335. changes["add"] = make(map[int64]*archive.Staff)
  336. changes["edit"] = make(map[int64]*archive.Staff)
  337. changes["del"] = make(map[int64]*archive.Staff)
  338. allS = append(allS, oS...)
  339. allS = append(allS, nS...)
  340. for _, v := range allS {
  341. if _, ok := oMap[v.Mid]; !ok {
  342. changes["add"][v.Mid] = v
  343. } else if _, ok := nMap[v.Mid]; !ok {
  344. changes["del"][v.Mid] = v
  345. } else if oMap[v.Mid].Title != nMap[v.Mid].Title {
  346. changes["edit"][v.Mid] = v
  347. }
  348. }
  349. return
  350. }
  351. // FRelations 获取用户与mid的关系(Relations的反向)
  352. func (s *Service) FRelations(c context.Context, mid int64, fids []int64, ip string) (res map[int64]int, err error) {
  353. var (
  354. g, ctx = errgroup.WithContext(c)
  355. sm sync.RWMutex
  356. )
  357. res = make(map[int64]int)
  358. for _, v := range fids {
  359. g.Go(func() error {
  360. var r map[int64]int
  361. if r, err = s.acc.Relations(ctx, v, []int64{mid}, ip); err != nil {
  362. return err
  363. }
  364. sm.Lock()
  365. res[v] = r[mid]
  366. sm.Unlock()
  367. return nil
  368. })
  369. }
  370. if err = g.Wait(); err != nil {
  371. log.Error("s.FRelations(%d,%v) error(%v)", mid, fids, err)
  372. }
  373. return
  374. }
  375. // checkStaffMoveType 联合投稿不允许移区和转载类型(有申请的Staff时,都不允许移区)
  376. func (s *Service) checkStaffMoveType(c context.Context, ap *archive.ArcParam, a *archive.Archive, ip string) (err error) {
  377. var (
  378. _logs []string
  379. )
  380. defer func() {
  381. if err != nil {
  382. log.Error("s.checkStaffMoveType ap: %+v, archive:%+v logs(%v)", ap, a, _logs)
  383. } else {
  384. log.Info("s.checkStaffMoveType ap: %+v, archive:%+v logs(%v)", ap, a, _logs)
  385. }
  386. }()
  387. //如果没发生移区和修改转载类型,则直接通过
  388. if ap.TypeID == a.TypeID && a.Copyright == ap.Copyright {
  389. _logs = append(_logs, "INFO:没有修改分区和转载类型")
  390. return
  391. }
  392. var (
  393. cStaffs []*archive.Staff //当前稿件的联合投稿人
  394. )
  395. if cStaffs, err = s.arc.ApplyStaffs(c, a.Aid, ip); err != nil {
  396. _logs = append(_logs, fmt.Sprintf("ERR:获取Staff失败。error:%v", err))
  397. log.Error("checkStaffMoveType() 获取线上Staffs失败,err:%v", err)
  398. return
  399. }
  400. if len(cStaffs) != 0 {
  401. _logs = append(_logs, fmt.Sprintf("ERR: 不允许操作。当前Staffs(%v)", cStaffs))
  402. err = ecode.VideoupStaffChangeTypeCopyright
  403. return
  404. }
  405. _logs = append(_logs, "INFO:通过")
  406. return
  407. }