diff --git a/app/controllers/api/v1/profiles_controller.rb b/app/controllers/api/v1/profiles_controller.rb
index c59edfce0..5805f49ed 100644
--- a/app/controllers/api/v1/profiles_controller.rb
+++ b/app/controllers/api/v1/profiles_controller.rb
@@ -6,6 +6,12 @@ class Api::V1::ProfilesController < Api::BaseController
end
def update
+ if password_params[:password].present?
+ render_could_not_create_error('Invalid current password') and return unless @user.valid_password?(password_params[:current_password])
+
+ @user.update!(password_params.except(:current_password))
+ end
+
@user.update!(profile_params)
end
@@ -20,11 +26,17 @@ class Api::V1::ProfilesController < Api::BaseController
:email,
:name,
:display_name,
- :password,
- :password_confirmation,
:avatar,
:availability,
ui_settings: {}
)
end
+
+ def password_params
+ params.require(:profile).permit(
+ :current_password,
+ :password,
+ :password_confirmation
+ )
+ end
end
diff --git a/app/javascript/dashboard/i18n/locale/en/settings.json b/app/javascript/dashboard/i18n/locale/en/settings.json
index 314bbbbda..aa51c35be 100644
--- a/app/javascript/dashboard/i18n/locale/en/settings.json
+++ b/app/javascript/dashboard/i18n/locale/en/settings.json
@@ -74,6 +74,11 @@
"ERROR": "Please enter a valid email address",
"PLACEHOLDER": "Please enter your email address, this would be displayed in conversations"
},
+ "CURRENT_PASSWORD": {
+ "LABEL": "Current password",
+ "ERROR": "Please enter the current password",
+ "PLACEHOLDER": "Please enter the current password"
+ },
"PASSWORD": {
"LABEL": "Password",
"ERROR": "Please enter a password of length 6 or more",
diff --git a/app/javascript/dashboard/routes/dashboard/settings/profile/ChangePassword.vue b/app/javascript/dashboard/routes/dashboard/settings/profile/ChangePassword.vue
new file mode 100644
index 000000000..2b226add9
--- /dev/null
+++ b/app/javascript/dashboard/routes/dashboard/settings/profile/ChangePassword.vue
@@ -0,0 +1,152 @@
+
+
+
+
+
+
+
diff --git a/app/javascript/dashboard/routes/dashboard/settings/profile/Index.vue b/app/javascript/dashboard/routes/dashboard/settings/profile/Index.vue
index 90d6f7012..93d965421 100644
--- a/app/javascript/dashboard/routes/dashboard/settings/profile/Index.vue
+++ b/app/javascript/dashboard/routes/dashboard/settings/profile/Index.vue
@@ -55,53 +55,7 @@
-
@@ -123,10 +77,12 @@ import { mapGetters } from 'vuex';
import { clearCookiesOnLogout } from '../../../../store/utils/api';
import NotificationSettings from './NotificationSettings';
import alertMixin from 'shared/mixins/alertMixin';
+import ChangePassword from './ChangePassword.vue';
export default {
components: {
NotificationSettings,
+ ChangePassword,
},
mixins: [alertMixin],
data() {
@@ -136,10 +92,8 @@ export default {
name: '',
displayName: '',
email: '',
- password: '',
- passwordConfirmation: '',
isProfileUpdating: false,
- isPasswordChanging: false,
+ errorMessage: '',
};
},
validations: {
@@ -152,18 +106,6 @@ export default {
required,
email,
},
- password: {
- minLength: minLength(6),
- },
- passwordConfirmation: {
- minLength: minLength(6),
- isEqPassword(value) {
- if (value !== this.password) {
- return false;
- }
- return true;
- },
- },
},
computed: {
...mapGetters({
@@ -190,41 +132,36 @@ export default {
this.avatarUrl = this.currentUser.avatar_url;
this.displayName = this.currentUser.display_name;
},
- async updateUser(type) {
+ async updateUser() {
this.$v.$touch();
if (this.$v.$invalid) {
this.showAlert(this.$t('PROFILE_SETTINGS.FORM.ERROR'));
return;
}
- if (type === 'profile') {
- this.isProfileUpdating = true;
- } else if (type === 'password') {
- this.isPasswordChanging = true;
- }
+
+ this.isProfileUpdating = true;
const hasEmailChanged = this.currentUser.email !== this.email;
try {
await this.$store.dispatch('updateProfile', {
name: this.name,
email: this.email,
avatar: this.avatarFile,
- password: this.password,
displayName: this.displayName,
- password_confirmation: this.passwordConfirmation,
});
this.isProfileUpdating = false;
- this.isPasswordChanging = false;
if (hasEmailChanged) {
clearCookiesOnLogout();
- this.showAlert(this.$t('PROFILE_SETTINGS.AFTER_EMAIL_CHANGED'));
- }
- if (type === 'profile') {
- this.showAlert(this.$t('PROFILE_SETTINGS.UPDATE_SUCCESS'));
- } else if (type === 'password') {
- this.showAlert(this.$t('PROFILE_SETTINGS.PASSWORD_UPDATE_SUCCESS'));
+ this.errorMessage = this.$t('PROFILE_SETTINGS.AFTER_EMAIL_CHANGED');
}
+ this.errorMessage = this.$t('PROFILE_SETTINGS.UPDATE_SUCCESS');
} catch (error) {
+ this.errorMessage = this.$t('RESET_PASSWORD.API.ERROR_MESSAGE');
+ if (error?.response?.data?.error) {
+ this.errorMessage = error.response.data.error;
+ }
+ } finally {
this.isProfileUpdating = false;
- this.isPasswordChanging = false;
+ this.showAlert(this.errorMessage);
}
},
handleImageUpload({ file, url }) {
diff --git a/app/javascript/dashboard/store/modules/auth.js b/app/javascript/dashboard/store/modules/auth.js
index 3cdc045d1..1ed23a41a 100644
--- a/app/javascript/dashboard/store/modules/auth.js
+++ b/app/javascript/dashboard/store/modules/auth.js
@@ -102,12 +102,13 @@ export const actions = {
},
updateProfile: async ({ commit }, params) => {
+ // eslint-disable-next-line no-useless-catch
try {
const response = await authAPI.profileUpdate(params);
setUser(response.data, getHeaderExpiry(response));
commit(types.default.SET_CURRENT_USER);
} catch (error) {
- // Ignore error
+ throw error;
}
},
diff --git a/spec/controllers/api/v1/profiles_controller_spec.rb b/spec/controllers/api/v1/profiles_controller_spec.rb
index 4282b02a7..0a936c6d4 100644
--- a/spec/controllers/api/v1/profiles_controller_spec.rb
+++ b/spec/controllers/api/v1/profiles_controller_spec.rb
@@ -39,7 +39,7 @@ RSpec.describe 'Profile API', type: :request do
end
context 'when it is an authenticated user' do
- let(:agent) { create(:user, account: account, role: :agent) }
+ let(:agent) { create(:user, password: 'Test123!', account: account, role: :agent) }
it 'updates the name & email' do
new_email = Faker::Internet.email
@@ -56,13 +56,23 @@ RSpec.describe 'Profile API', type: :request do
expect(agent.email).to eq(new_email)
end
- it 'updates the password' do
+ it 'updates the password when current password is provided' do
put '/api/v1/profile',
- params: { profile: { password: 'test123', password_confirmation: 'test123' } },
+ params: { profile: { current_password: 'Test123!', password: 'test123', password_confirmation: 'test123' } },
headers: agent.create_new_auth_token,
as: :json
expect(response).to have_http_status(:success)
+ expect(agent.reload.valid_password?('test123')).to eq true
+ end
+
+ it 'throws error when current password provided is invalid' do
+ put '/api/v1/profile',
+ params: { profile: { current_password: 'Test', password: 'test123', password_confirmation: 'test123' } },
+ headers: agent.create_new_auth_token,
+ as: :json
+
+ expect(response).to have_http_status(:unprocessable_entity)
end
it 'updates avatar' do