@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.
- package/LICENSE +22 -0
- package/README.md +1 -0
- package/admin/src/components/BoundRoute/getMethodColor.js +41 -0
- package/admin/src/components/BoundRoute/index.js +72 -0
- package/admin/src/components/FormModal/Input/index.js +121 -0
- package/admin/src/components/FormModal/index.js +121 -0
- package/admin/src/components/Permissions/PermissionRow/CheckboxWrapper.js +30 -0
- package/admin/src/components/Permissions/PermissionRow/SubCategory.js +114 -0
- package/admin/src/components/Permissions/PermissionRow/index.js +53 -0
- package/admin/src/components/Permissions/index.js +56 -0
- package/admin/src/components/Permissions/init.js +9 -0
- package/admin/src/components/Permissions/reducer.js +27 -0
- package/admin/src/components/Policies/index.js +60 -0
- package/admin/src/components/UsersPermissions/index.js +94 -0
- package/admin/src/components/UsersPermissions/init.js +10 -0
- package/admin/src/components/UsersPermissions/reducer.js +60 -0
- package/admin/src/contexts/UsersPermissionsContext/index.js +17 -0
- package/admin/src/hooks/index.js +5 -0
- package/admin/src/hooks/useFetchRole/index.js +64 -0
- package/admin/src/hooks/useFetchRole/reducer.js +31 -0
- package/admin/src/hooks/useForm/index.js +70 -0
- package/admin/src/hooks/useForm/reducer.js +40 -0
- package/admin/src/hooks/usePlugins/index.js +65 -0
- package/admin/src/hooks/usePlugins/init.js +5 -0
- package/admin/src/hooks/usePlugins/reducer.js +34 -0
- package/admin/src/hooks/useRolesList/index.js +63 -0
- package/admin/src/hooks/useRolesList/init.js +5 -0
- package/admin/src/hooks/useRolesList/reducer.js +31 -0
- package/admin/src/index.js +123 -0
- package/admin/src/pages/AdvancedSettings/index.js +238 -0
- package/admin/src/pages/AdvancedSettings/utils/api.js +13 -0
- package/admin/src/pages/AdvancedSettings/utils/layout.js +96 -0
- package/admin/src/pages/AdvancedSettings/utils/schema.js +19 -0
- package/admin/src/pages/EmailTemplates/components/EmailForm.js +173 -0
- package/admin/src/pages/EmailTemplates/components/EmailTable.js +121 -0
- package/admin/src/pages/EmailTemplates/index.js +162 -0
- package/admin/src/pages/EmailTemplates/utils/api.js +13 -0
- package/admin/src/pages/EmailTemplates/utils/schema.js +22 -0
- package/admin/src/pages/Providers/index.js +274 -0
- package/admin/src/pages/Providers/reducer.js +54 -0
- package/admin/src/pages/Providers/utils/api.js +21 -0
- package/admin/src/pages/Providers/utils/createProvidersArray.js +21 -0
- package/admin/src/pages/Providers/utils/forms.js +244 -0
- package/admin/src/pages/Roles/CreatePage/index.js +177 -0
- package/admin/src/pages/Roles/CreatePage/utils/schema.js +9 -0
- package/admin/src/pages/Roles/EditPage/index.js +190 -0
- package/admin/src/pages/Roles/EditPage/utils/schema.js +9 -0
- package/admin/src/pages/Roles/ListPage/components/TableBody.js +96 -0
- package/admin/src/pages/Roles/ListPage/index.js +216 -0
- package/admin/src/pages/Roles/ListPage/utils/api.js +28 -0
- package/admin/src/pages/Roles/ProtectedCreatePage/index.js +12 -0
- package/admin/src/pages/Roles/ProtectedEditPage/index.js +12 -0
- package/admin/src/pages/Roles/ProtectedListPage/index.js +15 -0
- package/admin/src/pages/Roles/index.js +27 -0
- package/admin/src/permissions.js +31 -0
- package/admin/src/pluginId.js +5 -0
- package/admin/src/translations/ar.json +40 -0
- package/admin/src/translations/cs.json +46 -0
- package/admin/src/translations/de.json +58 -0
- package/admin/src/translations/dk.json +83 -0
- package/admin/src/translations/en.json +83 -0
- package/admin/src/translations/es.json +83 -0
- package/admin/src/translations/fr.json +46 -0
- package/admin/src/translations/id.json +58 -0
- package/admin/src/translations/it.json +58 -0
- package/admin/src/translations/ja.json +44 -0
- package/admin/src/translations/ko.json +83 -0
- package/admin/src/translations/ms.json +45 -0
- package/admin/src/translations/nl.json +44 -0
- package/admin/src/translations/pl.json +83 -0
- package/admin/src/translations/pt-BR.json +40 -0
- package/admin/src/translations/pt.json +44 -0
- package/admin/src/translations/ru.json +58 -0
- package/admin/src/translations/sk.json +46 -0
- package/admin/src/translations/sv.json +58 -0
- package/admin/src/translations/th.json +56 -0
- package/admin/src/translations/tr.json +44 -0
- package/admin/src/translations/uk.json +45 -0
- package/admin/src/translations/vi.json +46 -0
- package/admin/src/translations/zh-Hans.json +62 -0
- package/admin/src/translations/zh.json +44 -0
- package/admin/src/utils/axiosInstance.js +36 -0
- package/admin/src/utils/cleanPermissions.js +25 -0
- package/admin/src/utils/formatPluginName.js +26 -0
- package/admin/src/utils/formatPolicies.js +8 -0
- package/admin/src/utils/getRequestURL.js +5 -0
- package/admin/src/utils/getTrad.js +5 -0
- package/admin/src/utils/index.js +5 -0
- package/documentation/content-api.yaml +848 -0
- package/jest.config.front.js +10 -0
- package/package.json +60 -0
- package/server/bootstrap/grant-config.js +123 -0
- package/server/bootstrap/index.js +133 -0
- package/server/bootstrap/users-permissions-actions.js +80 -0
- package/server/config.js +23 -0
- package/server/content-types/index.js +11 -0
- package/server/content-types/permission/index.js +34 -0
- package/server/content-types/role/index.js +51 -0
- package/server/content-types/user/index.js +72 -0
- package/server/content-types/user/schema-config.js +15 -0
- package/server/controllers/auth.js +398 -0
- package/server/controllers/content-manager-user.js +175 -0
- package/server/controllers/index.js +17 -0
- package/server/controllers/permissions.js +26 -0
- package/server/controllers/role.js +77 -0
- package/server/controllers/settings.js +85 -0
- package/server/controllers/user.js +198 -0
- package/server/controllers/validation/auth.js +57 -0
- package/server/controllers/validation/email-template.js +50 -0
- package/server/controllers/validation/user.js +26 -0
- package/server/graphql/index.js +44 -0
- package/server/graphql/mutations/auth/change-password.js +38 -0
- package/server/graphql/mutations/auth/email-confirmation.js +39 -0
- package/server/graphql/mutations/auth/forgot-password.js +35 -0
- package/server/graphql/mutations/auth/login.js +35 -0
- package/server/graphql/mutations/auth/register.js +36 -0
- package/server/graphql/mutations/auth/reset-password.js +38 -0
- package/server/graphql/mutations/crud/role/create-role.js +34 -0
- package/server/graphql/mutations/crud/role/delete-role.js +25 -0
- package/server/graphql/mutations/crud/role/update-role.js +35 -0
- package/server/graphql/mutations/crud/user/create-user.js +45 -0
- package/server/graphql/mutations/crud/user/delete-user.js +39 -0
- package/server/graphql/mutations/crud/user/update-user.js +46 -0
- package/server/graphql/mutations/index.js +43 -0
- package/server/graphql/queries/index.js +13 -0
- package/server/graphql/queries/me.js +17 -0
- package/server/graphql/resolvers-configs.js +42 -0
- package/server/graphql/types/create-role-payload.js +11 -0
- package/server/graphql/types/delete-role-payload.js +11 -0
- package/server/graphql/types/index.js +21 -0
- package/server/graphql/types/login-input.js +13 -0
- package/server/graphql/types/login-payload.js +12 -0
- package/server/graphql/types/me-role.js +14 -0
- package/server/graphql/types/me.js +16 -0
- package/server/graphql/types/password-payload.js +11 -0
- package/server/graphql/types/register-input.js +13 -0
- package/server/graphql/types/update-role-payload.js +11 -0
- package/server/graphql/utils.js +27 -0
- package/server/index.js +21 -0
- package/server/middlewares/index.js +7 -0
- package/server/middlewares/rateLimit.js +27 -0
- package/server/register.js +23 -0
- package/server/routes/admin/index.js +10 -0
- package/server/routes/admin/permissions.js +20 -0
- package/server/routes/admin/role.js +79 -0
- package/server/routes/admin/settings.js +95 -0
- package/server/routes/content-api/auth.js +82 -0
- package/server/routes/content-api/index.js +11 -0
- package/server/routes/content-api/permissions.js +9 -0
- package/server/routes/content-api/role.js +29 -0
- package/server/routes/content-api/user.js +60 -0
- package/server/routes/index.js +6 -0
- package/server/services/index.js +17 -0
- package/server/services/jwt.js +55 -0
- package/server/services/providers-registry.js +292 -0
- package/server/services/providers.js +115 -0
- package/server/services/role.js +177 -0
- package/server/services/user.js +140 -0
- package/server/services/users-permissions.js +236 -0
- package/server/strategies/users-permissions.js +102 -0
- package/server/utils/index.d.ts +16 -0
- package/server/utils/index.js +12 -0
- package/server/utils/sanitize/index.js +9 -0
- package/server/utils/sanitize/sanitizers.js +19 -0
- package/server/utils/sanitize/visitors/index.js +5 -0
- package/server/utils/sanitize/visitors/remove-user-relation-from-role-entities.js +11 -0
- package/strapi-admin.js +3 -0
- 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;
|