Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6af34335a8 |
@@ -38,6 +38,11 @@ class Api::V1::ProfilesController < Api::BaseController
|
|||||||
head :ok
|
head :ok
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def reset_access_token
|
||||||
|
@user.access_token.regenerate_token
|
||||||
|
@user.reload
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def set_user
|
def set_user
|
||||||
|
|||||||
@@ -102,4 +102,8 @@ export default {
|
|||||||
const urlData = endPoints('resendConfirmation');
|
const urlData = endPoints('resendConfirmation');
|
||||||
return axios.post(urlData.url);
|
return axios.post(urlData.url);
|
||||||
},
|
},
|
||||||
|
resetAccessToken() {
|
||||||
|
const urlData = endPoints('resetAccessToken');
|
||||||
|
return axios.post(urlData.url);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -51,6 +51,9 @@ const endPoints = {
|
|||||||
resendConfirmation: {
|
resendConfirmation: {
|
||||||
url: '/api/v1/profile/resend_confirmation',
|
url: '/api/v1/profile/resend_confirmation',
|
||||||
},
|
},
|
||||||
|
resetAccessToken: {
|
||||||
|
url: '/api/v1/profile/reset_access_token',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default page => {
|
export default page => {
|
||||||
|
|||||||
@@ -76,7 +76,10 @@
|
|||||||
"ACCESS_TOKEN": {
|
"ACCESS_TOKEN": {
|
||||||
"TITLE": "Access Token",
|
"TITLE": "Access Token",
|
||||||
"NOTE": "This token can be used if you are building an API based integration",
|
"NOTE": "This token can be used if you are building an API based integration",
|
||||||
"COPY": "Copy"
|
"COPY": "Copy",
|
||||||
|
"RESET": "Reset",
|
||||||
|
"RESET_SUCCESS": "Access token regenerated",
|
||||||
|
"RESET_ERROR": "Could not reset token"
|
||||||
},
|
},
|
||||||
"AUDIO_NOTIFICATIONS_SECTION": {
|
"AUDIO_NOTIFICATIONS_SECTION": {
|
||||||
"TITLE": "Audio Alerts",
|
"TITLE": "Audio Alerts",
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ const props = defineProps({
|
|||||||
default: '',
|
default: '',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const emit = defineEmits(['onCopy']);
|
const emit = defineEmits(['onCopy', 'onReset']);
|
||||||
const inputType = ref('password');
|
const inputType = ref('password');
|
||||||
const toggleMasked = () => {
|
const toggleMasked = () => {
|
||||||
inputType.value = inputType.value === 'password' ? 'text' : 'password';
|
inputType.value = inputType.value === 'password' ? 'text' : 'password';
|
||||||
@@ -20,6 +20,10 @@ const maskIcon = computed(() => {
|
|||||||
const onClick = () => {
|
const onClick = () => {
|
||||||
emit('onCopy', props.value);
|
emit('onCopy', props.value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onReset = () => {
|
||||||
|
emit('onReset');
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -56,5 +60,15 @@ const onClick = () => {
|
|||||||
>
|
>
|
||||||
{{ $t('PROFILE_SETTINGS.FORM.ACCESS_TOKEN.COPY') }}
|
{{ $t('PROFILE_SETTINGS.FORM.ACCESS_TOKEN.COPY') }}
|
||||||
</FormButton>
|
</FormButton>
|
||||||
|
<FormButton
|
||||||
|
type="button"
|
||||||
|
size="large"
|
||||||
|
icon="key"
|
||||||
|
variant="outline"
|
||||||
|
color-scheme="primary"
|
||||||
|
@click="onReset"
|
||||||
|
>
|
||||||
|
{{ $t('PROFILE_SETTINGS.FORM.ACCESS_TOKEN.RESET') }}
|
||||||
|
</FormButton>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -181,6 +181,14 @@ export default {
|
|||||||
await copyTextToClipboard(value);
|
await copyTextToClipboard(value);
|
||||||
useAlert(this.$t('COMPONENTS.CODE.COPY_SUCCESSFUL'));
|
useAlert(this.$t('COMPONENTS.CODE.COPY_SUCCESSFUL'));
|
||||||
},
|
},
|
||||||
|
async resetAccessToken() {
|
||||||
|
const success = await this.$store.dispatch('resetAccessToken');
|
||||||
|
if (success) {
|
||||||
|
useAlert(this.$t('PROFILE_SETTINGS.FORM.ACCESS_TOKEN.RESET_SUCCESS'));
|
||||||
|
} else {
|
||||||
|
useAlert(this.$t('PROFILE_SETTINGS.FORM.ACCESS_TOKEN.RESET_ERROR'));
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
@@ -281,7 +289,11 @@ export default {
|
|||||||
)
|
)
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
<AccessToken :value="currentUser.access_token" @on-copy="onCopyToken" />
|
<AccessToken
|
||||||
|
:value="currentUser.access_token"
|
||||||
|
@on-copy="onCopyToken"
|
||||||
|
@on-reset="resetAccessToken"
|
||||||
|
/>
|
||||||
</FormSection>
|
</FormSection>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -213,6 +213,16 @@ export const actions = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
resetAccessToken: async ({ commit }) => {
|
||||||
|
try {
|
||||||
|
const response = await authAPI.resetAccessToken();
|
||||||
|
commit(types.SET_CURRENT_USER, response.data);
|
||||||
|
return true;
|
||||||
|
} catch (error) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
resendConfirmation: async () => {
|
resendConfirmation: async () => {
|
||||||
try {
|
try {
|
||||||
await authAPI.resendConfirmation();
|
await authAPI.resendConfirmation();
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
json.partial! 'api/v1/models/user', formats: [:json], resource: @user
|
||||||
@@ -16,16 +16,13 @@ development:
|
|||||||
<<: *default
|
<<: *default
|
||||||
database: "<%= ENV.fetch('POSTGRES_DATABASE', 'chatwoot_dev') %>"
|
database: "<%= ENV.fetch('POSTGRES_DATABASE', 'chatwoot_dev') %>"
|
||||||
username: "<%= ENV.fetch('POSTGRES_USERNAME', 'postgres') %>"
|
username: "<%= ENV.fetch('POSTGRES_USERNAME', 'postgres') %>"
|
||||||
password: "<%= ENV.fetch('POSTGRES_PASSWORD', '') %>"
|
|
||||||
|
|
||||||
test:
|
test:
|
||||||
<<: *default
|
<<: *default
|
||||||
database: "<%= ENV.fetch('POSTGRES_DATABASE', 'chatwoot_test') %>"
|
database: "<%= ENV.fetch('POSTGRES_DATABASE', 'chatwoot_test') %>"
|
||||||
username: "<%= ENV.fetch('POSTGRES_USERNAME', 'postgres') %>"
|
username: "<%= ENV.fetch('POSTGRES_USERNAME', 'postgres') %>"
|
||||||
password: "<%= ENV.fetch('POSTGRES_PASSWORD', '') %>"
|
|
||||||
|
|
||||||
production:
|
production:
|
||||||
<<: *default
|
<<: *default
|
||||||
database: "<%= ENV.fetch('POSTGRES_DATABASE', 'chatwoot_production') %>"
|
database: "<%= ENV.fetch('POSTGRES_DATABASE', 'chatwoot_production') %>"
|
||||||
username: "<%= ENV.fetch('POSTGRES_USERNAME', 'chatwoot_prod') %>"
|
username: "<%= ENV.fetch('POSTGRES_USERNAME', 'chatwoot_prod') %>"
|
||||||
password: "<%= ENV.fetch('POSTGRES_PASSWORD', 'chatwoot_prod') %>"
|
|
||||||
|
|||||||
@@ -295,6 +295,7 @@ Rails.application.routes.draw do
|
|||||||
post :auto_offline
|
post :auto_offline
|
||||||
put :set_active_account
|
put :set_active_account
|
||||||
post :resend_confirmation
|
post :resend_confirmation
|
||||||
|
post :reset_access_token
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -296,4 +296,32 @@ RSpec.describe 'Profile API', type: :request do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'POST /api/v1/profile/reset_access_token' do
|
||||||
|
context 'when it is an unauthenticated user' do
|
||||||
|
it 'returns unauthorized' do
|
||||||
|
post '/api/v1/profile/reset_access_token'
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:unauthorized)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when it is an authenticated user' do
|
||||||
|
let(:agent) { create(:user, account: account, role: :agent) }
|
||||||
|
|
||||||
|
it 'regenerates the access token' do
|
||||||
|
old_token = agent.access_token.token
|
||||||
|
|
||||||
|
post '/api/v1/profile/reset_access_token',
|
||||||
|
headers: agent.create_new_auth_token,
|
||||||
|
as: :json
|
||||||
|
|
||||||
|
expect(response).to have_http_status(:success)
|
||||||
|
agent.reload
|
||||||
|
json_response = response.parsed_body
|
||||||
|
expect(json_response['access_token']).to eq(agent.access_token.token)
|
||||||
|
expect(agent.access_token.token).not_to eq(old_token)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user