diff --git a/cmd/server.go b/cmd/server.go index 6af316df..a74c848f 100644 --- a/cmd/server.go +++ b/cmd/server.go @@ -36,6 +36,7 @@ import ( "github.com/saltbo/zpan/disk" "github.com/saltbo/zpan/model" "github.com/saltbo/zpan/rest" + "github.com/saltbo/zpan/service" ) // serverCmd represents the server command @@ -47,7 +48,7 @@ var serverCmd = &cobra.Command{ gormutil.Init(conf.Database, &model.Matter{}, &model.Share{}, - &model.Storage{}, + &model.User{}, ) if conf.Debug { gormutil.Debug() @@ -67,8 +68,10 @@ var serverCmd = &cobra.Command{ simpleRouter.StaticFsIndex("/", ginutil.EmbedFS()) ge.NoRoute(simpleRouter.Handler) + ge.Use(rest.UserInjector()) + service.UserStorageInit(conf.Storage) ginutil.SetupResource(ge.Group("/api"), - rest.NewStorageResource(conf.Storage), + rest.NewUserResource(), rest.NewFileResource(diskProvider), rest.NewFolderResource(), rest.NewShareResource(), diff --git a/go.mod b/go.mod index 027511de..9a783258 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,6 @@ module github.com/saltbo/zpan go 1.14 require ( - github.com/aliyun/aliyun-oss-go-sdk v2.1.4+incompatible github.com/aws/aws-sdk-go v1.34.11 github.com/baiyubin/aliyun-sts-go-sdk v0.0.0-20180326062324-cfa1a18b161f // indirect github.com/gin-gonic/gin v1.6.3 @@ -17,8 +16,7 @@ require ( github.com/mitchellh/go-homedir v1.1.0 github.com/rakyll/statik v0.1.7 github.com/saltbo/gopkg v0.0.0-20200827161817-a4f845cbc9b2 - github.com/saltbo/moreu v0.0.0-20200826175621-181c5c7f57d7 - github.com/satori/go.uuid v1.2.0 + github.com/saltbo/moreu v0.0.0-20200831124119-22b4b6ac176b github.com/spf13/cobra v1.0.0 github.com/spf13/viper v1.7.1 github.com/urfave/cli/v2 v2.2.0 // indirect diff --git a/go.sum b/go.sum index fe4582d0..9606718d 100644 --- a/go.sum +++ b/go.sum @@ -299,6 +299,8 @@ github.com/saltbo/moreu v0.0.0-20200818144911-48e1687bed0a h1:Y2G5JKJVw1q+nAikG4 github.com/saltbo/moreu v0.0.0-20200818144911-48e1687bed0a/go.mod h1:VAjrZN3I7yG6rUXE47+gOAQT3ZkR4HhwtUWYRXY0Qi8= github.com/saltbo/moreu v0.0.0-20200826175621-181c5c7f57d7 h1:njZfLenyKjmqNMv20PSyjR6EpqqGs+TwaiMwX3mojv8= github.com/saltbo/moreu v0.0.0-20200826175621-181c5c7f57d7/go.mod h1:laP12N2qpWvvmLdmDdACULcnZW6E0dKWlK4qWC1QmOA= +github.com/saltbo/moreu v0.0.0-20200831124119-22b4b6ac176b h1:x6qlxq6IWsbBlwZQdfTjqlqDbQqZsgnjDhE+z3Ol9XY= +github.com/saltbo/moreu v0.0.0-20200831124119-22b4b6ac176b/go.mod h1:laP12N2qpWvvmLdmDdACULcnZW6E0dKWlK4qWC1QmOA= github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= diff --git a/model/storage.go b/model/storage.go deleted file mode 100644 index 030d2109..00000000 --- a/model/storage.go +++ /dev/null @@ -1,19 +0,0 @@ -package model - -import ( - "time" -) - -type Storage struct { - Id int64 `json:"id"` - UserId int64 `json:"user_id" gorm:"not null"` - Max uint64 `json:"max" gorm:"not null"` - Used uint64 `json:"used" gorm:"not null"` - Created time.Time `json:"created" gorm:"column:created_at;not null"` - Updated time.Time `json:"updated" gorm:"column:updated_at;not null"` - Deleted *time.Time `json:"-" gorm:"column:deleted_at"` -} - -func (Storage) TableName() string { - return "storage" -} diff --git a/model/user.go b/model/user.go new file mode 100644 index 00000000..1862cd1b --- /dev/null +++ b/model/user.go @@ -0,0 +1,27 @@ +package model + +import ( + "time" +) + +type User struct { + Id int64 `json:"id"` + Ux string `json:"ux" gorm:"not null"` + StorageUsed uint64 `json:"storage_used" gorm:"not null"` + StorageMax uint64 `json:"storage_max" gorm:"not null"` + Created time.Time `json:"created" gorm:"column:created_at;not null"` + Updated time.Time `json:"updated" gorm:"column:updated_at;not null"` + Deleted *time.Time `json:"-" gorm:"column:deleted_at"` +} + +func (User) TableName() string { + return "user" +} + +func (u *User) StorageOverflowed(addonSize int64) bool { + if u.StorageUsed+uint64(addonSize) >= u.StorageMax { + return true + } + + return false +} diff --git a/rest/bind/file.go b/rest/bind/file.go index 40a36eb3..1c651ad7 100644 --- a/rest/bind/file.go +++ b/rest/bind/file.go @@ -27,6 +27,7 @@ func (p *BodyFile) ToMatter(uid int64) *model.Matter { } m := model.NewMatter() + m.Uid = uid m.Name = p.Name m.Type = p.Type m.Size = p.Size diff --git a/rest/file.go b/rest/file.go index 3086b1ae..9613c869 100644 --- a/rest/file.go +++ b/rest/file.go @@ -8,17 +8,13 @@ import ( "github.com/gin-gonic/gin" "github.com/jinzhu/gorm" + "github.com/saltbo/gopkg/ginutil" "github.com/saltbo/gopkg/gormutil" "github.com/saltbo/gopkg/timeutil" - moreu "github.com/saltbo/moreu/client" - - "github.com/saltbo/gopkg/ginutil" "github.com/saltbo/zpan/disk" - "github.com/saltbo/zpan/service" - - "github.com/saltbo/zpan/model" "github.com/saltbo/zpan/rest/bind" + "github.com/saltbo/zpan/service" ) type FileResource struct { @@ -49,7 +45,7 @@ func (rs *FileResource) findAll(c *gin.Context) { return } - sm := service.NewMatter(moreu.GetUserId(c)) + sm := service.NewMatter(userIdGet(c)) if !p.Search { sm.SetDir(p.Dir) } else if p.Type != "" { @@ -71,19 +67,19 @@ func (rs *FileResource) create(c *gin.Context) { return } - uid := moreu.GetUserId(c) - if err := service.StorageQuotaVerify(uid, p.Size); err != nil { - ginutil.JSONBadRequest(c, err) + user := userGet(c) + if user.StorageOverflowed(p.Size) { + ginutil.JSONBadRequest(c, fmt.Errorf("service not enough space")) return } - if !service.MatterParentExist(uid, p.Dir) { + if !service.MatterParentExist(user.Id, p.Dir) { ginutil.JSONBadRequest(c, fmt.Errorf("parent dir not exist")) return } // auto append a suffix if matter exist - if service.MatterExist(uid, p.Name, p.Dir) { + if service.MatterExist(user.Id, p.Name, p.Dir) { ext := filepath.Ext(p.Name) name := strings.TrimSuffix(p.Name, ext) suffix := fmt.Sprintf("_%s", timeutil.Format(time.Now(), "YYYYMMDD_HHmmss")) @@ -94,7 +90,7 @@ func (rs *FileResource) create(c *gin.Context) { //if p.Dir == ".pics/" { // publicRead = true //} - matter := p.ToMatter(uid) + matter := p.ToMatter(user.Id) link, headers, err := rs.provider.PutPreSign(matter.Object, p.Type) if err != nil { ginutil.JSONServerError(c, err) @@ -107,12 +103,8 @@ func (rs *FileResource) create(c *gin.Context) { } // update the service - storage := new(model.Storage) - if gormutil.DB().First(storage, "user_id=?", uid).RecordNotFound() { - return fmt.Errorf("storage not exist") - } - - if err := tx.Model(storage).Update("used", gorm.Expr("used+?", p.Size)).Error; err != nil { + expr := gorm.Expr("storage_used+?", p.Size) + if err := tx.Model(user).Update("storage_used", expr).Error; err != nil { return err } @@ -150,7 +142,7 @@ func (rs *FileResource) find(c *gin.Context) { } func (rs *FileResource) uploaded(c *gin.Context) { - file, err := service.UserFileGet(moreu.GetUserId(c), c.Param("alias")) + file, err := service.UserFileGet(userIdGet(c), c.Param("alias")) if err != nil { ginutil.JSONBadRequest(c, err) return @@ -171,7 +163,7 @@ func (rs *FileResource) rename(c *gin.Context) { return } - file, err := service.UserFileGet(moreu.GetUserId(c), c.Param("alias")) + file, err := service.UserFileGet(userIdGet(c), c.Param("alias")) if err != nil { ginutil.JSONBadRequest(c, err) return @@ -197,7 +189,7 @@ func (rs *FileResource) move(c *gin.Context) { return } - file, err := service.UserFileGet(moreu.GetUserId(c), c.Param("alias")) + file, err := service.UserFileGet(userIdGet(c), c.Param("alias")) if err != nil { ginutil.JSONBadRequest(c, err) return @@ -218,7 +210,7 @@ func (rs *FileResource) copy(c *gin.Context) { return } - file, err := service.UserFileGet(moreu.GetUserId(c), c.Param("alias")) + file, err := service.UserFileGet(userIdGet(c), c.Param("alias")) if err != nil { ginutil.JSONBadRequest(c, err) return @@ -233,8 +225,8 @@ func (rs *FileResource) copy(c *gin.Context) { } func (rs *FileResource) delete(c *gin.Context) { - uid := moreu.GetUserId(c) - file, err := service.UserFileGet(uid, c.Param("alias")) + user := userGet(c) + file, err := service.UserFileGet(user.Id, c.Param("alias")) if err != nil { ginutil.JSONBadRequest(c, err) return @@ -252,12 +244,8 @@ func (rs *FileResource) delete(c *gin.Context) { } // update the user storage - storage := new(model.Storage) - if gormutil.DB().First(storage, "user_id=?", uid).RecordNotFound() { - return fmt.Errorf("BUG: storage not exist") - } - - if err := tx.Model(storage).Update("used", gorm.Expr("used-?", file.Size)).Error; err != nil { + expr := gorm.Expr("storage_used-?", file.Size) + if err := tx.Model(user).Update("storage_used", expr).Error; err != nil { return err } diff --git a/rest/folders.go b/rest/folders.go index b4ffc856..b021b65d 100644 --- a/rest/folders.go +++ b/rest/folders.go @@ -6,7 +6,6 @@ import ( "github.com/gin-gonic/gin" "github.com/saltbo/gopkg/ginutil" "github.com/saltbo/gopkg/gormutil" - moreu "github.com/saltbo/moreu/client" "github.com/saltbo/zpan/model" "github.com/saltbo/zpan/rest/bind" @@ -36,7 +35,7 @@ func (rs *FolderResource) findAll(c *gin.Context) { var total int64 list := make([]model.Matter, 0) query := "uid=? and dirtype=? and parent=?" - sn := gormutil.DB().Where(query, moreu.GetUserId(c), model.DirTypeUser, p.Parent) + sn := gormutil.DB().Where(query, userIdGet(c), model.DirTypeUser, p.Parent) sn.Model(model.Matter{}).Count(&total) if err := sn.Limit(p.Limit).Offset(p.Offset).Find(&list).Error; err != nil { ginutil.JSONServerError(c, err) @@ -53,7 +52,7 @@ func (rs *FolderResource) create(c *gin.Context) { return } - uid := moreu.GetUserId(c) + uid := userIdGet(c) if !service.MatterParentExist(uid, p.Dir) { ginutil.JSONBadRequest(c, fmt.Errorf("parent dir not exist")) return @@ -80,7 +79,7 @@ func (rs *FolderResource) rename(c *gin.Context) { return } - file, err := service.UserFileGet(moreu.GetUserId(c), c.Param("alias")) + file, err := service.UserFileGet(userIdGet(c), c.Param("alias")) if err != nil { ginutil.JSONBadRequest(c, err) return diff --git a/rest/share.go b/rest/share.go index 5f36dc58..062cc679 100644 --- a/rest/share.go +++ b/rest/share.go @@ -8,7 +8,6 @@ import ( "github.com/saltbo/gopkg/ginutil" "github.com/saltbo/gopkg/gormutil" "github.com/saltbo/gopkg/strutil" - moreu "github.com/saltbo/moreu/client" "github.com/saltbo/zpan/model" "github.com/saltbo/zpan/rest/bind" @@ -88,7 +87,7 @@ func (rs *ShareResource) findAll(c *gin.Context) { var total int64 list := make([]model.Share, 0) - sn := gormutil.DB().Where("uid=?", moreu.GetUserId(c)) + sn := gormutil.DB().Where("uid=?", userIdGet(c)) sn.Model(model.Share{}).Count(&total) if err := sn.Limit(p.Limit).Offset(p.Offset).Find(&list).Error; err != nil { ginutil.JSONBadRequest(c, err) @@ -113,7 +112,7 @@ func (rs *ShareResource) create(c *gin.Context) { m := &model.Share{ Alias: strutil.RandomText(12), - Uid: moreu.GetUserId(c), + Uid: userIdGet(c), Name: matter.Name, Matter: matter.Alias, ExpireAt: time.Now().Add(time.Second * time.Duration(p.ExpireSec)), diff --git a/rest/storage.go b/rest/storage.go deleted file mode 100644 index 3e4cf7b0..00000000 --- a/rest/storage.go +++ /dev/null @@ -1,43 +0,0 @@ -package rest - -import ( - "github.com/gin-gonic/gin" - "github.com/saltbo/gopkg/ginutil" - "github.com/saltbo/gopkg/gormutil" - moreu "github.com/saltbo/moreu/client" - - "github.com/saltbo/zpan/model" -) - -const defaultSize = 50 << 20 - -type StorageResource struct { - defaultSize uint64 -} - -func NewStorageResource(initSize uint64) *StorageResource { - if initSize == 0 { - initSize = defaultSize - } - - return &StorageResource{ - defaultSize: initSize, - } -} - -func (rs *StorageResource) Register(router *gin.RouterGroup) { - router.GET("/storage", rs.find) -} - -func (rs *StorageResource) find(c *gin.Context) { - storage := &model.Storage{ - UserId: moreu.GetUserId(c), - Max: rs.defaultSize, - } - if err := gormutil.DB().FirstOrCreate(storage, "user_id=?", storage.UserId).Error; err != nil { - ginutil.JSONServerError(c, err) - return - } - - ginutil.JSONData(c, storage) -} diff --git a/rest/user.go b/rest/user.go new file mode 100644 index 00000000..b80403b3 --- /dev/null +++ b/rest/user.go @@ -0,0 +1,57 @@ +package rest + +import ( + "net/http" + + "github.com/gin-gonic/gin" + "github.com/saltbo/gopkg/ginutil" + moreu "github.com/saltbo/moreu/client" + + "github.com/saltbo/zpan/model" + "github.com/saltbo/zpan/service" +) + +type UserResource struct { +} + +func NewUserResource() *UserResource { + return &UserResource{} +} + +func (rs *UserResource) Register(router *gin.RouterGroup) { + router.GET("/users/me", rs.me) +} + +func (rs *UserResource) me(c *gin.Context) { + user, err := service.UserFind(moreu.GetUx(c)) + if err != nil { + ginutil.JSONServerError(c, err) + return + } + + ginutil.JSONData(c, user) +} + +func UserInjector() gin.HandlerFunc { + return func(c *gin.Context) { + u, err := service.UserFind(moreu.GetUx(c)) + if err != nil { + c.AbortWithError(http.StatusInternalServerError, err) + return + } + + c.Set("user", u) + c.Set("uid", u.Id) + } +} + +func userGet(c *gin.Context) (u *model.User) { + if val, ok := c.Get("user"); ok && val != nil { + u, _ = val.(*model.User) + } + return +} + +func userIdGet(c *gin.Context) int64 { + return c.GetInt64("uid") +} diff --git a/service/storage.go b/service/storage.go deleted file mode 100644 index 79cbea84..00000000 --- a/service/storage.go +++ /dev/null @@ -1,20 +0,0 @@ -package service - -import ( - "fmt" - - "github.com/saltbo/gopkg/gormutil" - - "github.com/saltbo/zpan/model" -) - -func StorageQuotaVerify(uid, addonSize int64) error { - storage := new(model.Storage) - if err := gormutil.DB().First(storage, "user_id=?", uid).Error; err != nil { - return err - } else if storage.Used+uint64(addonSize) >= storage.Max { - return fmt.Errorf("service not enough space") - } - - return nil -} diff --git a/service/user.go b/service/user.go new file mode 100644 index 00000000..becc74d6 --- /dev/null +++ b/service/user.go @@ -0,0 +1,27 @@ +package service + +import ( + "github.com/saltbo/gopkg/gormutil" + + "github.com/saltbo/zpan/model" +) + +const defaultSize = 50 << 20 + +var iss uint64 = defaultSize + +func UserStorageInit(storage uint64) { + iss = storage +} + +func UserFind(ux string) (*model.User, error) { + user := &model.User{ + Ux: ux, + StorageMax: iss, + } + if err := gormutil.DB().FirstOrCreate(user, "ux=?", user.Ux).Error; err != nil { + return nil, err + } + + return user, nil +}