strapi-plugin-comments 2.0.2 → 2.0.6
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/.husky/pre-commit +4 -0
- package/README.md +31 -8
- package/__mocks__/initSetup.js +31 -2
- package/admin/src/components/FormSwitch/index.js +18 -0
- package/admin/src/components/FormSwitch/styles.js +8 -0
- package/admin/src/hooks/useConfig.js +49 -0
- package/admin/src/index.js +31 -2
- package/admin/src/pages/Details/index.js +5 -2
- package/admin/src/pages/Settings/components/RestartAlert/styles.js +8 -0
- package/admin/src/pages/Settings/index.js +392 -0
- package/admin/src/pages/Settings/utils/api.js +60 -0
- package/admin/src/permissions.js +3 -0
- package/admin/src/translations/en.json +46 -1
- package/admin/src/utils/handleAPIError.js +3 -2
- package/admin/src/utils/index.js +2 -1
- package/admin/src/utils/parseRegExp.js +10 -0
- package/package.json +10 -7
- package/server/bootstrap.js +24 -0
- package/server/config/index.js +1 -0
- package/server/controllers/admin.js +42 -8
- package/server/controllers/client.js +11 -2
- package/server/controllers/utils/__tests__/parsers.test.js +94 -0
- package/server/controllers/utils/parsers.js +15 -13
- package/server/graphql/index.js +7 -8
- package/server/graphql/queries/findAllFlat.js +1 -1
- package/server/graphql/resolvers-config.js +2 -4
- package/server/graphql/types/index.js +3 -0
- package/server/graphql/types/report-reason.js +10 -10
- package/server/graphql/types/response-find-all.js +7 -0
- package/server/graphql/types/response-meta.js +6 -0
- package/server/graphql/types/response-pagination.js +11 -0
- package/server/register.js +1 -3
- package/server/routes/admin.js +32 -0
- package/server/services/__tests__/common.test.js +95 -14
- package/server/services/admin.js +57 -6
- package/server/services/client.js +14 -8
- package/server/services/common.js +92 -15
- package/server/services/utils/__tests__/functions.test.js +12 -1
- package/server/services/utils/functions.js +9 -1
- package/server/utils/constants.js +9 -0
- package/strapi-server.js +12 -5
package/README.md
CHANGED
|
@@ -84,7 +84,7 @@ In our minimum support we're following [official Node.js releases timelines](htt
|
|
|
84
84
|
|
|
85
85
|
**Supported Strapi versions**:
|
|
86
86
|
|
|
87
|
-
- Strapi v4.0
|
|
87
|
+
- Strapi v4.1.0 (recently tested)
|
|
88
88
|
- Strapi v4.x
|
|
89
89
|
|
|
90
90
|
> This plugin is designed for **Strapi v4** and is not working with v3.x. To get version for **Strapi v3** install version [v1.x](https://github.com/VirtusLab-Open-Source/strapi-plugin-comments/tree/strapi-v3).
|
|
@@ -92,6 +92,16 @@ In our minimum support we're following [official Node.js releases timelines](htt
|
|
|
92
92
|
**We recommend always using the latest version of Strapi to start your new projects**.
|
|
93
93
|
|
|
94
94
|
## 🔧 Configuration
|
|
95
|
+
|
|
96
|
+
### In `v2.0.3` and newest
|
|
97
|
+
|
|
98
|
+
Version `2.0.3` introduce the intuitive **Settings** page which you can easly access via `Strapi Settings -> Section: Comments Plugin -> Configuration`. On dedicated page you will be able to setup all crucial properties which drives the plugin and customize each individual collection for which **Comments plugin** should be enabled.
|
|
99
|
+
|
|
100
|
+
> *Note*
|
|
101
|
+
> Default configuration for your plugin is fetched from `config/plugins.js` or directly from the plugin itself. If you would like to customize the default state to which you might revert, please follow the next section.
|
|
102
|
+
|
|
103
|
+
### In `v2.0.2` and older + default configuration state for `v2.0.3` and newest
|
|
104
|
+
|
|
95
105
|
To setup amend default plugin configuration we recommend to put following snippet as part of `config/plugins.js` or `config/<env>/plugins.js` file. If the file does not exist yet, you have to create it manually. If you've got already configurations for other plugins stores by this way, use just the `comments` part within exising `plugins` item.
|
|
96
106
|
|
|
97
107
|
|
|
@@ -99,6 +109,8 @@ To setup amend default plugin configuration we recommend to put following snippe
|
|
|
99
109
|
module.exports = ({ env }) => ({
|
|
100
110
|
//...
|
|
101
111
|
comments: {
|
|
112
|
+
enabled: true,
|
|
113
|
+
config: {
|
|
102
114
|
badWords: false,
|
|
103
115
|
moderatorRoles: ["Authenticated"],
|
|
104
116
|
approvalFlow: ['api::page.page'],
|
|
@@ -112,6 +124,7 @@ To setup amend default plugin configuration we recommend to put following snippe
|
|
|
112
124
|
gql: {
|
|
113
125
|
// ...
|
|
114
126
|
},
|
|
127
|
+
},
|
|
115
128
|
},
|
|
116
129
|
//...
|
|
117
130
|
});
|
|
@@ -128,11 +141,14 @@ To setup amend default plugin configuration we recommend to put following snippe
|
|
|
128
141
|
## Additional GQL Configuration
|
|
129
142
|
All you need to do is to install and enable `@strapi/plugin-graphql` for you instance based on the **[official Strapi v4 docs](https://docs.strapi.io/developer-docs/latest/plugins/graphql.html#configurations)** and decide if you would like to call it by anyone (open for world) or only by authenticated users (Strapi users).
|
|
130
143
|
|
|
144
|
+
> **Important!**
|
|
145
|
+
> If you're using `config/plugins.js` to configure your plugins , please put `comments` property before `graphql`. Otherwise types are not going to be properly added to GraphQL Schema. That's because of dynamic types which base on plugin configuration which are added on `boostrap` stage, not `register`. This is not valid if you're using `graphql` plugin without any custom configuration, so most of cases in real.
|
|
146
|
+
|
|
131
147
|
```json
|
|
132
148
|
{
|
|
133
149
|
// ...
|
|
134
|
-
gql: {
|
|
135
|
-
auth: true, // Default: false
|
|
150
|
+
"gql": {
|
|
151
|
+
"auth": true, // Default: false
|
|
136
152
|
},
|
|
137
153
|
// ...
|
|
138
154
|
}
|
|
@@ -213,10 +229,10 @@ Return a hierarchical tree structure of comments for specified instance of Conte
|
|
|
213
229
|
[
|
|
214
230
|
{
|
|
215
231
|
// -- Comment Model fields ---,
|
|
216
|
-
children: [
|
|
232
|
+
"children": [
|
|
217
233
|
{
|
|
218
234
|
// -- Comment Model fields ---,
|
|
219
|
-
children: [
|
|
235
|
+
"children": [
|
|
220
236
|
// ...
|
|
221
237
|
]
|
|
222
238
|
},
|
|
@@ -242,7 +258,8 @@ Return a flat structure of comments for specified instance of Content Type like
|
|
|
242
258
|
**Example response body**
|
|
243
259
|
|
|
244
260
|
```json
|
|
245
|
-
|
|
261
|
+
{
|
|
262
|
+
"data": [
|
|
246
263
|
{
|
|
247
264
|
// -- Comment Model fields ---
|
|
248
265
|
},
|
|
@@ -250,7 +267,13 @@ Return a flat structure of comments for specified instance of Content Type like
|
|
|
250
267
|
// -- Comment Model fields ---
|
|
251
268
|
},
|
|
252
269
|
// ...
|
|
253
|
-
]
|
|
270
|
+
],
|
|
271
|
+
"meta": {
|
|
272
|
+
"pagination": {
|
|
273
|
+
// payload based on Strapi REST Pagination specification
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
254
277
|
```
|
|
255
278
|
|
|
256
279
|
**Possible response codes**
|
|
@@ -360,7 +383,7 @@ Updates a specified Comment content based on it `commentId` and related to speci
|
|
|
360
383
|
|
|
361
384
|
*GraphQL equivalent: [Public GraphQL API -> Delete Comment](#delete-comment-1)*
|
|
362
385
|
|
|
363
|
-
`DELETE <host>/api/comments/api::<collection name>.<content type name>:<entity id
|
|
386
|
+
`DELETE <host>/api/comments/api::<collection name>.<content type name>:<entity id>/comment/<commentId>?authorId=<authorId>`
|
|
364
387
|
|
|
365
388
|
Deletes a specified Comment based on it `commentId` and related to specified instance of Content Type like for example `Page` with `ID: 1`.
|
|
366
389
|
|
package/__mocks__/initSetup.js
CHANGED
|
@@ -1,13 +1,42 @@
|
|
|
1
1
|
const { get, set } = require('lodash');
|
|
2
2
|
|
|
3
|
-
module.exports = (config = {}) => {
|
|
3
|
+
module.exports = (config = {}, toStore = false) => {
|
|
4
4
|
const mock = {
|
|
5
|
+
db: toStore ? {
|
|
6
|
+
plugin: {
|
|
7
|
+
comments: {
|
|
8
|
+
config: { ...config },
|
|
9
|
+
},
|
|
10
|
+
},
|
|
11
|
+
}: {},
|
|
5
12
|
getRef: function() {
|
|
6
13
|
return this;
|
|
7
14
|
},
|
|
8
15
|
plugin: function(name) {
|
|
9
16
|
return this.plugins[name];
|
|
10
17
|
},
|
|
18
|
+
store: async function(storeProps) {
|
|
19
|
+
const { type, name } = storeProps; // { type: 'plugin', name: 'comments' }
|
|
20
|
+
|
|
21
|
+
const mockedStore = {
|
|
22
|
+
get: async function(props) { // { key: 'config' }
|
|
23
|
+
const { key } = props;
|
|
24
|
+
return new Promise(resolve => resolve(get(mock.db, `${type}.${name}.${key}`, undefined)));
|
|
25
|
+
},
|
|
26
|
+
set: async function(props) { // { key: 'config', value: {...} }
|
|
27
|
+
const { key, value } = props;
|
|
28
|
+
set(mock.db, `${type}.${name}.${key}`, value);
|
|
29
|
+
return this.get(key);
|
|
30
|
+
},
|
|
31
|
+
delete: async function(props) { // { key: 'config' }
|
|
32
|
+
const { key } = props;
|
|
33
|
+
set(mock.db, `${type}.${name}.${key}`, undefined);
|
|
34
|
+
return new Promise(resolve => resolve(true));
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
return new Promise(resolve => resolve(mockedStore));
|
|
39
|
+
},
|
|
11
40
|
plugins: {
|
|
12
41
|
comments: {
|
|
13
42
|
service: function(name) {
|
|
@@ -44,7 +73,7 @@ module.exports = (config = {}) => {
|
|
|
44
73
|
entryLabel: {
|
|
45
74
|
'api::blog-post.blog-post': ['alternative_subject'],
|
|
46
75
|
},
|
|
47
|
-
...config
|
|
76
|
+
...(toStore ? {} : config)
|
|
48
77
|
}
|
|
49
78
|
}
|
|
50
79
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* Form Switch
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import React from 'react';
|
|
8
|
+
import { Stack } from '@strapi/design-system/Stack';
|
|
9
|
+
import { Typography } from '@strapi/design-system/Typography';
|
|
10
|
+
import { StyledSwitch } from './styles';
|
|
11
|
+
|
|
12
|
+
const FormSwitch = ({ label, hint, ...props }) => (<Stack size={1}>
|
|
13
|
+
{ label && (<Typography variant="pi" as="label" fontWeight="bold" textColor="neutral800">{ label }</Typography>) }
|
|
14
|
+
<StyledSwitch label={label} { ...props } />
|
|
15
|
+
{ hint && (<Typography variant="pi" as="label" textColor="neutral600">{ hint }</Typography>) }
|
|
16
|
+
</Stack>);
|
|
17
|
+
|
|
18
|
+
export default FormSwitch;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { useQuery, useMutation, useQueryClient } from 'react-query';
|
|
2
|
+
import { fetchConfig, restartStrapi, restoreConfig, updateConfig } from '../pages/Settings/utils/api';
|
|
3
|
+
import pluginId from '../pluginId';
|
|
4
|
+
|
|
5
|
+
const useConfig = (toggleNotification) => {
|
|
6
|
+
const queryClient = useQueryClient();
|
|
7
|
+
|
|
8
|
+
const fetch = useQuery('get-config', () =>
|
|
9
|
+
fetchConfig(toggleNotification)
|
|
10
|
+
);
|
|
11
|
+
|
|
12
|
+
const handleError = (type, callback = () => {}) => {
|
|
13
|
+
toggleNotification({
|
|
14
|
+
type: 'warning',
|
|
15
|
+
message: `${pluginId}.page.settings.notification.${type}.error`,
|
|
16
|
+
});
|
|
17
|
+
callback();
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const handleSuccess = (type, callback = () => {}, invalidateQueries = true) => {
|
|
21
|
+
if (invalidateQueries) {
|
|
22
|
+
queryClient.invalidateQueries('get-config');
|
|
23
|
+
};
|
|
24
|
+
toggleNotification({
|
|
25
|
+
type: 'success',
|
|
26
|
+
message: `${pluginId}.page.settings.notification.${type}.success`,
|
|
27
|
+
});
|
|
28
|
+
callback();
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const submitMutation = useMutation(updateConfig, {
|
|
32
|
+
onSuccess: () => handleSuccess('submit'),
|
|
33
|
+
onError: () => handleError('submit'),
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const restoreMutation = useMutation(restoreConfig, {
|
|
37
|
+
onSuccess: () => handleSuccess('restore'),
|
|
38
|
+
onError: () => handleError('restore'),
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
const restartMutation = useMutation(restartStrapi, {
|
|
42
|
+
onSuccess: () => handleSuccess('restart', () => {}, false),
|
|
43
|
+
onError: () => handleError('restart'),
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
return { fetch, restartMutation, submitMutation, restoreMutation };
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export default useConfig;
|
package/admin/src/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import PluginIcon from './components/PluginIcon';
|
|
|
6
6
|
import pluginPermissions from './permissions';
|
|
7
7
|
import reducers from './reducers';
|
|
8
8
|
|
|
9
|
-
const name = pluginPkg.strapi
|
|
9
|
+
const { name, displayName } = pluginPkg.strapi;
|
|
10
10
|
|
|
11
11
|
export default {
|
|
12
12
|
register(app) {
|
|
@@ -16,7 +16,7 @@ export default {
|
|
|
16
16
|
icon: PluginIcon,
|
|
17
17
|
intlLabel: {
|
|
18
18
|
id: `${pluginId}.plugin.name`,
|
|
19
|
-
defaultMessage:
|
|
19
|
+
defaultMessage: displayName,
|
|
20
20
|
},
|
|
21
21
|
Component: async () => {
|
|
22
22
|
const component = await import(/* webpackChunkName: "[request]" */ './pages/App');
|
|
@@ -25,6 +25,35 @@ export default {
|
|
|
25
25
|
},
|
|
26
26
|
permissions: pluginPermissions.access,
|
|
27
27
|
});
|
|
28
|
+
|
|
29
|
+
app.createSettingSection(
|
|
30
|
+
{
|
|
31
|
+
id: pluginId,
|
|
32
|
+
intlLabel: {
|
|
33
|
+
id: `${pluginId}.plugin.section`,
|
|
34
|
+
defaultMessage: `${displayName} plugin`,
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
[
|
|
38
|
+
{
|
|
39
|
+
intlLabel: {
|
|
40
|
+
id: `${pluginId}.plugin.section.item`,
|
|
41
|
+
defaultMessage: 'Configuration',
|
|
42
|
+
},
|
|
43
|
+
id: 'comments',
|
|
44
|
+
to: `/settings/${pluginId}`,
|
|
45
|
+
Component: async () => {
|
|
46
|
+
const component = await import(
|
|
47
|
+
/* webpackChunkName: "documentation-settings" */ './pages/Settings'
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
return component;
|
|
51
|
+
},
|
|
52
|
+
permissions: pluginPermissions.settings,
|
|
53
|
+
},
|
|
54
|
+
]
|
|
55
|
+
);
|
|
56
|
+
|
|
28
57
|
app.addReducers(reducers);
|
|
29
58
|
app.registerPlugin({
|
|
30
59
|
id: pluginId,
|
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
import getMessage from '../../utils/getMessage';
|
|
29
29
|
import { fetchDetailsData, fetchContentTypeData } from '../utils/api';
|
|
30
30
|
import pluginPermissions from '../../permissions';
|
|
31
|
-
import { getUrl } from '../../utils';
|
|
31
|
+
import { getUrl, parseRegExp } from '../../utils';
|
|
32
32
|
import Nav from '../../components/Nav';
|
|
33
33
|
import DetailsEntity from './components/DetailsEntity';
|
|
34
34
|
import DiscussionThread from '../../components/DiscussionThread';
|
|
@@ -60,7 +60,10 @@ const Details = ({ config }) => {
|
|
|
60
60
|
|
|
61
61
|
const [filters, setFilters] = useState({});
|
|
62
62
|
|
|
63
|
-
const regexUID = new RegExp(
|
|
63
|
+
const regexUID = new RegExp(
|
|
64
|
+
parseRegExp(config.regex.uid).value,
|
|
65
|
+
parseRegExp(config.regex.uid).flags
|
|
66
|
+
);
|
|
64
67
|
|
|
65
68
|
const { isLoading: isLoadingForData, data, isFetching } = useQuery(
|
|
66
69
|
['get-details-data', id, filters, canAccess],
|