user.go 6.7 KB
Newer Older
H
HFO4 已提交
1 2 3
package model

import (
H
HFO4 已提交
4
	"crypto/md5"
H
HFO4 已提交
5 6 7
	"crypto/sha1"
	"encoding/hex"
	"encoding/json"
H
HFO4 已提交
8
	"github.com/HFO4/cloudreve/pkg/util"
H
HFO4 已提交
9 10 11 12 13 14 15 16 17 18 19 20
	"github.com/jinzhu/gorm"
	"github.com/pkg/errors"
	"strings"
)

const (
	// Active 账户正常状态
	Active = iota
	// NotActivicated 未激活
	NotActivicated
	// Baned 被封禁
	Baned
H
HFO4 已提交
21 22
	// OveruseBaned 超额使用被封禁
	OveruseBaned
H
HFO4 已提交
23 24 25 26
)

// User 用户模型
type User struct {
H
HFO4 已提交
27
	// 表字段
H
HFO4 已提交
28
	gorm.Model
H
HFO4 已提交
29 30 31 32 33 34 35 36 37 38
	Email     string `gorm:"type:varchar(100);unique_index"`
	Nick      string `gorm:"size:50"`
	Password  string `json:"-"`
	Status    int
	GroupID   uint
	Storage   uint64
	TwoFactor string
	Avatar    string
	Options   string `json:"-",gorm:"type:text"`
	Authn     string `gorm:"type:text"`
H
HFO4 已提交
39 40

	// 关联模型
H
HFO4 已提交
41
	Group  Group  `gorm:"save_associations:false:false"`
H
HFO4 已提交
42
	Policy Policy `gorm:"PRELOAD:false,association_autoupdate:false"`
H
HFO4 已提交
43 44

	// 数据库忽略字段
H
HFO4 已提交
45 46 47 48 49
	OptionsSerialized UserOption `gorm:"-"`
}

// UserOption 用户个性化配置字段
type UserOption struct {
H
HFO4 已提交
50 51
	ProfileOff     bool   `json:"profile_off,omitempty"`
	PreferredTheme string `json:"preferred_theme,omitempty"`
H
HFO4 已提交
52 53
}

54 55 56
// Root 获取用户的根目录
func (user *User) Root() (*Folder, error) {
	var folder Folder
H
HFO4 已提交
57
	err := DB.Where("parent_id is NULL AND owner_id = ?", user.ID).First(&folder).Error
58 59 60
	return &folder, err
}

61 62
// DeductionStorage 减少用户已用容量
func (user *User) DeductionStorage(size uint64) bool {
H
HFO4 已提交
63 64 65
	if size == 0 {
		return true
	}
66 67
	if size <= user.Storage {
		user.Storage -= size
H
HFO4 已提交
68
		DB.Model(user).Update("storage", gorm.Expr("storage - ?", size))
69 70
		return true
	}
71
	// 如果要减少的容量超出已用容量,则设为零
H
HFO4 已提交
72
	user.Storage = 0
H
HFO4 已提交
73
	DB.Model(user).Update("storage", 0)
H
HFO4 已提交
74

75 76 77 78 79
	return false
}

// IncreaseStorage 检查并增加用户已用容量
func (user *User) IncreaseStorage(size uint64) bool {
H
HFO4 已提交
80 81 82
	if size == 0 {
		return true
	}
H
HFO4 已提交
83 84
	if size <= user.GetRemainingCapacity() {
		user.Storage += size
H
HFO4 已提交
85
		DB.Model(user).Update("storage", gorm.Expr("storage + ?", size))
H
HFO4 已提交
86 87 88 89 90
		return true
	}
	return false
}

H
HFO4 已提交
91 92 93 94 95 96
// IncreaseStorageWithoutCheck 忽略可用容量,增加用户已用容量
func (user *User) IncreaseStorageWithoutCheck(size uint64) {
	if size == 0 {
		return
	}
	user.Storage += size
H
HFO4 已提交
97
	DB.Model(user).Update("storage", gorm.Expr("storage + ?", size))
H
HFO4 已提交
98 99 100

}

H
HFO4 已提交
101 102
// GetRemainingCapacity 获取剩余配额
func (user *User) GetRemainingCapacity() uint64 {
H
HFO4 已提交
103
	total := user.Group.MaxStorage
H
HFO4 已提交
104
	if total <= user.Storage {
H
HFO4 已提交
105 106
		return 0
	}
H
HFO4 已提交
107
	return total - user.Storage
H
HFO4 已提交
108 109
}

H
HFO4 已提交
110
// GetPolicyID 获取用户当前的存储策略ID
111
func (user *User) GetPolicyID(prefer uint) uint {
H
HFO4 已提交
112 113 114 115
	if len(user.Group.PolicyList) > 0 {
		return user.Group.PolicyList[0]
	}
	return 0
H
HFO4 已提交
116 117
}

H
HFO4 已提交
118 119
// GetUserByID 用ID获取用户
func GetUserByID(ID interface{}) (User, error) {
H
HFO4 已提交
120
	var user User
H
HFO4 已提交
121
	result := DB.Set("gorm:auto_preload", true).First(&user, ID)
H
HFO4 已提交
122 123 124
	return user, result.Error
}

H
HFO4 已提交
125 126 127 128 129 130 131
// GetActiveUserByID 用ID获取可登录用户
func GetActiveUserByID(ID interface{}) (User, error) {
	var user User
	result := DB.Set("gorm:auto_preload", true).Where("status = ?", Active).First(&user, ID)
	return user, result.Error
}

H
HFO4 已提交
132 133 134 135 136 137 138
// GetActiveUserByOpenID 用OpenID获取可登录用户
func GetActiveUserByOpenID(openid string) (User, error) {
	var user User
	result := DB.Set("gorm:auto_preload", true).Where("status = ? and open_id = ?", Active, openid).Find(&user)
	return user, result.Error
}

H
HFO4 已提交
139 140 141
// GetUserByEmail 用Email获取用户
func GetUserByEmail(email string) (User, error) {
	var user User
H
HFO4 已提交
142
	result := DB.Set("gorm:auto_preload", true).Where("status = ? and email = ?", Active, email).First(&user)
H
HFO4 已提交
143 144 145
	return user, result.Error
}

H
HFO4 已提交
146 147
// NewUser 返回一个新的空 User
func NewUser() User {
H
HFO4 已提交
148
	options := UserOption{}
H
HFO4 已提交
149
	return User{
H
HFO4 已提交
150
		OptionsSerialized: options,
H
HFO4 已提交
151 152 153
	}
}

H
HFO4 已提交
154 155 156 157 158 159
// BeforeSave Save用户前的钩子
func (user *User) BeforeSave() (err error) {
	err = user.SerializeOptions()
	return err
}

H
HFO4 已提交
160 161 162 163
// AfterCreate 创建用户后的钩子
func (user *User) AfterCreate(tx *gorm.DB) (err error) {
	// 创建用户的默认根目录
	defaultFolder := &Folder{
164 165
		Name:    "/",
		OwnerID: user.ID,
H
HFO4 已提交
166 167 168 169 170
	}
	tx.Create(defaultFolder)
	return err
}

H
HFO4 已提交
171 172 173
// AfterFind 找到用户后的钩子
func (user *User) AfterFind() (err error) {
	// 解析用户设置到OptionsSerialized
H
HFO4 已提交
174 175 176
	if user.Options != "" {
		err = json.Unmarshal([]byte(user.Options), &user.OptionsSerialized)
	}
H
HFO4 已提交
177 178

	// 预加载存储策略
179
	user.Policy, _ = GetPolicyByID(user.GetPolicyID(0))
H
HFO4 已提交
180 181 182
	return err
}

183 184 185 186 187 188 189
//SerializeOptions 将序列后的Option写入到数据库字段
func (user *User) SerializeOptions() (err error) {
	optionsValue, err := json.Marshal(&user.OptionsSerialized)
	user.Options = string(optionsValue)
	return err
}

H
HFO4 已提交
190 191 192 193 194
// CheckPassword 根据明文校验密码
func (user *User) CheckPassword(password string) (bool, error) {

	// 根据存储密码拆分为 Salt 和 Digest
	passwordStore := strings.Split(user.Password, ":")
H
HFO4 已提交
195
	if len(passwordStore) != 2 && len(passwordStore) != 3 {
H
HFO4 已提交
196 197 198
		return false, errors.New("Unknown password type")
	}

H
HFO4 已提交
199 200 201 202 203 204 205 206 207 208 209 210 211 212
	// 兼容V2密码,升级后存储格式为: md5:$HASH:$SALT
	if len(passwordStore) == 3 {
		if passwordStore[0] != "md5" {
			return false, errors.New("Unknown password type")
		}
		hash := md5.New()
		_, err := hash.Write([]byte(passwordStore[2] + password))
		bs := hex.EncodeToString(hash.Sum(nil))
		if err != nil {
			return false, err
		}
		return bs == passwordStore[1], nil
	}

H
HFO4 已提交
213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241
	//计算 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
}
H
HFO4 已提交
242 243 244 245

// NewAnonymousUser 返回一个匿名用户
func NewAnonymousUser() *User {
	user := User{}
246
	user.Policy.Type = "anonymous"
H
HFO4 已提交
247 248 249 250 251 252 253 254
	user.Group, _ = GetGroupByID(3)
	return &user
}

// IsAnonymous 返回是否为未登录用户
func (user *User) IsAnonymous() bool {
	return user.ID == 0
}
H
HFO4 已提交
255 256 257 258 259 260

// SetStatus 设定用户状态
func (user *User) SetStatus(status int) {
	DB.Model(&user).Update("status", status)
}

H
HFO4 已提交
261 262 263 264 265
// Update 更新用户
func (user *User) Update(val map[string]interface{}) error {
	return DB.Model(user).Updates(val).Error
}

H
HFO4 已提交
266 267 268 269 270 271 272
// UpdateOptions 更新用户偏好设定
func (user *User) UpdateOptions() error {
	if err := user.SerializeOptions(); err != nil {
		return err
	}
	return user.Update(map[string]interface{}{"options": user.Options})
}