mirror of
https://github.com/eiblog/eiblog.git
synced 2026-02-15 10:52:26 +08:00
chore: rename field name
This commit is contained in:
@@ -6,6 +6,8 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/eiblog/eiblog/pkg/config"
|
"github.com/eiblog/eiblog/pkg/config"
|
||||||
|
"github.com/eiblog/eiblog/pkg/core/blog"
|
||||||
|
"github.com/eiblog/eiblog/pkg/core/blog/admin"
|
||||||
"github.com/eiblog/eiblog/pkg/core/blog/file"
|
"github.com/eiblog/eiblog/pkg/core/blog/file"
|
||||||
"github.com/eiblog/eiblog/pkg/core/blog/page"
|
"github.com/eiblog/eiblog/pkg/core/blog/page"
|
||||||
"github.com/eiblog/eiblog/pkg/core/blog/swag"
|
"github.com/eiblog/eiblog/pkg/core/blog/swag"
|
||||||
@@ -51,8 +53,15 @@ func runHTTPServer(endRun chan bool) {
|
|||||||
page.RegisterRoutes(e)
|
page.RegisterRoutes(e)
|
||||||
// static files
|
// static files
|
||||||
file.RegisterRoutes(e)
|
file.RegisterRoutes(e)
|
||||||
|
// unauthz api
|
||||||
|
admin.RegisterRoutes(e)
|
||||||
|
|
||||||
// api router
|
// admin router
|
||||||
|
group := e.Group("/admin", blog.AuthFilter)
|
||||||
|
{
|
||||||
|
page.RegisterRoutesAuthz(group)
|
||||||
|
admin.RegisterRoutesAuthz(group)
|
||||||
|
}
|
||||||
|
|
||||||
// start
|
// start
|
||||||
address := fmt.Sprintf(":%d", config.Conf.BlogApp.HTTPPort)
|
address := fmt.Sprintf(":%d", config.Conf.BlogApp.HTTPPort)
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
{{range .Articles}}
|
{{range .Articles}}
|
||||||
<url>
|
<url>
|
||||||
<loc>https://{{$.Host}}/post/{{.Slug}}.html</loc>
|
<loc>https://{{$.Host}}/post/{{.Slug}}.html</loc>
|
||||||
<lastmod>{{dateformat .CreateTime "2006-01-02"}}</lastmod>
|
<lastmod>{{dateformat .CreatedAt "2006-01-02"}}</lastmod>
|
||||||
<priority>0.6</priority>
|
<priority>0.6</priority>
|
||||||
</url>
|
</url>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|||||||
2
go.mod
2
go.mod
@@ -4,6 +4,7 @@ go 1.15
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751
|
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751
|
||||||
|
github.com/deepzz0/logd v0.0.0-20171206094927-f91dd8c6316f
|
||||||
github.com/eiblog/blackfriday v0.0.0-20161010144836-c0ec111761ae
|
github.com/eiblog/blackfriday v0.0.0-20161010144836-c0ec111761ae
|
||||||
github.com/eiblog/utils v0.0.0-20181119015747-92c93e218753
|
github.com/eiblog/utils v0.0.0-20181119015747-92c93e218753
|
||||||
github.com/gin-contrib/sessions v0.0.3
|
github.com/gin-contrib/sessions v0.0.3
|
||||||
@@ -17,5 +18,6 @@ require (
|
|||||||
go.mongodb.org/mongo-driver v1.5.1
|
go.mongodb.org/mongo-driver v1.5.1
|
||||||
google.golang.org/grpc v1.35.0
|
google.golang.org/grpc v1.35.0
|
||||||
google.golang.org/protobuf v1.25.0
|
google.golang.org/protobuf v1.25.0
|
||||||
|
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 // indirect
|
||||||
gopkg.in/yaml.v2 v2.3.0
|
gopkg.in/yaml.v2 v2.3.0
|
||||||
)
|
)
|
||||||
|
|||||||
4
go.sum
4
go.sum
@@ -22,6 +22,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:ma
|
|||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/deepzz0/logd v0.0.0-20171206094927-f91dd8c6316f h1:hjWy8ptp0ggYgv/3A8dixSB9KTRgDcZH2D3Ap5hrwOs=
|
||||||
|
github.com/deepzz0/logd v0.0.0-20171206094927-f91dd8c6316f/go.mod h1:8jMj6ab9czIU5udq3ovaK9/5sCIyQ1JWteFMn8w2QRI=
|
||||||
github.com/eiblog/blackfriday v0.0.0-20161010144836-c0ec111761ae h1:V6YC640Gs5jEUYfCimyuXsTW5gzNcIEESG4MGmOJCtA=
|
github.com/eiblog/blackfriday v0.0.0-20161010144836-c0ec111761ae h1:V6YC640Gs5jEUYfCimyuXsTW5gzNcIEESG4MGmOJCtA=
|
||||||
github.com/eiblog/blackfriday v0.0.0-20161010144836-c0ec111761ae/go.mod h1:HzHqTCGEAkSSzBM3shBvQHsHRQYUvjNOIC4mHipZ6tI=
|
github.com/eiblog/blackfriday v0.0.0-20161010144836-c0ec111761ae/go.mod h1:HzHqTCGEAkSSzBM3shBvQHsHRQYUvjNOIC4mHipZ6tI=
|
||||||
github.com/eiblog/utils v0.0.0-20181119015747-92c93e218753 h1:Nygjtnh1nF5zejJF7pZnsoFh77wOPS+jlfhikjkJg60=
|
github.com/eiblog/utils v0.0.0-20181119015747-92c93e218753 h1:Nygjtnh1nF5zejJF7pZnsoFh77wOPS+jlfhikjkJg60=
|
||||||
@@ -350,6 +352,8 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
|||||||
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
|
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
|
||||||
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
|
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
|
||||||
gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
|
gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
|
||||||
|
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 h1:VpOs+IwYnYBaFnrNAeB8UUWtL3vEUnzSCL1nVjPhqrw=
|
||||||
|
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
|
||||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
|||||||
14
pkg/cache/cache.go
vendored
14
pkg/cache/cache.go
vendored
@@ -235,7 +235,7 @@ func (c *Cache) rebuildArticle(article *model.Article, needSort bool) {
|
|||||||
}
|
}
|
||||||
// series
|
// series
|
||||||
for i, series := range c.Series {
|
for i, series := range c.Series {
|
||||||
if series.ID == article.SerieID {
|
if series.ID == article.SeriesID {
|
||||||
c.Series[i].Articles = append(c.Series[i].Articles, article)
|
c.Series[i].Articles = append(c.Series[i].Articles, article)
|
||||||
if needSort {
|
if needSort {
|
||||||
sort.Sort(c.Series[i].Articles)
|
sort.Sort(c.Series[i].Articles)
|
||||||
@@ -244,7 +244,7 @@ func (c *Cache) rebuildArticle(article *model.Article, needSort bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// archive
|
// archive
|
||||||
y, m, _ := article.CreateTime.Date()
|
y, m, _ := article.CreatedAt.Date()
|
||||||
for i, archive := range c.Archives {
|
for i, archive := range c.Archives {
|
||||||
if ay, am, _ := archive.Time.Date(); y == ay && m == am {
|
if ay, am, _ := archive.Time.Date(); y == ay && m == am {
|
||||||
c.Archives[i].Articles = append(c.Archives[i].Articles, article)
|
c.Archives[i].Articles = append(c.Archives[i].Articles, article)
|
||||||
@@ -257,7 +257,7 @@ func (c *Cache) rebuildArticle(article *model.Article, needSort bool) {
|
|||||||
}
|
}
|
||||||
// 新建归档
|
// 新建归档
|
||||||
c.Archives = append(c.Archives, &model.Archive{
|
c.Archives = append(c.Archives, &model.Archive{
|
||||||
Time: article.CreateTime,
|
Time: article.CreatedAt,
|
||||||
Articles: model.SortedArticles{article},
|
Articles: model.SortedArticles{article},
|
||||||
})
|
})
|
||||||
if needSort { // 重建归档
|
if needSort { // 重建归档
|
||||||
@@ -282,7 +282,7 @@ func (c *Cache) regeneratePages() {
|
|||||||
for _, article := range series.Articles {
|
for _, article := range series.Articles {
|
||||||
//eg. * [标题一](/post/hello-world.html) <span class="date">(Man 02, 2006)</span>
|
//eg. * [标题一](/post/hello-world.html) <span class="date">(Man 02, 2006)</span>
|
||||||
str := fmt.Sprintf(`* [%s](/post/%s.html) <span class="date">(%s)</span>`,
|
str := fmt.Sprintf(`* [%s](/post/%s.html) <span class="date">(%s)</span>`,
|
||||||
article.Title, article.Slug, article.CreateTime.Format("Jan 02, 2006"))
|
article.Title, article.Slug, article.CreatedAt.Format("Jan 02, 2006"))
|
||||||
buf.WriteString(str)
|
buf.WriteString(str)
|
||||||
}
|
}
|
||||||
buf.WriteString("\n\n")
|
buf.WriteString("\n\n")
|
||||||
@@ -291,7 +291,7 @@ func (c *Cache) regeneratePages() {
|
|||||||
case pageArchive:
|
case pageArchive:
|
||||||
sort.Sort(c.Archives)
|
sort.Sort(c.Archives)
|
||||||
buf := bytes.Buffer{}
|
buf := bytes.Buffer{}
|
||||||
buf.WriteString(c.Blogger.ArchivesSay + "\n")
|
buf.WriteString(c.Blogger.ArchiveSay + "\n")
|
||||||
var (
|
var (
|
||||||
currentYear string
|
currentYear string
|
||||||
gt12Month = len(Ei.Archives) > 12
|
gt12Month = len(Ei.Archives) > 12
|
||||||
@@ -309,11 +309,11 @@ func (c *Cache) regeneratePages() {
|
|||||||
for i, article := range archive.Articles {
|
for i, article := range archive.Articles {
|
||||||
if i == 0 && gt12Month {
|
if i == 0 && gt12Month {
|
||||||
str := fmt.Sprintf(`* *[%s](/post/%s.html) <span class="date">(%s)</span>`,
|
str := fmt.Sprintf(`* *[%s](/post/%s.html) <span class="date">(%s)</span>`,
|
||||||
article.Title, article.Slug, article.CreateTime.Format("Jan 02, 2006"))
|
article.Title, article.Slug, article.CreatedAt.Format("Jan 02, 2006"))
|
||||||
buf.WriteString(str)
|
buf.WriteString(str)
|
||||||
} else {
|
} else {
|
||||||
str := fmt.Sprintf(`* [%s](/post/%s.html) <span class="date">(%s)</span>`,
|
str := fmt.Sprintf(`* [%s](/post/%s.html) <span class="date">(%s)</span>`,
|
||||||
article.Title, article.Slug, article.CreateTime.Format("Jan 02, 2006"))
|
article.Title, article.Slug, article.CreatedAt.Format("Jan 02, 2006"))
|
||||||
buf.WriteString(str)
|
buf.WriteString(str)
|
||||||
}
|
}
|
||||||
buf.WriteByte('\n')
|
buf.WriteByte('\n')
|
||||||
|
|||||||
6
pkg/cache/store/mongodb.go
vendored
6
pkg/cache/store/mongodb.go
vendored
@@ -52,21 +52,21 @@ func (db *mongodb) Init(source string) (Store, error) {
|
|||||||
db.Client = client
|
db.Client = client
|
||||||
// create index
|
// create index
|
||||||
indexModel := mongo.IndexModel{
|
indexModel := mongo.IndexModel{
|
||||||
Keys: bson.D{{"username", 1}},
|
Keys: bson.D{bson.E{Key: "username", Value: 1}},
|
||||||
Options: options.Index().SetUnique(true).SetSparse(true),
|
Options: options.Index().SetUnique(true).SetSparse(true),
|
||||||
}
|
}
|
||||||
db.Database(mongoDBName).Collection(collectionAccount).
|
db.Database(mongoDBName).Collection(collectionAccount).
|
||||||
Indexes().
|
Indexes().
|
||||||
CreateOne(context.Background(), indexModel)
|
CreateOne(context.Background(), indexModel)
|
||||||
indexModel = mongo.IndexModel{
|
indexModel = mongo.IndexModel{
|
||||||
Keys: bson.D{{"slug", 1}},
|
Keys: bson.D{bson.E{Key: "slug", Value: 1}},
|
||||||
Options: options.Index().SetUnique(true).SetSparse(true),
|
Options: options.Index().SetUnique(true).SetSparse(true),
|
||||||
}
|
}
|
||||||
db.Database(mongoDBName).Collection(collectionArticle).
|
db.Database(mongoDBName).Collection(collectionArticle).
|
||||||
Indexes().
|
Indexes().
|
||||||
CreateOne(context.Background(), indexModel)
|
CreateOne(context.Background(), indexModel)
|
||||||
indexModel = mongo.IndexModel{
|
indexModel = mongo.IndexModel{
|
||||||
Keys: bson.D{{"slug", 1}},
|
Keys: bson.D{bson.E{Key: "slug", Value: 1}},
|
||||||
Options: options.Index().SetUnique(true).SetSparse(true),
|
Options: options.Index().SetUnique(true).SetSparse(true),
|
||||||
}
|
}
|
||||||
db.Database(mongoDBName).Collection(collectionSeries).
|
db.Database(mongoDBName).Collection(collectionSeries).
|
||||||
|
|||||||
52
pkg/core/blog/admin/admin.go
Normal file
52
pkg/core/blog/admin/admin.go
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
// Package admin provides ...
|
||||||
|
package admin
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/eiblog/eiblog/pkg/cache"
|
||||||
|
"github.com/eiblog/eiblog/pkg/core/blog"
|
||||||
|
"github.com/eiblog/eiblog/tools"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RegisterRoutes register routes
|
||||||
|
func RegisterRoutes(e *gin.Engine) {
|
||||||
|
e.POST("/admin/login", handleAcctLogin)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterRoutesAuthz register routes
|
||||||
|
func RegisterRoutesAuthz(group gin.IRoutes) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleAcctLogin 登录接口
|
||||||
|
func handleAcctLogin(c *gin.Context) {
|
||||||
|
user := c.PostForm("user")
|
||||||
|
pwd := c.PostForm("password")
|
||||||
|
// code := c.PostForm("code") // 二次验证
|
||||||
|
if user == "" || pwd == "" {
|
||||||
|
logrus.Warnf("参数错误: %s %s", user, pwd)
|
||||||
|
c.Redirect(http.StatusFound, "/admin/login")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if cache.Ei.Account.Username != user ||
|
||||||
|
cache.Ei.Account.Password != tools.EncryptPasswd(user, pwd) {
|
||||||
|
logrus.Warnf("账号或密码错误 %s, %s", user, pwd)
|
||||||
|
c.Redirect(http.StatusFound, "/admin/login")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 登录成功
|
||||||
|
blog.SetLogin(c, user)
|
||||||
|
|
||||||
|
cache.Ei.Account.LoginIP = c.ClientIP()
|
||||||
|
cache.Ei.Account.LoginAt = time.Now()
|
||||||
|
cache.Ei.UpdateAccount(context.Background(), user, map[string]interface{}{
|
||||||
|
"login_ip": cache.Ei.Account.LoginIP,
|
||||||
|
"login_at": cache.Ei.Account.LoginAt,
|
||||||
|
})
|
||||||
|
c.Redirect(http.StatusFound, "/admin/profile")
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// Package eiblog provides ...
|
// Package blog provides ...
|
||||||
package eiblog
|
package blog
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -14,67 +14,43 @@ import (
|
|||||||
|
|
||||||
// @BasePath /api
|
// @BasePath /api
|
||||||
|
|
||||||
// LogStatus log status
|
|
||||||
type LogStatus int
|
|
||||||
|
|
||||||
// user log status
|
|
||||||
var (
|
|
||||||
LogStatusOut LogStatus = 0
|
|
||||||
LogStatusTFA LogStatus = 1
|
|
||||||
LogStatusIn LogStatus = 2
|
|
||||||
)
|
|
||||||
|
|
||||||
// AuthFilter auth filter
|
// AuthFilter auth filter
|
||||||
func AuthFilter(c *gin.Context) {
|
func AuthFilter(c *gin.Context) {
|
||||||
if !IsLogined(c) {
|
if !IsLogined(c) {
|
||||||
c.Abort()
|
c.Abort()
|
||||||
c.Status(http.StatusUnauthorized)
|
c.Status(http.StatusUnauthorized)
|
||||||
|
c.Redirect(http.StatusFound, "/admin/login")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Next()
|
c.Next()
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetLogStatus login user
|
// SetLogin login user
|
||||||
func SetLogStatus(c *gin.Context, uid string, status LogStatus) {
|
func SetLogin(c *gin.Context, username string) {
|
||||||
session := sessions.Default(c)
|
session := sessions.Default(c)
|
||||||
session.Set("uid", uid)
|
session.Set("username", username)
|
||||||
session.Set("status", int(status))
|
|
||||||
session.Save()
|
session.Save()
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetLogout logout user
|
// SetLogout logout user
|
||||||
func SetLogout(c *gin.Context) {
|
func SetLogout(c *gin.Context) {
|
||||||
session := sessions.Default(c)
|
session := sessions.Default(c)
|
||||||
session.Set("status", int(LogStatusOut))
|
session.Delete("username")
|
||||||
session.Save()
|
session.Save()
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsLogined account logined
|
// IsLogined account logined
|
||||||
func IsLogined(c *gin.Context) bool {
|
func IsLogined(c *gin.Context) bool {
|
||||||
status := GetLogStatus(c)
|
return GetUsername(c) != ""
|
||||||
if status < 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
return status == LogStatusIn
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUserID get logined account uuid
|
// GetUsername get logined account
|
||||||
func GetUserID(c *gin.Context) string {
|
func GetUsername(c *gin.Context) string {
|
||||||
session := sessions.Default(c)
|
session := sessions.Default(c)
|
||||||
uid := session.Get("uid")
|
username := session.Get("username")
|
||||||
if uid == nil {
|
if username == nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
return uid.(string)
|
return username.(string)
|
||||||
}
|
|
||||||
|
|
||||||
// GetLogStatus get account log status
|
|
||||||
func GetLogStatus(c *gin.Context) LogStatus {
|
|
||||||
session := sessions.Default(c)
|
|
||||||
status := session.Get("status")
|
|
||||||
if status == nil {
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
return LogStatus(status.(int))
|
|
||||||
}
|
}
|
||||||
|
|||||||
61
pkg/core/blog/page/be.go
Normal file
61
pkg/core/blog/page/be.go
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
// Package page provides ...
|
||||||
|
package page
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
htemplate "html/template"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/eiblog/eiblog/pkg/cache"
|
||||||
|
"github.com/eiblog/eiblog/pkg/config"
|
||||||
|
"github.com/eiblog/eiblog/pkg/core/blog"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
// baseBEParams 基础参数
|
||||||
|
func baseBEParams(c *gin.Context) gin.H {
|
||||||
|
return gin.H{
|
||||||
|
"Author": cache.Ei.Account.Username,
|
||||||
|
"Qiniu": config.Conf.BlogApp.Qiniu.Domain,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleLoginPage 登录页面
|
||||||
|
func handleLoginPage(c *gin.Context) {
|
||||||
|
logout := c.Query("logout")
|
||||||
|
if logout == "true" {
|
||||||
|
blog.SetLogout(c)
|
||||||
|
} else if blog.IsLogined(c) {
|
||||||
|
c.Redirect(http.StatusFound, "/admin/profile")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
params := gin.H{"BTitle": cache.Ei.Blogger.BTitle}
|
||||||
|
renderHTMLAdminLayout(c, "login.html", params)
|
||||||
|
}
|
||||||
|
|
||||||
|
// renderHTMLAdminLayout 渲染admin页面
|
||||||
|
func renderHTMLAdminLayout(c *gin.Context, name string, data gin.H) {
|
||||||
|
c.Header("Content-Type", "text/html; charset=utf-8")
|
||||||
|
// special page
|
||||||
|
if name == "login.html" {
|
||||||
|
err := htmlTmpl.ExecuteTemplate(c.Writer, name, data)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
buf := bytes.Buffer{}
|
||||||
|
err := htmlTmpl.ExecuteTemplate(&buf, name, data)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
data["LayoutContent"] = htemplate.HTML(buf.String())
|
||||||
|
err = htmlTmpl.ExecuteTemplate(c.Writer, "adminLayout.html", data)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if c.Writer.Status() == 0 {
|
||||||
|
c.Status(http.StatusOK)
|
||||||
|
}
|
||||||
|
}
|
||||||
386
pkg/core/blog/page/fe.go
Normal file
386
pkg/core/blog/page/fe.go
Normal file
@@ -0,0 +1,386 @@
|
|||||||
|
// Package page provides ...
|
||||||
|
package page
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
htemplate "html/template"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"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/gin-gonic/gin"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
|
)
|
||||||
|
|
||||||
|
// baseFEParams 基础参数
|
||||||
|
func baseFEParams(c *gin.Context) gin.H {
|
||||||
|
version := 0
|
||||||
|
|
||||||
|
cookie, err := c.Request.Cookie("v")
|
||||||
|
if err != nil || cookie.Value !=
|
||||||
|
fmt.Sprint(config.Conf.BlogApp.StaticVersion) {
|
||||||
|
version = config.Conf.BlogApp.StaticVersion
|
||||||
|
}
|
||||||
|
return gin.H{
|
||||||
|
"BlogName": cache.Ei.Blogger.BlogName,
|
||||||
|
"SubTitle": cache.Ei.Blogger.SubTitle,
|
||||||
|
"BTitle": cache.Ei.Blogger.BTitle,
|
||||||
|
"BeiAn": cache.Ei.Blogger.BeiAn,
|
||||||
|
"Domain": config.Conf.BlogApp.Host,
|
||||||
|
"CopyYear": time.Now().Year(),
|
||||||
|
"Twitter": config.Conf.BlogApp.Twitter,
|
||||||
|
"Qiniu": config.Conf.BlogApp.Qiniu,
|
||||||
|
"Disqus": config.Conf.BlogApp.Disqus,
|
||||||
|
"Version": version,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleNotFound not found page
|
||||||
|
func handleNotFound(c *gin.Context) {
|
||||||
|
params := baseFEParams(c)
|
||||||
|
params["Title"] = "Not Found"
|
||||||
|
params["Description"] = "404 Not Found"
|
||||||
|
params["Path"] = ""
|
||||||
|
c.Status(http.StatusNotFound)
|
||||||
|
renderHTMLHomeLayout(c, "notfound", params)
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleHomePage 首页
|
||||||
|
func handleHomePage(c *gin.Context) {
|
||||||
|
params := baseFEParams(c)
|
||||||
|
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"
|
||||||
|
pn, err := strconv.Atoi(c.Query("pn"))
|
||||||
|
if err != nil || pn < 1 {
|
||||||
|
pn = 1
|
||||||
|
}
|
||||||
|
params["Prev"], params["Next"], params["List"] = cache.Ei.PageArticles(pn,
|
||||||
|
config.Conf.BlogApp.General.PageNum)
|
||||||
|
|
||||||
|
renderHTMLHomeLayout(c, "home", params)
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleArticlePage 文章页
|
||||||
|
func handleArticlePage(c *gin.Context) {
|
||||||
|
slug := c.Param("slug")
|
||||||
|
if !strings.HasSuffix(slug, ".html") || cache.Ei.ArticlesMap[slug[:len(slug)-5]] == nil {
|
||||||
|
handleNotFound(c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
article := cache.Ei.ArticlesMap[slug[:len(slug)-5]]
|
||||||
|
params := baseFEParams(c)
|
||||||
|
params["Title"] = article.Title + " | " + cache.Ei.Blogger.BTitle
|
||||||
|
params["Path"] = c.Request.URL.Path
|
||||||
|
params["CurrentPage"] = "post-" + article.Slug
|
||||||
|
params["Article"] = article
|
||||||
|
|
||||||
|
var name string
|
||||||
|
switch slug {
|
||||||
|
case "blogroll.html":
|
||||||
|
name = "blogroll"
|
||||||
|
params["Description"] = "友情连接," + cache.Ei.Blogger.SubTitle
|
||||||
|
case "about.html":
|
||||||
|
name = "about"
|
||||||
|
params["Description"] = "关于作者," + cache.Ei.Blogger.SubTitle
|
||||||
|
default:
|
||||||
|
params["Description"] = article.Desc + "," + cache.Ei.Blogger.SubTitle
|
||||||
|
name = "article"
|
||||||
|
params["Copyright"] = cache.Ei.Blogger.Copyright
|
||||||
|
if !article.UpdatedAt.IsZero() {
|
||||||
|
params["Days"] = int(time.Now().Sub(article.UpdatedAt).Hours()) / 24
|
||||||
|
} else {
|
||||||
|
params["Days"] = int(time.Now().Sub(article.CreatedAt).Hours()) / 24
|
||||||
|
}
|
||||||
|
if article.SeriesID > 0 {
|
||||||
|
for _, series := range cache.Ei.Series {
|
||||||
|
if series.ID == article.SeriesID {
|
||||||
|
params["Serie"] = series
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
renderHTMLHomeLayout(c, name, params)
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleSeriesPage 专题页
|
||||||
|
func handleSeriesPage(c *gin.Context) {
|
||||||
|
params := baseFEParams(c)
|
||||||
|
params["Title"] = "专题 | " + cache.Ei.Blogger.BTitle
|
||||||
|
params["Description"] = "专题列表," + cache.Ei.Blogger.SubTitle
|
||||||
|
params["Path"] = c.Request.URL.Path
|
||||||
|
params["CurrentPage"] = "series"
|
||||||
|
params["Article"] = cache.Ei.PageSeries
|
||||||
|
renderHTMLHomeLayout(c, "series", params)
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleArchivePage 归档页
|
||||||
|
func handleArchivePage(c *gin.Context) {
|
||||||
|
params := baseFEParams(c)
|
||||||
|
params["Title"] = "归档 | " + cache.Ei.Blogger.BTitle
|
||||||
|
params["Description"] = "博客归档," + cache.Ei.Blogger.SubTitle
|
||||||
|
params["Path"] = c.Request.URL.Path
|
||||||
|
params["CurrentPage"] = "archives"
|
||||||
|
params["Article"] = cache.Ei.PageArchives
|
||||||
|
renderHTMLHomeLayout(c, "archives", params)
|
||||||
|
}
|
||||||
|
|
||||||
|
// handleSearchPage 搜索页
|
||||||
|
func handleSearchPage(c *gin.Context) {
|
||||||
|
params := baseFEParams(c)
|
||||||
|
params["Title"] = "站内搜索 | " + cache.Ei.Blogger.BTitle
|
||||||
|
params["Description"] = "站内搜索," + cache.Ei.Blogger.SubTitle
|
||||||
|
params["Path"] = ""
|
||||||
|
params["CurrentPage"] = "search-post"
|
||||||
|
|
||||||
|
q := strings.TrimSpace(c.Query("q"))
|
||||||
|
if q != "" {
|
||||||
|
start, err := strconv.Atoi(c.Query("start"))
|
||||||
|
if start < 1 || err != nil {
|
||||||
|
start = 1
|
||||||
|
}
|
||||||
|
params["Word"] = q
|
||||||
|
|
||||||
|
vals := c.Request.URL.Query()
|
||||||
|
result, err := internal.ElasticSearch(q, config.Conf.BlogApp.General.PageNum, start-1)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Error("HandleSearchPage.ElasticSearch: ", err)
|
||||||
|
} else {
|
||||||
|
result.Took /= 1000
|
||||||
|
for i, v := range result.Hits.Hits {
|
||||||
|
article := cache.Ei.ArticlesMap[v.Source.Slug]
|
||||||
|
if len(v.Highlight.Content) == 0 && article != nil {
|
||||||
|
result.Hits.Hits[i].Highlight.Content = []string{article.Excerpt}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
params["SearchResult"] = result
|
||||||
|
if num := start - config.Conf.BlogApp.General.PageNum; num > 0 {
|
||||||
|
vals.Set("start", fmt.Sprint(num))
|
||||||
|
params["Prev"] = vals.Encode()
|
||||||
|
}
|
||||||
|
if num := start + config.Conf.BlogApp.General.PageNum; result.Hits.Total >= num {
|
||||||
|
vals.Set("start", fmt.Sprint(num))
|
||||||
|
params["Next"] = vals.Encode()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
params["HotWords"] = config.Conf.BlogApp.HotWords
|
||||||
|
}
|
||||||
|
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"), "|")
|
||||||
|
if len(array) != 4 || array[1] == "" {
|
||||||
|
c.String(http.StatusOK, "出错啦。。。")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
article := cache.Ei.ArticlesMap[array[0]]
|
||||||
|
params := gin.H{
|
||||||
|
"Titile": "发表评论 | " + cache.Ei.Blogger.BTitle,
|
||||||
|
"ATitle": article.Title,
|
||||||
|
"Thread": array[1],
|
||||||
|
"Slug": article.Slug,
|
||||||
|
}
|
||||||
|
renderHTMLHomeLayout(c, "disqus.html", params)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发表评论
|
||||||
|
// [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()
|
||||||
|
|
||||||
|
vals := c.Request.URL.Query()
|
||||||
|
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)
|
||||||
|
|
||||||
|
vals.Set("dl", c.Request.Referer())
|
||||||
|
vals.Set("uip", c.ClientIP())
|
||||||
|
go func() {
|
||||||
|
req, err := http.NewRequest("POST", config.Conf.BlogApp.Google.URL,
|
||||||
|
strings.NewReader(vals.Encode()))
|
||||||
|
if err != nil {
|
||||||
|
logrus.Error("HandleBeaconPage.NewRequest: ", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
req.Header.Set("User-Agent", ua)
|
||||||
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||||
|
res, err := http.DefaultClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Error("HandleBeaconPage.Do: ", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer res.Body.Close()
|
||||||
|
data, err := ioutil.ReadAll(res.Body)
|
||||||
|
if err != nil {
|
||||||
|
logrus.Error("HandleBeaconPage.ReadAll: ", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if res.StatusCode/100 != 2 {
|
||||||
|
logrus.Error(string(data))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
c.Status(http.StatusNoContent)
|
||||||
|
}
|
||||||
|
|
||||||
|
// renderHTMLHomeLayout homelayout html
|
||||||
|
func renderHTMLHomeLayout(c *gin.Context, name string, data gin.H) {
|
||||||
|
c.Header("Content-Type", "text/html; charset=utf-8")
|
||||||
|
// special page
|
||||||
|
if name == "disqus.html" {
|
||||||
|
err := htmlTmpl.ExecuteTemplate(c.Writer, name, data)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
buf := bytes.Buffer{}
|
||||||
|
err := htmlTmpl.ExecuteTemplate(&buf, name, data)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
data["LayoutContent"] = htemplate.HTML(buf.String())
|
||||||
|
err = htmlTmpl.ExecuteTemplate(c.Writer, "homeLayout.html", data)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if c.Writer.Status() == 0 {
|
||||||
|
c.Status(http.StatusOK)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,25 +2,14 @@
|
|||||||
package page
|
package page
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
htemplate "html/template"
|
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"text/template"
|
"text/template"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/eiblog/eiblog/pkg/cache"
|
|
||||||
"github.com/eiblog/eiblog/pkg/config"
|
"github.com/eiblog/eiblog/pkg/config"
|
||||||
"github.com/eiblog/eiblog/pkg/internal"
|
|
||||||
"github.com/eiblog/eiblog/tools"
|
"github.com/eiblog/eiblog/tools"
|
||||||
|
|
||||||
"github.com/eiblog/utils/tmpl"
|
"github.com/eiblog/utils/tmpl"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// htmlTmpl html template cache
|
// htmlTmpl html template cache
|
||||||
@@ -54,365 +43,12 @@ func RegisterRoutes(e *gin.Engine) {
|
|||||||
e.GET("/disqus/form/post-:slug", handleDisqusPage)
|
e.GET("/disqus/form/post-:slug", handleDisqusPage)
|
||||||
e.POST("/disqus/create", handleDisqusCreate)
|
e.POST("/disqus/create", handleDisqusCreate)
|
||||||
e.GET("/beacon.html", handleBeaconPage)
|
e.GET("/beacon.html", handleBeaconPage)
|
||||||
|
|
||||||
|
// login page
|
||||||
|
e.GET("/admin/login", handleLoginPage)
|
||||||
}
|
}
|
||||||
|
|
||||||
// baseParams 基础参数
|
// RegisterRoutesAuthz register admin
|
||||||
func baseParams(c *gin.Context) gin.H {
|
func RegisterRoutesAuthz(group gin.IRoutes) {
|
||||||
version := 0
|
|
||||||
|
|
||||||
cookie, err := c.Request.Cookie("v")
|
|
||||||
if err != nil || cookie.Value !=
|
|
||||||
fmt.Sprint(config.Conf.BlogApp.StaticVersion) {
|
|
||||||
version = config.Conf.BlogApp.StaticVersion
|
|
||||||
}
|
|
||||||
return gin.H{
|
|
||||||
"BlogName": cache.Ei.Blogger.BlogName,
|
|
||||||
"SubTitle": cache.Ei.Blogger.SubTitle,
|
|
||||||
"BTitle": cache.Ei.Blogger.BTitle,
|
|
||||||
"BeiAn": cache.Ei.Blogger.BeiAn,
|
|
||||||
"Domain": config.Conf.BlogApp.Host,
|
|
||||||
"CopyYear": time.Now().Year(),
|
|
||||||
"Twitter": config.Conf.BlogApp.Twitter,
|
|
||||||
"Qiniu": config.Conf.BlogApp.Qiniu,
|
|
||||||
"Disqus": config.Conf.BlogApp.Disqus,
|
|
||||||
"Version": version,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// handleNotFound not found page
|
|
||||||
func handleNotFound(c *gin.Context) {
|
|
||||||
params := baseParams(c)
|
|
||||||
params["Title"] = "Not Found"
|
|
||||||
params["Description"] = "404 Not Found"
|
|
||||||
params["Path"] = ""
|
|
||||||
c.Status(http.StatusNotFound)
|
|
||||||
renderHTMLHomeLayout(c, "notfound", params)
|
|
||||||
}
|
|
||||||
|
|
||||||
// handleHomePage 首页
|
|
||||||
func handleHomePage(c *gin.Context) {
|
|
||||||
params := baseParams(c)
|
|
||||||
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"
|
|
||||||
pn, err := strconv.Atoi(c.Query("pn"))
|
|
||||||
if err != nil || pn < 1 {
|
|
||||||
pn = 1
|
|
||||||
}
|
|
||||||
params["Prev"], params["Next"], params["List"] = cache.Ei.PageArticles(pn,
|
|
||||||
config.Conf.BlogApp.General.PageNum)
|
|
||||||
|
|
||||||
renderHTMLHomeLayout(c, "home", params)
|
|
||||||
}
|
|
||||||
|
|
||||||
// handleArticlePage 文章页
|
|
||||||
func handleArticlePage(c *gin.Context) {
|
|
||||||
slug := c.Param("slug")
|
|
||||||
if !strings.HasSuffix(slug, ".html") || cache.Ei.ArticlesMap[slug[:len(slug)-5]] == nil {
|
|
||||||
handleNotFound(c)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
article := cache.Ei.ArticlesMap[slug[:len(slug)-5]]
|
|
||||||
params := baseParams(c)
|
|
||||||
params["Title"] = article.Title + " | " + cache.Ei.Blogger.BTitle
|
|
||||||
params["Path"] = c.Request.URL.Path
|
|
||||||
params["CurrentPage"] = "post-" + article.Slug
|
|
||||||
params["Article"] = article
|
|
||||||
|
|
||||||
var name string
|
|
||||||
switch slug {
|
|
||||||
case "blogroll.html":
|
|
||||||
name = "blogroll"
|
|
||||||
params["Description"] = "友情连接," + cache.Ei.Blogger.SubTitle
|
|
||||||
case "about.html":
|
|
||||||
name = "about"
|
|
||||||
params["Description"] = "关于作者," + cache.Ei.Blogger.SubTitle
|
|
||||||
default:
|
|
||||||
params["Description"] = article.Desc + "," + cache.Ei.Blogger.SubTitle
|
|
||||||
name = "article"
|
|
||||||
params["Copyright"] = cache.Ei.Blogger.Copyright
|
|
||||||
if !article.UpdateTime.IsZero() {
|
|
||||||
params["Days"] = int(time.Now().Sub(article.UpdateTime).Hours()) / 24
|
|
||||||
} else {
|
|
||||||
params["Days"] = int(time.Now().Sub(article.CreateTime).Hours()) / 24
|
|
||||||
}
|
|
||||||
if article.SerieID > 0 {
|
|
||||||
for _, series := range cache.Ei.Series {
|
|
||||||
if series.ID == article.SerieID {
|
|
||||||
params["Serie"] = series
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
renderHTMLHomeLayout(c, name, params)
|
|
||||||
}
|
|
||||||
|
|
||||||
// handleSeriesPage 专题页
|
|
||||||
func handleSeriesPage(c *gin.Context) {
|
|
||||||
params := baseParams(c)
|
|
||||||
params["Title"] = "专题 | " + cache.Ei.Blogger.BTitle
|
|
||||||
params["Description"] = "专题列表," + cache.Ei.Blogger.SubTitle
|
|
||||||
params["Path"] = c.Request.URL.Path
|
|
||||||
params["CurrentPage"] = "series"
|
|
||||||
params["Article"] = cache.Ei.PageSeries
|
|
||||||
renderHTMLHomeLayout(c, "series", params)
|
|
||||||
}
|
|
||||||
|
|
||||||
// handleArchivePage 归档页
|
|
||||||
func handleArchivePage(c *gin.Context) {
|
|
||||||
params := baseParams(c)
|
|
||||||
params["Title"] = "归档 | " + cache.Ei.Blogger.BTitle
|
|
||||||
params["Description"] = "博客归档," + cache.Ei.Blogger.SubTitle
|
|
||||||
params["Path"] = c.Request.URL.Path
|
|
||||||
params["CurrentPage"] = "archives"
|
|
||||||
params["Article"] = cache.Ei.PageArchives
|
|
||||||
renderHTMLHomeLayout(c, "archives", params)
|
|
||||||
}
|
|
||||||
|
|
||||||
// handleSearchPage 搜索页
|
|
||||||
func handleSearchPage(c *gin.Context) {
|
|
||||||
params := baseParams(c)
|
|
||||||
params["Title"] = "站内搜索 | " + cache.Ei.Blogger.BTitle
|
|
||||||
params["Description"] = "站内搜索," + cache.Ei.Blogger.SubTitle
|
|
||||||
params["Path"] = ""
|
|
||||||
params["CurrentPage"] = "search-post"
|
|
||||||
|
|
||||||
q := strings.TrimSpace(c.Query("q"))
|
|
||||||
if q != "" {
|
|
||||||
start, err := strconv.Atoi(c.Query("start"))
|
|
||||||
if start < 1 || err != nil {
|
|
||||||
start = 1
|
|
||||||
}
|
|
||||||
params["Word"] = q
|
|
||||||
|
|
||||||
vals := c.Request.URL.Query()
|
|
||||||
result, err := internal.ElasticSearch(q, config.Conf.BlogApp.General.PageNum, start-1)
|
|
||||||
if err != nil {
|
|
||||||
logrus.Error("HandleSearchPage.ElasticSearch: ", err)
|
|
||||||
} else {
|
|
||||||
result.Took /= 1000
|
|
||||||
for i, v := range result.Hits.Hits {
|
|
||||||
article := cache.Ei.ArticlesMap[v.Source.Slug]
|
|
||||||
if len(v.Highlight.Content) == 0 && article != nil {
|
|
||||||
result.Hits.Hits[i].Highlight.Content = []string{article.Excerpt}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
params["SearchResult"] = result
|
|
||||||
if num := start - config.Conf.BlogApp.General.PageNum; num > 0 {
|
|
||||||
vals.Set("start", fmt.Sprint(num))
|
|
||||||
params["Prev"] = vals.Encode()
|
|
||||||
}
|
|
||||||
if num := start + config.Conf.BlogApp.General.PageNum; result.Hits.Total >= num {
|
|
||||||
vals.Set("start", fmt.Sprint(num))
|
|
||||||
params["Next"] = vals.Encode()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
params["HotWords"] = config.Conf.BlogApp.HotWords
|
|
||||||
}
|
|
||||||
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"), "|")
|
|
||||||
if len(array) != 4 || array[1] == "" {
|
|
||||||
c.String(http.StatusOK, "出错啦。。。")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
article := cache.Ei.ArticlesMap[array[0]]
|
|
||||||
params := gin.H{
|
|
||||||
"Titile": "发表评论 | " + cache.Ei.Blogger.BTitle,
|
|
||||||
"ATitle": article.Title,
|
|
||||||
"Thread": array[1],
|
|
||||||
"Slug": article.Slug,
|
|
||||||
}
|
|
||||||
err := htmlTmpl.ExecuteTemplate(c.Writer, "disqus.html", params)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
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()
|
|
||||||
|
|
||||||
vals := c.Request.URL.Query()
|
|
||||||
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)
|
|
||||||
|
|
||||||
vals.Set("dl", c.Request.Referer())
|
|
||||||
vals.Set("uip", c.ClientIP())
|
|
||||||
go func() {
|
|
||||||
req, err := http.NewRequest("POST", config.Conf.BlogApp.Google.URL,
|
|
||||||
strings.NewReader(vals.Encode()))
|
|
||||||
if err != nil {
|
|
||||||
logrus.Error("HandleBeaconPage.NewRequest: ", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
req.Header.Set("User-Agent", ua)
|
|
||||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
||||||
res, err := http.DefaultClient.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
logrus.Error("HandleBeaconPage.Do: ", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer res.Body.Close()
|
|
||||||
data, err := ioutil.ReadAll(res.Body)
|
|
||||||
if err != nil {
|
|
||||||
logrus.Error("HandleBeaconPage.ReadAll: ", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if res.StatusCode/100 != 2 {
|
|
||||||
logrus.Error(string(data))
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
c.Status(http.StatusNoContent)
|
|
||||||
}
|
|
||||||
|
|
||||||
// renderHTMLHomeLayout homelayout html
|
|
||||||
func renderHTMLHomeLayout(c *gin.Context, name string, data gin.H) {
|
|
||||||
buf := bytes.Buffer{}
|
|
||||||
err := htmlTmpl.ExecuteTemplate(&buf, name, data)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
data["LayoutContent"] = htemplate.HTML(buf.String())
|
|
||||||
err = htmlTmpl.ExecuteTemplate(c.Writer, "homeLayout.html", data)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
if c.Writer.Status() == 0 {
|
|
||||||
c.Status(http.StatusOK)
|
|
||||||
}
|
|
||||||
c.Header("Content-Type", "text/html; charset=utf-8")
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,17 +3,19 @@ package model
|
|||||||
|
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
|
// use snake_case as column name
|
||||||
|
|
||||||
// Account 博客账户
|
// Account 博客账户
|
||||||
type Account struct {
|
type Account struct {
|
||||||
Username string `gorm:"primaryKey"` // 用户名
|
Username string `gorm:"column:username;primaryKey" bson:"username"` // 用户名
|
||||||
Password string `gorm:"not null"` // 密码
|
Password string `gorm:"column:password;not null" bson:"password"` // 密码
|
||||||
Email string `gorm:"not null"` // 邮件地址
|
Email string `gorm:"column:email;not null" bson:"email"` // 邮件地址
|
||||||
PhoneN string `gorm:"not null"` // 手机号
|
PhoneN string `gorm:"column:phone_n;not null" bson:"phone_n"` // 手机号
|
||||||
Address string `gorm:"not null"` // 地址信息
|
Address string `gorm:"column:address;not null" bson:"address"` // 地址信息
|
||||||
|
|
||||||
LogoutTime time.Time `gorm:"default:null"` // 登出时间
|
LogoutAt time.Time `gorm:"column:logout_at;default:null" bson:"logout_at"` // 登出时间
|
||||||
LoginIP string `gorm:"default:null"` // 最近登录IP
|
LoginIP string `gorm:"column:login_ip;default:null" bson:"login_ip"` // 最近登录IP
|
||||||
LoginUA string `gorm:"default:null"` // 最近登录IP
|
LoginUA string `gorm:"column:login_ua;default:null" bson:"login_ua"` // 最近登录IP
|
||||||
LoginTime time.Time `gorm:"default:now()"` // 最近登录时间
|
LoginAt time.Time `gorm:"column:login_at;default:now()" bson:"login_at"` // 最近登录时间
|
||||||
CreateTime time.Time `gorm:"default:now()"` // 创建时间
|
CreatedAt time.Time `gorm:"column:creatd_at;default:now()" bson:"created_at"` // 创建时间
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,11 @@ package model
|
|||||||
|
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
|
// use snake_case as column name
|
||||||
|
|
||||||
// Archive 归档
|
// Archive 归档
|
||||||
type Archive struct {
|
type Archive struct {
|
||||||
Time time.Time
|
Time time.Time `gorm:"column:time;not null" bson:"time"`
|
||||||
|
|
||||||
Articles SortedArticles `gorm:"-" bson:"-"` // 归档下的文章
|
Articles SortedArticles `gorm:"-" bson:"-"` // 归档下的文章
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,21 +3,23 @@ package model
|
|||||||
|
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
|
// use snake_case as column name
|
||||||
|
|
||||||
// Article 文章
|
// Article 文章
|
||||||
type Article struct {
|
type Article struct {
|
||||||
ID int `gorm:"primaryKey;autoIncrement"` // 自增ID
|
ID int `gorm:"column:id;primaryKey" bson:"id"` // 自增ID
|
||||||
Author string `gorm:"not null"` // 作者名
|
Author string `gorm:"column:author;not null" bson:"author"` // 作者名
|
||||||
Slug string `gorm:"not null;uniqueIndex"` // 文章缩略名
|
Slug string `gorm:"column:slug;not null;uniqueIndex" bson:"slug"` // 文章缩略名
|
||||||
Title string `gorm:"not null"` // 标题
|
Title string `gorm:"column:title;not null" bson:"title"` // 标题
|
||||||
Count int `gorm:"not null"` // 评论数量
|
Count int `gorm:"column:count;not null" bson:"count"` // 评论数量
|
||||||
Content string `gorm:"not null"` // markdown内容
|
Content string `gorm:"column:content;not null" bson:"content"` // markdown内容
|
||||||
SerieID int `gorm:"not null"` // 专题ID
|
SeriesID int `gorm:"column:series_id;not null" bson:"series_id"` // 专题ID
|
||||||
Tags string `gorm:"not null"` // tag,以逗号隔开
|
Tags string `gorm:"column:tags;not null" bson:"tags"` // tag,以逗号隔开
|
||||||
IsDraft bool `gorm:"not null"` // 是否是草稿
|
IsDraft bool `gorm:"column:is_draft;not null" bson:"is_draft"` // 是否是草稿
|
||||||
|
|
||||||
DeleteTime time.Time `gorm:"default:null"` // 删除时间
|
DeletedAt time.Time `gorm:"column:deleted_at;default:null" bson:"deleted_at"` // 删除时间
|
||||||
UpdateTime time.Time `gorm:"default:now()"` // 更新时间
|
UpdatedAt time.Time `gorm:"column:updated_at;default:now()" bson:"updated_at"` // 更新时间
|
||||||
CreateTime time.Time `gorm:"default:now()"` // 创建时间
|
CreatedAt time.Time `gorm:"column:created_at;default:now()" bson:"created_at"` // 创建时间
|
||||||
|
|
||||||
Header string `gorm:"-" bson:"-"` // header
|
Header string `gorm:"-" bson:"-"` // header
|
||||||
Excerpt string `gorm:"-" bson:"-"` // 预览信息
|
Excerpt string `gorm:"-" bson:"-"` // 预览信息
|
||||||
@@ -34,7 +36,7 @@ type SortedArticles []*Article
|
|||||||
func (s SortedArticles) Len() int { return len(s) }
|
func (s SortedArticles) Len() int { return len(s) }
|
||||||
|
|
||||||
// Less 对比
|
// Less 对比
|
||||||
func (s SortedArticles) Less(i, j int) bool { return s[i].CreateTime.After(s[j].CreateTime) }
|
func (s SortedArticles) Less(i, j int) bool { return s[i].CreatedAt.After(s[j].CreatedAt) }
|
||||||
|
|
||||||
// Swap 交换
|
// Swap 交换
|
||||||
func (s SortedArticles) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
func (s SortedArticles) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||||
|
|||||||
@@ -3,12 +3,12 @@ package model
|
|||||||
|
|
||||||
// Blogger 博客信息
|
// Blogger 博客信息
|
||||||
type Blogger struct {
|
type Blogger struct {
|
||||||
BlogName string `gorm:"not null"` // 博客名
|
BlogName string `gorm:"column:blog_name;not null" bson:"blog_name"` // 博客名
|
||||||
SubTitle string `gorm:"not null"` // 子标题
|
SubTitle string `gorm:"column:sub_title;not null" bson:"sub_title"` // 子标题
|
||||||
BeiAn string `gorm:"not null"` // 备案号
|
BeiAn string `gorm:"column:bei_an;not null" bson:"bei_an"` // 备案号
|
||||||
BTitle string `gorm:"not null"` // 底部title
|
BTitle string `gorm:"column:b_title;not null" bson:"b_title"` // 底部title
|
||||||
Copyright string `gorm:"not null"` // 版权声明
|
Copyright string `gorm:"column:copyright;not null" bson:"copyright"` // 版权声明
|
||||||
|
|
||||||
SeriesSay string `gorm:"not null"` // 专题说明
|
SeriesSay string `gorm:"column:series_say;not null" bson:"series_say"` // 专题说明
|
||||||
ArchivesSay string `gorm:"not null"` // 归档说明
|
ArchiveSay string `gorm:"column:archive_say;not null" bson:"archive_say"` // 归档说明
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,11 +5,11 @@ import "time"
|
|||||||
|
|
||||||
// Series 专题
|
// Series 专题
|
||||||
type Series struct {
|
type Series struct {
|
||||||
ID int `gorm:"primaryKey;autoIncrement"` // 自增ID
|
ID int `gorm:"column:id;primaryKey" bson:"id"` // 自增ID
|
||||||
Slug string `gorm:"not null;uniqueIndex"` // 缩略名
|
Slug string `gorm:"column:slug;not null;uniqueIndex" bson:"slug"` // 缩略名
|
||||||
Name string `gorm:"not null"` // 专题名
|
Name string `gorm:"column:name;not null" bson:"name"` // 专题名
|
||||||
Desc string `gorm:"not null"` // 专题描述
|
Desc string `gorm:"column:desc;not null" bson:"desc"` // 专题描述
|
||||||
CreateTime time.Time `gorm:"default:now()"` // 创建时间
|
CreatedAt time.Time `gorm:"column:created_at;default:now()" bson:"created_at"` // 创建时间
|
||||||
|
|
||||||
Articles SortedArticles `gorm:"-" bson:"-"` // 专题下的文章
|
Articles SortedArticles `gorm:"-" bson:"-"` // 专题下的文章
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user