first commit
Этот коммит содержится в:
293
model/user.go
Обычный файл
293
model/user.go
Обычный файл
@@ -0,0 +1,293 @@
|
||||
// Copyright (c) 2015 Spinpunch, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"code.google.com/p/go.crypto/bcrypt"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
ROLE_ADMIN = "admin"
|
||||
ROLE_SYSTEM_ADMIN = "system_admin"
|
||||
ROLE_SYSTEM_SUPPORT = "system_support"
|
||||
USER_AWAY_TIMEOUT = 5 * 60 * 1000 // 5 minutes
|
||||
USER_OFFLINE_TIMEOUT = 5 * 60 * 1000 // 5 minutes
|
||||
USER_OFFLINE = "offline"
|
||||
USER_AWAY = "away"
|
||||
USER_ONLINE = "online"
|
||||
USER_NOTIFY_ALL = "all"
|
||||
USER_NOTIFY_MENTION = "mention"
|
||||
USER_NOTIFY_NONE = "none"
|
||||
BOT_USERNAME = "valet"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
Id string `json:"id"`
|
||||
CreateAt int64 `json:"create_at"`
|
||||
UpdateAt int64 `json:"update_at"`
|
||||
DeleteAt int64 `json:"delete_at"`
|
||||
TeamId string `json:"team_id"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
AuthData string `json:"auth_data"`
|
||||
Email string `json:"email"`
|
||||
EmailVerified bool `json:"email_verified"`
|
||||
FullName string `json:"full_name"`
|
||||
Roles string `json:"roles"`
|
||||
LastActivityAt int64 `json:"last_activity_at"`
|
||||
LastPingAt int64 `json:"last_ping_at"`
|
||||
AllowMarketing bool `json:"allow_marketing"`
|
||||
Props StringMap `json:"props"`
|
||||
NotifyProps StringMap `json:"notify_props"`
|
||||
LastPasswordUpdate int64 `json:"last_password_update"`
|
||||
}
|
||||
|
||||
// IsValid validates the user and returns an error if it isn't configured
|
||||
// correctly.
|
||||
func (u *User) IsValid() *AppError {
|
||||
|
||||
if len(u.Id) != 26 {
|
||||
return NewAppError("User.IsValid", "Invalid user id", "")
|
||||
}
|
||||
|
||||
if u.CreateAt == 0 {
|
||||
return NewAppError("User.IsValid", "Create at must be a valid time", "user_id="+u.Id)
|
||||
}
|
||||
|
||||
if u.UpdateAt == 0 {
|
||||
return NewAppError("User.IsValid", "Update at must be a valid time", "user_id="+u.Id)
|
||||
}
|
||||
|
||||
if len(u.TeamId) != 26 {
|
||||
return NewAppError("User.IsValid", "Invalid team id", "")
|
||||
}
|
||||
|
||||
if len(u.Username) == 0 || len(u.Username) > 64 {
|
||||
return NewAppError("User.IsValid", "Invalid username", "user_id="+u.Id)
|
||||
}
|
||||
|
||||
validChars, _ := regexp.Compile("^[a-z0-9\\.\\-\\_]+$")
|
||||
|
||||
if !validChars.MatchString(u.Username) {
|
||||
return NewAppError("User.IsValid", "Invalid username", "user_id="+u.Id)
|
||||
}
|
||||
|
||||
if len(u.Email) > 128 || len(u.Email) == 0 {
|
||||
return NewAppError("User.IsValid", "Invalid email", "user_id="+u.Id)
|
||||
}
|
||||
|
||||
if len(u.FullName) > 64 {
|
||||
return NewAppError("User.IsValid", "Invalid full name", "user_id="+u.Id)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// PreSave will set the Id and Username if missing. It will also fill
|
||||
// in the CreateAt, UpdateAt times. It will also hash the password. It should
|
||||
// be run before saving the user to the db.
|
||||
func (u *User) PreSave() {
|
||||
if u.Id == "" {
|
||||
u.Id = NewId()
|
||||
}
|
||||
|
||||
if u.Username == "" {
|
||||
u.Username = NewId()
|
||||
}
|
||||
|
||||
u.Username = strings.ToLower(u.Username)
|
||||
u.Email = strings.ToLower(u.Email)
|
||||
|
||||
u.CreateAt = GetMillis()
|
||||
u.UpdateAt = u.CreateAt
|
||||
|
||||
u.LastPasswordUpdate = u.CreateAt
|
||||
|
||||
if u.Props == nil {
|
||||
u.Props = make(map[string]string)
|
||||
}
|
||||
|
||||
if u.NotifyProps == nil || len(u.NotifyProps) == 0 {
|
||||
u.SetDefaultNotifications()
|
||||
}
|
||||
|
||||
if len(u.Password) > 0 {
|
||||
u.Password = HashPassword(u.Password)
|
||||
}
|
||||
}
|
||||
|
||||
// PreUpdate should be run before updating the user in the db.
|
||||
func (u *User) PreUpdate() {
|
||||
u.Username = strings.ToLower(u.Username)
|
||||
u.Email = strings.ToLower(u.Email)
|
||||
u.UpdateAt = GetMillis()
|
||||
|
||||
if u.NotifyProps == nil || len(u.NotifyProps) == 0 {
|
||||
u.SetDefaultNotifications()
|
||||
} else if _, ok := u.NotifyProps["mention_keys"]; ok {
|
||||
// Remove any blank mention keys
|
||||
splitKeys := strings.Split(u.NotifyProps["mention_keys"], ",")
|
||||
goodKeys := []string{}
|
||||
for _, key := range splitKeys {
|
||||
if len(key) > 0 {
|
||||
goodKeys = append(goodKeys, strings.ToLower(key))
|
||||
}
|
||||
}
|
||||
u.NotifyProps["mention_keys"] = strings.Join(goodKeys, ",")
|
||||
}
|
||||
}
|
||||
|
||||
func (u *User) SetDefaultNotifications() {
|
||||
u.NotifyProps = make(map[string]string)
|
||||
u.NotifyProps["email"] = "true"
|
||||
u.NotifyProps["desktop"] = USER_NOTIFY_ALL
|
||||
u.NotifyProps["desktop_sound"] = "true"
|
||||
u.NotifyProps["mention_keys"] = u.Username
|
||||
u.NotifyProps["first_name"] = "true"
|
||||
splitName := strings.Split(u.FullName, " ")
|
||||
if len(splitName) > 0 && splitName[0] != "" {
|
||||
u.NotifyProps["mention_keys"] += "," + splitName[0]
|
||||
}
|
||||
}
|
||||
|
||||
// ToJson convert a User to a json string
|
||||
func (u *User) ToJson() string {
|
||||
b, err := json.Marshal(u)
|
||||
if err != nil {
|
||||
return ""
|
||||
} else {
|
||||
return string(b)
|
||||
}
|
||||
}
|
||||
|
||||
// Generate a valid strong etag so the browser can cache the results
|
||||
func (u *User) Etag() string {
|
||||
return Etag(u.Id, u.UpdateAt)
|
||||
}
|
||||
|
||||
func (u *User) IsOffline() bool {
|
||||
return (GetMillis()-u.LastPingAt) > USER_OFFLINE_TIMEOUT && (GetMillis()-u.LastActivityAt) > USER_OFFLINE_TIMEOUT
|
||||
}
|
||||
|
||||
func (u *User) IsAway() bool {
|
||||
return (GetMillis() - u.LastActivityAt) > USER_AWAY_TIMEOUT
|
||||
}
|
||||
|
||||
// Remove any private data from the user object
|
||||
func (u *User) Sanitize(options map[string]bool) {
|
||||
u.Password = ""
|
||||
u.AuthData = ""
|
||||
|
||||
if len(options) != 0 && !options["email"] {
|
||||
u.Email = ""
|
||||
}
|
||||
if len(options) != 0 && !options["fullname"] {
|
||||
u.FullName = ""
|
||||
}
|
||||
if len(options) != 0 && !options["skypeid"] {
|
||||
// TODO - fill in when SkypeId is added to user model
|
||||
}
|
||||
if len(options) != 0 && !options["phonenumber"] {
|
||||
// TODO - fill in when PhoneNumber is added to user model
|
||||
}
|
||||
if len(options) != 0 && !options["passwordupadte"] {
|
||||
u.LastPasswordUpdate = 0
|
||||
}
|
||||
}
|
||||
|
||||
func (u *User) MakeNonNil() {
|
||||
if u.Props == nil {
|
||||
u.Props = make(map[string]string)
|
||||
}
|
||||
|
||||
if u.NotifyProps == nil {
|
||||
u.NotifyProps = make(map[string]string)
|
||||
}
|
||||
}
|
||||
|
||||
func (u *User) AddProp(key string, value string) {
|
||||
u.MakeNonNil()
|
||||
|
||||
u.Props[key] = value
|
||||
}
|
||||
|
||||
func (u *User) AddNotifyProp(key string, value string) {
|
||||
u.MakeNonNil()
|
||||
|
||||
u.NotifyProps[key] = value
|
||||
}
|
||||
|
||||
// UserFromJson will decode the input and return a User
|
||||
func UserFromJson(data io.Reader) *User {
|
||||
decoder := json.NewDecoder(data)
|
||||
var user User
|
||||
err := decoder.Decode(&user)
|
||||
if err == nil {
|
||||
return &user
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func UserMapToJson(u map[string]*User) string {
|
||||
b, err := json.Marshal(u)
|
||||
if err != nil {
|
||||
return ""
|
||||
} else {
|
||||
return string(b)
|
||||
}
|
||||
}
|
||||
|
||||
func UserMapFromJson(data io.Reader) map[string]*User {
|
||||
decoder := json.NewDecoder(data)
|
||||
var users map[string]*User
|
||||
err := decoder.Decode(&users)
|
||||
if err == nil {
|
||||
return users
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// HashPassword generates a hash using the bcrypt.GenerateFromPassword
|
||||
func HashPassword(password string) string {
|
||||
hash, err := bcrypt.GenerateFromPassword([]byte(password), 10)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return string(hash)
|
||||
}
|
||||
|
||||
// ComparePassword compares the hash
|
||||
func ComparePassword(hash string, password string) bool {
|
||||
|
||||
if len(password) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func IsUsernameValid(username string) bool {
|
||||
|
||||
var restrictedUsernames = []string {
|
||||
BOT_USERNAME,
|
||||
"all",
|
||||
"channel",
|
||||
}
|
||||
|
||||
for _,restrictedUsername := range restrictedUsernames {
|
||||
if username == restrictedUsername {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
Ссылка в новой задаче
Block a user