@strapi/plugin-users-permissions 4.12.7 → 4.13.0-alpha.0
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/Permissions/index.js +2 -4
- package/admin/src/index.js +7 -8
- package/admin/src/pages/AdvancedSettings/index.js +41 -24
- package/admin/src/pages/EmailTemplates/index.js +62 -47
- package/admin/src/pages/Providers/index.js +64 -58
- package/admin/src/{hooks → pages/Roles/hooks}/usePlugins.js +15 -8
- package/admin/src/pages/Roles/index.js +10 -7
- package/admin/src/pages/Roles/pages/CreatePage.js +190 -0
- package/admin/src/pages/Roles/pages/EditPage.js +211 -0
- package/admin/src/pages/Roles/{ListPage → pages/ListPage}/components/TableBody.js +41 -11
- package/admin/src/pages/Roles/{ListPage → pages/ListPage}/index.js +19 -15
- package/jest.config.front.js +1 -1
- package/package.json +4 -4
- package/server/bootstrap/index.js +35 -0
- package/server/controllers/auth.js +46 -13
- package/server/controllers/user.js +12 -1
- package/admin/src/hooks/index.js +0 -5
- package/admin/src/hooks/useFetchRole/index.js +0 -67
- package/admin/src/hooks/useFetchRole/reducer.js +0 -31
- package/admin/src/hooks/useForm/index.js +0 -68
- package/admin/src/hooks/useForm/reducer.js +0 -40
- package/admin/src/hooks/useRolesList/index.js +0 -65
- package/admin/src/hooks/useRolesList/init.js +0 -5
- package/admin/src/hooks/useRolesList/reducer.js +0 -31
- package/admin/src/pages/AdvancedSettings/utils/api.js +0 -16
- package/admin/src/pages/EmailTemplates/utils/api.js +0 -16
- package/admin/src/pages/Providers/reducer.js +0 -54
- package/admin/src/pages/Providers/utils/api.js +0 -24
- package/admin/src/pages/Providers/utils/createProvidersArray.js +0 -21
- package/admin/src/pages/Roles/CreatePage.js +0 -185
- package/admin/src/pages/Roles/EditPage.js +0 -197
- package/admin/src/pages/Roles/ProtectedCreatePage.js +0 -15
- package/admin/src/pages/Roles/ProtectedEditPage.js +0 -15
- package/admin/src/pages/Roles/ProtectedListPage.js +0 -17
- /package/admin/src/pages/Roles/{ListPage → pages/ListPage}/utils/api.js +0 -0
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
Button,
|
|
5
|
+
ContentLayout,
|
|
6
|
+
Flex,
|
|
7
|
+
Grid,
|
|
8
|
+
GridItem,
|
|
9
|
+
HeaderLayout,
|
|
10
|
+
Main,
|
|
11
|
+
Textarea,
|
|
12
|
+
TextInput,
|
|
13
|
+
Typography,
|
|
14
|
+
} from '@strapi/design-system';
|
|
15
|
+
import {
|
|
16
|
+
CheckPagePermissions,
|
|
17
|
+
Form,
|
|
18
|
+
SettingsPageTitle,
|
|
19
|
+
useFetchClient,
|
|
20
|
+
useNotification,
|
|
21
|
+
useOverlayBlocker,
|
|
22
|
+
useTracking,
|
|
23
|
+
} from '@strapi/helper-plugin';
|
|
24
|
+
import { Check } from '@strapi/icons';
|
|
25
|
+
import { Formik } from 'formik';
|
|
26
|
+
import { useIntl } from 'react-intl';
|
|
27
|
+
import { useMutation } from 'react-query';
|
|
28
|
+
import { useHistory } from 'react-router-dom';
|
|
29
|
+
|
|
30
|
+
import UsersPermissions from '../../../components/UsersPermissions';
|
|
31
|
+
import { PERMISSIONS } from '../../../constants';
|
|
32
|
+
import getTrad from '../../../utils/getTrad';
|
|
33
|
+
import { createRoleSchema } from '../constants';
|
|
34
|
+
import { usePlugins } from '../hooks/usePlugins';
|
|
35
|
+
|
|
36
|
+
export const CreatePage = () => {
|
|
37
|
+
const { formatMessage } = useIntl();
|
|
38
|
+
const toggleNotification = useNotification();
|
|
39
|
+
const { goBack } = useHistory();
|
|
40
|
+
const { lockApp, unlockApp } = useOverlayBlocker();
|
|
41
|
+
const { isLoading: isLoadingPlugins, permissions, routes } = usePlugins();
|
|
42
|
+
const { trackUsage } = useTracking();
|
|
43
|
+
const permissionsRef = React.useRef();
|
|
44
|
+
const { post } = useFetchClient();
|
|
45
|
+
const mutation = useMutation((body) => post(`/users-permissions/roles`, body), {
|
|
46
|
+
onError() {
|
|
47
|
+
toggleNotification({
|
|
48
|
+
type: 'warning',
|
|
49
|
+
message: {
|
|
50
|
+
id: 'notification.error',
|
|
51
|
+
defaultMessage: 'An error occurred',
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
onSuccess() {
|
|
57
|
+
trackUsage('didCreateRole');
|
|
58
|
+
|
|
59
|
+
toggleNotification({
|
|
60
|
+
type: 'success',
|
|
61
|
+
message: {
|
|
62
|
+
id: getTrad('Settings.roles.created'),
|
|
63
|
+
defaultMessage: 'Role created',
|
|
64
|
+
},
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// Forcing redirecting since we don't have the id in the response
|
|
68
|
+
goBack();
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
const handleCreateRoleSubmit = async (data) => {
|
|
73
|
+
lockApp();
|
|
74
|
+
|
|
75
|
+
// TODO: refactor. Child -> parent component communication is evil;
|
|
76
|
+
// We should either move the provider one level up or move the state
|
|
77
|
+
// straight into redux.
|
|
78
|
+
const permissions = permissionsRef.current.getPermissions();
|
|
79
|
+
|
|
80
|
+
await mutation.mutate({ ...data, ...permissions, users: [] });
|
|
81
|
+
|
|
82
|
+
unlockApp();
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
return (
|
|
86
|
+
<Main>
|
|
87
|
+
{/* TODO: This needs to be translated */}
|
|
88
|
+
<SettingsPageTitle name="Roles" />
|
|
89
|
+
<Formik
|
|
90
|
+
enableReinitialize
|
|
91
|
+
initialValues={{ name: '', description: '' }}
|
|
92
|
+
onSubmit={handleCreateRoleSubmit}
|
|
93
|
+
validationSchema={createRoleSchema}
|
|
94
|
+
>
|
|
95
|
+
{({ handleSubmit, values, handleChange, errors }) => (
|
|
96
|
+
<Form noValidate onSubmit={handleSubmit}>
|
|
97
|
+
<HeaderLayout
|
|
98
|
+
primaryAction={
|
|
99
|
+
!isLoadingPlugins && (
|
|
100
|
+
<Button type="submit" loading={mutation.isLoading} startIcon={<Check />}>
|
|
101
|
+
{formatMessage({
|
|
102
|
+
id: 'global.save',
|
|
103
|
+
defaultMessage: 'Save',
|
|
104
|
+
})}
|
|
105
|
+
</Button>
|
|
106
|
+
)
|
|
107
|
+
}
|
|
108
|
+
title={formatMessage({
|
|
109
|
+
id: 'Settings.roles.create.title',
|
|
110
|
+
defaultMessage: 'Create a role',
|
|
111
|
+
})}
|
|
112
|
+
subtitle={formatMessage({
|
|
113
|
+
id: 'Settings.roles.create.description',
|
|
114
|
+
defaultMessage: 'Define the rights given to the role',
|
|
115
|
+
})}
|
|
116
|
+
/>
|
|
117
|
+
<ContentLayout>
|
|
118
|
+
<Flex
|
|
119
|
+
background="neutral0"
|
|
120
|
+
direction="column"
|
|
121
|
+
alignItems="stretch"
|
|
122
|
+
gap={7}
|
|
123
|
+
hasRadius
|
|
124
|
+
paddingTop={6}
|
|
125
|
+
paddingBottom={6}
|
|
126
|
+
paddingLeft={7}
|
|
127
|
+
paddingRight={7}
|
|
128
|
+
shadow="filterShadow"
|
|
129
|
+
>
|
|
130
|
+
<Flex direction="column" alignItems="stretch">
|
|
131
|
+
<Typography variant="delta" as="h2">
|
|
132
|
+
{formatMessage({
|
|
133
|
+
id: getTrad('EditPage.form.roles'),
|
|
134
|
+
defaultMessage: 'Role details',
|
|
135
|
+
})}
|
|
136
|
+
</Typography>
|
|
137
|
+
|
|
138
|
+
<Grid gap={4}>
|
|
139
|
+
<GridItem col={6}>
|
|
140
|
+
<TextInput
|
|
141
|
+
name="name"
|
|
142
|
+
value={values.name || ''}
|
|
143
|
+
onChange={handleChange}
|
|
144
|
+
label={formatMessage({
|
|
145
|
+
id: 'global.name',
|
|
146
|
+
defaultMessage: 'Name',
|
|
147
|
+
})}
|
|
148
|
+
error={errors?.name ? formatMessage({ id: errors.name }) : false}
|
|
149
|
+
required
|
|
150
|
+
/>
|
|
151
|
+
</GridItem>
|
|
152
|
+
<GridItem col={6}>
|
|
153
|
+
<Textarea
|
|
154
|
+
id="description"
|
|
155
|
+
value={values.description || ''}
|
|
156
|
+
onChange={handleChange}
|
|
157
|
+
label={formatMessage({
|
|
158
|
+
id: 'global.description',
|
|
159
|
+
defaultMessage: 'Description',
|
|
160
|
+
})}
|
|
161
|
+
error={
|
|
162
|
+
errors?.description ? formatMessage({ id: errors.description }) : false
|
|
163
|
+
}
|
|
164
|
+
required
|
|
165
|
+
/>
|
|
166
|
+
</GridItem>
|
|
167
|
+
</Grid>
|
|
168
|
+
</Flex>
|
|
169
|
+
|
|
170
|
+
{!isLoadingPlugins && (
|
|
171
|
+
<UsersPermissions
|
|
172
|
+
ref={permissionsRef}
|
|
173
|
+
permissions={permissions}
|
|
174
|
+
routes={routes}
|
|
175
|
+
/>
|
|
176
|
+
)}
|
|
177
|
+
</Flex>
|
|
178
|
+
</ContentLayout>
|
|
179
|
+
</Form>
|
|
180
|
+
)}
|
|
181
|
+
</Formik>
|
|
182
|
+
</Main>
|
|
183
|
+
);
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
export const ProtectedRolesCreatePage = () => (
|
|
187
|
+
<CheckPagePermissions permissions={PERMISSIONS.createRole}>
|
|
188
|
+
<CreatePage />
|
|
189
|
+
</CheckPagePermissions>
|
|
190
|
+
);
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
ContentLayout,
|
|
5
|
+
HeaderLayout,
|
|
6
|
+
Main,
|
|
7
|
+
Button,
|
|
8
|
+
Flex,
|
|
9
|
+
TextInput,
|
|
10
|
+
Textarea,
|
|
11
|
+
Typography,
|
|
12
|
+
GridItem,
|
|
13
|
+
Grid,
|
|
14
|
+
} from '@strapi/design-system';
|
|
15
|
+
import {
|
|
16
|
+
CheckPagePermissions,
|
|
17
|
+
useOverlayBlocker,
|
|
18
|
+
SettingsPageTitle,
|
|
19
|
+
LoadingIndicatorPage,
|
|
20
|
+
Form,
|
|
21
|
+
useAPIErrorHandler,
|
|
22
|
+
useFetchClient,
|
|
23
|
+
useNotification,
|
|
24
|
+
Link,
|
|
25
|
+
} from '@strapi/helper-plugin';
|
|
26
|
+
import { ArrowLeft, Check } from '@strapi/icons';
|
|
27
|
+
import { Formik } from 'formik';
|
|
28
|
+
import { useIntl } from 'react-intl';
|
|
29
|
+
import { useQuery, useMutation } from 'react-query';
|
|
30
|
+
import { useRouteMatch } from 'react-router-dom';
|
|
31
|
+
|
|
32
|
+
import UsersPermissions from '../../../components/UsersPermissions';
|
|
33
|
+
import { PERMISSIONS } from '../../../constants';
|
|
34
|
+
import getTrad from '../../../utils/getTrad';
|
|
35
|
+
import { createRoleSchema } from '../constants';
|
|
36
|
+
import { usePlugins } from '../hooks/usePlugins';
|
|
37
|
+
|
|
38
|
+
export const EditPage = () => {
|
|
39
|
+
const { formatMessage } = useIntl();
|
|
40
|
+
const toggleNotification = useNotification();
|
|
41
|
+
const { lockApp, unlockApp } = useOverlayBlocker();
|
|
42
|
+
const {
|
|
43
|
+
params: { id },
|
|
44
|
+
} = useRouteMatch(`/settings/users-permissions/roles/:id`);
|
|
45
|
+
const { get } = useFetchClient();
|
|
46
|
+
const { isLoading: isLoadingPlugins, routes } = usePlugins();
|
|
47
|
+
const {
|
|
48
|
+
data: role,
|
|
49
|
+
isLoading: isLoadingRole,
|
|
50
|
+
refetch: refetchRole,
|
|
51
|
+
} = useQuery(['users-permissions', 'role', id], async () => {
|
|
52
|
+
// TODO: why doesn't this endpoint follow the admin API conventions?
|
|
53
|
+
const {
|
|
54
|
+
data: { role },
|
|
55
|
+
} = await get(`/users-permissions/roles/${id}`);
|
|
56
|
+
|
|
57
|
+
return role;
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
const permissionsRef = React.useRef();
|
|
61
|
+
const { put } = useFetchClient();
|
|
62
|
+
const { formatAPIError } = useAPIErrorHandler();
|
|
63
|
+
const mutation = useMutation((body) => put(`/users-permissions/roles/${id}`, body), {
|
|
64
|
+
onError(error) {
|
|
65
|
+
toggleNotification({
|
|
66
|
+
type: 'warning',
|
|
67
|
+
message: formatAPIError(error),
|
|
68
|
+
});
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
async onSuccess() {
|
|
72
|
+
toggleNotification({
|
|
73
|
+
type: 'success',
|
|
74
|
+
message: {
|
|
75
|
+
id: getTrad('Settings.roles.created'),
|
|
76
|
+
defaultMessage: 'Role edited',
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
await refetchRole();
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
const handleEditRoleSubmit = async (data) => {
|
|
85
|
+
// Set loading state
|
|
86
|
+
lockApp();
|
|
87
|
+
|
|
88
|
+
const permissions = permissionsRef.current.getPermissions();
|
|
89
|
+
|
|
90
|
+
await mutation.mutate({ ...data, ...permissions, users: [] });
|
|
91
|
+
|
|
92
|
+
unlockApp();
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
if (isLoadingRole) {
|
|
96
|
+
return <LoadingIndicatorPage />;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return (
|
|
100
|
+
<Main>
|
|
101
|
+
{/* TODO: this needs to be translated */}
|
|
102
|
+
<SettingsPageTitle name="Roles" />
|
|
103
|
+
<Formik
|
|
104
|
+
enableReinitialize
|
|
105
|
+
initialValues={{ name: role.name, description: role.description }}
|
|
106
|
+
onSubmit={handleEditRoleSubmit}
|
|
107
|
+
validationSchema={createRoleSchema}
|
|
108
|
+
>
|
|
109
|
+
{({ handleSubmit, values, handleChange, errors }) => (
|
|
110
|
+
<Form noValidate onSubmit={handleSubmit}>
|
|
111
|
+
<HeaderLayout
|
|
112
|
+
primaryAction={
|
|
113
|
+
!isLoadingPlugins && (
|
|
114
|
+
<Button
|
|
115
|
+
disabled={role.code === 'strapi-super-admin'}
|
|
116
|
+
type="submit"
|
|
117
|
+
loading={mutation.isLoading}
|
|
118
|
+
startIcon={<Check />}
|
|
119
|
+
>
|
|
120
|
+
{formatMessage({
|
|
121
|
+
id: 'global.save',
|
|
122
|
+
defaultMessage: 'Save',
|
|
123
|
+
})}
|
|
124
|
+
</Button>
|
|
125
|
+
)
|
|
126
|
+
}
|
|
127
|
+
title={role.name}
|
|
128
|
+
subtitle={role.description}
|
|
129
|
+
navigationAction={
|
|
130
|
+
<Link startIcon={<ArrowLeft />} to="/settings/users-permissions/roles">
|
|
131
|
+
{formatMessage({
|
|
132
|
+
id: 'global.back',
|
|
133
|
+
defaultMessage: 'Back',
|
|
134
|
+
})}
|
|
135
|
+
</Link>
|
|
136
|
+
}
|
|
137
|
+
/>
|
|
138
|
+
<ContentLayout>
|
|
139
|
+
<Flex
|
|
140
|
+
background="neutral0"
|
|
141
|
+
direction="column"
|
|
142
|
+
alignItems="stretch"
|
|
143
|
+
gap={7}
|
|
144
|
+
hasRadius
|
|
145
|
+
paddingTop={6}
|
|
146
|
+
paddingBottom={6}
|
|
147
|
+
paddingLeft={7}
|
|
148
|
+
paddingRight={7}
|
|
149
|
+
shadow="filterShadow"
|
|
150
|
+
>
|
|
151
|
+
<Flex direction="column" alignItems="stretch" gap={4}>
|
|
152
|
+
<Typography variant="delta" as="h2">
|
|
153
|
+
{formatMessage({
|
|
154
|
+
id: getTrad('EditPage.form.roles'),
|
|
155
|
+
defaultMessage: 'Role details',
|
|
156
|
+
})}
|
|
157
|
+
</Typography>
|
|
158
|
+
|
|
159
|
+
<Grid gap={4}>
|
|
160
|
+
<GridItem col={6}>
|
|
161
|
+
<TextInput
|
|
162
|
+
name="name"
|
|
163
|
+
value={values.name || ''}
|
|
164
|
+
onChange={handleChange}
|
|
165
|
+
label={formatMessage({
|
|
166
|
+
id: 'global.name',
|
|
167
|
+
defaultMessage: 'Name',
|
|
168
|
+
})}
|
|
169
|
+
error={errors?.name ? formatMessage({ id: errors.name }) : false}
|
|
170
|
+
required
|
|
171
|
+
/>
|
|
172
|
+
</GridItem>
|
|
173
|
+
<GridItem col={6}>
|
|
174
|
+
<Textarea
|
|
175
|
+
id="description"
|
|
176
|
+
value={values.description || ''}
|
|
177
|
+
onChange={handleChange}
|
|
178
|
+
label={formatMessage({
|
|
179
|
+
id: 'global.description',
|
|
180
|
+
defaultMessage: 'Description',
|
|
181
|
+
})}
|
|
182
|
+
error={
|
|
183
|
+
errors?.description ? formatMessage({ id: errors.description }) : false
|
|
184
|
+
}
|
|
185
|
+
required
|
|
186
|
+
/>
|
|
187
|
+
</GridItem>
|
|
188
|
+
</Grid>
|
|
189
|
+
</Flex>
|
|
190
|
+
|
|
191
|
+
{!isLoadingPlugins && (
|
|
192
|
+
<UsersPermissions
|
|
193
|
+
ref={permissionsRef}
|
|
194
|
+
permissions={role.permissions}
|
|
195
|
+
routes={routes}
|
|
196
|
+
/>
|
|
197
|
+
)}
|
|
198
|
+
</Flex>
|
|
199
|
+
</ContentLayout>
|
|
200
|
+
</Form>
|
|
201
|
+
)}
|
|
202
|
+
</Formik>
|
|
203
|
+
</Main>
|
|
204
|
+
);
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
export const ProtectedRolesEditPage = () => (
|
|
208
|
+
<CheckPagePermissions permissions={PERMISSIONS.updateRole}>
|
|
209
|
+
<EditPage />
|
|
210
|
+
</CheckPagePermissions>
|
|
211
|
+
);
|
|
@@ -1,13 +1,39 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
|
|
3
|
-
import { Flex, IconButton, Tbody, Td, Tr, Typography } from '@strapi/design-system';
|
|
4
|
-
import { CheckPermissions, onRowClick, stopPropagation } from '@strapi/helper-plugin';
|
|
3
|
+
import { Flex, IconButton, Link, Tbody, Td, Tr, Typography } from '@strapi/design-system';
|
|
4
|
+
import { CheckPermissions, onRowClick, pxToRem, stopPropagation } from '@strapi/helper-plugin';
|
|
5
5
|
import { Pencil, Trash } from '@strapi/icons';
|
|
6
6
|
import PropTypes from 'prop-types';
|
|
7
7
|
import { useIntl } from 'react-intl';
|
|
8
8
|
import { useHistory } from 'react-router-dom';
|
|
9
|
+
import styled from 'styled-components';
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
const EditLink = styled(Link)`
|
|
12
|
+
align-items: center;
|
|
13
|
+
height: ${pxToRem(32)};
|
|
14
|
+
display: flex;
|
|
15
|
+
justify-content: center;
|
|
16
|
+
padding: ${({ theme }) => `${theme.spaces[2]}}`};
|
|
17
|
+
width: ${pxToRem(32)};
|
|
18
|
+
|
|
19
|
+
svg {
|
|
20
|
+
height: ${pxToRem(12)};
|
|
21
|
+
width: ${pxToRem(12)};
|
|
22
|
+
|
|
23
|
+
path {
|
|
24
|
+
fill: ${({ theme }) => theme.colors.neutral500};
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
&:hover,
|
|
29
|
+
&:focus {
|
|
30
|
+
svg {
|
|
31
|
+
path {
|
|
32
|
+
fill: ${({ theme }) => theme.colors.neutral800};
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
`;
|
|
11
37
|
|
|
12
38
|
const TableBody = ({ sortedRoles, canDelete, permissions, setRoleToDelete, onDelete }) => {
|
|
13
39
|
const { formatMessage } = useIntl();
|
|
@@ -23,7 +49,7 @@ const TableBody = ({ sortedRoles, canDelete, permissions, setRoleToDelete, onDel
|
|
|
23
49
|
};
|
|
24
50
|
|
|
25
51
|
const handleClickEdit = (id) => {
|
|
26
|
-
push(`/settings
|
|
52
|
+
push(`/settings/users-permissions/roles/${id}`);
|
|
27
53
|
};
|
|
28
54
|
|
|
29
55
|
return (
|
|
@@ -39,7 +65,10 @@ const TableBody = ({ sortedRoles, canDelete, permissions, setRoleToDelete, onDel
|
|
|
39
65
|
<Td width="30%">
|
|
40
66
|
<Typography>
|
|
41
67
|
{formatMessage(
|
|
42
|
-
{
|
|
68
|
+
{
|
|
69
|
+
id: 'Roles.RoleRow.user-count',
|
|
70
|
+
defaultMessage: '{number, plural, =0 {# user} one {# user} other {# users}}',
|
|
71
|
+
},
|
|
43
72
|
{ number: role.nb_users }
|
|
44
73
|
)}
|
|
45
74
|
</Typography>
|
|
@@ -47,16 +76,17 @@ const TableBody = ({ sortedRoles, canDelete, permissions, setRoleToDelete, onDel
|
|
|
47
76
|
<Td>
|
|
48
77
|
<Flex justifyContent="end" {...stopPropagation}>
|
|
49
78
|
<CheckPermissions permissions={permissions.updateRole}>
|
|
50
|
-
<
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
icon={<Pencil />}
|
|
54
|
-
label={formatMessage(
|
|
79
|
+
<EditLink
|
|
80
|
+
to={`/settings/users-permissions/roles/${role.id}`}
|
|
81
|
+
aria-label={formatMessage(
|
|
55
82
|
{ id: 'app.component.table.edit', defaultMessage: 'Edit {target}' },
|
|
56
83
|
{ target: `${role.name}` }
|
|
57
84
|
)}
|
|
58
|
-
|
|
85
|
+
>
|
|
86
|
+
<Pencil />
|
|
87
|
+
</EditLink>
|
|
59
88
|
</CheckPermissions>
|
|
89
|
+
|
|
60
90
|
{checkCanDeleteRole(role) && (
|
|
61
91
|
<CheckPermissions permissions={permissions.deleteRole}>
|
|
62
92
|
<IconButton
|
|
@@ -2,7 +2,6 @@ import React, { useState } from 'react';
|
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
ActionLayout,
|
|
5
|
-
Button,
|
|
6
5
|
ContentLayout,
|
|
7
6
|
HeaderLayout,
|
|
8
7
|
Layout,
|
|
@@ -16,9 +15,11 @@ import {
|
|
|
16
15
|
VisuallyHidden,
|
|
17
16
|
} from '@strapi/design-system';
|
|
18
17
|
import {
|
|
18
|
+
CheckPagePermissions,
|
|
19
19
|
CheckPermissions,
|
|
20
20
|
ConfirmDialog,
|
|
21
21
|
EmptyStateLayout,
|
|
22
|
+
LinkButton,
|
|
22
23
|
LoadingIndicatorPage,
|
|
23
24
|
NoPermissions,
|
|
24
25
|
SearchURLQuery,
|
|
@@ -34,19 +35,16 @@ import {
|
|
|
34
35
|
import { Plus } from '@strapi/icons';
|
|
35
36
|
import { useIntl } from 'react-intl';
|
|
36
37
|
import { useMutation, useQuery } from 'react-query';
|
|
37
|
-
import { useHistory } from 'react-router-dom';
|
|
38
38
|
|
|
39
|
-
import { PERMISSIONS } from '
|
|
40
|
-
import
|
|
41
|
-
import { getTrad } from '../../../utils';
|
|
39
|
+
import { PERMISSIONS } from '../../../../constants';
|
|
40
|
+
import { getTrad } from '../../../../utils';
|
|
42
41
|
|
|
43
42
|
import TableBody from './components/TableBody';
|
|
44
43
|
import { deleteData, fetchData } from './utils/api';
|
|
45
44
|
|
|
46
|
-
const
|
|
45
|
+
export const RolesListPage = () => {
|
|
47
46
|
const { trackUsage } = useTracking();
|
|
48
47
|
const { formatMessage, locale } = useIntl();
|
|
49
|
-
const { push } = useHistory();
|
|
50
48
|
const toggleNotification = useNotification();
|
|
51
49
|
const { notifyStatus } = useNotifyAT();
|
|
52
50
|
const [{ query }] = useQueryParams();
|
|
@@ -89,11 +87,6 @@ const RoleListPage = () => {
|
|
|
89
87
|
|
|
90
88
|
const isLoading = isLoadingForData || isFetching;
|
|
91
89
|
|
|
92
|
-
const handleNewRoleClick = () => {
|
|
93
|
-
trackUsage('willCreateRole');
|
|
94
|
-
push(`/settings/${pluginId}/roles/new`);
|
|
95
|
-
};
|
|
96
|
-
|
|
97
90
|
const handleShowConfirmDelete = () => {
|
|
98
91
|
setShowConfirmDelete(!showConfirmDelete);
|
|
99
92
|
};
|
|
@@ -153,12 +146,17 @@ const RoleListPage = () => {
|
|
|
153
146
|
})}
|
|
154
147
|
primaryAction={
|
|
155
148
|
<CheckPermissions permissions={PERMISSIONS.createRole}>
|
|
156
|
-
<
|
|
149
|
+
<LinkButton
|
|
150
|
+
to="/settings/users-permissions/roles/new"
|
|
151
|
+
onClick={() => trackUsage('willCreateRole')}
|
|
152
|
+
startIcon={<Plus />}
|
|
153
|
+
size="S"
|
|
154
|
+
>
|
|
157
155
|
{formatMessage({
|
|
158
156
|
id: getTrad('List.button.roles'),
|
|
159
157
|
defaultMessage: 'Add new role',
|
|
160
158
|
})}
|
|
161
|
-
</
|
|
159
|
+
</LinkButton>
|
|
162
160
|
</CheckPermissions>
|
|
163
161
|
}
|
|
164
162
|
/>
|
|
@@ -235,4 +233,10 @@ const RoleListPage = () => {
|
|
|
235
233
|
);
|
|
236
234
|
};
|
|
237
235
|
|
|
238
|
-
export
|
|
236
|
+
export const ProtectedRolesListPage = () => {
|
|
237
|
+
return (
|
|
238
|
+
<CheckPagePermissions permissions={PERMISSIONS.accessRoles}>
|
|
239
|
+
<RolesListPage />
|
|
240
|
+
</CheckPagePermissions>
|
|
241
|
+
);
|
|
242
|
+
};
|
package/jest.config.front.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@strapi/plugin-users-permissions",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.13.0-alpha.0",
|
|
4
4
|
"description": "Protect your API with a full-authentication process based on JWT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -30,9 +30,9 @@
|
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
32
|
"@strapi/design-system": "1.9.0",
|
|
33
|
-
"@strapi/helper-plugin": "4.
|
|
33
|
+
"@strapi/helper-plugin": "4.13.0-alpha.0",
|
|
34
34
|
"@strapi/icons": "1.9.0",
|
|
35
|
-
"@strapi/utils": "4.
|
|
35
|
+
"@strapi/utils": "4.13.0-alpha.0",
|
|
36
36
|
"bcryptjs": "2.4.3",
|
|
37
37
|
"formik": "2.4.0",
|
|
38
38
|
"grant-koa": "5.4.8",
|
|
@@ -77,5 +77,5 @@
|
|
|
77
77
|
"required": true,
|
|
78
78
|
"kind": "plugin"
|
|
79
79
|
},
|
|
80
|
-
"gitHead": "
|
|
80
|
+
"gitHead": "41844c2867621a1f47dd6ae6ac83283aa54b22f8"
|
|
81
81
|
}
|
|
@@ -10,10 +10,12 @@
|
|
|
10
10
|
const crypto = require('crypto');
|
|
11
11
|
const _ = require('lodash');
|
|
12
12
|
const urljoin = require('url-join');
|
|
13
|
+
const { isArray } = require('lodash/fp');
|
|
13
14
|
const { getService } = require('../utils');
|
|
14
15
|
const getGrantConfig = require('./grant-config');
|
|
15
16
|
|
|
16
17
|
const usersPermissionsActions = require('./users-permissions-actions');
|
|
18
|
+
const userSchema = require('../content-types/user');
|
|
17
19
|
|
|
18
20
|
const initGrant = async (pluginStore) => {
|
|
19
21
|
const apiPrefix = strapi.config.get('api.rest.prefix');
|
|
@@ -97,6 +99,26 @@ const initAdvancedOptions = async (pluginStore) => {
|
|
|
97
99
|
}
|
|
98
100
|
};
|
|
99
101
|
|
|
102
|
+
const userSchemaAdditions = () => {
|
|
103
|
+
const defaultSchema = Object.keys(userSchema.attributes);
|
|
104
|
+
const currentSchema = Object.keys(
|
|
105
|
+
strapi.contentTypes['plugin::users-permissions.user'].attributes
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
// Some dynamic fields may not have been initialized yet, so we need to ignore them
|
|
109
|
+
// TODO: we should have a global method for finding these
|
|
110
|
+
const ignoreDiffs = [
|
|
111
|
+
'createdBy',
|
|
112
|
+
'createdAt',
|
|
113
|
+
'updatedBy',
|
|
114
|
+
'updatedAt',
|
|
115
|
+
'publishedAt',
|
|
116
|
+
'strapi_reviewWorkflows_stage',
|
|
117
|
+
];
|
|
118
|
+
|
|
119
|
+
return currentSchema.filter((key) => !(ignoreDiffs.includes(key) || defaultSchema.includes(key)));
|
|
120
|
+
};
|
|
121
|
+
|
|
100
122
|
module.exports = async ({ strapi }) => {
|
|
101
123
|
const pluginStore = strapi.store({ type: 'plugin', name: 'users-permissions' });
|
|
102
124
|
|
|
@@ -130,4 +152,17 @@ For security reasons, prefer storing the secret in an environment variable and r
|
|
|
130
152
|
);
|
|
131
153
|
}
|
|
132
154
|
}
|
|
155
|
+
|
|
156
|
+
// TODO v5: Remove this block of code and default allowedFields to empty array
|
|
157
|
+
if (!isArray(strapi.config.get('plugin.users-permissions.register.allowedFields'))) {
|
|
158
|
+
const modifications = userSchemaAdditions();
|
|
159
|
+
if (modifications.length > 0) {
|
|
160
|
+
// if there is a potential vulnerability, show a warning
|
|
161
|
+
strapi.log.warn(
|
|
162
|
+
`Users-permissions registration has defaulted to accepting the following additional user fields during registration: ${modifications.join(
|
|
163
|
+
','
|
|
164
|
+
)}`
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
133
168
|
};
|