@strapi/plugin-users-permissions 4.9.0-alpha.0 → 4.9.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/admin/src/components/BoundRoute/index.js +5 -7
- package/admin/src/components/FormModal/Input/index.js +1 -2
- package/admin/src/components/FormModal/index.js +9 -7
- package/admin/src/components/Permissions/PermissionRow/CheckboxWrapper.js +1 -1
- package/admin/src/components/Permissions/PermissionRow/SubCategory.js +3 -7
- package/admin/src/components/Permissions/PermissionRow/index.js +1 -1
- package/admin/src/components/Permissions/index.js +3 -5
- package/admin/src/components/Policies/index.js +9 -8
- package/admin/src/components/UsersPermissions/index.js +5 -7
- package/admin/src/components/UsersPermissions/reducer.js +3 -1
- package/admin/src/hooks/usePlugins/index.js +1 -1
- package/admin/src/hooks/useRolesList/index.js +1 -1
- package/admin/src/pages/AdvancedSettings/index.js +17 -12
- package/admin/src/pages/EmailTemplates/components/EmailForm.js +7 -5
- package/admin/src/pages/EmailTemplates/components/EmailTable.js +14 -9
- package/admin/src/pages/EmailTemplates/index.js +1 -3
- package/admin/src/pages/Providers/index.js +17 -8
- package/admin/src/pages/Providers/reducer.js +1 -1
- package/admin/src/pages/Providers/utils/createProvidersArray.js +1 -1
- package/admin/src/pages/Roles/CreatePage/index.js +18 -14
- package/admin/src/pages/Roles/EditPage/index.js +18 -15
- package/admin/src/pages/Roles/ListPage/components/TableBody.js +2 -6
- package/admin/src/pages/Roles/ListPage/index.js +16 -8
- package/admin/src/translations/zh-Hans.json +80 -60
- package/admin/src/utils/cleanPermissions.js +1 -1
- package/package.json +25 -10
- package/server/content-types/user/index.js +3 -0
- package/server/controllers/user.js +17 -6
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import styled from 'styled-components';
|
|
3
|
-
import {
|
|
4
|
-
import { Box } from '@strapi/design-system/Box';
|
|
5
|
-
import { Typography } from '@strapi/design-system/Typography';
|
|
3
|
+
import { Flex, Box, Typography } from '@strapi/design-system';
|
|
6
4
|
import map from 'lodash/map';
|
|
7
5
|
import tail from 'lodash/tail';
|
|
8
6
|
import { useIntl } from 'react-intl';
|
|
@@ -23,7 +21,7 @@ function BoundRoute({ route }) {
|
|
|
23
21
|
const colors = getMethodColor(route.method);
|
|
24
22
|
|
|
25
23
|
return (
|
|
26
|
-
<
|
|
24
|
+
<Flex direction="column" alignItems="stretch" gap={2}>
|
|
27
25
|
<Typography variant="delta" as="h3">
|
|
28
26
|
{formatMessage({
|
|
29
27
|
id: 'users-permissions.BoundRoute.title',
|
|
@@ -35,7 +33,7 @@ function BoundRoute({ route }) {
|
|
|
35
33
|
.{action}
|
|
36
34
|
</Typography>
|
|
37
35
|
</Typography>
|
|
38
|
-
<
|
|
36
|
+
<Flex hasRadius background="neutral0" borderColor="neutral200" gap={0}>
|
|
39
37
|
<MethodBox background={colors.background} borderColor={colors.border} padding={2}>
|
|
40
38
|
<Typography fontWeight="bold" textColor={colors.text}>
|
|
41
39
|
{method}
|
|
@@ -48,8 +46,8 @@ function BoundRoute({ route }) {
|
|
|
48
46
|
</Typography>
|
|
49
47
|
))}
|
|
50
48
|
</Box>
|
|
51
|
-
</
|
|
52
|
-
</
|
|
49
|
+
</Flex>
|
|
50
|
+
</Flex>
|
|
53
51
|
);
|
|
54
52
|
}
|
|
55
53
|
|
|
@@ -6,8 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
import React from 'react';
|
|
8
8
|
import { useIntl } from 'react-intl';
|
|
9
|
-
import { ToggleInput } from '@strapi/design-system
|
|
10
|
-
import { TextInput } from '@strapi/design-system/TextInput';
|
|
9
|
+
import { ToggleInput, TextInput } from '@strapi/design-system';
|
|
11
10
|
import PropTypes from 'prop-types';
|
|
12
11
|
|
|
13
12
|
const Input = ({
|
|
@@ -6,16 +6,18 @@
|
|
|
6
6
|
|
|
7
7
|
import React from 'react';
|
|
8
8
|
import { useIntl } from 'react-intl';
|
|
9
|
-
import { Button } from '@strapi/design-system/Button';
|
|
10
|
-
import { Stack } from '@strapi/design-system/Stack';
|
|
11
|
-
import { Breadcrumbs, Crumb } from '@strapi/design-system/Breadcrumbs';
|
|
12
|
-
import { Grid, GridItem } from '@strapi/design-system/Grid';
|
|
13
9
|
import {
|
|
10
|
+
Button,
|
|
11
|
+
Flex,
|
|
12
|
+
Breadcrumbs,
|
|
13
|
+
Crumb,
|
|
14
|
+
Grid,
|
|
15
|
+
GridItem,
|
|
14
16
|
ModalLayout,
|
|
15
17
|
ModalHeader,
|
|
16
18
|
ModalFooter,
|
|
17
19
|
ModalBody,
|
|
18
|
-
} from '@strapi/design-system
|
|
20
|
+
} from '@strapi/design-system';
|
|
19
21
|
import PropTypes from 'prop-types';
|
|
20
22
|
import { Formik } from 'formik';
|
|
21
23
|
import { Form } from '@strapi/helper-plugin';
|
|
@@ -56,7 +58,7 @@ const FormModal = ({
|
|
|
56
58
|
return (
|
|
57
59
|
<Form>
|
|
58
60
|
<ModalBody>
|
|
59
|
-
<
|
|
61
|
+
<Flex direction="column" alignItems="stretch" gap={1}>
|
|
60
62
|
<Grid gap={5}>
|
|
61
63
|
{layout.form.map((row) => {
|
|
62
64
|
return row.map((input) => {
|
|
@@ -74,7 +76,7 @@ const FormModal = ({
|
|
|
74
76
|
});
|
|
75
77
|
})}
|
|
76
78
|
</Grid>
|
|
77
|
-
</
|
|
79
|
+
</Flex>
|
|
78
80
|
</ModalBody>
|
|
79
81
|
<ModalFooter
|
|
80
82
|
startActions={
|
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
import React, { useCallback, useMemo } from 'react';
|
|
2
|
-
import
|
|
2
|
+
import get from 'lodash/get';
|
|
3
3
|
import styled from 'styled-components';
|
|
4
4
|
import PropTypes from 'prop-types';
|
|
5
|
-
import { Box } from '@strapi/design-system
|
|
6
|
-
import {
|
|
7
|
-
import { Flex } from '@strapi/design-system/Flex';
|
|
8
|
-
import { Typography } from '@strapi/design-system/Typography';
|
|
9
|
-
import { Grid, GridItem } from '@strapi/design-system/Grid';
|
|
10
|
-
import CogIcon from '@strapi/icons/Cog';
|
|
5
|
+
import { Box, Checkbox, Flex, Typography, Grid, GridItem } from '@strapi/design-system';
|
|
6
|
+
import { Cog as CogIcon } from '@strapi/icons';
|
|
11
7
|
import { useIntl } from 'react-intl';
|
|
12
8
|
import CheckboxWrapper from './CheckboxWrapper';
|
|
13
9
|
import { useUsersPermissions } from '../../../contexts/UsersPermissionsContext';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React, { useMemo } from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
import sortBy from 'lodash/sortBy';
|
|
4
|
-
import { Box } from '@strapi/design-system
|
|
4
|
+
import { Box } from '@strapi/design-system';
|
|
5
5
|
import SubCategory from './SubCategory';
|
|
6
6
|
|
|
7
7
|
const PermissionRow = ({ name, permissions }) => {
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import React, { useReducer } from 'react';
|
|
2
|
-
import { Accordion, AccordionToggle, AccordionContent } from '@strapi/design-system
|
|
2
|
+
import { Accordion, AccordionToggle, AccordionContent, Box, Flex } from '@strapi/design-system';
|
|
3
3
|
import { useIntl } from 'react-intl';
|
|
4
|
-
import { Box } from '@strapi/design-system/Box';
|
|
5
|
-
import { Stack } from '@strapi/design-system/Stack';
|
|
6
4
|
import { useUsersPermissions } from '../../contexts/UsersPermissionsContext';
|
|
7
5
|
import formatPluginName from '../../utils/formatPluginName';
|
|
8
6
|
import PermissionRow from './PermissionRow';
|
|
@@ -23,7 +21,7 @@ const Permissions = () => {
|
|
|
23
21
|
});
|
|
24
22
|
|
|
25
23
|
return (
|
|
26
|
-
<
|
|
24
|
+
<Flex direction="column" alignItems="stretch" gap={1}>
|
|
27
25
|
{collapses.map((collapse, index) => (
|
|
28
26
|
<Accordion
|
|
29
27
|
expanded={collapse.isOpen}
|
|
@@ -49,7 +47,7 @@ const Permissions = () => {
|
|
|
49
47
|
</AccordionContent>
|
|
50
48
|
</Accordion>
|
|
51
49
|
))}
|
|
52
|
-
</
|
|
50
|
+
</Flex>
|
|
53
51
|
);
|
|
54
52
|
};
|
|
55
53
|
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { useIntl } from 'react-intl';
|
|
3
|
-
import { Typography } from '@strapi/design-system
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
3
|
+
import { Typography, Flex, GridItem } from '@strapi/design-system';
|
|
4
|
+
import get from 'lodash/get';
|
|
5
|
+
import isEmpty from 'lodash/isEmpty';
|
|
6
|
+
import without from 'lodash/without';
|
|
7
|
+
|
|
7
8
|
import { useUsersPermissions } from '../../contexts/UsersPermissionsContext';
|
|
8
9
|
import BoundRoute from '../BoundRoute';
|
|
9
10
|
|
|
@@ -30,14 +31,14 @@ const Policies = () => {
|
|
|
30
31
|
style={{ minHeight: '100%' }}
|
|
31
32
|
>
|
|
32
33
|
{selectedAction ? (
|
|
33
|
-
<
|
|
34
|
+
<Flex direction="column" alignItems="stretch" gap={2}>
|
|
34
35
|
{displayedRoutes.map((route, key) => (
|
|
35
36
|
// eslint-disable-next-line react/no-array-index-key
|
|
36
37
|
<BoundRoute key={key} route={route} />
|
|
37
38
|
))}
|
|
38
|
-
</
|
|
39
|
+
</Flex>
|
|
39
40
|
) : (
|
|
40
|
-
<
|
|
41
|
+
<Flex direction="column" alignItems="stretch" gap={2}>
|
|
41
42
|
<Typography variant="delta" as="h3">
|
|
42
43
|
{formatMessage({
|
|
43
44
|
id: 'users-permissions.Policies.header.title',
|
|
@@ -51,7 +52,7 @@ const Policies = () => {
|
|
|
51
52
|
"Select the application's actions or the plugin's actions and click on the cog icon to display the bound route",
|
|
52
53
|
})}
|
|
53
54
|
</Typography>
|
|
54
|
-
</
|
|
55
|
+
</Flex>
|
|
55
56
|
)}
|
|
56
57
|
</GridItem>
|
|
57
58
|
);
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import React, { memo, useReducer, forwardRef, useImperativeHandle } from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
|
-
import { Typography } from '@strapi/design-system
|
|
4
|
-
import { Stack } from '@strapi/design-system/Stack';
|
|
5
|
-
import { Grid, GridItem } from '@strapi/design-system/Grid';
|
|
3
|
+
import { Typography, Flex, Grid, GridItem } from '@strapi/design-system';
|
|
6
4
|
import { useIntl } from 'react-intl';
|
|
7
5
|
import getTrad from '../../utils/getTrad';
|
|
8
6
|
import Policies from '../Policies';
|
|
@@ -62,8 +60,8 @@ const UsersPermissions = forwardRef(({ permissions, routes }, ref) => {
|
|
|
62
60
|
<UsersPermissionsProvider value={providerValue}>
|
|
63
61
|
<Grid gap={0} shadow="filterShadow" hasRadius background="neutral0">
|
|
64
62
|
<GridItem col={7} paddingTop={6} paddingBottom={6} paddingLeft={7} paddingRight={7}>
|
|
65
|
-
<
|
|
66
|
-
<
|
|
63
|
+
<Flex direction="column" alignItems="stretch" gap={6}>
|
|
64
|
+
<Flex direction="column" alignItems="stretch" gap={2}>
|
|
67
65
|
<Typography variant="delta" as="h2">
|
|
68
66
|
{formatMessage({
|
|
69
67
|
id: getTrad('Plugins.header.title'),
|
|
@@ -76,9 +74,9 @@ const UsersPermissions = forwardRef(({ permissions, routes }, ref) => {
|
|
|
76
74
|
defaultMessage: 'Only actions bound by a route are listed below.',
|
|
77
75
|
})}
|
|
78
76
|
</Typography>
|
|
79
|
-
</
|
|
77
|
+
</Flex>
|
|
80
78
|
<Permissions />
|
|
81
|
-
</
|
|
79
|
+
</Flex>
|
|
82
80
|
</GridItem>
|
|
83
81
|
<Policies />
|
|
84
82
|
</Grid>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useCallback, useEffect, useReducer } from 'react';
|
|
2
2
|
import { useNotification, useFetchClient } from '@strapi/helper-plugin';
|
|
3
|
-
import
|
|
3
|
+
import get from 'lodash/get';
|
|
4
4
|
import init from './init';
|
|
5
5
|
import pluginId from '../../pluginId';
|
|
6
6
|
import { cleanPermissions } from '../../utils';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useEffect, useReducer, useRef } from 'react';
|
|
2
2
|
import { request, useNotification } from '@strapi/helper-plugin';
|
|
3
|
-
import
|
|
3
|
+
import get from 'lodash/get';
|
|
4
4
|
import init from './init';
|
|
5
5
|
import pluginId from '../../pluginId';
|
|
6
6
|
import reducer, { initialState } from './reducer';
|
|
@@ -13,16 +13,21 @@ import {
|
|
|
13
13
|
useOverlayBlocker,
|
|
14
14
|
useRBAC,
|
|
15
15
|
} from '@strapi/helper-plugin';
|
|
16
|
-
import {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
16
|
+
import {
|
|
17
|
+
useNotifyAT,
|
|
18
|
+
Main,
|
|
19
|
+
HeaderLayout,
|
|
20
|
+
ContentLayout,
|
|
21
|
+
Button,
|
|
22
|
+
Box,
|
|
23
|
+
Flex,
|
|
24
|
+
Select,
|
|
25
|
+
Option,
|
|
26
|
+
Typography,
|
|
27
|
+
Grid,
|
|
28
|
+
GridItem,
|
|
29
|
+
} from '@strapi/design-system';
|
|
30
|
+
import { Check } from '@strapi/icons';
|
|
26
31
|
import pluginPermissions from '../../permissions';
|
|
27
32
|
import { getTrad } from '../../utils';
|
|
28
33
|
import layout from './utils/layout';
|
|
@@ -168,7 +173,7 @@ const AdvancedSettingsPage = () => {
|
|
|
168
173
|
paddingLeft={7}
|
|
169
174
|
paddingRight={7}
|
|
170
175
|
>
|
|
171
|
-
<
|
|
176
|
+
<Flex direction="column" alignItems="stretch" gap={4}>
|
|
172
177
|
<Typography variant="delta" as="h2">
|
|
173
178
|
{formatMessage({
|
|
174
179
|
id: 'global.settings',
|
|
@@ -224,7 +229,7 @@ const AdvancedSettingsPage = () => {
|
|
|
224
229
|
);
|
|
225
230
|
})}
|
|
226
231
|
</Grid>
|
|
227
|
-
</
|
|
232
|
+
</Flex>
|
|
228
233
|
</Box>
|
|
229
234
|
</ContentLayout>
|
|
230
235
|
</Form>
|
|
@@ -8,11 +8,13 @@ import {
|
|
|
8
8
|
ModalHeader,
|
|
9
9
|
ModalFooter,
|
|
10
10
|
ModalBody,
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
11
|
+
Grid,
|
|
12
|
+
GridItem,
|
|
13
|
+
Button,
|
|
14
|
+
Breadcrumbs,
|
|
15
|
+
Crumb,
|
|
16
|
+
Textarea,
|
|
17
|
+
} from '@strapi/design-system';
|
|
16
18
|
import { getTrad } from '../../../utils';
|
|
17
19
|
import schema from '../utils/schema';
|
|
18
20
|
|
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
import { useIntl } from 'react-intl';
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
4
|
+
import {
|
|
5
|
+
Table,
|
|
6
|
+
Thead,
|
|
7
|
+
Tbody,
|
|
8
|
+
Tr,
|
|
9
|
+
Td,
|
|
10
|
+
Th,
|
|
11
|
+
Typography,
|
|
12
|
+
IconButton,
|
|
13
|
+
Icon,
|
|
14
|
+
VisuallyHidden,
|
|
15
|
+
} from '@strapi/design-system';
|
|
16
|
+
import { Pencil, Refresh, Check } from '@strapi/icons';
|
|
11
17
|
import { onRowClick, stopPropagation } from '@strapi/helper-plugin';
|
|
12
|
-
import Check from '@strapi/icons/Check';
|
|
13
18
|
import { getTrad } from '../../../utils';
|
|
14
19
|
|
|
15
20
|
const EmailTable = ({ canUpdate, onEditClick }) => {
|
|
@@ -49,7 +54,7 @@ const EmailTable = ({ canUpdate, onEditClick }) => {
|
|
|
49
54
|
<Tr {...onRowClick({ fn: () => onEditClick('reset_password') })}>
|
|
50
55
|
<Td>
|
|
51
56
|
<Icon>
|
|
52
|
-
<
|
|
57
|
+
<Refresh
|
|
53
58
|
aria-label={formatMessage({
|
|
54
59
|
id: 'global.reset-password',
|
|
55
60
|
defaultMessage: 'Reset password',
|
|
@@ -11,9 +11,7 @@ import {
|
|
|
11
11
|
useFocusWhenNavigate,
|
|
12
12
|
LoadingIndicatorPage,
|
|
13
13
|
} from '@strapi/helper-plugin';
|
|
14
|
-
import { useNotifyAT } from '@strapi/design-system
|
|
15
|
-
import { Main } from '@strapi/design-system/Main';
|
|
16
|
-
import { ContentLayout, HeaderLayout } from '@strapi/design-system/Layout';
|
|
14
|
+
import { useNotifyAT, Main, ContentLayout, HeaderLayout } from '@strapi/design-system';
|
|
17
15
|
import pluginPermissions from '../../permissions';
|
|
18
16
|
import { getTrad } from '../../utils';
|
|
19
17
|
import { fetchData, putEmailTemplate } from './utils/api';
|
|
@@ -14,14 +14,23 @@ import {
|
|
|
14
14
|
} from '@strapi/helper-plugin';
|
|
15
15
|
import has from 'lodash/has';
|
|
16
16
|
import upperFirst from 'lodash/upperFirst';
|
|
17
|
-
import {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
17
|
+
import {
|
|
18
|
+
HeaderLayout,
|
|
19
|
+
Layout,
|
|
20
|
+
ContentLayout,
|
|
21
|
+
Main,
|
|
22
|
+
useNotifyAT,
|
|
23
|
+
Table,
|
|
24
|
+
Thead,
|
|
25
|
+
Tr,
|
|
26
|
+
Th,
|
|
27
|
+
Tbody,
|
|
28
|
+
Td,
|
|
29
|
+
Typography,
|
|
30
|
+
IconButton,
|
|
31
|
+
VisuallyHidden,
|
|
32
|
+
} from '@strapi/design-system';
|
|
33
|
+
import { Pencil } from '@strapi/icons';
|
|
25
34
|
import { useQuery, useMutation, useQueryClient } from 'react-query';
|
|
26
35
|
import forms from './utils/forms';
|
|
27
36
|
import { fetchData, putProvider } from './utils/api';
|
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
import React, { useState, useRef } from 'react';
|
|
2
2
|
import { useHistory } from 'react-router-dom';
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
3
|
+
import {
|
|
4
|
+
ContentLayout,
|
|
5
|
+
HeaderLayout,
|
|
6
|
+
Main,
|
|
7
|
+
Button,
|
|
8
|
+
Flex,
|
|
9
|
+
Box,
|
|
10
|
+
TextInput,
|
|
11
|
+
Textarea,
|
|
12
|
+
Typography,
|
|
13
|
+
GridItem,
|
|
14
|
+
Grid,
|
|
15
|
+
} from '@strapi/design-system';
|
|
16
|
+
import { Check } from '@strapi/icons';
|
|
13
17
|
import { Formik } from 'formik';
|
|
14
18
|
import { useIntl } from 'react-intl';
|
|
15
19
|
import {
|
|
@@ -103,7 +107,7 @@ const EditPage = () => {
|
|
|
103
107
|
})}
|
|
104
108
|
/>
|
|
105
109
|
<ContentLayout>
|
|
106
|
-
<
|
|
110
|
+
<Flex direction="column" alignItems="stretch" gap={7}>
|
|
107
111
|
<Box
|
|
108
112
|
background="neutral0"
|
|
109
113
|
hasRadius
|
|
@@ -113,7 +117,7 @@ const EditPage = () => {
|
|
|
113
117
|
paddingLeft={7}
|
|
114
118
|
paddingRight={7}
|
|
115
119
|
>
|
|
116
|
-
<
|
|
120
|
+
<Flex direction="column" alignItems="stretch" gap={4}>
|
|
117
121
|
<Typography variant="delta" as="h2">
|
|
118
122
|
{formatMessage({
|
|
119
123
|
id: getTrad('EditPage.form.roles'),
|
|
@@ -157,7 +161,7 @@ const EditPage = () => {
|
|
|
157
161
|
/>
|
|
158
162
|
</GridItem>
|
|
159
163
|
</Grid>
|
|
160
|
-
</
|
|
164
|
+
</Flex>
|
|
161
165
|
</Box>
|
|
162
166
|
{!isLoadingPlugins && (
|
|
163
167
|
<UsersPermissions
|
|
@@ -166,7 +170,7 @@ const EditPage = () => {
|
|
|
166
170
|
routes={routes}
|
|
167
171
|
/>
|
|
168
172
|
)}
|
|
169
|
-
</
|
|
173
|
+
</Flex>
|
|
170
174
|
</ContentLayout>
|
|
171
175
|
</Form>
|
|
172
176
|
)}
|
|
@@ -11,17 +11,20 @@ import {
|
|
|
11
11
|
useNotification,
|
|
12
12
|
Link,
|
|
13
13
|
} from '@strapi/helper-plugin';
|
|
14
|
-
import {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
14
|
+
import {
|
|
15
|
+
ContentLayout,
|
|
16
|
+
HeaderLayout,
|
|
17
|
+
Main,
|
|
18
|
+
Button,
|
|
19
|
+
Flex,
|
|
20
|
+
Box,
|
|
21
|
+
TextInput,
|
|
22
|
+
Textarea,
|
|
23
|
+
Typography,
|
|
24
|
+
GridItem,
|
|
25
|
+
Grid,
|
|
26
|
+
} from '@strapi/design-system';
|
|
27
|
+
import { ArrowLeft, Check } from '@strapi/icons';
|
|
25
28
|
import UsersPermissions from '../../../components/UsersPermissions';
|
|
26
29
|
import getTrad from '../../../utils/getTrad';
|
|
27
30
|
import pluginId from '../../../pluginId';
|
|
@@ -116,7 +119,7 @@ const EditPage = () => {
|
|
|
116
119
|
}
|
|
117
120
|
/>
|
|
118
121
|
<ContentLayout>
|
|
119
|
-
<
|
|
122
|
+
<Flex direction="column" alignItems="stretch" gap={7}>
|
|
120
123
|
<Box
|
|
121
124
|
background="neutral0"
|
|
122
125
|
hasRadius
|
|
@@ -126,7 +129,7 @@ const EditPage = () => {
|
|
|
126
129
|
paddingLeft={7}
|
|
127
130
|
paddingRight={7}
|
|
128
131
|
>
|
|
129
|
-
<
|
|
132
|
+
<Flex direction="column" alignItems="stretch" gap={4}>
|
|
130
133
|
<Typography variant="delta" as="h2">
|
|
131
134
|
{formatMessage({
|
|
132
135
|
id: getTrad('EditPage.form.roles'),
|
|
@@ -170,7 +173,7 @@ const EditPage = () => {
|
|
|
170
173
|
/>
|
|
171
174
|
</GridItem>
|
|
172
175
|
</Grid>
|
|
173
|
-
</
|
|
176
|
+
</Flex>
|
|
174
177
|
</Box>
|
|
175
178
|
{!isLoadingPlugins && (
|
|
176
179
|
<UsersPermissions
|
|
@@ -179,7 +182,7 @@ const EditPage = () => {
|
|
|
179
182
|
routes={routes}
|
|
180
183
|
/>
|
|
181
184
|
)}
|
|
182
|
-
</
|
|
185
|
+
</Flex>
|
|
183
186
|
</ContentLayout>
|
|
184
187
|
</Form>
|
|
185
188
|
)}
|
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
|
-
import { IconButton } from '@strapi/design-system
|
|
4
|
-
import {
|
|
5
|
-
import { Flex } from '@strapi/design-system/Flex';
|
|
6
|
-
import { Tbody, Tr, Td } from '@strapi/design-system/Table';
|
|
7
|
-
import Pencil from '@strapi/icons/Pencil';
|
|
8
|
-
import Trash from '@strapi/icons/Trash';
|
|
3
|
+
import { IconButton, Typography, Flex, Tbody, Tr, Td } from '@strapi/design-system';
|
|
4
|
+
import { Pencil, Trash } from '@strapi/icons';
|
|
9
5
|
import { CheckPermissions, onRowClick, stopPropagation } from '@strapi/helper-plugin';
|
|
10
6
|
import { useIntl } from 'react-intl';
|
|
11
7
|
import { useHistory } from 'react-router-dom';
|
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
import React, { useMemo, useState } from 'react';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
2
|
+
import {
|
|
3
|
+
Button,
|
|
4
|
+
HeaderLayout,
|
|
5
|
+
Layout,
|
|
6
|
+
ContentLayout,
|
|
7
|
+
ActionLayout,
|
|
8
|
+
Main,
|
|
9
|
+
Table,
|
|
10
|
+
Tr,
|
|
11
|
+
Thead,
|
|
12
|
+
Th,
|
|
13
|
+
Typography,
|
|
14
|
+
useNotifyAT,
|
|
15
|
+
VisuallyHidden,
|
|
16
|
+
} from '@strapi/design-system';
|
|
17
|
+
import { Plus } from '@strapi/icons';
|
|
10
18
|
import {
|
|
11
19
|
useTracking,
|
|
12
20
|
SettingsPageTitle,
|
|
@@ -1,62 +1,82 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
2
|
+
"BoundRoute.title": "绑定路由到",
|
|
3
|
+
"EditForm.inputSelect.description.role": "新验证身份的用户将被赋予所选角色。",
|
|
4
|
+
"EditForm.inputSelect.label.role": "认证用户的默认角色",
|
|
5
|
+
"EditForm.inputToggle.description.email": "不允许用户使用不同的认证提供者(绑定的相同的电子邮件地址)来创建多个帐户。",
|
|
6
|
+
"EditForm.inputToggle.description.email-confirmation": "启用(ON)后,新注册的用户会收到一封确认电子邮件。",
|
|
7
|
+
"EditForm.inputToggle.description.email-confirmation-redirection": "确认您的电子邮件后,选择将您重定向到的位置。",
|
|
8
|
+
"EditForm.inputToggle.description.email-reset-password": "应用程序的重置密码页面的 URL",
|
|
9
|
+
"EditForm.inputToggle.description.sign-up": "当禁用(OFF)时,注册过程将被禁止。任何人无论使用任何的供应商都不可以订阅。",
|
|
10
|
+
"EditForm.inputToggle.label.email": "每个电子邮件地址一个帐户",
|
|
11
|
+
"EditForm.inputToggle.label.email-confirmation": "启用电子邮件确认",
|
|
12
|
+
"EditForm.inputToggle.label.email-confirmation-redirection": "重定向 URL",
|
|
13
|
+
"EditForm.inputToggle.label.email-reset-password": "重置密码页面 URL",
|
|
14
|
+
"EditForm.inputToggle.label.sign-up": "启用注册",
|
|
15
|
+
"EditForm.inputToggle.placeholder.email-confirmation-redirection": "例如: https://yourfrontend.com/reset-password",
|
|
16
|
+
"EditForm.inputToggle.placeholder.email-reset-password": "例如: https://yourfrontend.com/reset-password",
|
|
17
|
+
"EditPage.form.roles": "角色详情",
|
|
18
|
+
"Email.template.data.loaded": "电子邮件模板已加载",
|
|
19
|
+
"Email.template.email_confirmation": "邮箱地址确认",
|
|
20
|
+
"Email.template.form.edit.label": "编辑模板",
|
|
21
|
+
"Email.template.table.action.label": "操作",
|
|
22
|
+
"Email.template.table.icon.label": "图标",
|
|
23
|
+
"Email.template.table.name.label": "名称",
|
|
24
|
+
"Form.advancedSettings.data.loaded": "高级设置数据已加载",
|
|
25
|
+
"HeaderNav.link.advancedSettings": "高级设置",
|
|
26
|
+
"HeaderNav.link.emailTemplates": "电子邮件模板",
|
|
27
|
+
"HeaderNav.link.providers": "提供者",
|
|
28
|
+
"Plugin.permissions.plugins.description": "定义 {name} 插件所有允许的操作。",
|
|
29
|
+
"Plugins.header.description": "下面只列出路由绑定的操作。",
|
|
30
|
+
"Plugins.header.title": "权限",
|
|
31
|
+
"Policies.header.hint": "选择应用程序或插件的操作,然后点击 COG 图标显示绑定的路由",
|
|
32
|
+
"Policies.header.title": "高级设置",
|
|
33
|
+
"PopUpForm.Email.email_templates.inputDescription": "如果你不确定如何使用变量, {link}",
|
|
34
|
+
"PopUpForm.Email.link.documentation": "查看我们的文档",
|
|
35
|
+
"PopUpForm.Email.options.from.email.label": "发件人地址",
|
|
36
|
+
"PopUpForm.Email.options.from.email.placeholder": "kai@doe.com",
|
|
37
|
+
"PopUpForm.Email.options.from.name.label": "发件人名称",
|
|
38
|
+
"PopUpForm.Email.options.from.name.placeholder": "Kai Doe",
|
|
39
|
+
"PopUpForm.Email.options.message.label": "消息",
|
|
40
|
+
"PopUpForm.Email.options.object.label": "主题",
|
|
41
|
+
"PopUpForm.Email.options.object.placeholder": "请为%APP_NAME%确认邮箱地址",
|
|
42
|
+
"PopUpForm.Email.options.response_email.label": "回复邮件",
|
|
43
|
+
"PopUpForm.Email.options.response_email.placeholder": "kai@doe.com",
|
|
44
|
+
"PopUpForm.Providers.enabled.description": "如果禁用,用户将无法使用此供应商。",
|
|
45
|
+
"PopUpForm.Providers.enabled.label": "启用",
|
|
46
|
+
"PopUpForm.Providers.key.label": "客户端 ID",
|
|
47
|
+
"PopUpForm.Providers.key.placeholder": "文本",
|
|
48
|
+
"PopUpForm.Providers.redirectURL.front-end.label": "重定向 URL",
|
|
49
|
+
"PopUpForm.Providers.redirectURL.label": "添加到{provider}应用配置的跳转URL",
|
|
50
|
+
"PopUpForm.Providers.secret.label": "客户端秘钥",
|
|
51
|
+
"PopUpForm.Providers.secret.placeholder": "文本",
|
|
52
|
+
"PopUpForm.Providers.subdomain.label": "主机URI(子域名)",
|
|
53
|
+
"PopUpForm.Providers.subdomain.placeholder": "my.subdomain.com",
|
|
54
|
+
"PopUpForm.header.edit.email-templates": "编辑电子邮件模版",
|
|
55
|
+
"PopUpForm.header.edit.providers": "编辑提供商",
|
|
56
|
+
"Providers.data.loaded": "提供商已加载",
|
|
57
|
+
"Providers.status": "状态",
|
|
58
|
+
"Roles.empty": "您还没有任何角色。",
|
|
59
|
+
"Roles.empty.search": "没有与搜索相匹配的角色。",
|
|
60
|
+
"Settings.roles.deleted": "角色已被删除",
|
|
61
|
+
"Settings.roles.edited": "角色编辑完成",
|
|
62
|
+
"Settings.section-label": "用户及权限插件",
|
|
63
|
+
"components.Input.error.validation.email": "这是一个无效的电子邮件",
|
|
64
|
+
"components.Input.error.validation.json": "这不符合JSON格式",
|
|
65
|
+
"components.Input.error.validation.max": "值过高。",
|
|
66
|
+
"components.Input.error.validation.maxLength": "值过长。",
|
|
67
|
+
"components.Input.error.validation.min": "值太低。",
|
|
68
|
+
"components.Input.error.validation.minLength": "值太短。",
|
|
69
|
+
"components.Input.error.validation.minSupMax": "不能超过上限",
|
|
70
|
+
"components.Input.error.validation.regex": "该值不符合正则表达式。",
|
|
71
|
+
"components.Input.error.validation.required": "该值为必填项。",
|
|
72
|
+
"components.Input.error.validation.unique": "该值已被使用。",
|
|
73
|
+
"notification.success.submit": "设置已被更新",
|
|
74
|
+
"page.title": "设置 - 角色",
|
|
75
|
+
"plugin.description.long": "使用基于 JWT 的完整身份验证过程来保护 API。这个插件还有一个 ACL 策略,允许你管理用户组之间的权限。",
|
|
76
|
+
"plugin.description.short": "使用基于 JWT 的完整身份验证过程保护 API",
|
|
77
|
+
"plugin.name": "角色及权限",
|
|
78
|
+
"popUpWarning.button.cancel": "取消",
|
|
79
|
+
"popUpWarning.button.confirm": "确认",
|
|
80
|
+
"popUpWarning.title": "请确认",
|
|
81
|
+
"popUpWarning.warning.cancel": "你确定你要取消你的修改?"
|
|
62
82
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@strapi/plugin-users-permissions",
|
|
3
|
-
"version": "4.9.0-
|
|
3
|
+
"version": "4.9.0-beta.1",
|
|
4
4
|
"description": "Protect your API with a full-authentication process based on JWT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -27,31 +27,46 @@
|
|
|
27
27
|
"test:front:watch:ce": "cross-env IS_EE=false jest --config ./jest.config.front.js --watchAll"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@strapi/
|
|
31
|
-
"@strapi/
|
|
30
|
+
"@strapi/design-system": "1.6.6",
|
|
31
|
+
"@strapi/helper-plugin": "4.9.0-beta.1",
|
|
32
|
+
"@strapi/icons": "1.6.6",
|
|
33
|
+
"@strapi/utils": "4.9.0-beta.1",
|
|
32
34
|
"bcryptjs": "2.4.3",
|
|
35
|
+
"formik": "2.2.9",
|
|
33
36
|
"grant-koa": "5.4.8",
|
|
37
|
+
"immer": "9.0.19",
|
|
34
38
|
"jsonwebtoken": "9.0.0",
|
|
35
39
|
"jwk-to-pem": "2.0.5",
|
|
36
40
|
"koa": "^2.13.4",
|
|
37
41
|
"koa2-ratelimit": "^1.1.2",
|
|
38
42
|
"lodash": "4.17.21",
|
|
43
|
+
"match-sorter": "^4.0.2",
|
|
44
|
+
"prop-types": "^15.7.2",
|
|
39
45
|
"purest": "4.0.2",
|
|
40
|
-
"react": "^17.0.2",
|
|
41
|
-
"react-dom": "^17.0.2",
|
|
42
46
|
"react-intl": "6.2.8",
|
|
47
|
+
"react-query": "3.24.3",
|
|
43
48
|
"react-redux": "8.0.5",
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
"url-join": "4.0.1"
|
|
49
|
+
"url-join": "4.0.1",
|
|
50
|
+
"yup": "^0.32.9"
|
|
47
51
|
},
|
|
48
52
|
"devDependencies": {
|
|
49
53
|
"@testing-library/dom": "8.19.0",
|
|
50
54
|
"@testing-library/react": "12.1.4",
|
|
51
55
|
"@testing-library/react-hooks": "8.0.1",
|
|
52
56
|
"@testing-library/user-event": "14.4.3",
|
|
57
|
+
"history": "^4.9.0",
|
|
53
58
|
"msw": "1.0.1",
|
|
54
|
-
"react
|
|
59
|
+
"react": "^17.0.2",
|
|
60
|
+
"react-dom": "^17.0.2",
|
|
61
|
+
"react-router-dom": "5.3.4",
|
|
62
|
+
"react-test-renderer": "^17.0.2",
|
|
63
|
+
"styled-components": "5.3.3"
|
|
64
|
+
},
|
|
65
|
+
"peerDependencies": {
|
|
66
|
+
"react": "^17.0.2",
|
|
67
|
+
"react-dom": "^17.0.2",
|
|
68
|
+
"react-router-dom": "5.3.4",
|
|
69
|
+
"styled-components": "5.3.3"
|
|
55
70
|
},
|
|
56
71
|
"engines": {
|
|
57
72
|
"node": ">=14.19.1 <=18.x.x",
|
|
@@ -64,5 +79,5 @@
|
|
|
64
79
|
"required": true,
|
|
65
80
|
"kind": "plugin"
|
|
66
81
|
},
|
|
67
|
-
"gitHead": "
|
|
82
|
+
"gitHead": "ff37d666d0634fc84827e3d6419d916618275572"
|
|
68
83
|
}
|
|
@@ -38,16 +38,19 @@ module.exports = {
|
|
|
38
38
|
minLength: 6,
|
|
39
39
|
configurable: false,
|
|
40
40
|
private: true,
|
|
41
|
+
searchable: false,
|
|
41
42
|
},
|
|
42
43
|
resetPasswordToken: {
|
|
43
44
|
type: 'string',
|
|
44
45
|
configurable: false,
|
|
45
46
|
private: true,
|
|
47
|
+
searchable: false,
|
|
46
48
|
},
|
|
47
49
|
confirmationToken: {
|
|
48
50
|
type: 'string',
|
|
49
51
|
configurable: false,
|
|
50
52
|
private: true,
|
|
53
|
+
searchable: false,
|
|
51
54
|
},
|
|
52
55
|
confirmed: {
|
|
53
56
|
type: 'boolean',
|
|
@@ -14,13 +14,20 @@ const { validateCreateUserBody, validateUpdateUserBody } = require('./validation
|
|
|
14
14
|
const { sanitize } = utils;
|
|
15
15
|
const { ApplicationError, ValidationError, NotFoundError } = utils.errors;
|
|
16
16
|
|
|
17
|
-
const sanitizeOutput = (user, ctx) => {
|
|
17
|
+
const sanitizeOutput = async (user, ctx) => {
|
|
18
18
|
const schema = strapi.getModel('plugin::users-permissions.user');
|
|
19
19
|
const { auth } = ctx.state;
|
|
20
20
|
|
|
21
21
|
return sanitize.contentAPI.output(user, schema, { auth });
|
|
22
22
|
};
|
|
23
23
|
|
|
24
|
+
const sanitizeQuery = async (query, ctx) => {
|
|
25
|
+
const schema = strapi.getModel('plugin::users-permissions.user');
|
|
26
|
+
const { auth } = ctx.state;
|
|
27
|
+
|
|
28
|
+
return sanitize.contentAPI.query(query, schema, { auth });
|
|
29
|
+
};
|
|
30
|
+
|
|
24
31
|
module.exports = {
|
|
25
32
|
/**
|
|
26
33
|
* Create a/an user record.
|
|
@@ -136,7 +143,8 @@ module.exports = {
|
|
|
136
143
|
* @return {Object|Array}
|
|
137
144
|
*/
|
|
138
145
|
async find(ctx) {
|
|
139
|
-
const
|
|
146
|
+
const sanitizedQuery = await sanitizeQuery(ctx.query, ctx);
|
|
147
|
+
const users = await getService('user').fetchAll(sanitizedQuery);
|
|
140
148
|
|
|
141
149
|
ctx.body = await Promise.all(users.map((user) => sanitizeOutput(user, ctx)));
|
|
142
150
|
},
|
|
@@ -147,9 +155,9 @@ module.exports = {
|
|
|
147
155
|
*/
|
|
148
156
|
async findOne(ctx) {
|
|
149
157
|
const { id } = ctx.params;
|
|
150
|
-
const
|
|
158
|
+
const sanitizedQuery = await sanitizeQuery(ctx.query, ctx);
|
|
151
159
|
|
|
152
|
-
let data = await getService('user').fetch(id,
|
|
160
|
+
let data = await getService('user').fetch(id, sanitizedQuery);
|
|
153
161
|
|
|
154
162
|
if (data) {
|
|
155
163
|
data = await sanitizeOutput(data, ctx);
|
|
@@ -163,7 +171,9 @@ module.exports = {
|
|
|
163
171
|
* @return {Number}
|
|
164
172
|
*/
|
|
165
173
|
async count(ctx) {
|
|
166
|
-
|
|
174
|
+
const sanitizedQuery = await sanitizeQuery(ctx.query, ctx);
|
|
175
|
+
|
|
176
|
+
ctx.body = await getService('user').count(sanitizedQuery);
|
|
167
177
|
},
|
|
168
178
|
|
|
169
179
|
/**
|
|
@@ -191,7 +201,8 @@ module.exports = {
|
|
|
191
201
|
return ctx.unauthorized();
|
|
192
202
|
}
|
|
193
203
|
|
|
194
|
-
const
|
|
204
|
+
const sanitizedQuery = await sanitizeQuery(query, ctx);
|
|
205
|
+
const user = await getService('user').fetch(authUser.id, sanitizedQuery);
|
|
195
206
|
|
|
196
207
|
ctx.body = await sanitizeOutput(user, ctx);
|
|
197
208
|
},
|