123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295 |
- package service
- import (
- "context"
- "html"
- "regexp"
- "strconv"
- "strings"
- "unicode"
- "unicode/utf16"
- "unicode/utf8"
- "go-common/app/interface/openplatform/article/dao"
- "go-common/app/interface/openplatform/article/model"
- "go-common/library/ecode"
- "go-common/library/log"
- strip "github.com/grokify/html-strip-tags-go"
- )
- var (
- _zeroWidthReg = regexp.MustCompile(`[\x{200b}]+`)
- _nocharReg = []*regexp.Regexp{
- // regexp.MustCompile(`[\p{Hangul}]+`), // kr
- regexp.MustCompile(`[\p{Tibetan}]+`), // tibe
- regexp.MustCompile(`[\p{Arabic}]+`), // arabic
- }
- _chineseReg = regexp.MustCompile(`[\p{Han}]+`) // chinese
- )
- func (s *Service) allowRepeat(c context.Context, mid int64, title string) (ok bool) {
- log.Info("allowRepeat check start | mid(%d) title(%s).", mid, title)
- exist, _ := s.dao.SubmitCache(c, mid, title)
- log.Info("allowRepeat from cache | mid(%d) title(%s) exist(%d).", mid, title, exist)
- if !exist {
- log.Info("allowRepeat not exist | mid(%d) title(%s)", mid, title)
- s.dao.AddSubmitCache(c, mid, title)
- log.Info("allowRepeat add cache | mid(%d) title(%s).", mid, title)
- ok = true
- return
- }
- dao.PromInfo("creation:禁止重复标题")
- return
- }
- func (s *Service) preMust(c context.Context, art *model.Article) (err error) {
- var ok bool
- if art.Title, ok = s.checkTitle(art.Title); !ok || art.Title == "" {
- log.Error("s.checkTitle mid(%d) art.Title(%s) title contains illegal char or is empty", art.Author.Mid, art.Title)
- err = ecode.CreativeArticleTitleErr
- return
- }
- if art.Content, ok = s.checkContent(art.Content); !ok {
- log.Error("s.checkContent mid(%d) content too long", art.Author.Mid)
- err = ecode.CreativeArticleContentErr
- return
- }
- if !s.allowCategory(art.Category.ID) {
- log.Error("s.allowCategory mid(%d) art.Category(%d) not exists", art.Author.Mid, art.Category)
- err = ecode.CreativeArticleCategoryErr
- return
- }
- if !s.allowReprints(int8(art.Reprint)) {
- log.Error("s.allowReprints mid(%d) art.Reprint(%d) illegal reprint", art.Author.Mid, art.Reprint)
- err = ecode.CreativeArticleReprintErr
- return
- }
- if !s.allowTID(int8(art.TemplateID)) {
- log.Error("s.allowTID mid(%d) art.TemplateID(%d) illegal reprint", art.Author.Mid, art.TemplateID)
- err = ecode.CreativeArticleTIDErr
- return
- }
- if !model.ValidTemplate(art.TemplateID, art.ImageURLs) {
- err = ecode.ArtCreationTplErr
- return
- }
- if !s.allowTag(art.Tags) {
- log.Error("s.allowTag mid(%d) art.Tags(%s) tag name or number too large", art.Author.Mid, art.Tags)
- err = ecode.CreativeArticleTagErr
- }
- if art.Dynamic, ok = s.allowDynamicIntro(art.Dynamic); !ok {
- log.Error("s.checkDynamicIntro mid(%d) art.DynamicIntro(%s) title contains illegal char", art.Author.Mid, art.Dynamic)
- err = ecode.CreativeDynamicIntroErr
- return
- }
- return
- }
- func (s *Service) checkTitle(title string) (ct string, ok bool) {
- title = strings.TrimSpace(title)
- allCount := utf8.RuneCountInString(title)
- enCount := utf8.RuneCountInString(_chineseReg.ReplaceAllString(title, ""))
- chineseCount := allCount - enCount
- if chineseCount*2+enCount > 80 {
- return
- }
- for _, reg := range _nocharReg {
- if reg.MatchString(title) {
- return
- }
- }
- ct = _zeroWidthReg.ReplaceAllString(title, "")
- if utf8.RuneCountInString(ct) <= 0 {
- return
- }
- ok = true
- return
- }
- func (s *Service) contentStripSize(content string) (count int) {
- stripped := strip.StripTags(content)
- stripped = html.UnescapeString(stripped)
- stripped = strings.Map(func(r rune) rune {
- if unicode.IsSpace(r) {
- return -1
- }
- return r
- }, stripped)
- stripped = strings.Replace(stripped, "\u200B", "", -1)
- stripped = strings.Replace(stripped, "\u00a0", "", -1)
- // utf16 size
- for _, r := range stripped {
- count += len(utf16.Encode([]rune{rune(r)}))
- }
- // 图片计算为一个字
- offset := strings.Count(content, "<img") - strings.Count(stripped, "<img")
- count += offset
- return
- }
- func (s *Service) checkContent(content string) (ct string, ok bool) {
- ct = strings.TrimSpace(content)
- ct = _zeroWidthReg.ReplaceAllString(ct, "")
- if len(ct) > s.c.Article.MaxContentSize {
- return
- }
- size := s.contentStripSize(ct)
- if size < s.c.Article.MinContentLength || size > s.c.Article.MaxContentLength {
- return
- }
- ok = true
- return
- }
- func (s *Service) preArticleCheck(c context.Context, art *model.Article) (err error) {
- if !s.allowRepeat(c, art.Author.Mid, art.Title) {
- err = ecode.CreativeArticleCanNotRepeat
- return
- }
- if err = s.preMust(c, art); err != nil {
- return
- }
- return
- }
- func (s *Service) allowCategory(cid int64) (ok bool) {
- _, ok = s.categoriesMap[cid]
- return
- }
- func (s *Service) allowReprints(cp int8) (ok bool) {
- ok = model.InReprints(cp)
- return
- }
- func (s *Service) allowTID(tid int8) (ok bool) {
- ok = model.InTemplateID(tid)
- return
- }
- func (s *Service) allowTag(tags []*model.Tag) (ok bool) {
- if (len(tags) > 12) || (len(tags) == 0) {
- return
- }
- for _, tag := range tags {
- if _zeroWidthReg.MatchString(tag.Name) {
- return
- }
- if (utf8.RuneCountInString(tag.Name) > 20) || (tag.Name == "") {
- return
- }
- }
- return true
- }
- //allowDynamicIntro 移动端动态推荐语,选填,不能超过233字.
- func (s *Service) allowDynamicIntro(dynamicIntro string) (ct string, ok bool) {
- ct = strings.TrimSpace(dynamicIntro)
- if utf8.RuneCountInString(ct) > 233 {
- return
- }
- ok = true
- return
- }
- func (s *Service) preDraftCheck(c context.Context, art *model.Draft) (err error) {
- if art.Title == "" {
- art.Title = "无标题"
- }
- var ok bool
- if art.Title, ok = s.checkTitle(art.Title); !ok {
- log.Error("s.checkTitle mid(%d) art.Title(%s) title contains illegal char or is empty", art.Author.Mid, art.Title)
- err = ecode.CreativeArticleTitleErr
- }
- return
- }
- // ParseParam parse article param which type is int.
- func (s *Service) ParseParam(c context.Context, categoryStr, reprintStr, tidStr, imageURLs, originImageURLs string) (art *model.ArtParam, err error) {
- var (
- category int64
- tid, reprint int
- )
- category, err = strconv.ParseInt(categoryStr, 10, 64)
- if err != nil || category <= 0 { //文章要求必须传大于0的分类
- err = ecode.CreativeArticleCategoryErr
- return
- }
- tid, err = strconv.Atoi(tidStr)
- if err != nil || tid < 0 {
- err = ecode.CreativeArticleTIDErr
- return
- }
- reprint, err = strconv.Atoi(reprintStr)
- if err != nil || reprint < 0 {
- err = ecode.CreativeArticleReprintErr
- return
- }
- imgs, oimgs, err := ParseImageURLs(imageURLs, originImageURLs)
- if err != nil {
- return
- }
- art = &model.ArtParam{
- Category: category,
- TemplateID: int32(tid),
- Reprint: int32(reprint),
- ImageURLs: imgs,
- OriginImageURLs: oimgs,
- }
- return
- }
- // ParseDraftParam parse draft param which type is int.
- func (s *Service) ParseDraftParam(c context.Context, categoryStr, reprintStr, tidStr, imageURLs, originImageURLs string) (art *model.ArtParam, err error) {
- var (
- category int64
- tid, reprint int
- )
- if categoryStr != "" {
- category, err = strconv.ParseInt(categoryStr, 10, 64)
- if err != nil || category < 0 {
- err = ecode.CreativeArticleCategoryErr
- return
- }
- }
- if tidStr != "" {
- tid, err = strconv.Atoi(tidStr)
- if err != nil || tid < 0 {
- err = ecode.CreativeArticleTIDErr
- return
- }
- }
- if reprintStr != "" {
- reprint, err = strconv.Atoi(reprintStr)
- if err != nil || reprint < 0 {
- err = ecode.CreativeArticleReprintErr
- return
- }
- }
- imgs, oimgs, err := ParseImageURLs(imageURLs, originImageURLs)
- if err != nil {
- return
- }
- art = &model.ArtParam{
- Category: category,
- TemplateID: int32(tid),
- Reprint: int32(reprint),
- ImageURLs: imgs,
- OriginImageURLs: oimgs,
- }
- return
- }
- //ParseImageURLs parse img urls to []string.
- func ParseImageURLs(imageURLs, originImageURLs string) (imgs, oimgs []string, err error) {
- if originImageURLs == "" {
- originImageURLs = imageURLs
- }
- imgs = strings.Split(imageURLs, ",")
- oimgs = strings.Split(originImageURLs, ",")
- if len(imgs) != len(oimgs) {
- err = ecode.CreativeArticleImageURLsErr
- }
- return
- }
|