123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550 |
- package service
- import (
- "context"
- "sort"
- "time"
- "go-common/app/interface/openplatform/article/dao"
- "go-common/app/interface/openplatform/article/model"
- filter "go-common/app/service/main/filter/model/rpc"
- "go-common/library/database/sql"
- "go-common/library/ecode"
- "go-common/library/log"
- xtime "go-common/library/time"
- )
- // const _novel = 16
- const _positionStep = 1000
- // CreativeUpLists up list
- func (s *Service) CreativeUpLists(c context.Context, mid int64) (novel bool, lists []*model.CreativeList, err error) {
- if err = s.checkPrivilege(c, mid); err != nil {
- return
- }
- // var count int64
- // if count, err = s.dao.CreativeCountArticles(c, mid, s.novelCIDs()); err != nil {
- // return
- // }
- // novel = count > 0
- novel = true
- ls, err := s.dao.CreativeUpLists(c, mid)
- if err != nil {
- return
- }
- sortLists(ls)
- var ids []int64
- for _, l := range ls {
- ids = append(ids, l.ID)
- }
- arts, err := s.dao.CreativeListsArticles(c, ids)
- if err != nil {
- return
- }
- for _, l := range ls {
- lists = append(lists, &model.CreativeList{List: l, Total: len(arts[l.ID])})
- }
- return
- }
- func sortLists(lists []*model.List) {
- sort.Slice(lists, func(i, j int) bool {
- it := int64(lists[i].Ctime)
- jt := int64(lists[j].Ctime)
- if int64(lists[i].UpdateTime) > it {
- it = int64(lists[i].UpdateTime)
- }
- if int64(lists[j].UpdateTime) > jt {
- jt = int64(lists[j].UpdateTime)
- }
- return it > jt
- })
- }
- func (s *Service) filter(c context.Context, content string) (res string, err error) {
- arg := filter.ArgFilter{Area: "article", Message: content}
- var filterRes *filter.FilterRes
- if filterRes, err = s.filterRPC.FilterArea(c, &arg); err != nil {
- dao.PromError("creative:过滤服务")
- log.Errorv(c, log.KV("log", "s.filterRPC.Filter"), log.KV("content", content), log.KV("err", err))
- res = content
- return
- }
- res = filterRes.Result
- return
- }
- // CreativeAddList add list
- func (s *Service) CreativeAddList(c context.Context, mid int64, name string, summary, imageURL string) (res *model.List, err error) {
- if err = s.checkPrivilege(c, mid); err != nil {
- return
- }
- if lists, _ := s.dao.CreativeUpLists(c, mid); len(lists) >= s.c.Article.ListLimit {
- err = ecode.ArtMaxListErr
- return
- }
- var newName, newSummary string
- newName, _ = s.filter(c, name)
- if newName != name {
- log.Infov(c, log.KV("log", "filter list"), log.KV("old", name), log.KV("new", newName))
- }
- if summary != "" {
- newSummary, _ = s.filter(c, summary)
- if newSummary != summary {
- log.Infov(c, log.KV("log", "filter list summary"), log.KV("old", summary), log.KV("new", newSummary))
- }
- }
- name = newName
- summary = newSummary
- var ok bool
- if name, ok = s.checkTitle(name); !ok || name == "" {
- log.Errorv(c, log.KV("log", "CreativeAddList"), log.KV("name", name), log.KV("mid", mid))
- err = ecode.ArtListNameErr
- return
- }
- id, err := s.dao.CreativeListAdd(c, mid, name, imageURL, summary, xtime.Time(0), 0)
- if err != nil {
- return
- }
- res, err = s.dao.RawList(c, id)
- cache.Save(func() {
- s.dao.RebuildUpListsCache(context.TODO(), mid)
- })
- return
- }
- // CreativeDelList del list
- func (s *Service) CreativeDelList(c context.Context, mid int64, id int64) (err error) {
- if err = s.checkPrivilege(c, mid); err != nil {
- return
- }
- if _, err = s.checkList(c, mid, id); err != nil {
- return
- }
- arts, _ := s.dao.CreativeListArticles(c, id)
- err = s.dao.CreativeListDel(c, id)
- if err != nil {
- return
- }
- err = s.dao.CreativeListDelAllArticles(c, id)
- // del list cache/articles cache/article list cache
- cache.Save(func() {
- c := context.TODO()
- var aids []int64
- for _, a := range arts {
- aids = append(aids, a.ID)
- }
- s.deleteArtsListCache(c, aids...)
- s.deleteListArtsCache(c, id)
- s.deleteListCache(c, id)
- s.dao.RebuildUpListsCache(context.TODO(), mid)
- })
- return
- }
- // func (s *Service) novelCIDs() (cids []int64) {
- // for _, a := range s.categoriesReverseMap[_novel] {
- // cids = append(cids, a.ID)
- // }
- // return
- // }
- func (s *Service) creativeNotAddListArticles(c context.Context, mid int64) (res []*model.ListArtMeta, err error) {
- // cids := s.novelCIDs()
- arts, err := s.dao.CreativeCategoryArticles(c, mid)
- if err != nil {
- return
- }
- lists, err := s.dao.CreativeUpLists(c, mid)
- if err != nil {
- return
- }
- var ids []int64
- for _, l := range lists {
- ids = append(ids, l.ID)
- }
- listsArts, err := s.dao.CreativeListsArticles(c, ids)
- if err != nil {
- return
- }
- exists := make(map[int64]bool)
- for _, la := range listsArts {
- for _, a := range la {
- exists[a.ID] = true
- }
- }
- for _, art := range arts {
- if !exists[art.ID] {
- res = append(res, art)
- }
- }
- return
- }
- // CreativeCanAddArticles can added passed articles
- func (s *Service) CreativeCanAddArticles(c context.Context, mid int64) (res []*model.ListArtMeta, err error) {
- if err = s.checkPrivilege(c, mid); err != nil {
- return
- }
- arts, err := s.creativeNotAddListArticles(c, mid)
- if err != nil {
- return
- }
- for _, art := range arts {
- if art.IsNormal() {
- res = append(res, art)
- }
- }
- sort.Slice(res, func(i, j int) bool {
- return res[i].PublishTime > res[j].PublishTime
- })
- return
- }
- // CreativeListAllArticles get read list articles
- func (s *Service) CreativeListAllArticles(c context.Context, mid, id int64) (list *model.List, arts []*model.ListArtMeta, err error) {
- if err = s.checkPrivilege(c, mid); err != nil {
- return
- }
- list, err = s.checkList(c, mid, id)
- if err != nil {
- return
- }
- list.Read, _ = s.dao.CacheListReadCount(c, id)
- arts, err = s.rawListArticles(c, id)
- return
- }
- func (s *Service) checkList(c context.Context, mid, id int64) (list *model.List, err error) {
- if id == 0 {
- return
- }
- list, err = s.dao.RawList(c, id)
- if err != nil {
- return
- }
- if list == nil {
- err = ecode.NothingFound
- return
- }
- if list.Mid != mid {
- err = ecode.ArtCreationMIDErr
- return
- }
- return
- }
- // CreativeUpdateListArticles update list articles
- func (s *Service) CreativeUpdateListArticles(c context.Context, listID int64, name, imageURL, summary string, onlyList bool, mid int64, aids []int64) (list *model.List, err error) {
- if err = s.checkPrivilege(c, mid); err != nil {
- return
- }
- list, err = s.checkList(c, mid, listID)
- if err != nil {
- return
- }
- list, err = s.CreativeUpdateList(c, listID, name, imageURL, summary, list.PublishTime, list.Words)
- if err != nil {
- return
- }
- if onlyList {
- cache.Save(func() {
- s.updateListCache(c, listID)
- })
- return
- }
- if len(aids) > s.c.Article.ListArtsLimit {
- err = ecode.ArtAddListLimitErr
- return
- }
- existArts, err := s.dao.CreativeListArticles(c, listID)
- if err != nil {
- return
- }
- existsMap := make(map[int64]bool)
- for _, a := range existArts {
- existsMap[a.ID] = true
- }
- // 过滤非自己的文章
- metas, err := s.CreativeCanAddArticles(c, mid)
- if err != nil {
- return
- }
- metasMap := make(map[int64]*model.ListArtMeta)
- for _, m := range metas {
- metasMap[m.ID] = m
- }
- var newAids []int64
- for _, aid := range aids {
- if existsMap[aid] || (metasMap[aid] != nil) {
- newAids = append(newAids, aid)
- }
- }
- aids = newAids
- // 计算排序
- updated, deleted := calculateListArtPosition(existArts, aids)
- log.Info("creative: update list update(%v) deleted(%v)", len(updated), len(deleted))
- var tx *sql.Tx
- if tx, err = s.dao.BeginTran(c); err != nil {
- log.Error("tx.BeginTran() error(%+v)", err)
- return
- }
- defer func() {
- if err != nil {
- if err1 := tx.Rollback(); err1 != nil {
- log.Error("tx.Rollback() error(%+v)", err1)
- }
- return
- }
- if err = tx.Commit(); err != nil {
- dao.PromError("creative:修改文集")
- log.Error("tx.Commit() error(%+v)", err)
- return
- }
- err = s.updateListInfo(c, listID)
- cache.Save(func() {
- s.dao.CreativeListUpdateTime(context.TODO(), listID, time.Now())
- s.RebuildListCache(context.TODO(), listID)
- s.deleteArtsListCache(context.TODO(), deleted...)
- })
- }()
- for _, id := range deleted {
- if err = s.dao.TxDelListArticle(c, tx, listID, id); err != nil {
- return
- }
- }
- for _, a := range updated {
- if err = s.dao.TxAddListArticle(c, tx, listID, a.ID, a.Position); err != nil {
- return
- }
- }
- return
- }
- func calculateListArtPosition(src []*model.ListArtMeta, dest []int64) (update []*model.ListArtMeta, delete []int64) {
- srcMap := make(map[int64]*model.ListArtMeta)
- for _, m := range src {
- srcMap[m.ID] = m
- }
- destMap := make(map[int64]bool)
- for _, id := range dest {
- destMap[id] = true
- }
- var newSrc []*model.ListArtMeta
- for _, m := range src {
- if !destMap[m.ID] {
- delete = append(delete, m.ID)
- continue
- }
- newSrc = append(newSrc, m)
- }
- if len(newSrc) == len(dest) {
- equal := true
- for i, d := range dest {
- if newSrc[i].ID != d {
- equal = false
- break
- }
- }
- if equal {
- return
- }
- }
- if len(dest) == 0 {
- return
- }
- for i, id := range dest {
- pos := (i + 1) * _positionStep
- if (srcMap[id] != nil) && (srcMap[id].Position == pos) {
- continue
- }
- update = append(update, &model.ListArtMeta{ID: id, Position: pos})
- }
- return
- }
- // CreativeUpdateList update list
- func (s *Service) CreativeUpdateList(c context.Context, id int64, name, imageURL, summary string, publishTime xtime.Time, words int64) (res *model.List, err error) {
- var newName string
- newName, _ = s.filter(c, name)
- if newName != name {
- log.Infov(c, log.KV("log", "filter title"), log.KV("old", name), log.KV("new", newName))
- }
- name = newName
- var ok bool
- if name, ok = s.checkTitle(name); !ok || name == "" {
- log.Errorv(c, log.KV("log", "CreativeUpdateList"), log.KV("name", name), log.KV("id", id))
- err = ecode.ArtListNameErr
- return
- }
- if summary != "" {
- summary, _ = s.filter(c, summary)
- }
- if err = s.dao.CreativeListUpdate(c, id, name, imageURL, summary, publishTime, words); err != nil {
- return
- }
- res, err = s.dao.RawList(c, id)
- if err != nil {
- return
- }
- cache.Save(func() {
- s.dao.AddCacheList(context.TODO(), res.ID, res)
- })
- return
- }
- // creativeAddArticleList set article list
- func (s *Service) creativeAddArticleList(c context.Context, mid, listID, articleID int64, onlyPass bool) (err error) {
- if listID == 0 {
- return
- }
- log.Infov(c, log.KV("log", "creativeSetArticleList"), log.KV("list_id", listID), log.KV("article_id", articleID), log.KV("mid", mid))
- defer func() {
- if err != nil {
- log.Errorv(c, log.KV("log", "creativeSetArticleList"), log.KV("list_id", listID), log.KV("article_id", articleID), log.KV("mid", mid), log.KV("err", err))
- }
- }()
- if _, err = s.checkList(c, mid, listID); err != nil {
- return
- }
- var can bool
- if can, err = s.checkArticleCanAddList(c, mid, articleID, onlyPass); (err != nil) || !can {
- log.Errorv(c, log.KV("log", "checkArticleCanAddList"), log.KV("mid", mid), log.KV("aid", articleID), log.KV("err", err), log.KV("error", err))
- err = ecode.ArtArtAddListErr
- return
- }
- arts, _ := s.dao.CreativeListArticles(c, listID)
- if len(arts) >= s.c.Article.ListArtsLimit {
- err = ecode.ArtAddListLimitErr
- return
- }
- position := _positionStep
- if len(arts) > 0 {
- position = arts[len(arts)-1].Position + _positionStep
- }
- err = s.dao.AddListArticle(c, listID, articleID, position)
- if err != nil {
- return
- }
- err = s.updateListInfo(c, listID)
- if err != nil {
- return
- }
- cache.Save(func() {
- s.dao.CreativeListUpdateTime(context.TODO(), listID, time.Now())
- // only update passed art
- s.RebuildListCache(context.TODO(), listID)
- })
- return
- }
- // CreativeUpdateArticleList update article list
- func (s *Service) CreativeUpdateArticleList(c context.Context, mid, aid, listID int64, onlyPass bool) (err error) {
- if err = s.checkPrivilege(c, mid); err != nil {
- return
- }
- if listID > 0 {
- _, err = s.checkList(c, mid, listID)
- if err != nil {
- return
- }
- }
- // check article
- meta, err := s.dao.AllArticleMeta(c, aid)
- if err != nil {
- return
- }
- if meta == nil {
- err = ecode.NothingFound
- return
- }
- if meta.Author.Mid != mid {
- err = ecode.ArtCreationMIDErr
- return
- }
- // get article list
- lists, err := s.dao.RawArtsListID(c, []int64{aid})
- if err != nil {
- return
- }
- oldListID := lists[aid]
- if oldListID == listID {
- return
- }
- defer func() {
- if err == nil {
- err = s.dao.CreativeListUpdateTime(c, listID, time.Now())
- }
- }()
- s.deleteArtsListCache(c, aid)
- if oldListID > 0 {
- err = s.dao.DelListArticle(c, oldListID, aid)
- if err != nil {
- return
- }
- err = s.updateListInfo(c, oldListID)
- if err != nil {
- return
- }
- cache.Save(func() {
- s.RebuildListCache(context.TODO(), oldListID)
- })
- }
- if listID > 0 {
- err = s.creativeAddArticleList(c, mid, listID, aid, onlyPass)
- }
- return
- }
- func (s *Service) checkArticleCanAddList(c context.Context, mid, aid int64, onlyPass bool) (res bool, err error) {
- metas, err := s.creativeNotAddListArticles(c, mid)
- if err != nil {
- log.Errorv(c, log.KV("log", "checkArticleCanAddList"), log.KV("mid", mid), log.KV("aid", aid), log.KV("err", err))
- return
- }
- metasMap := make(map[int64]*model.ListArtMeta)
- for _, m := range metas {
- metasMap[m.ID] = m
- }
- if onlyPass {
- res = (metasMap[aid] != nil) && metasMap[aid].IsNormal()
- return
- }
- res = metasMap[aid] != nil
- return
- }
- // updateListInfo update list words and publish_time
- func (s *Service) updateListInfo(c context.Context, id int64) (err error) {
- list, err := s.dao.RawList(c, id)
- if err != nil {
- return
- }
- if list == nil {
- err = ecode.NothingFound
- return
- }
- metas, err := s.dao.RawListArts(c, id)
- if err != nil {
- return
- }
- var words, pt int64
- for _, meta := range metas {
- if meta.IsNormal() {
- words += meta.Words
- if int64(meta.PublishTime) > pt {
- pt = int64(meta.PublishTime)
- }
- }
- }
- err = s.dao.CreativeListUpdate(c, id, list.Name, list.ImageURL, list.Summary, xtime.Time(pt), words)
- return
- }
- // RefreshList refresh list info and cache use in api
- func (s *Service) RefreshList(c context.Context, id int64) (err error) {
- if err = s.updateListInfo(c, id); err != nil {
- return
- }
- return s.RebuildListCache(c, id)
- }
|