strapi-plugin-comments 1.0.4 → 2.0.0-beta.1
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/.circleci/config.yml +2 -2
- package/README.md +47 -125
- package/admin/src/components/ConfirmationDialog/index.js +56 -0
- package/admin/src/components/DiscussionStatus/index.js +33 -0
- package/admin/src/components/DiscussionThread/index.js +58 -0
- package/admin/src/components/DiscussionThreadItem/index.js +87 -0
- package/admin/src/components/DiscussionThreadItem/styles.js +87 -0
- package/admin/src/components/DiscussionThreadItemActions/index.js +176 -0
- package/admin/src/components/DiscussionThreadItemActions/styles.js +22 -0
- package/admin/src/components/DiscussionThreadItemMeta/index.js +31 -0
- package/admin/src/components/DiscussionThreadItemWarnings/index.js +137 -0
- package/admin/src/components/DiscussionThreadItemWarnings/styles.js +7 -0
- package/admin/src/components/EntityDetails/index.js +53 -0
- package/admin/src/{containers → components}/Initializer/index.js +4 -4
- package/admin/src/components/LoadingIndicatorOverlay/index.js +15 -0
- package/admin/src/components/LoadingIndicatorOverlay/styles.js +20 -0
- package/admin/src/components/Nav/index.js +45 -0
- package/admin/src/components/PluginIcon/index.js +12 -0
- package/admin/src/components/ReportsReviewModal/index.js +45 -0
- package/admin/src/components/ReportsReviewTable/index.js +142 -0
- package/admin/src/components/TableFilters/index.js +53 -0
- package/admin/src/components/TablePagination/index.js +35 -0
- package/admin/src/components/icons/comments.js +9 -0
- package/admin/src/index.js +56 -42
- package/admin/src/pages/App/index.js +32 -0
- package/admin/src/pages/ComingSoonPage/index.js +25 -0
- package/admin/src/pages/Details/index.js +109 -0
- package/admin/src/pages/Details/utils/api.js +41 -0
- package/admin/src/pages/Discover/index.js +185 -0
- package/admin/src/pages/Discover/utils/api.js +23 -0
- package/admin/src/pages/Discover/utils/filtersSchema.js +9 -0
- package/admin/src/permissions.js +13 -37
- package/admin/src/pluginId.js +2 -4
- package/admin/src/translations/en.json +72 -37
- package/admin/src/translations/fr.json +1 -0
- package/admin/src/utils/axiosInstance.js +35 -0
- package/admin/src/utils/constants.js +25 -6
- package/admin/src/utils/getApiUrl.js +5 -0
- package/admin/src/utils/getMessage.js +14 -0
- package/admin/src/utils/getRelatedGroups.js +5 -0
- package/admin/src/utils/getUrl.js +5 -0
- package/admin/src/utils/handleAPIError.js +15 -0
- package/admin/src/utils/index.js +6 -0
- package/codecov.yml +2 -1
- package/content-types/comment.js +97 -0
- package/content-types/index.js +11 -0
- package/content-types/report.js +54 -0
- package/package.json +11 -25
- package/server/bootstrap.js +5 -0
- package/server/config/index.js +6 -0
- package/server/controllers/admin.js +150 -0
- package/server/controllers/client.js +109 -0
- package/server/controllers/index.js +9 -0
- package/{controllers → server/controllers}/utils/__tests__/functions.test.js +0 -0
- package/{controllers → server/controllers}/utils/functions.js +1 -1
- package/server/destroy.js +5 -0
- package/server/index.js +22 -0
- package/server/register.js +5 -0
- package/server/routes/admin.js +92 -0
- package/server/routes/client.js +52 -0
- package/server/routes/index.js +15 -0
- package/server/services/admin.js +180 -0
- package/server/services/client.js +227 -0
- package/server/services/common.js +191 -0
- package/server/services/index.js +11 -0
- package/{services → server/services}/utils/__tests__/functions.test.js +0 -0
- package/{services → server/services}/utils/functions.js +17 -6
- package/server/utils/constants.js +16 -0
- package/{services → server}/utils/error.js +0 -0
- package/server/utils/functions.js +19 -0
- package/strapi-admin.js +3 -0
- package/strapi-server.js +9 -0
- package/admin/src/assets/images/icon-cross-blue.svg +0 -1
- package/admin/src/assets/images/icon_remove.svg +0 -19
- package/admin/src/assets/images/logo.svg +0 -5
- package/admin/src/components/AbuseReportsPopUp/ItemPreviewContainer.js +0 -8
- package/admin/src/components/AbuseReportsPopUp/ModalFooter.js +0 -31
- package/admin/src/components/AbuseReportsPopUp/TableContainer.js +0 -63
- package/admin/src/components/AbuseReportsPopUp/index.js +0 -148
- package/admin/src/components/Container/index.js +0 -7
- package/admin/src/components/EmptyView/index.js +0 -25
- package/admin/src/components/Filters/index.js +0 -151
- package/admin/src/components/Filters/index.styled.js +0 -82
- package/admin/src/components/Filters/utils.js +0 -21
- package/admin/src/components/Item/CardItem.js +0 -30
- package/admin/src/components/Item/CardWrapper.js +0 -10
- package/admin/src/components/Item/index.js +0 -107
- package/admin/src/components/ItemDetails/CardItem.js +0 -33
- package/admin/src/components/ItemDetails/CardLevelCounter.js +0 -46
- package/admin/src/components/ItemDetails/CardLevelCounterLink.js +0 -24
- package/admin/src/components/ItemDetails/CardLevelWrapper.js +0 -22
- package/admin/src/components/ItemDetails/CardWrapper.js +0 -52
- package/admin/src/components/ItemDetails/index.js +0 -167
- package/admin/src/components/ItemFooter/CardItemAuthor.js +0 -10
- package/admin/src/components/ItemFooter/CardItemRelation.js +0 -18
- package/admin/src/components/ItemFooter/Wrapper.js +0 -20
- package/admin/src/components/ItemFooter/index.js +0 -87
- package/admin/src/components/ItemHeader/CardHeaderBlocked.js +0 -24
- package/admin/src/components/ItemHeader/CardHeaderIndicator.js +0 -30
- package/admin/src/components/ItemHeader/CardHeaderIndicatorBlue.js +0 -11
- package/admin/src/components/ItemHeader/CardHeaderIndicatorRed.js +0 -11
- package/admin/src/components/ItemHeader/CardHeaderIndicatorsContainer.js +0 -18
- package/admin/src/components/ItemHeader/CardHeaderPending.js +0 -11
- package/admin/src/components/ItemHeader/CardHeaderReports.js +0 -40
- package/admin/src/components/ItemHeader/Wrapper.js +0 -16
- package/admin/src/components/ItemHeader/index.js +0 -97
- package/admin/src/components/ItemModeration/Wrapper.js +0 -19
- package/admin/src/components/ItemModeration/index.js +0 -84
- package/admin/src/components/List/Container.js +0 -20
- package/admin/src/components/List/index.js +0 -21
- package/admin/src/components/Search/index.js +0 -83
- package/admin/src/containers/App/Wrapper.js +0 -14
- package/admin/src/containers/App/index.js +0 -47
- package/admin/src/containers/DataManagerProvider/actions.js +0 -15
- package/admin/src/containers/DataManagerProvider/index.js +0 -332
- package/admin/src/containers/DataManagerProvider/init.js +0 -5
- package/admin/src/containers/DataManagerProvider/reducer.js +0 -59
- package/admin/src/containers/DetailsView/Wrapper.js +0 -18
- package/admin/src/containers/DetailsView/index.js +0 -106
- package/admin/src/containers/ListView/FadedWrapper.js +0 -42
- package/admin/src/containers/ListView/Footer.js +0 -53
- package/admin/src/containers/ListView/Wrapper.js +0 -17
- package/admin/src/containers/ListView/components.js +0 -138
- package/admin/src/containers/ListView/index.js +0 -45
- package/admin/src/containers/Panel/actions.js +0 -5
- package/admin/src/containers/Panel/index.js +0 -191
- package/admin/src/containers/Panel/index.styled.js +0 -6
- package/admin/src/containers/Panel/reducer.js +0 -44
- package/admin/src/contexts/DataManagerContext.js +0 -5
- package/admin/src/hooks/useDataManager.js +0 -6
- package/admin/src/lifecycles.js +0 -3
- package/admin/src/translations/index.js +0 -7
- package/admin/src/utils/getTrad.js +0 -5
- package/admin/src/utils/getTradId.js +0 -5
- package/config/functions/bootstrap.js +0 -62
- package/config/routes.json +0 -142
- package/config/schema.graphql.js +0 -268
- package/controllers/comments.js +0 -228
- package/models/comment.js +0 -8
- package/models/comment.settings.json +0 -102
- package/models/report.js +0 -8
- package/models/report.settings.json +0 -49
- package/services/comments.js +0 -539
- package/services/utils/constants.js +0 -9
package/.circleci/config.yml
CHANGED
|
@@ -20,7 +20,7 @@ jobs:
|
|
|
20
20
|
- restore_cache:
|
|
21
21
|
keys:
|
|
22
22
|
# when lock file changes, use increasingly general patterns to restore cache
|
|
23
|
-
- strapi-plugin-comments-
|
|
23
|
+
- strapi-plugin-comments-v2-{{ checksum "yarn.lock" }}
|
|
24
24
|
- strapi-plugin-comments-
|
|
25
25
|
- run:
|
|
26
26
|
name: Echo versions
|
|
@@ -41,7 +41,7 @@ jobs:
|
|
|
41
41
|
- save_cache:
|
|
42
42
|
paths:
|
|
43
43
|
- ./node_modules
|
|
44
|
-
key: strapi-plugin-comments-
|
|
44
|
+
key: strapi-plugin-comments-v2-{{ checksum "yarn.lock" }}
|
|
45
45
|
workflows:
|
|
46
46
|
build-and-test:
|
|
47
47
|
jobs:
|
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Strapi - Comments plugin
|
|
1
|
+
# Strapi v4 - Comments plugin - BETA
|
|
2
2
|
|
|
3
3
|
<p align="center">
|
|
4
4
|
<a href="https://www.npmjs.org/package/strapi-plugin-comments">
|
|
@@ -17,7 +17,9 @@
|
|
|
17
17
|
|
|
18
18
|
A plugin for [Strapi Headless CMS](https://github.com/strapi/strapi) that provides end to end comments feature with their moderation panel, bad words filtering, abuse reporting and more.
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
### Versions
|
|
21
|
+
- **Stable** - [v1.0.4](https://github.com/VirtusLab-Open-Source/strapi-plugin-comments)
|
|
22
|
+
- **Beta** - v4 support - [v2.0.0-beta.x](https://github.com/VirtusLab-Open-Source/strapi-plugin-comments/tree/feat/strapi-v4)
|
|
21
23
|
|
|
22
24
|
### ⏳ Installation
|
|
23
25
|
|
|
@@ -46,14 +48,13 @@ Enjoy 🎉
|
|
|
46
48
|
|
|
47
49
|
### 🖐 Requirements
|
|
48
50
|
|
|
49
|
-
Complete installation requirements are exact same as for Strapi itself and can be found in the documentation under [Installation Requirements](https://strapi.io/
|
|
51
|
+
Complete installation requirements are exact same as for Strapi itself and can be found in the documentation under [Installation Requirements](https://docs.strapi.io/developer-docs/latest/getting-started/introduction.html).
|
|
50
52
|
|
|
51
53
|
**Supported Strapi versions**:
|
|
52
54
|
|
|
53
|
-
- Strapi
|
|
54
|
-
- Strapi v3.x
|
|
55
|
+
- Strapi v4.0.2 (recently tested)
|
|
55
56
|
|
|
56
|
-
(This plugin may work with the older Strapi versions, but these are not tested nor officially supported at this time.)
|
|
57
|
+
(This plugin is not working with v3.x and not may work with the older Strapi v4 versions, but these are not tested nor officially supported at this time.)
|
|
57
58
|
|
|
58
59
|
**We recommend always using the latest version of Strapi to start your new projects**.
|
|
59
60
|
|
|
@@ -66,32 +67,6 @@ Complete installation requirements are exact same as for Strapi itself and can b
|
|
|
66
67
|
- **Automated Bad Words filtering:** By detault end users are not allowed to post abusing comments where bad words have been used.
|
|
67
68
|
- **Abuse Reporting & Reviewing:** Don't allow inferior language, react to reports from your community, send email notifiactions about abuse reports
|
|
68
69
|
|
|
69
|
-
## Content Type model relation to Comment
|
|
70
|
-
|
|
71
|
-
To enable Content Type to work with Comments, you've to add following field to your model `*.settings.json`:
|
|
72
|
-
|
|
73
|
-
```json
|
|
74
|
-
"comments": {
|
|
75
|
-
"plugin": "comments",
|
|
76
|
-
"collection": "comment",
|
|
77
|
-
"via": "related"
|
|
78
|
-
}
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
inside the `attributes` section like in example below:
|
|
82
|
-
|
|
83
|
-
```json
|
|
84
|
-
"attributes": {
|
|
85
|
-
...,
|
|
86
|
-
"comments": {
|
|
87
|
-
"plugin": "comments",
|
|
88
|
-
"collection": "comment",
|
|
89
|
-
"via": "related"
|
|
90
|
-
},
|
|
91
|
-
...
|
|
92
|
-
},
|
|
93
|
-
```
|
|
94
|
-
|
|
95
70
|
## Configuration
|
|
96
71
|
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.
|
|
97
72
|
|
|
@@ -99,50 +74,19 @@ To setup amend default plugin configuration we recommend to put following snippe
|
|
|
99
74
|
```js
|
|
100
75
|
...
|
|
101
76
|
comments: {
|
|
102
|
-
enableUsers: true,
|
|
103
77
|
badWords: false,
|
|
104
|
-
|
|
78
|
+
moderatorRoles: ["Authenticated"]
|
|
105
79
|
},
|
|
106
80
|
...
|
|
107
81
|
```
|
|
108
82
|
|
|
109
83
|
### Properties
|
|
110
|
-
- `enableUsers` - Enabled support for built-in Strapi users, if endpoints are exposed with usage of `Authenticated` policy or JWT tokens are in use by the Client App. Default value: `false`.
|
|
111
84
|
- `badWords` - Enabled support for [bad words filtering](https://www.npmjs.com/package/bad-words). Can be turned off or overwritten using [options reference](https://www.npmjs.com/package/bad-words#constructor). Default value: `true`.
|
|
112
|
-
- `moderatorRoles` - Optional list of names of roles. Users with those roles will be notified by email when a new abuse report is created. This feature requires a built-in [Strapi email plugin](https://strapi.io/
|
|
85
|
+
- `moderatorRoles` - Optional list of names of roles. Users with those roles will be notified by email when a new abuse report is created. This feature requires a built-in [Strapi email plugin](https://docs.strapi.io/developer-docs/latest/plugins/email.html) configured.
|
|
113
86
|
|
|
114
87
|
## Additional GQL Configuration
|
|
115
88
|
|
|
116
|
-
>
|
|
117
|
-
> Introduced in `v1.0.2`
|
|
118
|
-
|
|
119
|
-
```js
|
|
120
|
-
...
|
|
121
|
-
comments: {
|
|
122
|
-
enableUsers: true,
|
|
123
|
-
badWords: false,
|
|
124
|
-
relatedContentTypes: {
|
|
125
|
-
pages: {
|
|
126
|
-
uuid: 'application::pages.pages',
|
|
127
|
-
contentManager: true,
|
|
128
|
-
isSingle: true, // optional
|
|
129
|
-
__contentType: '',
|
|
130
|
-
key: 'title',
|
|
131
|
-
value: 'id',
|
|
132
|
-
url: 'my-custom-url/:id' // optional
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
},
|
|
136
|
-
...
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
### Properties
|
|
140
|
-
- `relatedContentTypes` - list of properties where each single one reflects the related collection like `pages`, `posts`, etc. Each of collection properties should contain following set:
|
|
141
|
-
- `uuid` - strapi content type `uuid`
|
|
142
|
-
- `contentManager` - boolean to mark if element taken from **Strapi Content Manager** or maybe custom plugin
|
|
143
|
-
- `isSingle` (optional) - boolean to identify collection type or single type
|
|
144
|
-
- `key/value` - will be used to take id and example title to display link on the list
|
|
145
|
-
- `url` (optional) - to be defined if `contentManager` is set to **false**. Reflects the custom url that returns the content type items. With id as identifier - which is dynamically replaced
|
|
89
|
+
> To be done
|
|
146
90
|
|
|
147
91
|
## Public API Comment model
|
|
148
92
|
|
|
@@ -154,14 +98,15 @@ To setup amend default plugin configuration we recommend to put following snippe
|
|
|
154
98
|
"blocked": null,
|
|
155
99
|
"blockedThread": true,
|
|
156
100
|
"blockReason": null,
|
|
157
|
-
"points": 1,
|
|
158
101
|
"authorUser": null,
|
|
159
102
|
"authorId": "207ccfdc-94ba-45eb-979c-790f6f49c392",
|
|
160
103
|
"authorName": "Joe Doe",
|
|
161
104
|
"authorEmail": "jdoe@sample.com",
|
|
162
105
|
"authorAvatar": null,
|
|
163
|
-
"
|
|
164
|
-
"
|
|
106
|
+
"createdAt": "2020-07-14T20:13:01.649Z",
|
|
107
|
+
"updatedAt": "2020-07-14T20:13:01.670Z",
|
|
108
|
+
"related": {}, // Related content type entity
|
|
109
|
+
"reports": [] // Reports issued against this comment
|
|
165
110
|
}
|
|
166
111
|
```
|
|
167
112
|
### Strapi User
|
|
@@ -172,7 +117,6 @@ To setup amend default plugin configuration we recommend to put following snippe
|
|
|
172
117
|
"blocked": true,
|
|
173
118
|
"blockedThread": null,
|
|
174
119
|
"blockReason": null,
|
|
175
|
-
"points": null,
|
|
176
120
|
"authorUser": {
|
|
177
121
|
"id": 1,
|
|
178
122
|
"username": "Sample User",
|
|
@@ -188,8 +132,10 @@ To setup amend default plugin configuration we recommend to put following snippe
|
|
|
188
132
|
"authorName": null,
|
|
189
133
|
"authorEmail": null,
|
|
190
134
|
"authorAvatar": null,
|
|
191
|
-
"
|
|
192
|
-
"
|
|
135
|
+
"createdAt": "2020-07-14T20:13:01.649Z",
|
|
136
|
+
"updatedAt": "2020-07-14T20:13:01.670Z",
|
|
137
|
+
"related": {}, // Related content type entity
|
|
138
|
+
"reports": [] // Reports issued against this comment
|
|
193
139
|
}
|
|
194
140
|
|
|
195
141
|
```
|
|
@@ -198,11 +144,11 @@ To setup amend default plugin configuration we recommend to put following snippe
|
|
|
198
144
|
|
|
199
145
|
### Get Comments
|
|
200
146
|
|
|
201
|
-
`GET <host>/comments
|
|
147
|
+
`GET <host>/comments/api::<collection name>.<content type name>:<entity id>`
|
|
202
148
|
|
|
203
|
-
Return a hierarchical tree structure of comments for specified instance of Content Type like for example `
|
|
149
|
+
Return a hierarchical tree structure of comments for specified instance of Content Type like for example `Page` with `ID: 1`
|
|
204
150
|
|
|
205
|
-
**Example URL**: `https://localhost:1337/comments/
|
|
151
|
+
**Example URL**: `https://localhost:1337/comments/api::page.page:1`
|
|
206
152
|
|
|
207
153
|
**Example response body**
|
|
208
154
|
|
|
@@ -224,11 +170,11 @@ Return a hierarchical tree structure of comments for specified instance of Conte
|
|
|
224
170
|
|
|
225
171
|
### Get Comments (flat structure)
|
|
226
172
|
|
|
227
|
-
`GET <host>/comments
|
|
173
|
+
`GET <host>/comments/api::<collection name>.<content type name>:<entity id>/flat`
|
|
228
174
|
|
|
229
|
-
Return a flat structure of comments for specified instance of Content Type like for example `
|
|
175
|
+
Return a flat structure of comments for specified instance of Content Type like for example `Page` with `ID: 1`
|
|
230
176
|
|
|
231
|
-
**Example URL**: `https://localhost:1337/comments/
|
|
177
|
+
**Example URL**: `https://localhost:1337/comments/api::page.page:1/flat`
|
|
232
178
|
|
|
233
179
|
**Example response body**
|
|
234
180
|
|
|
@@ -250,27 +196,26 @@ Return a flat structure of comments for specified instance of Content Type like
|
|
|
250
196
|
|
|
251
197
|
### Post a Comment
|
|
252
198
|
|
|
253
|
-
`POST <host>/comments
|
|
199
|
+
`POST <host>/comments/api::<collection name>.<content type name>:<entity id>`
|
|
254
200
|
|
|
255
|
-
Posts a Comment related to specified instance of Content Type like for example `
|
|
201
|
+
Posts a Comment related to specified instance of Content Type like for example `Page` with `ID: 1`
|
|
256
202
|
|
|
257
|
-
**Example URL**: `https://localhost:1337/comments/
|
|
203
|
+
**Example URL**: `https://localhost:1337/comments/api::page.page:1`
|
|
258
204
|
|
|
259
205
|
**Example request body**
|
|
260
206
|
|
|
261
207
|
*Generic (non Strapi User)*
|
|
262
208
|
```
|
|
263
209
|
{
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
210
|
+
"author": {
|
|
211
|
+
"id": "<any ID like value>",
|
|
212
|
+
"name": "Joe Doe",
|
|
213
|
+
"email": "jdoe@sample.com",
|
|
214
|
+
"avatar": "<any image url>"
|
|
215
|
+
},
|
|
267
216
|
"content": "My sample response",
|
|
268
217
|
"threadOf": 2, // id of comment we would like to start / continue the thread (Optional)
|
|
269
|
-
"related":
|
|
270
|
-
"refId": 1,
|
|
271
|
-
"ref": "article",
|
|
272
|
-
"field": "comments"
|
|
273
|
-
}]
|
|
218
|
+
"related": "api::page.page:1"
|
|
274
219
|
}
|
|
275
220
|
```
|
|
276
221
|
|
|
@@ -280,11 +225,7 @@ Posts a Comment related to specified instance of Content Type like for example `
|
|
|
280
225
|
"authorUser": 1, // id of a author user. Optional in case of 'enableUsers: true' in the plugin configuration
|
|
281
226
|
"content": "My sample response",
|
|
282
227
|
"threadOf": 2, // id of comment we would like to start / continue the thread (Optional)
|
|
283
|
-
"related":
|
|
284
|
-
"refId": 1,
|
|
285
|
-
"ref": "article",
|
|
286
|
-
"field": "comments"
|
|
287
|
-
}]
|
|
228
|
+
"related": "api::page.page:1"
|
|
288
229
|
}
|
|
289
230
|
```
|
|
290
231
|
|
|
@@ -302,20 +243,20 @@ Posts a Comment related to specified instance of Content Type like for example `
|
|
|
302
243
|
|
|
303
244
|
### Update Comment
|
|
304
245
|
|
|
305
|
-
`PUT <host>/comments
|
|
246
|
+
`PUT <host>/comments/api::<collection name>.<content type name>:<entity id>/comment/<commentId>`
|
|
306
247
|
|
|
307
|
-
Updates a specified Comment content based on it `commentId` and related to specified instance of Content Type like for example `
|
|
248
|
+
Updates a specified Comment content based on it `commentId` and related to specified instance of Content Type like for example `Page` with `ID: 1`
|
|
308
249
|
|
|
309
|
-
**Example URL**: `https://localhost:1337/comments/
|
|
250
|
+
**Example URL**: `https://localhost:1337/comments/api::page.page:1/comment/2`
|
|
310
251
|
|
|
311
252
|
**Example request body**
|
|
312
253
|
|
|
313
254
|
*Generic (non Strapi User)*
|
|
314
255
|
```
|
|
315
256
|
{
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
257
|
+
"author": {
|
|
258
|
+
"id": "<any ID like value>"
|
|
259
|
+
},
|
|
319
260
|
"content": "My sample response"
|
|
320
261
|
}
|
|
321
262
|
```
|
|
@@ -343,11 +284,11 @@ Updates a specified Comment content based on it `commentId` and related to speci
|
|
|
343
284
|
|
|
344
285
|
### Delete Comment
|
|
345
286
|
|
|
346
|
-
`DELETE <host>/comments
|
|
287
|
+
`DELETE <host>/comments/api::<collection name>.<content type name>:<entity id>/<commentId>?authorId=<authorId>`
|
|
347
288
|
|
|
348
|
-
Deletes a specified Comment based on it `commentId` and related to specified instance of Content Type like for example `
|
|
289
|
+
Deletes a specified Comment based on it `commentId` and related to specified instance of Content Type like for example `Page` with `ID: 1`.
|
|
349
290
|
|
|
350
|
-
**Example URL**: `https://localhost:1337/comments/
|
|
291
|
+
**Example URL**: `https://localhost:1337/comments/api::page.page:1/comment/1?authorId=1`
|
|
351
292
|
|
|
352
293
|
**Example response body**
|
|
353
294
|
|
|
@@ -361,33 +302,14 @@ Deletes a specified Comment based on it `commentId` and related to specified ins
|
|
|
361
302
|
- `200` - Successful with blank Response.
|
|
362
303
|
- `409` - Conflict. Occurs when trying to delete a non existing comment.
|
|
363
304
|
|
|
364
|
-
### Like Comment
|
|
365
|
-
|
|
366
|
-
`PATCH <host>/comments/<content-type>:<id>/comment/<commentId>/like`
|
|
367
|
-
|
|
368
|
-
Likes a specified Comment based on it `commentId` and related to specified instance of Content Type like for example `Article` with `ID: 1`.
|
|
369
|
-
|
|
370
|
-
**Example URL**: `https://localhost:1337/comments/article:1/comment/2/like`
|
|
371
|
-
|
|
372
|
-
**Example response body**
|
|
373
|
-
|
|
374
|
-
```
|
|
375
|
-
{
|
|
376
|
-
-- Comment Model fields ---
|
|
377
|
-
}
|
|
378
|
-
```
|
|
379
|
-
|
|
380
|
-
**Possible response codes**
|
|
381
|
-
- `200` - Successful. Response with liked Comment Model.
|
|
382
|
-
- `409` - Conflict. Occurs when trying to like a non existing comment.
|
|
383
305
|
|
|
384
306
|
### Report abuse in the Comment
|
|
385
307
|
|
|
386
|
-
`POST <host>/comments
|
|
308
|
+
`POST <host>/comments/api::<collection name>.<content type name>:<entity id>/comment/<commentId>/report-abuse`
|
|
387
309
|
|
|
388
|
-
Reports abuse in specified Comment content based on it `commentId` and related to specified instance of Content Type like for example `
|
|
310
|
+
Reports abuse in specified Comment content based on it `commentId` and related to specified instance of Content Type like for example `Page` with `ID: 1` and requests moderator attention.
|
|
389
311
|
|
|
390
|
-
**Example URL**: `https://localhost:1337/comments/
|
|
312
|
+
**Example URL**: `https://localhost:1337/comments/api::page.page:1/comment/2/report-abuse`
|
|
391
313
|
|
|
392
314
|
**Example request body**
|
|
393
315
|
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* Entity Details
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import React from 'react';
|
|
8
|
+
import PropTypes from 'prop-types';
|
|
9
|
+
import { Button } from '@strapi/design-system/Button';
|
|
10
|
+
import { Dialog, DialogBody, DialogFooter } from '@strapi/design-system/Dialog';
|
|
11
|
+
import { Flex } from '@strapi/design-system/Flex';
|
|
12
|
+
import { Stack } from '@strapi/design-system/Stack';
|
|
13
|
+
import { Typography } from '@strapi/design-system/Typography';
|
|
14
|
+
import { ExclamationMarkCircle, Check } from '@strapi/icons';
|
|
15
|
+
import { getMessage } from '../../utils';
|
|
16
|
+
|
|
17
|
+
const ConfirmationDialog = ({
|
|
18
|
+
isVisible = false,
|
|
19
|
+
isActionAsync = false,
|
|
20
|
+
children,
|
|
21
|
+
onConfirm,
|
|
22
|
+
onCancel,
|
|
23
|
+
header,
|
|
24
|
+
labelCancel,
|
|
25
|
+
labelConfirm,
|
|
26
|
+
iconConfirm
|
|
27
|
+
}) => (
|
|
28
|
+
<Dialog onClose={onCancel} title={header || getMessage('compontents.confirmation.dialog.header', 'Confirmation')} isOpen={isVisible}>
|
|
29
|
+
<DialogBody icon={<ExclamationMarkCircle />}>
|
|
30
|
+
<Stack size={2}>
|
|
31
|
+
<Flex justifyContent="center">
|
|
32
|
+
<Typography id="dialog-confirm-description">{children || getMessage('compontents.confirmation.dialog.description') }</Typography>
|
|
33
|
+
</Flex>
|
|
34
|
+
</Stack>
|
|
35
|
+
</DialogBody>
|
|
36
|
+
<DialogFooter startAction={<Button onClick={onCancel} variant="tertiary" disabled={isActionAsync}>
|
|
37
|
+
{ labelCancel || getMessage('compontents.confirmation.dialog.button.cancel', 'Cancel') }
|
|
38
|
+
</Button>} endAction={<Button onClick={onConfirm} variant="danger-light" startIcon={iconConfirm || <Check />} disabled={isActionAsync}>
|
|
39
|
+
{ labelConfirm || getMessage('compontents.confirmation.dialog.button.confirm', 'Confirm') }
|
|
40
|
+
</Button>} />
|
|
41
|
+
</Dialog>
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
ConfirmationDialog.propTypes = {
|
|
45
|
+
isVisible: PropTypes.bool,
|
|
46
|
+
isActionAsync: PropTypes.bool,
|
|
47
|
+
children: PropTypes.array.isRequired,
|
|
48
|
+
header: PropTypes.string,
|
|
49
|
+
labelCancel: PropTypes.string,
|
|
50
|
+
labelConfirm: PropTypes.string,
|
|
51
|
+
iconConfirm: PropTypes.object,
|
|
52
|
+
onConfirm: PropTypes.func.isRequired,
|
|
53
|
+
onCancel: PropTypes.func.isRequired,
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
export default ConfirmationDialog;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* Entity Details
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import React from 'react';
|
|
8
|
+
import PropTypes from 'prop-types';
|
|
9
|
+
import { isNil } from 'lodash';
|
|
10
|
+
import { Box } from '@strapi/design-system/Box';
|
|
11
|
+
import { Status } from '@strapi/design-system/Status';
|
|
12
|
+
import { Typography } from '@strapi/design-system/Typography';
|
|
13
|
+
import { getMessage } from '../../utils';
|
|
14
|
+
|
|
15
|
+
const DiscussionStatus = ({ blocked, blockedThread }) => {
|
|
16
|
+
let variant = 'success';
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<Box styles={{ marginBottom: 10 }}>
|
|
20
|
+
<Status variant={variant}>
|
|
21
|
+
<Typography>
|
|
22
|
+
{ getMessage('page.details.panel.status', 'Discussion is') } <Typography fontWeight="bold">{ getMessage('page.details.panel.open', 'OPEN') } </Typography>
|
|
23
|
+
</Typography>
|
|
24
|
+
</Status>
|
|
25
|
+
</Box>);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
DiscussionStatus.propTypes = {
|
|
29
|
+
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export default DiscussionStatus;
|
|
33
|
+
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* Entity Details
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import React from 'react';
|
|
8
|
+
import PropTypes from 'prop-types';
|
|
9
|
+
import { isNil } from 'lodash';
|
|
10
|
+
import { Box } from '@strapi/design-system/Box';
|
|
11
|
+
import { Divider } from '@strapi/design-system/Divider';
|
|
12
|
+
import { Flex } from '@strapi/design-system/Flex';
|
|
13
|
+
import { Link } from '@strapi/design-system/Link';
|
|
14
|
+
import { Typography } from '@strapi/design-system/Typography';
|
|
15
|
+
import { ArrowUp } from '@strapi/icons';
|
|
16
|
+
import DiscussionThreadItem from '../DiscussionThreadItem';
|
|
17
|
+
import { getMessage, getUrl } from '../../utils';
|
|
18
|
+
import LoadingIndicatorOverlay from '../LoadingIndicatorOverlay';
|
|
19
|
+
import { LoadingIndicatorContainer } from '../LoadingIndicatorOverlay/styles';
|
|
20
|
+
|
|
21
|
+
const DiscussionThread = ({ level = [], selected = {}, isReloading }) => {
|
|
22
|
+
const rootThread = selected?.threadOf;
|
|
23
|
+
return (<LoadingIndicatorContainer as={Box} padding={4}>
|
|
24
|
+
{ isReloading && <LoadingIndicatorOverlay />}
|
|
25
|
+
<Flex as={Box} direction="row" justifyContent="space-between">
|
|
26
|
+
<Typography variant="sigma" textColor="neutral600" id="entity-details">
|
|
27
|
+
{ getMessage('page.details.panel.discussion', 'Discussion') }
|
|
28
|
+
</Typography>
|
|
29
|
+
{ rootThread && (<Link to={getUrl(`discover/${rootThread.id}`)} startIcon={<ArrowUp />}>
|
|
30
|
+
{ getMessage('page.details.panel.discussion.nav.back') }
|
|
31
|
+
</Link>) }
|
|
32
|
+
</Flex>
|
|
33
|
+
<Box paddingTop={2} paddingBottom={6}>
|
|
34
|
+
<Divider />
|
|
35
|
+
</Box>
|
|
36
|
+
<Flex as="ul" direction="column" alignItems="flex-start">
|
|
37
|
+
{ rootThread && (<DiscussionThreadItem {...rootThread} isThreadAuthor root />) }
|
|
38
|
+
{ level.map(item => {
|
|
39
|
+
const isSelected = selected.id === item.id;
|
|
40
|
+
const isThreadAuthor = !isNil(selected?.threadOf?.authorId) && (selected?.threadOf?.authorId === item.authorId);
|
|
41
|
+
return (<DiscussionThreadItem
|
|
42
|
+
{...item}
|
|
43
|
+
blockedThread={rootThread?.blockedThread || item.blockedThread}
|
|
44
|
+
isSelected={isSelected}
|
|
45
|
+
isThreadAuthor={isThreadAuthor}
|
|
46
|
+
/>);
|
|
47
|
+
})}
|
|
48
|
+
</Flex>
|
|
49
|
+
</LoadingIndicatorContainer>);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
DiscussionThread.propTypes = {
|
|
53
|
+
level: PropTypes.array.isRequired,
|
|
54
|
+
selected: PropTypes.object.isRequired,
|
|
55
|
+
isReloading: PropTypes.bool,
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
export default DiscussionThread;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
*
|
|
3
|
+
* Entity Details
|
|
4
|
+
*
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import React from 'react';
|
|
8
|
+
import PropTypes from 'prop-types';
|
|
9
|
+
import { first } from 'lodash';
|
|
10
|
+
import { Avatar, Initials } from '@strapi/design-system/Avatar';
|
|
11
|
+
import { Box } from '@strapi/design-system/Box';
|
|
12
|
+
import { Divider } from '@strapi/design-system/Divider';
|
|
13
|
+
import { Flex } from '@strapi/design-system/Flex';
|
|
14
|
+
import { Link } from '@strapi/design-system/Link';
|
|
15
|
+
import { Typography } from '@strapi/design-system/Typography';
|
|
16
|
+
import { ArrowRight } from '@strapi/icons';
|
|
17
|
+
import DiscussionThreadItemMeta from '../DiscussionThreadItemMeta';
|
|
18
|
+
import { AvatarWrapper, DiscussionThreadItemBox, DiscussionThreadItemBoxContent, DiscussionThreadItemContent, DiscussionThreadItemLeft, DiscussionThreadItemLinkBox, DiscussionThreadItemRight, DiscussionThreadItemRoot } from './styles';
|
|
19
|
+
import DiscussionThreadItemActions from '../DiscussionThreadItemActions';
|
|
20
|
+
import { getMessage, getUrl } from '../../utils';
|
|
21
|
+
import DiscussionThreadItemWarnings from '../DiscussionThreadItemWarnings';
|
|
22
|
+
|
|
23
|
+
const DiscussionThreadItem = (item) => {
|
|
24
|
+
const { id, isSelected, isThreadAuthor, content, root, preview, blocked, blockedThread, gotThread, threadFirstItemId, authorUser, authorAvatar, authorName } = item;
|
|
25
|
+
|
|
26
|
+
let background = 'neutral100';
|
|
27
|
+
let borderColor = 'neutral200';
|
|
28
|
+
let dividerColor = 'neutral200';
|
|
29
|
+
let StyledComponent = DiscussionThreadItemRight;
|
|
30
|
+
|
|
31
|
+
if(isThreadAuthor || root){
|
|
32
|
+
StyledComponent = DiscussionThreadItemLeft;
|
|
33
|
+
borderColor = 'neutral100';
|
|
34
|
+
dividerColor = 'neutral100';
|
|
35
|
+
background = null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (isSelected) {
|
|
39
|
+
background = 'secondary100'
|
|
40
|
+
borderColor = 'secondary500';
|
|
41
|
+
dividerColor = 'secondary200';
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (root) {
|
|
45
|
+
StyledComponent = DiscussionThreadItemRoot;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const avatar = authorAvatar || authorUser?.avatar;
|
|
49
|
+
const name = authorName || `${authorUser?.firstName} ${authorUser?.lastName}`;
|
|
50
|
+
const isBlocked = blocked || blockedThread;
|
|
51
|
+
|
|
52
|
+
const renderInitials = value => value.split(' ').map(_ => first(_)).join('').toUpperCase();
|
|
53
|
+
|
|
54
|
+
return (<StyledComponent as="li">
|
|
55
|
+
<DiscussionThreadItemContent as={Flex} direction="row">
|
|
56
|
+
<AvatarWrapper>
|
|
57
|
+
{ avatar ? <Avatar src={avatar} alt={name} /> : <Initials>{ renderInitials(name) }</Initials> }
|
|
58
|
+
</AvatarWrapper>
|
|
59
|
+
<DiscussionThreadItemBox hasRadius shadow="filterShadow" borderColor={borderColor} background={background} padding={2}>
|
|
60
|
+
<Flex as={Box} paddingBottom={2} direction="column">
|
|
61
|
+
<DiscussionThreadItemBoxContent as={Flex} direction="row">
|
|
62
|
+
<Box as={Flex} grow={1} alignItems="center">
|
|
63
|
+
<Typography variant="omega">{ content }</Typography>
|
|
64
|
+
</Box>
|
|
65
|
+
{ !preview && (<DiscussionThreadItemActions { ...item } root={root} />) }
|
|
66
|
+
</DiscussionThreadItemBoxContent>
|
|
67
|
+
{ !(preview || isBlocked) && (<DiscussionThreadItemWarnings { ...item } />) }
|
|
68
|
+
</Flex>
|
|
69
|
+
<Divider background={dividerColor} />
|
|
70
|
+
<DiscussionThreadItemMeta { ...item } />
|
|
71
|
+
</DiscussionThreadItemBox>
|
|
72
|
+
</DiscussionThreadItemContent>
|
|
73
|
+
|
|
74
|
+
{ (gotThread && !preview) && (<DiscussionThreadItemLinkBox direction="row" alignItems="flex-end">
|
|
75
|
+
<Link to={getUrl(`discover/${threadFirstItemId}`)} endIcon={<ArrowRight />}>
|
|
76
|
+
{ getMessage('page.details.panel.discussion.nav.drilldown') }
|
|
77
|
+
</Link>
|
|
78
|
+
</DiscussionThreadItemLinkBox>) }
|
|
79
|
+
</StyledComponent>);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
DiscussionThreadItem.propTypes = {
|
|
83
|
+
content: PropTypes.string.isRequired,
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
export default DiscussionThreadItem;
|
|
87
|
+
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import styled from 'styled-components';
|
|
2
|
+
import { Box } from '@strapi/design-system/Box';
|
|
3
|
+
import { Flex } from '@strapi/design-system/Flex';
|
|
4
|
+
|
|
5
|
+
export const AvatarWrapper = styled(Box)``;
|
|
6
|
+
export const InitialsWrapper = styled(Box)``;
|
|
7
|
+
|
|
8
|
+
export const DiscussionThreadItemLinkBox = styled(Flex)`
|
|
9
|
+
margin-top: .5rem;
|
|
10
|
+
margin-bottom: .5rem;
|
|
11
|
+
`
|
|
12
|
+
|
|
13
|
+
const DiscussionThreadItemStyled = styled(Box)`
|
|
14
|
+
display: flex;
|
|
15
|
+
flex-direction: column;
|
|
16
|
+
width: 100%;
|
|
17
|
+
margin-bottom: 1rem;
|
|
18
|
+
|
|
19
|
+
${AvatarWrapper},
|
|
20
|
+
${InitialsWrapper} {
|
|
21
|
+
align-self: flex-start;
|
|
22
|
+
margin-top: .4rem;
|
|
23
|
+
}
|
|
24
|
+
`;
|
|
25
|
+
|
|
26
|
+
export const DiscussionThreadItemContent = styled(Box)`
|
|
27
|
+
max-width: 45%;
|
|
28
|
+
`;
|
|
29
|
+
|
|
30
|
+
export const DiscussionThreadItemLeft = styled(DiscussionThreadItemStyled)`
|
|
31
|
+
align-items: flex-start;
|
|
32
|
+
padding-left: 4rem;
|
|
33
|
+
text-align: left;
|
|
34
|
+
|
|
35
|
+
${DiscussionThreadItemContent} {
|
|
36
|
+
align-self: flex-start;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
${AvatarWrapper},
|
|
40
|
+
${InitialsWrapper} {
|
|
41
|
+
margin-right: 1rem;
|
|
42
|
+
}
|
|
43
|
+
`;
|
|
44
|
+
|
|
45
|
+
export const DiscussionThreadItemRight = styled(DiscussionThreadItemStyled)`
|
|
46
|
+
align-items: flex-end;
|
|
47
|
+
padding-right: 4rem;
|
|
48
|
+
text-align: left;
|
|
49
|
+
|
|
50
|
+
${DiscussionThreadItemContent} {
|
|
51
|
+
align-self: flex-end;
|
|
52
|
+
flex-direction: row-reverse;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
${AvatarWrapper},
|
|
56
|
+
${InitialsWrapper} {
|
|
57
|
+
margin-left: 1rem;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
${DiscussionThreadItemLinkBox} {
|
|
61
|
+
margin-right: 3rem;
|
|
62
|
+
}
|
|
63
|
+
`;
|
|
64
|
+
|
|
65
|
+
export const DiscussionThreadItemBox = styled(Box)`
|
|
66
|
+
|
|
67
|
+
`;
|
|
68
|
+
|
|
69
|
+
export const DiscussionThreadItemBoxContent = styled(Box)`
|
|
70
|
+
width: 100%;
|
|
71
|
+
align-items: stretch;
|
|
72
|
+
`
|
|
73
|
+
|
|
74
|
+
export const DiscussionThreadItemRoot = styled(DiscussionThreadItemLeft)`
|
|
75
|
+
padding-left: 0;
|
|
76
|
+
padding-right: 0;
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
${DiscussionThreadItemContent} {
|
|
80
|
+
width: 100%;
|
|
81
|
+
max-width: 100%;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
${DiscussionThreadItemBox} {
|
|
85
|
+
flex-grow: 1;
|
|
86
|
+
}
|
|
87
|
+
`;
|