You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
460 lines
14 KiB
460 lines
14 KiB
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 |
|
}
|
|
|