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