mirror of
https://github.com/strapi/strapi.git
synced 2025-08-07 08:16:35 +00:00
Merge branch 'features/api-token-v2' into api-token-v2/regenerate-an-api-token
This commit is contained in:
commit
c641c5d71d
@ -119,7 +119,15 @@ const ApiTokenCreateView = () => {
|
||||
|
||||
toggleNotification({
|
||||
type: 'success',
|
||||
message: formatMessage({ id: 'notification.success.saved', defaultMessage: 'Saved' }),
|
||||
message: isCreating
|
||||
? formatMessage({
|
||||
id: 'notification.success.tokencreated',
|
||||
defaultMessage: 'API Token successfully created',
|
||||
})
|
||||
: formatMessage({
|
||||
id: 'notification.success.tokenedited',
|
||||
defaultMessage: 'API Token successfully edited',
|
||||
}),
|
||||
});
|
||||
|
||||
trackUsageRef.current(isCreating ? 'didCreateToken' : 'didEditToken', {
|
||||
|
@ -1,5 +1,4 @@
|
||||
import React from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
|
||||
@ -13,13 +12,11 @@ import {
|
||||
pxToRem,
|
||||
useTracking,
|
||||
} from '@strapi/helper-plugin';
|
||||
|
||||
import DeleteButton from './DeleteButton';
|
||||
import UpdateButton from './UpdateButton';
|
||||
import ReadButton from './ReadButton';
|
||||
|
||||
const TableRows = ({ canDelete, canUpdate, canRead, onClickDelete, withBulkActions, rows }) => {
|
||||
const { formatMessage } = useIntl();
|
||||
const [{ query }] = useQueryParams();
|
||||
const [, sortOrder] = query.sort.split(':');
|
||||
const {
|
||||
@ -60,16 +57,15 @@ const TableRows = ({ canDelete, canUpdate, canRead, onClickDelete, withBulkActio
|
||||
</Td>
|
||||
<Td>
|
||||
<Typography textColor="neutral800">
|
||||
{formatMessage({
|
||||
id: `Settings.apiTokens.types.${apiToken.type}`,
|
||||
defaultMessage: 'Type unknown',
|
||||
})}
|
||||
<RelativeTime timestamp={new Date(apiToken.createdAt)} />
|
||||
</Typography>
|
||||
</Td>
|
||||
<Td>
|
||||
<Typography textColor="neutral800">
|
||||
<RelativeTime timestamp={new Date(apiToken.createdAt)} />
|
||||
</Typography>
|
||||
{apiToken.lastUsedAt && (
|
||||
<Typography textColor="neutral800">
|
||||
<RelativeTime timestamp={new Date(apiToken.lastUsedAt)} />
|
||||
</Typography>
|
||||
)}
|
||||
</Td>
|
||||
|
||||
{withBulkActions && (
|
||||
|
@ -806,10 +806,10 @@ describe('ADMIN | Pages | API TOKENS | ListPage', () => {
|
||||
<span
|
||||
aria-labelledby="tooltip-5"
|
||||
class="c23"
|
||||
label="Token type"
|
||||
label="Created at"
|
||||
tabindex="-1"
|
||||
>
|
||||
Token type
|
||||
Created at
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
@ -828,10 +828,10 @@ describe('ADMIN | Pages | API TOKENS | ListPage', () => {
|
||||
<span
|
||||
aria-labelledby="tooltip-7"
|
||||
class="c23"
|
||||
label="Created at"
|
||||
label="Last used"
|
||||
tabindex="-1"
|
||||
>
|
||||
Created at
|
||||
Last used
|
||||
</span>
|
||||
</span>
|
||||
<span
|
||||
@ -893,17 +893,6 @@ describe('ADMIN | Pages | API TOKENS | ListPage', () => {
|
||||
aria-colindex="3"
|
||||
class="c21"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
class="c33"
|
||||
>
|
||||
Type unknown
|
||||
</span>
|
||||
</td>
|
||||
<td
|
||||
aria-colindex="4"
|
||||
class="c21"
|
||||
tabindex="-1"
|
||||
>
|
||||
<span
|
||||
class="c33"
|
||||
@ -916,6 +905,11 @@ describe('ADMIN | Pages | API TOKENS | ListPage', () => {
|
||||
</time>
|
||||
</span>
|
||||
</td>
|
||||
<td
|
||||
aria-colindex="4"
|
||||
class="c21"
|
||||
tabindex="-1"
|
||||
/>
|
||||
<td
|
||||
aria-colindex="5"
|
||||
class="c21"
|
||||
|
@ -21,17 +21,6 @@ const tableHeaders = [
|
||||
sortable: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'type',
|
||||
key: 'type',
|
||||
metadatas: {
|
||||
label: {
|
||||
id: 'Settings.apiTokens.ListView.headers.type',
|
||||
defaultMessage: 'Token type',
|
||||
},
|
||||
sortable: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'createdAt',
|
||||
key: 'createdAt',
|
||||
@ -43,6 +32,17 @@ const tableHeaders = [
|
||||
sortable: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'lastUsedAt',
|
||||
key: 'lastUsedAt',
|
||||
metadatas: {
|
||||
label: {
|
||||
id: 'Settings.apiTokens.ListView.headers.lastUsedAt',
|
||||
defaultMessage: 'Last used',
|
||||
},
|
||||
sortable: false,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export default tableHeaders;
|
||||
|
@ -76,7 +76,7 @@ const permissions = {
|
||||
update: [{ action: 'admin::webhooks.update', subject: null }],
|
||||
},
|
||||
'api-tokens': {
|
||||
main: [],
|
||||
main: [{ action: 'admin::api-tokens.access', subject: null }],
|
||||
create: [{ action: 'admin::api-tokens.create', subject: null }],
|
||||
delete: [{ action: 'admin::api-tokens.delete', subject: null }],
|
||||
read: [{ action: 'admin::api-tokens.read', subject: null }],
|
||||
|
@ -91,6 +91,7 @@
|
||||
"Settings.apiTokens.ListView.headers.description": "Description",
|
||||
"Settings.apiTokens.ListView.headers.type": "Token type",
|
||||
"Settings.apiTokens.ListView.headers.createdAt": "Created at",
|
||||
"Settings.apiTokens.ListView.headers.lastUsedAt": "Last used",
|
||||
"Settings.apiTokens.notification.copied": "Token copied to clipboard.",
|
||||
"Settings.apiTokens.title": "API Tokens",
|
||||
"Settings.apiTokens.types.full-access": "Full access",
|
||||
@ -768,6 +769,8 @@
|
||||
"notification.success.delete": "The item has been deleted",
|
||||
"notification.success.saved": "Saved",
|
||||
"notification.success.title": "Success:",
|
||||
"notification.success.tokencreated": "API Token successfully created",
|
||||
"notification.success.tokenedited": "API Token successfully edited",
|
||||
"notification.version.update.message": "A new version of Strapi is available!",
|
||||
"notification.warning.title": "Warning:",
|
||||
"notification.warning.404": "404 - Not found",
|
||||
|
@ -118,12 +118,21 @@ module.exports = {
|
||||
category: 'users and roles',
|
||||
subCategory: 'roles',
|
||||
},
|
||||
{
|
||||
uid: 'api-tokens.access',
|
||||
displayName: 'Access the API tokens settings page',
|
||||
pluginName: 'admin',
|
||||
section: 'settings',
|
||||
category: 'api tokens',
|
||||
subCategory: 'api Tokens',
|
||||
},
|
||||
{
|
||||
uid: 'api-tokens.create',
|
||||
displayName: 'Create (generate)',
|
||||
pluginName: 'admin',
|
||||
section: 'settings',
|
||||
category: 'api tokens',
|
||||
subCategory: 'general',
|
||||
},
|
||||
{
|
||||
uid: 'api-tokens.read',
|
||||
@ -131,6 +140,7 @@ module.exports = {
|
||||
pluginName: 'admin',
|
||||
section: 'settings',
|
||||
category: 'api tokens',
|
||||
subCategory: 'general',
|
||||
},
|
||||
{
|
||||
uid: 'api-tokens.update',
|
||||
@ -138,6 +148,7 @@ module.exports = {
|
||||
pluginName: 'admin',
|
||||
section: 'settings',
|
||||
category: 'api tokens',
|
||||
subCategory: 'general',
|
||||
},
|
||||
{
|
||||
uid: 'api-tokens.delete',
|
||||
@ -145,6 +156,7 @@ module.exports = {
|
||||
pluginName: 'admin',
|
||||
section: 'settings',
|
||||
category: 'api tokens',
|
||||
subCategory: 'general',
|
||||
},
|
||||
{
|
||||
uid: 'project-settings.update',
|
||||
|
@ -258,6 +258,62 @@ describe('API Token Controller', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Regenerate an API token', () => {
|
||||
const token = {
|
||||
id: 1,
|
||||
name: 'api-token_tests-regenerate',
|
||||
description: 'api-token_tests-description',
|
||||
type: 'read-only',
|
||||
};
|
||||
|
||||
test('Regenerates an API token successfully', async () => {
|
||||
const regenerate = jest.fn().mockResolvedValue(token);
|
||||
const getById = jest.fn().mockResolvedValue(token);
|
||||
const created = jest.fn();
|
||||
const ctx = createContext({ params: { id: token.id } }, { created });
|
||||
|
||||
global.strapi = {
|
||||
admin: {
|
||||
services: {
|
||||
'api-token': {
|
||||
regenerate,
|
||||
getById,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
await apiTokenController.regenerate(ctx);
|
||||
|
||||
expect(regenerate).toHaveBeenCalledWith(token.id);
|
||||
});
|
||||
|
||||
test('Fails if token not found', async () => {
|
||||
const regenerate = jest.fn().mockResolvedValue(token);
|
||||
const getById = jest.fn().mockResolvedValue(null);
|
||||
const created = jest.fn();
|
||||
const notFound = jest.fn();
|
||||
const ctx = createContext({ params: { id: token.id } }, { created, notFound });
|
||||
|
||||
global.strapi = {
|
||||
admin: {
|
||||
services: {
|
||||
'api-token': {
|
||||
regenerate,
|
||||
getById,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
await apiTokenController.regenerate(ctx);
|
||||
|
||||
expect(regenerate).not.toHaveBeenCalled();
|
||||
expect(getById).toHaveBeenCalledWith(token.id);
|
||||
expect(notFound).toHaveBeenCalledWith('API Token not found');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Retrieve an API token', () => {
|
||||
const token = {
|
||||
id: 1,
|
||||
|
@ -293,6 +293,12 @@ describe('Role CRUD End to End', () => {
|
||||
},
|
||||
],
|
||||
"settings": Array [
|
||||
Object {
|
||||
"action": "admin::api-tokens.access",
|
||||
"category": "api tokens",
|
||||
"displayName": "Access the API tokens settings page",
|
||||
"subCategory": "api Tokens",
|
||||
},
|
||||
Object {
|
||||
"action": "admin::api-tokens.create",
|
||||
"category": "api tokens",
|
||||
@ -784,6 +790,12 @@ describe('Role CRUD End to End', () => {
|
||||
},
|
||||
],
|
||||
"settings": Array [
|
||||
Object {
|
||||
"action": "admin::api-tokens.access",
|
||||
"category": "api tokens",
|
||||
"displayName": "Access the API tokens settings page",
|
||||
"subCategory": "api Tokens",
|
||||
},
|
||||
Object {
|
||||
"action": "admin::api-tokens.create",
|
||||
"category": "api tokens",
|
||||
@ -1210,6 +1222,12 @@ describe('Role CRUD End to End', () => {
|
||||
},
|
||||
],
|
||||
"settings": Array [
|
||||
Object {
|
||||
"action": "admin::api-tokens.access",
|
||||
"category": "api tokens",
|
||||
"displayName": "Access the API tokens settings page",
|
||||
"subCategory": "api Tokens",
|
||||
},
|
||||
Object {
|
||||
"action": "admin::api-tokens.create",
|
||||
"category": "api tokens",
|
||||
|
Loading…
x
Reference in New Issue
Block a user