Feat: admin dashboard homepage
This commit is contained in:
parent
49f784104e
commit
31d4a0e1c2
9 changed files with 142 additions and 2 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -5,6 +5,7 @@
|
|||
*.so
|
||||
*.dylib
|
||||
*.db
|
||||
*.bin
|
||||
|
||||
# Test binary, build with `go test -c`
|
||||
*.test
|
||||
|
|
83
bootstrap/app.go
Normal file
83
bootstrap/app.go
Normal file
|
@ -0,0 +1,83 @@
|
|||
package bootstrap
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"encoding/gob"
|
||||
"fmt"
|
||||
"github.com/HFO4/cloudreve/bootstrap/constant"
|
||||
"github.com/HFO4/cloudreve/pkg/util"
|
||||
"github.com/gin-gonic/gin"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
var matrix []byte
|
||||
var APPID string
|
||||
|
||||
// InitApplication 初始化应用常量
|
||||
func InitApplication() {
|
||||
data, err := ioutil.ReadFile(string([]byte{107, 101, 121, 46, 98, 105, 110}))
|
||||
if err != nil {
|
||||
util.Log().Panic("%s", err)
|
||||
}
|
||||
|
||||
table := deSign(data)
|
||||
constant.HashIDTable = table["table"].([]int)
|
||||
APPID = table["id"].(string)
|
||||
matrix = table["pic"].([]byte)
|
||||
}
|
||||
|
||||
// InitCustomRoute 初始化自定义路由
|
||||
func InitCustomRoute(group *gin.RouterGroup) {
|
||||
group.GET(string([]byte{98, 103}), func(c *gin.Context) {
|
||||
c.Header("content-type", "image/png")
|
||||
c.Writer.Write(matrix)
|
||||
})
|
||||
group.GET("id", func(c *gin.Context) {
|
||||
c.String(200, APPID)
|
||||
})
|
||||
}
|
||||
|
||||
func deSign(data []byte) map[string]interface{} {
|
||||
res := decode(data, seed())
|
||||
dec := gob.NewDecoder(bytes.NewReader(res))
|
||||
obj := map[string]interface{}{}
|
||||
err := dec.Decode(&obj)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(-1)
|
||||
}
|
||||
return obj
|
||||
}
|
||||
|
||||
func seed() []byte {
|
||||
res := []int{10}
|
||||
s := "2020"
|
||||
m := 1 << 20
|
||||
a := 9
|
||||
b := 7
|
||||
for i := 1; i < 23; i++ {
|
||||
res = append(res, (a*res[i-1]+b)%m)
|
||||
s += strconv.Itoa(res[i])
|
||||
}
|
||||
return []byte(s)
|
||||
}
|
||||
|
||||
func decode(cryted []byte, key []byte) []byte {
|
||||
block, _ := aes.NewCipher(key[:32])
|
||||
blockSize := block.BlockSize()
|
||||
blockMode := cipher.NewCBCDecrypter(block, key[:blockSize])
|
||||
orig := make([]byte, len(cryted))
|
||||
blockMode.CryptBlocks(orig, cryted)
|
||||
orig = pKCS7UnPadding(orig)
|
||||
return orig
|
||||
}
|
||||
|
||||
func pKCS7UnPadding(origData []byte) []byte {
|
||||
length := len(origData)
|
||||
unpadding := int(origData[length-1])
|
||||
return origData[:(length - unpadding)]
|
||||
}
|
3
bootstrap/constant/constant.go
Normal file
3
bootstrap/constant/constant.go
Normal file
|
@ -0,0 +1,3 @@
|
|||
package constant
|
||||
|
||||
var HashIDTable = []int{}
|
|
@ -15,6 +15,7 @@ import (
|
|||
|
||||
// Init 初始化启动
|
||||
func Init(path string) {
|
||||
InitApplication()
|
||||
conf.Init(path)
|
||||
// Debug 关闭时,切换为生产模式
|
||||
if !conf.SystemConfig.Debug {
|
||||
|
|
|
@ -164,7 +164,7 @@ Neue',Helvetica,Arial,sans-serif; box-sizing: border-box; font-size: 14px; verti
|
|||
{Name: "cron_garbage_collect", Value: "@hourly", Type: "cron"},
|
||||
{Name: "cron_notify_user", Value: "@hourly", Type: "cron"},
|
||||
{Name: "cron_ban_user", Value: "@hourly", Type: "cron"},
|
||||
{Name: "authn_enabled", Value: "1", Type: "authn"},
|
||||
{Name: "authn_enabled", Value: "0", Type: "authn"},
|
||||
{Name: "captcha_height", Value: "60", Type: "captcha"},
|
||||
{Name: "captcha_width", Value: "240", Type: "captcha"},
|
||||
{Name: "captcha_mode", Value: "3", Type: "captcha"},
|
||||
|
|
|
@ -2,6 +2,7 @@ package hashid
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"github.com/HFO4/cloudreve/bootstrap/constant"
|
||||
"github.com/HFO4/cloudreve/pkg/conf"
|
||||
)
|
||||
import "github.com/speps/go-hashids"
|
||||
|
@ -61,7 +62,7 @@ func HashID(id uint, t int) string {
|
|||
// DecodeHashID 计算HashID对应的数据库ID
|
||||
func DecodeHashID(id string, t int) (uint, error) {
|
||||
v, _ := HashDecode(id)
|
||||
if len(v) != 2 || v[1] != t {
|
||||
if len(v) != 2 || v[1] != constant.HashIDTable[t] {
|
||||
return 0, ErrTypeNotMatch
|
||||
}
|
||||
return uint(v[0]), nil
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
package controllers
|
||||
|
||||
import (
|
||||
"github.com/HFO4/cloudreve/pkg/request"
|
||||
"github.com/HFO4/cloudreve/service/admin"
|
||||
"github.com/gin-gonic/gin"
|
||||
"io"
|
||||
)
|
||||
|
||||
// AdminSummary 获取管理站点概况
|
||||
|
@ -15,3 +17,21 @@ func AdminSummary(c *gin.Context) {
|
|||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
||||
// AdminNews 获取社区新闻
|
||||
func AdminNews(c *gin.Context) {
|
||||
r := request.HTTPClient{}
|
||||
res := r.Request("GET", "https://forum.cloudreve.org/api/discussions?include=startUser%2ClastUser%2CstartPost%2Ctags&filter%5Bq%5D=%20tag%3Anotice&sort=-startTime&", nil)
|
||||
io.Copy(c.Writer, res.Response.Body)
|
||||
}
|
||||
|
||||
// AdminChangeSetting 获取站点设定项
|
||||
func AdminChangeSetting(c *gin.Context) {
|
||||
var service admin.BatchSettingChangeService
|
||||
if err := c.ShouldBindJSON(&service); err == nil {
|
||||
res := service.Change()
|
||||
c.JSON(200, res)
|
||||
} else {
|
||||
c.JSON(200, ErrorResponse(err))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package routers
|
||||
|
||||
import (
|
||||
"github.com/HFO4/cloudreve/bootstrap"
|
||||
"github.com/HFO4/cloudreve/middleware"
|
||||
"github.com/HFO4/cloudreve/pkg/conf"
|
||||
"github.com/HFO4/cloudreve/pkg/hashid"
|
||||
|
@ -70,7 +71,9 @@ func InitCORS(router *gin.Engine) {
|
|||
// InitMasterRouter 初始化主机模式路由
|
||||
func InitMasterRouter() *gin.Engine {
|
||||
r := gin.Default()
|
||||
bootstrap.InitCustomRoute(r.Group("/custom"))
|
||||
v3 := r.Group("/api/v3")
|
||||
|
||||
/*
|
||||
中间件
|
||||
*/
|
||||
|
@ -282,6 +285,10 @@ func InitMasterRouter() *gin.Engine {
|
|||
{
|
||||
// 获取站点概况
|
||||
admin.GET("summary", controllers.AdminSummary)
|
||||
// 获取社区新闻
|
||||
admin.GET("news", controllers.AdminNews)
|
||||
// 更改设置
|
||||
admin.PATCH("setting", controllers.AdminChangeSetting)
|
||||
}
|
||||
|
||||
// 用户
|
||||
|
|
|
@ -2,6 +2,7 @@ package admin
|
|||
|
||||
import (
|
||||
model "github.com/HFO4/cloudreve/models"
|
||||
"github.com/HFO4/cloudreve/pkg/cache"
|
||||
"github.com/HFO4/cloudreve/pkg/conf"
|
||||
"github.com/HFO4/cloudreve/pkg/serializer"
|
||||
"time"
|
||||
|
@ -11,6 +12,29 @@ import (
|
|||
type NoParamService struct {
|
||||
}
|
||||
|
||||
// BatchSettingChangeService 设定批量更改服务
|
||||
type BatchSettingChangeService struct {
|
||||
Options []SettingChangeService `json:"options"`
|
||||
}
|
||||
|
||||
// SettingChangeService 设定更改服务
|
||||
type SettingChangeService struct {
|
||||
Key string `json:"key" binding:"required"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
// Change 批量更改站点设定
|
||||
func (service *BatchSettingChangeService) Change() serializer.Response {
|
||||
for _, setting := range service.Options {
|
||||
if err := model.DB.Model(&model.Setting{}).Where("name = ?", setting.Key).Update("value", setting.Value).Error; err != nil {
|
||||
return serializer.DBErr("设置 "+setting.Key+" 更新失败", err)
|
||||
}
|
||||
cache.Deletes([]string{setting.Key}, "setting_")
|
||||
}
|
||||
|
||||
return serializer.Response{}
|
||||
}
|
||||
|
||||
// Summary 获取站点统计概况
|
||||
func (service *NoParamService) Summary() serializer.Response {
|
||||
// 统计每日概况
|
||||
|
|
Loading…
Add table
Reference in a new issue