diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | i18n/en.json | 4 | ||||
-rw-r--r-- | store/sql_user_store.go | 12 | ||||
-rw-r--r-- | store/sql_user_store_test.go | 11 | ||||
-rw-r--r-- | utils/config.go | 1 | ||||
-rw-r--r-- | webapp/components/user_settings/user_settings_general.jsx | 313 |
6 files changed, 207 insertions, 136 deletions
@@ -145,7 +145,7 @@ test: start-docker $(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=340s ./api || exit 1 $(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=12s ./model || exit 1 - $(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=120s ./store || exit 1 + $(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=180s ./store || exit 1 $(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=120s ./utils || exit 1 $(GO) test $(GOFLAGS) -run=$(TESTS) -test.v -test.timeout=120s ./web || exit 1 ifeq ($(BUILD_ENTERPRISE_READY),true) diff --git a/i18n/en.json b/i18n/en.json index 5cc2ec9f6..bfcfe845e 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -3496,6 +3496,10 @@ "translation": "We couldn't update the account" }, { + "id": "store.sql_user.update.can_not_change_ldap.app_error", + "translation": "Can not change fields set by LDAP" + }, + { "id": "store.sql_user.update.email_taken.app_error", "translation": "This email is already taken. Please choose another." }, diff --git a/store/sql_user_store.go b/store/sql_user_store.go index 636400ce9..9db378341 100644 --- a/store/sql_user_store.go +++ b/store/sql_user_store.go @@ -136,7 +136,17 @@ func (us SqlUserStore) Update(user *model.User, allowActiveUpdate bool) StoreCha if user.IsOAuthUser() { user.Email = oldUser.Email - } else if !user.IsLDAPUser() && user.Email != oldUser.Email { + } else if user.IsLDAPUser() { + if user.Username != oldUser.Username || + user.FirstName != oldUser.FirstName || + user.LastName != oldUser.LastName || + user.Email != oldUser.Email { + result.Err = model.NewLocAppError("SqlUserStore.Update", "store.sql_user.update.can_not_change_ldap.app_error", nil, "user_id="+user.Id) + storeChannel <- result + close(storeChannel) + return + } + } else if user.Email != oldUser.Email { user.EmailVerified = false } diff --git a/store/sql_user_store_test.go b/store/sql_user_store_test.go index 2d17c5888..9fed32dc8 100644 --- a/store/sql_user_store_test.go +++ b/store/sql_user_store_test.go @@ -77,6 +77,12 @@ func TestUserStoreUpdate(t *testing.T) { Must(store.User().Save(u1)) Must(store.Team().SaveMember(&model.TeamMember{TeamId: model.NewId(), UserId: u1.Id})) + u2 := &model.User{} + u2.Email = model.NewId() + u2.AuthService = "ldap" + Must(store.User().Save(u2)) + Must(store.Team().SaveMember(&model.TeamMember{TeamId: model.NewId(), UserId: u2.Id})) + time.Sleep(100 * time.Millisecond) if err := (<-store.User().Update(u1, false)).Err; err != nil { @@ -92,6 +98,11 @@ func TestUserStoreUpdate(t *testing.T) { if err := (<-store.User().Update(u1, false)).Err; err == nil { t.Fatal("Update should have faile because id change") } + + u2.Email = model.NewId() + if err := (<-store.User().Update(u2, false)).Err; err == nil { + t.Fatal("Update should have failed because you can't modify LDAP fields") + } } func TestUserStoreUpdateLastPingAt(t *testing.T) { diff --git a/utils/config.go b/utils/config.go index 1ae658b16..9e2776f75 100644 --- a/utils/config.go +++ b/utils/config.go @@ -259,6 +259,7 @@ func getClientConfig(c *model.Config) map[string]string { props["EnableLdap"] = strconv.FormatBool(*c.LdapSettings.Enable) props["LdapLoginFieldName"] = *c.LdapSettings.LoginFieldName props["LdapPasswordFieldName"] = *c.LdapSettings.PasswordFieldName + props["NicknameAttributeSet"] = strconv.FormatBool(*c.LdapSettings.NicknameAttribute != "") } if *License.Features.MFA { diff --git a/webapp/components/user_settings/user_settings_general.jsx b/webapp/components/user_settings/user_settings_general.jsx index abf5ca7a9..718ad5ed8 100644 --- a/webapp/components/user_settings/user_settings_general.jsx +++ b/webapp/components/user_settings/user_settings_general.jsx @@ -513,85 +513,100 @@ class UserSettingsGeneralTab extends React.Component { const inputs = []; if (this.props.activeSection === 'name') { - inputs.push( - <div - key='firstNameSetting' - className='form-group' - > - <label className='col-sm-5 control-label'> - <FormattedMessage - id='user.settings.general.firstName' - defaultMessage='First Name' - /> - </label> - <div className='col-sm-7'> - <input - className='form-control' - type='text' - onChange={this.updateFirstName} - value={this.state.firstName} - /> + let extraInfo; + let submit = null; + if (this.props.user.auth_service === '') { + inputs.push( + <div + key='firstNameSetting' + className='form-group' + > + <label className='col-sm-5 control-label'> + <FormattedMessage + id='user.settings.general.firstName' + defaultMessage='First Name' + /> + </label> + <div className='col-sm-7'> + <input + className='form-control' + type='text' + onChange={this.updateFirstName} + value={this.state.firstName} + /> + </div> </div> - </div> - ); + ); - inputs.push( - <div - key='lastNameSetting' - className='form-group' - > - <label className='col-sm-5 control-label'> + inputs.push( + <div + key='lastNameSetting' + className='form-group' + > + <label className='col-sm-5 control-label'> + <FormattedMessage + id='user.settings.general.lastName' + defaultMessage='Last Name' + /> + </label> + <div className='col-sm-7'> + <input + className='form-control' + type='text' + onChange={this.updateLastName} + value={this.state.lastName} + /> + </div> + </div> + ); + + function notifClick(e) { + e.preventDefault(); + this.updateSection(''); + this.props.updateTab('notifications'); + } + + const notifLink = ( + <a + href='#' + onClick={notifClick.bind(this)} + > <FormattedMessage - id='user.settings.general.lastName' - defaultMessage='Last Name' + id='user.settings.general.notificationsLink' + defaultMessage='Notifications' /> - </label> - <div className='col-sm-7'> - <input - className='form-control' - type='text' - onChange={this.updateLastName} - value={this.state.lastName} + </a> + ); + + extraInfo = ( + <span> + <FormattedMessage + id='user.settings.general.notificationsExtra' + defaultMessage='By default, you will receive mention notifications when someone types your first name. Go to {notify} settings to change this default.' + values={{ + notify: (notifLink) + }} /> - </div> - </div> - ); + </span> + ); - function notifClick(e) { - e.preventDefault(); - this.updateSection(''); - this.props.updateTab('notifications'); + submit = this.submitName; + } else { + extraInfo = ( + <span> + <FormattedMessage + id='user.settings.general.field_handled_externally' + defaultMessage='This field is handled through your login provider. If you want to change it, you need to do so though your login provider.' + /> + </span> + ); } - const notifLink = ( - <a - href='#' - onClick={notifClick.bind(this)} - > - <FormattedMessage - id='user.settings.general.notificationsLink' - defaultMessage='Notifications' - /> - </a> - ); - - const extraInfo = ( - <span> - <FormattedMessage - id='user.settings.general.notificationsExtra' - defaultMessage='By default, you will receive mention notifications when someone types your first name. Go to {notify} settings to change this default.' - values={{ - notify: (notifLink) - }} - /> - </span> - ); - nameSection = ( <SettingItemMax title={formatMessage(holders.fullName)} inputs={inputs} - submit={this.submitName} + submit={submit} server_error={serverError} client_error={clientError} updateSection={(e) => { @@ -632,47 +647,62 @@ class UserSettingsGeneralTab extends React.Component { let nicknameSection; if (this.props.activeSection === 'nickname') { - let nicknameLabel = ( - <FormattedMessage - id='user.settings.general.nickname' - defaultMessage='Nickname' - /> - ); - if (Utils.isMobile()) { - nicknameLabel = ''; - } - - inputs.push( - <div - key='nicknameSetting' - className='form-group' - > - <label className='col-sm-5 control-label'>{nicknameLabel}</label> - <div className='col-sm-7'> - <input - className='form-control' - type='text' - onChange={this.updateNickname} - value={this.state.nickname} + let extraInfo; + let submit = null; + if (this.props.user.auth_service === 'ldap' && global.window.mm_config.NicknameAttributeSet) { + extraInfo = ( + <span> + <FormattedMessage + id='user.settings.general.field_handled_externally' + defaultMessage='This field is handled through your login provider. If you want to change it, you need to do so though your login provider.' /> - </div> - </div> - ); - - const extraInfo = ( - <span> + </span> + ); + } else { + let nicknameLabel = ( <FormattedMessage - id='user.settings.general.nicknameExtra' - defaultMessage='Use Nickname for a name you might be called that is different from your first name and username. This is most often used when two or more people have similar sounding names and usernames.' + id='user.settings.general.nickname' + defaultMessage='Nickname' /> - </span> - ); + ); + if (Utils.isMobile()) { + nicknameLabel = ''; + } + + inputs.push( + <div + key='nicknameSetting' + className='form-group' + > + <label className='col-sm-5 control-label'>{nicknameLabel}</label> + <div className='col-sm-7'> + <input + className='form-control' + type='text' + onChange={this.updateNickname} + value={this.state.nickname} + /> + </div> + </div> + ); + + extraInfo = ( + <span> + <FormattedMessage + id='user.settings.general.nicknameExtra' + defaultMessage='Use Nickname for a name you might be called that is different from your first name and username. This is most often used when two or more people have similar sounding names and usernames.' + /> + </span> + ); + + submit = this.submitNickname; + } nicknameSection = ( <SettingItemMax title={formatMessage(holders.nickname)} inputs={inputs} - submit={this.submitNickname} + submit={submit} server_error={serverError} client_error={clientError} updateSection={(e) => { @@ -708,48 +738,63 @@ class UserSettingsGeneralTab extends React.Component { let usernameSection; if (this.props.activeSection === 'username') { - let usernameLabel = ( - <FormattedMessage - id='user.settings.general.username' - defaultMessage='Username' - /> - ); - if (Utils.isMobile()) { - usernameLabel = ''; - } + let extraInfo; + let submit = null; + if (this.props.user.auth_service === '') { + let usernameLabel = ( + <FormattedMessage + id='user.settings.general.username' + defaultMessage='Username' + /> + ); + if (Utils.isMobile()) { + usernameLabel = ''; + } - inputs.push( - <div - key='usernameSetting' - className='form-group' - > - <label className='col-sm-5 control-label'>{usernameLabel}</label> - <div className='col-sm-7'> - <input - maxLength={Constants.MAX_USERNAME_LENGTH} - className='form-control' - type='text' - onChange={this.updateUsername} - value={this.state.username} - /> + inputs.push( + <div + key='usernameSetting' + className='form-group' + > + <label className='col-sm-5 control-label'>{usernameLabel}</label> + <div className='col-sm-7'> + <input + maxLength={Constants.MAX_USERNAME_LENGTH} + className='form-control' + type='text' + onChange={this.updateUsername} + value={this.state.username} + /> + </div> </div> - </div> - ); + ); - const extraInfo = ( - <span> - <FormattedMessage - id='user.settings.general.usernameInfo' - defaultMessage='Pick something easy for teammates to recognize and recall.' - /> - </span> - ); + extraInfo = ( + <span> + <FormattedMessage + id='user.settings.general.usernameInfo' + defaultMessage='Pick something easy for teammates to recognize and recall.' + /> + </span> + ); + + submit = this.submitUsername; + } else { + extraInfo = ( + <span> + <FormattedMessage + id='user.settings.general.field_handled_externally' + defaultMessage='This field is handled through your login provider. If you want to change it, you need to do so though your login provider.' + /> + </span> + ); + } usernameSection = ( <SettingItemMax title={formatMessage(holders.username)} inputs={inputs} - submit={this.submitUsername} + submit={submit} server_error={serverError} client_error={clientError} updateSection={(e) => { |