From c3fdbfcb78e2f50abd082c412858386fabd4e225 Mon Sep 17 00:00:00 2001 From: deepzz0 Date: Tue, 27 Apr 2021 14:02:52 +0800 Subject: [PATCH] chore: remove blogger config --- conf/app.yml | 9 --- pkg/cache/cache.go | 75 +++++++++--------- pkg/cache/store/mongodb.go | 45 ++++++++--- pkg/cache/store/mongodb_test.go | 1 + pkg/cache/store/store.go | 5 +- pkg/core/blog/page/page.go | 134 +++++++++++++++++++++++++++++++- pkg/internal/pinger.go | 14 ++-- tools/tools.go | 65 ++++++++++++++++ website/homeLayout.html | 2 +- 9 files changed, 280 insertions(+), 70 deletions(-) diff --git a/conf/app.yml b/conf/app.yml index 5621927..ad2bd6b 100644 --- a/conf/app.yml +++ b/conf/app.yml @@ -54,15 +54,6 @@ blogapp: account: username: deepzz # *后台登录用户名 password: deepzz # *登录明文密码 - email: chenqijing2@163.com # 邮箱,用于通知: chenqijing2@163.com - phonenumber: "+8615100000000" # 手机号, "+8615100000000" - address: "" # 家庭住址 - blogger: - blogname: Deepzz # left显示名称: Deepzz - subtitle: 不抛弃,不放弃 # 小标题: 不抛弃,不放弃 - beian: 蜀 ICP 备 16021362 号 # 备案号: 蜀 ICP 备 16021362 号 - btitle: Deepzz's Blog # footer显示名称及tab标题: Deepzz's Blog - copyright: 本站使用「署名 4.0 国际」创作共享协议,转载请注明作者及原网址。 # 版权声明 backupapp: name: cmd-backup enablehttp: true diff --git a/pkg/cache/cache.go b/pkg/cache/cache.go index 3312b5c..c08efc1 100644 --- a/pkg/cache/cache.go +++ b/pkg/cache/cache.go @@ -41,17 +41,7 @@ func init() { TagArticles: make(map[string]model.SortedArticles), ArticlesMap: make(map[string]*model.Article), } - err = Ei.loadAccount() - if err != nil { - panic(err) - } - // blogger - err = Ei.loadBlogger() - if err != nil { - panic(err) - } - // articles - err = Ei.loadArticles() + err = Ei.loadOrInit() if err != nil { panic(err) } @@ -151,47 +141,60 @@ func (c *Cache) PageArticles(page int, pageSize int) (prev, return } -// loadBlogger 博客信息 -func (c *Cache) loadBlogger() error { +// loadOrInit 读取数据或初始化 +func (c *Cache) loadOrInit() error { blogapp := config.Conf.BlogApp + // blogger blogger := &model.Blogger{ - BlogName: blogapp.Blogger.BlogName, - SubTitle: blogapp.Blogger.SubTitle, - BeiAn: blogapp.Blogger.BeiAn, - BTitle: blogapp.Blogger.BTitle, - Copyright: blogapp.Blogger.Copyright, + BlogName: strings.Title(blogapp.Account.Username), + SubTitle: "Rome was not built in one day.", + BeiAn: "蜀ICP备xxxxxxxx号-1", + BTitle: fmt.Sprintf("%s's Blog", strings.Title(blogapp.Account.Username)), + Copyright: `本站使用「署名 4.0 国际」创作共享协议,转载请注明作者及原网址。`, } - blogger, err := c.LoadInsertBlogger(context.Background(), blogger) + created, err := c.LoadInsertBlogger(context.Background(), blogger) if err != nil { return err } c.Blogger = blogger - return nil -} - -// loadAccount 账户账户信息 -func (c *Cache) loadAccount() error { - blogapp := config.Conf.BlogApp + if created { // init articles: about blogroll + about := &model.Article{ + ID: 1, // 固定ID + Author: blogapp.Account.Username, + Title: "关于", + Slug: "about", + } + err = c.InsertArticle(context.Background(), about) + if err != nil { + return err + } + // 推送到 disqus + go internal.ThreadCreate(about, blogger.BTitle) + blogroll := &model.Article{ + ID: 2, // 固定ID + Author: blogapp.Account.Username, + Title: "友情链接", + Slug: "blogroll", + } + err = c.InsertArticle(context.Background(), blogroll) + if err != nil { + return err + } + } + // account pwd := tools.EncryptPasswd(blogapp.Account.Password, blogapp.Account.Password) account := &model.Account{ Username: blogapp.Account.Username, Password: pwd, - Email: blogapp.Account.Email, - PhoneN: blogapp.Account.PhoneNumber, - Address: blogapp.Account.Address, } - account, err := c.LoadInsertAccount(context.Background(), account) + _, err = c.LoadInsertAccount(context.Background(), account) if err != nil { return err } c.Account = account - return nil -} - -// loadArticles 文章信息 -func (c *Cache) loadArticles() error { + // all articles articles, err := c.LoadAllArticle(context.Background()) if err != nil { return err @@ -204,13 +207,13 @@ func (c *Cache) loadArticles() error { c.ArticlesMap[v.Slug] = v // 分析文章 - if v.ID < config.Conf.BlogApp.General.StartID { + if v.ID < blogapp.General.StartID { continue } if i > 0 { v.Prev = Ei.Articles[i-1] } - if Ei.Articles[i+1].ID >= config.Conf.BlogApp.General.StartID { + if Ei.Articles[i+1].ID >= blogapp.General.StartID { v.Next = Ei.Articles[i+1] } c.rebuildArticle(v, false) diff --git a/pkg/cache/store/mongodb.go b/pkg/cache/store/mongodb.go index 10f303e..831eae1 100644 --- a/pkg/cache/store/mongodb.go +++ b/pkg/cache/store/mongodb.go @@ -50,27 +50,50 @@ func (db *mongodb) Init(source string) (Store, error) { return nil, err } db.Client = client + // create index + indexModel := mongo.IndexModel{ + Keys: bson.D{{"username", 1}}, + Options: options.Index().SetUnique(true).SetSparse(true), + } + db.Database(mongoDBName).Collection(collectionAccount). + Indexes(). + CreateOne(context.Background(), indexModel) + indexModel = mongo.IndexModel{ + Keys: bson.D{{"slug", 1}}, + Options: options.Index().SetUnique(true).SetSparse(true), + } + db.Database(mongoDBName).Collection(collectionArticle). + Indexes(). + CreateOne(context.Background(), indexModel) + indexModel = mongo.IndexModel{ + Keys: bson.D{{"slug", 1}}, + Options: options.Index().SetUnique(true).SetSparse(true), + } + db.Database(mongoDBName).Collection(collectionSeries). + Indexes(). + CreateOne(context.Background(), indexModel) return db, nil } // LoadInsertBlogger 读取或创建博客 func (db *mongodb) LoadInsertBlogger(ctx context.Context, - blogger *model.Blogger) (*model.Blogger, error) { + blogger *model.Blogger) (created bool, err error) { collection := db.Database(mongoDBName).Collection(collectionBlogger) filter := bson.M{} result := collection.FindOne(ctx, filter) - err := result.Err() + err = result.Err() if err != nil { if err != mongo.ErrNoDocuments { - return nil, err + return } _, err = collection.InsertOne(ctx, blogger) + created = true } else { err = result.Decode(blogger) } - return blogger, err + return } // UpdateBlogger 更新博客 @@ -91,22 +114,23 @@ func (db *mongodb) UpdateBlogger(ctx context.Context, // LoadInsertAccount 读取或创建账户 func (db *mongodb) LoadInsertAccount(ctx context.Context, - acct *model.Account) (*model.Account, error) { + acct *model.Account) (created bool, err error) { collection := db.Database(mongoDBName).Collection(collectionAccount) filter := bson.M{"username": config.Conf.BlogApp.Account.Username} result := collection.FindOne(ctx, filter) - err := result.Err() + err = result.Err() if err != nil { if err != mongo.ErrNoDocuments { - return nil, err + return } _, err = collection.InsertOne(ctx, acct) + created = true } else { err = result.Decode(acct) } - return acct, err + return } // UpdateAccount 更新账户 @@ -185,14 +209,13 @@ func (db *mongodb) LoadAllSeries(ctx context.Context) (model.SortedSeries, error // InsertArticle 创建文章 func (db *mongodb) InsertArticle(ctx context.Context, article *model.Article) error { - // 分配ID, 占位至起始id - for { + // 可手动分配ID或者分配ID, 占位至起始id + for article.ID == 0 { id := db.nextValue(ctx, counterNameArticle) if id < config.Conf.BlogApp.General.StartID { continue } else { article.ID = id - break } } diff --git a/pkg/cache/store/mongodb_test.go b/pkg/cache/store/mongodb_test.go index a2e524e..0bbe04c 100644 --- a/pkg/cache/store/mongodb_test.go +++ b/pkg/cache/store/mongodb_test.go @@ -135,6 +135,7 @@ func TestLoadAllSeries(t *testing.T) { } func TestInsertArticle(t *testing.T) { + article.ID = 12 err := store.InsertArticle(context.Background(), article) if err != nil { t.Fatal(err) diff --git a/pkg/cache/store/store.go b/pkg/cache/store/store.go index 4ca9538..8d2b7b3 100644 --- a/pkg/cache/store/store.go +++ b/pkg/cache/store/store.go @@ -18,12 +18,12 @@ var ( // Store 存储后端 type Store interface { // LoadInsertBlogger 读取或创建博客 - LoadInsertBlogger(ctx context.Context, blogger *model.Blogger) (*model.Blogger, error) + LoadInsertBlogger(ctx context.Context, blogger *model.Blogger) (bool, error) // UpdateBlogger 更新博客 UpdateBlogger(ctx context.Context, fields map[string]interface{}) error // LoadInsertAccount 读取或创建账户 - LoadInsertAccount(ctx context.Context, acct *model.Account) (*model.Account, error) + LoadInsertAccount(ctx context.Context, acct *model.Account) (bool, error) // UpdateAccount 更新账户 UpdateAccount(ctx context.Context, name string, fields map[string]interface{}) error @@ -58,6 +58,7 @@ type Store interface { // Driver 存储驱动 type Driver interface { + // Init 数据库初始化, 建表, 加索引操作等 Init(source string) (Store, error) } diff --git a/pkg/core/blog/page/page.go b/pkg/core/blog/page/page.go index 432b686..df64888 100644 --- a/pkg/core/blog/page/page.go +++ b/pkg/core/blog/page/page.go @@ -50,7 +50,9 @@ func RegisterRoutes(e *gin.Engine) { e.GET("/series.html", handleSeriesPage) e.GET("/archives.html", handleArchivePage) e.GET("/search.html", handleSearchPage) + e.GET("/disqus/post-:slug", handleDisqusList) e.GET("/disqus/form/post-:slug", handleDisqusPage) + e.POST("/disqus/create", handleDisqusCreate) e.GET("/beacon.html", handleBeaconPage) } @@ -80,7 +82,7 @@ func baseParams(c *gin.Context) gin.H { // handleNotFound not found page func handleNotFound(c *gin.Context) { params := baseParams(c) - params["title"] = "Not Found" + params["Title"] = "Not Found" params["Description"] = "404 Not Found" params["Path"] = "" c.Status(http.StatusNotFound) @@ -90,7 +92,7 @@ func handleNotFound(c *gin.Context) { // handleHomePage 首页 func handleHomePage(c *gin.Context) { params := baseParams(c) - params["title"] = cache.Ei.Blogger.BTitle + " | " + cache.Ei.Blogger.SubTitle + params["Title"] = cache.Ei.Blogger.BTitle + " | " + cache.Ei.Blogger.SubTitle params["Description"] = "博客首页," + cache.Ei.Blogger.SubTitle params["Path"] = c.Request.URL.Path params["CurrentPage"] = "blog-home" @@ -212,6 +214,58 @@ func handleSearchPage(c *gin.Context) { renderHTMLHomeLayout(c, "search", params) } +// disqusComments 服务端获取评论详细 +type disqusComments struct { + ErrNo int `json:"errno"` + ErrMsg string `json:"errmsg"` + Data struct { + Next string `json:"next"` + Total int `json:"total"` + Comments []commentsDetail `json:"comments"` + Thread string `json:"thread"` + } `json:"data"` +} + +// handleDisqusList 获取评论列表 +func handleDisqusList(c *gin.Context) { + dcs := &disqusComments{} + defer c.JSON(http.StatusOK, dcs) + + slug := c.Param("slug") + cursor := c.Query("cursor") + if artc := cache.Ei.ArticlesMap[slug]; artc != nil { + dcs.Data.Thread = artc.Thread + } + postsList, err := internal.PostsList(slug, cursor) + if err != nil { + logrus.Error("hadnleDisqusList.PostsList: ", err) + dcs.ErrNo = 0 + dcs.ErrMsg = "系统错误" + return + } + dcs.ErrNo = postsList.Code + if postsList.Cursor.HasNext { + dcs.Data.Next = postsList.Cursor.Next + } + dcs.Data.Total = len(postsList.Response) + dcs.Data.Comments = make([]commentsDetail, len(postsList.Response)) + for i, v := range postsList.Response { + if dcs.Data.Thread == "" { + dcs.Data.Thread = v.Thread + } + dcs.Data.Comments[i] = commentsDetail{ + ID: v.ID, + Name: v.Author.Name, + Parent: v.Parent, + Url: v.Author.ProfileUrl, + Avatar: v.Author.Avatar.Cache, + CreatedAtStr: tools.ConvertStr(v.CreatedAt), + Message: v.Message, + IsDeleted: v.IsDeleted, + } + } +} + // handleDisqusPage 评论页 func handleDisqusPage(c *gin.Context) { array := strings.Split(c.Param("slug"), "|") @@ -221,7 +275,7 @@ func handleDisqusPage(c *gin.Context) { } article := cache.Ei.ArticlesMap[array[0]] params := gin.H{ - "Titile": "发表评论 | " + config.Conf.BlogApp.Blogger.BTitle, + "Titile": "发表评论 | " + cache.Ei.Blogger.BTitle, "ATitle": article.Title, "Thread": array[1], "Slug": article.Slug, @@ -233,6 +287,78 @@ func handleDisqusPage(c *gin.Context) { c.Header("Content-Type", "text/html; charset=utf-8") } +// 发表评论 +// [thread:[5279901489] parent:[] identifier:[post-troubleshooting-https] +// next:[] author_name:[你好] author_email:[chenqijing2@163.com] message:[fdsfdsf]] +type disqusCreate struct { + ErrNo int `json:"errno"` + ErrMsg string `json:"errmsg"` + Data commentsDetail `json:"data"` +} + +type commentsDetail struct { + ID string `json:"id"` + Parent int `json:"parent"` + Name string `json:"name"` + Url string `json:"url"` + Avatar string `json:"avatar"` + CreatedAtStr string `json:"createdAtStr"` + Message string `json:"message"` + IsDeleted bool `json:"isDeleted"` +} + +// handleDisqusCreate 评论文章 +func handleDisqusCreate(c *gin.Context) { + resp := &disqusCreate{} + defer c.JSON(http.StatusOK, resp) + + msg := c.PostForm("message") + email := c.PostForm("author_name") + name := c.PostForm("author_name") + thread := c.PostForm("thread") + identifier := c.PostForm("identifier") + if msg == "" || email == "" || name == "" || thread == "" || identifier == "" { + resp.ErrNo = 1 + resp.ErrMsg = "参数错误" + return + } + logrus.Info("email: %s comments: %s", email, thread) + + comment := internal.PostComment{ + Message: msg, + Parent: c.PostForm("parent"), + Thread: thread, + AuthorEmail: email, + AuthorName: name, + Identifier: identifier, + IpAddress: c.ClientIP(), + } + postDetail, err := internal.PostCreate(&comment) + if err != nil { + logrus.Error("handleDisqusCreate.PostCreate: ", err) + resp.ErrNo = 1 + resp.ErrMsg = "提交评论失败,请重试" + return + } + err = internal.PostApprove(postDetail.Response.ID) + if err != nil { + logrus.Error("handleDisqusCreate.PostApprove: ", err) + resp.ErrNo = 1 + resp.ErrMsg = "提交评论失败,请重试" + } + resp.ErrNo = 0 + resp.Data = commentsDetail{ + ID: postDetail.Response.ID, + Name: name, + Parent: postDetail.Response.Parent, + Url: postDetail.Response.Author.ProfileUrl, + Avatar: postDetail.Response.Author.Avatar.Cache, + CreatedAtStr: tools.ConvertStr(postDetail.Response.CreatedAt), + Message: postDetail.Response.Message, + IsDeleted: postDetail.Response.IsDeleted, + } +} + // handleBeaconPage 服务端推送谷歌统计 func handleBeaconPage(c *gin.Context) { ua := c.Request.UserAgent() @@ -281,7 +407,7 @@ func renderHTMLHomeLayout(c *gin.Context, name string, data gin.H) { panic(err) } data["LayoutContent"] = htemplate.HTML(buf.String()) - err = htmlTmpl.ExecuteTemplate(c.Writer, "homelayout.html", data) + err = htmlTmpl.ExecuteTemplate(c.Writer, "homeLayout.html", data) if err != nil { panic(err) } diff --git a/pkg/internal/pinger.go b/pkg/internal/pinger.go index b200b83..5849067 100644 --- a/pkg/internal/pinger.go +++ b/pkg/internal/pinger.go @@ -10,12 +10,12 @@ import ( "net/url" "github.com/eiblog/eiblog/pkg/config" - + "github.com/sirupsen/logrus" ) // feedrPingFunc http://.superfeedr.com/ -var feedrPingFunc = func(slug string) error { +var feedrPingFunc = func(btitle, slug string) error { feedrHost := config.Conf.BlogApp.FeedRPC.FeedrURL if feedrHost == "" { return nil @@ -60,13 +60,13 @@ type rpcValue struct { } // rpcPingFunc ping rpc -var rpcPingFunc = func(slug string) error { +var rpcPingFunc = func(btitle, slug string) error { if len(config.Conf.BlogApp.FeedRPC.PingRPC) == 0 { return nil } param := rpcPingParam{MethodName: "weblogUpdates.extendedPing"} param.Params.Param = [4]rpcValue{ - 0: rpcValue{Value: config.Conf.BlogApp.Blogger.BTitle}, + 0: rpcValue{Value: btitle}, 1: rpcValue{Value: "https://" + config.Conf.BlogApp.Host}, 2: rpcValue{Value: fmt.Sprintf("https://%s/post/%s.html", config.Conf.BlogApp.Host, slug)}, 3: rpcValue{Value: "https://" + config.Conf.BlogApp.Host + "/rss.html"}, @@ -100,12 +100,12 @@ var rpcPingFunc = func(slug string) error { } // PingFunc ping blog article to SE -func PingFunc(slug string) { - err := feedrPingFunc(slug) +func PingFunc(btitle, slug string) { + err := feedrPingFunc(btitle, slug) if err != nil { logrus.Error("pinger: PingFunc feedr: ", err) } - err = rpcPingFunc(slug) + err = rpcPingFunc(btitle, slug) if err != nil { logrus.Error("pinger: PingFunc: rpc: ", err) } diff --git a/tools/tools.go b/tools/tools.go index 33217cc..ef54b65 100644 --- a/tools/tools.go +++ b/tools/tools.go @@ -7,6 +7,7 @@ import ( "io" "io/ioutil" "path" + "time" ) // EncryptPasswd encrypt password @@ -37,3 +38,67 @@ func ReadDirFiles(dir string, filter func(name string) bool) (files []string) { } return } + +// 2016-10-22T07:03:01 +const ( + JUST_NOW = "几秒前" + MINUTES_AGO = "%d分钟前" + HOURS_AGO = "%d小时前" + DAYS_AGO = "%d天前" + MONTH_AGO = "%d月前" + YEARS_AGO = "%d年前" +) + +// ConvertStr 时间转换为间隔 +func ConvertStr(str string) string { + t, err := time.ParseInLocation("2006-01-02T15:04:05", str, time.UTC) + if err != nil { + return JUST_NOW + } + now := time.Now().UTC() + y1, m1, d1 := t.Date() + y2, m2, d2 := now.Date() + h1, mi1, s1 := t.Clock() + h2, mi2, s2 := now.Clock() + if y := y2 - y1; y > 1 || (y == 1 && m2-m1 >= 0) { + return fmt.Sprintf(YEARS_AGO, y) + } else if m := y*12 + int(m2-m1); m > 1 || (m == 1 && d2-d1 >= 0) { + return fmt.Sprintf(MONTH_AGO, m) + } else if d := m*dayIn(y1, m1) + d2 - d1; d > 1 || (d == 1 && h2-h1 >= 0) { + return fmt.Sprintf(DAYS_AGO, d) + } else if h := d*24 + h2 - h1; h > 1 || (h == 1 && mi2-mi1 >= 0) { + return fmt.Sprintf(HOURS_AGO, h) + } else if mi := h*60 + mi2 - mi1; mi > 1 || (mi == 1 && s2-s1 >= 0) { + return fmt.Sprintf(MINUTES_AGO, mi) + } + return JUST_NOW +} + +// dayIn 获取天数 +func dayIn(year int, m time.Month) int { + if m == time.February && isLeapYear(year) { + return 29 + } + return monthToDays[m] +} + +// monthToDays 月份转换 +var monthToDays = map[time.Month]int{ + time.January: 31, + time.February: 28, + time.March: 31, + time.April: 30, + time.May: 31, + time.June: 30, + time.July: 31, + time.August: 31, + time.September: 30, + time.October: 31, + time.November: 30, + time.December: 31, +} + +// isLeapYear是否是闰年 +func isLeapYear(year int) bool { + return year%4 == 0 && (year%100 != 0 || year%400 == 0) +} diff --git a/website/homeLayout.html b/website/homeLayout.html index 20c1d48..7436865 100644 --- a/website/homeLayout.html +++ b/website/homeLayout.html @@ -1 +1 @@ -{{.Title}}{{if .Version}}{{end}}{{if .Version}}{{else}}{{end}}
{{.LayoutContent}}
{{if .Version}}{{else}}{{end}}{{if .Version}}{{else}}{{end}}{{if .Version}}{{else}}{{end}}{{if .Version}}{{else}}{{end}} +{{.Title}}{{if .Version}}{{end}}{{if .Version}}{{else}}{{end}}
{{.LayoutContent}}
{{if .Version}}{{else}}{{end}}{{if .Version}}{{else}}{{end}}{{if .Version}}{{else}}{{end}}{{if .Version}}{{else}}{{end}}