@strapi/plugin-users-permissions 0.0.0-4fc90398602f

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.
Files changed (168) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +1 -0
  3. package/admin/src/components/BoundRoute/getMethodColor.js +41 -0
  4. package/admin/src/components/BoundRoute/index.js +72 -0
  5. package/admin/src/components/FormModal/Input/index.js +121 -0
  6. package/admin/src/components/FormModal/index.js +121 -0
  7. package/admin/src/components/Permissions/PermissionRow/CheckboxWrapper.js +30 -0
  8. package/admin/src/components/Permissions/PermissionRow/SubCategory.js +114 -0
  9. package/admin/src/components/Permissions/PermissionRow/index.js +53 -0
  10. package/admin/src/components/Permissions/index.js +56 -0
  11. package/admin/src/components/Permissions/init.js +9 -0
  12. package/admin/src/components/Permissions/reducer.js +27 -0
  13. package/admin/src/components/Policies/index.js +60 -0
  14. package/admin/src/components/UsersPermissions/index.js +94 -0
  15. package/admin/src/components/UsersPermissions/init.js +10 -0
  16. package/admin/src/components/UsersPermissions/reducer.js +60 -0
  17. package/admin/src/contexts/UsersPermissionsContext/index.js +17 -0
  18. package/admin/src/hooks/index.js +5 -0
  19. package/admin/src/hooks/useFetchRole/index.js +64 -0
  20. package/admin/src/hooks/useFetchRole/reducer.js +31 -0
  21. package/admin/src/hooks/useForm/index.js +70 -0
  22. package/admin/src/hooks/useForm/reducer.js +40 -0
  23. package/admin/src/hooks/usePlugins/index.js +65 -0
  24. package/admin/src/hooks/usePlugins/init.js +5 -0
  25. package/admin/src/hooks/usePlugins/reducer.js +34 -0
  26. package/admin/src/hooks/useRolesList/index.js +63 -0
  27. package/admin/src/hooks/useRolesList/init.js +5 -0
  28. package/admin/src/hooks/useRolesList/reducer.js +31 -0
  29. package/admin/src/index.js +123 -0
  30. package/admin/src/pages/AdvancedSettings/index.js +238 -0
  31. package/admin/src/pages/AdvancedSettings/utils/api.js +13 -0
  32. package/admin/src/pages/AdvancedSettings/utils/layout.js +96 -0
  33. package/admin/src/pages/AdvancedSettings/utils/schema.js +19 -0
  34. package/admin/src/pages/EmailTemplates/components/EmailForm.js +173 -0
  35. package/admin/src/pages/EmailTemplates/components/EmailTable.js +121 -0
  36. package/admin/src/pages/EmailTemplates/index.js +162 -0
  37. package/admin/src/pages/EmailTemplates/utils/api.js +13 -0
  38. package/admin/src/pages/EmailTemplates/utils/schema.js +22 -0
  39. package/admin/src/pages/Providers/index.js +274 -0
  40. package/admin/src/pages/Providers/reducer.js +54 -0
  41. package/admin/src/pages/Providers/utils/api.js +21 -0
  42. package/admin/src/pages/Providers/utils/createProvidersArray.js +21 -0
  43. package/admin/src/pages/Providers/utils/forms.js +244 -0
  44. package/admin/src/pages/Roles/CreatePage/index.js +177 -0
  45. package/admin/src/pages/Roles/CreatePage/utils/schema.js +9 -0
  46. package/admin/src/pages/Roles/EditPage/index.js +190 -0
  47. package/admin/src/pages/Roles/EditPage/utils/schema.js +9 -0
  48. package/admin/src/pages/Roles/ListPage/components/TableBody.js +96 -0
  49. package/admin/src/pages/Roles/ListPage/index.js +216 -0
  50. package/admin/src/pages/Roles/ListPage/utils/api.js +28 -0
  51. package/admin/src/pages/Roles/ProtectedCreatePage/index.js +12 -0
  52. package/admin/src/pages/Roles/ProtectedEditPage/index.js +12 -0
  53. package/admin/src/pages/Roles/ProtectedListPage/index.js +15 -0
  54. package/admin/src/pages/Roles/index.js +27 -0
  55. package/admin/src/permissions.js +31 -0
  56. package/admin/src/pluginId.js +5 -0
  57. package/admin/src/translations/ar.json +40 -0
  58. package/admin/src/translations/cs.json +46 -0
  59. package/admin/src/translations/de.json +58 -0
  60. package/admin/src/translations/dk.json +83 -0
  61. package/admin/src/translations/en.json +83 -0
  62. package/admin/src/translations/es.json +83 -0
  63. package/admin/src/translations/fr.json +46 -0
  64. package/admin/src/translations/id.json +58 -0
  65. package/admin/src/translations/it.json +58 -0
  66. package/admin/src/translations/ja.json +44 -0
  67. package/admin/src/translations/ko.json +83 -0
  68. package/admin/src/translations/ms.json +45 -0
  69. package/admin/src/translations/nl.json +44 -0
  70. package/admin/src/translations/pl.json +83 -0
  71. package/admin/src/translations/pt-BR.json +40 -0
  72. package/admin/src/translations/pt.json +44 -0
  73. package/admin/src/translations/ru.json +58 -0
  74. package/admin/src/translations/sk.json +46 -0
  75. package/admin/src/translations/sv.json +58 -0
  76. package/admin/src/translations/th.json +56 -0
  77. package/admin/src/translations/tr.json +44 -0
  78. package/admin/src/translations/uk.json +45 -0
  79. package/admin/src/translations/vi.json +46 -0
  80. package/admin/src/translations/zh-Hans.json +62 -0
  81. package/admin/src/translations/zh.json +44 -0
  82. package/admin/src/utils/axiosInstance.js +36 -0
  83. package/admin/src/utils/cleanPermissions.js +25 -0
  84. package/admin/src/utils/formatPluginName.js +26 -0
  85. package/admin/src/utils/formatPolicies.js +8 -0
  86. package/admin/src/utils/getRequestURL.js +5 -0
  87. package/admin/src/utils/getTrad.js +5 -0
  88. package/admin/src/utils/index.js +5 -0
  89. package/documentation/content-api.yaml +848 -0
  90. package/jest.config.front.js +10 -0
  91. package/package.json +60 -0
  92. package/server/bootstrap/grant-config.js +123 -0
  93. package/server/bootstrap/index.js +133 -0
  94. package/server/bootstrap/users-permissions-actions.js +80 -0
  95. package/server/config.js +23 -0
  96. package/server/content-types/index.js +11 -0
  97. package/server/content-types/permission/index.js +34 -0
  98. package/server/content-types/role/index.js +51 -0
  99. package/server/content-types/user/index.js +72 -0
  100. package/server/content-types/user/schema-config.js +15 -0
  101. package/server/controllers/auth.js +398 -0
  102. package/server/controllers/content-manager-user.js +175 -0
  103. package/server/controllers/index.js +17 -0
  104. package/server/controllers/permissions.js +26 -0
  105. package/server/controllers/role.js +77 -0
  106. package/server/controllers/settings.js +85 -0
  107. package/server/controllers/user.js +198 -0
  108. package/server/controllers/validation/auth.js +57 -0
  109. package/server/controllers/validation/email-template.js +50 -0
  110. package/server/controllers/validation/user.js +26 -0
  111. package/server/graphql/index.js +44 -0
  112. package/server/graphql/mutations/auth/change-password.js +38 -0
  113. package/server/graphql/mutations/auth/email-confirmation.js +39 -0
  114. package/server/graphql/mutations/auth/forgot-password.js +35 -0
  115. package/server/graphql/mutations/auth/login.js +35 -0
  116. package/server/graphql/mutations/auth/register.js +36 -0
  117. package/server/graphql/mutations/auth/reset-password.js +38 -0
  118. package/server/graphql/mutations/crud/role/create-role.js +34 -0
  119. package/server/graphql/mutations/crud/role/delete-role.js +25 -0
  120. package/server/graphql/mutations/crud/role/update-role.js +35 -0
  121. package/server/graphql/mutations/crud/user/create-user.js +45 -0
  122. package/server/graphql/mutations/crud/user/delete-user.js +39 -0
  123. package/server/graphql/mutations/crud/user/update-user.js +46 -0
  124. package/server/graphql/mutations/index.js +43 -0
  125. package/server/graphql/queries/index.js +13 -0
  126. package/server/graphql/queries/me.js +17 -0
  127. package/server/graphql/resolvers-configs.js +42 -0
  128. package/server/graphql/types/create-role-payload.js +11 -0
  129. package/server/graphql/types/delete-role-payload.js +11 -0
  130. package/server/graphql/types/index.js +21 -0
  131. package/server/graphql/types/login-input.js +13 -0
  132. package/server/graphql/types/login-payload.js +12 -0
  133. package/server/graphql/types/me-role.js +14 -0
  134. package/server/graphql/types/me.js +16 -0
  135. package/server/graphql/types/password-payload.js +11 -0
  136. package/server/graphql/types/register-input.js +13 -0
  137. package/server/graphql/types/update-role-payload.js +11 -0
  138. package/server/graphql/utils.js +27 -0
  139. package/server/index.js +21 -0
  140. package/server/middlewares/index.js +7 -0
  141. package/server/middlewares/rateLimit.js +27 -0
  142. package/server/register.js +23 -0
  143. package/server/routes/admin/index.js +10 -0
  144. package/server/routes/admin/permissions.js +20 -0
  145. package/server/routes/admin/role.js +79 -0
  146. package/server/routes/admin/settings.js +95 -0
  147. package/server/routes/content-api/auth.js +82 -0
  148. package/server/routes/content-api/index.js +11 -0
  149. package/server/routes/content-api/permissions.js +9 -0
  150. package/server/routes/content-api/role.js +29 -0
  151. package/server/routes/content-api/user.js +60 -0
  152. package/server/routes/index.js +6 -0
  153. package/server/services/index.js +17 -0
  154. package/server/services/jwt.js +55 -0
  155. package/server/services/providers-registry.js +292 -0
  156. package/server/services/providers.js +115 -0
  157. package/server/services/role.js +177 -0
  158. package/server/services/user.js +140 -0
  159. package/server/services/users-permissions.js +236 -0
  160. package/server/strategies/users-permissions.js +102 -0
  161. package/server/utils/index.d.ts +16 -0
  162. package/server/utils/index.js +12 -0
  163. package/server/utils/sanitize/index.js +9 -0
  164. package/server/utils/sanitize/sanitizers.js +19 -0
  165. package/server/utils/sanitize/visitors/index.js +5 -0
  166. package/server/utils/sanitize/visitors/remove-user-relation-from-role-entities.js +11 -0
  167. package/strapi-admin.js +3 -0
  168. package/strapi-server.js +3 -0
@@ -0,0 +1,123 @@
1
+ // NOTE TO PLUGINS DEVELOPERS:
2
+ // If you modify this file by adding new options to the plugin entry point
3
+ // Here's the file: strapi/docs/3.0.0-beta.x/plugin-development/frontend-field-api.md
4
+ // Here's the file: strapi/docs/3.0.0-beta.x/guides/registering-a-field-in-admin.md
5
+ // Also the strapi-generate-plugins/files/admin/src/index.js needs to be updated
6
+ // IF THE DOC IS NOT UPDATED THE PULL REQUEST WILL NOT BE MERGED
7
+ import { prefixPluginTranslations } from '@strapi/helper-plugin';
8
+ import pluginPkg from '../../package.json';
9
+ import pluginPermissions from './permissions';
10
+ import pluginId from './pluginId';
11
+ import getTrad from './utils/getTrad';
12
+
13
+ const name = pluginPkg.strapi.name;
14
+
15
+ export default {
16
+ register(app) {
17
+ // Create the plugin's settings section
18
+ app.createSettingSection(
19
+ {
20
+ id: pluginId,
21
+ intlLabel: {
22
+ id: getTrad('Settings.section-label'),
23
+ defaultMessage: 'Users & Permissions plugin',
24
+ },
25
+ },
26
+ [
27
+ {
28
+ intlLabel: {
29
+ id: 'global.roles',
30
+ defaultMessage: 'Roles',
31
+ },
32
+ id: 'roles',
33
+ to: `/settings/${pluginId}/roles`,
34
+ async Component() {
35
+ const component = await import(
36
+ /* webpackChunkName: "users-roles-settings-page" */ './pages/Roles'
37
+ );
38
+
39
+ return component;
40
+ },
41
+ permissions: pluginPermissions.accessRoles,
42
+ },
43
+ {
44
+ intlLabel: {
45
+ id: getTrad('HeaderNav.link.providers'),
46
+ defaultMessage: 'Providers',
47
+ },
48
+ id: 'providers',
49
+ to: `/settings/${pluginId}/providers`,
50
+ async Component() {
51
+ const component = await import(
52
+ /* webpackChunkName: "users-providers-settings-page" */ './pages/Providers'
53
+ );
54
+
55
+ return component;
56
+ },
57
+ permissions: pluginPermissions.readProviders,
58
+ },
59
+ {
60
+ intlLabel: {
61
+ id: getTrad('HeaderNav.link.emailTemplates'),
62
+ defaultMessage: 'Email templates',
63
+ },
64
+ id: 'email-templates',
65
+ to: `/settings/${pluginId}/email-templates`,
66
+ async Component() {
67
+ const component = await import(
68
+ /* webpackChunkName: "users-email-settings-page" */ './pages/EmailTemplates'
69
+ );
70
+
71
+ return component;
72
+ },
73
+ permissions: pluginPermissions.readEmailTemplates,
74
+ },
75
+ {
76
+ intlLabel: {
77
+ id: getTrad('HeaderNav.link.advancedSettings'),
78
+ defaultMessage: 'Advanced Settings',
79
+ },
80
+ id: 'advanced-settings',
81
+ to: `/settings/${pluginId}/advanced-settings`,
82
+ async Component() {
83
+ const component = await import(
84
+ /* webpackChunkName: "users-advanced-settings-page" */ './pages/AdvancedSettings'
85
+ );
86
+
87
+ return component;
88
+ },
89
+ permissions: pluginPermissions.readAdvancedSettings,
90
+ },
91
+ ]
92
+ );
93
+
94
+ app.registerPlugin({
95
+ id: pluginId,
96
+ name,
97
+ });
98
+ },
99
+ bootstrap() {},
100
+ async registerTrads({ locales }) {
101
+ const importedTrads = await Promise.all(
102
+ locales.map((locale) => {
103
+ return import(
104
+ /* webpackChunkName: "users-permissions-translation-[request]" */ `./translations/${locale}.json`
105
+ )
106
+ .then(({ default: data }) => {
107
+ return {
108
+ data: prefixPluginTranslations(data, pluginId),
109
+ locale,
110
+ };
111
+ })
112
+ .catch(() => {
113
+ return {
114
+ data: {},
115
+ locale,
116
+ };
117
+ });
118
+ })
119
+ );
120
+
121
+ return Promise.resolve(importedTrads);
122
+ },
123
+ };
@@ -0,0 +1,238 @@
1
+ import React, { useMemo } from 'react';
2
+ import { useQuery, useMutation, useQueryClient } from 'react-query';
3
+ import { useIntl } from 'react-intl';
4
+ import { Formik } from 'formik';
5
+ import {
6
+ CheckPagePermissions,
7
+ Form,
8
+ GenericInput,
9
+ LoadingIndicatorPage,
10
+ SettingsPageTitle,
11
+ useFocusWhenNavigate,
12
+ useNotification,
13
+ useOverlayBlocker,
14
+ useRBAC,
15
+ } from '@strapi/helper-plugin';
16
+ import { useNotifyAT } from '@strapi/design-system/LiveRegions';
17
+ import { Main } from '@strapi/design-system/Main';
18
+ import { HeaderLayout, ContentLayout } from '@strapi/design-system/Layout';
19
+ import { Button } from '@strapi/design-system/Button';
20
+ import { Box } from '@strapi/design-system/Box';
21
+ import { Stack } from '@strapi/design-system/Stack';
22
+ import { Select, Option } from '@strapi/design-system/Select';
23
+ import { Typography } from '@strapi/design-system/Typography';
24
+ import { Grid, GridItem } from '@strapi/design-system/Grid';
25
+ import Check from '@strapi/icons/Check';
26
+ import pluginPermissions from '../../permissions';
27
+ import { getTrad } from '../../utils';
28
+ import layout from './utils/layout';
29
+ import schema from './utils/schema';
30
+ import { fetchData, putAdvancedSettings } from './utils/api';
31
+
32
+ const ProtectedAdvancedSettingsPage = () => (
33
+ <CheckPagePermissions permissions={pluginPermissions.readAdvancedSettings}>
34
+ <AdvancedSettingsPage />
35
+ </CheckPagePermissions>
36
+ );
37
+
38
+ const AdvancedSettingsPage = () => {
39
+ const { formatMessage } = useIntl();
40
+ const toggleNotification = useNotification();
41
+ const { lockApp, unlockApp } = useOverlayBlocker();
42
+ const { notifyStatus } = useNotifyAT();
43
+ const queryClient = useQueryClient();
44
+ useFocusWhenNavigate();
45
+
46
+ const updatePermissions = useMemo(
47
+ () => ({ update: pluginPermissions.updateAdvancedSettings }),
48
+ []
49
+ );
50
+ const {
51
+ isLoading: isLoadingForPermissions,
52
+ allowedActions: { canUpdate },
53
+ } = useRBAC(updatePermissions);
54
+
55
+ const { status: isLoadingData, data } = useQuery('advanced', () => fetchData(), {
56
+ onSuccess() {
57
+ notifyStatus(
58
+ formatMessage({
59
+ id: getTrad('Form.advancedSettings.data.loaded'),
60
+ defaultMessage: 'Advanced settings data has been loaded',
61
+ })
62
+ );
63
+ },
64
+ onError() {
65
+ toggleNotification({
66
+ type: 'warning',
67
+ message: { id: getTrad('notification.error'), defaultMessage: 'An error occured' },
68
+ });
69
+ },
70
+ });
71
+
72
+ const isLoading = isLoadingForPermissions || isLoadingData !== 'success';
73
+
74
+ const submitMutation = useMutation((body) => putAdvancedSettings(body), {
75
+ async onSuccess() {
76
+ await queryClient.invalidateQueries('advanced');
77
+ toggleNotification({
78
+ type: 'success',
79
+ message: { id: getTrad('notification.success.saved'), defaultMessage: 'Saved' },
80
+ });
81
+
82
+ unlockApp();
83
+ },
84
+ onError() {
85
+ toggleNotification({
86
+ type: 'warning',
87
+ message: { id: getTrad('notification.error'), defaultMessage: 'An error occured' },
88
+ });
89
+ unlockApp();
90
+ },
91
+ refetchActive: true,
92
+ });
93
+
94
+ const { isLoading: isSubmittingForm } = submitMutation;
95
+
96
+ const handleSubmit = async (body) => {
97
+ lockApp();
98
+
99
+ const urlConfirmation = body.email_confirmation ? body.email_confirmation_redirection : '';
100
+
101
+ await submitMutation.mutateAsync({ ...body, email_confirmation_redirection: urlConfirmation });
102
+ };
103
+
104
+ if (isLoading) {
105
+ return (
106
+ <Main aria-busy="true">
107
+ <SettingsPageTitle
108
+ name={formatMessage({
109
+ id: getTrad('HeaderNav.link.advancedSettings'),
110
+ defaultMessage: 'Advanced Settings',
111
+ })}
112
+ />
113
+ <HeaderLayout
114
+ title={formatMessage({
115
+ id: getTrad('HeaderNav.link.advancedSettings'),
116
+ defaultMessage: 'Advanced Settings',
117
+ })}
118
+ />
119
+ <ContentLayout>
120
+ <LoadingIndicatorPage />
121
+ </ContentLayout>
122
+ </Main>
123
+ );
124
+ }
125
+
126
+ return (
127
+ <Main aria-busy={isSubmittingForm}>
128
+ <SettingsPageTitle
129
+ name={formatMessage({
130
+ id: getTrad('HeaderNav.link.advancedSettings'),
131
+ defaultMessage: 'Advanced Settings',
132
+ })}
133
+ />
134
+ <Formik
135
+ onSubmit={handleSubmit}
136
+ initialValues={data.settings}
137
+ validateOnChange={false}
138
+ validationSchema={schema}
139
+ enableReinitialize
140
+ >
141
+ {({ errors, values, handleChange, isSubmitting }) => {
142
+ return (
143
+ <Form>
144
+ <HeaderLayout
145
+ title={formatMessage({
146
+ id: getTrad('HeaderNav.link.advancedSettings'),
147
+ defaultMessage: 'Advanced Settings',
148
+ })}
149
+ primaryAction={
150
+ <Button
151
+ loading={isSubmitting}
152
+ type="submit"
153
+ disabled={!canUpdate}
154
+ startIcon={<Check />}
155
+ size="L"
156
+ >
157
+ {formatMessage({ id: 'global.save', defaultMessage: 'Save' })}
158
+ </Button>
159
+ }
160
+ />
161
+ <ContentLayout>
162
+ <Box
163
+ background="neutral0"
164
+ hasRadius
165
+ shadow="filterShadow"
166
+ paddingTop={6}
167
+ paddingBottom={6}
168
+ paddingLeft={7}
169
+ paddingRight={7}
170
+ >
171
+ <Stack spacing={4}>
172
+ <Typography variant="delta" as="h2">
173
+ {formatMessage({
174
+ id: 'global.settings',
175
+ defaultMessage: 'Settings',
176
+ })}
177
+ </Typography>
178
+ <Grid gap={6}>
179
+ <GridItem col={6} s={12}>
180
+ <Select
181
+ label={formatMessage({
182
+ id: getTrad('EditForm.inputSelect.label.role'),
183
+ defaultMessage: 'Default role for authenticated users',
184
+ })}
185
+ value={values.default_role}
186
+ hint={formatMessage({
187
+ id: getTrad('EditForm.inputSelect.description.role'),
188
+ defaultMessage:
189
+ 'It will attach the new authenticated user to the selected role.',
190
+ })}
191
+ onChange={(e) =>
192
+ handleChange({ target: { name: 'default_role', value: e } })
193
+ }
194
+ >
195
+ {data.roles.map((role) => {
196
+ return (
197
+ <Option key={role.type} value={role.type}>
198
+ {role.name}
199
+ </Option>
200
+ );
201
+ })}
202
+ </Select>
203
+ </GridItem>
204
+ {layout.map((input) => {
205
+ let value = values[input.name];
206
+
207
+ if (!value) {
208
+ value = input.type === 'bool' ? false : '';
209
+ }
210
+
211
+ return (
212
+ <GridItem key={input.name} {...input.size}>
213
+ <GenericInput
214
+ {...input}
215
+ value={value}
216
+ error={errors[input.name]}
217
+ disabled={
218
+ input.name === 'email_confirmation_redirection' &&
219
+ values.email_confirmation === false
220
+ }
221
+ onChange={handleChange}
222
+ />
223
+ </GridItem>
224
+ );
225
+ })}
226
+ </Grid>
227
+ </Stack>
228
+ </Box>
229
+ </ContentLayout>
230
+ </Form>
231
+ );
232
+ }}
233
+ </Formik>
234
+ </Main>
235
+ );
236
+ };
237
+
238
+ export default ProtectedAdvancedSettingsPage;
@@ -0,0 +1,13 @@
1
+ import { axiosInstance, getRequestURL } from '../../../utils';
2
+
3
+ const fetchData = async () => {
4
+ const { data } = await axiosInstance.get(getRequestURL('advanced'));
5
+
6
+ return data;
7
+ };
8
+
9
+ const putAdvancedSettings = (body) => {
10
+ return axiosInstance.put(getRequestURL('advanced'), body);
11
+ };
12
+
13
+ export { fetchData, putAdvancedSettings };
@@ -0,0 +1,96 @@
1
+ import { getTrad } from '../../../utils';
2
+
3
+ const layout = [
4
+ {
5
+ intlLabel: {
6
+ id: getTrad('EditForm.inputToggle.label.email'),
7
+ defaultMessage: 'One account per email address',
8
+ },
9
+ description: {
10
+ id: getTrad('EditForm.inputToggle.description.email'),
11
+ defaultMessage:
12
+ 'Disallow the user to create multiple accounts using the same email address with different authentication providers.',
13
+ },
14
+ name: 'unique_email',
15
+ type: 'bool',
16
+ size: {
17
+ col: 12,
18
+ xs: 12,
19
+ },
20
+ },
21
+ {
22
+ intlLabel: {
23
+ id: getTrad('EditForm.inputToggle.label.sign-up'),
24
+ defaultMessage: 'Enable sign-ups',
25
+ },
26
+ description: {
27
+ id: getTrad('EditForm.inputToggle.description.sign-up'),
28
+ defaultMessage:
29
+ 'When disabled (OFF), the registration process is forbidden. No one can subscribe anymore no matter the used provider.',
30
+ },
31
+ name: 'allow_register',
32
+ type: 'bool',
33
+ size: {
34
+ col: 12,
35
+ xs: 12,
36
+ },
37
+ },
38
+ {
39
+ intlLabel: {
40
+ id: getTrad('EditForm.inputToggle.label.email-reset-password'),
41
+ defaultMessage: 'Reset password page',
42
+ },
43
+ description: {
44
+ id: getTrad('EditForm.inputToggle.description.email-reset-password'),
45
+ defaultMessage: "URL of your application's reset password page.",
46
+ },
47
+ placeholder: {
48
+ id: getTrad('EditForm.inputToggle.placeholder.email-reset-password'),
49
+ defaultMessage: 'ex: https://youtfrontend.com/reset-password',
50
+ },
51
+ name: 'email_reset_password',
52
+ type: 'text',
53
+ size: {
54
+ col: 6,
55
+ xs: 12,
56
+ },
57
+ },
58
+ {
59
+ intlLabel: {
60
+ id: getTrad('EditForm.inputToggle.label.email-confirmation'),
61
+ defaultMessage: 'Enable email confirmation',
62
+ },
63
+ description: {
64
+ id: getTrad('EditForm.inputToggle.description.email-confirmation'),
65
+ defaultMessage: 'When enabled (ON), new registered users receive a confirmation email.',
66
+ },
67
+ name: 'email_confirmation',
68
+ type: 'bool',
69
+ size: {
70
+ col: 12,
71
+ xs: 12,
72
+ },
73
+ },
74
+ {
75
+ intlLabel: {
76
+ id: getTrad('EditForm.inputToggle.label.email-confirmation-redirection'),
77
+ defaultMessage: 'Redirection url',
78
+ },
79
+ description: {
80
+ id: getTrad('EditForm.inputToggle.description.email-confirmation-redirection'),
81
+ defaultMessage: 'After you confirmed your email, choose where you will be redirected.',
82
+ },
83
+ placeholder: {
84
+ id: getTrad('EditForm.inputToggle.placeholder.email-confirmation-redirection'),
85
+ defaultMessage: 'ex: https://youtfrontend.com/email-confirmation',
86
+ },
87
+ name: 'email_confirmation_redirection',
88
+ type: 'text',
89
+ size: {
90
+ col: 6,
91
+ xs: 12,
92
+ },
93
+ },
94
+ ];
95
+
96
+ export default layout;
@@ -0,0 +1,19 @@
1
+ import * as yup from 'yup';
2
+ import { translatedErrors } from '@strapi/helper-plugin';
3
+
4
+ // eslint-disable-next-line prefer-regex-literals
5
+ const URL_REGEX = new RegExp('(^$)|((.+:\\/\\/.*)(d*)\\/?(.*))');
6
+
7
+ const schema = yup.object().shape({
8
+ email_confirmation_redirection: yup.mixed().when('email_confirmation', {
9
+ is: true,
10
+ then: yup.string().matches(URL_REGEX).required(),
11
+ otherwise: yup.string().nullable(),
12
+ }),
13
+ email_reset_password: yup
14
+ .string(translatedErrors.string)
15
+ .matches(URL_REGEX, translatedErrors.regex)
16
+ .nullable(),
17
+ });
18
+
19
+ export default schema;
@@ -0,0 +1,173 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { useIntl } from 'react-intl';
4
+ import { Form, GenericInput } from '@strapi/helper-plugin';
5
+ import { Formik } from 'formik';
6
+ import {
7
+ ModalLayout,
8
+ ModalHeader,
9
+ ModalFooter,
10
+ ModalBody,
11
+ } from '@strapi/design-system/ModalLayout';
12
+ import { Grid, GridItem } from '@strapi/design-system/Grid';
13
+ import { Button } from '@strapi/design-system/Button';
14
+ import { Breadcrumbs, Crumb } from '@strapi/design-system/Breadcrumbs';
15
+ import { Textarea } from '@strapi/design-system/Textarea';
16
+ import { getTrad } from '../../../utils';
17
+ import schema from '../utils/schema';
18
+
19
+ const EmailForm = ({ template, onToggle, onSubmit }) => {
20
+ const { formatMessage } = useIntl();
21
+
22
+ return (
23
+ <ModalLayout
24
+ onClose={onToggle}
25
+ labelledBy={`${formatMessage({
26
+ id: getTrad('PopUpForm.header.edit.email-templates'),
27
+ defaultMessage: 'Edit email template',
28
+ })}, ${formatMessage({ id: getTrad(template.display), defaultMessage: template.display })}`}
29
+ >
30
+ <ModalHeader>
31
+ <Breadcrumbs
32
+ label={`${formatMessage({
33
+ id: getTrad('PopUpForm.header.edit.email-templates'),
34
+ defaultMessage: 'Edit email template',
35
+ })}, ${formatMessage({
36
+ id: getTrad(template.display),
37
+ defaultMessage: template.display,
38
+ })}`}
39
+ >
40
+ <Crumb>
41
+ {formatMessage({
42
+ id: getTrad('PopUpForm.header.edit.email-templates'),
43
+ defaultMessage: 'Edit email template',
44
+ })}
45
+ </Crumb>
46
+ <Crumb>
47
+ {formatMessage({ id: getTrad(template.display), defaultMessage: template.display })}
48
+ </Crumb>
49
+ </Breadcrumbs>
50
+ </ModalHeader>
51
+ <Formik
52
+ onSubmit={onSubmit}
53
+ initialValues={template}
54
+ validateOnChange={false}
55
+ validationSchema={schema}
56
+ enableReinitialize
57
+ >
58
+ {({ errors, values, handleChange, isSubmitting }) => {
59
+ return (
60
+ <Form>
61
+ <ModalBody>
62
+ <Grid gap={5}>
63
+ <GridItem col={6} s={12}>
64
+ <GenericInput
65
+ intlLabel={{
66
+ id: getTrad('PopUpForm.Email.options.from.name.label'),
67
+ defaultMessage: 'Shipper name',
68
+ }}
69
+ name="options.from.name"
70
+ onChange={handleChange}
71
+ value={values.options.from.name}
72
+ error={errors?.options?.from?.name}
73
+ type="text"
74
+ />
75
+ </GridItem>
76
+ <GridItem col={6} s={12}>
77
+ <GenericInput
78
+ intlLabel={{
79
+ id: getTrad('PopUpForm.Email.options.from.email.label'),
80
+ defaultMessage: 'Shipper email',
81
+ }}
82
+ name="options.from.email"
83
+ onChange={handleChange}
84
+ value={values.options.from.email}
85
+ error={errors?.options?.from?.email}
86
+ type="text"
87
+ />
88
+ </GridItem>
89
+ <GridItem col={6} s={12}>
90
+ <GenericInput
91
+ intlLabel={{
92
+ id: getTrad('PopUpForm.Email.options.response_email.label'),
93
+ defaultMessage: 'Response email',
94
+ }}
95
+ name="options.response_email"
96
+ onChange={handleChange}
97
+ value={values.options.response_email}
98
+ error={errors?.options?.response_email}
99
+ type="text"
100
+ />
101
+ </GridItem>
102
+ <GridItem col={6} s={12}>
103
+ <GenericInput
104
+ intlLabel={{
105
+ id: getTrad('PopUpForm.Email.options.object.label'),
106
+ defaultMessage: 'Subject',
107
+ }}
108
+ name="options.object"
109
+ onChange={handleChange}
110
+ value={values.options.object}
111
+ error={errors?.options?.object}
112
+ type="text"
113
+ />
114
+ </GridItem>
115
+ <GridItem col={12} s={12}>
116
+ <Textarea
117
+ label={formatMessage({
118
+ id: getTrad('PopUpForm.Email.options.message.label'),
119
+ defaultMessage: 'Message',
120
+ })}
121
+ name="options.message"
122
+ onChange={handleChange}
123
+ value={values.options.message}
124
+ error={
125
+ errors?.options?.message &&
126
+ formatMessage({
127
+ id: errors.options.message,
128
+ defaultMessage: errors.options.message,
129
+ })
130
+ }
131
+ />
132
+ </GridItem>
133
+ </Grid>
134
+ </ModalBody>
135
+ <ModalFooter
136
+ startActions={
137
+ <Button onClick={onToggle} variant="tertiary">
138
+ Cancel
139
+ </Button>
140
+ }
141
+ endActions={
142
+ <Button loading={isSubmitting} type="submit">
143
+ Finish
144
+ </Button>
145
+ }
146
+ />
147
+ </Form>
148
+ );
149
+ }}
150
+ </Formik>
151
+ </ModalLayout>
152
+ );
153
+ };
154
+
155
+ EmailForm.propTypes = {
156
+ template: PropTypes.shape({
157
+ display: PropTypes.string,
158
+ icon: PropTypes.string,
159
+ options: PropTypes.shape({
160
+ from: PropTypes.shape({
161
+ name: PropTypes.string,
162
+ email: PropTypes.string,
163
+ }),
164
+ message: PropTypes.string,
165
+ object: PropTypes.string,
166
+ response_email: PropTypes.string,
167
+ }),
168
+ }).isRequired,
169
+ onSubmit: PropTypes.func.isRequired,
170
+ onToggle: PropTypes.func.isRequired,
171
+ };
172
+
173
+ export default EmailForm;