mirror of
https://github.com/eiblog/eiblog.git
synced 2026-02-08 23:52:26 +08:00
Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
52da8abceb | ||
|
|
f016b28cb6 | ||
|
|
01b7643ca5 | ||
|
|
375d43761b | ||
|
|
f3e9727947 | ||
|
|
911aa963c7 | ||
|
|
fb66b6871e | ||
|
|
5ae76f243e | ||
|
|
051b034e51 | ||
|
|
27439ecc71 |
15
CHANGELOG.md
15
CHANGELOG.md
@@ -1,5 +1,20 @@
|
|||||||
# Eiblog Changelog
|
# Eiblog Changelog
|
||||||
|
|
||||||
|
## v1.4.4 (2018-05-07)
|
||||||
|
* 修复基础评论分钟数计算错误
|
||||||
|
* let's encrypt v2证书内嵌ct,故移除有关ct内容
|
||||||
|
|
||||||
|
## v1.4.3 (2018-02-09)
|
||||||
|
* 修复博客初始化后,about 页面不能够评论 #6
|
||||||
|
* 修复编辑专题,按钮显示“添加专题”错误
|
||||||
|
* 优化“添加文章”从同步改为异步推送:feed,es,disqus。速度显著提升
|
||||||
|
* (**重要*)头像图片从 avatar.jpg 改为 avatar.png(透明)
|
||||||
|
* docker-compose.yml mongodb 去掉端口映射,防止用户将端口暴露至外网
|
||||||
|
* session key 每次重启随机生成等一些细节的修复
|
||||||
|
|
||||||
|
## v1.4.2 (2018-01-25)
|
||||||
|
* fix archive page bug
|
||||||
|
|
||||||
## v1.4.1 (2018-01-14)
|
## v1.4.1 (2018-01-14)
|
||||||
* 修复创建新文章,disqus 不收录bug
|
* 修复创建新文章,disqus 不收录bug
|
||||||
* 修复创建新文章,归档页面不刷新bug
|
* 修复创建新文章,归档页面不刷新bug
|
||||||
|
|||||||
28
Makefile
28
Makefile
@@ -26,7 +26,7 @@ dist:
|
|||||||
gencert:makedir
|
gencert:makedir
|
||||||
@if [ ! -n "$(sans)" ]; then \
|
@if [ ! -n "$(sans)" ]; then \
|
||||||
printf "Need one argument [sans=params]\n"; \
|
printf "Need one argument [sans=params]\n"; \
|
||||||
printf "example: sans=\"-d domain -d domain\"\n"; \
|
printf "example: sans=\"-d domain -d *.domain\"\n"; \
|
||||||
exit 1; \
|
exit 1; \
|
||||||
fi; \
|
fi; \
|
||||||
if [ ! -n "$(cn)" ]; then \
|
if [ ! -n "$(cn)" ]; then \
|
||||||
@@ -39,22 +39,18 @@ gencert:makedir
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
@echo "generate rsa cert..."
|
@echo "generate rsa cert..."
|
||||||
@$(acme.sh) --force --issue --dns dns_ali $(sans) --log \
|
@$(acme.sh) --force --issue --dns dns_ali $(sans) \
|
||||||
--renew-hook "ct-submit ctlog-gen2.api.venafi.com < $(config)/ssl/domain.rsa.pem > $(config)/scts/rsa/venafi.sct \
|
--renew-hook "$(acme.sh) --install-cert -d $(cn) \
|
||||||
&& ct-submit ctlog.wosign.com < $(config)/ssl/domain.rsa.pem > $(config)/scts/rsa/wosign.sct"
|
--key-file $(config)/ssl/domain.rsa.key \
|
||||||
@$(acme.sh) --install-cert -d $(cn) \
|
--fullchain-file $(config)/ssl/domain.rsa.pem \
|
||||||
--key-file $(config)/ssl/domain.rsa.key \
|
--reloadcmd \"service nginx force-reload\""
|
||||||
--fullchain-file $(config)/ssl/domain.rsa.pem \
|
|
||||||
--reloadcmd "service nginx force-reload"
|
|
||||||
|
|
||||||
@echo "generate ecc cert..."
|
@echo "generate ecc cert..."
|
||||||
@$(acme.sh) --force --issue --dns dns_ali $(sans) -k ec-256 --log \
|
@$(acme.sh) --force --issue --dns dns_ali $(sans) -k ec-256 \
|
||||||
--renew-hook "ct-submit ctlog-gen2.api.venafi.com < $(config)/ssl/domain.ecc.pem > $(config)/scts/ecc/venafi.sct \
|
--renew-hook "$(acme.sh) --install-cert -d $(cn) --ecc \
|
||||||
&& ct-submit ctlog.wosign.com < $(config)/ssl/domain.ecc.pem > $(config)/scts/ecc/wosign.sct"
|
--key-file $(config)/ssl/domain.ecc.key \
|
||||||
@$(acme.sh) --install-cert -d $(cn) --ecc \
|
--fullchain-file $(config)/ssl/domain.ecc.pem \
|
||||||
--key-file $(config)/ssl/domain.ecc.key \
|
--reloadcmd \"service nginx force-reload\""
|
||||||
--fullchain-file $(config)/ssl/domain.ecc.pem \
|
|
||||||
--reloadcmd "service nginx force-reload"
|
|
||||||
|
|
||||||
dhparams:
|
dhparams:
|
||||||
@openssl dhparam -out $(config)/ssl/dhparams.pem 2048
|
@openssl dhparam -out $(config)/ssl/dhparams.pem 2048
|
||||||
@@ -63,7 +59,7 @@ ssticket:
|
|||||||
@openssl rand 48 > $(config)/ssl/session_ticket.key
|
@openssl rand 48 > $(config)/ssl/session_ticket.key
|
||||||
|
|
||||||
makedir:
|
makedir:
|
||||||
@mkdir -p $(config)/ssl $(config)/scts/rsa $(config)/scts/ecc
|
@mkdir -p $(config)/ssl
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
|
|
||||||
|
|||||||
34
api.go
34
api.go
@@ -231,12 +231,15 @@ func apiPostAdd(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
cid = int(artc.ID)
|
cid = int(artc.ID)
|
||||||
if !artc.IsDraft {
|
if !artc.IsDraft {
|
||||||
// elastic
|
// 异步执行,快
|
||||||
ElasticIndex(artc)
|
go func() {
|
||||||
// rss
|
// elastic
|
||||||
DoPings(slug)
|
ElasticIndex(artc)
|
||||||
// disqus
|
// rss
|
||||||
ThreadCreate(artc)
|
DoPings(slug)
|
||||||
|
// disqus
|
||||||
|
ThreadCreate(artc)
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -260,14 +263,17 @@ func apiPostAdd(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
if !artc.IsDraft {
|
if !artc.IsDraft {
|
||||||
ReplaceArticle(a, artc)
|
ReplaceArticle(a, artc)
|
||||||
// elastic
|
// 异步执行,快
|
||||||
ElasticIndex(artc)
|
go func() {
|
||||||
// rss
|
// elastic
|
||||||
DoPings(slug)
|
ElasticIndex(artc)
|
||||||
// disqus
|
// rss
|
||||||
if a == nil {
|
DoPings(slug)
|
||||||
ThreadCreate(artc)
|
// disqus
|
||||||
}
|
if a == nil {
|
||||||
|
ThreadCreate(artc)
|
||||||
|
}
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,9 +9,11 @@ server {
|
|||||||
# ip 黑名单
|
# ip 黑名单
|
||||||
include /data/eiblog/conf/nginx/ip.blacklist;
|
include /data/eiblog/conf/nginx/ip.blacklist;
|
||||||
|
|
||||||
# 现在一般证书是内置的。letsencrypt 暂未
|
# letsencrypt v2已内置
|
||||||
# https://imququ.com/post/certificate-transparency.html#toc-2
|
# https://imququ.com/post/certificate-transparency.html#toc-2
|
||||||
ssl_ct on;
|
#ssl_ct on;
|
||||||
|
#ssl_ct_static_scts /data/eiblog/conf/scts/rsa/;
|
||||||
|
#ssl_ct_static_scts /data/eiblog/conf/scts/ecc/;
|
||||||
|
|
||||||
# 中间证书 + 根证书
|
# 中间证书 + 根证书
|
||||||
# https://imququ.com/post/why-can-not-turn-on-ocsp-stapling.html
|
# https://imququ.com/post/why-can-not-turn-on-ocsp-stapling.html
|
||||||
@@ -20,10 +22,8 @@ server {
|
|||||||
# 站点证书 + 中间证书,私钥
|
# 站点证书 + 中间证书,私钥
|
||||||
ssl_certificate /data/eiblog/conf/ssl/domain.rsa.pem;
|
ssl_certificate /data/eiblog/conf/ssl/domain.rsa.pem;
|
||||||
ssl_certificate_key /data/eiblog/conf/ssl/domain.rsa.key;
|
ssl_certificate_key /data/eiblog/conf/ssl/domain.rsa.key;
|
||||||
ssl_ct_static_scts /data/eiblog/conf/scts/rsa/;
|
|
||||||
# ssl_certificate /data/eiblog/conf/ssl/domain.ecc.pem;
|
# ssl_certificate /data/eiblog/conf/ssl/domain.ecc.pem;
|
||||||
# ssl_certificate_key /data/eiblog/conf/ssl/domain.ecc.key;
|
# ssl_certificate_key /data/eiblog/conf/ssl/domain.ecc.key;
|
||||||
# ssl_ct_static_scts /data/eiblog/conf/scts/ecc/;
|
|
||||||
|
|
||||||
# openssl dhparam -out dhparams.pem 2048
|
# openssl dhparam -out dhparams.pem 2048
|
||||||
# https://weakdh.org/sysadmin.html
|
# https://weakdh.org/sysadmin.html
|
||||||
@@ -105,7 +105,7 @@ server {
|
|||||||
|
|
||||||
proxy_set_header Connection "";
|
proxy_set_header Connection "";
|
||||||
proxy_set_header Host deepzz.com;
|
proxy_set_header Host deepzz.com;
|
||||||
proxy_set_header X-Real_IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
|
||||||
proxy_pass http://127.0.0.1:9000;
|
proxy_pass http://127.0.0.1:9000;
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
50
db.go
50
db.go
@@ -75,9 +75,9 @@ func init() {
|
|||||||
logd.Fatal(err)
|
logd.Fatal(err)
|
||||||
}
|
}
|
||||||
// 读取帐号信息
|
// 读取帐号信息
|
||||||
Ei = loadAccount()
|
loadAccount()
|
||||||
// 获取文章数据
|
// 获取文章数据
|
||||||
Ei.Articles = loadArticles()
|
loadArticles()
|
||||||
// 生成markdown文档
|
// 生成markdown文档
|
||||||
go generateMarkdown()
|
go generateMarkdown()
|
||||||
// 启动定时器
|
// 启动定时器
|
||||||
@@ -87,12 +87,13 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 读取或初始化帐号信息
|
// 读取或初始化帐号信息
|
||||||
func loadAccount() (a *Account) {
|
func loadAccount() {
|
||||||
a = &Account{}
|
Ei = &Account{}
|
||||||
err := mgo.FindOne(DB, COLLECTION_ACCOUNT, mgo.M{"username": setting.Conf.Account.Username}, a)
|
err := mgo.FindOne(DB, COLLECTION_ACCOUNT, mgo.M{"username": setting.Conf.Account.Username}, Ei)
|
||||||
// 初始化用户数据
|
// 初始化用户数据
|
||||||
if err == mgo.ErrNotFound {
|
if err == mgo.ErrNotFound {
|
||||||
a = &Account{
|
logd.Printf("Initializing account: %s\n", setting.Conf.Account.Username)
|
||||||
|
Ei = &Account{
|
||||||
Username: setting.Conf.Account.Username,
|
Username: setting.Conf.Account.Username,
|
||||||
Password: EncryptPasswd(setting.Conf.Account.Username, setting.Conf.Account.Password),
|
Password: EncryptPasswd(setting.Conf.Account.Username, setting.Conf.Account.Password),
|
||||||
Email: setting.Conf.Account.Email,
|
Email: setting.Conf.Account.Email,
|
||||||
@@ -100,29 +101,28 @@ func loadAccount() (a *Account) {
|
|||||||
Address: setting.Conf.Account.Address,
|
Address: setting.Conf.Account.Address,
|
||||||
CreateTime: time.Now(),
|
CreateTime: time.Now(),
|
||||||
}
|
}
|
||||||
a.BlogName = setting.Conf.Blogger.BlogName
|
Ei.BlogName = setting.Conf.Blogger.BlogName
|
||||||
a.SubTitle = setting.Conf.Blogger.SubTitle
|
Ei.SubTitle = setting.Conf.Blogger.SubTitle
|
||||||
a.BeiAn = setting.Conf.Blogger.BeiAn
|
Ei.BeiAn = setting.Conf.Blogger.BeiAn
|
||||||
a.BTitle = setting.Conf.Blogger.BTitle
|
Ei.BTitle = setting.Conf.Blogger.BTitle
|
||||||
a.Copyright = setting.Conf.Blogger.Copyright
|
Ei.Copyright = setting.Conf.Blogger.Copyright
|
||||||
err = mgo.Insert(DB, COLLECTION_ACCOUNT, a)
|
err = mgo.Insert(DB, COLLECTION_ACCOUNT, Ei)
|
||||||
generateTopic()
|
generateTopic()
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
logd.Fatal(err)
|
logd.Fatal(err)
|
||||||
}
|
}
|
||||||
a.CH = make(chan string, 2)
|
Ei.CH = make(chan string, 2)
|
||||||
a.MapArticles = make(map[string]*Article)
|
Ei.MapArticles = make(map[string]*Article)
|
||||||
a.Tags = make(map[string]SortArticles)
|
Ei.Tags = make(map[string]SortArticles)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadArticles() (artcs SortArticles) {
|
func loadArticles() {
|
||||||
err := mgo.FindAll(DB, COLLECTION_ARTICLE, mgo.M{"isdraft": false, "deletetime": mgo.M{"$eq": time.Time{}}}, &artcs)
|
err := mgo.FindAll(DB, COLLECTION_ARTICLE, mgo.M{"isdraft": false, "deletetime": mgo.M{"$eq": time.Time{}}}, &Ei.Articles)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logd.Fatal(err)
|
logd.Fatal(err)
|
||||||
}
|
}
|
||||||
sort.Sort(artcs)
|
sort.Sort(Ei.Articles)
|
||||||
for i, v := range artcs {
|
for i, v := range Ei.Articles {
|
||||||
// 渲染文章
|
// 渲染文章
|
||||||
GenerateExcerptAndRender(v)
|
GenerateExcerptAndRender(v)
|
||||||
Ei.MapArticles[v.Slug] = v
|
Ei.MapArticles[v.Slug] = v
|
||||||
@@ -131,16 +131,15 @@ func loadArticles() (artcs SortArticles) {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
v.Prev = artcs[i-1]
|
v.Prev = Ei.Articles[i-1]
|
||||||
}
|
}
|
||||||
if artcs[i+1].ID >= setting.Conf.General.StartID {
|
if Ei.Articles[i+1].ID >= setting.Conf.General.StartID {
|
||||||
v.Next = artcs[i+1]
|
v.Next = Ei.Articles[i+1]
|
||||||
}
|
}
|
||||||
upArticle(v, false)
|
upArticle(v, false)
|
||||||
}
|
}
|
||||||
Ei.CH <- SERIES_MD
|
Ei.CH <- SERIES_MD
|
||||||
Ei.CH <- ARCHIVE_MD
|
Ei.CH <- ARCHIVE_MD
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// generate series,archive markdown
|
// generate series,archive markdown
|
||||||
@@ -209,6 +208,9 @@ func generateTopic() {
|
|||||||
CreateTime: time.Time{},
|
CreateTime: time.Time{},
|
||||||
UpdateTime: time.Time{},
|
UpdateTime: time.Time{},
|
||||||
}
|
}
|
||||||
|
// 推送到 disqus
|
||||||
|
go func() { ThreadCreate(about) }()
|
||||||
|
|
||||||
blogroll := &Article{
|
blogroll := &Article{
|
||||||
ID: mgo.NextVal(DB, COUNTER_ARTICLE),
|
ID: mgo.NextVal(DB, COUNTER_ARTICLE),
|
||||||
Author: setting.Conf.Account.Username,
|
Author: setting.Conf.Account.Username,
|
||||||
|
|||||||
@@ -6,8 +6,6 @@ services:
|
|||||||
volumes:
|
volumes:
|
||||||
- /data/eiblog/mgodb:/data/db
|
- /data/eiblog/mgodb:/data/db
|
||||||
restart: always
|
restart: always
|
||||||
ports:
|
|
||||||
- 27017:27017
|
|
||||||
elasticsearch:
|
elasticsearch:
|
||||||
image: elasticsearch:2.4.1
|
image: elasticsearch:2.4.1
|
||||||
container_name: eisearch
|
container_name: eisearch
|
||||||
|
|||||||
1
docs/_config.yml
Normal file
1
docs/_config.yml
Normal file
@@ -0,0 +1 @@
|
|||||||
|
theme: jekyll-theme-cayman
|
||||||
@@ -90,7 +90,7 @@ $ docker run -d --name eisearch \
|
|||||||
| ------------------ | ---------------------------------------- | ---------------------------------------- |
|
| ------------------ | ---------------------------------------- | ---------------------------------------- |
|
||||||
| favicon.ico | st.example.com/static/img/favicon.ico | cdn 中的文件名为 `static/img/favicon.ico`。你也可以复制 favicon.ico 到 static 文件夹下,通过 example.com/favicon.ico 也是能够访问到。docker 用户可能需要重新打包镜像。 |
|
| favicon.ico | st.example.com/static/img/favicon.ico | cdn 中的文件名为 `static/img/favicon.ico`。你也可以复制 favicon.ico 到 static 文件夹下,通过 example.com/favicon.ico 也是能够访问到。docker 用户可能需要重新打包镜像。 |
|
||||||
| bg04.jpg | st.example.com/static/img/bg04.jpg | 首页左侧的大背景图,需要更名请到 views/st_blog.css 修改。 |
|
| bg04.jpg | st.example.com/static/img/bg04.jpg | 首页左侧的大背景图,需要更名请到 views/st_blog.css 修改。 |
|
||||||
| avatar.jpg | st.example.com/static/img/avatar.jpg | 头像 |
|
| avatar.png | st.example.com/static/img/avatar.png | 头像 |
|
||||||
| blank.gif | st.example.com/static/img/blank.gif | 空白图片,[下载](https://st.deepzz.com/static/img/blank.gif) |
|
| blank.gif | st.example.com/static/img/blank.gif | 空白图片,[下载](https://st.deepzz.com/static/img/blank.gif) |
|
||||||
| default_avatar.png | st.example.com/static/img/default_avatar.png | disqus 默认图片,[下载](https://st.deepzz.com/static/img/default_avatar.png) |
|
| default_avatar.png | st.example.com/static/img/default_avatar.png | disqus 默认图片,[下载](https://st.deepzz.com/static/img/default_avatar.png) |
|
||||||
| disqus.js | st.example.com/static/js/disqus_xxx.js | disqus 文件,你可以通过 https://short_name.disqus.com/embed.js 下载你的专属文件,并上传到七牛。更新配置文件 app.yml。 |
|
| disqus.js | st.example.com/static/js/disqus_xxx.js | disqus 文件,你可以通过 https://short_name.disqus.com/embed.js 下载你的专属文件,并上传到七牛。更新配置文件 app.yml。 |
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -23,10 +24,20 @@ const (
|
|||||||
ES_DATE = `{"range":{"date":{"gte":"%s","lte": "%s","format": "yyyy-MM-dd||yyyy-MM||yyyy"}}}` // 2016-10||/M
|
ES_DATE = `{"range":{"date":{"gte":"%s","lte": "%s","format": "yyyy-MM-dd||yyyy-MM||yyyy"}}}` // 2016-10||/M
|
||||||
)
|
)
|
||||||
|
|
||||||
var es *ElasticService
|
var (
|
||||||
|
ErrUninitializedES = errors.New("uninitialized elasticsearch")
|
||||||
|
|
||||||
|
es *ElasticService
|
||||||
|
)
|
||||||
|
|
||||||
// 初始化 Elasticsearch 服务器
|
// 初始化 Elasticsearch 服务器
|
||||||
func init() {
|
func init() {
|
||||||
|
_, err := net.LookupIP("elasticsearch")
|
||||||
|
if err != nil {
|
||||||
|
logd.Info(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
es = &ElasticService{url: "http://elasticsearch:9200", c: new(http.Client)}
|
es = &ElasticService{url: "http://elasticsearch:9200", c: new(http.Client)}
|
||||||
initIndex()
|
initIndex()
|
||||||
}
|
}
|
||||||
@@ -41,7 +52,11 @@ func initIndex() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 查询
|
// 查询
|
||||||
func Elasticsearch(qStr string, size, from int) *ESSearchResult {
|
func Elasticsearch(qStr string, size, from int) (*ESSearchResult, error) {
|
||||||
|
if es == nil {
|
||||||
|
return nil, ErrUninitializedES
|
||||||
|
}
|
||||||
|
|
||||||
// 分析查询字符串
|
// 分析查询字符串
|
||||||
reg := regexp.MustCompile(`(tag|slug|date):`)
|
reg := regexp.MustCompile(`(tag|slug|date):`)
|
||||||
indexs := reg.FindAllStringIndex(qStr, -1)
|
indexs := reg.FindAllStringIndex(qStr, -1)
|
||||||
@@ -92,14 +107,17 @@ func Elasticsearch(qStr string, size, from int) *ESSearchResult {
|
|||||||
}
|
}
|
||||||
docs, err := IndexQueryDSL(INDEX, TYPE, size, from, []byte(dsl))
|
docs, err := IndexQueryDSL(INDEX, TYPE, size, from, []byte(dsl))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logd.Error(err)
|
return nil, err
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
return docs
|
return docs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加或更新索引
|
// 添加或更新索引
|
||||||
func ElasticIndex(artc *Article) error {
|
func ElasticIndex(artc *Article) error {
|
||||||
|
if es == nil {
|
||||||
|
return ErrUninitializedES
|
||||||
|
}
|
||||||
|
|
||||||
img := PickFirstImage(artc.Content)
|
img := PickFirstImage(artc.Content)
|
||||||
mapping := map[string]interface{}{
|
mapping := map[string]interface{}{
|
||||||
"title": artc.Title,
|
"title": artc.Title,
|
||||||
@@ -115,6 +133,10 @@ func ElasticIndex(artc *Article) error {
|
|||||||
|
|
||||||
// 删除索引
|
// 删除索引
|
||||||
func ElasticDelIndex(ids []int32) error {
|
func ElasticDelIndex(ids []int32) error {
|
||||||
|
if es == nil {
|
||||||
|
return ErrUninitializedES
|
||||||
|
}
|
||||||
|
|
||||||
var target []string
|
var target []string
|
||||||
for _, id := range ids {
|
for _, id := range ids {
|
||||||
target = append(target, fmt.Sprint(id))
|
target = append(target, fmt.Sprint(id))
|
||||||
|
|||||||
8
front.go
8
front.go
@@ -199,10 +199,12 @@ func HandleSearchPage(c *gin.Context) {
|
|||||||
start = 1
|
start = 1
|
||||||
}
|
}
|
||||||
h["Word"] = q
|
h["Word"] = q
|
||||||
var result *ESSearchResult
|
|
||||||
vals := c.Request.URL.Query()
|
vals := c.Request.URL.Query()
|
||||||
result = Elasticsearch(q, setting.Conf.General.PageNum, start-1)
|
result, err := Elasticsearch(q, setting.Conf.General.PageNum, start-1)
|
||||||
if result != nil {
|
if err != nil {
|
||||||
|
logd.Error(err)
|
||||||
|
} else {
|
||||||
result.Took /= 1000
|
result.Took /= 1000
|
||||||
for i, v := range result.Hits.Hits {
|
for i, v := range result.Hits.Hits {
|
||||||
if artc := Ei.MapArticles[result.Hits.Hits[i].Source.Slug]; len(v.Highlight.Content) == 0 && artc != nil {
|
if artc := Ei.MapArticles[result.Hits.Hits[i].Source.Slug]; len(v.Highlight.Content) == 0 && artc != nil {
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ func ConvertStr(str string) string {
|
|||||||
} else if h := d*24 + h2 - h1; h > 1 || (h == 1 && mi2-mi1 >= 0) {
|
} else if h := d*24 + h2 - h1; h > 1 || (h == 1 && mi2-mi1 >= 0) {
|
||||||
return fmt.Sprintf(HOURS_AGO, h)
|
return fmt.Sprintf(HOURS_AGO, h)
|
||||||
} else if mi := h*60 + mi2 - mi1; mi > 1 || (mi == 1 && s2-s1 >= 0) {
|
} else if mi := h*60 + mi2 - mi1; mi > 1 || (mi == 1 && s2-s1 >= 0) {
|
||||||
return fmt.Sprintf(MINUTES_AGO, m)
|
return fmt.Sprintf(MINUTES_AGO, mi)
|
||||||
}
|
}
|
||||||
return JUST_NOW
|
return JUST_NOW
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,15 +44,21 @@ func TestPickFirstImage(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestCovertStr(t *testing.T) {
|
func TestCovertStr(t *testing.T) {
|
||||||
|
now := time.Now().UTC()
|
||||||
testStr := []string{
|
testStr := []string{
|
||||||
time.Now().Format("2006-01-02T15:04:05"),
|
now.Format("2006-01-02T15:04:05"),
|
||||||
|
now.Add(-time.Second * 20).Format("2006-01-02T15:04:05"),
|
||||||
|
now.Add(-time.Minute).Format("2006-01-02T15:04:05"),
|
||||||
|
now.Add(-time.Minute * 2).Format("2006-01-02T15:04:05"),
|
||||||
|
now.Add(-time.Minute * 20).Format("2006-01-02T15:04:05"),
|
||||||
|
now.Add(-time.Hour).Format("2006-01-02T15:04:05"),
|
||||||
|
now.Add(-time.Hour * 2).Format("2006-01-02T15:04:05"),
|
||||||
|
now.Add(-time.Hour * 24).Format("2006-01-02T15:04:05"),
|
||||||
}
|
}
|
||||||
|
|
||||||
expectStr := []string{
|
time.Sleep(time.Second)
|
||||||
JUST_NOW,
|
t.Log(now.Format("2006-01-02T15:04:05"))
|
||||||
}
|
for _, v := range testStr {
|
||||||
|
t.Log(v, ConvertStr(v))
|
||||||
for i, v := range testStr {
|
|
||||||
assert.Equal(t, expectStr[i], ConvertStr(v))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
10
router.go
10
router.go
@@ -2,6 +2,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/rand"
|
||||||
"fmt"
|
"fmt"
|
||||||
"text/template"
|
"text/template"
|
||||||
"time"
|
"time"
|
||||||
@@ -27,7 +28,12 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
router = gin.Default()
|
router = gin.Default()
|
||||||
store := sessions.NewCookieStore([]byte("eiblog321"))
|
b := make([]byte, 16)
|
||||||
|
_, err := rand.Read(b)
|
||||||
|
if err != nil {
|
||||||
|
logd.Fatal(err)
|
||||||
|
}
|
||||||
|
store := sessions.NewCookieStore(b)
|
||||||
store.Options(sessions.Options{
|
store.Options(sessions.Options{
|
||||||
MaxAge: 86400 * 7,
|
MaxAge: 86400 * 7,
|
||||||
Path: "/",
|
Path: "/",
|
||||||
@@ -43,7 +49,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
_, err := Tmpl.ParseFiles(files...)
|
_, err = Tmpl.ParseFiles(files...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logd.Fatal(err)
|
logd.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,7 +60,7 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
<div class="operate">
|
<div class="operate">
|
||||||
<a target="_self" title="{{.LastLogin}}" href="/admin/profile" class="author">{{.Author}}</a><a class="exit" href="/admin/login?logout=true">登出</a><a target="_back" href="/">网站</a>
|
<a target="_self" title="{{.LastLogin}}" href="/admin/profile" class="author">{{.Author}}</a><a class="exit" href="/admin/login?logout=true">登出</a><a target="_blank" href="/">网站</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="main">
|
<div class="main">
|
||||||
|
|||||||
@@ -64,7 +64,7 @@
|
|||||||
<td><a href="/post/{{.Slug}}.html#comments" class="balloon-button size-1">{{.Count}}</a></td>
|
<td><a href="/post/{{.Slug}}.html#comments" class="balloon-button size-1">{{.Count}}</a></td>
|
||||||
<td>
|
<td>
|
||||||
<a href="/admin/write-post?cid={{.ID}}">{{.Title}}</a>
|
<a href="/admin/write-post?cid={{.ID}}">{{.Title}}</a>
|
||||||
<a target="_black" href="/post/{{.Slug}}.html" title="浏览 {{.Title}}"><i class="i-exlink"></i></a>
|
<a target="_blank" href="/post/{{.Slug}}.html" title="浏览 {{.Title}}"><i class="i-exlink"></i></a>
|
||||||
</td>
|
</td>
|
||||||
<td>{{.Author}}</td>
|
<td>{{.Author}}</td>
|
||||||
<td>{{if gt .SerieID 0}}专题ID:{{.SerieID}}{{else}}--{{end}}</td>
|
<td>{{if gt .SerieID 0}}专题ID:{{.SerieID}}{{else}}--{{end}}</td>
|
||||||
|
|||||||
@@ -39,7 +39,7 @@
|
|||||||
<ul class="typecho-option typecho-option-submit" id="typecho-option-item--6">
|
<ul class="typecho-option typecho-option-submit" id="typecho-option-item--6">
|
||||||
<li>
|
<li>
|
||||||
<button type="submit" class="btn primary">
|
<button type="submit" class="btn primary">
|
||||||
增加专题</button>
|
{{if .Edit}}更新专题{{else}}新增专题{{end}}</button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -45,10 +45,11 @@
|
|||||||
<td>
|
<td>
|
||||||
<input type="checkbox" value="{{.ID}}" name="mid[]" />
|
<input type="checkbox" value="{{.ID}}" name="mid[]" />
|
||||||
</td>
|
</td>
|
||||||
<td><a href="/admin/add-serie?mid={{.ID}}">{{.ID}}</a>
|
<td>{{.ID}}</td>
|
||||||
<a href="/series.html#toc-{{.ID}}" title="浏览 {{.Name}}"><i class="i-exlink"></i></a>
|
<td>
|
||||||
|
<a href="/admin/add-serie?mid={{.ID}}">{{.Name}}</a>
|
||||||
|
<a target="_blank" href="/series.html#toc-{{.ID}}" title="浏览 {{.Name}}"><i class="i-exlink"></i></a>
|
||||||
</td>
|
</td>
|
||||||
<td>{{.Name}}</td>
|
|
||||||
<td>{{dateformat .CreateTime "2006/01/02 15:04"}}</td>
|
<td>{{dateformat .CreateTime "2006/01/02 15:04"}}</td>
|
||||||
<td><a class="balloon-button left size-50" href="#">{{len .Articles}}</a></td>
|
<td><a class="balloon-button left size-50" href="#">{{len .Articles}}</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
Reference in New Issue
Block a user