strapi-plugin-comments 1.0.4 → 2.0.0-beta.4
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 +53 -126
- 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 +59 -0
- package/admin/src/components/DiscussionThreadItem/index.js +87 -0
- package/admin/src/components/DiscussionThreadItem/styles.js +88 -0
- package/admin/src/components/DiscussionThreadItemActions/index.js +178 -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 +141 -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 +43 -0
- package/admin/src/components/ReportsReviewTable/index.js +146 -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/components/icons/index.js +6 -0
- package/admin/src/components/icons/lock.js +22 -0
- package/admin/src/components/icons/review.js +18 -0
- package/admin/src/components/icons/unlock.js +20 -0
- package/admin/src/index.js +58 -42
- package/admin/src/pages/App/index.js +71 -0
- package/admin/src/pages/App/reducer/actions.js +8 -0
- package/admin/src/pages/App/reducer/constants.js +4 -0
- package/admin/src/pages/App/reducer/index.js +26 -0
- package/admin/src/pages/App/reducer/init.js +7 -0
- package/admin/src/pages/App/reducer/selectors.js +35 -0
- package/admin/src/pages/App/utils/api.js +12 -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/components/DiscoverTableRow/index.js +196 -0
- package/admin/src/pages/Discover/index.js +157 -0
- package/admin/src/pages/Discover/utils/api.js +14 -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/reducers.js +8 -0
- package/admin/src/translations/en.json +73 -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 +21 -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 +10 -0
- package/server/controllers/admin.js +134 -0
- package/server/controllers/client.js +117 -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 +215 -0
- package/server/services/client.js +227 -0
- package/server/services/common.js +197 -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,24 @@ To setup amend default plugin configuration we recommend to put following snippe
|
|
|
99
74
|
```js
|
|
100
75
|
...
|
|
101
76
|
comments: {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
77
|
+
badWords: false,
|
|
78
|
+
moderatorRoles: ["Authenticated"],
|
|
79
|
+
entryLabel: {
|
|
80
|
+
'*': ['Title', 'title', 'Name', 'name', 'Subject', 'subject'],
|
|
81
|
+
'api::page.page': ['MyField'],
|
|
82
|
+
},
|
|
105
83
|
},
|
|
106
84
|
...
|
|
107
85
|
```
|
|
108
86
|
|
|
109
87
|
### 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
88
|
- `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/
|
|
89
|
+
- `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.
|
|
90
|
+
- `entryLabel` - ordered list of property names per Content Type to generate related entity label. Default set as `*`.
|
|
113
91
|
|
|
114
92
|
## Additional GQL Configuration
|
|
115
93
|
|
|
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
|
|
94
|
+
> To be done
|
|
146
95
|
|
|
147
96
|
## Public API Comment model
|
|
148
97
|
|
|
@@ -154,14 +103,15 @@ To setup amend default plugin configuration we recommend to put following snippe
|
|
|
154
103
|
"blocked": null,
|
|
155
104
|
"blockedThread": true,
|
|
156
105
|
"blockReason": null,
|
|
157
|
-
"points": 1,
|
|
158
106
|
"authorUser": null,
|
|
159
107
|
"authorId": "207ccfdc-94ba-45eb-979c-790f6f49c392",
|
|
160
108
|
"authorName": "Joe Doe",
|
|
161
109
|
"authorEmail": "jdoe@sample.com",
|
|
162
110
|
"authorAvatar": null,
|
|
163
|
-
"
|
|
164
|
-
"
|
|
111
|
+
"createdAt": "2020-07-14T20:13:01.649Z",
|
|
112
|
+
"updatedAt": "2020-07-14T20:13:01.670Z",
|
|
113
|
+
"related": {}, // Related content type entity
|
|
114
|
+
"reports": [] // Reports issued against this comment
|
|
165
115
|
}
|
|
166
116
|
```
|
|
167
117
|
### Strapi User
|
|
@@ -172,7 +122,6 @@ To setup amend default plugin configuration we recommend to put following snippe
|
|
|
172
122
|
"blocked": true,
|
|
173
123
|
"blockedThread": null,
|
|
174
124
|
"blockReason": null,
|
|
175
|
-
"points": null,
|
|
176
125
|
"authorUser": {
|
|
177
126
|
"id": 1,
|
|
178
127
|
"username": "Sample User",
|
|
@@ -188,8 +137,10 @@ To setup amend default plugin configuration we recommend to put following snippe
|
|
|
188
137
|
"authorName": null,
|
|
189
138
|
"authorEmail": null,
|
|
190
139
|
"authorAvatar": null,
|
|
191
|
-
"
|
|
192
|
-
"
|
|
140
|
+
"createdAt": "2020-07-14T20:13:01.649Z",
|
|
141
|
+
"updatedAt": "2020-07-14T20:13:01.670Z",
|
|
142
|
+
"related": {}, // Related content type entity
|
|
143
|
+
"reports": [] // Reports issued against this comment
|
|
193
144
|
}
|
|
194
145
|
|
|
195
146
|
```
|
|
@@ -198,11 +149,11 @@ To setup amend default plugin configuration we recommend to put following snippe
|
|
|
198
149
|
|
|
199
150
|
### Get Comments
|
|
200
151
|
|
|
201
|
-
`GET <host>/comments
|
|
152
|
+
`GET <host>/comments/api::<collection name>.<content type name>:<entity id>`
|
|
202
153
|
|
|
203
|
-
Return a hierarchical tree structure of comments for specified instance of Content Type like for example `
|
|
154
|
+
Return a hierarchical tree structure of comments for specified instance of Content Type like for example `Page` with `ID: 1`
|
|
204
155
|
|
|
205
|
-
**Example URL**: `https://localhost:1337/comments/
|
|
156
|
+
**Example URL**: `https://localhost:1337/comments/api::page.page:1`
|
|
206
157
|
|
|
207
158
|
**Example response body**
|
|
208
159
|
|
|
@@ -224,11 +175,11 @@ Return a hierarchical tree structure of comments for specified instance of Conte
|
|
|
224
175
|
|
|
225
176
|
### Get Comments (flat structure)
|
|
226
177
|
|
|
227
|
-
`GET <host>/comments
|
|
178
|
+
`GET <host>/comments/api::<collection name>.<content type name>:<entity id>/flat`
|
|
228
179
|
|
|
229
|
-
Return a flat structure of comments for specified instance of Content Type like for example `
|
|
180
|
+
Return a flat structure of comments for specified instance of Content Type like for example `Page` with `ID: 1`
|
|
230
181
|
|
|
231
|
-
**Example URL**: `https://localhost:1337/comments/
|
|
182
|
+
**Example URL**: `https://localhost:1337/comments/api::page.page:1/flat`
|
|
232
183
|
|
|
233
184
|
**Example response body**
|
|
234
185
|
|
|
@@ -250,27 +201,26 @@ Return a flat structure of comments for specified instance of Content Type like
|
|
|
250
201
|
|
|
251
202
|
### Post a Comment
|
|
252
203
|
|
|
253
|
-
`POST <host>/comments
|
|
204
|
+
`POST <host>/comments/api::<collection name>.<content type name>:<entity id>`
|
|
254
205
|
|
|
255
|
-
Posts a Comment related to specified instance of Content Type like for example `
|
|
206
|
+
Posts a Comment related to specified instance of Content Type like for example `Page` with `ID: 1`
|
|
256
207
|
|
|
257
|
-
**Example URL**: `https://localhost:1337/comments/
|
|
208
|
+
**Example URL**: `https://localhost:1337/comments/api::page.page:1`
|
|
258
209
|
|
|
259
210
|
**Example request body**
|
|
260
211
|
|
|
261
212
|
*Generic (non Strapi User)*
|
|
262
213
|
```
|
|
263
214
|
{
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
215
|
+
"author": {
|
|
216
|
+
"id": "<any ID like value>",
|
|
217
|
+
"name": "Joe Doe",
|
|
218
|
+
"email": "jdoe@sample.com",
|
|
219
|
+
"avatar": "<any image url>"
|
|
220
|
+
},
|
|
267
221
|
"content": "My sample response",
|
|
268
222
|
"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
|
-
}]
|
|
223
|
+
"related": "api::page.page:1"
|
|
274
224
|
}
|
|
275
225
|
```
|
|
276
226
|
|
|
@@ -280,11 +230,7 @@ Posts a Comment related to specified instance of Content Type like for example `
|
|
|
280
230
|
"authorUser": 1, // id of a author user. Optional in case of 'enableUsers: true' in the plugin configuration
|
|
281
231
|
"content": "My sample response",
|
|
282
232
|
"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
|
-
}]
|
|
233
|
+
"related": "api::page.page:1"
|
|
288
234
|
}
|
|
289
235
|
```
|
|
290
236
|
|
|
@@ -302,20 +248,20 @@ Posts a Comment related to specified instance of Content Type like for example `
|
|
|
302
248
|
|
|
303
249
|
### Update Comment
|
|
304
250
|
|
|
305
|
-
`PUT <host>/comments
|
|
251
|
+
`PUT <host>/comments/api::<collection name>.<content type name>:<entity id>/comment/<commentId>`
|
|
306
252
|
|
|
307
|
-
Updates a specified Comment content based on it `commentId` and related to specified instance of Content Type like for example `
|
|
253
|
+
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
254
|
|
|
309
|
-
**Example URL**: `https://localhost:1337/comments/
|
|
255
|
+
**Example URL**: `https://localhost:1337/comments/api::page.page:1/comment/2`
|
|
310
256
|
|
|
311
257
|
**Example request body**
|
|
312
258
|
|
|
313
259
|
*Generic (non Strapi User)*
|
|
314
260
|
```
|
|
315
261
|
{
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
262
|
+
"author": {
|
|
263
|
+
"id": "<any ID like value>"
|
|
264
|
+
},
|
|
319
265
|
"content": "My sample response"
|
|
320
266
|
}
|
|
321
267
|
```
|
|
@@ -343,11 +289,11 @@ Updates a specified Comment content based on it `commentId` and related to speci
|
|
|
343
289
|
|
|
344
290
|
### Delete Comment
|
|
345
291
|
|
|
346
|
-
`DELETE <host>/comments
|
|
292
|
+
`DELETE <host>/comments/api::<collection name>.<content type name>:<entity id>/<commentId>?authorId=<authorId>`
|
|
347
293
|
|
|
348
|
-
Deletes a specified Comment based on it `commentId` and related to specified instance of Content Type like for example `
|
|
294
|
+
Deletes a specified Comment based on it `commentId` and related to specified instance of Content Type like for example `Page` with `ID: 1`.
|
|
349
295
|
|
|
350
|
-
**Example URL**: `https://localhost:1337/comments/
|
|
296
|
+
**Example URL**: `https://localhost:1337/comments/api::page.page:1/comment/1?authorId=1`
|
|
351
297
|
|
|
352
298
|
**Example response body**
|
|
353
299
|
|
|
@@ -361,33 +307,14 @@ Deletes a specified Comment based on it `commentId` and related to specified ins
|
|
|
361
307
|
- `200` - Successful with blank Response.
|
|
362
308
|
- `409` - Conflict. Occurs when trying to delete a non existing comment.
|
|
363
309
|
|
|
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
310
|
|
|
384
311
|
### Report abuse in the Comment
|
|
385
312
|
|
|
386
|
-
`POST <host>/comments
|
|
313
|
+
`POST <host>/comments/api::<collection name>.<content type name>:<entity id>/comment/<commentId>/report-abuse`
|
|
387
314
|
|
|
388
|
-
Reports abuse in specified Comment content based on it `commentId` and related to specified instance of Content Type like for example `
|
|
315
|
+
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
316
|
|
|
390
|
-
**Example URL**: `https://localhost:1337/comments/
|
|
317
|
+
**Example URL**: `https://localhost:1337/comments/api::page.page:1/comment/2/report-abuse`
|
|
391
318
|
|
|
392
319
|
**Example request body**
|
|
393
320
|
|
|
@@ -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,59 @@
|
|
|
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 pinned />) }
|
|
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
|
+
root={isNil(rootThread)}
|
|
44
|
+
blockedThread={rootThread?.blockedThread || item.blockedThread}
|
|
45
|
+
isSelected={isSelected}
|
|
46
|
+
isThreadAuthor={isThreadAuthor}
|
|
47
|
+
/>);
|
|
48
|
+
})}
|
|
49
|
+
</Flex>
|
|
50
|
+
</LoadingIndicatorContainer>);
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
DiscussionThread.propTypes = {
|
|
54
|
+
level: PropTypes.array.isRequired,
|
|
55
|
+
selected: PropTypes.object.isRequired,
|
|
56
|
+
isReloading: PropTypes.bool,
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
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, pinned, 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 || pinned} />) }
|
|
66
|
+
</DiscussionThreadItemBoxContent>
|
|
67
|
+
{ !(preview || isBlocked) && (<DiscussionThreadItemWarnings { ...item } gotThread={gotThread || root} />) }
|
|
68
|
+
</Flex>
|
|
69
|
+
<Divider background={dividerColor} />
|
|
70
|
+
<DiscussionThreadItemMeta { ...item } />
|
|
71
|
+
</DiscussionThreadItemBox>
|
|
72
|
+
</DiscussionThreadItemContent>
|
|
73
|
+
|
|
74
|
+
{ (gotThread && !(preview || pinned)) && (<DiscussionThreadItemLinkBox direction="column" 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,88 @@
|
|
|
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
|
+
width: 100%;
|
|
10
|
+
margin-top: .5rem;
|
|
11
|
+
margin-bottom: .5rem;
|
|
12
|
+
`
|
|
13
|
+
|
|
14
|
+
const DiscussionThreadItemStyled = styled(Box)`
|
|
15
|
+
display: flex;
|
|
16
|
+
flex-direction: column;
|
|
17
|
+
width: 100%;
|
|
18
|
+
margin-bottom: 1rem;
|
|
19
|
+
|
|
20
|
+
${AvatarWrapper},
|
|
21
|
+
${InitialsWrapper} {
|
|
22
|
+
align-self: flex-start;
|
|
23
|
+
margin-top: .4rem;
|
|
24
|
+
}
|
|
25
|
+
`;
|
|
26
|
+
|
|
27
|
+
export const DiscussionThreadItemContent = styled(Box)`
|
|
28
|
+
max-width: 45%;
|
|
29
|
+
`;
|
|
30
|
+
|
|
31
|
+
export const DiscussionThreadItemLeft = styled(DiscussionThreadItemStyled)`
|
|
32
|
+
align-items: flex-start;
|
|
33
|
+
padding-left: 4rem;
|
|
34
|
+
text-align: left;
|
|
35
|
+
|
|
36
|
+
${DiscussionThreadItemContent} {
|
|
37
|
+
align-self: flex-start;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
${AvatarWrapper},
|
|
41
|
+
${InitialsWrapper} {
|
|
42
|
+
margin-right: 1rem;
|
|
43
|
+
}
|
|
44
|
+
`;
|
|
45
|
+
|
|
46
|
+
export const DiscussionThreadItemRight = styled(DiscussionThreadItemStyled)`
|
|
47
|
+
align-items: flex-end;
|
|
48
|
+
padding-right: 4rem;
|
|
49
|
+
text-align: left;
|
|
50
|
+
|
|
51
|
+
${DiscussionThreadItemContent} {
|
|
52
|
+
align-self: flex-end;
|
|
53
|
+
flex-direction: row-reverse;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
${AvatarWrapper},
|
|
57
|
+
${InitialsWrapper} {
|
|
58
|
+
margin-left: 1rem;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
${DiscussionThreadItemLinkBox} {
|
|
62
|
+
margin-right: 3rem;
|
|
63
|
+
}
|
|
64
|
+
`;
|
|
65
|
+
|
|
66
|
+
export const DiscussionThreadItemBox = styled(Box)`
|
|
67
|
+
|
|
68
|
+
`;
|
|
69
|
+
|
|
70
|
+
export const DiscussionThreadItemBoxContent = styled(Box)`
|
|
71
|
+
width: 100%;
|
|
72
|
+
align-items: stretch;
|
|
73
|
+
`
|
|
74
|
+
|
|
75
|
+
export const DiscussionThreadItemRoot = styled(DiscussionThreadItemLeft)`
|
|
76
|
+
padding-left: 0;
|
|
77
|
+
padding-right: 0;
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
${DiscussionThreadItemContent} {
|
|
81
|
+
width: 100%;
|
|
82
|
+
max-width: 100%;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
${DiscussionThreadItemBox} {
|
|
86
|
+
flex-grow: 1;
|
|
87
|
+
}
|
|
88
|
+
`;
|