chore: store mongodb

This commit is contained in:
deepzz0
2021-04-26 23:02:24 +08:00
parent 68e01cdf1f
commit e2df642a46
20 changed files with 488 additions and 193 deletions

12
pkg/cache/cache.go vendored
View File

@@ -8,12 +8,12 @@ import (
"strings"
"time"
"github.com/eiblog/eiblog/v2/pkg/cache/render"
"github.com/eiblog/eiblog/v2/pkg/cache/store"
"github.com/eiblog/eiblog/v2/pkg/config"
"github.com/eiblog/eiblog/v2/pkg/internal"
"github.com/eiblog/eiblog/v2/pkg/model"
"github.com/eiblog/eiblog/v2/tools"
"github.com/eiblog/eiblog/pkg/cache/render"
"github.com/eiblog/eiblog/pkg/cache/store"
"github.com/eiblog/eiblog/pkg/config"
"github.com/eiblog/eiblog/pkg/internal"
"github.com/eiblog/eiblog/pkg/model"
"github.com/eiblog/eiblog/tools"
"github.com/sirupsen/logrus"
)

View File

@@ -5,8 +5,8 @@ import (
"regexp"
"strings"
"github.com/eiblog/eiblog/v2/pkg/config"
"github.com/eiblog/eiblog/v2/pkg/model"
"github.com/eiblog/eiblog/pkg/config"
"github.com/eiblog/eiblog/pkg/model"
"github.com/eiblog/blackfriday"
)

View File

@@ -1,2 +1,312 @@
// Package store provides ...
package store
import (
"context"
"sort"
"time"
"github.com/eiblog/eiblog/pkg/config"
"github.com/eiblog/eiblog/pkg/model"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"go.mongodb.org/mongo-driver/mongo/readpref"
)
const (
mongoDBName = "eiblog"
collectionAccount = "account"
collectionArticle = "article"
collectionBlogger = "blogger"
collectionCounter = "counter"
collectionSeries = "series"
counterNameSerie = "serie"
counterNameArticle = "article"
)
type mongodb struct {
*mongo.Client
}
// Init init mongodb client
func (db *mongodb) Init(source string) (Store, error) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
opts := options.Client().ApplyURI(source)
client, err := mongo.Connect(ctx, opts)
if err != nil {
return nil, err
}
err = client.Ping(ctx, readpref.Primary())
if err != nil {
return nil, err
}
db.Client = client
return db, nil
}
// LoadInsertAccount 读取或创建账户
func (db *mongodb) LoadInsertAccount(ctx context.Context, acct *model.Account) (*model.Account, error) {
collection := db.Database(mongoDBName).Collection(collectionAccount)
filter := bson.M{"username": config.Conf.BlogApp.Account.Username}
result := collection.FindOne(ctx, filter)
err := result.Err()
if err != nil {
if err != mongo.ErrNoDocuments {
return nil, err
}
_, err = collection.InsertOne(ctx, acct)
} else {
err = result.Decode(acct)
}
return acct, err
}
// LoadInsertBlogger 读取或创建博客
func (db *mongodb) LoadInsertBlogger(ctx context.Context, blogger *model.Blogger) (*model.Blogger, error) {
collection := db.Database(mongoDBName).Collection(collectionBlogger)
filter := bson.M{}
result := collection.FindOne(ctx, filter)
err := result.Err()
if err != nil {
if err != mongo.ErrNoDocuments {
return nil, err
}
_, err = collection.InsertOne(ctx, blogger)
} else {
err = result.Decode(blogger)
}
return blogger, err
}
// LoadAllArticle 读取所有文章
func (db *mongodb) LoadAllArticle(ctx context.Context) (model.SortedArticles, error) {
collection := db.Database(mongoDBName).Collection(collectionArticle)
filter := bson.M{"isdraft": false, "deletetime": bson.M{"$eq": time.Time{}}}
cur, err := collection.Find(ctx, filter)
if err != nil {
return nil, err
}
defer cur.Close(ctx)
var articles model.SortedArticles
for cur.Next(ctx) {
article := model.Article{}
err = cur.Decode(&article)
if err != nil {
return nil, err
}
articles = append(articles, &article)
}
sort.Sort(articles)
return articles, nil
}
// LoadTrashArticles 读取回收箱
func (db *mongodb) LoadTrashArticles(ctx context.Context) (model.SortedArticles, error) {
collection := db.Database(mongoDBName).Collection(collectionArticle)
filter := bson.M{"deletetime": bson.M{"$ne": time.Time{}}}
cur, err := collection.Find(ctx, filter)
if err != nil {
return nil, err
}
defer cur.Close(ctx)
var articles model.SortedArticles
for cur.Next(ctx) {
article := model.Article{}
err = cur.Decode(&article)
if err != nil {
return nil, err
}
articles = append(articles, &article)
}
sort.Sort(articles)
return articles, nil
}
// LoadDraftArticles 读取草稿箱
func (db *mongodb) LoadDraftArticles(ctx context.Context) (model.SortedArticles, error) {
collection := db.Database(mongoDBName).Collection(collectionArticle)
filter := bson.M{"isdraft": true}
cur, err := collection.Find(ctx, filter)
if err != nil {
return nil, err
}
defer cur.Close(ctx)
var articles model.SortedArticles
for cur.Next(ctx) {
article := model.Article{}
err = cur.Decode(&article)
if err != nil {
return nil, err
}
articles = append(articles, &article)
}
sort.Sort(articles)
return articles, nil
}
// InsertSeries 创建专题
func (db *mongodb) InsertSeries(ctx context.Context, series *model.Series) error {
collection := db.Database(mongoDBName).Collection(collectionSeries)
series.ID = db.nextValue(ctx, counterNameSerie)
_, err := collection.InsertOne(ctx, series)
return err
}
// RemoveSeries 删除专题
func (db *mongodb) RemoveSeries(ctx context.Context, id int) error {
collection := db.Database(mongoDBName).Collection(collectionSeries)
filter := bson.M{"id": id}
_, err := collection.DeleteOne(ctx, filter)
return err
}
// UpdateSeries 更新专题
func (db *mongodb) UpdateSeries(ctx context.Context, series *model.Series) error {
collection := db.Database(mongoDBName).Collection(collectionSeries)
filter := bson.M{"id": series.ID}
update := bson.M{"$set": bson.M{"desc": series.Desc}}
_, err := collection.UpdateOne(ctx, filter, update)
return err
}
// InsertArticle 创建文章
func (db *mongodb) InsertArticle(ctx context.Context, article *model.Article) error {
// 分配ID, 占位至起始id
for {
id := db.nextValue(ctx, counterNameArticle)
if id < config.Conf.BlogApp.General.StartID {
continue
} else {
article.ID = id
break
}
}
collection := db.Database(mongoDBName).Collection(collectionArticle)
_, err := collection.InsertOne(ctx, article)
return err
}
// DeleteArticle 软删除文章,放入回收箱
func (db *mongodb) DeleteArticle(ctx context.Context, id int) error {
collection := db.Database(mongoDBName).Collection(collectionArticle)
filter := bson.M{"id": id}
update := bson.M{"$set": bson.M{"deletetime": time.Now()}}
_, err := collection.UpdateOne(ctx, filter, update)
return err
}
// RemoveArticle 硬删除文章
func (db *mongodb) RemoveArticle(ctx context.Context, id int) error {
collection := db.Database(mongoDBName).Collection(collectionArticle)
filter := bson.M{"id": id}
_, err := collection.DeleteOne(ctx, filter)
return err
}
// CleanArticles 清理回收站文章
func (db *mongodb) CleanArticles(ctx context.Context) error {
collection := db.Database(mongoDBName).Collection(collectionArticle)
exp := time.Now().Add(time.Duration(config.Conf.BlogApp.General.Trash) * time.Hour)
filter := bson.M{"deletetime": bson.M{"$gt": time.Time{}, "$lt": exp}}
_, err := collection.DeleteMany(ctx, filter)
return err
}
// RecoverArticle 恢复文章到草稿
func (db *mongodb) RecoverArticle(ctx context.Context, id int) error {
collection := db.Database(mongoDBName).Collection(collectionArticle)
filter := bson.M{"id": id}
update := bson.M{"$set": bson.M{"deletetime": time.Time{}, "isdraft": true}}
_, err := collection.UpdateOne(ctx, filter, update)
return err
}
// UpdateAccount 更新账户
func (db *mongodb) UpdateAccount(ctx context.Context, name string, fields map[string]interface{}) error {
collection := db.Database(mongoDBName).Collection(collectionAccount)
filter := bson.M{"username": name}
update := bson.M{}
for k, v := range fields {
update[k] = v
}
_, err := collection.UpdateOne(ctx, filter, update)
return err
}
// UpdateBlogger 更新博客
func (db *mongodb) UpdateBlogger(ctx context.Context, fields map[string]interface{}) error {
collection := db.Database(mongoDBName).Collection(collectionBlogger)
filter := bson.M{}
update := bson.M{}
for k, v := range fields {
update[k] = v
}
_, err := collection.UpdateOne(ctx, filter, update)
return err
}
// UpdateArticle 更新文章
func (db *mongodb) UpdateArticle(ctx context.Context, article *model.Article) error {
collection := db.Database(mongoDBName).Collection(collectionBlogger)
filter := bson.M{"id": article.ID}
update := bson.M{"$set": bson.M{
"title": article.Title,
"content": article.Content,
"updatetime": article.UpdateTime,
"createtime": article.CreateTime,
}}
_, err := collection.UpdateOne(ctx, filter, update)
return err
}
// counter counter
type counter struct {
Name string
NextVal int
}
// nextValue counter value
func (db *mongodb) nextValue(ctx context.Context, name string) int {
collection := db.Database(mongoDBName).Collection(collectionCounter)
opts := options.FindOneAndUpdate().SetUpsert(true).
SetReturnDocument(options.After)
filter := bson.M{"name": name}
update := bson.M{"$inc": bson.M{"nextval": 1}}
next := counter{}
err := collection.FindOneAndUpdate(ctx, filter, update, opts).Decode(&next)
if err != nil {
return -1
}
return next.NextVal
}
// register store
func init() {
Register("mongodb", &mongodb{})
}

12
pkg/cache/store/mongodb_test.go vendored Normal file
View File

@@ -0,0 +1,12 @@
// Package store provides ...
package store
var store Store
func init() {
var err error
store, err = NewStore("mongodb", "mongodb://127.0.0.1:27017")
if err != nil {
panic(err)
}
}

View File

@@ -2,11 +2,12 @@
package store
import (
"context"
"fmt"
"sort"
"sync"
"github.com/eiblog/eiblog/v2/pkg/model"
"github.com/eiblog/eiblog/pkg/model"
)
var (
@@ -16,14 +17,41 @@ var (
// Store 存储后端
type Store interface {
LoadOrCreateAccount(acct *model.Account) (*model.Account, error)
LoadOrCreateBlogger(blogger *model.Blogger) (*model.Blogger, error)
LoadAllArticles() ([]*model.Article, error)
// LoadInsertAccount 读取或创建账户
LoadInsertAccount(ctx context.Context, acct *model.Account) (*model.Account, error)
// LoadInsertBlogger 读取或创建博客
LoadInsertBlogger(ctx context.Context, blogger *model.Blogger) (*model.Blogger, error)
// LoadAllArticle 读取所有文章
LoadAllArticle(ctx context.Context) (model.SortedArticles, error)
// LoadTrashArticles 读取回收箱
LoadTrashArticles(ctx context.Context) (model.SortedArticles, error)
// LoadDraftArticles 读取草稿箱
LoadDraftArticles(ctx context.Context) (model.SortedArticles, error)
UpdateAccount(name string, fields map[string]interface{}) error
UpdateBlogger(fields map[string]interface{}) error
UpdateArticle(article *model.Article) error
CleanArticles() error
// InsertSeries 创建专题
InsertSeries(ctx context.Context, series *model.Series) error
// RemoveSeries 删除专题
RemoveSeries(ctx context.Context, id int) error
// UpdateSeries 更新专题
UpdateSeries(ctx context.Context, series *model.Series) error
// InsertArticle 创建文章
InsertArticle(ctx context.Context, article *model.Article) error
// DeleteArticle 软删除文章,放入回收箱
DeleteArticle(ctx context.Context, id int) error
// RemoveArticle 硬删除文章
RemoveArticle(ctx context.Context, id int) error
// CleanArticles 清理回收站文章
CleanArticles(ctx context.Context) error
// RecoverArticle 恢复文章到草稿
RecoverArticle(ctx context.Context, id int) error
// UpdateAccount 更新账户
UpdateAccount(ctx context.Context, name string, fields map[string]interface{}) error
// UpdateBlogger 更新博客
UpdateBlogger(ctx context.Context, fields map[string]interface{}) error
// UpdateArticle 更新文章
UpdateArticle(ctx context.Context, article *model.Article) error
}
// Driver 存储驱动

View File

@@ -42,7 +42,7 @@ type Database struct {
type General struct {
PageNum int `yaml:"pagenum"` // 前台每页文章数量
PageSize int `yaml:"pagesize"` // 后台每页文章数量
StartID int32 `yaml:"startid"` // 文章启始ID
StartID int `yaml:"startid"` // 文章启始ID
DescPrefix string `yaml:"descprefix"` // 文章描述前缀
Identifier string `yaml:"identifier"` // 文章截取标识
Length int `yaml:"length"` // 文章预览长度

View File

@@ -7,8 +7,8 @@ import (
"text/template"
"time"
"github.com/eiblog/eiblog/v2/pkg/cache"
"github.com/eiblog/eiblog/v2/pkg/config"
"github.com/eiblog/eiblog/pkg/cache"
"github.com/eiblog/eiblog/pkg/config"
"github.com/eiblog/utils/tmpl"
"github.com/sirupsen/logrus"

View File

@@ -13,13 +13,12 @@ import (
"text/template"
"time"
"github.com/eiblog/eiblog/setting"
"github.com/eiblog/eiblog/v2/pkg/cache"
"github.com/eiblog/eiblog/v2/pkg/config"
"github.com/eiblog/eiblog/v2/pkg/internal"
"github.com/eiblog/eiblog/v2/tools"
"github.com/eiblog/utils/tmpl"
"github.com/eiblog/eiblog/pkg/cache"
"github.com/eiblog/eiblog/pkg/config"
"github.com/eiblog/eiblog/pkg/internal"
"github.com/eiblog/eiblog/tools"
"github.com/eiblog/utils/tmpl"
"github.com/gin-gonic/gin"
"github.com/sirupsen/logrus"
)
@@ -239,9 +238,9 @@ func handleBeaconPage(c *gin.Context) {
ua := c.Request.UserAgent()
vals := c.Request.URL.Query()
vals.Set("v", setting.Conf.Google.V)
vals.Set("tid", setting.Conf.Google.Tid)
vals.Set("t", setting.Conf.Google.T)
vals.Set("v", config.Conf.BlogApp.Google.V)
vals.Set("tid", config.Conf.BlogApp.Google.Tid)
vals.Set("t", config.Conf.BlogApp.Google.T)
cookie, _ := c.Cookie("u")
vals.Set("cid", cookie)

View File

@@ -2,7 +2,7 @@
package swag
import (
_ "github.com/eiblog/eiblog/v2/pkg/core/blog/docs" // docs
_ "github.com/eiblog/eiblog/pkg/core/blog/docs" // docs
"github.com/gin-gonic/gin"
ginSwagger "github.com/swaggo/gin-swagger"

View File

@@ -10,8 +10,8 @@ import (
"net/url"
"strings"
"github.com/eiblog/eiblog/v2/pkg/config"
"github.com/eiblog/eiblog/v2/pkg/model"
"github.com/eiblog/eiblog/pkg/config"
"github.com/eiblog/eiblog/pkg/model"
)
// disqus api

View File

@@ -12,7 +12,7 @@ import (
"strings"
"time"
"github.com/eiblog/eiblog/v2/pkg/config"
"github.com/eiblog/eiblog/pkg/config"
"github.com/sirupsen/logrus"
)
@@ -30,7 +30,7 @@ func init() {
}
mappings := fmt.Sprintf(`{"mappings":{"%s":{"properties":{"content":{"analyzer":"ik_syno","search_analyzer":"ik_syno","term_vector":"with_positions_offsets","type":"string"},"date":{"index":"not_analyzed","type":"date"},"slug":{"type":"string"},"tag":{"index":"not_analyzed","type":"string"},"title":{"analyzer":"ik_syno","search_analyzer":"ik_syno","term_vector":"with_positions_offsets","type":"string"}}}}}`, "article")
err := createIndexAndMappings("article", "eiblog", []byte(mappings))
err := createIndexAndMappings("eiblog", "article", []byte(mappings))
if err != nil {
panic(err)
}
@@ -130,7 +130,7 @@ func createIndexAndMappings(index, typ string, mappings []byte) error {
result := indicesCreateResult{}
err = json.Unmarshal(data, &result)
if err != nil {
return err
return errors.New(string(data))
}
if !result.Acknowledged {
return errors.New(string(data))

View File

@@ -36,16 +36,21 @@ func newRequest(method, rawurl string, data interface{}) (*http.Request, error)
if err != nil {
return nil, err
}
host := u.Host
originHost := u.Host
// 获取主机IP
ips, err := net.LookupHost(u.Host)
host, port, err := net.SplitHostPort(u.Host)
if err != nil {
return nil, err
}
ips, err := net.LookupHost(host)
if err != nil {
return nil, err
}
if len(ips) == 0 {
return nil, fmt.Errorf("http: not found ip(%s)", u.Host)
}
u.Host = ips[0]
host = net.JoinHostPort(ips[0], port)
u.Host = host
// 创建HTTP Request
var req *http.Request
switch raw := data.(type) {
@@ -65,7 +70,7 @@ func newRequest(method, rawurl string, data interface{}) (*http.Request, error)
return nil, err
}
// 设置Host
req.Host = host
req.Host = originHost
return req, nil
}

View File

@@ -9,7 +9,8 @@ import (
"net/http"
"net/url"
"github.com/eiblog/eiblog/v2/pkg/config"
"github.com/eiblog/eiblog/pkg/config"
"github.com/sirupsen/logrus"
)

View File

@@ -7,7 +7,7 @@ import (
"io"
"path/filepath"
"github.com/eiblog/eiblog/v2/pkg/config"
"github.com/eiblog/eiblog/pkg/config"
"github.com/qiniu/api.v7/v7/auth/qbox"
"github.com/qiniu/api.v7/v7/storage"

View File

@@ -5,7 +5,7 @@ import "time"
// Article 文章
type Article struct {
ID int32 `gorm:"primaryKey;autoIncrement"` // 自增ID
ID int `gorm:"primaryKey;autoIncrement"` // 自增ID
Author string `gorm:"not null"` // 作者名
Slug string `gorm:"not null;uniqueIndex"` // 文章缩略名
Title string `gorm:"not null"` // 标题

View File

@@ -5,7 +5,7 @@ import "time"
// Series 专题
type Series struct {
ID int32 `gorm:"primaryKey;autoIncrement"` // 自增ID
ID int `gorm:"primaryKey;autoIncrement"` // 自增ID
Slug string `gorm:"not null;uniqueIndex"` // 缩略名
Name string `gorm:"not null"` // 专题名
Desc string `gorm:"not null"` // 专题描述