Cloudreve/models/user.go

269 lines
6.5 KiB
Go
Raw Normal View History

2019-11-07 02:56:05 -05:00
package model
import (
"crypto/sha1"
"encoding/hex"
"encoding/json"
2019-11-16 03:11:37 -05:00
"github.com/HFO4/cloudreve/pkg/util"
2019-11-07 02:56:05 -05:00
"github.com/jinzhu/gorm"
"github.com/pkg/errors"
"strings"
"time"
)
const (
// Active 账户正常状态
Active = iota
// NotActivicated 未激活
NotActivicated
// Baned 被封禁
Baned
)
// User 用户模型
type User struct {
2019-11-13 03:28:14 -05:00
// 表字段
2019-11-07 02:56:05 -05:00
gorm.Model
2019-11-13 03:28:14 -05:00
Email string `gorm:"type:varchar(100);unique_index"`
Nick string `gorm:"size:50"`
Password string `json:"-"`
Status int
GroupID uint
PrimaryGroup int
ActivationKey string `json:"-"`
Storage uint64
LastNotify *time.Time
OpenID string `json:"-"`
TwoFactor string `json:"-"`
Delay int
Avatar string
2020-02-02 01:40:07 -05:00
Options string `json:"-",gorm:"type:text"`
Authn string `gorm:"type:text"`
Score int
2019-11-13 03:28:14 -05:00
// 关联模型
2019-11-18 06:09:56 -05:00
Group Group `gorm:"association_autoupdate:false"`
2019-11-14 01:18:10 -05:00
Policy Policy `gorm:"PRELOAD:false,association_autoupdate:false"`
2019-11-13 03:28:14 -05:00
// 数据库忽略字段
2019-11-12 02:34:54 -05:00
OptionsSerialized UserOption `gorm:"-"`
}
// UserOption 用户个性化配置字段
type UserOption struct {
2019-11-14 01:18:10 -05:00
ProfileOn int `json:"profile_on"`
PreferredPolicy uint `json:"preferred_policy"`
WebDAVKey string `json:"webdav_key"`
PreferredTheme string `json:"preferred_theme"`
2019-11-14 01:18:10 -05:00
}
// Root 获取用户的根目录
func (user *User) Root() (*Folder, error) {
var folder Folder
2020-01-29 00:45:27 -05:00
err := DB.Where("parent_id is NULL AND owner_id = ?", user.ID).First(&folder).Error
return &folder, err
}
// DeductionStorage 减少用户已用容量
func (user *User) DeductionStorage(size uint64) bool {
2019-12-01 01:31:29 -05:00
if size == 0 {
return true
}
if size <= user.Storage {
user.Storage -= size
2019-11-18 06:09:56 -05:00
DB.Model(user).UpdateColumn("storage", gorm.Expr("storage - ?", size))
return true
}
// 如果要减少的容量超出已用容量,则设为零
2019-12-01 01:31:29 -05:00
user.Storage = 0
DB.Model(user).UpdateColumn("storage", 0)
return false
}
// IncreaseStorage 检查并增加用户已用容量
func (user *User) IncreaseStorage(size uint64) bool {
2019-12-01 01:31:29 -05:00
if size == 0 {
return true
}
2019-11-16 03:05:10 -05:00
if size <= user.GetRemainingCapacity() {
user.Storage += size
2019-11-18 06:09:56 -05:00
DB.Model(user).UpdateColumn("storage", gorm.Expr("storage + ?", size))
2019-11-16 03:05:10 -05:00
return true
}
return false
}
// PayScore 扣除积分,返回是否成功
func (user *User) PayScore(score int) bool {
if score == 0 {
return true
}
if score <= user.Score {
user.Score -= score
DB.Model(user).UpdateColumn("score", gorm.Expr("score - ?", score))
return true
}
return false
}
// AddScore 增加积分
func (user *User) AddScore(score int) {
user.Score += score
DB.Model(user).UpdateColumn("score", gorm.Expr("score + ?", score))
}
2019-12-03 03:32:23 -05:00
// IncreaseStorageWithoutCheck 忽略可用容量,增加用户已用容量
func (user *User) IncreaseStorageWithoutCheck(size uint64) {
if size == 0 {
return
}
user.Storage += size
DB.Model(user).UpdateColumn("storage", gorm.Expr("storage + ?", size))
}
2019-11-16 03:05:10 -05:00
// GetRemainingCapacity 获取剩余配额
func (user *User) GetRemainingCapacity() uint64 {
2020-01-13 21:32:54 -05:00
total := user.Group.MaxStorage + user.GetAvailablePackSize()
if total <= user.Storage {
2019-11-16 03:05:10 -05:00
return 0
}
2020-01-13 21:32:54 -05:00
return total - user.Storage
2019-11-16 03:05:10 -05:00
}
2019-11-30 02:09:56 -05:00
// GetPolicyID 获取用户当前的存储策略ID
2019-11-14 01:18:10 -05:00
func (user *User) GetPolicyID() uint {
// 用户未指定时,返回可用的第一个
if user.OptionsSerialized.PreferredPolicy == 0 {
if len(user.Group.PolicyList) != 0 {
return user.Group.PolicyList[0]
}
return 1
}
// 用户指定时,先检查是否为可用策略列表中的值
if util.ContainsUint(user.Group.PolicyList, user.OptionsSerialized.PreferredPolicy) {
return user.OptionsSerialized.PreferredPolicy
}
// 不可用时,返回第一个
if len(user.Group.PolicyList) != 0 {
return user.Group.PolicyList[0]
}
return 1
2019-11-07 02:56:05 -05:00
}
2019-11-11 06:13:17 -05:00
// GetUserByID 用ID获取用户
func GetUserByID(ID interface{}) (User, error) {
2019-11-07 02:56:05 -05:00
var user User
2019-11-13 03:28:14 -05:00
result := DB.Set("gorm:auto_preload", true).First(&user, ID)
2019-11-07 02:56:05 -05:00
return user, result.Error
}
2019-11-11 06:13:17 -05:00
// GetUserByEmail 用Email获取用户
func GetUserByEmail(email string) (User, error) {
var user User
2019-11-13 03:28:14 -05:00
result := DB.Set("gorm:auto_preload", true).Where("email = ?", email).First(&user)
2019-11-11 06:13:17 -05:00
return user, result.Error
}
2019-11-07 02:56:05 -05:00
// NewUser 返回一个新的空 User
func NewUser() User {
2019-11-12 02:34:54 -05:00
options := UserOption{
2019-11-07 02:56:05 -05:00
ProfileOn: 1,
}
return User{
2019-11-14 01:18:10 -05:00
Avatar: "default",
OptionsSerialized: options,
2019-11-07 02:56:05 -05:00
}
}
2019-11-14 01:18:10 -05:00
// BeforeSave Save用户前的钩子
func (user *User) BeforeSave() (err error) {
err = user.SerializeOptions()
return err
}
2019-11-15 03:32:43 -05:00
// AfterCreate 创建用户后的钩子
func (user *User) AfterCreate(tx *gorm.DB) (err error) {
// 创建用户的默认根目录
defaultFolder := &Folder{
Name: "/",
OwnerID: user.ID,
2019-11-15 03:32:43 -05:00
}
tx.Create(defaultFolder)
return err
}
2019-11-11 06:13:17 -05:00
// AfterFind 找到用户后的钩子
func (user *User) AfterFind() (err error) {
// 解析用户设置到OptionsSerialized
2019-12-30 06:56:01 -05:00
if user.Options != "" {
err = json.Unmarshal([]byte(user.Options), &user.OptionsSerialized)
}
2019-11-14 01:18:10 -05:00
// 预加载存储策略
user.Policy, _ = GetPolicyByID(user.GetPolicyID())
2019-11-11 06:13:17 -05:00
return err
}
//SerializeOptions 将序列后的Option写入到数据库字段
func (user *User) SerializeOptions() (err error) {
optionsValue, err := json.Marshal(&user.OptionsSerialized)
user.Options = string(optionsValue)
return err
}
2019-11-07 02:56:05 -05:00
// CheckPassword 根据明文校验密码
func (user *User) CheckPassword(password string) (bool, error) {
// 根据存储密码拆分为 Salt 和 Digest
passwordStore := strings.Split(user.Password, ":")
if len(passwordStore) != 2 {
return false, errors.New("Unknown password type")
}
// todo 兼容V2/V1密码
//计算 Salt 和密码组合的SHA1摘要
hash := sha1.New()
_, err := hash.Write([]byte(password + passwordStore[0]))
bs := hex.EncodeToString(hash.Sum(nil))
if err != nil {
return false, err
}
return bs == passwordStore[1], nil
}
// SetPassword 根据给定明文设定 User 的 Password 字段
func (user *User) SetPassword(password string) error {
//生成16位 Salt
salt := util.RandStringRunes(16)
//计算 Salt 和密码组合的SHA1摘要
hash := sha1.New()
_, err := hash.Write([]byte(password + salt))
bs := hex.EncodeToString(hash.Sum(nil))
if err != nil {
return err
}
//存储 Salt 值和摘要, ":"分割
user.Password = salt + ":" + string(bs)
return nil
}
2020-01-26 01:57:07 -05:00
// NewAnonymousUser 返回一个匿名用户
func NewAnonymousUser() *User {
user := User{}
user.Policy.Type = "anonymous"
2020-01-26 01:57:07 -05:00
user.Group, _ = GetGroupByID(3)
return &user
}
// IsAnonymous 返回是否为未登录用户
func (user *User) IsAnonymous() bool {
return user.ID == 0
}