Refactor and migrate more functions out of api into app package (#5063)
Этот коммит содержится в:
коммит произвёл
Harrison Healey
родитель
97558f6a6e
Коммит
0e2b321e6f
421
app/user.go
421
app/user.go
@@ -4,11 +4,105 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
"image"
|
||||
"image/color"
|
||||
"image/draw"
|
||||
_ "image/gif"
|
||||
_ "image/jpeg"
|
||||
"image/png"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
l4g "github.com/alecthomas/log4go"
|
||||
"github.com/golang/freetype"
|
||||
"github.com/mattermost/platform/einterfaces"
|
||||
"github.com/mattermost/platform/model"
|
||||
"github.com/mattermost/platform/utils"
|
||||
)
|
||||
|
||||
func CreateUserWithHash(user *model.User, hash string, data string) (*model.User, *model.AppError) {
|
||||
props := model.MapFromJson(strings.NewReader(data))
|
||||
|
||||
if !model.ComparePassword(hash, fmt.Sprintf("%v:%v", data, utils.Cfg.EmailSettings.InviteSalt)) {
|
||||
return nil, model.NewLocAppError("CreateUserWithHash", "api.user.create_user.signup_link_invalid.app_error", nil, "")
|
||||
}
|
||||
|
||||
if t, err := strconv.ParseInt(props["time"], 10, 64); err != nil || model.GetMillis()-t > 1000*60*60*48 { // 48 hours
|
||||
return nil, model.NewLocAppError("CreateUserWithHash", "api.user.create_user.signup_link_expired.app_error", nil, "")
|
||||
}
|
||||
|
||||
teamId := props["id"]
|
||||
|
||||
var team *model.Team
|
||||
if result := <-Srv.Store.Team().Get(teamId); result.Err != nil {
|
||||
return nil, result.Err
|
||||
} else {
|
||||
team = result.Data.(*model.Team)
|
||||
}
|
||||
|
||||
user.Email = props["email"]
|
||||
user.EmailVerified = true
|
||||
|
||||
var ruser *model.User
|
||||
var err *model.AppError
|
||||
if ruser, err = CreateUser(user); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := JoinUserToTeam(team, ruser); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
AddDirectChannels(team.Id, ruser)
|
||||
|
||||
return ruser, nil
|
||||
}
|
||||
|
||||
func CreateUserWithInviteId(user *model.User, inviteId string) (*model.User, *model.AppError) {
|
||||
var team *model.Team
|
||||
if result := <-Srv.Store.Team().GetByInviteId(inviteId); result.Err != nil {
|
||||
return nil, result.Err
|
||||
} else {
|
||||
team = result.Data.(*model.Team)
|
||||
}
|
||||
|
||||
var ruser *model.User
|
||||
var err *model.AppError
|
||||
if ruser, err = CreateUser(user); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := JoinUserToTeam(team, ruser); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
AddDirectChannels(team.Id, ruser)
|
||||
|
||||
return ruser, nil
|
||||
}
|
||||
|
||||
func IsFirstUserAccount() bool {
|
||||
if SessionCacheLength() == 0 {
|
||||
if cr := <-Srv.Store.User().GetTotalUsersCount(); cr.Err != nil {
|
||||
l4g.Error(cr.Err)
|
||||
return false
|
||||
} else {
|
||||
count := cr.Data.(int64)
|
||||
if count <= 0 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func CreateUser(user *model.User) (*model.User, *model.AppError) {
|
||||
|
||||
user.Roles = model.ROLE_SYSTEM_USER.Id
|
||||
@@ -58,3 +152,330 @@ func CreateUser(user *model.User) (*model.User, *model.AppError) {
|
||||
return ruser, nil
|
||||
}
|
||||
}
|
||||
|
||||
func CreateOAuthUser(service string, userData io.Reader, teamId string) (*model.User, *model.AppError) {
|
||||
var user *model.User
|
||||
provider := einterfaces.GetOauthProvider(service)
|
||||
if provider == nil {
|
||||
return nil, model.NewLocAppError("CreateOAuthUser", "api.user.create_oauth_user.not_available.app_error", map[string]interface{}{"Service": strings.Title(service)}, "")
|
||||
} else {
|
||||
user = provider.GetUserFromJson(userData)
|
||||
}
|
||||
|
||||
if user == nil {
|
||||
return nil, model.NewLocAppError("CreateOAuthUser", "api.user.create_oauth_user.create.app_error", map[string]interface{}{"Service": service}, "")
|
||||
}
|
||||
|
||||
suchan := Srv.Store.User().GetByAuth(user.AuthData, service)
|
||||
euchan := Srv.Store.User().GetByEmail(user.Email)
|
||||
|
||||
found := true
|
||||
count := 0
|
||||
for found {
|
||||
if found = IsUsernameTaken(user.Username); found {
|
||||
user.Username = user.Username + strconv.Itoa(count)
|
||||
count += 1
|
||||
}
|
||||
}
|
||||
|
||||
if result := <-suchan; result.Err == nil {
|
||||
return nil, model.NewLocAppError("CreateOAuthUser", "api.user.create_oauth_user.already_used.app_error", map[string]interface{}{"Service": service}, "email="+user.Email)
|
||||
}
|
||||
|
||||
if result := <-euchan; result.Err == nil {
|
||||
authService := result.Data.(*model.User).AuthService
|
||||
if authService == "" {
|
||||
return nil, model.NewLocAppError("CreateOAuthUser", "api.user.create_oauth_user.already_attached.app_error",
|
||||
map[string]interface{}{"Service": service, "Auth": model.USER_AUTH_SERVICE_EMAIL}, "email="+user.Email)
|
||||
} else {
|
||||
return nil, model.NewLocAppError("CreateOAuthUser", "api.user.create_oauth_user.already_attached.app_error",
|
||||
map[string]interface{}{"Service": service, "Auth": authService}, "email="+user.Email)
|
||||
}
|
||||
}
|
||||
|
||||
user.EmailVerified = true
|
||||
|
||||
ruser, err := CreateUser(user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(teamId) > 0 {
|
||||
err = JoinUserToTeamById(teamId, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = AddDirectChannels(teamId, user)
|
||||
if err != nil {
|
||||
l4g.Error(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
return ruser, nil
|
||||
}
|
||||
|
||||
// Check if the username is already used by another user. Return false if the username is invalid.
|
||||
func IsUsernameTaken(name string) bool {
|
||||
|
||||
if !model.IsValidUsername(name) {
|
||||
return false
|
||||
}
|
||||
|
||||
if result := <-Srv.Store.User().GetByUsername(name); result.Err != nil {
|
||||
return false
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func GetUser(userId string) (*model.User, *model.AppError) {
|
||||
if result := <-Srv.Store.User().Get(userId); result.Err != nil {
|
||||
return nil, result.Err
|
||||
} else {
|
||||
return result.Data.(*model.User), nil
|
||||
}
|
||||
}
|
||||
|
||||
func GetUserByUsername(username string) (*model.User, *model.AppError) {
|
||||
if result := <-Srv.Store.User().GetByUsername(username); result.Err != nil {
|
||||
return nil, result.Err
|
||||
} else {
|
||||
return result.Data.(*model.User), nil
|
||||
}
|
||||
}
|
||||
|
||||
func GetUserByEmail(email string) (*model.User, *model.AppError) {
|
||||
if result := <-Srv.Store.User().GetByEmail(email); result.Err != nil {
|
||||
return nil, result.Err
|
||||
} else {
|
||||
return result.Data.(*model.User), nil
|
||||
}
|
||||
}
|
||||
|
||||
func GetUserByAuth(authData *string, authService string) (*model.User, *model.AppError) {
|
||||
if result := <-Srv.Store.User().GetByAuth(authData, authService); result.Err != nil {
|
||||
return nil, result.Err
|
||||
} else {
|
||||
return result.Data.(*model.User), nil
|
||||
}
|
||||
}
|
||||
|
||||
func GetUserForLogin(loginId string, onlyLdap bool) (*model.User, *model.AppError) {
|
||||
ldapAvailable := *utils.Cfg.LdapSettings.Enable && einterfaces.GetLdapInterface() != nil && utils.IsLicensed && *utils.License.Features.LDAP
|
||||
|
||||
if result := <-Srv.Store.User().GetForLogin(
|
||||
loginId,
|
||||
*utils.Cfg.EmailSettings.EnableSignInWithUsername && !onlyLdap,
|
||||
*utils.Cfg.EmailSettings.EnableSignInWithEmail && !onlyLdap,
|
||||
ldapAvailable,
|
||||
); result.Err != nil && result.Err.Id == "store.sql_user.get_for_login.multiple_users" {
|
||||
// don't fall back to LDAP in this case since we already know there's an LDAP user, but that it shouldn't work
|
||||
result.Err.StatusCode = http.StatusBadRequest
|
||||
return nil, result.Err
|
||||
} else if result.Err != nil {
|
||||
if !ldapAvailable {
|
||||
// failed to find user and no LDAP server to fall back on
|
||||
result.Err.StatusCode = http.StatusBadRequest
|
||||
return nil, result.Err
|
||||
}
|
||||
|
||||
// fall back to LDAP server to see if we can find a user
|
||||
if ldapUser, ldapErr := einterfaces.GetLdapInterface().GetUser(loginId); ldapErr != nil {
|
||||
ldapErr.StatusCode = http.StatusBadRequest
|
||||
return nil, ldapErr
|
||||
} else {
|
||||
return ldapUser, nil
|
||||
}
|
||||
} else {
|
||||
return result.Data.(*model.User), nil
|
||||
}
|
||||
}
|
||||
|
||||
func GetUsers(offset int, limit int) (map[string]*model.User, *model.AppError) {
|
||||
if result := <-Srv.Store.User().GetAllProfiles(offset, limit); result.Err != nil {
|
||||
return nil, result.Err
|
||||
} else {
|
||||
return result.Data.(map[string]*model.User), nil
|
||||
}
|
||||
}
|
||||
|
||||
func GetUsersEtag() string {
|
||||
return (<-Srv.Store.User().GetEtagForAllProfiles()).Data.(string)
|
||||
}
|
||||
|
||||
func GetUsersInTeam(teamId string, offset int, limit int) (map[string]*model.User, *model.AppError) {
|
||||
if result := <-Srv.Store.User().GetProfiles(teamId, offset, limit); result.Err != nil {
|
||||
return nil, result.Err
|
||||
} else {
|
||||
return result.Data.(map[string]*model.User), nil
|
||||
}
|
||||
}
|
||||
|
||||
func GetUsersInTeamEtag(teamId string) string {
|
||||
return (<-Srv.Store.User().GetEtagForProfiles(teamId)).Data.(string)
|
||||
}
|
||||
|
||||
func GetUsersInChannel(channelId string, offset int, limit int) (map[string]*model.User, *model.AppError) {
|
||||
if result := <-Srv.Store.User().GetProfilesInChannel(channelId, offset, limit, false); result.Err != nil {
|
||||
return nil, result.Err
|
||||
} else {
|
||||
return result.Data.(map[string]*model.User), nil
|
||||
}
|
||||
}
|
||||
|
||||
func GetUsersNotInChannel(teamId string, channelId string, offset int, limit int) (map[string]*model.User, *model.AppError) {
|
||||
if result := <-Srv.Store.User().GetProfilesNotInChannel(teamId, channelId, offset, limit); result.Err != nil {
|
||||
return nil, result.Err
|
||||
} else {
|
||||
return result.Data.(map[string]*model.User), nil
|
||||
}
|
||||
}
|
||||
|
||||
func ActivateMfa(userId, token string) *model.AppError {
|
||||
mfaInterface := einterfaces.GetMfaInterface()
|
||||
if mfaInterface == nil {
|
||||
err := model.NewLocAppError("ActivateMfa", "api.user.update_mfa.not_available.app_error", nil, "")
|
||||
err.StatusCode = http.StatusNotImplemented
|
||||
return err
|
||||
}
|
||||
|
||||
var user *model.User
|
||||
if result := <-Srv.Store.User().Get(userId); result.Err != nil {
|
||||
return result.Err
|
||||
} else {
|
||||
user = result.Data.(*model.User)
|
||||
}
|
||||
|
||||
if len(user.AuthService) > 0 && user.AuthService != model.USER_AUTH_SERVICE_LDAP {
|
||||
return model.NewLocAppError("ActivateMfa", "api.user.activate_mfa.email_and_ldap_only.app_error", nil, "")
|
||||
}
|
||||
|
||||
if err := mfaInterface.Activate(user, token); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeactivateMfa(userId string) *model.AppError {
|
||||
mfaInterface := einterfaces.GetMfaInterface()
|
||||
if mfaInterface == nil {
|
||||
err := model.NewLocAppError("DeactivateMfa", "api.user.update_mfa.not_available.app_error", nil, "")
|
||||
err.StatusCode = http.StatusNotImplemented
|
||||
return err
|
||||
}
|
||||
|
||||
if err := mfaInterface.Deactivate(userId); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func CreateProfileImage(username string, userId string) ([]byte, *model.AppError) {
|
||||
colors := []color.NRGBA{
|
||||
{197, 8, 126, 255},
|
||||
{227, 207, 18, 255},
|
||||
{28, 181, 105, 255},
|
||||
{35, 188, 224, 255},
|
||||
{116, 49, 196, 255},
|
||||
{197, 8, 126, 255},
|
||||
{197, 19, 19, 255},
|
||||
{250, 134, 6, 255},
|
||||
{227, 207, 18, 255},
|
||||
{123, 201, 71, 255},
|
||||
{28, 181, 105, 255},
|
||||
{35, 188, 224, 255},
|
||||
{116, 49, 196, 255},
|
||||
{197, 8, 126, 255},
|
||||
{197, 19, 19, 255},
|
||||
{250, 134, 6, 255},
|
||||
{227, 207, 18, 255},
|
||||
{123, 201, 71, 255},
|
||||
{28, 181, 105, 255},
|
||||
{35, 188, 224, 255},
|
||||
{116, 49, 196, 255},
|
||||
{197, 8, 126, 255},
|
||||
{197, 19, 19, 255},
|
||||
{250, 134, 6, 255},
|
||||
{227, 207, 18, 255},
|
||||
{123, 201, 71, 255},
|
||||
}
|
||||
|
||||
h := fnv.New32a()
|
||||
h.Write([]byte(userId))
|
||||
seed := h.Sum32()
|
||||
|
||||
initial := string(strings.ToUpper(username)[0])
|
||||
|
||||
fontBytes, err := ioutil.ReadFile(utils.FindDir("fonts") + utils.Cfg.FileSettings.InitialFont)
|
||||
if err != nil {
|
||||
return nil, model.NewLocAppError("CreateProfileImage", "api.user.create_profile_image.default_font.app_error", nil, err.Error())
|
||||
}
|
||||
font, err := freetype.ParseFont(fontBytes)
|
||||
if err != nil {
|
||||
return nil, model.NewLocAppError("CreateProfileImage", "api.user.create_profile_image.default_font.app_error", nil, err.Error())
|
||||
}
|
||||
|
||||
width := int(utils.Cfg.FileSettings.ProfileWidth)
|
||||
height := int(utils.Cfg.FileSettings.ProfileHeight)
|
||||
color := colors[int64(seed)%int64(len(colors))]
|
||||
dstImg := image.NewRGBA(image.Rect(0, 0, width, height))
|
||||
srcImg := image.White
|
||||
draw.Draw(dstImg, dstImg.Bounds(), &image.Uniform{color}, image.ZP, draw.Src)
|
||||
size := float64((width + height) / 4)
|
||||
|
||||
c := freetype.NewContext()
|
||||
c.SetFont(font)
|
||||
c.SetFontSize(size)
|
||||
c.SetClip(dstImg.Bounds())
|
||||
c.SetDst(dstImg)
|
||||
c.SetSrc(srcImg)
|
||||
|
||||
pt := freetype.Pt(width/6, height*2/3)
|
||||
_, err = c.DrawString(initial, pt)
|
||||
if err != nil {
|
||||
return nil, model.NewLocAppError("CreateProfileImage", "api.user.create_profile_image.initial.app_error", nil, err.Error())
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
|
||||
if imgErr := png.Encode(buf, dstImg); imgErr != nil {
|
||||
return nil, model.NewLocAppError("CreateProfileImage", "api.user.create_profile_image.encode.app_error", nil, imgErr.Error())
|
||||
} else {
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
}
|
||||
|
||||
func GetProfileImage(user *model.User) ([]byte, *model.AppError) {
|
||||
var img []byte
|
||||
|
||||
if len(utils.Cfg.FileSettings.DriverName) == 0 {
|
||||
var err *model.AppError
|
||||
if img, err = CreateProfileImage(user.Username, user.Id); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
path := "users/" + user.Id + "/profile.png"
|
||||
|
||||
if data, err := ReadFile(path); err != nil {
|
||||
if img, err = CreateProfileImage(user.Username, user.Id); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if user.LastPictureUpdate == 0 {
|
||||
if err := WriteFile(img, path); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
img = data
|
||||
}
|
||||
}
|
||||
|
||||
return img, nil
|
||||
}
|
||||
|
||||
Ссылка в новой задаче
Block a user