github.com/cloudreve/Cloudreve/v3@v3.0.0-20240224133659-3edb00a6484c/models/user.go (about)

     1  package model
     2  
     3  import (
     4  	"crypto/md5"
     5  	"crypto/sha1"
     6  	"encoding/gob"
     7  	"encoding/hex"
     8  	"encoding/json"
     9  	"strings"
    10  
    11  	"github.com/cloudreve/Cloudreve/v3/pkg/util"
    12  	"github.com/jinzhu/gorm"
    13  	"github.com/pkg/errors"
    14  )
    15  
    16  const (
    17  	// Active 账户正常状态
    18  	Active = iota
    19  	// NotActivicated 未激活
    20  	NotActivicated
    21  	// Baned 被封禁
    22  	Baned
    23  	// OveruseBaned 超额使用被封禁
    24  	OveruseBaned
    25  )
    26  
    27  // User 用户模型
    28  type User struct {
    29  	// 表字段
    30  	gorm.Model
    31  	Email     string `gorm:"type:varchar(100);unique_index"`
    32  	Nick      string `gorm:"size:50"`
    33  	Password  string `json:"-"`
    34  	Status    int
    35  	GroupID   uint
    36  	Storage   uint64
    37  	TwoFactor string
    38  	Avatar    string
    39  	Options   string `json:"-" gorm:"size:4294967295"`
    40  	Authn     string `gorm:"size:4294967295"`
    41  
    42  	// 关联模型
    43  	Group  Group  `gorm:"save_associations:false:false"`
    44  	Policy Policy `gorm:"PRELOAD:false,association_autoupdate:false"`
    45  
    46  	// 数据库忽略字段
    47  	OptionsSerialized UserOption `gorm:"-"`
    48  }
    49  
    50  func init() {
    51  	gob.Register(User{})
    52  }
    53  
    54  // UserOption 用户个性化配置字段
    55  type UserOption struct {
    56  	ProfileOff     bool   `json:"profile_off,omitempty"`
    57  	PreferredTheme string `json:"preferred_theme,omitempty"`
    58  }
    59  
    60  // Root 获取用户的根目录
    61  func (user *User) Root() (*Folder, error) {
    62  	var folder Folder
    63  	err := DB.Where("parent_id is NULL AND owner_id = ?", user.ID).First(&folder).Error
    64  	return &folder, err
    65  }
    66  
    67  // DeductionStorage 减少用户已用容量
    68  func (user *User) DeductionStorage(size uint64) bool {
    69  	if size == 0 {
    70  		return true
    71  	}
    72  	if size <= user.Storage {
    73  		user.Storage -= size
    74  		DB.Model(user).Update("storage", gorm.Expr("storage - ?", size))
    75  		return true
    76  	}
    77  	// 如果要减少的容量超出已用容量,则设为零
    78  	user.Storage = 0
    79  	DB.Model(user).Update("storage", 0)
    80  
    81  	return false
    82  }
    83  
    84  // IncreaseStorage 检查并增加用户已用容量
    85  func (user *User) IncreaseStorage(size uint64) bool {
    86  	if size == 0 {
    87  		return true
    88  	}
    89  	if size <= user.GetRemainingCapacity() {
    90  		user.Storage += size
    91  		DB.Model(user).Update("storage", gorm.Expr("storage + ?", size))
    92  		return true
    93  	}
    94  	return false
    95  }
    96  
    97  // ChangeStorage 更新用户容量
    98  func (user *User) ChangeStorage(tx *gorm.DB, operator string, size uint64) error {
    99  	return tx.Model(user).Update("storage", gorm.Expr("storage "+operator+" ?", size)).Error
   100  }
   101  
   102  // IncreaseStorageWithoutCheck 忽略可用容量,增加用户已用容量
   103  func (user *User) IncreaseStorageWithoutCheck(size uint64) {
   104  	if size == 0 {
   105  		return
   106  	}
   107  	user.Storage += size
   108  	DB.Model(user).Update("storage", gorm.Expr("storage + ?", size))
   109  
   110  }
   111  
   112  // GetRemainingCapacity 获取剩余配额
   113  func (user *User) GetRemainingCapacity() uint64 {
   114  	total := user.Group.MaxStorage
   115  	if total <= user.Storage {
   116  		return 0
   117  	}
   118  	return total - user.Storage
   119  }
   120  
   121  // GetPolicyID 获取用户当前的存储策略ID
   122  func (user *User) GetPolicyID(prefer uint) uint {
   123  	if len(user.Group.PolicyList) > 0 {
   124  		return user.Group.PolicyList[0]
   125  	}
   126  	return 0
   127  }
   128  
   129  // GetUserByID 用ID获取用户
   130  func GetUserByID(ID interface{}) (User, error) {
   131  	var user User
   132  	result := DB.Set("gorm:auto_preload", true).First(&user, ID)
   133  	return user, result.Error
   134  }
   135  
   136  // GetActiveUserByID 用ID获取可登录用户
   137  func GetActiveUserByID(ID interface{}) (User, error) {
   138  	var user User
   139  	result := DB.Set("gorm:auto_preload", true).Where("status = ?", Active).First(&user, ID)
   140  	return user, result.Error
   141  }
   142  
   143  // GetActiveUserByOpenID 用OpenID获取可登录用户
   144  func GetActiveUserByOpenID(openid string) (User, error) {
   145  	var user User
   146  	result := DB.Set("gorm:auto_preload", true).Where("status = ? and open_id = ?", Active, openid).Find(&user)
   147  	return user, result.Error
   148  }
   149  
   150  // GetUserByEmail 用Email获取用户
   151  func GetUserByEmail(email string) (User, error) {
   152  	var user User
   153  	result := DB.Set("gorm:auto_preload", true).Where("email = ?", email).First(&user)
   154  	return user, result.Error
   155  }
   156  
   157  // GetActiveUserByEmail 用Email获取可登录用户
   158  func GetActiveUserByEmail(email string) (User, error) {
   159  	var user User
   160  	result := DB.Set("gorm:auto_preload", true).Where("status = ? and email = ?", Active, email).First(&user)
   161  	return user, result.Error
   162  }
   163  
   164  // NewUser 返回一个新的空 User
   165  func NewUser() User {
   166  	options := UserOption{}
   167  	return User{
   168  		OptionsSerialized: options,
   169  	}
   170  }
   171  
   172  // BeforeSave Save用户前的钩子
   173  func (user *User) BeforeSave() (err error) {
   174  	err = user.SerializeOptions()
   175  	return err
   176  }
   177  
   178  // AfterCreate 创建用户后的钩子
   179  func (user *User) AfterCreate(tx *gorm.DB) (err error) {
   180  	// 创建用户的默认根目录
   181  	defaultFolder := &Folder{
   182  		Name:    "/",
   183  		OwnerID: user.ID,
   184  	}
   185  	tx.Create(defaultFolder)
   186  	return err
   187  }
   188  
   189  // AfterFind 找到用户后的钩子
   190  func (user *User) AfterFind() (err error) {
   191  	// 解析用户设置到OptionsSerialized
   192  	if user.Options != "" {
   193  		err = json.Unmarshal([]byte(user.Options), &user.OptionsSerialized)
   194  	}
   195  
   196  	// 预加载存储策略
   197  	user.Policy, _ = GetPolicyByID(user.GetPolicyID(0))
   198  	return err
   199  }
   200  
   201  //SerializeOptions 将序列后的Option写入到数据库字段
   202  func (user *User) SerializeOptions() (err error) {
   203  	optionsValue, err := json.Marshal(&user.OptionsSerialized)
   204  	user.Options = string(optionsValue)
   205  	return err
   206  }
   207  
   208  // CheckPassword 根据明文校验密码
   209  func (user *User) CheckPassword(password string) (bool, error) {
   210  
   211  	// 根据存储密码拆分为 Salt 和 Digest
   212  	passwordStore := strings.Split(user.Password, ":")
   213  	if len(passwordStore) != 2 && len(passwordStore) != 3 {
   214  		return false, errors.New("Unknown password type")
   215  	}
   216  
   217  	// 兼容V2密码,升级后存储格式为: md5:$HASH:$SALT
   218  	if len(passwordStore) == 3 {
   219  		if passwordStore[0] != "md5" {
   220  			return false, errors.New("Unknown password type")
   221  		}
   222  		hash := md5.New()
   223  		_, err := hash.Write([]byte(passwordStore[2] + password))
   224  		bs := hex.EncodeToString(hash.Sum(nil))
   225  		if err != nil {
   226  			return false, err
   227  		}
   228  		return bs == passwordStore[1], nil
   229  	}
   230  
   231  	//计算 Salt 和密码组合的SHA1摘要
   232  	hash := sha1.New()
   233  	_, err := hash.Write([]byte(password + passwordStore[0]))
   234  	bs := hex.EncodeToString(hash.Sum(nil))
   235  	if err != nil {
   236  		return false, err
   237  	}
   238  
   239  	return bs == passwordStore[1], nil
   240  }
   241  
   242  // SetPassword 根据给定明文设定 User 的 Password 字段
   243  func (user *User) SetPassword(password string) error {
   244  	//生成16位 Salt
   245  	salt := util.RandStringRunes(16)
   246  
   247  	//计算 Salt 和密码组合的SHA1摘要
   248  	hash := sha1.New()
   249  	_, err := hash.Write([]byte(password + salt))
   250  	bs := hex.EncodeToString(hash.Sum(nil))
   251  
   252  	if err != nil {
   253  		return err
   254  	}
   255  
   256  	//存储 Salt 值和摘要, ":"分割
   257  	user.Password = salt + ":" + string(bs)
   258  	return nil
   259  }
   260  
   261  // NewAnonymousUser 返回一个匿名用户
   262  func NewAnonymousUser() *User {
   263  	user := User{}
   264  	user.Policy.Type = "anonymous"
   265  	user.Group, _ = GetGroupByID(3)
   266  	return &user
   267  }
   268  
   269  // IsAnonymous 返回是否为未登录用户
   270  func (user *User) IsAnonymous() bool {
   271  	return user.ID == 0
   272  }
   273  
   274  // SetStatus 设定用户状态
   275  func (user *User) SetStatus(status int) {
   276  	DB.Model(&user).Update("status", status)
   277  }
   278  
   279  // Update 更新用户
   280  func (user *User) Update(val map[string]interface{}) error {
   281  	return DB.Model(user).Updates(val).Error
   282  }
   283  
   284  // UpdateOptions 更新用户偏好设定
   285  func (user *User) UpdateOptions() error {
   286  	if err := user.SerializeOptions(); err != nil {
   287  		return err
   288  	}
   289  	return user.Update(map[string]interface{}{"options": user.Options})
   290  }