strapi-plugin-comments 2.0.10 → 2.0.11

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.
Files changed (261) hide show
  1. package/README.md +39 -5
  2. package/admin/src/translations/fr.json +132 -1
  3. package/build/README.md +818 -0
  4. package/build/admin/src/components/ActionButton/styles.d.ts +2 -0
  5. package/build/admin/src/components/ActionButton/styles.js +17 -0
  6. package/build/admin/src/components/ConfirmationDialog/index.d.ts +26 -0
  7. package/build/admin/src/components/ConfirmationDialog/index.js +104 -0
  8. package/build/admin/src/components/DiscussionStatus/index.d.ts +9 -0
  9. package/build/admin/src/components/DiscussionStatus/index.js +38 -0
  10. package/build/admin/src/components/DiscussionThread/index.d.ts +16 -0
  11. package/build/admin/src/components/DiscussionThread/index.js +99 -0
  12. package/build/admin/src/components/DiscussionThreadItem/index.d.ts +9 -0
  13. package/build/admin/src/components/DiscussionThreadItem/index.js +72 -0
  14. package/build/admin/src/components/DiscussionThreadItem/styles.d.ts +4 -0
  15. package/build/admin/src/components/DiscussionThreadItem/styles.js +27 -0
  16. package/build/admin/src/components/DiscussionThreadItemActions/index.d.ts +19 -0
  17. package/build/admin/src/components/DiscussionThreadItemActions/index.js +414 -0
  18. package/build/admin/src/components/DiscussionThreadItemActions/styles.d.ts +2 -0
  19. package/build/admin/src/components/DiscussionThreadItemActions/styles.js +17 -0
  20. package/build/admin/src/components/DiscussionThreadItemApprovalFlowActions/index.d.ts +17 -0
  21. package/build/admin/src/components/DiscussionThreadItemApprovalFlowActions/index.js +103 -0
  22. package/build/admin/src/components/DiscussionThreadItemApprovalFlowActions/styles.d.ts +2 -0
  23. package/build/admin/src/components/DiscussionThreadItemApprovalFlowActions/styles.js +15 -0
  24. package/build/admin/src/components/DiscussionThreadItemFooter/index.d.ts +16 -0
  25. package/build/admin/src/components/DiscussionThreadItemFooter/index.js +73 -0
  26. package/build/admin/src/components/DiscussionThreadItemFooter/styles.d.ts +3 -0
  27. package/build/admin/src/components/DiscussionThreadItemFooter/styles.js +25 -0
  28. package/build/admin/src/components/DiscussionThreadItemReviewAction/index.d.ts +30 -0
  29. package/build/admin/src/components/DiscussionThreadItemReviewAction/index.js +233 -0
  30. package/build/admin/src/components/FormSwitch/index.d.ts +11 -0
  31. package/build/admin/src/components/FormSwitch/index.js +39 -0
  32. package/build/admin/src/components/FormSwitch/styles.d.ts +2 -0
  33. package/build/admin/src/components/FormSwitch/styles.js +16 -0
  34. package/build/admin/src/components/IconButton/styles.d.ts +2 -0
  35. package/build/admin/src/components/IconButton/styles.js +27 -0
  36. package/build/admin/src/components/Initializer/index.d.ts +3 -0
  37. package/build/admin/src/components/Initializer/index.js +14 -0
  38. package/build/admin/src/components/LoadingIndicatorOverlay/index.d.ts +3 -0
  39. package/build/admin/src/components/LoadingIndicatorOverlay/index.js +18 -0
  40. package/build/admin/src/components/LoadingIndicatorOverlay/styles.d.ts +3 -0
  41. package/build/admin/src/components/LoadingIndicatorOverlay/styles.js +32 -0
  42. package/build/admin/src/components/Nav/index.d.ts +7 -0
  43. package/build/admin/src/components/Nav/index.js +72 -0
  44. package/build/admin/src/components/PluginIcon/index.d.ts +3 -0
  45. package/build/admin/src/components/PluginIcon/index.js +13 -0
  46. package/build/admin/src/components/ReportsReviewModal/index.d.ts +21 -0
  47. package/build/admin/src/components/ReportsReviewModal/index.js +72 -0
  48. package/build/admin/src/components/ReportsReviewTable/index.d.ts +21 -0
  49. package/build/admin/src/components/ReportsReviewTable/index.js +321 -0
  50. package/build/admin/src/components/StatusBadge/index.d.ts +11 -0
  51. package/build/admin/src/components/StatusBadge/index.js +22 -0
  52. package/build/admin/src/components/StatusBadge/styles.d.ts +2 -0
  53. package/build/admin/src/components/StatusBadge/styles.js +25 -0
  54. package/build/admin/src/components/TableFilters/index.d.ts +10 -0
  55. package/build/admin/src/components/TableFilters/index.js +109 -0
  56. package/build/admin/src/components/TablePagination/index.d.ts +15 -0
  57. package/build/admin/src/components/TablePagination/index.js +45 -0
  58. package/build/admin/src/components/icons/comments.d.ts +9 -0
  59. package/build/admin/src/components/icons/comments.js +23 -0
  60. package/build/admin/src/components/icons/index.d.ts +6 -0
  61. package/build/admin/src/components/icons/index.js +21 -0
  62. package/build/admin/src/components/icons/lock.d.ts +11 -0
  63. package/build/admin/src/components/icons/lock.js +29 -0
  64. package/build/admin/src/components/icons/review.d.ts +11 -0
  65. package/build/admin/src/components/icons/review.js +31 -0
  66. package/build/admin/src/components/icons/unlock.d.ts +11 -0
  67. package/build/admin/src/components/icons/unlock.js +29 -0
  68. package/build/admin/src/hooks/useConfig.d.ts +8 -0
  69. package/build/admin/src/hooks/useConfig.js +52 -0
  70. package/build/admin/src/index.d.ts +7 -0
  71. package/build/admin/src/index.js +137 -0
  72. package/build/admin/src/pages/App/index.d.ts +4 -0
  73. package/build/admin/src/pages/App/index.js +90 -0
  74. package/build/admin/src/pages/App/reducer/actions.d.ts +8 -0
  75. package/build/admin/src/pages/App/reducer/actions.js +12 -0
  76. package/build/admin/src/pages/App/reducer/constants.d.ts +4 -0
  77. package/build/admin/src/pages/App/reducer/constants.js +7 -0
  78. package/build/admin/src/pages/App/reducer/index.d.ts +14 -0
  79. package/build/admin/src/pages/App/reducer/index.js +31 -0
  80. package/build/admin/src/pages/App/reducer/init.d.ts +3 -0
  81. package/build/admin/src/pages/App/reducer/init.js +9 -0
  82. package/build/admin/src/pages/App/reducer/selectors.d.ts +6 -0
  83. package/build/admin/src/pages/App/reducer/selectors.js +20 -0
  84. package/build/admin/src/pages/App/utils/api.d.ts +2 -0
  85. package/build/admin/src/pages/App/utils/api.js +16 -0
  86. package/build/admin/src/pages/ComingSoonPage/index.d.ts +3 -0
  87. package/build/admin/src/pages/ComingSoonPage/index.js +78 -0
  88. package/build/admin/src/pages/Details/components/DetailsEntity/index.d.ts +18 -0
  89. package/build/admin/src/pages/Details/components/DetailsEntity/index.js +132 -0
  90. package/build/admin/src/pages/Details/components/DetailsFilters/index.d.ts +12 -0
  91. package/build/admin/src/pages/Details/components/DetailsFilters/index.js +48 -0
  92. package/build/admin/src/pages/Details/components/DetailsFilters/styles.d.ts +2 -0
  93. package/build/admin/src/pages/Details/components/DetailsFilters/styles.js +16 -0
  94. package/build/admin/src/pages/Details/index.d.ts +4 -0
  95. package/build/admin/src/pages/Details/index.js +216 -0
  96. package/build/admin/src/pages/Discover/components/DiscoverTableRow/index.d.ts +20 -0
  97. package/build/admin/src/pages/Discover/components/DiscoverTableRow/index.js +344 -0
  98. package/build/admin/src/pages/Discover/components/DiscoverTableRow/styles.d.ts +2 -0
  99. package/build/admin/src/pages/Discover/components/DiscoverTableRow/styles.js +16 -0
  100. package/build/admin/src/pages/Discover/index.d.ts +4 -0
  101. package/build/admin/src/pages/Discover/index.js +332 -0
  102. package/build/admin/src/pages/Discover/utils/api.d.ts +2 -0
  103. package/build/admin/src/pages/Discover/utils/api.js +23 -0
  104. package/build/admin/src/pages/Discover/utils/filtersSchema.d.ts +11 -0
  105. package/build/admin/src/pages/Discover/utils/filtersSchema.js +11 -0
  106. package/build/admin/src/pages/Settings/components/RestartAlert/styles.d.ts +2 -0
  107. package/build/admin/src/pages/Settings/components/RestartAlert/styles.js +16 -0
  108. package/build/admin/src/pages/Settings/index.d.ts +3 -0
  109. package/build/admin/src/pages/Settings/index.js +712 -0
  110. package/build/admin/src/pages/Settings/utils/api.d.ts +7 -0
  111. package/build/admin/src/pages/Settings/utils/api.js +80 -0
  112. package/build/admin/src/pages/utils/api.d.ts +12 -0
  113. package/build/admin/src/pages/utils/api.js +83 -0
  114. package/build/admin/src/permissions.d.ts +28 -0
  115. package/build/admin/src/permissions.js +65 -0
  116. package/build/admin/src/pluginId.d.ts +2 -0
  117. package/build/admin/src/pluginId.js +50 -0
  118. package/build/admin/src/reducers.d.ts +12 -0
  119. package/build/admin/src/reducers.js +14 -0
  120. package/build/admin/src/translations/en.json +132 -0
  121. package/build/admin/src/translations/fr.json +1 -0
  122. package/build/admin/src/translations/pt-BR.json +132 -0
  123. package/build/admin/src/utils/axiosInstance.d.ts +3 -0
  124. package/build/admin/src/utils/axiosInstance.js +37 -0
  125. package/build/admin/src/utils/constants.d.ts +25 -0
  126. package/build/admin/src/utils/constants.js +30 -0
  127. package/build/admin/src/utils/getApiUrl.d.ts +3 -0
  128. package/build/admin/src/utils/getApiUrl.js +6 -0
  129. package/build/admin/src/utils/getMessage.d.ts +4 -0
  130. package/build/admin/src/utils/getMessage.js +25 -0
  131. package/build/admin/src/utils/getRelatedGroups.d.ts +4 -0
  132. package/build/admin/src/utils/getRelatedGroups.js +6 -0
  133. package/build/admin/src/utils/getUrl.d.ts +3 -0
  134. package/build/admin/src/utils/getUrl.js +6 -0
  135. package/build/admin/src/utils/handleAPIError.d.ts +4 -0
  136. package/build/admin/src/utils/handleAPIError.js +20 -0
  137. package/build/admin/src/utils/index.d.ts +12 -0
  138. package/build/admin/src/utils/index.js +97 -0
  139. package/build/admin/src/utils/parseRegExp.d.ts +6 -0
  140. package/build/admin/src/utils/parseRegExp.js +11 -0
  141. package/build/admin/src/utils/renderEntryTitle.d.ts +4 -0
  142. package/build/admin/src/utils/renderEntryTitle.js +16 -0
  143. package/build/admin/src/utils/renderInitials.d.ts +3 -0
  144. package/build/admin/src/utils/renderInitials.js +11 -0
  145. package/build/admin/src/utils/resolveCommentStatus.d.ts +4 -0
  146. package/build/admin/src/utils/resolveCommentStatus.js +32 -0
  147. package/build/admin/src/utils/resolveCommentStatusColor.d.ts +4 -0
  148. package/build/admin/src/utils/resolveCommentStatusColor.js +22 -0
  149. package/build/content-types/comment.d.ts +91 -0
  150. package/build/content-types/comment.js +92 -0
  151. package/build/content-types/index.d.ts +143 -0
  152. package/build/content-types/index.js +18 -0
  153. package/build/content-types/report.d.ts +48 -0
  154. package/build/content-types/report.js +49 -0
  155. package/build/package.json +94 -0
  156. package/build/permissions.d.ts +18 -0
  157. package/build/permissions.js +18 -0
  158. package/build/server/bootstrap.d.ts +4 -0
  159. package/build/server/bootstrap.js +65 -0
  160. package/build/server/config/index.d.ts +4 -0
  161. package/build/server/config/index.js +19 -0
  162. package/build/server/controllers/admin.d.ts +4 -0
  163. package/build/server/controllers/admin.js +124 -0
  164. package/build/server/controllers/client.d.ts +4 -0
  165. package/build/server/controllers/client.js +111 -0
  166. package/build/server/controllers/index.d.ts +6 -0
  167. package/build/server/controllers/index.js +15 -0
  168. package/build/server/controllers/utils/functions.d.ts +7 -0
  169. package/build/server/controllers/utils/functions.js +24 -0
  170. package/build/server/controllers/utils/parsers.d.ts +15 -0
  171. package/build/server/controllers/utils/parsers.js +25 -0
  172. package/build/server/destroy.d.ts +3 -0
  173. package/build/server/destroy.js +3 -0
  174. package/build/server/graphql/index.d.ts +4 -0
  175. package/build/server/graphql/index.js +37 -0
  176. package/build/server/graphql/mutations/createAbuseReport.d.ts +11 -0
  177. package/build/server/graphql/mutations/createAbuseReport.js +27 -0
  178. package/build/server/graphql/mutations/createComment.d.ts +14 -0
  179. package/build/server/graphql/mutations/createComment.js +26 -0
  180. package/build/server/graphql/mutations/index.d.ts +4 -0
  181. package/build/server/graphql/mutations/index.js +28 -0
  182. package/build/server/graphql/mutations/removeComment.d.ts +11 -0
  183. package/build/server/graphql/mutations/removeComment.js +27 -0
  184. package/build/server/graphql/mutations/updateComment.d.ts +11 -0
  185. package/build/server/graphql/mutations/updateComment.js +27 -0
  186. package/build/server/graphql/queries/findAllFlat.d.ts +19 -0
  187. package/build/server/graphql/queries/findAllFlat.js +47 -0
  188. package/build/server/graphql/queries/findAllInHierarchy.d.ts +18 -0
  189. package/build/server/graphql/queries/findAllInHierarchy.js +38 -0
  190. package/build/server/graphql/queries/index.d.ts +4 -0
  191. package/build/server/graphql/queries/index.js +24 -0
  192. package/build/server/graphql/resolvers-config.d.ts +23 -0
  193. package/build/server/graphql/resolvers-config.js +13 -0
  194. package/build/server/graphql/types/comment-author.d.ts +4 -0
  195. package/build/server/graphql/types/comment-author.js +12 -0
  196. package/build/server/graphql/types/comment-nested.d.ts +4 -0
  197. package/build/server/graphql/types/comment-nested.js +19 -0
  198. package/build/server/graphql/types/comment.d.ts +4 -0
  199. package/build/server/graphql/types/comment.js +18 -0
  200. package/build/server/graphql/types/create-comment-author.d.ts +4 -0
  201. package/build/server/graphql/types/create-comment-author.js +12 -0
  202. package/build/server/graphql/types/create-comment.d.ts +4 -0
  203. package/build/server/graphql/types/create-comment.js +12 -0
  204. package/build/server/graphql/types/create-report.d.ts +4 -0
  205. package/build/server/graphql/types/create-report.js +12 -0
  206. package/build/server/graphql/types/id.d.ts +4 -0
  207. package/build/server/graphql/types/id.js +26 -0
  208. package/build/server/graphql/types/identify-comment-author.d.ts +4 -0
  209. package/build/server/graphql/types/identify-comment-author.js +9 -0
  210. package/build/server/graphql/types/index.d.ts +4 -0
  211. package/build/server/graphql/types/index.js +44 -0
  212. package/build/server/graphql/types/remove-comment.d.ts +4 -0
  213. package/build/server/graphql/types/remove-comment.js +11 -0
  214. package/build/server/graphql/types/report-reason.d.ts +4 -0
  215. package/build/server/graphql/types/report-reason.js +12 -0
  216. package/build/server/graphql/types/report.d.ts +4 -0
  217. package/build/server/graphql/types/report.js +14 -0
  218. package/build/server/graphql/types/response-find-all.d.ts +4 -0
  219. package/build/server/graphql/types/response-find-all.js +10 -0
  220. package/build/server/graphql/types/response-meta.d.ts +4 -0
  221. package/build/server/graphql/types/response-meta.js +9 -0
  222. package/build/server/graphql/types/response-pagination.d.ts +4 -0
  223. package/build/server/graphql/types/response-pagination.js +14 -0
  224. package/build/server/graphql/types/update-comment.d.ts +4 -0
  225. package/build/server/graphql/types/update-comment.js +12 -0
  226. package/build/server/index.d.ts +26 -0
  227. package/build/server/index.js +25 -0
  228. package/build/server/register.d.ts +3 -0
  229. package/build/server/register.js +3 -0
  230. package/build/server/routes/admin.d.ts +4 -0
  231. package/build/server/routes/admin.js +118 -0
  232. package/build/server/routes/client.d.ts +4 -0
  233. package/build/server/routes/client.js +54 -0
  234. package/build/server/routes/index.d.ts +11 -0
  235. package/build/server/routes/index.js +21 -0
  236. package/build/server/services/admin.d.ts +5 -0
  237. package/build/server/services/admin.js +296 -0
  238. package/build/server/services/client.d.ts +5 -0
  239. package/build/server/services/client.js +247 -0
  240. package/build/server/services/common.d.ts +5 -0
  241. package/build/server/services/common.js +266 -0
  242. package/build/server/services/graphql.d.ts +5 -0
  243. package/build/server/services/graphql.js +136 -0
  244. package/build/server/services/index.d.ts +8 -0
  245. package/build/server/services/index.js +16 -0
  246. package/build/server/services/utils/functions.d.ts +13 -0
  247. package/build/server/services/utils/functions.js +141 -0
  248. package/build/server/utils/constants.d.ts +9 -0
  249. package/build/server/utils/constants.js +23 -0
  250. package/build/server/utils/error.d.ts +23 -0
  251. package/build/server/utils/error.js +29 -0
  252. package/build/server/utils/functions.d.ts +14 -0
  253. package/build/server/utils/functions.js +50 -0
  254. package/build/strapi-admin.d.ts +3 -0
  255. package/build/strapi-admin.js +10 -0
  256. package/build/strapi-server.d.ts +177 -0
  257. package/build/strapi-server.js +46 -0
  258. package/build/tsconfig.tsbuildinfo +1 -0
  259. package/build/types/contentTypes.d.ts +46 -0
  260. package/build/types/contentTypes.js +3 -0
  261. package/package.json +3 -3
@@ -0,0 +1,818 @@
1
+ <div align="center" width="150px">
2
+ <img style="width: 150px; height: auto;" src="public/assets/logo.png" alt="Logo - Strapi Comments plugin" />
3
+ </div>
4
+ <div align="center">
5
+ <h1>Strapi v4 - Comments plugin</h1>
6
+ <p>Powerful Strapi based comments moderation tool for you and your users</p>
7
+ <a href="https://www.npmjs.org/package/strapi-plugin-comments">
8
+ <img alt="GitHub package.json version" src="https://img.shields.io/github/package-json/v/VirtusLab-Open-Source/strapi-plugin-comments?label=npm&logo=npm">
9
+ </a>
10
+ <a href="https://www.npmjs.org/package/strapi-plugin-comments">
11
+ <img src="https://img.shields.io/npm/dm/strapi-plugin-comments.svg" alt="Monthly download on NPM" />
12
+ </a>
13
+ <a href="https://circleci.com/gh/VirtusLab-Open-Source/strapi-plugin-comments">
14
+ <img src="https://circleci.com/gh/VirtusLab-Open-Source/strapi-plugin-comments.svg?style=shield" alt="CircleCI" />
15
+ </a>
16
+ <a href="https://codecov.io/gh/VirtusLab-Open-Source/strapi-plugin-comments">
17
+ <img src="https://codecov.io/gh/VirtusLab-Open-Source/strapi-plugin-comments/coverage.svg?branch=master" alt="codecov.io" />
18
+ </a>
19
+ <a href="https://sharing.clickup.com/tl/xhcmx-83/strapiv-4-comments-roadmap">
20
+ <img src="https://img.shields.io/website?down_message=roadmap&label=product&up_message=roadmap&url=https%3A%2F%2Fsharing.clickup.com%2Ftl%2Fxhcmx-83%2Fstrapiv-4-comments-roadmap" />
21
+ </a>
22
+ <a href="https://sharing.clickup.com/b/xhcmx-63/strapiv-4-comments-board">
23
+ <img src="https://img.shields.io/website?down_message=board&label=product&up_color=blue&up_message=board&url=https%3A%2F%2Fsharing.clickup.com%2Fb%2Fxhcmx-63%2Fstrapiv-4-comments-board" />
24
+ </a>
25
+ </div>
26
+
27
+ ---
28
+
29
+ <div style="margin: 20px 0" align="center">
30
+ <img style="width: 100%; height: auto;" src="public/assets/preview.png" alt="UI preview" />
31
+ </div>
32
+
33
+ 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 much more.
34
+
35
+ ## ✨ Features
36
+
37
+ - **Comments Public REST + GraphQL API:** Elegant, entirely customizable and a fully extensible admin panel.
38
+ - **Strapi &amp; generic users:** Support for built-in &amp; also generic non-Strapi users that might be the comments authors.
39
+ - **Any Content Type relation:** Comments can be linked to any of your Content Types by default. Simply, you're controlling it.
40
+ - **Moderation Panel:** Search & Filter through the bucket with your auditory comments. Manage them by blocking single ones or full threads. All in combined list &amp; hierarchical tree view of threads.
41
+ - **Automated Bad Words filtering:** By default end users are not allowed to post abusing comments where bad words have been used.
42
+ - **Abuse Reporting & Reviewing:** Don't allow inferior language, react to reports from your community, send email notifications about issued reports
43
+
44
+ ## ⚙️ Versions
45
+
46
+ - **Strapi v4** - (current) - [v2.x](https://github.com/VirtusLab-Open-Source/strapi-plugin-comments)
47
+ - **Strapi v3** - [v1.x](https://github.com/VirtusLab-Open-Source/strapi-plugin-comments/tree/strapi-v3)
48
+
49
+ ## ⏳ Installation
50
+
51
+ (Use **yarn** to install this plugin within your Strapi project (recommended). [Install yarn with these docs](https://yarnpkg.com/lang/en/docs/install/).)
52
+
53
+ ```bash
54
+ yarn add strapi-plugin-comments@latest
55
+ ```
56
+
57
+ After successful installation you've to build a fresh package that includes plugin UI. To archive that simply use:
58
+
59
+ ```bash
60
+ yarn build
61
+ yarn develop
62
+ ```
63
+
64
+ or just run Strapi in the development mode with `--watch-admin` option:
65
+
66
+ ```bash
67
+ yarn develop --watch-admin
68
+ ```
69
+
70
+ The **Comments** plugin should appear in the **Plugins** section of Strapi sidebar after you run app again.
71
+
72
+ Enjoy 🎉
73
+
74
+ ### Working in development mode
75
+
76
+ 1. Clone repository
77
+
78
+ ```
79
+ git clone git@github.com:VirtusLab-Open-Source/strapi-plugin-comments.git
80
+ ```
81
+
82
+ 2. Create a soft link in your strapi project to plugin build folder
83
+
84
+ ```sh
85
+ ln -s <your path>/strapi-plugin-comments/build <your path>/strapi-project/src/plugins/comments
86
+ ```
87
+
88
+ 3. Run develop or build command
89
+
90
+ ```ts
91
+ // Watch for file changes
92
+ yarn develop
93
+ // or run build without nodemon
94
+ yarn build:dev
95
+ ```
96
+
97
+ ## 🖐 Requirements
98
+
99
+ 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).
100
+
101
+ **Minimum environment requirements**
102
+
103
+ - Node.js `>=14.x.x`
104
+ - NPM `>=7.x.x`
105
+
106
+ In our minimum support we're following [official Node.js releases timelines](https://nodejs.org/en/about/releases/).
107
+
108
+ **Supported Strapi versions**:
109
+
110
+ - Strapi v4.1.2 (recently tested)
111
+ - Strapi v4.x
112
+
113
+ > 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).
114
+
115
+ **We recommend always using the latest version of Strapi to start your new projects**.
116
+
117
+ ## 🔧 Configuration
118
+
119
+ ### In `v2.0.3` and newest
120
+
121
+ 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.
122
+
123
+ > _Note_
124
+ > 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.
125
+
126
+ ### In `v2.0.2` and older + default configuration state for `v2.0.3` and newest
127
+
128
+ 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.
129
+
130
+ ```js
131
+ module.exports = ({ env }) => ({
132
+ //...
133
+ comments: {
134
+ enabled: true,
135
+ config: {
136
+ badWords: false,
137
+ moderatorRoles: ["Authenticated"],
138
+ approvalFlow: ["api::page.page"],
139
+ entryLabel: {
140
+ "*": ["Title", "title", "Name", "name", "Subject", "subject"],
141
+ "api::page.page": ["MyField"],
142
+ },
143
+ reportReasons: {
144
+ MY_CUSTOM_REASON: "MY_CUSTOM_REASON",
145
+ },
146
+ gql: {
147
+ // ...
148
+ },
149
+ },
150
+ },
151
+ //...
152
+ });
153
+ ```
154
+
155
+ ### Properties
156
+
157
+ - `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`.
158
+ - `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.
159
+ - `approvalFlow` - list of Content Types which are supporting approval flow. Values must be in format like `'api::<collection name>.<content type name>'`. For not included, posted comments are going to be immediately visible.
160
+ - `entryLabel` - ordered list of property names per Content Type to generate related entity label. Keys must be in format like `'api::<collection name>.<content type name>'`. Default formatting set as `*`.
161
+ - `reportReasons` - set of enums you would like to use for issuing abuse reports. Provided by default `'BAD_LANGUAGE'`, `'DISCRIMINATION'` and `'OTHER'`.
162
+ - `gql` - specific configuration for GraphQL. See [Additional GQL Configuration](#additional-gql-configuration)
163
+
164
+ ## Additional GQL Configuration
165
+
166
+ 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).
167
+
168
+ > **Important!**
169
+ > 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.
170
+
171
+ ```json
172
+ {
173
+ // ...
174
+ "gql": {
175
+ "auth": true // Default: false
176
+ }
177
+ // ...
178
+ }
179
+ ```
180
+
181
+ ### Properties
182
+
183
+ - `auth` - does GraphQL Queries should be authenticated or not? Default: `false`
184
+
185
+ ### Queries
186
+
187
+ See [available GQL specification section](#public-graphql-specification).
188
+
189
+ > If `auth` is set to `true` you must provide relevant authentication headers to all requests like for example:
190
+ >
191
+ > ```json
192
+ > {
193
+ > "Authorization": "Bearer <your token here>"
194
+ > }
195
+ > ```
196
+
197
+ ## 👤 RBAC
198
+
199
+ Plugin provides granular permissions based on Strapi RBAC functionality.
200
+
201
+ ### Mandatory permissions
202
+
203
+ For any role different than **Super Admin**, to access the **Comments panel** you must set following permissions:
204
+
205
+ - _Plugins_ -> _Content-type-builder_ -> _Read_ - gives you ability to fetch Content Type schema
206
+ - _Plugins_ -> _Comments_ -> _Comments: Read_ - gives you the basic read access to **Comments Panel**
207
+
208
+ ### Optional permissions
209
+
210
+ Feature / Capability focused permissions:
211
+
212
+ - _Plugins_ -> _Comments_ -> _Comments: Moderate_ - allows you to block, unblock, approve &amp; reject comments
213
+ - _Plugins_ -> _Comments_ -> _Reports: Read_ - allows you to see the list of issued abuse reports against comments
214
+ - _Plugins_ -> _Comments_ -> _Reports: Moderate_ - allows you to review (resolve) issued abuse reports against comments
215
+
216
+ ## Base Comment model
217
+
218
+ ```json
219
+ {
220
+ "id": 1,
221
+ "content": "My comment content",
222
+ "blocked": null,
223
+ "blockedThread": true,
224
+ "blockReason": null,
225
+ "authorUser": null,
226
+ "removed": null,
227
+ "approvalStatus": "APPROVED", // Only in case of enabled approval flow. Default: null
228
+ "author": {
229
+ "id": "207ccfdc-94ba-45eb-979c-790f6f49c392", // For Strapi users id reflects to the format used by your Strapi
230
+ "name": "Joe Doe", // For Strapi users it is equal to 'username' field
231
+ "email": "jdoe@sample.com",
232
+ "avatar": null
233
+ },
234
+ "createdAt": "2020-07-14T20:13:01.649Z",
235
+ "updatedAt": "2020-07-14T20:13:01.670Z",
236
+ "related": {}, // Related content type entity
237
+ "reports": [] // Reports issued against this comment
238
+ }
239
+ ```
240
+
241
+ ## 🕸️ Public REST API specification
242
+
243
+ **Strapi Users vs. Generic authors**
244
+
245
+ > Keep in mind that if you're using auth / authz your requests to setup proper user contexts it has got higher priority in order to take author data comparing to `author` property provided as part of your payload.
246
+
247
+ ### Get Comments
248
+
249
+ _GraphQL equivalent: [Public GraphQL API -> Get Comments](#get-comments-1)_
250
+
251
+ `GET <host>/api/comments/api::<collection name>.<content type name>:<entity id>`
252
+
253
+ Return a hierarchical tree structure of comments for specified instance of Content Type like for example `Page` with `ID: 1`.
254
+
255
+ **Example URL**: `https://localhost:1337/api/comments/api::page.page:1`
256
+
257
+ **Example response body**
258
+
259
+ ```json
260
+ [
261
+ {
262
+ // -- Comment Model fields ---,
263
+ "children": [
264
+ {
265
+ // -- Comment Model fields ---,
266
+ "children": [
267
+ // ...
268
+ ]
269
+ }
270
+ // ...
271
+ ]
272
+ }
273
+ // ...
274
+ ]
275
+ ```
276
+
277
+ #### Strapi REST API properties support:
278
+
279
+ - [sorting](https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/rest/sort-pagination.html#sorting)
280
+
281
+ ### Get Comments (flat structure)
282
+
283
+ _GraphQL equivalent: [Public GraphQL API -> Get Comments (flat structure)](#get-comments-flat-structure-1)_
284
+
285
+ `GET <host>/api/comments/api::<collection name>.<content type name>:<entity id>/flat`
286
+
287
+ Return a flat structure of comments for specified instance of Content Type like for example `Page` with `ID: 1`
288
+
289
+ **Example URL**: `https://localhost:1337/api/comments/api::page.page:1/flat`
290
+
291
+ **Example response body**
292
+
293
+ ```json
294
+ {
295
+ "data": [
296
+ {
297
+ // -- Comment Model fields ---
298
+ },
299
+ {
300
+ // -- Comment Model fields ---
301
+ }
302
+ // ...
303
+ ],
304
+ "meta": {
305
+ "pagination": {
306
+ // payload based on Strapi REST Pagination specification
307
+ }
308
+ }
309
+ }
310
+ ```
311
+
312
+ **Possible response codes**
313
+
314
+ - `200` - Successful. Response with list of comments (can be empty)
315
+ - `400` - Bad Request. Requested list for not valid / not existing Content Type
316
+
317
+ #### Strapi REST API properties support:
318
+
319
+ - [filtering](https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/rest/filtering-locale-publication.html#filtering)
320
+ - [sorting](https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/rest/sort-pagination.html#sorting)
321
+ - [pagination](https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/rest/sort-pagination.html#pagination)
322
+
323
+ ### Post a Comment
324
+
325
+ _GraphQL equivalent: [Public GraphQL API -> Post a Comments](#post-a-comment-1)_
326
+
327
+ `POST <host>/api/comments/api::<collection name>.<content type name>:<entity id>`
328
+
329
+ Posts a Comment related to specified instance of Content Type like for example `Page` with `ID: 1`
330
+
331
+ **Example URL**: `https://localhost:1337/api/comments/api::page.page:1`
332
+
333
+ **Example request body**
334
+
335
+ _Generic (non Strapi User)_
336
+
337
+ ```json
338
+ {
339
+ "author": {
340
+ "id": "<any ID like value>",
341
+ "name": "Joe Doe",
342
+ "email": "jdoe@sample.com",
343
+ "avatar": "<any image url>"
344
+ },
345
+ "content": "My sample response",
346
+ "threadOf": 2 // id of comment we would like to start / continue the thread (Optional)
347
+ }
348
+ ```
349
+
350
+ _Strapi user_
351
+
352
+ > Author is taken directly from the request context
353
+
354
+ ```json
355
+ {
356
+ "content": "My sample response",
357
+ "threadOf": 2 // id of comment we would like to start / continue the thread (Optional)
358
+ }
359
+ ```
360
+
361
+ **Example response body**
362
+
363
+ ```json
364
+ {
365
+ // -- Comment Model fields ---
366
+ }
367
+ ```
368
+
369
+ **Possible response codes**
370
+
371
+ - `200` - Successful. Response with created Comment Model
372
+ - `400` - Bad Request. Missing field values or bad words check fails. Error message will provide relevant reason.
373
+
374
+ ### Update Comment
375
+
376
+ _GraphQL equivalent: [Public GraphQL API -> Update Comments](#update-comment-1)_
377
+
378
+ `PUT <host>/api/comments/api::<collection name>.<content type name>:<entity id>/comment/<commentId>`
379
+
380
+ Updates a specified Comment content based on it `commentId` and related to specified instance of Content Type like for example `Page` with `ID: 1`
381
+
382
+ **Example URL**: `https://localhost:1337/api/comments/api::page.page:1/comment/2`
383
+
384
+ **Example request body**
385
+
386
+ _Generic (non Strapi User)_
387
+
388
+ ```json
389
+ {
390
+ "author": {
391
+ "id": "<any ID like value>"
392
+ },
393
+ "content": "My sample response"
394
+ }
395
+ ```
396
+
397
+ _Strapi user_
398
+
399
+ > Author is taken directly from the request context
400
+
401
+ ```json
402
+ {
403
+ "content": "My sample response"
404
+ }
405
+ ```
406
+
407
+ **Example response body**
408
+
409
+ ```json
410
+ {
411
+ // -- Comment Model fields ---
412
+ }
413
+ ```
414
+
415
+ **Possible response codes**
416
+
417
+ - `200` - Successful. Response with updated Comment Model
418
+ - `400` - Bad Request. Missing field values or bad words check fails. Error message will provide relevant reason.
419
+ - `409` - Conflict. Occurs when trying to update a non existing or not own comment. Possible cause might be that `authorId` or `authorUser` mismatch with existing comment.
420
+
421
+ ### Delete Comment
422
+
423
+ _GraphQL equivalent: [Public GraphQL API -> Delete Comment](#delete-comment-1)_
424
+
425
+ `DELETE <host>/api/comments/api::<collection name>.<content type name>:<entity id>/comment/<commentId>?authorId=<authorId>`
426
+
427
+ Deletes a specified Comment based on it `commentId` and related to specified instance of Content Type like for example `Page` with `ID: 1`.
428
+
429
+ **Example URL**: `https://localhost:1337/api/comments/api::page.page:1/comment/1?authorId=1`
430
+
431
+ **Example response body**
432
+
433
+ ```json
434
+ {
435
+ // -- Empty Response ---
436
+ }
437
+ ```
438
+
439
+ **Possible response codes**
440
+
441
+ - `200` - Successful with blank Response.
442
+ - `409` - Conflict. Occurs when trying to delete a non existing comment.
443
+
444
+ ### Issue Abuse Report against specified Comment
445
+
446
+ _GraphQL equivalent: [Public GraphQL API -> Issue Abuse Report against specified Comment](#issue-abuse-report-against-specified-comment-1)_
447
+
448
+ `POST <host>/api/comments/api::<collection name>.<content type name>:<entity id>/comment/<commentId>/report-abuse`
449
+
450
+ 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.
451
+
452
+ **Example URL**: `https://localhost:1337/api/comments/api::page.page:1/comment/2/report-abuse`
453
+
454
+ **Example request body**
455
+
456
+ ```json
457
+ {
458
+ "reason": "<reason enum>",
459
+ "content": "This comment is not relevant"
460
+ }
461
+ ```
462
+
463
+ _Available reason enums:_ `BAD_WORDS`, `OTHER`, `DISCRIMINATION` (want more? See [configuration section](#configuration).)
464
+
465
+ **Example response body**
466
+
467
+ ```json
468
+ {
469
+ // -- Comment Abuse Report fields ---
470
+ }
471
+ ```
472
+
473
+ **Possible response codes**
474
+
475
+ - `200` - Successful. Response with reported abuse.
476
+ - `409` - Conflict. Occurs when trying to report an abuse to a non existing comment.
477
+
478
+ ## 🕸️ Public GraphQL specification
479
+
480
+ **Strapi Users vs. Generic authors**
481
+
482
+ > Keep in mind that if you're using auth / authz your requests to setup proper user contexts it has got higher priority in order to take author data comparing to `author` property provided as part of your payload.
483
+
484
+ **Testing**
485
+
486
+ > To test all queries and understand the schemas use GraphQL Playground exposed by `@strapi/plugin-graphql` on `http://localhost:1337/graphql`
487
+
488
+ ### Get Comments
489
+
490
+ _REST API equivalent: [Public REST API -> Get Comments](#get-comments)_
491
+
492
+ **Example request**
493
+
494
+ ```graphql
495
+ query {
496
+ findAllFlat(
497
+ relation: "api::page.page:1"
498
+ filters: { content: { contains: "Test" } }
499
+ ) {
500
+ id
501
+ content
502
+ blocked
503
+ threadOf {
504
+ id
505
+ }
506
+ author {
507
+ id
508
+ name
509
+ }
510
+ }
511
+ }
512
+ ```
513
+
514
+ **Example response**
515
+
516
+ ```json
517
+ {
518
+ "data": {
519
+ "findAllFlat": [
520
+ {
521
+ "id": 3,
522
+ "content": "Test",
523
+ "blocked": false,
524
+ "threadOf": null,
525
+ "author": {
526
+ "id": "123456",
527
+ "name": "Joe Doe"
528
+ }
529
+ },
530
+ // ...
531
+ ]
532
+ }
533
+ ```
534
+
535
+ #### Strapi GraphQL API properties support:
536
+
537
+ - [sorting](https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/graphql-api.html#sorting)
538
+
539
+ ### Get Comments (flat structure)
540
+
541
+ _REST API equivalent: [Public REST API -> Get Comments (flat structure)](#get-comments-flat-structure)_
542
+
543
+ **Example request**
544
+
545
+ ```graphql
546
+ query {
547
+ findAllInHierarchy(relation: "api::page.page:1") {
548
+ id
549
+ content
550
+ blocked
551
+ children {
552
+ id
553
+ content
554
+ }
555
+ threadOf {
556
+ id
557
+ }
558
+ author {
559
+ id
560
+ name
561
+ }
562
+ }
563
+ }
564
+ ```
565
+
566
+ **Example response**
567
+
568
+ ```json
569
+ {
570
+ "data": {
571
+ "findAllInHierarchy": [
572
+ {
573
+ "id": 1,
574
+ "content": "Test",
575
+ "blocked": false,
576
+ "children": [
577
+ {
578
+ "id": 6,
579
+ "content": "Text to search for"
580
+ }
581
+ // ...
582
+ ],
583
+ "threadOf": null,
584
+ "author": {
585
+ "id": "123456",
586
+ "name": "Joe Doe"
587
+ }
588
+ }
589
+ // ...
590
+ ]
591
+ }
592
+ }
593
+ ```
594
+
595
+ #### Strapi GraphQL API properties support:
596
+
597
+ - [filtering](https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/graphql-api.html#filters)
598
+ - [sorting](https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/graphql-api.html#sorting)
599
+ - [pagination](https://docs.strapi.io/developer-docs/latest/developer-resources/database-apis-reference/graphql-api.html#pagination)
600
+
601
+ ### Post a Comment
602
+
603
+ _REST API equivalent: [Public REST API -> Post a Comment](#post-a-comment)_
604
+
605
+ **Example request**
606
+
607
+ ```graphql
608
+ mutation createComment {
609
+ createComment(
610
+ input: {
611
+ relation: "api::page.page:1"
612
+ content: "Hello World!"
613
+ threadOf: 3
614
+ author: { id: "12345678", name: "John Wick", email: "test@test.pl" } # Optional if using auth / authz requests
615
+ }
616
+ ) {
617
+ id
618
+ content
619
+ threadOf {
620
+ id
621
+ }
622
+ author {
623
+ id
624
+ name
625
+ }
626
+ }
627
+ }
628
+ ```
629
+
630
+ **Example response**
631
+
632
+ ```json
633
+ {
634
+ "data": {
635
+ "createComment": {
636
+ "id": 34,
637
+ "content": "Hello World!",
638
+ "threadOf": {
639
+ "id": 3
640
+ },
641
+ "author": {
642
+ "id": "12345678",
643
+ "name": "John Wick"
644
+ }
645
+ }
646
+ }
647
+ }
648
+ ```
649
+
650
+ ### Update Comment
651
+
652
+ _REST API equivalent: [Public REST API -> Update Comment](#update-comment)_
653
+
654
+ **Example request**
655
+
656
+ ```graphql
657
+ mutation updateComment {
658
+ updateComment(
659
+ input: {
660
+ id: 34
661
+ relation: "api::page.page:1"
662
+ content: "I've changed it!"
663
+ author: { id: "12345678" } # Optional if using auth / authz requests
664
+ }
665
+ ) {
666
+ id
667
+ content
668
+ threadOf {
669
+ id
670
+ }
671
+ author {
672
+ id
673
+ name
674
+ }
675
+ createdAt
676
+ updatedAt
677
+ }
678
+ }
679
+ ```
680
+
681
+ **Example response**
682
+
683
+ ```json
684
+ {
685
+ "data": {
686
+ "updateComment": {
687
+ "id": 34,
688
+ "content": "I've changed it!",
689
+ "threadOf": {
690
+ "id": 3
691
+ },
692
+ "author": {
693
+ "id": "12345678",
694
+ "name": "John Wick"
695
+ },
696
+ "createdAt": "2022-01-26T07:45:35.978Z",
697
+ "updatedAt": "2022-01-26T07:47:44.659Z"
698
+ }
699
+ }
700
+ }
701
+ ```
702
+
703
+ ### Delete Comment
704
+
705
+ _REST API equivalent: [Public REST API -> Delete Comment](#delete-comment)_
706
+
707
+ **Example request**
708
+
709
+ ```graphql
710
+ mutation removeComment {
711
+ removeComment(
712
+ input: {
713
+ id: 33
714
+ relation: "api::page.page:1"
715
+ author: { id: "12345678" } # Optional if using auth / authz requests
716
+ }
717
+ ) {
718
+ id
719
+ removed
720
+ }
721
+ }
722
+ ```
723
+
724
+ **Example response**
725
+
726
+ ```json
727
+ {
728
+ "data": {
729
+ "removeComment": {
730
+ "id": 33,
731
+ "removed": true
732
+ }
733
+ }
734
+ }
735
+ ```
736
+
737
+ ### Issue Abuse Report against specified Comment
738
+
739
+ _REST API equivalent: [Public REST API -> Issue Abuse Report against specified Comment](#issue-abuse-report-against-specified-comment)_
740
+
741
+ **Example request body**
742
+
743
+ ```graphql
744
+ mutation createAbuseReport {
745
+ createAbuseReport(
746
+ input: {
747
+ commentId: 34
748
+ relation: "api::page.page:1"
749
+ reason: BAD_LANGUAGE
750
+ content: "Rude language"
751
+ }
752
+ ) {
753
+ id
754
+ reason
755
+ content
756
+ related {
757
+ id
758
+ author {
759
+ id
760
+ name
761
+ }
762
+ }
763
+ }
764
+ }
765
+ ```
766
+
767
+ _Available reason enums:_ `BAD_WORDS`, `OTHER`, `DISCRIMINATION` (want more? See [configuration section](#configuration).)
768
+
769
+ **Example response**
770
+
771
+ ```json
772
+ {
773
+ "data": {
774
+ "createAbuseReport": {
775
+ "id": 28,
776
+ "content": "Rude language",
777
+ "reason": "DISCRIMINATION",
778
+ "related": {
779
+ "id": 34,
780
+ "author": {
781
+ "id": "12345678",
782
+ "name": "John Wick"
783
+ }
784
+ }
785
+ }
786
+ }
787
+ }
788
+ ```
789
+
790
+ ## 🧩 Examples
791
+
792
+ Live example of plugin usage can be found in the [VirtusLab Strapi Examples](https://github.com/VirtusLab/strapi-examples/tree/master/strapi-v4-plugin-comments) repository.
793
+
794
+ ## 🤝 Contributing
795
+
796
+ <div>
797
+ <a href="https://sharing.clickup.com/tl/xhcmx-83/strapiv-4-comments-roadmap">
798
+ <img src="https://img.shields.io/website?down_message=roadmap&label=product&up_message=roadmap&url=https%3A%2F%2Fsharing.clickup.com%2Ftl%2Fxhcmx-83%2Fstrapiv-4-comments-roadmap" />
799
+ </a>
800
+ <a href="https://sharing.clickup.com/b/xhcmx-63/strapiv-4-comments-board">
801
+ <img src="https://img.shields.io/website?down_message=board&label=product&up_color=blue&up_message=board&url=https%3A%2F%2Fsharing.clickup.com%2Fb%2Fxhcmx-63%2Fstrapiv-4-comments-board" />
802
+ </a>
803
+ </div>
804
+
805
+ Feel free to fork and make a Pull Request to this plugin project. All the input is warmly welcome!
806
+
807
+ ## 👨‍💻 Community support
808
+
809
+ For general help using Strapi, please refer to [the official Strapi documentation](https://strapi.io/documentation/). For additional help, you can use one of these channels to ask a question:
810
+
811
+ - [Discord](https://discord.strapi.io/) We're present on official Strapi Discord workspace. Find us by `[VirtusLab]` prefix and DM.
812
+ - [Slack - VirtusLab Open Source](https://virtuslab-oss.slack.com) We're present on a public channel #strapi-molecules
813
+ - [GitHub](https://github.com/VirtusLab-Open-Source/strapi-plugin-comments/issues) (Bug reports, Contributions, Questions and Discussions)
814
+ - [E-mail](mailto:strapi@virtuslab.com) - we will respond back as soon as possible
815
+
816
+ ## 📝 License
817
+
818
+ [MIT License](LICENSE.md) Copyright (c) [VirtusLab Sp. z o.o.](https://virtuslab.com/) &amp; [Strapi Solutions](https://strapi.io/).