bilibili-backup/app/interface/main/videoup/service/check.go
2019-04-22 02:59:20 +00:00

461 lines
14 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package service
import (
"context"
"go-common/app/interface/main/creative/model/tag"
"go-common/app/interface/main/videoup/model/archive"
"go-common/app/interface/main/videoup/model/mission"
"go-common/app/interface/main/videoup/model/porder"
accapi "go-common/app/service/main/account/api"
"go-common/library/ecode"
"go-common/library/log"
xtime "go-common/library/time"
"go-common/library/xstr"
"net/url"
"regexp"
"strings"
"time"
"unicode/utf8"
)
var (
_emptyUnicodeRegForTitle = []*regexp.Regexp{
regexp.MustCompile(`[\x{202e}]+`), // right-to-left override
regexp.MustCompile(`[\x{200b}]+`), // zeroWithChar
regexp.MustCompile(`[\x{1f6ab}]+`), // no_entry_sign
regexp.MustCompile(`[\n]+`), // newline
regexp.MustCompile(`[\r]+`), // newline
}
_emptyUnicodeReg = []*regexp.Regexp{
regexp.MustCompile(`[\x{202e}]+`), // right-to-left override
regexp.MustCompile(`[\x{200b}]+`), // zeroWithChar
regexp.MustCompile(`[\x{1f6ab}]+`), // no_entry_sign
}
_nocharReg = []*regexp.Regexp{
regexp.MustCompile(`[\p{Hangul}]+`), // kr
regexp.MustCompile(`[\p{Tibetan}]+`), // tibe
regexp.MustCompile(`[\p{Arabic}]+`), // arabic
}
_filenameReg = regexp.MustCompile(`^[A-Z0-9a-z]+$`) // only letter digital.
_staffNameReg = regexp.MustCompile("^[\u4e00-\u9fa5a-zA-Z0-9]+$") //职能:数字、字母、中文
)
func (s *Service) checkMission(c context.Context, ap *archive.ArcParam) (err error) {
if ap.MissionID <= 0 {
log.Warn("MissionID(%d) error", ap.MissionID)
ap.MissionID = 0
return
}
missionID := ap.MissionID
tid := ap.TypeID
m, ok := s.missCache[missionID]
if !ok || m.ID == 0 {
err = ecode.VideoupMissionErr
return
}
if m.ETime.Before(time.Now()) {
log.Error("VideoupMissionEtimeInvalid err, tid(%d)|etime(%+v)", tid, m.ETime)
err = ecode.VideoupMissionEtimeInvalid
return
}
var missionTys map[int]*mission.Mission
if missionTys, err = s.miss.MissionOnlineByTid(c, tid); err != nil {
log.Error("MissionOnlineByTid err, s.tid(%+v)|err(%+v)", tid, err)
err = nil
return
}
// case: 这是活动全下架,还想参加活动
if len(missionTys) == 0 {
log.Error("missionTys already empty, tid(%d)|missionTys(%+v)", tid, missionTys)
err = ecode.VideoupMissionNoMatch
return
}
// 包含对分区无限制的活动
if _, ok := missionTys[missionID]; !ok {
log.Error("VideoupMissionNoMatch err, tid(%d)|missionID(%d)", tid, missionID)
err = ecode.VideoupMissionNoMatch
return
}
if ap.Copyright == archive.CopyrightCopy {
log.Error("VideoupCopyForbidJoinMission err, copyright(%d)|missionID(%d)", ap.Copyright, ap.MissionID)
err = ecode.VideoupCopyForbidJoinMission
return
}
return
}
func (s *Service) checkMissionTag(srcTag string, missionID int) (dstTag string, err error) {
var ctags = strings.Split(srcTag, ",")
dstTag = srcTag
// 交叉对比剔除掉当前活动已经使用的tag内容
if len(s.missTagsCache) != 0 {
var tags = make([]string, 0, len(ctags))
for _, t := range ctags {
if _, ok := s.missTagsCache[t]; !ok {
tags = append(tags, t)
}
}
dstTag = strings.Join(tags, ",")
}
// 校验
// 两种情况报错提示用户: 1. 未参加活动,只提交一个tag且是活动tag, 2. 参加活动只提交了一个tag且是其他活动的活动tag
if dstTag == "" && missionID == 0 {
log.Error("forbidMissionTagWithoutJoinMission srcTag(%s), MissionID(%d),s.missCache(%+v),s.missTagsCache(%+v)", srcTag, missionID, s.missCache, s.missTagsCache)
err = ecode.VideoupTagForbidNotJoinMission
return
}
// 未参加活动就直接返回校验后的tag内容
m, ok := s.missCache[missionID]
if !ok {
return
}
// 如果参加了当前有效的活动就会把对应的活动第一个tag拼接在头部, 对于活动id和tag不匹配的会做校验
var singleMissionTag string
if m.Tags != "" {
singleMissionTag = strings.Split(m.Tags, ",")[0]
} else {
singleMissionTag = m.Name
}
if len(dstTag) > 0 {
dstTag = singleMissionTag + "," + dstTag
} else {
dstTag = singleMissionTag
}
return
}
func (s *Service) checkVideo(ap *archive.ArcParam) (err error) {
vds := make([]*archive.VideoParam, 0)
fnMap := make(map[string]int)
var ok bool
for i, v := range ap.Videos {
if v == nil {
continue
}
if v.Title, ok = s.checkTitle(v.Title); !ok {
newErr := ecode.VideoupVideoTitleErr
err = ecode.Errorf(newErr, newErr.Message(), i+1)
log.Error("ap.Videos checkTitle err(%+v)|Title(%s)", err, v.Title)
return
}
if v.Desc, ok = s.checkDesc(v.Desc); !ok {
newErr := ecode.VideoupVideoDescErr
err = ecode.Errorf(newErr, newErr.Message(), i+1)
log.Error("ap.Videos checkDesc err(%+v)|Desc(%s)", err, v.Desc)
return
}
if ok = _filenameReg.MatchString(v.Filename); !ok {
newErr := ecode.VideoupVideoFilenameErr
err = ecode.Errorf(newErr, newErr.Message(), i+1)
log.Error("ap.Videos _filenameReg err(%+v)|filename(%s)", err, v.Filename)
return
}
if v.Cid == 0 && v.Filename == "" { // NOTE: cid>0 means code mode
newErr := ecode.VideoupVideoFilenameErr
err = ecode.Errorf(newErr, newErr.Message(), i+1)
log.Error("ap.Videos err(%+v)|Filename(%s)|Cid(%d)", err, v.Filename, v.Cid)
return
}
if _, ok := fnMap[v.Filename]; ok {
err = ecode.VideoupFilenameCanotRepeat
log.Error("ecode.VideoupFilenameCanotRepeat err(%+v)|Filename(%s)|index(%d)", err, v.Filename, i)
return
}
vds = append(vds, v)
fnMap[v.Filename] = 1
}
ap.Videos = vds
return
}
func (s *Service) checkCover(cover string) (cv string, ok bool) {
if cover == "" {
ok = true
return
}
uri, err := url.Parse(cover)
if err != nil {
return
}
if strings.Contains(uri.Host, "hdslb.com") {
cv = uri.Path
ok = true
return
} else if strings.Contains(uri.Host, "acgvideo.com") {
cv = cover
ok = true
return
}
return
}
func (s *Service) checkDynamicLen233(dynamic string) (dyn string, ok bool) {
dyn = strings.TrimSpace(dynamic)
var _emptyDynUnicodeReg = []*regexp.Regexp{
regexp.MustCompile(`[\x{FFFC}]+`), // obj
}
for _, reg := range _emptyDynUnicodeReg {
dyn = reg.ReplaceAllString(dyn, "")
}
if utf8.RuneCountInString(dyn) > 233 {
return
}
ok = true
return
}
func (s *Service) checkTitle(title string) (ct string, ok bool) {
ct = strings.TrimSpace(title)
if utf8.RuneCountInString(ct) > 80 {
return
}
for _, reg := range _nocharReg {
if reg.MatchString(ct) {
return
}
}
for _, reg := range _emptyUnicodeRegForTitle {
ct = reg.ReplaceAllString(ct, "")
}
ok = true
return
}
func (s *Service) checkDesc(desc string) (cd string, ok bool) {
cd = strings.TrimSpace(desc)
for _, reg := range _emptyUnicodeReg {
cd = reg.ReplaceAllString(cd, "")
}
if utf8.RuneCountInString(cd) > 2000 {
return
}
ok = true
return
}
func (s *Service) checkAccount(c context.Context, mid int64, ip string) (p *accapi.Profile, err error) {
if p, err = s.acc.Profile(c, mid, ip); err != nil {
return
}
if p.Silence == 1 {
err = ecode.UserDisabled
} else if p.Level < 1 {
err = ecode.UserLevelLow
}
if _, ok := s.exemptZeroLevelAndAnswerUps[mid]; ok && err == ecode.UserLevelLow {
log.Info("s.exemptZeroLevelAndAnswerUps, (%s),(%d),(%+v)", ip, mid, err)
err = nil
}
return
}
func (s *Service) checkOrderID(c context.Context, mid, orderID int64, ip string) (err error) {
orderIDs, err := s.order.ExecuteOrders(c, mid, ip)
if err != nil {
log.Error("s.order.ExecuteOrders mid(%d) ip(%s) error(%v)", mid, err)
err = ecode.VideoupOrderAPIErr
return
}
if _, ok := orderIDs[orderID]; !ok {
err = ecode.VideoupOrderIDNotAllow
}
return
}
func (s *Service) checkIdentify(c context.Context, mid int64, ip string) (err error) {
if _, ok := s.exemptIDCheckUps[mid]; ok {
log.Info("s.exemptIDCheckUps, (%s),(%d),(%+v)", ip, mid, err)
return
}
// fault-tolerant for service interruption
if err = s.acc.IdentifyInfo(c, ip, mid); err != nil {
if err != ecode.UserCheckNoPhone && err != ecode.UserCheckInvalidPhone {
log.Warn("s.accIdentifyInfo, account service maybe in interruption,(%s),(%d),(%+v)", ip, mid, err)
return nil
}
log.Error("s.accIdentifyInfo, (%s),(%d),(%+v)", ip, mid, err)
return
}
return
}
// checkPorderForAdd
func (s *Service) checkPorderForAdd(c context.Context, ap *archive.ArcParam, mid int64) (err error) {
// 防止脏数据, 强制计算和校验Porder的数据
ap.Porder.FlowID = 1
log.Info("ap.Porder (%+v)", ap.Porder)
// showType check
if len(ap.Porder.ShowType) > 0 {
var showTypes []int64
if showTypes, err = xstr.SplitInts(ap.Porder.ShowType); err != nil {
log.Error("SplitInts ShowType err, (%s),(%+v)", ap.Porder.ShowType, err)
return
}
//广告的展现形式太多或者太少
if len(showTypes) == 0 {
err = ecode.VideoupAdShowTypeErr
log.Error("check showTypes (%+v)|err(%+v)", ap.Porder, err)
return
}
for _, showType := range showTypes {
if showType > 0 {
if _, ok := s.PorderCfgs[showType]; !ok {
err = ecode.VideoupAdShowTypeErr
log.Error("VideoupAdShowTypeErr Porder(%+v)|err(%+v)", ap.Porder.ShowType, err)
return
}
}
}
}
// Official check
if ap.Porder.Official == 1 {
if _, ok := porder.OfficialIndustryMaps[ap.Porder.IndustryID]; !ok {
err = ecode.VideoupAdOfficialIndustryIDErr
log.Error("VideoupAdOfficialIndustryIDErr Porder(%+v)|err(%+v)", ap.Porder, err)
return
}
if ap.Porder.BrandID < 0 {
err = ecode.VideoupAdBrandIDErr
log.Error("VideoupAdBrandIDErr Porder(%+v)|err(%+v)", ap.Porder, err)
return
}
// logic map to OfficialIndustryMaps waiting for add other official industry
if _, ok := s.PorderGames[ap.Porder.BrandID]; !ok {
err = ecode.VideoupAdBrandIDErr
log.Error("VideoupAdBrandIDErr Porder(%+v)|err(%+v)", ap.Porder, err)
return
}
}
// Industry check
if ap.Porder.IndustryID > 0 {
if _, ok := s.PorderCfgs[ap.Porder.IndustryID]; !ok {
err = ecode.VideoupAdIndustryIDErr
log.Error("VideoupAdIndustryIDErr Porder(%+v)|err(%+v)", ap.Porder, err)
return
}
}
return
}
// checkDescForLength fn
func (s *Service) checkDescForLength(desc string, descFormatID int, typeID int16, copyright int8) (err error) {
if descFormatID == 0 {
if utf8.RuneCountInString(desc) > 250 {
err = ecode.VideoupFmDesLenOverLimit
log.Error("ecode.VideoupFmDesLenOverLimit, desc(%s),formatID(%d)", desc, descFormatID)
return
}
return
}
if utf8.RuneCountInString(desc) > 2000 {
err = ecode.VideoupFmDesLenOverLimit
log.Error("ecode.VideoupFmDesLenOverLimit, desc(%s),formatID(%d)", desc, descFormatID)
return
}
return
}
// checkVideos, 1: check len(video) == ? 0 , 2: check typeID in (145,146,147,83) and with multi Videos
func (s *Service) checkVideos(c context.Context, ap *archive.ArcParam) (err error) {
if len(ap.Videos) == 0 {
log.Error("checkVideos vds length 0")
err = ecode.VideoupZeroVideos
return
}
if len(ap.Videos) > 1 && ap.ForbidMultiVideoType() {
log.Error("checkVideos vds ForbidMultiVideoType, len(%d), type(%d) ", len(ap.Videos), ap.TypeID)
err = ecode.VideoupForbidMultiVideoForTypes
return
}
return
}
// tagsCheck fn
func (s *Service) tagsCheck(c context.Context, mid int64, tagName, ip string) (err error) {
var t *tag.Tag
tags := strings.Split(tagName, ",")
for i, tagStr := range tags {
if t, err = s.tag.TagCheck(c, mid, tagStr); err != nil {
log.Error("s.tag.TagCheck(%d, %+v, %s) error(%+v)", mid, t, ip, err)
err = nil
return
}
if t != nil && (t.State == tag.TagStateDel || t.State == tag.TagStateHide || t.Type == tag.OfficailActiveTag) {
newErr := ecode.VideoupTagForbid
err = ecode.Errorf(newErr, newErr.Message(), i+1)
log.Error("s.tag.VideoupTagForbid (%d, %+v, %s) error(%+v)", mid, t, ip, err)
return
}
}
return
}
// checkVideosMaxLimitForEdit fn
func (s *Service) checkVideosMaxLimitForEdit(vs []*archive.Video, pvideos []*archive.VideoParam) (addCnt int) {
fnMaps := make(map[string]string)
for _, v := range vs {
fnMaps[v.Filename] = v.Filename
}
for _, v := range pvideos {
if _, exist := fnMaps[v.Filename]; len(v.Filename) > 0 && !exist {
addCnt++
}
}
return
}
// checkPay fn
func (s *Service) checkAddPay(c context.Context, ap *archive.ArcParam, ip string) (err error) {
if err = s.checkPayProtocol(c, ap.Pay, ap.Mid); err != nil {
log.Error("s.checkAddPayProtocol (ap %+v) error(%+v)", ap, err)
return
}
if err = s.checkPayLimit(c, ap); err != nil {
log.Error("s.checkAddPayLimit (ap %+v) error(%+v)", ap, err)
return
}
if err = s.checkPayWithOrder(c, ap.Porder, ap.Pay, ap.OrderID, ap.Mid); err != nil {
log.Error("s.checkAddPayWithOrder (ap %+v) error(%+v)", ap, err)
return
}
return
}
// checkEditPay fn
// 关于RefuseUpdate
// 1.当ctime==ptime的时候也就是尚未稿件一审都是可以update付费模块的
// 2.开放过的,打回的稿件可以在任何时间点进行付费修改
// 3.开放过的非打回的稿件想要修改只能等60天时间过了之后(时间锁是为了保护普通用户的收看权利),否则自己申诉付费审核人员,要求强制打回
func (s *Service) checkEditPay(c context.Context, ap *archive.ArcParam, a *archive.Archive, ip string) (err error) {
_, registed, _ := s.pay.Ass(c, a.Aid, ip)
// 只要注册过付费信息都允许自主修改付费模块
if registed {
if err = s.checkPayProtocol(c, ap.Pay, ap.Mid); err != nil {
log.Error("s.checkAddPayProtocol (ap %+v) error(%+v)", ap, err)
return
}
if err = s.checkPayLimit(c, ap); err != nil {
log.Error("s.checkAddPayLimit (ap %+v) error(%+v)", ap, err)
return
}
if err = s.checkPayWithOrder(c, ap.Porder, ap.Pay, ap.OrderID, ap.Mid); err != nil {
log.Error("s.checkAddPayWithOrder (ap %+v) error(%+v)", ap, err)
return
}
//如果其他端都不传付费信息,那么就用现在有的来进行最后覆盖
if ap.Pay == nil {
ap.UgcPay = a.UgcPay
return
}
updateDeadLine := xtime.Time(a.PTime.Time().AddDate(0, 0, s.c.UgcPayAllowEditDays).Unix())
if ap.Pay != nil &&
a.CTime != a.PTime &&
a.State != archive.StateForbidRecicle &&
xtime.Time(time.Now().Unix()) < updateDeadLine {
log.Warn("checkEditPay ap.Pay.RefuseUpdate updateDeadLine (%+v)|(%+v)|(%+v)", a.Aid, a.CTime, a.PTime)
ap.Pay.RefuseUpdate = true
}
}
return
}