461 lines
14 KiB
Go
461 lines
14 KiB
Go
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
|
||
}
|