strapi-plugin-comments 2.0.1 → 2.0.2
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/README.md +19 -4
- package/package.json +1 -1
- package/server/controllers/client.js +4 -4
- package/server/controllers/utils/parsers.js +3 -1
- package/server/graphql/queries/findAllFlat.js +4 -2
- package/server/graphql/queries/findAllInHierarchy.js +3 -3
- package/server/services/common.js +34 -4
- package/server/utils/constants.js +1 -0
- package/.circleci/config.yml +0 -48
- package/.eslintrc +0 -35
- package/.github/pull_request_template.md +0 -13
- package/.nvmrc +0 -1
- package/codecov.yml +0 -4
- package/public/assets/logo.png +0 -0
- package/public/assets/preview.png +0 -0
package/README.md
CHANGED
|
@@ -37,10 +37,10 @@ A plugin for [Strapi Headless CMS](https://github.com/strapi/strapi) that provid
|
|
|
37
37
|
|
|
38
38
|
- **Comments Public REST + GraphQL API:** Elegant, entirely customizable and a fully extensible admin panel.
|
|
39
39
|
- **Strapi & generic users:** Support for built-in & also generic non-Strapi users that might be the comments authors.
|
|
40
|
-
- **Any Content Type relation:** Comments can
|
|
40
|
+
- **Any Content Type relation:** Comments can be linked to any of your Content Types by default. Simply, you're controlling it.
|
|
41
41
|
- **Moderation Panel:** Search & Filter through the bucket with your auditory comments. Manage them by blocking single ones or full threads. All in combined list & hierarchical tree view of threads.
|
|
42
|
-
- **Automated Bad Words filtering:** By
|
|
43
|
-
- **Abuse Reporting & Reviewing:** Don't allow inferior language, react to reports from your community, send email
|
|
42
|
+
- **Automated Bad Words filtering:** By default end users are not allowed to post abusing comments where bad words have been used.
|
|
43
|
+
- **Abuse Reporting & Reviewing:** Don't allow inferior language, react to reports from your community, send email notifications about issued reports
|
|
44
44
|
|
|
45
45
|
## ⚙️ Versions
|
|
46
46
|
|
|
@@ -203,7 +203,7 @@ Feature / Capability focused permissions:
|
|
|
203
203
|
|
|
204
204
|
`GET <host>/api/comments/api::<collection name>.<content type name>:<entity id>`
|
|
205
205
|
|
|
206
|
-
Return a hierarchical tree structure of comments for specified instance of Content Type like for example `Page` with `ID: 1
|
|
206
|
+
Return a hierarchical tree structure of comments for specified instance of Content Type like for example `Page` with `ID: 1`.
|
|
207
207
|
|
|
208
208
|
**Example URL**: `https://localhost:1337/comments/api::page.page:1`
|
|
209
209
|
|
|
@@ -226,6 +226,8 @@ Return a hierarchical tree structure of comments for specified instance of Conte
|
|
|
226
226
|
// ...
|
|
227
227
|
]
|
|
228
228
|
```
|
|
229
|
+
#### Strapi REST API properties support:
|
|
230
|
+
- [sorting](https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/rest/sort-pagination.html#sorting)
|
|
229
231
|
|
|
230
232
|
### Get Comments (flat structure)
|
|
231
233
|
|
|
@@ -255,6 +257,11 @@ Return a flat structure of comments for specified instance of Content Type like
|
|
|
255
257
|
- `200` - Successful. Response with list of comments (can be empty)
|
|
256
258
|
- `400` - Bad Request. Requested list for not valid / not existing Content Type
|
|
257
259
|
|
|
260
|
+
#### Strapi REST API properties support:
|
|
261
|
+
- [filtering](https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/rest/filtering-locale-publication.html#filtering)
|
|
262
|
+
- [sorting](https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/rest/sort-pagination.html#sorting)
|
|
263
|
+
- [pagination](https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/rest/sort-pagination.html#pagination)
|
|
264
|
+
|
|
258
265
|
### Post a Comment
|
|
259
266
|
|
|
260
267
|
*GraphQL equivalent: [Public GraphQL API -> Post a Comments](#post-a-comment-1)*
|
|
@@ -460,6 +467,9 @@ query {
|
|
|
460
467
|
}
|
|
461
468
|
```
|
|
462
469
|
|
|
470
|
+
#### Strapi GraphQL API properties support:
|
|
471
|
+
- [sorting](https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/graphql-api.html#sorting)
|
|
472
|
+
|
|
463
473
|
### Get Comments (flat structure)
|
|
464
474
|
|
|
465
475
|
*REST API equivalent: [Public REST API -> Get Comments (flat structure)](#get-comments-flat-structure)*
|
|
@@ -516,6 +526,11 @@ query {
|
|
|
516
526
|
}
|
|
517
527
|
```
|
|
518
528
|
|
|
529
|
+
#### Strapi GraphQL API properties support:
|
|
530
|
+
- [filtering](https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/graphql-api.html#filters)
|
|
531
|
+
- [sorting](https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/graphql-api.html#sorting)
|
|
532
|
+
- [pagination](https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/graphql-api.html#pagination)
|
|
533
|
+
|
|
519
534
|
### Post a Comment
|
|
520
535
|
|
|
521
536
|
*REST API equivalent: [Public REST API -> Post a Comment](#post-a-comment)*
|
package/package.json
CHANGED
|
@@ -11,23 +11,23 @@ module.exports = {
|
|
|
11
11
|
},
|
|
12
12
|
|
|
13
13
|
async findAllFlat(ctx) {
|
|
14
|
-
const { params = {}, query } = ctx;
|
|
14
|
+
const { params = {}, query, sort, pagination } = ctx;
|
|
15
15
|
const { relation } = parseParams(params);
|
|
16
16
|
try {
|
|
17
17
|
return this.getService('common')
|
|
18
|
-
.findAllFlat(flatInput(relation, query));
|
|
18
|
+
.findAllFlat(flatInput(relation, query, sort, pagination));
|
|
19
19
|
} catch (e) {
|
|
20
20
|
throwError(ctx, e);
|
|
21
21
|
}
|
|
22
22
|
},
|
|
23
23
|
|
|
24
24
|
async findAllInHierarchy(ctx) {
|
|
25
|
-
const { params = {}, query } = ctx;
|
|
25
|
+
const { params = {}, query, sort } = ctx;
|
|
26
26
|
const { relation } = parseParams(params);
|
|
27
27
|
try {
|
|
28
28
|
return await this.getService('common')
|
|
29
29
|
.findAllInHierarchy({
|
|
30
|
-
...flatInput(relation, query),
|
|
30
|
+
...flatInput(relation, query, sort),
|
|
31
31
|
dropBlockedThreads: true,
|
|
32
32
|
});
|
|
33
33
|
} catch (e) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
module.exports = {
|
|
4
|
-
flatInput(relation, query) {
|
|
4
|
+
flatInput(relation, query, sort, pagination) {
|
|
5
5
|
return {
|
|
6
6
|
query: {
|
|
7
7
|
...query,
|
|
@@ -13,6 +13,8 @@ module.exports = {
|
|
|
13
13
|
populate: { authorUser: true },
|
|
14
14
|
},
|
|
15
15
|
},
|
|
16
|
+
pagination,
|
|
17
|
+
sort,
|
|
16
18
|
};
|
|
17
19
|
},
|
|
18
20
|
|
|
@@ -18,11 +18,13 @@ module.exports = ({ strapi, nexus }) => {
|
|
|
18
18
|
sort: args.SortArg,
|
|
19
19
|
},
|
|
20
20
|
async resolve(obj, args) {
|
|
21
|
-
const { relation, filters } = args;
|
|
21
|
+
const { relation, filters, sort, pagination } = args;
|
|
22
22
|
return await getPluginService('common')
|
|
23
23
|
.findAllFlat(flatInput(
|
|
24
24
|
relation,
|
|
25
|
-
getPluginService('gql').graphQLFiltersToStrapiQuery(filters, contentType)
|
|
25
|
+
getPluginService('gql').graphQLFiltersToStrapiQuery(filters, contentType),
|
|
26
|
+
sort,
|
|
27
|
+
pagination
|
|
26
28
|
), undefined);
|
|
27
29
|
},
|
|
28
30
|
};
|
|
@@ -13,16 +13,16 @@ module.exports = ({ strapi, nexus }) => {
|
|
|
13
13
|
type: nonNull(list('CommentNested')),
|
|
14
14
|
args: {
|
|
15
15
|
relation: nonNull(stringArg()),
|
|
16
|
-
// filters: filtersArg,
|
|
17
16
|
sort: args.SortArg,
|
|
18
17
|
},
|
|
19
18
|
async resolve(obj, args) {
|
|
20
|
-
const { relation, filters } = args;
|
|
19
|
+
const { relation, filters, sort } = args;
|
|
21
20
|
return await getPluginService('common')
|
|
22
21
|
.findAllInHierarchy({
|
|
23
22
|
...flatInput(
|
|
24
23
|
relation,
|
|
25
|
-
getPluginService('gql').graphQLFiltersToStrapiQuery(filters, contentType)
|
|
24
|
+
getPluginService('gql').graphQLFiltersToStrapiQuery(filters, contentType),
|
|
25
|
+
sort
|
|
26
26
|
),
|
|
27
27
|
dropBlockedThreads: true,
|
|
28
28
|
});
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const BadWordsFilter = require('bad-words');
|
|
4
|
-
const { isArray, isNumber, isObject, isNil, first, parseInt } = require('lodash');
|
|
4
|
+
const { isArray, isNumber, isObject, isNil, isString, first, parseInt, set } = require('lodash');
|
|
5
|
+
const { REGEX } = require('../utils/constants');
|
|
5
6
|
const PluginError = require('./../utils/error');
|
|
6
7
|
const {
|
|
7
8
|
getModelUid,
|
|
@@ -27,12 +28,39 @@ module.exports = ({ strapi }) => ({
|
|
|
27
28
|
},
|
|
28
29
|
|
|
29
30
|
// Find comments in the flat structure
|
|
30
|
-
async findAllFlat({
|
|
31
|
+
async findAllFlat({
|
|
32
|
+
query = {},
|
|
33
|
+
populate = {},
|
|
34
|
+
sort,
|
|
35
|
+
pagination }, relatedEntity = null) {
|
|
31
36
|
|
|
32
37
|
const defaultPopulate = {
|
|
33
38
|
authorUser: true,
|
|
34
39
|
};
|
|
35
40
|
|
|
41
|
+
let queryExtension = {};
|
|
42
|
+
|
|
43
|
+
if (sort && (isString(sort) || isArray(sort))) {
|
|
44
|
+
queryExtension = {
|
|
45
|
+
...queryExtension,
|
|
46
|
+
orderBy: (isString(sort) ? [sort] : sort)
|
|
47
|
+
.map(_ => REGEX.sorting.test(_) ? _ : `${_}:asc`)
|
|
48
|
+
.reduce((prev, curr) => {
|
|
49
|
+
const [type = 'asc', ...parts] = curr.split(':').reverse();
|
|
50
|
+
return { ...set(prev, parts.reverse().join('.'), type) };
|
|
51
|
+
}, {})
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (pagination && isObject(pagination)) {
|
|
56
|
+
const { page = 1, pageSize = 10 } = pagination;
|
|
57
|
+
queryExtension = {
|
|
58
|
+
...queryExtension,
|
|
59
|
+
offset: (page - 1) * pageSize,
|
|
60
|
+
limit: pageSize,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
36
64
|
const entries = await strapi.db.query(getModelUid('comment'))
|
|
37
65
|
.findMany({
|
|
38
66
|
where: {
|
|
@@ -42,6 +70,7 @@ module.exports = ({ strapi }) => ({
|
|
|
42
70
|
...defaultPopulate,
|
|
43
71
|
...populate,
|
|
44
72
|
},
|
|
73
|
+
...queryExtension,
|
|
45
74
|
});
|
|
46
75
|
|
|
47
76
|
const entriesWithThreads = await Promise.all(entries.map(async _ => {
|
|
@@ -76,10 +105,11 @@ module.exports = ({ strapi }) => ({
|
|
|
76
105
|
async findAllInHierarchy ({
|
|
77
106
|
query,
|
|
78
107
|
populate = {},
|
|
108
|
+
sort,
|
|
79
109
|
startingFromId = null,
|
|
80
110
|
dropBlockedThreads = false,
|
|
81
111
|
}, relatedEntity) {
|
|
82
|
-
const entities = await this.findAllFlat({ query, populate }, relatedEntity);
|
|
112
|
+
const entities = await this.findAllFlat({ query, populate, sort }, relatedEntity);
|
|
83
113
|
return buildNestedStructure(entities, startingFromId, 'threadOf', dropBlockedThreads, false);
|
|
84
114
|
},
|
|
85
115
|
|
|
@@ -116,7 +146,7 @@ module.exports = ({ strapi }) => ({
|
|
|
116
146
|
Object.entries(data)
|
|
117
147
|
.map(async ([relatedUid, relatedStringIds]) =>
|
|
118
148
|
strapi.db.query(relatedUid).findMany({
|
|
119
|
-
where: { id: Array.from(new Set(relatedStringIds)) }
|
|
149
|
+
where: { id: Array.from(new Set(relatedStringIds)) },
|
|
120
150
|
}).then(relatedEntities => relatedEntities.map(_ =>
|
|
121
151
|
({
|
|
122
152
|
..._,
|
|
@@ -8,6 +8,7 @@ const REGEX = {
|
|
|
8
8
|
uid: /^(?<type>[a-z0-9-]+)\:{2}(?<api>[a-z0-9-]+)\.{1}(?<contentType>[a-z0-9-]+)$/i,
|
|
9
9
|
relatedUid: /^(?<uid>[a-z0-9-]+\:{2}[a-z0-9-]+\.[a-z0-9-]+)\:{1}(?<id>[a-z0-9-]+)$/i,
|
|
10
10
|
email: /\S+@\S+\.\S+/,
|
|
11
|
+
sorting: /^(?<path>[a-z0-9-_\:\.]+)\:+(asc|desc)$/i
|
|
11
12
|
};
|
|
12
13
|
|
|
13
14
|
module.exports = {
|
package/.circleci/config.yml
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
version: 2.1
|
|
2
|
-
orbs:
|
|
3
|
-
codecov: codecov/codecov@1.1.1
|
|
4
|
-
jobs:
|
|
5
|
-
build-and-test:
|
|
6
|
-
environment:
|
|
7
|
-
CODECOV_TOKEN: 02e2d4e8-88c4-4e5d-99da-a9a2888634c6
|
|
8
|
-
docker:
|
|
9
|
-
- image: circleci/node:14.17.3
|
|
10
|
-
working_directory: ~/repo
|
|
11
|
-
steps:
|
|
12
|
-
- checkout
|
|
13
|
-
- run:
|
|
14
|
-
name: set GIT name and email
|
|
15
|
-
command: |
|
|
16
|
-
git config --global -l
|
|
17
|
-
git config --global user.email "$GIT_COMMITTER_EMAIL"
|
|
18
|
-
git config --global user.name "$GIT_COMMITTER_NAME"
|
|
19
|
-
git config --global -l
|
|
20
|
-
- restore_cache:
|
|
21
|
-
keys:
|
|
22
|
-
# when lock file changes, use increasingly general patterns to restore cache
|
|
23
|
-
- strapi-plugin-comments-v2-{{ checksum "yarn.lock" }}
|
|
24
|
-
- strapi-plugin-comments-
|
|
25
|
-
- run:
|
|
26
|
-
name: Echo versions
|
|
27
|
-
command: |
|
|
28
|
-
node --version
|
|
29
|
-
yarn --version
|
|
30
|
-
- run:
|
|
31
|
-
name: Install
|
|
32
|
-
command: |
|
|
33
|
-
yarn install
|
|
34
|
-
- run:
|
|
35
|
-
name: Test
|
|
36
|
-
command: |
|
|
37
|
-
yarn test:unit
|
|
38
|
-
- codecov/upload:
|
|
39
|
-
flags: unittest
|
|
40
|
-
file:
|
|
41
|
-
- save_cache:
|
|
42
|
-
paths:
|
|
43
|
-
- ./node_modules
|
|
44
|
-
key: strapi-plugin-comments-v2-{{ checksum "yarn.lock" }}
|
|
45
|
-
workflows:
|
|
46
|
-
build-and-test:
|
|
47
|
-
jobs:
|
|
48
|
-
- build-and-test
|
package/.eslintrc
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"parserOptions": {
|
|
3
|
-
"jsx": true,
|
|
4
|
-
"useJSXTextNode": true,
|
|
5
|
-
"sourceType": "module"
|
|
6
|
-
},
|
|
7
|
-
"plugins": ["react-hooks", "import"],
|
|
8
|
-
"rules": {
|
|
9
|
-
"no-console": "warn",
|
|
10
|
-
"curly": "warn",
|
|
11
|
-
"prefer-template": "warn",
|
|
12
|
-
|
|
13
|
-
"react-hooks/rules-of-hooks": "error",
|
|
14
|
-
"react-hooks/exhaustive-deps": "error",
|
|
15
|
-
|
|
16
|
-
"import/no-default-export": "warn",
|
|
17
|
-
"import/newline-after-import": "warn",
|
|
18
|
-
"import/order": [
|
|
19
|
-
"warn",
|
|
20
|
-
{
|
|
21
|
-
"newlines-between": "always",
|
|
22
|
-
"alphabetize": { "order": "asc" },
|
|
23
|
-
"pathGroupsExcludedImportTypes": ["builtin"],
|
|
24
|
-
"groups": [
|
|
25
|
-
"builtin",
|
|
26
|
-
"external",
|
|
27
|
-
"internal",
|
|
28
|
-
"parent",
|
|
29
|
-
"sibling",
|
|
30
|
-
"index"
|
|
31
|
-
]
|
|
32
|
-
}
|
|
33
|
-
]
|
|
34
|
-
}
|
|
35
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
## Ticket
|
|
2
|
-
|
|
3
|
-
https://github.com/VirtusLab/strapi-plugin-comments/issues/-<your-ticket-#>
|
|
4
|
-
|
|
5
|
-
## Summary
|
|
6
|
-
|
|
7
|
-
What does this PR do/solve?
|
|
8
|
-
|
|
9
|
-
> PRs should be as small as they need to be, if this section starts becoming a novel you should _seriously_ consider breaking it up into multiple PRs
|
|
10
|
-
|
|
11
|
-
## Test Plan
|
|
12
|
-
|
|
13
|
-
How are you testing the work you're submitting?
|
package/.nvmrc
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
v14.17.3
|
package/codecov.yml
DELETED
package/public/assets/logo.png
DELETED
|
Binary file
|
|
Binary file
|