Compare commits

..

23 Commits

Author SHA1 Message Date
henry.chen
dc3e6659b5 chore(release): 2.1.4 2021-10-26 16:18:21 +08:00
henry.chen
ca74d13598 chore(release): 2.1.4 2021-10-26 16:18:00 +08:00
henry.chen
82fba0ddb4 fix(release): github action runner 2021-10-26 16:17:50 +08:00
henry.chen
2b6bae1f74 chore(release): 2.1.3 2021-10-15 16:54:47 +08:00
Deepzz
6387412776 Update README.md 2021-09-14 21:32:37 +08:00
razeen
cfaa25e123 fix(auto_save): fix auto save return empty id 2021-08-15 03:51:45 -07:00
Deepzz
6ff6acdbda Merge pull request #32 from eiblog/qiniu_zone
qiniu upload remove zone, support all zone upload
2021-08-12 09:19:56 +08:00
razeen
b3b3be448f chore(qiniu): qiniu upload remove zone, support all zone upload 2021-08-11 08:31:04 -07:00
henry.chen
78f5bfc1ce fix: backup app judge db driver 2021-08-11 18:44:35 +08:00
Deepzz
4b9eb1ff4d Merge pull request #29 from eiblog/fix_init_password
初始化地方参数错了。。。
2021-08-10 16:17:10 +08:00
Razeen
7d04b8f5c0 fix(pwd): fix init pwd 2021-08-10 10:37:42 +08:00
henry.chen
d000090e30 chore(release): 2.1.2 2021-07-27 17:19:04 +08:00
henry.chen
56e396f252 chore: restore app.yml database 2021-07-27 17:18:58 +08:00
henry.chen
f6662fa4c5 chore(release): 2.1.1 2021-07-27 09:15:17 +08:00
henry.chen
a570c783f3 chore(gin): upgrade gin to fix CVE-2020-28483 2021-07-27 09:15:03 +08:00
henry.chen
e2046d0d39 fix: sqlite error 2021-07-25 10:45:33 +08:00
henry.chen
cdbe082764 chore(docs): update backup.md 2021-07-14 12:10:40 +08:00
henry.chen
3a86c6a65c chore: clean go.sum 2021-07-14 10:57:37 +08:00
henry.chen
c1c9e6025a chore: add backup app 2021-07-14 10:54:30 +08:00
deepzz0
a15791a792 chore: clean dir 2021-05-27 13:54:12 +08:00
deepzz0
ea87f4b2e6 chore: update readme 2021-05-17 10:48:22 +08:00
deepzz0
a0653cf67f chore: update README.md 2021-05-16 11:22:13 +08:00
deepzz0
397d47bc00 fix: excerpt for es 2021-05-11 22:55:20 +08:00
29 changed files with 510 additions and 104 deletions

View File

@@ -7,7 +7,7 @@ on:
jobs:
package:
runs-on: ubuntu-16.04
runs-on: self-hosted
steps:
- name: Golang env
uses: actions/setup-go@v2
@@ -35,6 +35,8 @@ jobs:
password: ${{ secrets.DOCKER_PASSWORD }}
username: ${{ secrets.DOCKER_USERNAME }}
- name: Build image
env:
GOPROXY: https://goproxy.io,direct
run: scripts/run_build.sh deepzz0 ${{ steps.vars.outputs.tag }}
- name: Package tar
@@ -44,6 +46,7 @@ jobs:
if: startsWith(github.ref, 'refs/tags/')
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GOPROXY: https://goproxy.io,direct
with:
files: |
*.tar.gz

1
.gitignore vendored
View File

@@ -6,6 +6,7 @@
*.dylib
*.DS_Store
*.tar.gz
*.db
backend
# Test binary, built with `go test -c`

View File

@@ -2,6 +2,38 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
### [2.1.4](https://github.com/eiblog/eiblog/compare/v2.1.3...v2.1.4) (2021-10-26)
### Bug Fixes
* **release:** github action runner ([82fba0d](https://github.com/eiblog/eiblog/commit/82fba0ddb47c1f66cb659f775c120c08dd2b4447))
### [2.1.4](https://github.com/eiblog/eiblog/compare/v2.1.3...v2.1.4) (2021-10-26)
### Bug Fixes
* **release:** github action runner ([82fba0d](https://github.com/eiblog/eiblog/commit/82fba0ddb47c1f66cb659f775c120c08dd2b4447))
### [2.1.3](https://github.com/eiblog/eiblog/compare/v2.1.2...v2.1.3) (2021-10-15)
### Bug Fixes
* **auto_save:** fix auto save return empty id ([cfaa25e](https://github.com/eiblog/eiblog/commit/cfaa25e1239aba580e0718d40f1a2bf31158b217))
* backup app judge db driver ([78f5bfc](https://github.com/eiblog/eiblog/commit/78f5bfc1ce017bf77a7442f40963a706e608df51))
* **pwd:** fix init pwd ([7d04b8f](https://github.com/eiblog/eiblog/commit/7d04b8f5c0846bcd0c7e07d0fc3704a535f6360a))
### [2.1.2](https://github.com/eiblog/eiblog/compare/v2.1.1...v2.1.2) (2021-07-27)
### [2.1.1](https://github.com/eiblog/eiblog/compare/v2.1.0...v2.1.1) (2021-07-27)
### Bug Fixes
* sqlite error ([e2046d0](https://github.com/eiblog/eiblog/commit/e2046d0d39d9914473fe7b8fae3b18246ed133ce))
### [2.0.6](https://github.com/eiblog/eiblog/compare/v2.0.5...v2.0.6) (2021-05-08)

View File

@@ -8,34 +8,52 @@
### 快速体验
1、下载程序压缩包到 [这里](https://github.com/eiblog/eiblog/releases) 下载 eiblog 相应系统压缩包,然后解压缩。
这里以 mongodb 为例,更多支持的后端存储服务如下:
2、启动数据库服务博客支持多种数据库后端如MongoDB、MySQL、Postgres、SQLite等。
| 类型driver | 地址source示例 |
| -------------- | ------------------------------------------------------------ |
| mongodb | mongodb://localhost:27017 |
| mysql | user:password@tcp(localhost:3306)/eiblog?charset=utf8mb4&parseTime=True&loc=Local |
| postgres | host=localhost port=5432 user=user password=password dbname=eiblog sslmode=disable |
| sqlite | /path/eiblog.db |
| sqlserver | sqlserver://user:password@localhost:9930?database=eiblog |
| clickhouse | tcp://localhost:9000?database=eiblog&username=user&password=password&read_timeout=10&write_timeout=20 |
1、启动依赖服务mongodb、elasticsearch
```
$ docker run --name mongodb \
-p 27017:27017 \
-v ${PWD}/mgodb:/data/db \
mongo:3.2
$ docker run --name elasticsearch \
-p 9200:9200 \
-v ${PWD}/esdata:/usr/share/elasticsearch/data \
deepzz0/elasticsearch:2.4.1
```
2、下载压缩包到 [这里](https://github.com/eiblog/eiblog/releases) 下载 eiblog非backup 相应系统压缩包,然后解压缩。
3、修改配置将数据库与ES地址修改为相应地址
```
# 修改 conf/app.yml 数据库连接配置
# driver可选mongodb、mysql、postgres、sqlite、sqlserver、clickhouse、redis等
# source为相应的连接地址
database:
driver: postgres
source: host=localhost port=5432 user=postgres dbname=eiblog sslmode=disable password=MTI3LjAuMC4x
```
driver: mongodb
source: mongodb://localhost:27017
3、启动 ES 搜索服务:博客使用 ElasticSearch 2.4.1 做为搜索引擎。
```
# 修改 conf/app.yml ElasticSearch连接配置
# 如果不启用搜索功能可以置空
# 修改 conf/app.yml ES连接配置如果不启用搜索功能可以置空
eshost: http://localhost:9200
```
4、启动博客程序。
4、启动服务:
```
./backend
```
然后访问 `localhost:9000` 就可以了。
然后访问 `localhost:9000` 就可以了,后台地址 `localhost:9000/admin/login`,默认账户密码 `deepzz/deepzz`
### 功能特性
@@ -47,16 +65,16 @@ eshost: http://localhost:9200
功能说明:
- [x] 博客归档,利用时间线帮助我们将归纳博文,内容少于一年按月归档,大于则按年归档。
- [x] 博客专题,有时候博文是同一系列,专题能够帮助我们很好归纳博文,对阅读者是非常友好的。
- [x] 标签系统,每篇博文都可以打上不同标签,使得在归档和专题不满足的情况下自定义归档,这块辅助搜索简直完美。
- [x] 搜索系统依托ElasticSearch实现的站内搜索速度与效率并存再加上google opensearch搜索只流畅。
- [x] 管理后台,内嵌全功能 `Typecho` 后台系统,全功能 `Markdown` 编辑器让你感觉什么是简洁清爽。
- [x] 谷歌统计由于google api的速度问题从而实现了后端API异步统计使得博客页面加载飞速。
- [x] Disqus评论国内评论系统不友好因此选择disqus又由于众所周知原因国内不能用实现另类disqus评论方式。
- [x] 多存储后端支持mongodb、mysql、postgres、sqlite等存储后端。
- [x] 七牛CDN支持在 `Markdown` 编辑器直接上传附件,让你只考虑编辑内容,解放思想。
- [x] 自动备份支持多存储后端的备份功能备份数据保存到七牛CDN上。
* 博客归档,利用时间线帮助我们将归纳博文,内容少于一年按月归档,大于则按年归档。
* 博客专题,有时候博文是同一系列,专题能够帮助我们很好归纳博文,对阅读者是非常友好的。
* 标签系统,每篇博文都可以打上不同标签,使得在归档和专题不满足的情况下自定义归档,这块辅助搜索简直完美。
* 搜索系统依托ElasticSearch实现的站内搜索速度与效率并存再加上google opensearch搜索只流畅。
* 管理后台,内嵌全功能 `Typecho` 后台系统,全功能 `Markdown` 编辑器让你感觉什么是简洁清爽。
* 谷歌统计由于google api的速度问题从而实现了后端API异步统计使得博客页面加载飞速。
* Disqus评论国内评论系统不友好因此选择disqus又由于众所周知原因国内不能用实现另类disqus评论方式。
* 多存储后端支持mongodb、mysql、postgres、sqlite等存储后端。
* 七牛CDN支持在 `Markdown` 编辑器直接上传附件,让你只考虑编辑内容,解放思想。
* 自动备份支持多存储后端的备份功能备份数据保存到七牛CDN上。
当然,为了让整个系统加载速度更快,还做了更多优化措施:

View File

@@ -1,8 +1,54 @@
// Package main provides ...
package main
import "fmt"
import (
"fmt"
"github.com/eiblog/eiblog/pkg/config"
"github.com/eiblog/eiblog/pkg/core/backup/ping"
"github.com/eiblog/eiblog/pkg/core/backup/swag"
"github.com/eiblog/eiblog/pkg/core/backup/timer"
"github.com/gin-gonic/gin"
)
func main() {
fmt.Println("hello world!")
fmt.Println("Hi, it's App " + config.Conf.BackupApp.Name)
endRun := make(chan error, 1)
runTimer(endRun)
runHTTPServer(endRun)
fmt.Println(<-endRun)
}
func runTimer(endRun chan error) {
go func() {
endRun <- timer.Start()
}()
}
func runHTTPServer(endRun chan error) {
if !config.Conf.EiBlogApp.EnableHTTP {
return
}
if config.Conf.RunMode == config.ModeProd {
gin.SetMode(gin.ReleaseMode)
}
e := gin.Default()
// swag
swag.RegisterRoutes(e)
// route
ping.RegisterRoutes(e)
// start
address := fmt.Sprintf(":%d", config.Conf.EiBlogApp.HTTPPort)
go func() {
endRun <- e.Run(address)
}()
fmt.Println("HTTP server running on: " + address)
}

View File

@@ -19,13 +19,13 @@ import (
func main() {
fmt.Println("Hi, it's App " + config.Conf.EiBlogApp.Name)
endRun := make(chan bool, 1)
endRun := make(chan error, 1)
runHTTPServer(endRun)
<-endRun
fmt.Println(<-endRun)
}
func runHTTPServer(endRun chan bool) {
func runHTTPServer(endRun chan error) {
if !config.Conf.EiBlogApp.EnableHTTP {
return
}
@@ -65,6 +65,8 @@ func runHTTPServer(endRun chan bool) {
// start
address := fmt.Sprintf(":%d", config.Conf.EiBlogApp.HTTPPort)
go e.Run(address)
go func() {
endRun <- e.Run(address)
}()
fmt.Println("HTTP server running on: " + address)
}

View File

@@ -2,7 +2,7 @@ appname: eiblog
database:
driver: postgres
source: host=localhost port=5432 user=postgres dbname=eiblog sslmode=disable password=MTI3LjAuMC4x
eshost: http://localhost:9200
eshost:
eiblogapp:
mode:
name: cmd-eiblog
@@ -53,6 +53,15 @@ eiblogapp:
username: deepzz # *后台登录用户名
password: deepzz # *登录明文密码
backupapp:
name: cmd-backup
enablehttp: true
httpport: 9001
mode:
name: cmd-backup
enablehttp: true
httpport: 9001
backupto: qiniu # 备份到七牛云
interval: 7d # 多久备份一次
validity: 60d # 保存时长
qiniu: # 七牛OSS
bucket: backup
domain: st.deepzz.com
accesskey: MB6AXl_Sj_mmFsL-Lt59Dml2Vmy2o8XMmiCbbSeC
secretkey: BIrMy0fsZ0_SHNceNXk3eDuo7WmVYzj2-zrmd5Tf

View File

@@ -2,6 +2,8 @@
> 博客项目结构参考模版https://github.com/deepzz0/appdemo
EiBlog 镜像仓库地址https://hub.docker.com/u/deepzz0
用过其它博客系统,不喜欢,不够轻,不够快!这是我开发的第二款博客系统,也实在不想再在这件事情上过多纠结了。`EiBlog` 是一个比较稳定的博客系统,现已迭代至 `2.0` 版本,稳定性和维护你是不用担心的。
但它有着部署简单(上线复杂!)的特点,不推荐没有计算机知识的朋友搭建,欢迎咨询。该博客的个中优点(简洁、轻快,安全),等你体验。

View File

@@ -1,2 +1,42 @@
待完善。。。
### 备份数据
EiBlog 镜像仓库地址https://hub.docker.com/u/deepzz0备份镜像为deepzz0/backup。
目前仅支持同步 mongodb 数据到七牛云,参考 `app.yml`
```
backupapp:
mode:
name: cmd-backup
enablehttp: true
httpport: 9001
backupto: qiniu # 备份到七牛云
interval: 7d # 多久备份一次
validity: 60d # 保存时长
qiniu: # 七牛OSS
bucket: backup
domain: st.deepzz.com
accesskey: MB6AXl_Sj_mmFsL-Lt59Dml2Vmy2o8XMmiCbbSeC
secretkey: BIrMy0fsZ0_SHNceNXk3eDuo7WmVYzj2-zrmd5Tf
```
### 运行
1、获取备份镜像
```
$ docker pull deepzz0/backup
```
2、启动备份镜像
```
$ docker run --name backup \
-v ${PWD}/conf:/app/conf
```
Docker-compose 请参考项目根目录下的 `docker-compose.yml` 文件。

View File

@@ -43,7 +43,7 @@ $ docker run --name es \
修改 `conf/app.yml` 下的 `eshost` 配置:
```
# 如果不部署,请置空
# 如果不提供搜索,请置空
eshost: http://localhost:9200
```

View File

@@ -1 +0,0 @@
Examples for your applications and/or public libraries.

2
go.mod
View File

@@ -6,7 +6,7 @@ require (
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751
github.com/eiblog/blackfriday v0.0.0-20161010144836-c0ec111761ae
github.com/gin-contrib/sessions v0.0.3
github.com/gin-gonic/gin v1.6.3
github.com/gin-gonic/gin v1.7.2
github.com/gofrs/uuid v3.3.0+incompatible
github.com/golang/protobuf v1.4.2
github.com/lib/pq v1.10.1

15
go.sum
View File

@@ -15,7 +15,6 @@ github.com/aws/aws-sdk-go v1.34.28 h1:sscPpn/Ns3i0F4HPEWAVcwdIRaZZCuL7llJ2/60yPI
github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48=
github.com/bkaradzic/go-lz4 v1.0.0 h1:RXc4wYsyz985CkXXeX04y4VnZFGG8Rd43pRaHsOXAKk=
github.com/bkaradzic/go-lz4 v1.0.0/go.mod h1:0YdlkowM3VswSROI7qDxhRvJ3sLhlFrRRwjwegp5jy4=
github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff h1:RmdPFa+slIr4SCBg4st/l/vZWVe9QJKMXGO60Bxbe04=
github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff/go.mod h1:+RTT1BOk5P97fT2CiHkbFQwkK3mjsFAP6zCYV2aXtjw=
github.com/bradfitz/gomemcache v0.0.0-20190329173943-551aad21a668/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA=
github.com/bradleypeabody/gorilla-sessions-memcache v0.0.0-20181103040241-659414f458e1/go.mod h1:dkChI7Tbtx7H1Tj7TqGSZMOeGpMP5gLHtjroHd4agiI=
@@ -53,8 +52,9 @@ github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm
github.com/gin-gonic/gin v1.3.0/go.mod h1:7cKuhb5qV2ggCFctp2fJQ+ErvciLZrIeoOSOm6mUr7Y=
github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM=
github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do=
github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
github.com/gin-gonic/gin v1.7.2 h1:Tg03T9yM2xa8j6I3Z3oqLaQRSmKvxPd6g/2HJ6zICFA=
github.com/gin-gonic/gin v1.7.2/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=
github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
github.com/go-openapi/jsonpointer v0.17.0/go.mod h1:cOnomiV+CVVwFLk0A/MExoFMjwdsUdVpsRhURCKh+3M=
github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w=
@@ -77,8 +77,9 @@ github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTM
github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY=
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY=
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE=
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
@@ -119,7 +120,6 @@ github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
@@ -131,13 +131,11 @@ github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0=
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0 h1:/QaMHBdZ26BB3SSst0Iwl10Epc+xhTquomWX0oZEB6w=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
@@ -277,7 +275,6 @@ github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAv
github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -367,7 +364,6 @@ golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2 h1:It14KIkyBFYkHkwZ7k45minvA9aorojkyjGk9KJ5B/w=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
@@ -392,7 +388,6 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200625001655-4c5254603344 h1:vGXIOMxbNfDTk/aXCmfdLgkrSV+Z2tcbze+pEc3v5W4=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
@@ -422,14 +417,12 @@ golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd h1:xhmwyvizuTgC2qz7ZlMluP20uW+C3Rm0FD/WLDX8884=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 h1:nxC68pudNYkKU6jWhgrqdreuFiOQWj1Fs7T3VrH4Pjw=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=

View File

@@ -1 +0,0 @@
System init (systemd, upstart, sysv) and process manager/supervisor (runit, supervisord) configs.

2
pkg/cache/cache.go vendored
View File

@@ -443,7 +443,7 @@ func (c *Cache) loadOrInit() error {
}
}
// account
pwd := tools.EncryptPasswd(blogapp.Account.Password,
pwd := tools.EncryptPasswd(blogapp.Account.Username,
blogapp.Account.Password)
account := &model.Account{

View File

@@ -7,6 +7,7 @@ import (
"github.com/eiblog/eiblog/pkg/config"
"github.com/eiblog/eiblog/pkg/model"
"github.com/eiblog/eiblog/tools"
"github.com/eiblog/blackfriday"
)
@@ -41,17 +42,6 @@ var (
regHeader = regexp.MustCompile("</nav></div>")
)
// IgnoreHtmlTag 去掉 html tag
func IgnoreHtmlTag(src string) string {
// 去除所有尖括号内的HTML代码
re, _ := regexp.Compile(`<[\S\s]+?>`)
src = re.ReplaceAllString(src, "")
// 去除换行符
re, _ = regexp.Compile(`\s+`)
return re.ReplaceAllString(src, "")
}
// RenderPage 渲染markdown
func RenderPage(md []byte) []byte {
renderer := blackfriday.HtmlRenderer(commonHtmlFlags, "", "")
@@ -66,7 +56,7 @@ func GenerateExcerptMarkdown(article *model.Article) {
index := strings.Index(article.Content, "\r\n")
prefix := article.Content[len(blogapp.General.DescPrefix):index]
article.Desc = IgnoreHtmlTag(prefix)
article.Desc = tools.IgnoreHtmlTag(prefix)
article.Content = article.Content[index:]
}
@@ -83,12 +73,13 @@ func GenerateExcerptMarkdown(article *model.Article) {
// excerpt
index = regIdentifier.FindStringIndex(article.Content)
if index != nil {
article.Excerpt = IgnoreHtmlTag(article.Content[:index[0]])
article.Excerpt = tools.IgnoreHtmlTag(article.Content[:index[0]])
return
}
uc := []rune(article.Content)
length := blogapp.General.Length
if len(uc) < length {
length = len(uc)
}
article.Excerpt = IgnoreHtmlTag(string(uc[0:length]))
article.Excerpt = tools.IgnoreHtmlTag(string(uc[0:length]))
}

View File

@@ -121,6 +121,16 @@ type EiBlogApp struct {
Blogger Blogger `yaml:"blogger"`
}
// BackupApp config
type BackupApp struct {
Mode
BackupTo string `yaml:"backupto"`
Interval string `yaml:"interval"` // circle backup, default: 7d
Validity string `yaml:"validity"` // storage days, default: 60d
Qiniu Qiniu `yaml:"qiniu"` // qiniu config
}
// Config app config
type Config struct {
RunMode string `yaml:"runmode"`
@@ -128,7 +138,7 @@ type Config struct {
Database Database `yaml:"database"`
ESHost string `yaml:"eshost"`
EiBlogApp EiBlogApp `yaml:"eiblogapp"`
BackupApp Mode `yaml:"backupapp"`
BackupApp BackupApp `yaml:"backupapp"`
}
// load config file

View File

@@ -0,0 +1,18 @@
// Package ping provides ...
package ping
import (
"net/http"
"github.com/gin-gonic/gin"
)
// RegisterRoutes register routes
func RegisterRoutes(group gin.IRoutes) {
group.GET("/ping", handlePing)
}
// handlePing ping
func handlePing(c *gin.Context) {
c.String(http.StatusOK, "it's ok")
}

View File

@@ -0,0 +1,15 @@
// Package swag provides ...
package swag
import (
_ "github.com/eiblog/eiblog/pkg/core/backup/docs" // docs
"github.com/gin-gonic/gin"
ginSwagger "github.com/swaggo/gin-swagger"
"github.com/swaggo/gin-swagger/swaggerFiles"
)
// RegisterRoutes register routes
func RegisterRoutes(group gin.IRoutes) {
group.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
}

View File

@@ -0,0 +1,77 @@
// Package qiniu provides ...
package qiniu
import (
"context"
"errors"
"fmt"
"os"
"os/exec"
"time"
"github.com/eiblog/eiblog/pkg/config"
"github.com/eiblog/eiblog/pkg/internal"
)
// Storage qiniu storage
type Storage struct{}
// BackupData implements timer.Storage
func (s Storage) BackupData(now time.Time) error {
switch config.Conf.Database.Driver {
case "mongodb":
return backupFromMongoDB(now)
default:
return errors.New("unsupported database source backup to qiniu")
}
}
func backupFromMongoDB(now time.Time) error {
ctx, cancel := context.WithTimeout(context.Background(), time.Minute*20)
defer cancel()
// dump
arg := fmt.Sprintf("mongodump -h %s -d eiblog -o /tmp",
config.Conf.Database.Source)
cmd := exec.CommandContext(ctx, "sh", "-c", arg)
err := cmd.Run()
if err != nil {
return err
}
// tar
name := fmt.Sprintf("eiblog-%s.tar.gz", now.Format("2006-01-02"))
arg = fmt.Sprintf("tar czf %s /tmp/eiblog", name)
cmd = exec.CommandContext(ctx, "sh", "-c", arg)
err = cmd.Run()
if err != nil {
return err
}
// upload file
f, err := os.Open("/tmp/eiblog/" + name)
if err != nil {
return err
}
s, err := f.Stat()
if err != nil {
return err
}
uploadParams := internal.UploadParams{
Name: name,
Size: s.Size(),
Data: f,
Conf: config.Conf.BackupApp.Qiniu,
}
_, err = internal.QiniuUpload(uploadParams)
if err != nil {
return err
}
// after days delete
deleteParams := internal.DeleteParams{
Name: name,
Conf: config.Conf.BackupApp.Qiniu,
}
return internal.QiniuDelete(deleteParams)
}

View File

@@ -0,0 +1,68 @@
// Package timer provides ...
package timer
import (
"errors"
"strconv"
"time"
"github.com/eiblog/eiblog/pkg/config"
"github.com/eiblog/eiblog/pkg/core/backup/timer/qiniu"
"github.com/sirupsen/logrus"
)
// Start to backup with ticker
func Start() error {
var storage Storage
// backup instance
switch config.Conf.BackupApp.BackupTo {
case "qiniu":
storage = qiniu.Storage{}
default:
return errors.New("timer: unknown backup to driver: " +
config.Conf.BackupApp.BackupTo)
}
// parse duration
interval, err := ParseDuration(config.Conf.BackupApp.Interval)
if err != nil {
return err
}
t := time.NewTicker(interval)
for now := range t.C {
err = storage.BackupData(now)
if err != nil {
logrus.Error("timer: Start.BackupData: ", now, err)
}
}
return nil
}
// ParseDuration parse string to duration
func ParseDuration(d string) (time.Duration, error) {
if len(d) == 0 {
return 0, errors.New("timer: incorrect duration input")
}
length := len(d)
switch d[length-1] {
case 's', 'm', 'h':
return time.ParseDuration(d)
case 'd':
di, err := strconv.Atoi(d[:length-1])
if err != nil {
return 0, err
}
return time.Duration(di) * time.Hour * 24, nil
}
return 0, errors.New("timer: unsupported duration:" + d)
}
// Storage backup backend
type Storage interface {
BackupData(now time.Time) error
}

View File

@@ -283,6 +283,9 @@ func handleAPIPostCreate(c *gin.Context) {
logrus.Error("handleAPIPostCreate.AddArticle: ", err)
return
}
cid = article.ID
if !article.IsDraft {
// 异步执行,快
go func() {
@@ -467,7 +470,15 @@ func handleAPIQiniuUpload(c *gin.Context) {
return
}
filename := strings.ToLower(header.Filename)
url, err := internal.QiniuUpload(filename, s.Size(), file)
params := internal.UploadParams{
Name: filename,
Size: s.Size(),
Data: file,
Conf: config.Conf.EiBlogApp.Qiniu,
}
url, err := internal.QiniuUpload(params)
if err != nil {
logrus.Error("handleAPIQiniuUpload.QiniuUpload: ", err)
c.String(http.StatusBadRequest, err.Error())
@@ -491,7 +502,13 @@ func handleAPIQiniuDelete(c *gin.Context) {
logrus.Error("handleAPIQiniuDelete.PostForm: 参数错误")
return
}
err := internal.QiniuDelete(name)
params := internal.DeleteParams{
Name: name,
Conf: config.Conf.EiBlogApp.Qiniu,
}
err := internal.QiniuDelete(params)
if err != nil {
logrus.Error("handleAPIQiniuDelete.QiniuDelete: ", err)
}

View File

@@ -13,19 +13,28 @@ import (
"github.com/qiniu/go-sdk/v7/storage"
)
// UploadParams upload params
type UploadParams struct {
Name string
Size int64
Data io.Reader
Conf config.Qiniu
}
// QiniuUpload 上传文件
func QiniuUpload(name string, size int64, data io.Reader) (string, error) {
if config.Conf.EiBlogApp.Qiniu.AccessKey == "" ||
config.Conf.EiBlogApp.Qiniu.SecretKey == "" {
func QiniuUpload(params UploadParams) (string, error) {
if params.Conf.AccessKey == "" ||
params.Conf.SecretKey == "" {
return "", errors.New("qiniu config error")
}
key := completeQiniuKey(name)
key := completeQiniuKey(params.Name)
mac := qbox.NewMac(config.Conf.EiBlogApp.Qiniu.AccessKey,
config.Conf.EiBlogApp.Qiniu.SecretKey)
mac := qbox.NewMac(params.Conf.AccessKey,
params.Conf.SecretKey)
// 设置上传策略
putPolicy := &storage.PutPolicy{
Scope: config.Conf.EiBlogApp.Qiniu.Bucket,
Scope: params.Conf.Bucket,
Expires: 3600,
InsertOnly: 1,
}
@@ -33,7 +42,6 @@ func QiniuUpload(name string, size int64, data io.Reader) (string, error) {
uploadToken := putPolicy.UploadToken(mac)
// 上传配置
cfg := &storage.Config{
Zone: &storage.ZoneHuadong,
UseHTTPS: true,
}
// uploader
@@ -42,20 +50,28 @@ func QiniuUpload(name string, size int64, data io.Reader) (string, error) {
putExtra := &storage.PutExtra{}
err := uploader.Put(context.Background(), ret, uploadToken,
key, data, size, putExtra)
key, params.Data, params.Size, putExtra)
if err != nil {
return "", err
}
url := "https://" + config.Conf.EiBlogApp.Qiniu.Domain + "/" + key
url := "https://" + params.Conf.Domain + "/" + key
return url, nil
}
// QiniuDelete 删除文件
func QiniuDelete(name string) error {
key := completeQiniuKey(name)
// DeleteParams delete params
type DeleteParams struct {
Name string
Days int
mac := qbox.NewMac(config.Conf.EiBlogApp.Qiniu.AccessKey,
config.Conf.EiBlogApp.Qiniu.SecretKey)
Conf config.Qiniu
}
// QiniuDelete 删除文件
func QiniuDelete(params DeleteParams) error {
key := completeQiniuKey(params.Name)
mac := qbox.NewMac(params.Conf.AccessKey,
params.Conf.SecretKey)
// 上传配置
cfg := &storage.Config{
Zone: &storage.ZoneHuadong,
@@ -64,7 +80,10 @@ func QiniuDelete(name string) error {
// manager
bucketManager := storage.NewBucketManager(mac, cfg)
// Delete
return bucketManager.Delete(config.Conf.EiBlogApp.Qiniu.Bucket, key)
if params.Days > 0 {
return bucketManager.DeleteAfterDays(params.Conf.Bucket, key, params.Days)
}
return bucketManager.Delete(params.Conf.Bucket, key)
}
// completeQiniuKey 修复路径

View File

@@ -0,0 +1,47 @@
// Package internal provides ...
package internal
import (
"os"
"testing"
"time"
"github.com/eiblog/eiblog/pkg/config"
)
func TestQiniuUpload(t *testing.T) {
f, _ := os.Open("qiniu_test.go")
fi, _ := f.Stat()
type args struct {
params UploadParams
}
tests := []struct {
name string
args args
wantErr bool
}{
// TODO: Add test cases.
{"1", args{params: UploadParams{
Name: "test-" + time.Now().Format("200601021504059999") + ".go",
Size: fi.Size(),
Data: f,
Conf: config.Qiniu{
AccessKey: os.Getenv("QINIU_ACCESSKEY"),
SecretKey: os.Getenv("QINIU_SECRETKEY"),
Bucket: os.Getenv("QINIU_BUCKET"),
},
}}, false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := QiniuUpload(tt.args.params)
if (err != nil) != tt.wantErr {
t.Errorf("QiniuUpload() error = %v, wantErr %v", err, tt.wantErr)
return
}
t.Logf("QiniuUpload() = %v", got)
})
}
}

View File

@@ -13,9 +13,9 @@ type Account struct {
PhoneN string `gorm:"column:phone_n;not null" bson:"phone_n"` // 手机号
Address string `gorm:"column:address;not null" bson:"address"` // 地址信息
LogoutAt time.Time `gorm:"column:logout_at;not null" bson:"logout_at"` // 登出时间
LoginIP string `gorm:"column:login_ip;not null" bson:"login_ip"` // 最近登录IP
LoginUA string `gorm:"column:login_ua;not null" bson:"login_ua"` // 最近登录IP
LoginAt time.Time `gorm:"column:login_at;default:now()" bson:"login_at"` // 最近登录时间
CreatedAt time.Time `gorm:"column:created_at;default:now()" bson:"created_at"` // 创建时间
LogoutAt time.Time `gorm:"column:logout_at;not null" bson:"logout_at"` // 登出时间
LoginIP string `gorm:"column:login_ip;not null" bson:"login_ip"` // 最近登录IP
LoginUA string `gorm:"column:login_ua;not null" bson:"login_ua"` // 最近登录IP
LoginAt time.Time `gorm:"column:login_at;default:current_timestamp" bson:"login_at"` // 最近登录时间
CreatedAt time.Time `gorm:"column:created_at;default:current_timestamp" bson:"created_at"` // 创建时间
}

View File

@@ -21,9 +21,9 @@ type Article struct {
Tags pq.StringArray `gorm:"column:tags;type:text[]" bson:"tags"` // tags
IsDraft bool `gorm:"column:is_draft;not null" bson:"is_draft"` // 是否是草稿
DeletedAt time.Time `gorm:"column:deleted_at;not null" bson:"deleted_at"` // 删除时间
UpdatedAt time.Time `gorm:"column:updated_at;default:now()" bson:"updated_at"` // 更新时间
CreatedAt time.Time `gorm:"column:created_at;default:now()" bson:"created_at"` // 创建时间
DeletedAt time.Time `gorm:"column:deleted_at;not null" bson:"deleted_at"` // 删除时间
UpdatedAt time.Time `gorm:"column:updated_at;default:current_timestamp" bson:"updated_at"` // 更新时间
CreatedAt time.Time `gorm:"column:created_at;default:current_timestamp" bson:"created_at"` // 创建时间
Header string `gorm:"-" bson:"-"` // header
Excerpt string `gorm:"-" bson:"-"` // 预览信息

View File

@@ -5,11 +5,11 @@ import "time"
// Serie 专题
type Serie struct {
ID int `gorm:"column:id;primaryKey" bson:"id"` // 自增ID
Slug string `gorm:"column:slug;not null;uniqueIndex" bson:"slug"` // 缩略名
Name string `gorm:"column:name;not null" bson:"name"` // 专题名
Desc string `gorm:"column:desc;not null" bson:"desc"` // 专题描述
CreatedAt time.Time `gorm:"column:created_at;default:now()" bson:"created_at"` // 创建时间
ID int `gorm:"column:id;primaryKey" bson:"id"` // 自增ID
Slug string `gorm:"column:slug;not null;uniqueIndex" bson:"slug"` // 缩略名
Name string `gorm:"column:name;not null" bson:"name"` // 专题名
Desc string `gorm:"column:desc;not null" bson:"desc"` // 专题描述
CreatedAt time.Time `gorm:"column:created_at;default:current_timestamp" bson:"created_at"` // 创建时间
Articles SortedArticles `gorm:"-" bson:"-"` // 专题下的文章
}

View File

@@ -1,7 +1,5 @@
#!/usr/bin/env sh
set -e
_registry="$1"
_tag="$2"
_platform="linux/amd64,linux/arm64,linux/386"
@@ -11,11 +9,14 @@ if [ -z "$_registry" ] || [ -z "$_tag" ]; then
exit 0;
fi
# create and use builder
docker buildx inspect builder >/dev/null 2>&1
if [ "$?" != "0" ]; then
docker buildx create --use --name builder
fi
# prepare dir ./bin
mkdir -p ./bin
# create builder
docker buildx create --use --name builder
# build demo app
for file in pkg/core/*; do
app="$(basename $file)";

View File

@@ -1 +0,0 @@
External helper tools, forked code and other 3rd party utilities (e.g., Swagger UI).