user service: initial implementation (#17668)
* conceptual user service: initial commit * reflect review comments * fix i18n issues and some tests * implement get user methods * add license * reflect review comments
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
d320b50abb
Коммит
ac3bb2e811
181
app/user.go
181
app/user.go
@@ -33,6 +33,7 @@ import (
|
||||
"github.com/mattermost/mattermost-server/v5/einterfaces"
|
||||
"github.com/mattermost/mattermost-server/v5/model"
|
||||
"github.com/mattermost/mattermost-server/v5/plugin"
|
||||
"github.com/mattermost/mattermost-server/v5/services/users"
|
||||
"github.com/mattermost/mattermost-server/v5/shared/i18n"
|
||||
"github.com/mattermost/mattermost-server/v5/shared/mfa"
|
||||
"github.com/mattermost/mattermost-server/v5/shared/mlog"
|
||||
@@ -244,37 +245,58 @@ func (a *App) CreateGuest(c *request.Context, user *model.User) (*model.User, *m
|
||||
}
|
||||
|
||||
func (a *App) createUserOrGuest(c *request.Context, user *model.User, guest bool) (*model.User, *model.AppError) {
|
||||
user.Roles = model.SYSTEM_USER_ROLE_ID
|
||||
if guest {
|
||||
user.Roles = model.SYSTEM_GUEST_ROLE_ID
|
||||
ruser, nErr := a.srv.userService.CreateUser(user, users.UserCreateOptions{Guest: guest})
|
||||
if nErr != nil {
|
||||
var appErr *model.AppError
|
||||
var invErr *store.ErrInvalidInput
|
||||
var nfErr *users.ErrInvalidPassword
|
||||
switch {
|
||||
case errors.As(nErr, &appErr):
|
||||
return nil, appErr
|
||||
case errors.Is(nErr, users.AcceptedDomainError):
|
||||
return nil, model.NewAppError("createUserOrGuest", "api.user.create_user.accepted_domain.app_error", nil, "", http.StatusBadRequest)
|
||||
case errors.As(nErr, &nfErr):
|
||||
return nil, model.NewAppError("createUserOrGuest", "api.user.check_user_password.invalid.app_error", nil, "", http.StatusBadRequest)
|
||||
case errors.Is(nErr, users.UserCountError):
|
||||
return nil, model.NewAppError("createUserOrGuest", "app.user.get_total_users_count.app_error", nil, nErr.Error(), http.StatusInternalServerError)
|
||||
case errors.As(nErr, &invErr):
|
||||
switch invErr.Field {
|
||||
case "email":
|
||||
return nil, model.NewAppError("createUserOrGuest", "app.user.save.email_exists.app_error", nil, invErr.Error(), http.StatusBadRequest)
|
||||
case "username":
|
||||
return nil, model.NewAppError("createUserOrGuest", "app.user.save.username_exists.app_error", nil, invErr.Error(), http.StatusBadRequest)
|
||||
default:
|
||||
return nil, model.NewAppError("createUserOrGuest", "app.user.save.existing.app_error", nil, invErr.Error(), http.StatusBadRequest)
|
||||
}
|
||||
default:
|
||||
return nil, model.NewAppError("createUserOrGuest", "app.user.save.app_error", nil, nErr.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
if !user.IsLDAPUser() && !user.IsSAMLUser() && !user.IsGuest() && !CheckUserDomain(user, *a.Config().TeamSettings.RestrictCreationToDomains) {
|
||||
return nil, model.NewAppError("CreateUser", "api.user.create_user.accepted_domain.app_error", nil, "", http.StatusBadRequest)
|
||||
if user.EmailVerified {
|
||||
a.InvalidateCacheForUser(ruser.Id)
|
||||
|
||||
nUser, err := a.srv.userService.GetUser(ruser.Id)
|
||||
if err != nil {
|
||||
var nfErr *store.ErrNotFound
|
||||
switch {
|
||||
case errors.As(err, &nfErr):
|
||||
return nil, model.NewAppError("createUserOrGuest", MissingAccountError, nil, nfErr.Error(), http.StatusNotFound)
|
||||
default:
|
||||
return nil, model.NewAppError("createUserOrGuest", "app.user.get.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
a.sendUpdatedUserEvent(*nUser)
|
||||
}
|
||||
|
||||
if !user.IsLDAPUser() && !user.IsSAMLUser() && user.IsGuest() && !CheckUserDomain(user, *a.Config().GuestAccountsSettings.RestrictCreationToDomains) {
|
||||
return nil, model.NewAppError("CreateUser", "api.user.create_user.accepted_domain.app_error", nil, "", http.StatusBadRequest)
|
||||
pref := model.Preference{UserId: ruser.Id, Category: model.PREFERENCE_CATEGORY_TUTORIAL_STEPS, Name: ruser.Id, Value: "0"}
|
||||
if err := a.Srv().Store.Preference().Save(&model.Preferences{pref}); err != nil {
|
||||
mlog.Warn("Encountered error saving tutorial preference", mlog.Err(err))
|
||||
}
|
||||
|
||||
// Below is a special case where the first user in the entire
|
||||
// system is granted the system_admin role
|
||||
count, err := a.Srv().Store.User().Count(model.UserCountOptions{IncludeDeleted: true})
|
||||
if err != nil {
|
||||
return nil, model.NewAppError("createUserOrGuest", "app.user.get_total_users_count.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
if count <= 0 {
|
||||
user.Roles = model.SYSTEM_ADMIN_ROLE_ID + " " + model.SYSTEM_USER_ROLE_ID
|
||||
}
|
||||
go a.UpdateViewedProductNoticesForNewUser(ruser.Id)
|
||||
|
||||
if _, ok := i18n.GetSupportedLocales()[user.Locale]; !ok {
|
||||
user.Locale = *a.Config().LocalizationSettings.DefaultClientLocale
|
||||
}
|
||||
|
||||
ruser, appErr := a.createUser(user)
|
||||
if appErr != nil {
|
||||
return nil, appErr
|
||||
}
|
||||
// This message goes to everyone, so the teamID, channelID and userID are irrelevant
|
||||
message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_NEW_USER, "", "", "", nil)
|
||||
message.Add("user_id", ruser.Id)
|
||||
@@ -293,53 +315,6 @@ func (a *App) createUserOrGuest(c *request.Context, user *model.User, guest bool
|
||||
return ruser, nil
|
||||
}
|
||||
|
||||
func (a *App) createUser(user *model.User) (*model.User, *model.AppError) {
|
||||
user.MakeNonNil()
|
||||
|
||||
if err := a.IsPasswordValid(user.Password); user.AuthService == "" && err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ruser, nErr := a.Srv().Store.User().Save(user)
|
||||
if nErr != nil {
|
||||
var appErr *model.AppError
|
||||
var invErr *store.ErrInvalidInput
|
||||
switch {
|
||||
case errors.As(nErr, &appErr):
|
||||
return nil, appErr
|
||||
case errors.As(nErr, &invErr):
|
||||
switch invErr.Field {
|
||||
case "email":
|
||||
return nil, model.NewAppError("createUser", "app.user.save.email_exists.app_error", nil, invErr.Error(), http.StatusBadRequest)
|
||||
case "username":
|
||||
return nil, model.NewAppError("createUser", "app.user.save.username_exists.app_error", nil, invErr.Error(), http.StatusBadRequest)
|
||||
default:
|
||||
return nil, model.NewAppError("createUser", "app.user.save.existing.app_error", nil, invErr.Error(), http.StatusBadRequest)
|
||||
}
|
||||
default:
|
||||
return nil, model.NewAppError("createUser", "app.user.save.app_error", nil, nErr.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
if user.EmailVerified {
|
||||
if err := a.VerifyUserEmail(ruser.Id, user.Email); err != nil {
|
||||
mlog.Warn("Failed to set email verified", mlog.Err(err))
|
||||
}
|
||||
}
|
||||
|
||||
pref := model.Preference{UserId: ruser.Id, Category: model.PREFERENCE_CATEGORY_TUTORIAL_STEPS, Name: ruser.Id, Value: "0"}
|
||||
if err := a.Srv().Store.Preference().Save(&model.Preferences{pref}); err != nil {
|
||||
mlog.Warn("Encountered error saving tutorial preference", mlog.Err(err))
|
||||
}
|
||||
|
||||
go a.UpdateViewedProductNoticesForNewUser(ruser.Id)
|
||||
ruser.Sanitize(map[string]bool{})
|
||||
|
||||
// Determine whether to send the created user a welcome email
|
||||
ruser.DisableWelcomeEmail = user.DisableWelcomeEmail
|
||||
return ruser, nil
|
||||
}
|
||||
|
||||
func (a *App) CreateOAuthUser(c *request.Context, service string, userData io.Reader, teamID string, tokenUser *model.User) (*model.User, *model.AppError) {
|
||||
if !*a.Config().TeamSettings.EnableUserCreation {
|
||||
return nil, model.NewAppError("CreateOAuthUser", "api.user.create_user.disabled.app_error", nil, "", http.StatusNotImplemented)
|
||||
@@ -360,7 +335,7 @@ func (a *App) CreateOAuthUser(c *request.Context, service string, userData io.Re
|
||||
found := true
|
||||
count := 0
|
||||
for found {
|
||||
if found = a.IsUsernameTaken(user.Username); found {
|
||||
if found = a.srv.userService.IsUsernameTaken(user.Username); found {
|
||||
user.Username = user.Username + strconv.Itoa(count)
|
||||
count++
|
||||
}
|
||||
@@ -430,28 +405,15 @@ func CheckUserDomain(user *model.User, domains string) bool {
|
||||
return CheckEmailDomain(user.Email, domains)
|
||||
}
|
||||
|
||||
// IsUsernameTaken checks if the username is already used by another user. Return false if the username is invalid.
|
||||
func (a *App) IsUsernameTaken(name string) bool {
|
||||
if !model.IsValidUsername(name) {
|
||||
return false
|
||||
}
|
||||
|
||||
if _, err := a.Srv().Store.User().GetByUsername(name); err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (a *App) GetUser(userID string) (*model.User, *model.AppError) {
|
||||
user, err := a.Srv().Store.User().Get(context.Background(), userID)
|
||||
user, err := a.srv.userService.GetUser(userID)
|
||||
if err != nil {
|
||||
var nfErr *store.ErrNotFound
|
||||
switch {
|
||||
case errors.As(err, &nfErr):
|
||||
return nil, model.NewAppError("GetUser", MissingAccountError, nil, nfErr.Error(), http.StatusNotFound)
|
||||
default:
|
||||
return nil, model.NewAppError("GetUser", "app.user.get.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
return nil, model.NewAppError("GetUser", "app.user.get_by_username.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -459,7 +421,7 @@ func (a *App) GetUser(userID string) (*model.User, *model.AppError) {
|
||||
}
|
||||
|
||||
func (a *App) GetUserByUsername(username string) (*model.User, *model.AppError) {
|
||||
result, err := a.Srv().Store.User().GetByUsername(username)
|
||||
result, err := a.srv.userService.GetUserByUsername(username)
|
||||
if err != nil {
|
||||
var nfErr *store.ErrNotFound
|
||||
switch {
|
||||
@@ -473,7 +435,7 @@ func (a *App) GetUserByUsername(username string) (*model.User, *model.AppError)
|
||||
}
|
||||
|
||||
func (a *App) GetUserByEmail(email string) (*model.User, *model.AppError) {
|
||||
user, err := a.Srv().Store.User().GetByEmail(email)
|
||||
user, err := a.srv.userService.GetUserByEmail(email)
|
||||
if err != nil {
|
||||
var nfErr *store.ErrNotFound
|
||||
switch {
|
||||
@@ -487,7 +449,7 @@ func (a *App) GetUserByEmail(email string) (*model.User, *model.AppError) {
|
||||
}
|
||||
|
||||
func (a *App) GetUserByAuth(authData *string, authService string) (*model.User, *model.AppError) {
|
||||
user, err := a.Srv().Store.User().GetByAuth(authData, authService)
|
||||
user, err := a.srv.userService.GetUserByAuth(authData, authService)
|
||||
if err != nil {
|
||||
var invErr *store.ErrInvalidInput
|
||||
var nfErr *store.ErrNotFound
|
||||
@@ -505,7 +467,7 @@ func (a *App) GetUserByAuth(authData *string, authService string) (*model.User,
|
||||
}
|
||||
|
||||
func (a *App) GetUsers(options *model.UserGetOptions) ([]*model.User, *model.AppError) {
|
||||
users, err := a.Srv().Store.User().GetAllProfiles(options)
|
||||
users, err := a.srv.userService.GetUsers(options)
|
||||
if err != nil {
|
||||
return nil, model.NewAppError("GetUsers", "app.user.get_profiles.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
@@ -514,20 +476,20 @@ func (a *App) GetUsers(options *model.UserGetOptions) ([]*model.User, *model.App
|
||||
}
|
||||
|
||||
func (a *App) GetUsersPage(options *model.UserGetOptions, asAdmin bool) ([]*model.User, *model.AppError) {
|
||||
users, err := a.GetUsers(options)
|
||||
users, err := a.srv.userService.GetUsersPage(options, asAdmin)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, model.NewAppError("GetUsersPage", "app.user.get_profiles.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
return a.sanitizeProfiles(users, asAdmin), nil
|
||||
return users, nil
|
||||
}
|
||||
|
||||
func (a *App) GetUsersEtag(restrictionsHash string) string {
|
||||
return fmt.Sprintf("%v.%v.%v.%v", a.Srv().Store.User().GetEtagForAllProfiles(), a.Config().PrivacySettings.ShowFullName, a.Config().PrivacySettings.ShowEmailAddress, restrictionsHash)
|
||||
return a.srv.userService.GetUsersEtag(restrictionsHash)
|
||||
}
|
||||
|
||||
func (a *App) GetUsersInTeam(options *model.UserGetOptions) ([]*model.User, *model.AppError) {
|
||||
users, err := a.Srv().Store.User().GetProfiles(options)
|
||||
users, err := a.srv.userService.GetUsersInTeam(options)
|
||||
if err != nil {
|
||||
return nil, model.NewAppError("GetUsersInTeam", "app.user.get_profiles.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
@@ -536,7 +498,7 @@ func (a *App) GetUsersInTeam(options *model.UserGetOptions) ([]*model.User, *mod
|
||||
}
|
||||
|
||||
func (a *App) GetUsersNotInTeam(teamID string, groupConstrained bool, offset int, limit int, viewRestrictions *model.ViewUsersRestrictions) ([]*model.User, *model.AppError) {
|
||||
users, err := a.Srv().Store.User().GetProfilesNotInTeam(teamID, groupConstrained, offset, limit, viewRestrictions)
|
||||
users, err := a.srv.userService.GetUsersNotInTeam(teamID, groupConstrained, offset, limit, viewRestrictions)
|
||||
if err != nil {
|
||||
return nil, model.NewAppError("GetUsersNotInTeam", "app.user.get_profiles.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
@@ -545,29 +507,29 @@ func (a *App) GetUsersNotInTeam(teamID string, groupConstrained bool, offset int
|
||||
}
|
||||
|
||||
func (a *App) GetUsersInTeamPage(options *model.UserGetOptions, asAdmin bool) ([]*model.User, *model.AppError) {
|
||||
users, err := a.GetUsersInTeam(options)
|
||||
users, err := a.srv.userService.GetUsersInTeamPage(options, asAdmin)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, model.NewAppError("GetUsersInTeamPage", "app.user.get_profiles.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
return a.sanitizeProfiles(users, asAdmin), nil
|
||||
}
|
||||
|
||||
func (a *App) GetUsersNotInTeamPage(teamID string, groupConstrained bool, page int, perPage int, asAdmin bool, viewRestrictions *model.ViewUsersRestrictions) ([]*model.User, *model.AppError) {
|
||||
users, err := a.GetUsersNotInTeam(teamID, groupConstrained, page*perPage, perPage, viewRestrictions)
|
||||
users, err := a.srv.userService.GetUsersNotInTeamPage(teamID, groupConstrained, page*perPage, perPage, asAdmin, viewRestrictions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, model.NewAppError("GetUsersNotInTeamPage", "app.user.get_profiles.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
return a.sanitizeProfiles(users, asAdmin), nil
|
||||
}
|
||||
|
||||
func (a *App) GetUsersInTeamEtag(teamID string, restrictionsHash string) string {
|
||||
return fmt.Sprintf("%v.%v.%v.%v", a.Srv().Store.User().GetEtagForProfiles(teamID), a.Config().PrivacySettings.ShowFullName, a.Config().PrivacySettings.ShowEmailAddress, restrictionsHash)
|
||||
return a.srv.userService.GetUsersInTeamEtag(teamID, restrictionsHash)
|
||||
}
|
||||
|
||||
func (a *App) GetUsersNotInTeamEtag(teamID string, restrictionsHash string) string {
|
||||
return fmt.Sprintf("%v.%v.%v.%v", a.Srv().Store.User().GetEtagForProfilesNotInTeam(teamID), a.Config().PrivacySettings.ShowFullName, a.Config().PrivacySettings.ShowEmailAddress, restrictionsHash)
|
||||
return a.srv.userService.GetUsersNotInTeamEtag(teamID, restrictionsHash)
|
||||
}
|
||||
|
||||
func (a *App) GetUsersInChannel(options *model.UserGetOptions) ([]*model.User, *model.AppError) {
|
||||
@@ -655,16 +617,16 @@ func (a *App) GetUsersNotInChannelPage(teamID string, channelID string, groupCon
|
||||
}
|
||||
|
||||
func (a *App) GetUsersWithoutTeamPage(options *model.UserGetOptions, asAdmin bool) ([]*model.User, *model.AppError) {
|
||||
users, err := a.GetUsersWithoutTeam(options)
|
||||
users, err := a.srv.userService.GetUsersWithoutTeamPage(options, asAdmin)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, model.NewAppError("GetUsersWithoutTeamPage", "app.user.get_profiles.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
return a.sanitizeProfiles(users, asAdmin), nil
|
||||
}
|
||||
|
||||
func (a *App) GetUsersWithoutTeam(options *model.UserGetOptions) ([]*model.User, *model.AppError) {
|
||||
users, err := a.Srv().Store.User().GetProfilesWithoutTeam(options)
|
||||
users, err := a.srv.userService.GetUsersWithoutTeam(options)
|
||||
if err != nil {
|
||||
return nil, model.NewAppError("GetUsersWithoutTeam", "app.user.get_profiles.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
@@ -693,14 +655,12 @@ func (a *App) GetChannelGroupUsers(channelID string) ([]*model.User, *model.AppE
|
||||
}
|
||||
|
||||
func (a *App) GetUsersByIds(userIDs []string, options *store.UserGetByIdsOpts) ([]*model.User, *model.AppError) {
|
||||
allowFromCache := options.ViewRestrictions == nil
|
||||
|
||||
users, err := a.Srv().Store.User().GetProfileByIds(context.Background(), userIDs, options, allowFromCache)
|
||||
users, err := a.srv.userService.GetUsersByIds(userIDs, options)
|
||||
if err != nil {
|
||||
return nil, model.NewAppError("GetUsersByIds", "app.user.get_profiles.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
return a.sanitizeProfiles(users, options.IsAdmin), nil
|
||||
return users, nil
|
||||
}
|
||||
|
||||
func (a *App) GetUsersByGroupChannelIds(c *request.Context, channelIDs []string, asAdmin bool) (map[string][]*model.User, *model.AppError) {
|
||||
@@ -1125,6 +1085,7 @@ func (a *App) DeactivateGuests(c *request.Context) *model.AppError {
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO: migrate this after the user service implementation is completed
|
||||
func (a *App) GetSanitizeOptions(asAdmin bool) map[string]bool {
|
||||
options := a.Config().GetSanitizeOptions()
|
||||
if asAdmin {
|
||||
|
||||
Ссылка в новой задаче
Block a user