strapi-plugin-comments 2.0.0-beta.4 → 2.0.0-beta.5

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 (36) hide show
  1. package/README.md +10 -4
  2. package/admin/src/components/DiscussionThread/index.js +1 -0
  3. package/admin/src/components/DiscussionThreadItem/index.js +3 -3
  4. package/admin/src/components/DiscussionThreadItemActions/index.js +22 -38
  5. package/admin/src/components/DiscussionThreadItemActions/styles.js +0 -4
  6. package/admin/src/components/DiscussionThreadItemApprovalFlowActions/index.js +72 -0
  7. package/admin/src/components/DiscussionThreadItemApprovalFlowActions/styles.js +6 -0
  8. package/admin/src/components/DiscussionThreadItemWarnings/index.js +1 -1
  9. package/admin/src/components/Nav/index.js +5 -1
  10. package/admin/src/components/icons/review.js +2 -2
  11. package/admin/src/pages/Details/components/DetailsEntity/index.js +66 -0
  12. package/admin/src/pages/Details/components/DetailsFilters/index.js +36 -0
  13. package/admin/src/pages/Details/components/DetailsFilters/styles.js +8 -0
  14. package/admin/src/pages/Details/index.js +40 -13
  15. package/admin/src/pages/Discover/components/DiscoverTableRow/index.js +33 -39
  16. package/admin/src/pages/Discover/components/DiscoverTableRow/styles.js +8 -0
  17. package/admin/src/pages/Discover/index.js +6 -3
  18. package/admin/src/pages/{Details/utils → utils}/api.js +15 -3
  19. package/admin/src/translations/en.json +15 -4
  20. package/admin/src/utils/constants.js +3 -6
  21. package/admin/src/utils/getMessage.js +1 -1
  22. package/admin/src/utils/getRelatedGroups.js +1 -3
  23. package/admin/src/utils/index.js +3 -1
  24. package/admin/src/utils/renderEntryTitle.js +14 -0
  25. package/admin/src/utils/resolveCommentStatus.js +30 -0
  26. package/admin/src/utils/resolveCommentStatusColor.js +22 -0
  27. package/package.json +7 -3
  28. package/server/config/index.js +2 -1
  29. package/server/controllers/admin.js +3 -3
  30. package/server/controllers/client.js +1 -0
  31. package/server/services/admin.js +33 -7
  32. package/server/services/client.js +21 -13
  33. package/server/services/common.js +30 -65
  34. package/server/services/utils/functions.js +7 -14
  35. package/server/utils/constants.js +3 -3
  36. package/admin/src/components/EntityDetails/index.js +0 -53
@@ -2,7 +2,7 @@ import React, { useState } from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import { useIntl } from 'react-intl';
4
4
  import { useMutation, useQueryClient } from 'react-query';
5
- import { first, isEmpty, orderBy } from 'lodash';
5
+ import { isNil, isEmpty, orderBy } from 'lodash';
6
6
  import { Badge } from '@strapi/design-system/Badge';
7
7
  import { Box } from '@strapi/design-system/Box';
8
8
  import { Button } from '@strapi/design-system/Button';
@@ -13,15 +13,17 @@ import { Link } from '@strapi/design-system/Link';
13
13
  import { Stack } from '@strapi/design-system/Stack';
14
14
  import { Tr, Td } from '@strapi/design-system/Table';
15
15
  import { Typography } from '@strapi/design-system/Typography';
16
- import { Eye, Lock } from '@strapi/icons';
16
+ import { Eye } from '@strapi/icons';
17
17
  import { useNotification, useOverlayBlocker } from '@strapi/helper-plugin';
18
- import { getMessage, handleAPIError } from '../../../../utils';
19
- import { COMMENT_STATUS } from '../../../../utils/constants';
18
+ import { getMessage, getUrl, handleAPIError, resolveCommentStatus, resolveCommentStatusColor } from '../../../../utils';
20
19
  import ReportsReviewModal from '../../../../components/ReportsReviewModal';
21
20
  import ReportsReviewTable from '../../../../components/ReportsReviewTable';
22
- import { blockItem, blockItemThread, resolveReport } from '../../../Details/utils/api';
21
+ import { blockItem, blockItemThread, resolveReport } from '../../../utils/api';
23
22
  import pluginId from '../../../../pluginId';
24
23
  import { ReviewIcon, LockIcon } from '../../../../components/icons';
24
+ import { TableLink } from './styles';
25
+ import renderEntryTitle from '../../../../utils/renderEntryTitle';
26
+ import DiscussionThreadItemApprovalFlowActions from '../../../../components/DiscussionThreadItemApprovalFlowActions';
25
27
 
26
28
  const DiscoverTableRow = ({ config, item, onClick }) => {
27
29
 
@@ -94,54 +96,45 @@ const DiscoverTableRow = ({ config, item, onClick }) => {
94
96
  const handleClick = () => onClick();
95
97
  const handleBlockButtonsStateChange = disabled => setBlockButtonsDisabled(disabled);
96
98
 
97
- const renderStatus = ({ blocked, blockedThread }) => {
98
- let status = blocked || blockedThread ? COMMENT_STATUS.BLOCKED : COMMENT_STATUS.OPEN;
99
- if (reviewFlowEnabled) {
100
- status = COMMENT_STATUS.TO_REVIEW;
101
- }
102
- let color = 'secondary';
103
- switch (status) {
104
- case COMMENT_STATUS.OPEN:
105
- color = 'success';
106
- break;
107
- case COMMENT_STATUS.TO_REVIEW:
108
- color = 'warning';
109
- break;
110
- case COMMENT_STATUS.BLOCKED:
111
- color = 'danger';
112
- break;
113
- };
99
+ const renderStatus = (props) => {
100
+ const status = resolveCommentStatus({ ...props, reviewFlowEnabled });
101
+ const color = resolveCommentStatusColor(status);
102
+
114
103
  return (<Badge backgroundColor={`${color}100`} textColor={`${color}600`}>{ getMessage({
115
- id: `page.discover.table.header.status.${status}`,
104
+ id: `page.common.item.status.${status}`,
116
105
  props: {
117
106
  count: openReports.length
118
107
  }
119
108
  }, status) }</Badge>);
120
109
  };
121
110
 
122
- const renderEntryTitle = entry => {
123
- const { entryLabel } = config;
124
- const rule = entry.uid in entryLabel ? entryLabel[entry.uid] : entryLabel['*'];
125
- return first(
126
- Object.keys(entry)
127
- .filter(_ => (rule === _) || rule.includes(_))
128
- .map(_ => entry[_])
129
- .filter(_ => _)
130
- );
131
- };
132
-
133
111
  const renderEntryUrl = entry => `/content-manager/collectionType/${entry.uid}/${entry.id}`;
112
+ const renderDetailsUrl = entry => getUrl(`discover/${entry.id}`);
113
+
114
+ const gotApprovalFlow = !isNil(item.approvalStatus);
115
+ const needsApproval = gotApprovalFlow && (item.approvalStatus === 'PENDING');
116
+
117
+ let actionItemsCount = 1;
118
+ if(reviewFlowEnabled || needsApproval) {
119
+ actionItemsCount = 2;
120
+ }
134
121
 
135
122
  return (
136
123
  <Tr key={item.id}>
137
- <Td style={{ maxWidth: '40vw' }}>
124
+ <Td>
125
+ <Typography textColor="neutral800" fontWeight="bold">#{ item.id }</Typography>
126
+ </Td>
127
+ <Td style={{ maxWidth: '30vw' }}>
138
128
  <Typography textColor="neutral800" ellipsis>{item.content}</Typography>
139
129
  </Td>
140
130
  <Td>
141
- <Typography textColor="neutral800">{item.threadOf?.id || '-'}</Typography>
131
+ { item.threadOf?.id ? (<Link to={ renderDetailsUrl(item.threadOf) }>{ getMessage({
132
+ id: 'page.discover.table.cell.thread',
133
+ props: { id: item.threadOf.id },
134
+ }, '#' + item.threadOf.id) }</Link>) : '-' }
142
135
  </Td>
143
- <Td>
144
- <Link to={ renderEntryUrl(item.related) }>{ renderEntryTitle(item.related) }</Link>
136
+ <Td style={{ maxWidth: '15vw' }}>
137
+ <TableLink to={ renderEntryUrl(item.related) }>{ renderEntryTitle(item.related, config) }</TableLink>
145
138
  </Td>
146
139
  <Td>
147
140
  <Typography textColor="neutral800">{ formatDate(item.updatedAt || item.createdAt, { dateStyle: 'long', timeStyle: 'short' }) }</Typography>
@@ -151,8 +144,9 @@ const DiscoverTableRow = ({ config, item, onClick }) => {
151
144
  </Td>
152
145
  <Td>
153
146
  <Flex direction="column" alignItems="flex-end">
154
- <Stack size={reviewFlowEnabled ? 2 : 1} horizontal>
147
+ <Stack size={actionItemsCount} horizontal>
155
148
  { reviewFlowEnabled && (<IconButton onClick={handleReportsReviewClick} label={ getMessage('page.discover.table.reports.review') } icon={<ReviewIcon />} />)}
149
+ { needsApproval && (<DiscussionThreadItemApprovalFlowActions id={item.id} queryToInvalidate="get-data" />)}
156
150
  <IconButton onClick={handleClick} label={ getMessage('page.discover.table.action.display') } icon={<Eye />} />
157
151
  </Stack>
158
152
  </Flex>
@@ -0,0 +1,8 @@
1
+ import styled from 'styled-components';
2
+ import { Link } from '@strapi/design-system/Link';
3
+
4
+ export const TableLink = styled(Link)`
5
+ display: block;
6
+ text-overflow: ellipsis;
7
+ overflow: hidden;
8
+ `
@@ -90,10 +90,10 @@ const Discover = ({ config }) => {
90
90
 
91
91
  const emptyContent = _q ? 'search' : 'comments';
92
92
 
93
- const COL_COUNT = 6;
93
+ const COL_COUNT = 7;
94
94
 
95
95
  return <Box background="neutral100">
96
- <Layout sideNav={<Nav />}>
96
+ <Layout>
97
97
  {isLoading || isLoadingForPermissions ? (<LoadingIndicatorPage />) : (
98
98
  <>
99
99
  <HeaderLayout title={ getMessage('page.discover.header') } subtitle={ `${total} ${ getMessage('page.discover.header.count')}` } as="h2" />
@@ -109,6 +109,9 @@ const Discover = ({ config }) => {
109
109
  <Table colCount={COL_COUNT} rowCount={result.length}>
110
110
  <Thead>
111
111
  <Tr>
112
+ <Th>
113
+ <Typography variant="sigma">{ getMessage('page.discover.table.header.id') }</Typography>
114
+ </Th>
112
115
  <Th>
113
116
  <Typography variant="sigma">{ getMessage('page.discover.table.header.message') }</Typography>
114
117
  </Th>
@@ -130,7 +133,7 @@ const Discover = ({ config }) => {
130
133
  </Tr>
131
134
  </Thead>
132
135
  <Tbody>
133
- {result.map(entry => (<DiscoverTableRow config={config} item={entry} onClick={() => handleClickDisplay(entry.id)}/>))}
136
+ {result.map(entry => (<DiscoverTableRow key={`comment-${entry.id}`} config={config} item={entry} onClick={() => handleClickDisplay(entry.id)}/>))}
134
137
  </Tbody>
135
138
  </Table>
136
139
  <TablePagination pagination={{ pageCount: pagination?.pageCount || 1 }} />
@@ -1,9 +1,13 @@
1
- import { getApiURL, axiosInstance, handleAPIError } from '../../../utils';
1
+ import { stringify } from 'qs';
2
+ import { isEmpty } from 'lodash';
3
+
4
+ import { getApiURL, axiosInstance, handleAPIError } from '../../utils';
2
5
 
3
6
  // eslint-disable-next-line import/prefer-default-export
4
- export const fetchDetailsData = async (id, toggleNotification) => {
7
+ export const fetchDetailsData = async (id, queryParams, toggleNotification) => {
5
8
  try {
6
- const { data } = await axiosInstance.get(getApiURL(`moderate/single/${id}`));
9
+ const stringifiedProps = !isEmpty(queryParams) ? `?${stringify(queryParams, { encode: false })}` : '';
10
+ const { data } = await axiosInstance.get(getApiURL(`moderate/single/${id}${stringifiedProps}`));
7
11
 
8
12
  return data;
9
13
  } catch (err) {
@@ -28,6 +32,14 @@ export const unblockItem = id => {
28
32
  return axiosInstance.patch(getApiURL(`moderate/single/${id}/unblock`));
29
33
  };
30
34
 
35
+ export const approveItem = id => {
36
+ return axiosInstance.patch(getApiURL(`moderate/single/${id}/approve`));
37
+ };
38
+
39
+ export const rejectItem = id => {
40
+ return axiosInstance.patch(getApiURL(`moderate/single/${id}/reject`));
41
+ };
42
+
31
43
  export const blockItemThread = id => {
32
44
  return axiosInstance.patch(getApiURL(`moderate/thread/${id}/block`));
33
45
  };
@@ -7,18 +7,23 @@
7
7
  "nav.item.discover": "Discover",
8
8
  "nav.item.reports": "Reports",
9
9
  "nav.item.settings": "Settings",
10
+ "page.common.item.status.OPEN": "OPEN",
11
+ "page.common.item.status.BLOCKED": "BLOCKED",
12
+ "page.common.item.status.APPROVED": "APPROVED",
13
+ "page.common.item.status.TO_REVIEW": "TO REVIEW ({count, number})",
14
+ "page.common.item.status.REJECTED": "REJECTED",
15
+ "page.common.item.status.REMOVED": "REMOVED BY AUTHOR",
10
16
  "page.updates.header": "Recent updates",
11
17
  "page.discover.header": "Discover threads",
12
18
  "page.discover.header.count": "entries found",
19
+ "page.discover.table.header.id": "ID",
13
20
  "page.discover.table.header.message": "Message",
14
21
  "page.discover.table.header.thread": "Thread of",
15
22
  "page.discover.table.header.entry": "Entry",
16
23
  "page.discover.table.header.lastUpdate": "Last update",
17
24
  "page.discover.table.header.status": "Status",
18
- "page.discover.table.header.status.OPEN": "OPEN",
19
- "page.discover.table.header.status.BLOCKED": "BLOCKED",
20
- "page.discover.table.header.status.TO_REVIEW": "TO REVIEW ({count, number})",
21
- "page.discover.table.header.actions": "Status",
25
+ "page.discover.table.header.actions": "Actions",
26
+ "page.discover.table.cell.thread": "Comment #{id}",
22
27
  "page.discover.table.action.display": "Display",
23
28
  "page.discover.table.action.reports": "Reports",
24
29
  "page.discover.table.empty": "You don't have any comments yet.",
@@ -52,6 +57,7 @@
52
57
  "page.details.panel.status.open": "OPEN",
53
58
  "page.details.panel.status.blocked": "BLOCKED",
54
59
  "page.details.panel.status.pending": "PENDING",
60
+ "page.details.panel.loading": "Fetching entity...",
55
61
  "page.details.actions.comment.block": "Block comment",
56
62
  "page.details.actions.comment.block.confirmation.header": "Moderation: Block comment",
57
63
  "page.details.actions.comment.block.confirmation.description": "Do you really want to block this comment?",
@@ -67,6 +73,11 @@
67
73
  "page.details.actions.thread.block.confirmation.success": "Thread has been blocked",
68
74
  "page.details.actions.thread.unblock": "Unblock thread",
69
75
  "page.details.actions.thread.unblock.confirmation.success": "Thread has been unblocked",
76
+ "page.details.actions.comment.approve.confirmation.success": "Comment has been approved",
77
+ "page.details.actions.comment.reject.confirmation.success": "Comment has been rejected",
78
+ "page.details.filters.label": "View",
79
+ "page.details.filters.removed.show": "Show removed",
80
+ "page.details.filters.removed.hide": "Hide removed",
70
81
  "page.coming.soon": "Wait for what is coming soon...",
71
82
  "compontents.confirmation.dialog.header": "Confirmation",
72
83
  "compontents.confirmation.dialog.description": "Do you really want to perform this action?",
@@ -16,13 +16,10 @@ export const REPORT_REASON = {
16
16
  };
17
17
 
18
18
  export const COMMENT_STATUS = {
19
+ 'UNKNOWN': 'UNKNOWN',
19
20
  'BLOCKED': 'BLOCKED',
20
21
  'OPEN': 'OPEN',
22
+ 'REMOVED': 'REMOVED',
21
23
  'TO_REVIEW': 'TO_REVIEW',
22
- };
23
-
24
- export const REGEX = {
25
- uid: new RegExp(/^(?<type>[a-z]+)\:{2}(?<api>[a-z]+)\.{1}(?<contentType>[a-z]+)$/gmi),
26
- relatedUid: new RegExp(/^(?<uid>[a-z]+\:{2}[a-z]+\.[a-z]+)\:{1}(?<id>[0-9]+)$/gmi),
27
- email: new RegExp(/\S+@\S+\.\S+/),
24
+ ...APPROVAL_STATUS,
28
25
  };
@@ -4,7 +4,7 @@ import { isString } from 'lodash';
4
4
 
5
5
  import pluginId from '../pluginId';
6
6
 
7
- const getMessage = (input, defaultMessage, inPluginScope = true) => {
7
+ const getMessage = (input, defaultMessage = '', inPluginScope = true) => {
8
8
  const { formatMessage } = useIntl();
9
9
  let formattedId = ''
10
10
  if (isString(input)) {
@@ -1,5 +1,3 @@
1
- import { REGEX } from "./constants";
2
-
3
- const getRelatedGroups = related => related.split(REGEX.relatedUid).filter(s => s && s.length > 0);
1
+ const getRelatedGroups = (related, config) => related.split(config.regex.relatedUid).filter(s => s && s.length > 0);
4
2
 
5
3
  export default getRelatedGroups;
@@ -3,4 +3,6 @@ export { default as getApiURL } from './getApiUrl';
3
3
  export { default as getUrl } from './getUrl';
4
4
  export { default as getMessage } from './getMessage';
5
5
  export { default as handleAPIError } from './handleAPIError';
6
- export { default as getRelatedGroups } from './getRelatedGroups';
6
+ export { default as getRelatedGroups } from './getRelatedGroups';
7
+ export { default as resolveCommentStatus } from './resolveCommentStatus';
8
+ export { default as resolveCommentStatusColor } from './resolveCommentStatusColor';
@@ -0,0 +1,14 @@
1
+ import { first } from 'lodash';
2
+
3
+ const renderEntryTitle = (entry, config = {}) => {
4
+ const { entryLabel } = config;
5
+ const rule = entry.uid in entryLabel ? entryLabel[entry.uid] : entryLabel['*'];
6
+ return first(
7
+ Object.keys(entry)
8
+ .filter(_ => (rule === _) || rule.includes(_))
9
+ .map(_ => entry[_])
10
+ .filter(_ => _)
11
+ );
12
+ };
13
+
14
+ export default renderEntryTitle;
@@ -0,0 +1,30 @@
1
+ import { isNil } from 'lodash';
2
+ import { COMMENT_STATUS } from './constants';
3
+
4
+ const resolveCommentStatus = ({ removed, blocked, blockedThread, approvalStatus, reviewFlowEnabled }) => {
5
+ const gotApprovalFlow = !isNil(approvalStatus);
6
+
7
+ if (reviewFlowEnabled) {
8
+ return COMMENT_STATUS.TO_REVIEW;
9
+ }
10
+
11
+ if (removed) {
12
+ return COMMENT_STATUS.REMOVED;
13
+ }
14
+
15
+ if (blocked || blockedThread) {
16
+ return COMMENT_STATUS.BLOCKED;
17
+ }
18
+
19
+ if (gotApprovalFlow) {
20
+ const status = approvalStatus.toUpperCase();
21
+ if (Object.keys(COMMENT_STATUS).includes(status)) {
22
+ return status;
23
+ }
24
+ return COMMENT_STATUS.UNKNOWN;
25
+ }
26
+
27
+ return COMMENT_STATUS.OPEN;
28
+ }
29
+
30
+ export default resolveCommentStatus;
@@ -0,0 +1,22 @@
1
+ import { isNil } from 'lodash';
2
+ import { COMMENT_STATUS } from './constants';
3
+
4
+ const resolveCommentStatusColor = (status) => {
5
+ if (Object.keys(COMMENT_STATUS).includes(status)) {
6
+ switch (status) {
7
+ case COMMENT_STATUS.REMOVED:
8
+ return 'secondary';
9
+ case COMMENT_STATUS.TO_REVIEW:
10
+ case COMMENT_STATUS.REJECTED:
11
+ return 'warning';
12
+ case COMMENT_STATUS.BLOCKED:
13
+ return 'danger';
14
+ case COMMENT_STATUS.OPEN:
15
+ case COMMENT_STATUS.APPROVED:
16
+ return 'success';
17
+ };
18
+ }
19
+ return 'secondary';
20
+ }
21
+
22
+ export default resolveCommentStatusColor;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "strapi-plugin-comments",
3
- "version": "2.0.0-beta.4",
3
+ "version": "2.0.0-beta.5",
4
4
  "description": "Strapi - Comments plugin",
5
5
  "strapi": {
6
6
  "name": "comments",
@@ -15,6 +15,7 @@
15
15
  "url": "https://github.com/VirtusLab-Open-Source/strapi-plugin-comments"
16
16
  },
17
17
  "dependencies": {
18
+ "@strapi/utils": "^4.0.5",
18
19
  "bad-words": "^3.0.4"
19
20
  },
20
21
  "devDependencies": {
@@ -23,6 +24,9 @@
23
24
  "jest-cli": "^26.0.1",
24
25
  "jest-styled-components": "^7.0.2"
25
26
  },
27
+ "peerDependencies": {
28
+ "@strapi/strapi": "4.x"
29
+ },
26
30
  "author": {
27
31
  "name": "VirtusLab // Mateusz Ziarko",
28
32
  "email": "mziarko@virtuslab.com",
@@ -41,8 +45,8 @@
41
45
  }
42
46
  ],
43
47
  "engines": {
44
- "node": ">=12.x. <=16.x.x",
45
- "npm": ">=6.0.0"
48
+ "node": ">=14.x.x <=17.x.x",
49
+ "npm": ">=7.x.x"
46
50
  },
47
51
  "keywords": ["strapi", "plugin", "comments"],
48
52
  "license": "MIT"
@@ -2,9 +2,10 @@
2
2
 
3
3
  module.exports = {
4
4
  default: {
5
+ approvalFlow: [],
5
6
  entryLabel: {
6
7
  '*': ['Title', 'title', 'Name', 'name', 'Subject', 'subject']
7
- }
8
+ },
8
9
  },
9
10
  validator() {},
10
11
  };
@@ -16,11 +16,11 @@ module.exports = {
16
16
  },
17
17
 
18
18
  async findOne(ctx) {
19
- const { params = {} } = ctx;
19
+ const { params = {}, query } = ctx;
20
20
  const { id } = parseParams(params);
21
21
  try {
22
22
  return await this.getService()
23
- .findOneAndThread(id);
23
+ .findOneAndThread(id, query);
24
24
  } catch (e) {
25
25
  throwError(ctx, e);
26
26
  }
@@ -101,7 +101,7 @@ module.exports = {
101
101
  }
102
102
  },
103
103
 
104
- async config() {
104
+ async config(ctx) {
105
105
  try {
106
106
  return await this.getService().config();
107
107
  } catch (e) {
@@ -18,6 +18,7 @@ module.exports = {
18
18
  .findAllFlat({
19
19
  query: {
20
20
  ...query,
21
+ $or: [{ removed: { $null: true } }, { removed: false }],
21
22
  related: relation,
22
23
  },
23
24
  populate: {
@@ -1,14 +1,12 @@
1
1
  'use strict';
2
2
 
3
3
  const { getPluginService, parseParams } = require('./../utils/functions');
4
- const { getAssociationModel } = require('./common');
5
- const { first, isEmpty, isNil, uniq, get } = require('lodash');
4
+ const { isEmpty, isNil } = require('lodash');
6
5
  const PluginError = require('./../utils/error');
7
6
  const {
8
7
  getModelUid,
9
8
  getRelatedGroups,
10
9
  filterOurResolvedReports,
11
- convertContentTypeNameToSlug
12
10
  } = require('./utils/functions');
13
11
  const { APPROVAL_STATUS, REGEX } = require('./../utils/constants')
14
12
 
@@ -25,8 +23,14 @@ const { APPROVAL_STATUS, REGEX } = require('./../utils/constants')
25
23
  // Config
26
24
  async config() {
27
25
  const entryLabel = this.getCommonService().getConfig('entryLabel');
26
+ const approvalFlow = this.getCommonService().getConfig('approvalFlow');
28
27
  return {
29
28
  entryLabel,
29
+ approvalFlow,
30
+ regex: Object.keys(REGEX).reduce((prev, curr) => ({
31
+ ...prev,
32
+ [curr]: REGEX[curr].toString(),
33
+ }), {}),
30
34
  };
31
35
  },
32
36
 
@@ -34,10 +38,18 @@ const { APPROVAL_STATUS, REGEX } = require('./../utils/constants')
34
38
  async findAll({ related, entity, ...query }) {
35
39
  const { _q, orderBy, pageSize = 10, page = 1, filters, ...rest } = parseParams(query);
36
40
 
41
+ const defaultWhere = {
42
+ $or: [
43
+ { removed: false },
44
+ { removed: null },
45
+ ],
46
+ };
47
+
37
48
  let params = {
38
49
  where: !isEmpty(filters) ? {
50
+ ...defaultWhere,
39
51
  ...filters,
40
- } : undefined,
52
+ } : { ...defaultWhere },
41
53
  offset: (page - 1)*pageSize,
42
54
  limit: pageSize,
43
55
  orderBy: orderBy || [{ createdAt: 'desc' }],
@@ -59,6 +71,7 @@ const { APPROVAL_STATUS, REGEX } = require('./../utils/constants')
59
71
  ...params,
60
72
  populate: {
61
73
  authorUser: true,
74
+ threadOf: true,
62
75
  reports: {
63
76
  where: {
64
77
  resolved: false
@@ -87,7 +100,14 @@ const { APPROVAL_STATUS, REGEX } = require('./../utils/constants')
87
100
  },
88
101
 
89
102
  // Find single comment
90
- async findOneAndThread(id) {
103
+ async findOneAndThread(id, { removed, ...query }) {
104
+ const defaultWhere = !removed ? {
105
+ $or: [
106
+ { removed: false },
107
+ { removed: null },
108
+ ],
109
+ } : {};
110
+
91
111
  const reportsPopulation = {
92
112
  reports: {
93
113
  where: {
@@ -98,7 +118,7 @@ const { APPROVAL_STATUS, REGEX } = require('./../utils/constants')
98
118
 
99
119
  const entity = await strapi.db.query(getModelUid('comment')).findOne({
100
120
  where: {
101
- id
121
+ id,
102
122
  },
103
123
  populate: {
104
124
  authorUser: true,
@@ -132,6 +152,8 @@ const { APPROVAL_STATUS, REGEX } = require('./../utils/constants')
132
152
  const entitiesOnSameLevel = await this.getCommonService()
133
153
  .findAllInHierarchy({
134
154
  query: {
155
+ ...defaultWhere,
156
+ ...query,
135
157
  threadOf: levelThreadId,
136
158
  related: entity.related,
137
159
  },
@@ -167,9 +189,13 @@ const { APPROVAL_STATUS, REGEX } = require('./../utils/constants')
167
189
  // Block / Unblock a comment thread
168
190
  async blockCommentThread(id, forceStatus) {
169
191
  const existingEntity = await this.getCommonService().findOne({ id });
192
+ const status = !isNil(forceStatus) ? forceStatus : !existingEntity.blockedThread;
170
193
  const changedEntity = await strapi.db.query(getModelUid('comment')).update({
171
194
  where: { id },
172
- data: { blockedThread: !isNil(forceStatus) ? forceStatus : !existingEntity.blockedThread }
195
+ data: {
196
+ blocked: status,
197
+ blockedThread: status,
198
+ },
173
199
  });
174
200
  await this.blockNestedThreads(id, changedEntity.blockedThread);
175
201
 
@@ -26,18 +26,14 @@ module.exports = ({ strapi }) => ({
26
26
 
27
27
  // Create a comment
28
28
  async create(relation, data, user = undefined) {
29
- const { content, threadOf, related } = data;
30
- const singleRelationFulfilled = related && REGEX.relatedUid.test(related);
31
-
32
- if (relation !== related) {
33
- throw new PluginError(400, `Insonsistent relation uid`);
34
- }
35
-
29
+ const { content, threadOf } = data;
30
+ const singleRelationFulfilled = relation && REGEX.relatedUid.test(relation);
31
+
36
32
  if(!singleRelationFulfilled) {
37
33
  throw new PluginError(400, `Field "related" got incorrect format, use format like "api::<collection name>.<content type name>:<entity id>"`);
38
34
  }
39
35
 
40
- const [ uid, relatedStringId ] = getRelatedGroups(related);
36
+ const [ uid, relatedStringId ] = getRelatedGroups(relation);
41
37
  const relatedId = parseInt(relatedStringId, 10);
42
38
 
43
39
  const relatedEntity = await strapi.db.query(uid).findOne(relatedId);
@@ -45,9 +41,12 @@ module.exports = ({ strapi }) => ({
45
41
  throw new PluginError(400, `Relation for field "related" does not exist. Check your payload please.`);
46
42
  }
47
43
 
44
+ const isApprovalFlowEnabled = this.getCommonService().getConfig('approvalFlow', []).includes(uid) ||
45
+ relatedEntity.requireCommentsApproval;
46
+
48
47
  const linkToThread = !isNil(threadOf) ? !!await this.getCommonService().findOne({
49
48
  id: threadOf,
50
- related,
49
+ related: relation,
51
50
  }) : true;
52
51
  const validContext = isValidUserContext(user);
53
52
 
@@ -87,7 +86,8 @@ module.exports = ({ strapi }) => ({
87
86
  throw new PluginError(400, 'Object: "author" is invalid. Check your payload');
88
87
  }
89
88
 
90
- if (relatedEntity.requireCommentsApproval && data.approvalStatus !== APPROVAL_STATUS.PENDING) {
89
+ if (isApprovalFlowEnabled &&
90
+ (!isNil(data.approvalStatus) && (data.approvalStatus !== APPROVAL_STATUS.PENDING))) {
91
91
  throw new PluginError(400, 'Invalid approval status');
92
92
  }
93
93
 
@@ -95,7 +95,8 @@ module.exports = ({ strapi }) => ({
95
95
  data: {
96
96
  ...rest,
97
97
  ...authorData,
98
- related,
98
+ related: relation,
99
+ approvalStatus: isApprovalFlowEnabled ? APPROVAL_STATUS.PENDING : null,
99
100
  }
100
101
  });
101
102
  return this.getCommonService().sanitizeCommentEntity(entity);
@@ -177,10 +178,17 @@ module.exports = ({ strapi }) => ({
177
178
  $or: [{ authorUser: authorId }, { authorId }],
178
179
  });
179
180
  if (!entity){
180
- throw strapi.errors.notFound('Entity not exist');
181
+ throw new PluginError(404, 'Entity not exist');
181
182
  }
183
+
182
184
  return strapi.db.query(getModelUid('comment'))
183
- .update({ id: commentId, relatedSlug: relationId }, { removed: true })
185
+ .update({
186
+ where: {
187
+ id: commentId,
188
+ related: relationId
189
+ },
190
+ data: { removed: true }
191
+ })
184
192
  .then(({ id }) => this.markAsRemovedNested(id, true))
185
193
  .then(() => ({ id: commentId }));
186
194
  },