305 lines
8.8 KiB
Go
305 lines
8.8 KiB
Go
|
package dao
|
|||
|
|
|||
|
import (
|
|||
|
"context"
|
|||
|
"database/sql"
|
|||
|
"fmt"
|
|||
|
"strconv"
|
|||
|
"strings"
|
|||
|
"sync"
|
|||
|
"time"
|
|||
|
|
|||
|
artmdl "go-common/app/interface/openplatform/article/model"
|
|||
|
xsql "go-common/library/database/sql"
|
|||
|
"go-common/library/log"
|
|||
|
xtime "go-common/library/time"
|
|||
|
"go-common/library/xstr"
|
|||
|
|
|||
|
"go-common/library/sync/errgroup"
|
|||
|
)
|
|||
|
|
|||
|
// Article gets article's meta and content.
|
|||
|
func (d *Dao) Article(c context.Context, aid int64) (res *artmdl.Article, err error) {
|
|||
|
res = &artmdl.Article{}
|
|||
|
if res.Meta, err = d.ArticleMeta(c, aid); err != nil {
|
|||
|
PromError("article:获取文章meta")
|
|||
|
return
|
|||
|
}
|
|||
|
if res.Meta == nil {
|
|||
|
res = nil
|
|||
|
return
|
|||
|
}
|
|||
|
if res.Content, err = d.ArticleContent(c, aid); err != nil {
|
|||
|
PromError("article:获取文章content")
|
|||
|
}
|
|||
|
if res.Keywords, err = d.ArticleKeywords(c, aid); err != nil {
|
|||
|
PromError("article:获取文章keywords")
|
|||
|
}
|
|||
|
res.Strong()
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// ArticleContent get article content
|
|||
|
func (d *Dao) ArticleContent(c context.Context, id int64) (res string, err error) {
|
|||
|
contentSQL := fmt.Sprintf(_articleContentSQL, d.hit(id))
|
|||
|
if err = d.articleDB.QueryRow(c, contentSQL, id).Scan(&res); err != nil {
|
|||
|
if err == sql.ErrNoRows {
|
|||
|
err = nil
|
|||
|
return
|
|||
|
}
|
|||
|
PromError("db:ArticleContent")
|
|||
|
log.Error("dao.ArticleContent(%s) error(%+v)", contentSQL, err)
|
|||
|
}
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// ArticleKeywords get article keywords
|
|||
|
func (d *Dao) ArticleKeywords(c context.Context, id int64) (res string, err error) {
|
|||
|
keywordsSQL := fmt.Sprintf(_articleKeywordsSQL, d.hit(id))
|
|||
|
if err = d.articleDB.QueryRow(c, keywordsSQL, id).Scan(&res); err != nil {
|
|||
|
if err == sql.ErrNoRows {
|
|||
|
err = nil
|
|||
|
return
|
|||
|
}
|
|||
|
PromError("db:ArticleKeywords")
|
|||
|
log.Error("dao.ArticleKeywords(%s) error(%+v)", keywordsSQL, err)
|
|||
|
}
|
|||
|
res = strings.Replace(res, "\001", ",", -1)
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// ArticleMeta get article meta
|
|||
|
func (d *Dao) ArticleMeta(c context.Context, id int64) (res *artmdl.Meta, err error) {
|
|||
|
var (
|
|||
|
row *xsql.Row
|
|||
|
imageURLs, originImageURLs string
|
|||
|
category = &artmdl.Category{}
|
|||
|
author = &artmdl.Author{}
|
|||
|
t int64
|
|||
|
ct time.Time
|
|||
|
)
|
|||
|
res = &artmdl.Meta{Media: &artmdl.Media{}}
|
|||
|
row = d.articleMetaStmt.QueryRow(c, id)
|
|||
|
if err = row.Scan(&res.ID, &category.ID, &res.Title, &res.Summary, &res.BannerURL, &res.TemplateID, &res.State, &author.Mid, &res.Reprint, &imageURLs, &t, &ct, &res.Attributes, &res.Words, &res.Dynamic, &originImageURLs, &res.Media.MediaID, &res.Media.Spoiler); err != nil {
|
|||
|
if err == sql.ErrNoRows {
|
|||
|
res = nil
|
|||
|
err = nil
|
|||
|
return
|
|||
|
}
|
|||
|
PromError("db:ArticleMeta")
|
|||
|
log.Error("dao.ArticleMeta.Scan error(%+v)", err)
|
|||
|
return
|
|||
|
}
|
|||
|
res.PublishTime = xtime.Time(t)
|
|||
|
res.Category = category
|
|||
|
res.Author = author
|
|||
|
res.Ctime = xtime.Time(ct.Unix())
|
|||
|
res.ImageURLs = strings.Split(imageURLs, ",")
|
|||
|
res.OriginImageURLs = strings.Split(originImageURLs, ",")
|
|||
|
res.BannerURL = artmdl.CompleteURL(res.BannerURL)
|
|||
|
res.ImageURLs = artmdl.CompleteURLs(res.ImageURLs)
|
|||
|
res.OriginImageURLs = artmdl.CompleteURLs(res.OriginImageURLs)
|
|||
|
res.Strong()
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// ArticleMetas get article metats
|
|||
|
func (d *Dao) ArticleMetas(c context.Context, aids []int64) (res map[int64]*artmdl.Meta, err error) {
|
|||
|
var (
|
|||
|
group, errCtx = errgroup.WithContext(c)
|
|||
|
mutex = &sync.Mutex{}
|
|||
|
)
|
|||
|
if len(aids) == 0 {
|
|||
|
return
|
|||
|
}
|
|||
|
res = make(map[int64]*artmdl.Meta)
|
|||
|
keysLen := len(aids)
|
|||
|
for i := 0; i < keysLen; i += _mysqlBulkSize {
|
|||
|
var keys []int64
|
|||
|
if (i + _mysqlBulkSize) > keysLen {
|
|||
|
keys = aids[i:]
|
|||
|
} else {
|
|||
|
keys = aids[i : i+_mysqlBulkSize]
|
|||
|
}
|
|||
|
group.Go(func() (err error) {
|
|||
|
var rows *xsql.Rows
|
|||
|
metasSQL := fmt.Sprintf(_articlesMetaSQL, xstr.JoinInts(keys))
|
|||
|
if rows, err = d.articleDB.Query(errCtx, metasSQL); err != nil {
|
|||
|
PromError("db:ArticleMetas")
|
|||
|
return
|
|||
|
}
|
|||
|
defer rows.Close()
|
|||
|
for rows.Next() {
|
|||
|
var (
|
|||
|
imageURLs, originImageURLs string
|
|||
|
t int64
|
|||
|
ct time.Time
|
|||
|
a = &artmdl.Meta{Category: &artmdl.Category{}, Author: &artmdl.Author{}, Media: &artmdl.Media{}}
|
|||
|
)
|
|||
|
err = rows.Scan(&a.ID, &a.Category.ID, &a.Title, &a.Summary, &a.BannerURL, &a.TemplateID, &a.State, &a.Author.Mid, &a.Reprint, &imageURLs, &t, &ct, &a.Attributes, &a.Words, &a.Dynamic, &originImageURLs, &a.Media.MediaID, &a.Media.Spoiler)
|
|||
|
if err != nil {
|
|||
|
return
|
|||
|
}
|
|||
|
a.ImageURLs = strings.Split(imageURLs, ",")
|
|||
|
a.OriginImageURLs = strings.Split(originImageURLs, ",")
|
|||
|
a.PublishTime = xtime.Time(t)
|
|||
|
a.Ctime = xtime.Time(ct.Unix())
|
|||
|
a.BannerURL = artmdl.CompleteURL(a.BannerURL)
|
|||
|
a.ImageURLs = artmdl.CompleteURLs(a.ImageURLs)
|
|||
|
a.OriginImageURLs = artmdl.CompleteURLs(a.OriginImageURLs)
|
|||
|
a.Strong()
|
|||
|
mutex.Lock()
|
|||
|
res[a.ID] = a
|
|||
|
mutex.Unlock()
|
|||
|
}
|
|||
|
err = rows.Err()
|
|||
|
return err
|
|||
|
})
|
|||
|
}
|
|||
|
if err = group.Wait(); err != nil {
|
|||
|
PromError("db:ArticleMetas")
|
|||
|
log.Error("dao.ArticleMetas error(%+v)", err)
|
|||
|
return
|
|||
|
}
|
|||
|
if len(res) == 0 {
|
|||
|
res = nil
|
|||
|
}
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// AllArticleMeta 所有状态/删除 的文章
|
|||
|
func (d *Dao) AllArticleMeta(c context.Context, id int64) (res *artmdl.Meta, err error) {
|
|||
|
var (
|
|||
|
row *xsql.Row
|
|||
|
imageURLs, originImageURLs string
|
|||
|
category = &artmdl.Category{}
|
|||
|
author = &artmdl.Author{}
|
|||
|
t int64
|
|||
|
ct time.Time
|
|||
|
)
|
|||
|
res = &artmdl.Meta{Media: &artmdl.Media{}}
|
|||
|
row = d.allArticleMetaStmt.QueryRow(c, id)
|
|||
|
if err = row.Scan(&res.ID, &category.ID, &res.Title, &res.Summary, &res.BannerURL, &res.TemplateID, &res.State, &author.Mid, &res.Reprint, &imageURLs, &t, &ct, &res.Attributes, &res.Words, &res.Dynamic, &originImageURLs, &res.Media.MediaID, &res.Media.Spoiler); err != nil {
|
|||
|
if err == sql.ErrNoRows {
|
|||
|
res = nil
|
|||
|
err = nil
|
|||
|
return
|
|||
|
}
|
|||
|
PromError("db:AllArticleMeta")
|
|||
|
log.Error("row.AllArticleMeta.Scan error(%+v)", err)
|
|||
|
return
|
|||
|
}
|
|||
|
res.PublishTime = xtime.Time(t)
|
|||
|
res.Category = category
|
|||
|
res.Author = author
|
|||
|
res.Ctime = xtime.Time(ct.Unix())
|
|||
|
res.ImageURLs = strings.Split(imageURLs, ",")
|
|||
|
res.OriginImageURLs = strings.Split(originImageURLs, ",")
|
|||
|
res.BannerURL = artmdl.CompleteURL(res.BannerURL)
|
|||
|
res.ImageURLs = artmdl.CompleteURLs(res.ImageURLs)
|
|||
|
res.OriginImageURLs = artmdl.CompleteURLs(res.OriginImageURLs)
|
|||
|
res.Strong()
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// UpperArticleCount get upper article count
|
|||
|
func (d *Dao) UpperArticleCount(c context.Context, mid int64) (res int, err error) {
|
|||
|
row := d.articleUpperCountStmt.QueryRow(c, mid)
|
|||
|
if err = row.Scan(&res); err != nil {
|
|||
|
if err == sql.ErrNoRows {
|
|||
|
err = nil
|
|||
|
return
|
|||
|
}
|
|||
|
PromError("db:UpperArticleCount")
|
|||
|
log.Error("dao.UpperArticleCount error(%+v)", err)
|
|||
|
}
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// ArticleRemainCount returns the number that user could be use to posting new articles.
|
|||
|
func (d *Dao) ArticleRemainCount(c context.Context, mid int64) (count int, err error) {
|
|||
|
beginTime := time.Now().Format("2006-01-02") + " 00:00:00"
|
|||
|
if err = d.articleUpCntTodayStmt.QueryRow(c, mid, beginTime).Scan(&count); err != nil {
|
|||
|
if err == sql.ErrNoRows {
|
|||
|
err = nil
|
|||
|
return
|
|||
|
}
|
|||
|
PromError("db:ArticleRemainCount")
|
|||
|
log.Error("dao.ArticleRemainCount(%d,%s) error(%+v)", mid, beginTime, err)
|
|||
|
}
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// TagArticles .
|
|||
|
func (d *Dao) TagArticles(c context.Context, tags []int64) (aids []int64, err error) {
|
|||
|
var (
|
|||
|
rows *xsql.Rows
|
|||
|
query string
|
|||
|
tmps = make(map[int64]bool)
|
|||
|
)
|
|||
|
query = fmt.Sprintf(_tagArticlesSQL, xstr.JoinInts(tags))
|
|||
|
if rows, err = d.articleDB.Query(c, query); err != nil {
|
|||
|
PromError("dao:TagArticles")
|
|||
|
log.Error("dao.TagArticles(%s) error(%+v)", query, err)
|
|||
|
return
|
|||
|
}
|
|||
|
defer rows.Close()
|
|||
|
for rows.Next() {
|
|||
|
var (
|
|||
|
tid int64
|
|||
|
oid string
|
|||
|
logDate xtime.Time
|
|||
|
ts []int64
|
|||
|
aid int64
|
|||
|
now = time.Now()
|
|||
|
)
|
|||
|
rows.Scan(&tid, &oid, &logDate)
|
|||
|
if now.Sub(logDate.Time()) > time.Hour*60 {
|
|||
|
continue
|
|||
|
}
|
|||
|
ids := strings.Split(oid, ",")
|
|||
|
for _, id := range ids {
|
|||
|
if aid, err = strconv.ParseInt(id, 10, 64); err != nil {
|
|||
|
log.Error("dao.TagArticles.ParseInt(%s) error(%+v)", id, err)
|
|||
|
return
|
|||
|
}
|
|||
|
if !tmps[aid] {
|
|||
|
aids = append(aids, aid)
|
|||
|
tmps[aid] = true
|
|||
|
}
|
|||
|
ts = append(ts, aid)
|
|||
|
}
|
|||
|
d.AddCacheAidsByTag(c, tid, &artmdl.TagArts{Tid: tid, Aids: ts})
|
|||
|
}
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// MediaArticle .
|
|||
|
func (d *Dao) MediaArticle(c context.Context, mediaID int64, mid int64) (id int64, err error) {
|
|||
|
var rows *xsql.Rows
|
|||
|
if rows, err = d.articleDB.Query(c, _mediaArticleSQL, mid, mediaID); err != nil {
|
|||
|
log.Error("dao.MediaArticle.Query error(%v)", err)
|
|||
|
return
|
|||
|
}
|
|||
|
defer rows.Close()
|
|||
|
for rows.Next() {
|
|||
|
if err = rows.Scan(&id); err != nil {
|
|||
|
log.Error("dao.MediaArticle.Scan error(%v)", err)
|
|||
|
return
|
|||
|
}
|
|||
|
if id > 0 {
|
|||
|
return
|
|||
|
}
|
|||
|
}
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// MediaIDByID .
|
|||
|
func (d *Dao) MediaIDByID(c context.Context, aid int64) (id int64, err error) {
|
|||
|
row := d.articleDB.QueryRow(c, _mediaByIDSQL, aid)
|
|||
|
if err = row.Scan(&id); err != nil {
|
|||
|
log.Error("dao.MediaIDByID.Scan error(%v)", err)
|
|||
|
}
|
|||
|
return
|
|||
|
}
|