Skip to content
代码片段 群组 项目
未验证 提交 25020eb5 编辑于 作者: Eduardo Sanz García's avatar Eduardo Sanz García 提交者: GitLab
浏览文件

Merge branch 'eduardosanz/refactor-access-token-store' into 'master'

No related branches found
No related tags found
2 合并请求!3031Merge per-main-jh to main-jh by luzhiyuan,!3030Merge per-main-jh to main-jh
...@@ -10,13 +10,19 @@ import { ...@@ -10,13 +10,19 @@ import {
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import { SORT_OPTIONS, DEFAULT_SORT } from '~/access_tokens/constants'; import { SORT_OPTIONS, DEFAULT_SORT } from '~/access_tokens/constants';
/**
* @typedef {{type: string, value: {data: string, operator: string}}} Filter
* @typedef {Array<string|Filter>} Filters
*/
/** /**
* Fetch access tokens * Fetch access tokens
* *
* @param {string} url * @param {Object} options
* @param {string|number} id * @param {string} options.url
* @param {Object<string, string|number>} params * @param {string|number} options.id
* @param {string} sort * @param {Object<string, string|number>} options.params
* @param {string} options.sort
*/ */
const fetchTokens = async ({ url, id, params, sort }) => { const fetchTokens = async ({ url, id, params, sort }) => {
const { data, headers } = await axios.get(url, { const { data, headers } = await axios.get(url, {
...@@ -32,6 +38,7 @@ export const useAccessTokens = defineStore('accessTokens', { ...@@ -32,6 +38,7 @@ export const useAccessTokens = defineStore('accessTokens', {
return { return {
alert: null, alert: null,
busy: false, busy: false,
/** @type {Filters} */
filters: [], filters: [],
id: null, id: null,
page: 1, page: 1,
...@@ -69,6 +76,9 @@ export const useAccessTokens = defineStore('accessTokens', { ...@@ -69,6 +76,9 @@ export const useAccessTokens = defineStore('accessTokens', {
this.busy = false; this.busy = false;
} }
}, },
/**
* @param {number} tokenId
*/
async revokeToken(tokenId) { async revokeToken(tokenId) {
this.alert?.dismiss(); this.alert?.dismiss();
this.busy = true; this.busy = true;
...@@ -92,17 +102,21 @@ export const useAccessTokens = defineStore('accessTokens', { ...@@ -92,17 +102,21 @@ export const useAccessTokens = defineStore('accessTokens', {
this.busy = false; this.busy = false;
} }
}, },
/**
* @param {number} tokenId
* @param {string} expiresAt
*/
async rotateToken(tokenId, expiresAt) { async rotateToken(tokenId, expiresAt) {
this.alert?.dismiss(); this.alert?.dismiss();
this.busy = true; this.busy = true;
try { try {
const url = this.urlRotate.replace(':id', this.id); const url = this.urlRotate.replace(':id', this.id);
const { data } = await axios.post(`${url}/${tokenId}/rotate`, { expires_at: expiresAt }); const { data } = await axios.post(`${url}/${tokenId}/rotate`, { expires_at: expiresAt });
this.token = data.token;
smoothScrollTop(); smoothScrollTop();
// Reset pagination because after rotation the token may appear on a different page. // Reset pagination because after rotation the token may appear on a different page.
this.page = 1; this.page = 1;
await this.fetchTokens({ clearAlert: false }); await this.fetchTokens({ clearAlert: false });
this.token = data.token;
} catch (error) { } catch (error) {
const message = const message =
error?.response?.data?.message ?? error?.response?.data?.message ??
...@@ -112,29 +126,50 @@ export const useAccessTokens = defineStore('accessTokens', { ...@@ -112,29 +126,50 @@ export const useAccessTokens = defineStore('accessTokens', {
this.busy = false; this.busy = false;
} }
}, },
setup({ filters, id, urlRevoke, urlRotate, urlShow }) { /**
this.filters = filters; * @param {Filters} filters
this.id = id; */
this.urlRevoke = urlRevoke;
this.urlRotate = urlRotate;
this.urlShow = urlShow;
},
setFilters(filters) { setFilters(filters) {
this.filters = filters; this.filters = filters;
}, },
/**
* @param {number} page
*/
setPage(page) { setPage(page) {
smoothScrollTop(); smoothScrollTop();
this.page = page; this.page = page;
}, },
/**
* @param {string} token
*/
setToken(token) { setToken(token) {
this.token = token; this.token = token;
}, },
/**
* @param {{isAsc: boolean, value: string}} sorting
*/
setSorting(sorting) { setSorting(sorting) {
this.sorting = sorting; this.sorting = sorting;
}, },
/**
* @param {Object} options
* @param {Filters} options.filters
* @param {number} options.id
* @param {string} options.urlRevoke
* @param {string} options.urlRotate
* @param {string} options.urlShow
*/
setup({ filters, id, urlRevoke, urlRotate, urlShow }) {
this.filters = filters;
this.id = id;
this.urlRevoke = urlRevoke;
this.urlRotate = urlRotate;
this.urlShow = urlShow;
},
}, },
getters: { getters: {
params() { params() {
/** @type {Object<string, number|string>} */
const newParams = { page: this.page }; const newParams = { page: this.page };
this.filters?.forEach((token) => { this.filters?.forEach((token) => {
......
...@@ -64,18 +64,6 @@ describe('useAccessTokens store', () => { ...@@ -64,18 +64,6 @@ describe('useAccessTokens store', () => {
mockAxios.reset(); mockAxios.reset();
}); });
describe('setup', () => {
it('sets up the store', async () => {
await store.setup({ filters, id, urlRevoke, urlRotate, urlShow });
expect(store.filters).toEqual(filters);
expect(store.id).toBe(id);
expect(store.urlRevoke).toBe(urlRevoke);
expect(store.urlRotate).toBe(urlRotate);
expect(store.urlShow).toBe(urlShow);
});
});
describe('fetchTokens', () => { describe('fetchTokens', () => {
beforeEach(() => { beforeEach(() => {
store.setup({ id, filters, urlShow }); store.setup({ id, filters, urlShow });
...@@ -236,6 +224,11 @@ describe('useAccessTokens store', () => { ...@@ -236,6 +224,11 @@ describe('useAccessTokens store', () => {
await store.revokeToken(1); await store.revokeToken(1);
expect(createAlert).toHaveBeenCalledTimes(2); expect(createAlert).toHaveBeenCalledTimes(2);
expect(createAlert).toHaveBeenCalledWith({
message: 'The token was revoked successfully.',
variant: 'success',
});
// This alert hides the one above.
expect(createAlert).toHaveBeenCalledWith({ expect(createAlert).toHaveBeenCalledWith({
message: 'An error occurred while fetching the tokens.', message: 'An error occurred while fetching the tokens.',
}); });
...@@ -294,14 +287,14 @@ describe('useAccessTokens store', () => { ...@@ -294,14 +287,14 @@ describe('useAccessTokens store', () => {
}); });
it('scrolls to the top', async () => { it('scrolls to the top', async () => {
mockAxios.onPost().replyOnce(HTTP_STATUS_NO_CONTENT); mockAxios.onPost().replyOnce(HTTP_STATUS_OK, { token: 'new-token' });
await store.rotateToken(1, '2025-01-01'); await store.rotateToken(1, '2025-01-01');
expect(smoothScrollTop).toHaveBeenCalledTimes(1); expect(smoothScrollTop).toHaveBeenCalledTimes(1);
}); });
it('updates tokens and sets busy to false after fetching', async () => { it('updates tokens and sets busy to false after fetching', async () => {
mockAxios.onPost().replyOnce(HTTP_STATUS_NO_CONTENT); mockAxios.onPost().replyOnce(HTTP_STATUS_OK, { token: 'new-token' });
mockAxios.onGet().replyOnce(HTTP_STATUS_OK, [{ active: true, name: 'Token' }], headers); mockAxios.onGet().replyOnce(HTTP_STATUS_OK, [{ active: true, name: 'Token' }], headers);
await store.rotateToken(1, '2025-01-01'); await store.rotateToken(1, '2025-01-01');
...@@ -321,11 +314,11 @@ describe('useAccessTokens store', () => { ...@@ -321,11 +314,11 @@ describe('useAccessTokens store', () => {
}); });
it('shows an alert if an error occurs while fetching', async () => { it('shows an alert if an error occurs while fetching', async () => {
mockAxios.onPost().replyOnce(HTTP_STATUS_NO_CONTENT); mockAxios.onPost().replyOnce(HTTP_STATUS_OK, { token: 'new-token' });
mockAxios.onGet().replyOnce(HTTP_STATUS_INTERNAL_SERVER_ERROR); mockAxios.onGet().replyOnce(HTTP_STATUS_INTERNAL_SERVER_ERROR);
await store.rotateToken(1, '2025-01-01'); await store.rotateToken(1, '2025-01-01');
expect(createAlert).toHaveBeenCalledTimes(2); expect(createAlert).toHaveBeenCalledTimes(1);
expect(createAlert).toHaveBeenCalledWith({ expect(createAlert).toHaveBeenCalledWith({
message: 'An error occurred while fetching the tokens.', message: 'An error occurred while fetching the tokens.',
}); });
...@@ -333,7 +326,7 @@ describe('useAccessTokens store', () => { ...@@ -333,7 +326,7 @@ describe('useAccessTokens store', () => {
}); });
it('uses correct params in the fetch', async () => { it('uses correct params in the fetch', async () => {
mockAxios.onPost().replyOnce(HTTP_STATUS_NO_CONTENT); mockAxios.onPost().replyOnce(HTTP_STATUS_OK, { token: 'new-token' });
mockAxios.onGet().replyOnce(HTTP_STATUS_OK, [{ active: true, name: 'Token' }], headers); mockAxios.onGet().replyOnce(HTTP_STATUS_OK, [{ active: true, name: 'Token' }], headers);
store.setPage(2); store.setPage(2);
store.setFilters(['my token']); store.setFilters(['my token']);
...@@ -353,6 +346,14 @@ describe('useAccessTokens store', () => { ...@@ -353,6 +346,14 @@ describe('useAccessTokens store', () => {
}); });
}); });
describe('setFilters', () => {
it('sets the filters', () => {
store.setFilters(['my token']);
expect(store.filters).toEqual(['my token']);
});
});
describe('setPage', () => { describe('setPage', () => {
it('sets the page', () => { it('sets the page', () => {
store.setPage(2); store.setPage(2);
...@@ -369,29 +370,41 @@ describe('useAccessTokens store', () => { ...@@ -369,29 +370,41 @@ describe('useAccessTokens store', () => {
describe('setToken', () => { describe('setToken', () => {
it('sets the token', () => { it('sets the token', () => {
store.setToken(2); store.setToken('new-token');
expect(store.token).toBe(2); expect(store.token).toBe('new-token');
}); });
}); });
describe('setSorting', () => { describe('setSorting', () => {
it('sets the sorting', () => { it('sets the sorting', () => {
store.setSorting({ value: 'name', isAsc: false }); store.setSorting({ isAsc: false, value: 'name' });
expect(store.sorting).toEqual({ isAsc: false, value: 'name' });
});
});
describe('setup', () => {
it('sets up the store', async () => {
await store.setup({ filters, id, urlRevoke, urlRotate, urlShow });
expect(store.sorting).toEqual({ value: 'name', isAsc: false }); expect(store.filters).toEqual(filters);
expect(store.id).toBe(id);
expect(store.urlRevoke).toBe(urlRevoke);
expect(store.urlRotate).toBe(urlRotate);
expect(store.urlShow).toBe(urlShow);
}); });
}); });
});
describe('getters', () => { describe('getters', () => {
describe('sort', () => { describe('sort', () => {
it('returns correct value', () => { it('returns correct value', () => {
expect(store.sort).toBe('expires_at_asc_id_desc'); expect(store.sort).toBe('expires_at_asc_id_desc');
store.sorting = { value: 'name', isAsc: false }; store.sorting = { value: 'name', isAsc: false };
expect(store.sort).toBe('name_desc'); expect(store.sort).toBe('name_desc');
});
}); });
}); });
}); });
......
0% 加载中 .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册