123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322 |
- package dao
- import (
- "context"
- "fmt"
- "strings"
- "sync"
- "time"
- "go-common/app/interface/openplatform/article/model"
- "go-common/library/database/sql"
- "go-common/library/log"
- "go-common/library/xstr"
- "go-common/library/sync/errgroup"
- )
- const (
- _sharding = 100
- _mysqlBulkSize = 50
- // article
- _articleMetaSQL = "SELECT article_id,category_id,title,summary,banner_url, template_id, state, mid, reprint, image_urls, publish_time, ctime, attributes,words,dynamic_intro, origin_image_urls, media_id, spoiler FROM filtered_articles WHERE article_id = ?"
- _allArticleMetaSQL = "SELECT id,category_id,title,summary,banner_url, template_id, state, mid, reprint, image_urls, publish_time, ctime, attributes,words,dynamic_intro, origin_image_urls, media_id, spoiler FROM articles WHERE id = ?"
- _articlesMetaSQL = "SELECT article_id,category_id,title,summary,banner_url, template_id, state, mid, reprint, image_urls, publish_time, ctime, attributes,words,dynamic_intro, origin_image_urls, media_id, spoiler FROM filtered_articles WHERE article_id in (%s)"
- _upperPassedSQL = "SELECT article_id, publish_time, attributes FROM filtered_articles WHERE mid = ? ORDER BY publish_time desc"
- _uppersPassedSQL = "SELECT article_id, mid, publish_time, attributes FROM filtered_articles WHERE mid in (%s) ORDER BY publish_time desc"
- _articleContentSQL = "SELECT content FROM filtered_article_contents_%s WHERE article_id = ?"
- _articleKeywordsSQL = "SELECT tags FROM article_contents_%s WHERE article_id = ?"
- _articleUpperCountSQL = "SELECT count(*) FROM filtered_articles WHERE mid = ?"
- _articleUpCntTodaySQL = "SELECT count(*) FROM articles WHERE mid = ? and ctime >= ?"
- _delFilteredArtMetaSQL = "DELETE FROM filtered_articles where article_id = ?"
- _delFilteredArtContentSQL = "DELETE FROM filtered_article_contents_%s where article_id = ?"
- // stat
- _statSQL = "SELECT view,favorite,likes,dislike,reply,share,coin,dynamic FROM article_stats_%s WHERE article_id = ? and deleted_time = 0"
- _statsSQL = "SELECT article_id, view,favorite,likes,dislike,reply,share,coin,dynamic FROM article_stats_%s WHERE article_id in (%s) and deleted_time = 0"
- // category
- _categoriesSQL = "SELECT id,parent_id,name,position,banner_url FROM article_categories WHERE state = 1 and deleted_time = 0"
- // authors
- _authorsSQL = "SELECT mid, daily_limit, state FROM article_authors WHERE deleted_time=0"
- _authorSQL = "SELECT state,rtime, daily_limit FROM article_authors WHERE mid=? AND deleted_time=0"
- _applyCountSQL = "SELECT count(*) FROM article_authors WHERE atime >= ?"
- _applySQL = "INSERT INTO article_authors (mid,atime,count,content,category) VALUES (?,?,1,?,?) ON DUPLICATE KEY UPDATE atime=?,rtime=0,state=0,count=count+1,content=?,category=?,deleted_time=0"
- _addAuthorSQL = "INSERT INTO article_authors (mid,state,type) VALUES (?,1,5) ON DUPLICATE KEY UPDATE state=1,deleted_time=0"
- // recommends
- _recommendCategorySQL = "SELECT article_id, big_banner_url, show_recommend, position, end_time, big_banner_start_time, big_banner_end_time FROM article_recommends WHERE start_time <= ? and (end_time >= ? or end_time = 0) and category_id = ? and deleted_time = 0 ORDER BY position ASC"
- _allRecommendSQL = "SELECT article_id FROM article_recommends WHERE start_time <= ? and (end_time >= ? or end_time = 0) and deleted_time = 0 and category_id = 0 ORDER BY mtime DESC LIMIT ?,?"
- _allRecommendCountSQL = "SELECT COUNT(*) FROM article_recommends WHERE start_time <= ? and (end_time >= ? or end_time = 0) and deleted_time = 0 and category_id = 0"
- _deleteRecommendSQL = "UPDATE article_recommends SET deleted_time=? WHERE article_id=? and deleted_time = 0"
- // setting
- _settingsSQL = "SELECT name,value FROM article_settings WHERE deleted_time=0"
- // sort
- _newestArtsMetaSQL = "SELECT article_id, publish_time, attributes FROM filtered_articles ORDER BY publish_time DESC LIMIT ?"
- //notice
- _noticeSQL = "SELECT id, title, url, plat, condi, build from article_notices where state = 1 and stime <= ? and etime > ?"
- // users
- _userNoticeSQL = "SELECT notice_state from users where mid = ?"
- _updateUserNoticeSQL = "INSERT INTO users (mid,notice_state) VALUES (?,?) ON DUPLICATE KEY UPDATE notice_state=?"
- // hotspots
- _hotspotsSQL = "select id, title, tag, icon, top_articles from hotspots where deleted_time = 0 and `order` != 0 order by `order` asc"
- // search articles
- _searchArticles = "select article_id, publish_time, tags, stats_view, stats_reply from search_articles where publish_time >= ? and publish_time < ?"
- _addCheatSQL = "INSERT INTO stats_filters(article_id, lv) VALUES(?,?) ON DUPLICATE KEY UPDATE lv=?, deleted_time = 0"
- _delCheatSQL = "UPDATE stats_filters SET deleted_time = ? WHERE article_id = ? and deleted_time = 0"
- _tagArticlesSQL = "select tid, oid, log_date FROM article_tags where tid in (%s) and is_deleted = 0"
- _mediaArticleSQL = "select id from articles where mid = ? and media_id = ? and deleted_time = 0 and state > -10"
- _mediaByIDSQL = "select media_id from articles where id = ?"
- )
- var _searchInterval = int64(3 * 24 * 3600)
- func (d *Dao) hit(id int64) string {
- return fmt.Sprintf("%02d", id%_sharding)
- }
- // Categories get Categories
- func (d *Dao) Categories(c context.Context) (res map[int64]*model.Category, err error) {
- var rows *sql.Rows
- if rows, err = d.categoriesStmt.Query(c); err != nil {
- PromError("db:分区查询")
- log.Error("mysql: db.Categories.Query error(%+v)", err)
- return
- }
- defer rows.Close()
- res = make(map[int64]*model.Category)
- for rows.Next() {
- ca := &model.Category{}
- if err = rows.Scan(&ca.ID, &ca.ParentID, &ca.Name, &ca.Position, &ca.BannerURL); err != nil {
- PromError("分区Scan")
- log.Error("mysql: rows.Categories.Scan error(%+v)", err)
- return
- }
- res[ca.ID] = ca
- }
- err = rows.Err()
- promErrorCheck(err)
- return
- }
- // ArticleStats get article stats
- func (d *Dao) ArticleStats(c context.Context, id int64) (res *model.Stats, err error) {
- res = new(model.Stats)
- row := d.articleDB.QueryRow(c, fmt.Sprintf(_statSQL, d.hit(id)), id)
- if err = row.Scan(&res.View, &res.Favorite, &res.Like, &res.Dislike, &res.Reply, &res.Share, &res.Coin, &res.Dynamic); err != nil {
- if err == sql.ErrNoRows {
- res = nil
- err = nil
- } else {
- PromError("Stat scan")
- log.Error("mysql: ArticleStats row.Scan(%d) error(%+v)", id, err)
- }
- }
- return
- }
- // ArticlesStats get articles stats
- func (d *Dao) ArticlesStats(c context.Context, ids []int64) (res map[int64]*model.Stats, err error) {
- var (
- shardings = make(map[int64][]int64)
- group = &errgroup.Group{}
- mutex = &sync.Mutex{}
- )
- res = make(map[int64]*model.Stats)
- for _, id := range ids {
- shardings[id%_sharding] = append(shardings[id%_sharding], id)
- }
- for sharding, subIDs := range shardings {
- keysLen := len(subIDs)
- sharding := sharding
- subIDs := subIDs
- for i := 0; i < keysLen; i += _mysqlBulkSize {
- var keys []int64
- if (i + _mysqlBulkSize) > keysLen {
- keys = subIDs[i:]
- } else {
- keys = subIDs[i : i+_mysqlBulkSize]
- }
- group.Go(func() error {
- statsSQL := fmt.Sprintf(_statsSQL, d.hit(sharding), xstr.JoinInts(keys))
- rows, e := d.articleDB.Query(c, statsSQL)
- if e != nil {
- return e
- }
- defer rows.Close()
- for rows.Next() {
- s := &model.Stats{}
- var aid int64
- e = rows.Scan(&aid, &s.View, &s.Favorite, &s.Like, &s.Dislike, &s.Reply, &s.Share, &s.Coin, &s.Dynamic)
- if e != nil {
- return e
- }
- mutex.Lock()
- res[aid] = s
- mutex.Unlock()
- }
- return rows.Err()
- })
- }
- }
- err = group.Wait()
- if err != nil {
- PromError("stats Scan")
- log.Error("mysql: rows.ArticleStats.Scan error(%+v)", err)
- }
- if len(res) == 0 {
- res = nil
- }
- return
- }
- // Settings gets article settings.
- func (d *Dao) Settings(c context.Context) (res map[string]string, err error) {
- var rows *sql.Rows
- if rows, err = d.settingsStmt.Query(c); err != nil {
- PromError("db:文章配置查询")
- log.Error("mysql: db.settingsStmt.Query error(%+v)", err)
- return
- }
- defer rows.Close()
- res = make(map[string]string)
- for rows.Next() {
- var name, value string
- if err = rows.Scan(&name, &value); err != nil {
- PromError("文章配置scan")
- log.Error("mysql: rows.Scan error(%+v)", err)
- return
- }
- res[name] = value
- }
- err = rows.Err()
- promErrorCheck(err)
- return
- }
- // Notices notice .
- func (d *Dao) Notices(c context.Context, t time.Time) (res []*model.Notice, err error) {
- var rows *sql.Rows
- if rows, err = d.noticeStmt.Query(c, t, t); err != nil {
- PromError("db:notice")
- log.Error("mysql: notice Query() error(%+v)", err)
- return
- }
- defer rows.Close()
- for rows.Next() {
- ba := &model.Notice{}
- if err = rows.Scan(&ba.ID, &ba.Title, &ba.URL, &ba.Plat, &ba.Condition, &ba.Build); err != nil {
- PromError("db:notice")
- log.Error("mysql: notice Scan() error(%+v)", err)
- return
- }
- res = append(res, ba)
- }
- err = rows.Err()
- promErrorCheck(err)
- return
- }
- // NoticeState .
- func (d *Dao) NoticeState(c context.Context, mid int64) (res int64, err error) {
- if err = d.userNoticeStmt.QueryRow(c, mid).Scan(&res); err != nil {
- if err == sql.ErrNoRows {
- err = nil
- } else {
- PromError("db:notice_state")
- log.Error("mysql: notice state row.Scan error(%+v)", err)
- }
- }
- return
- }
- // UpdateNoticeState update notice state
- func (d *Dao) UpdateNoticeState(c context.Context, mid int64, state int64) (err error) {
- if _, err = d.updateUserNoticeStmt.Exec(c, mid, state, state); err != nil {
- PromError("db:修改用户引导状态")
- log.Error("mysql: update_notice state(mid: %v, state: %v) error(%+v)", mid, state, err)
- }
- return
- }
- // Hotspots .
- func (d *Dao) Hotspots(c context.Context) (res []*model.Hotspot, err error) {
- var rows *sql.Rows
- if rows, err = d.hotspotsStmt.Query(c); err != nil {
- PromError("db:hotspots")
- log.Error("mysql: hotspot Query() error(%+v)", err)
- return
- }
- defer rows.Close()
- for rows.Next() {
- ba := &model.Hotspot{}
- var ic int
- var arts string
- if err = rows.Scan(&ba.ID, &ba.Title, &ba.Tag, &ic, &arts); err != nil {
- PromError("db:hostspot")
- log.Error("mysql: hotspot Scan() error(%+v)", err)
- return
- }
- if ic != 0 {
- ba.Icon = true
- }
- ba.TopArticles, _ = xstr.SplitInts(arts)
- res = append(res, ba)
- }
- err = rows.Err()
- promErrorCheck(err)
- return
- }
- // SearchArts get articles publish time after ptime
- func (d *Dao) SearchArts(c context.Context, ptime int64) (res []*model.SearchArt, err error) {
- var rows *sql.Rows
- now := time.Now().Unix()
- for ; ptime < now; ptime += _searchInterval {
- if rows, err = d.searchArtsStmt.Query(c, ptime, ptime+_searchInterval); err != nil {
- PromError("db:searchArts")
- log.Error("mysql: search arts Query() error(%+v)", err)
- return
- }
- defer rows.Close()
- for rows.Next() {
- ba := &model.SearchArt{}
- var t string
- if err = rows.Scan(&ba.ID, &ba.PublishTime, &t, &ba.StatsView, &ba.StatsReply); err != nil {
- PromError("db:searchArts")
- log.Error("mysql: search arts Scan() error(%+v)", err)
- return
- }
- if t != "" {
- ba.Tags = strings.Split(t, ",")
- }
- res = append(res, ba)
- }
- if err = rows.Err(); err != nil {
- PromError("db:searchArts")
- log.Error("mysql: search arts Query() error(%+v)", err)
- return
- }
- }
- return
- }
- // AddCheatFilter .
- func (d *Dao) AddCheatFilter(c context.Context, aid int64, lv int) (err error) {
- if _, err = d.addCheatStmt.Exec(c, aid, lv, lv); err != nil {
- PromError("db:新增防刷过滤")
- log.Error("mysql: addCheatFilter state(aid: %v, lv: %v) error(%+v)", aid, lv, err)
- return
- }
- log.Info("mysql: addCheatFilter state(aid: %v, lv: %v)", aid, lv)
- return
- }
- // DelCheatFilter .
- func (d *Dao) DelCheatFilter(c context.Context, aid int64) (err error) {
- if _, err = d.delCheatStmt.Exec(c, time.Now().Unix(), aid); err != nil {
- PromError("db:删除防刷过滤")
- log.Error("mysql: delCheatFilter state(aid: %v) error(%+v)", aid, err)
- return
- }
- log.Info("mysql: delCheatFilter state(aid: %v)", aid)
- return
- }
|