diff --git a/middleware/auth.go b/middleware/auth.go index 4226778..6c23500 100644 --- a/middleware/auth.go +++ b/middleware/auth.go @@ -310,3 +310,17 @@ func COSCallbackAuth() gin.HandlerFunc { c.Next() } } + +// IsAdmin 必须为管理员用户组 +func IsAdmin() gin.HandlerFunc { + return func(c *gin.Context) { + user, _ := c.Get("user") + if user.(*model.User).Group.ID != 1 { + c.JSON(200, serializer.Err(serializer.CodeAdminRequired, "您不是管理组成员", nil)) + c.Abort() + return + } + + c.Next() + } +} diff --git a/models/migration.go b/models/migration.go index 3314bef..9a620b8 100644 --- a/models/migration.go +++ b/models/migration.go @@ -200,6 +200,8 @@ func addDefaultGroups() { ArchiveDownload: true, ArchiveTask: true, ShareDownload: true, + ShareFree: true, + Aria2: true, }, } if err := DB.Create(&defaultAdminGroup).Error; err != nil { diff --git a/pkg/aria2/rpc/call_test.go b/pkg/aria2/rpc/call_test.go deleted file mode 100644 index 64d2520..0000000 --- a/pkg/aria2/rpc/call_test.go +++ /dev/null @@ -1,23 +0,0 @@ -package rpc - -import ( - "context" - "testing" - "time" -) - -func TestWebsocketCaller(t *testing.T) { - time.Sleep(time.Second) - c, err := newWebsocketCaller(context.Background(), "ws://localhost:6800/jsonrpc", time.Second, &DummyNotifier{}) - if err != nil { - t.Fatal(err.Error()) - } - defer c.Close() - - var info VersionInfo - if err := c.Call(aria2GetVersion, []interface{}{}, &info); err != nil { - t.Error(err.Error()) - } else { - println(info.Version) - } -} diff --git a/pkg/aria2/rpc/client_test.go b/pkg/aria2/rpc/client_test.go deleted file mode 100644 index abf68f4..0000000 --- a/pkg/aria2/rpc/client_test.go +++ /dev/null @@ -1,125 +0,0 @@ -package rpc - -import ( - "context" - "testing" - "time" -) - -func TestHTTPAll(t *testing.T) { - const targetURL = "https://nodejs.org/dist/index.json" - rpc, err := New(context.Background(), "http://localhost:6800/jsonrpc", "", time.Second, &DummyNotifier{}) - if err != nil { - t.Fatal(err) - } - defer rpc.Close() - g, err := rpc.AddURI(targetURL) - if err != nil { - t.Fatal(err) - } - println(g) - if _, err = rpc.TellActive(); err != nil { - t.Error(err) - } - if _, err = rpc.PauseAll(); err != nil { - t.Error(err) - } - if _, err = rpc.TellStatus(g); err != nil { - t.Error(err) - } - if _, err = rpc.GetURIs(g); err != nil { - t.Error(err) - } - if _, err = rpc.GetFiles(g); err != nil { - t.Error(err) - } - if _, err = rpc.GetPeers(g); err != nil { - t.Error(err) - } - if _, err = rpc.TellActive(); err != nil { - t.Error(err) - } - if _, err = rpc.TellWaiting(0, 1); err != nil { - t.Error(err) - } - if _, err = rpc.TellStopped(0, 1); err != nil { - t.Error(err) - } - if _, err = rpc.GetOption(g); err != nil { - t.Error(err) - } - if _, err = rpc.GetGlobalOption(); err != nil { - t.Error(err) - } - if _, err = rpc.GetGlobalStat(); err != nil { - t.Error(err) - } - if _, err = rpc.GetSessionInfo(); err != nil { - t.Error(err) - } - if _, err = rpc.Remove(g); err != nil { - t.Error(err) - } - if _, err = rpc.TellActive(); err != nil { - t.Error(err) - } -} - -func TestWebsocketAll(t *testing.T) { - const targetURL = "https://nodejs.org/dist/index.json" - rpc, err := New(context.Background(), "ws://localhost:6800/jsonrpc", "", time.Second, &DummyNotifier{}) - if err != nil { - t.Fatal(err) - } - defer rpc.Close() - g, err := rpc.AddURI(targetURL) - if err != nil { - t.Fatal(err) - } - println(g) - if _, err = rpc.TellActive(); err != nil { - t.Error(err) - } - if _, err = rpc.PauseAll(); err != nil { - t.Error(err) - } - if _, err = rpc.TellStatus(g); err != nil { - t.Error(err) - } - if _, err = rpc.GetURIs(g); err != nil { - t.Error(err) - } - if _, err = rpc.GetFiles(g); err != nil { - t.Error(err) - } - if _, err = rpc.GetPeers(g); err != nil { - t.Error(err) - } - if _, err = rpc.TellActive(); err != nil { - t.Error(err) - } - if _, err = rpc.TellWaiting(0, 1); err != nil { - t.Error(err) - } - if _, err = rpc.TellStopped(0, 1); err != nil { - t.Error(err) - } - if _, err = rpc.GetOption(g); err != nil { - t.Error(err) - } - if _, err = rpc.GetGlobalOption(); err != nil { - t.Error(err) - } - if _, err = rpc.GetGlobalStat(); err != nil { - t.Error(err) - } - if _, err = rpc.GetSessionInfo(); err != nil { - t.Error(err) - } - if _, err = rpc.Remove(g); err != nil { - t.Error(err) - } - if _, err = rpc.TellActive(); err != nil { - t.Error(err) - } -} diff --git a/pkg/conf/version.go b/pkg/conf/version.go index e75bd3f..e457b9d 100644 --- a/pkg/conf/version.go +++ b/pkg/conf/version.go @@ -1,7 +1,13 @@ package conf // BackendVersion 当前后端版本号 -const BackendVersion = string("3.0.0-beta1") +var BackendVersion = "3.0.0-beta1" // RequiredDBVersion 与当前版本匹配的数据库版本 -const RequiredDBVersion = string("3.0.0-beta1") +var RequiredDBVersion = "3.0.0-beta1" + +// IsPro 是否为Pro版本 +var IsPro = "true" + +// LastCommit 最后commit id +var LastCommit = "" diff --git a/pkg/serializer/error.go b/pkg/serializer/error.go index 3af265e..6a2bae8 100644 --- a/pkg/serializer/error.go +++ b/pkg/serializer/error.go @@ -62,6 +62,8 @@ const ( CodePolicyNotAllowed = 40006 // CodeGroupNotAllowed 用户组无法进行此操作 CodeGroupNotAllowed = 40007 + // CodeAdminRequired 非管理用户组 + CodeAdminRequired = 40008 // CodeDBError 数据库操作失败 CodeDBError = 50001 // CodeEncryptError 加密失败 diff --git a/routers/controllers/admin.go b/routers/controllers/admin.go new file mode 100644 index 0000000..ec40057 --- /dev/null +++ b/routers/controllers/admin.go @@ -0,0 +1,17 @@ +package controllers + +import ( + "github.com/HFO4/cloudreve/service/admin" + "github.com/gin-gonic/gin" +) + +// AdminSummary 获取管理站点概况 +func AdminSummary(c *gin.Context) { + var service admin.NoParamService + if err := c.ShouldBindUri(&service); err == nil { + res := service.Summary() + c.JSON(200, res) + } else { + c.JSON(200, ErrorResponse(err)) + } +} diff --git a/routers/router.go b/routers/router.go index 55f9e45..5b13d00 100644 --- a/routers/router.go +++ b/routers/router.go @@ -277,6 +277,13 @@ func InitMasterRouter() *gin.Engine { auth := v3.Group("") auth.Use(middleware.AuthRequired()) { + // 管理 + admin := auth.Group("admin", middleware.IsAdmin()) + { + // 获取站点概况 + admin.GET("summary", controllers.AdminSummary) + } + // 用户 user := auth.Group("user") { diff --git a/service/admin/site.go b/service/admin/site.go new file mode 100644 index 0000000..6434245 --- /dev/null +++ b/service/admin/site.go @@ -0,0 +1,66 @@ +package admin + +import ( + model "github.com/HFO4/cloudreve/models" + "github.com/HFO4/cloudreve/pkg/conf" + "github.com/HFO4/cloudreve/pkg/serializer" + "time" +) + +// NoParamService 无需参数的服务 +type NoParamService struct { +} + +// Summary 获取站点统计概况 +func (service *NoParamService) Summary() serializer.Response { + // 统计每日概况 + total := 12 + files := make([]int, total) + users := make([]int, total) + shares := make([]int, total) + date := make([]string, total) + + toRound := time.Now() + timeBase := time.Date(toRound.Year(), toRound.Month(), toRound.Day()+1, 0, 0, 0, 0, toRound.Location()) + for day := range files { + start := timeBase.Add(-time.Duration(total-day) * time.Hour * 24) + end := timeBase.Add(-time.Duration(total-day-1) * time.Hour * 24) + date[day] = start.Format("1月2日") + model.DB.Model(&model.User{}).Where("created_at BETWEEN ? AND ?", start, end).Count(&users[day]) + model.DB.Model(&model.File{}).Where("created_at BETWEEN ? AND ?", start, end).Count(&files[day]) + model.DB.Model(&model.Share{}).Where("created_at BETWEEN ? AND ?", start, end).Count(&shares[day]) + } + + // 统计总数 + fileTotal := 0 + userTotal := 0 + publicShareTotal := 0 + secretShareTotal := 0 + model.DB.Model(&model.User{}).Count(&userTotal) + model.DB.Model(&model.File{}).Count(&fileTotal) + model.DB.Model(&model.Share{}).Where("password = ?", "").Count(&publicShareTotal) + model.DB.Model(&model.Share{}).Where("password <> ?", "").Count(&secretShareTotal) + + // 获取版本信息 + versions := map[string]string{ + "backend": conf.BackendVersion, + "db": conf.RequiredDBVersion, + "commit": conf.LastCommit, + "is_pro": conf.IsPro, + } + + return serializer.Response{ + Data: map[string]interface{}{ + "date": date, + "files": files, + "users": users, + "shares": shares, + "version": versions, + "siteURL": model.GetSettingByName("siteURL"), + "fileTotal": fileTotal, + "userTotal": userTotal, + "publicShareTotal": publicShareTotal, + "secretShareTotal": secretShareTotal, + }, + } +}