strapi-plugin-comments 2.0.0-beta.5 → 2.0.0-rc.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +472 -118
- package/admin/src/components/DiscussionThread/index.js +9 -3
- package/admin/src/components/DiscussionThreadItem/index.js +24 -11
- package/admin/src/components/DiscussionThreadItemActions/index.js +45 -18
- package/admin/src/components/DiscussionThreadItemApprovalFlowActions/index.js +20 -11
- package/admin/src/components/DiscussionThreadItemMeta/index.js +16 -5
- package/admin/src/components/DiscussionThreadItemWarnings/index.js +15 -9
- package/admin/src/components/ReportsReviewModal/index.js +5 -0
- package/admin/src/components/ReportsReviewTable/index.js +60 -52
- package/admin/src/components/icons/review.js +1 -1
- package/admin/src/index.js +1 -1
- package/admin/src/pages/Details/components/DetailsEntity/index.js +2 -2
- package/admin/src/pages/Details/components/DetailsFilters/index.js +1 -0
- package/admin/src/pages/Details/index.js +43 -37
- package/admin/src/pages/Discover/components/DiscoverTableRow/index.js +38 -11
- package/admin/src/pages/Discover/index.js +72 -59
- package/admin/src/permissions.js +10 -8
- package/admin/src/translations/en.json +2 -0
- package/admin/src/utils/index.js +2 -0
- package/admin/src/utils/renderInitials.js +5 -0
- package/content-types/comment.js +0 -4
- package/package.json +4 -2
- package/permissions.js +19 -0
- package/public/assets/logo.png +0 -0
- package/public/assets/preview.png +0 -0
- package/server/bootstrap.js +38 -2
- package/server/config/index.js +7 -2
- package/server/controllers/client.js +11 -21
- package/server/controllers/utils/parsers.js +19 -0
- package/server/graphql/index.js +26 -0
- package/server/graphql/mutations/createAbuseReport.js +25 -0
- package/server/graphql/mutations/createComment.js +25 -0
- package/server/graphql/mutations/index.js +21 -0
- package/server/graphql/mutations/removeComment.js +25 -0
- package/server/graphql/mutations/updateComment.js +25 -0
- package/server/graphql/queries/findAllFlat.js +29 -0
- package/server/graphql/queries/findAllInHierarchy.js +31 -0
- package/server/graphql/queries/index.js +19 -0
- package/server/graphql/resolvers-config.js +15 -0
- package/server/graphql/types/comment-author.js +9 -0
- package/server/graphql/types/comment-nested.js +15 -0
- package/server/graphql/types/comment.js +15 -0
- package/server/graphql/types/create-comment-author.js +9 -0
- package/server/graphql/types/create-comment.js +9 -0
- package/server/graphql/types/create-report.js +9 -0
- package/server/graphql/types/id.js +24 -0
- package/server/graphql/types/identify-comment-author.js +6 -0
- package/server/graphql/types/index.js +16 -0
- package/server/graphql/types/remove-comment.js +8 -0
- package/server/graphql/types/report-reason.js +10 -0
- package/server/graphql/types/report.js +11 -0
- package/server/graphql/types/update-comment.js +9 -0
- package/server/register.js +3 -1
- package/server/services/admin.js +20 -16
- package/server/services/client.js +72 -49
- package/server/services/common.js +23 -12
- package/server/services/graphql.js +190 -0
- package/server/services/index.js +2 -0
- package/server/services/utils/functions.js +30 -11
- package/strapi-server.js +33 -0
|
@@ -50,13 +50,16 @@ const Details = ({ config }) => {
|
|
|
50
50
|
const trackUsageRef = useRef(trackUsage);
|
|
51
51
|
const toggleNotification = useNotification();
|
|
52
52
|
|
|
53
|
-
const viewPermissions = useMemo(() => {
|
|
54
|
-
|
|
55
|
-
|
|
53
|
+
const viewPermissions = useMemo(() => ({
|
|
54
|
+
access: pluginPermissions.access,
|
|
55
|
+
moderate: pluginPermissions.moderate,
|
|
56
|
+
accessReports: pluginPermissions.reports,
|
|
57
|
+
reviewReports: pluginPermissions.reportsReview,
|
|
58
|
+
}), []);
|
|
56
59
|
|
|
57
60
|
const {
|
|
58
61
|
isLoading: isLoadingForPermissions,
|
|
59
|
-
allowedActions: {
|
|
62
|
+
allowedActions: { canAccess, canModerate, canAccessReports, canReviewReports },
|
|
60
63
|
} = useRBAC(viewPermissions);
|
|
61
64
|
|
|
62
65
|
const [filters, setFilters] = useState({});
|
|
@@ -64,7 +67,7 @@ const Details = ({ config }) => {
|
|
|
64
67
|
const regexUID = new RegExp(config.regex.uid);
|
|
65
68
|
|
|
66
69
|
const { isLoading: isLoadingForData, data, isFetching } = useQuery(
|
|
67
|
-
['get-details-data', id, filters],
|
|
70
|
+
['get-details-data', id, filters, canAccess],
|
|
68
71
|
() => fetchDetailsData(id, filters, toggleNotification),
|
|
69
72
|
{
|
|
70
73
|
initialData: { },
|
|
@@ -75,7 +78,7 @@ const Details = ({ config }) => {
|
|
|
75
78
|
const entityUidValid = entity?.uid && regexUID.test(entity.uid);
|
|
76
79
|
|
|
77
80
|
const { data: contentTypeData } = useQuery(
|
|
78
|
-
['get-additional-data', entity?.uid],
|
|
81
|
+
['get-additional-data', entity?.uid, canAccess],
|
|
79
82
|
() => fetchContentTypeData(entity?.uid, toggleNotification),
|
|
80
83
|
{
|
|
81
84
|
enabled: !!entity?.uid,
|
|
@@ -87,37 +90,40 @@ const Details = ({ config }) => {
|
|
|
87
90
|
|
|
88
91
|
const isLoading = isLoadingForData || isFetching;
|
|
89
92
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
{
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
<
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
<
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
93
|
+
if (canAccess) {
|
|
94
|
+
return <Box background="neutral100">
|
|
95
|
+
<Layout>
|
|
96
|
+
{(isLoading || isLoadingForPermissions) && isEmpty(data) ? (<LoadingIndicatorPage />) : (
|
|
97
|
+
<>
|
|
98
|
+
<HeaderLayout
|
|
99
|
+
navigationAction={
|
|
100
|
+
<Link startIcon={<ArrowLeft />} to={getUrl(`discover`)}>
|
|
101
|
+
{ getMessage('HeaderLayout.link.go-back', 'Back', false) }
|
|
102
|
+
</Link>}
|
|
103
|
+
title={ getMessage('page.details.header') }
|
|
104
|
+
subtitle={ getMessage('page.details.header.description') }
|
|
105
|
+
primaryAction={<DetailsFilters data={filters} onChange={handleChangeFilters} />}
|
|
106
|
+
secondaryAction={<Box as={Flex}> </Box>}
|
|
107
|
+
as="h2" />
|
|
108
|
+
<ContentLayout>
|
|
109
|
+
<TwoColsLayout
|
|
110
|
+
startCol={<DiscussionThread level={level} selected={selected} isReloading={isLoading} allowedActions={{ canModerate, canAccessReports, canReviewReports }} />}
|
|
111
|
+
endCol={ <Stack size={2}>
|
|
112
|
+
<DiscussionStatus item={selected} />
|
|
113
|
+
{ !contentTypeData?.schema ? (<Box padding={4}>
|
|
114
|
+
<Loader small>{ getMessage('page.details.panel.loading', 'Loading...') }</Loader>
|
|
115
|
+
</Box>) :
|
|
116
|
+
(<DetailsEntity data={entity} schema={contentTypeData?.schema} config={config} />)
|
|
117
|
+
}
|
|
118
|
+
</Stack>
|
|
119
|
+
}
|
|
120
|
+
/>
|
|
121
|
+
</ContentLayout>
|
|
122
|
+
</>) }
|
|
123
|
+
</Layout>
|
|
124
|
+
</Box>;
|
|
125
|
+
}
|
|
126
|
+
return null;
|
|
121
127
|
}
|
|
122
128
|
|
|
123
129
|
const mapStateToProps = makeAppView();
|
|
@@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
|
|
|
3
3
|
import { useIntl } from 'react-intl';
|
|
4
4
|
import { useMutation, useQueryClient } from 'react-query';
|
|
5
5
|
import { isNil, isEmpty, orderBy } from 'lodash';
|
|
6
|
+
import { Avatar, Initials } from '@strapi/design-system/Avatar';
|
|
6
7
|
import { Badge } from '@strapi/design-system/Badge';
|
|
7
8
|
import { Box } from '@strapi/design-system/Box';
|
|
8
9
|
import { Button } from '@strapi/design-system/Button';
|
|
@@ -15,7 +16,7 @@ import { Tr, Td } from '@strapi/design-system/Table';
|
|
|
15
16
|
import { Typography } from '@strapi/design-system/Typography';
|
|
16
17
|
import { Eye } from '@strapi/icons';
|
|
17
18
|
import { useNotification, useOverlayBlocker } from '@strapi/helper-plugin';
|
|
18
|
-
import { getMessage, getUrl, handleAPIError, resolveCommentStatus, resolveCommentStatusColor } from '../../../../utils';
|
|
19
|
+
import { getMessage, getUrl, handleAPIError, renderInitials, resolveCommentStatus, resolveCommentStatusColor } from '../../../../utils';
|
|
19
20
|
import ReportsReviewModal from '../../../../components/ReportsReviewModal';
|
|
20
21
|
import ReportsReviewTable from '../../../../components/ReportsReviewTable';
|
|
21
22
|
import { blockItem, blockItemThread, resolveReport } from '../../../utils/api';
|
|
@@ -25,7 +26,7 @@ import { TableLink } from './styles';
|
|
|
25
26
|
import renderEntryTitle from '../../../../utils/renderEntryTitle';
|
|
26
27
|
import DiscussionThreadItemApprovalFlowActions from '../../../../components/DiscussionThreadItemApprovalFlowActions';
|
|
27
28
|
|
|
28
|
-
const DiscoverTableRow = ({ config, item, onClick }) => {
|
|
29
|
+
const DiscoverTableRow = ({ config, item, allowedActions: { canModerate, canAccessReports, canReviewReports }, onClick }) => {
|
|
29
30
|
|
|
30
31
|
const { id, reports } = item;
|
|
31
32
|
|
|
@@ -74,14 +75,22 @@ const DiscoverTableRow = ({ config, item, onClick }) => {
|
|
|
74
75
|
refetchActive: false,
|
|
75
76
|
});
|
|
76
77
|
|
|
77
|
-
const handleReportsReviewClick = () =>
|
|
78
|
+
const handleReportsReviewClick = () => {
|
|
79
|
+
if (canAccessReports) {
|
|
80
|
+
setReportsReviewVisible(true);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
78
83
|
const handleBlockItemClick = async () => {
|
|
79
|
-
|
|
80
|
-
|
|
84
|
+
if (canModerate) {
|
|
85
|
+
lockApp();
|
|
86
|
+
blockItemMutation.mutate(id);
|
|
87
|
+
}
|
|
81
88
|
};
|
|
82
89
|
const handleBlockItemThreadClick = async () => {
|
|
83
|
-
|
|
84
|
-
|
|
90
|
+
if (canModerate) {
|
|
91
|
+
lockApp();
|
|
92
|
+
blockItemThreadMutation.mutate(id);
|
|
93
|
+
}
|
|
85
94
|
};
|
|
86
95
|
const handleReportsReviewClose = async () => {
|
|
87
96
|
await queryClient.invalidateQueries('get-data');
|
|
@@ -91,7 +100,7 @@ const DiscoverTableRow = ({ config, item, onClick }) => {
|
|
|
91
100
|
const isLoading = blockItemMutation.isLoading || blockItemThreadMutation.isLoading || resolveReportMutation.isLoading;
|
|
92
101
|
const openReports = reports?.filter(_ => !_.resolved);
|
|
93
102
|
const hasReports = !isEmpty(openReports);
|
|
94
|
-
const reviewFlowEnabled = hasReports && !(item.blocked || item.blockedThread);
|
|
103
|
+
const reviewFlowEnabled = (canAccessReports && hasReports) && !(item.blocked || item.blockedThread);
|
|
95
104
|
|
|
96
105
|
const handleClick = () => onClick();
|
|
97
106
|
const handleBlockButtonsStateChange = disabled => setBlockButtonsDisabled(disabled);
|
|
@@ -124,6 +133,12 @@ const DiscoverTableRow = ({ config, item, onClick }) => {
|
|
|
124
133
|
<Td>
|
|
125
134
|
<Typography textColor="neutral800" fontWeight="bold">#{ item.id }</Typography>
|
|
126
135
|
</Td>
|
|
136
|
+
<Td>
|
|
137
|
+
<Stack size={2} horizontal>
|
|
138
|
+
{ item.author?.avatar ? <Avatar src={item.author?.avatar} alt={item.author.name} /> : <Initials>{ renderInitials(item.author.name) }</Initials> }
|
|
139
|
+
<Typography textColor="neutral800" variant="pi">{ item.author.name }</Typography>
|
|
140
|
+
</Stack>
|
|
141
|
+
</Td>
|
|
127
142
|
<Td style={{ maxWidth: '30vw' }}>
|
|
128
143
|
<Typography textColor="neutral800" ellipsis>{item.content}</Typography>
|
|
129
144
|
</Td>
|
|
@@ -146,22 +161,28 @@ const DiscoverTableRow = ({ config, item, onClick }) => {
|
|
|
146
161
|
<Flex direction="column" alignItems="flex-end">
|
|
147
162
|
<Stack size={actionItemsCount} horizontal>
|
|
148
163
|
{ reviewFlowEnabled && (<IconButton onClick={handleReportsReviewClick} label={ getMessage('page.discover.table.reports.review') } icon={<ReviewIcon />} />)}
|
|
149
|
-
{ needsApproval && (
|
|
164
|
+
{ (canModerate && needsApproval) && (
|
|
165
|
+
<DiscussionThreadItemApprovalFlowActions
|
|
166
|
+
id={item.id}
|
|
167
|
+
allowedActions={{ canModerate }}
|
|
168
|
+
queryToInvalidate="get-data" />
|
|
169
|
+
)}
|
|
150
170
|
<IconButton onClick={handleClick} label={ getMessage('page.discover.table.action.display') } icon={<Eye />} />
|
|
151
171
|
</Stack>
|
|
152
172
|
</Flex>
|
|
153
173
|
{ reviewFlowEnabled && (<ReportsReviewModal
|
|
154
174
|
isVisible={reportsReviewVisible}
|
|
155
175
|
isActionAsync={isLoading}
|
|
176
|
+
allowedActions={{ canModerate, canAccessReports, canReviewReports }}
|
|
156
177
|
onClose={handleReportsReviewClose}
|
|
157
|
-
startActions={<>
|
|
178
|
+
startActions={canModerate && (<>
|
|
158
179
|
<Button onClick={handleBlockItemClick} variant="danger-light" startIcon={<LockIcon />} disabled={blockButtonsDisabled}>
|
|
159
180
|
{ getMessage(`page.details.actions.comment.block`, 'Block comment') }
|
|
160
181
|
</Button>
|
|
161
182
|
{ item.gotThread && (<Button onClick={handleBlockItemThreadClick} variant="danger" startIcon={<LockIcon />} disabled={blockButtonsDisabled}>
|
|
162
183
|
{ getMessage(`page.details.actions.thread.block`, 'Block thread') }
|
|
163
184
|
</Button>) }
|
|
164
|
-
</>}
|
|
185
|
+
</>)}
|
|
165
186
|
item={item}>
|
|
166
187
|
<Typography variant="sigma" textColor="neutral600" id="reports-list">
|
|
167
188
|
{ getMessage('page.details.panel.discussion.warnings.reports.list', 'List') }
|
|
@@ -173,6 +194,7 @@ const DiscoverTableRow = ({ config, item, onClick }) => {
|
|
|
173
194
|
commentId={item.id}
|
|
174
195
|
items={orderBy(reports, ['resolved', 'createdAt'], ['DESC', 'DESC'])}
|
|
175
196
|
mutation={resolveReportMutation}
|
|
197
|
+
allowedActions={{ canAccessReports, canReviewReports }}
|
|
176
198
|
onBlockButtonsStateChange={handleBlockButtonsStateChange}
|
|
177
199
|
/>
|
|
178
200
|
</ReportsReviewModal>) }
|
|
@@ -184,6 +206,11 @@ const DiscoverTableRow = ({ config, item, onClick }) => {
|
|
|
184
206
|
DiscoverTableRow.propTypes = {
|
|
185
207
|
config: PropTypes.object.isRequired,
|
|
186
208
|
item: PropTypes.object.isRequired,
|
|
209
|
+
allowedActions: PropTypes.shape({
|
|
210
|
+
canModerate: PropTypes.bool,
|
|
211
|
+
canAccessReports: PropTypes.bool,
|
|
212
|
+
canReviewReports: PropTypes.bool,
|
|
213
|
+
}),
|
|
187
214
|
onClick: PropTypes.func.isRequired,
|
|
188
215
|
};
|
|
189
216
|
|
|
@@ -51,17 +51,20 @@ const Discover = ({ config }) => {
|
|
|
51
51
|
const [{ query: queryParams }] = useQueryParams();
|
|
52
52
|
const _q = queryParams?._q || '';
|
|
53
53
|
|
|
54
|
-
const viewPermissions = useMemo(() => {
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
const viewPermissions = useMemo(() => ({
|
|
55
|
+
access: pluginPermissions.access,
|
|
56
|
+
moderate: pluginPermissions.moderate,
|
|
57
|
+
accessReports: pluginPermissions.reports,
|
|
58
|
+
reviewReports: pluginPermissions.reportsReview,
|
|
59
|
+
}), []);
|
|
57
60
|
|
|
58
61
|
const {
|
|
59
62
|
isLoading: isLoadingForPermissions,
|
|
60
|
-
allowedActions: {
|
|
63
|
+
allowedActions: { canAccess, canModerate, canAccessReports, canReviewReports },
|
|
61
64
|
} = useRBAC(viewPermissions);
|
|
62
65
|
|
|
63
66
|
const { isLoading: isLoadingForData, data: { result, pagination = {} }, isFetching } = useQuery(
|
|
64
|
-
['get-data', queryParams],
|
|
67
|
+
['get-data', queryParams, canAccess],
|
|
65
68
|
() => fetchData(queryParams, toggleNotification),
|
|
66
69
|
{
|
|
67
70
|
initialData: { },
|
|
@@ -86,62 +89,72 @@ const Discover = ({ config }) => {
|
|
|
86
89
|
},
|
|
87
90
|
};
|
|
88
91
|
|
|
89
|
-
|
|
90
|
-
|
|
91
92
|
const emptyContent = _q ? 'search' : 'comments';
|
|
92
93
|
|
|
93
|
-
const COL_COUNT =
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
<
|
|
111
|
-
<
|
|
112
|
-
<
|
|
113
|
-
<
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
<
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
<
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
<
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
<
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
<
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
<
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
94
|
+
const COL_COUNT = 8;
|
|
95
|
+
|
|
96
|
+
if (canAccess) {
|
|
97
|
+
return <Box background="neutral100">
|
|
98
|
+
<Layout>
|
|
99
|
+
{isLoading || isLoadingForPermissions ? (<LoadingIndicatorPage />) : (
|
|
100
|
+
<>
|
|
101
|
+
<HeaderLayout title={ getMessage('page.discover.header') } subtitle={ `${total} ${ getMessage('page.discover.header.count')}` } as="h2" />
|
|
102
|
+
<ActionLayout
|
|
103
|
+
startActions={<>
|
|
104
|
+
<SearchURLQuery
|
|
105
|
+
label={ getMessage('search.label', 'Search', false) }
|
|
106
|
+
/>
|
|
107
|
+
<TableFilters displayedFilters={filtersSchema} />
|
|
108
|
+
</>} />
|
|
109
|
+
<ContentLayout>
|
|
110
|
+
{ !isEmpty(result) ? (<>
|
|
111
|
+
<Table colCount={COL_COUNT} rowCount={result.length}>
|
|
112
|
+
<Thead>
|
|
113
|
+
<Tr>
|
|
114
|
+
<Th>
|
|
115
|
+
<Typography variant="sigma">{ getMessage('page.discover.table.header.id') }</Typography>
|
|
116
|
+
</Th>
|
|
117
|
+
<Th>
|
|
118
|
+
<Typography variant="sigma">{ getMessage('page.discover.table.header.author') }</Typography>
|
|
119
|
+
</Th>
|
|
120
|
+
<Th>
|
|
121
|
+
<Typography variant="sigma">{ getMessage('page.discover.table.header.message') }</Typography>
|
|
122
|
+
</Th>
|
|
123
|
+
<Th>
|
|
124
|
+
<Typography variant="sigma">{ getMessage('page.discover.table.header.thread') }</Typography>
|
|
125
|
+
</Th>
|
|
126
|
+
<Th>
|
|
127
|
+
<Typography variant="sigma">{ getMessage('page.discover.table.header.entry') }</Typography>
|
|
128
|
+
</Th>
|
|
129
|
+
<Th>
|
|
130
|
+
<Typography variant="sigma">{ getMessage('page.discover.table.header.lastUpdate') }</Typography>
|
|
131
|
+
</Th>
|
|
132
|
+
<Th>
|
|
133
|
+
<Typography variant="sigma">{ getMessage('page.discover.table.header.status') }</Typography>
|
|
134
|
+
</Th>
|
|
135
|
+
<Th>
|
|
136
|
+
<VisuallyHidden>{ getMessage('page.discover.table.header.actions') }</VisuallyHidden>
|
|
137
|
+
</Th>
|
|
138
|
+
</Tr>
|
|
139
|
+
</Thead>
|
|
140
|
+
<Tbody>
|
|
141
|
+
{result.map(entry => (<DiscoverTableRow
|
|
142
|
+
key={`comment-${entry.id}`}
|
|
143
|
+
config={config}
|
|
144
|
+
item={entry}
|
|
145
|
+
allowedActions={{ canModerate, canAccessReports, canReviewReports }}
|
|
146
|
+
onClick={() => handleClickDisplay(entry.id)}
|
|
147
|
+
/>))}
|
|
148
|
+
</Tbody>
|
|
149
|
+
</Table>
|
|
150
|
+
<TablePagination pagination={{ pageCount: pagination?.pageCount || 1 }} />
|
|
151
|
+
</>) : (<EmptyStateLayout content={emptyLayout[emptyContent]} />) }
|
|
152
|
+
</ContentLayout>
|
|
153
|
+
</>) }
|
|
154
|
+
</Layout>
|
|
155
|
+
</Box>;
|
|
156
|
+
}
|
|
157
|
+
return null;
|
|
145
158
|
}
|
|
146
159
|
|
|
147
160
|
const mapStateToProps = makeAppView();
|
package/admin/src/permissions.js
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
|
+
const permissions = require('./../../permissions');
|
|
2
|
+
|
|
1
3
|
const pluginPermissions = {
|
|
2
4
|
access: [
|
|
3
|
-
{ action:
|
|
4
|
-
{ action:
|
|
5
|
-
{ action: 'plugin::comments.
|
|
6
|
-
{ action:
|
|
5
|
+
{ action: permissions.render(permissions.comments.read), subject: null },
|
|
6
|
+
{ action: permissions.render(permissions.reports.read), subject: null },
|
|
7
|
+
// { action: 'plugin::comments.discover.read', subject: null },
|
|
8
|
+
{ action: permissions.render(permissions.settings.read), subject: null },
|
|
7
9
|
],
|
|
8
|
-
discover: [{ action: 'plugin::comments.read', subject: null }],
|
|
9
|
-
moderate: [{ action:
|
|
10
|
-
reports: [{ action:
|
|
11
|
-
reportsReview: [{ action:
|
|
10
|
+
// discover: [{ action: 'plugin::comments.discover.read', subject: null }],
|
|
11
|
+
moderate: [{ action: permissions.render(permissions.comments.moderate), subject: null }],
|
|
12
|
+
reports: [{ action: permissions.render(permissions.reports.read), subject: null }],
|
|
13
|
+
reportsReview: [{ action: permissions.render(permissions.reports.action), subject: null }],
|
|
12
14
|
};
|
|
13
15
|
|
|
14
16
|
export default pluginPermissions;
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"page.discover.header": "Discover threads",
|
|
18
18
|
"page.discover.header.count": "entries found",
|
|
19
19
|
"page.discover.table.header.id": "ID",
|
|
20
|
+
"page.discover.table.header.author": "Author",
|
|
20
21
|
"page.discover.table.header.message": "Message",
|
|
21
22
|
"page.discover.table.header.thread": "Thread of",
|
|
22
23
|
"page.discover.table.header.entry": "Entry",
|
|
@@ -76,6 +77,7 @@
|
|
|
76
77
|
"page.details.actions.comment.approve.confirmation.success": "Comment has been approved",
|
|
77
78
|
"page.details.actions.comment.reject.confirmation.success": "Comment has been rejected",
|
|
78
79
|
"page.details.filters.label": "View",
|
|
80
|
+
"page.details.filters.removed.visibility": "Comments visibility",
|
|
79
81
|
"page.details.filters.removed.show": "Show removed",
|
|
80
82
|
"page.details.filters.removed.hide": "Hide removed",
|
|
81
83
|
"page.coming.soon": "Wait for what is coming soon...",
|
package/admin/src/utils/index.js
CHANGED
|
@@ -4,5 +4,7 @@ export { default as getUrl } from './getUrl';
|
|
|
4
4
|
export { default as getMessage } from './getMessage';
|
|
5
5
|
export { default as handleAPIError } from './handleAPIError';
|
|
6
6
|
export { default as getRelatedGroups } from './getRelatedGroups';
|
|
7
|
+
export { default as renderEntryTitle } from './renderEntryTitle';
|
|
8
|
+
export { default as renderInitials } from './renderInitials';
|
|
7
9
|
export { default as resolveCommentStatus } from './resolveCommentStatus';
|
|
8
10
|
export { default as resolveCommentStatusColor } from './resolveCommentStatusColor';
|
package/content-types/comment.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "strapi-plugin-comments",
|
|
3
|
-
"version": "2.0.0-
|
|
3
|
+
"version": "2.0.0-rc.2",
|
|
4
4
|
"description": "Strapi - Comments plugin",
|
|
5
5
|
"strapi": {
|
|
6
6
|
"name": "comments",
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
"kind": "plugin"
|
|
9
9
|
},
|
|
10
10
|
"scripts": {
|
|
11
|
+
"publish": "npm publish --tag latest",
|
|
11
12
|
"test:unit": "jest --verbose --coverage"
|
|
12
13
|
},
|
|
13
14
|
"repository": {
|
|
@@ -15,7 +16,8 @@
|
|
|
15
16
|
"url": "https://github.com/VirtusLab-Open-Source/strapi-plugin-comments"
|
|
16
17
|
},
|
|
17
18
|
"dependencies": {
|
|
18
|
-
"@strapi/utils": "^4.0.
|
|
19
|
+
"@strapi/utils": "^4.0.6",
|
|
20
|
+
"@strapi/plugin-graphql": "^4.0.6",
|
|
19
21
|
"bad-words": "^3.0.4"
|
|
20
22
|
},
|
|
21
23
|
"devDependencies": {
|
package/permissions.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
module.exports = {
|
|
4
|
+
render: function(uid) {
|
|
5
|
+
return `plugin::comments.${uid}`;
|
|
6
|
+
},
|
|
7
|
+
comments: {
|
|
8
|
+
read: 'read',
|
|
9
|
+
moderate: 'moderate',
|
|
10
|
+
},
|
|
11
|
+
reports: {
|
|
12
|
+
read: 'reports.read',
|
|
13
|
+
action: 'reports.action',
|
|
14
|
+
},
|
|
15
|
+
settings: {
|
|
16
|
+
read: 'settings.read',
|
|
17
|
+
change: 'settings.change',
|
|
18
|
+
},
|
|
19
|
+
};
|
|
Binary file
|
|
Binary file
|
package/server/bootstrap.js
CHANGED
|
@@ -1,5 +1,41 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
const permissions = require('./../permissions');
|
|
4
|
+
|
|
5
|
+
module.exports = async ({ strapi }) => {
|
|
6
|
+
// Check if the plugin users-permissions is installed because the navigation needs it
|
|
7
|
+
if (Object.keys(strapi.plugins).indexOf("users-permissions") === -1) {
|
|
8
|
+
throw new Error(
|
|
9
|
+
"In order to make the comments plugin work the users-permissions plugin is required",
|
|
10
|
+
);
|
|
11
|
+
}
|
|
12
|
+
// Add permissions
|
|
13
|
+
const actions = [
|
|
14
|
+
{
|
|
15
|
+
section: "plugins",
|
|
16
|
+
displayName: "Comments: Read",
|
|
17
|
+
uid: permissions.comments.read,
|
|
18
|
+
pluginName: "comments",
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
section: "plugins",
|
|
22
|
+
displayName: "Comments: Moderate",
|
|
23
|
+
uid: permissions.comments.moderate,
|
|
24
|
+
pluginName: "comments",
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
section: "plugins",
|
|
28
|
+
displayName: "Reports: Read",
|
|
29
|
+
uid: permissions.reports.read,
|
|
30
|
+
pluginName: "comments",
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
section: "plugins",
|
|
34
|
+
displayName: "Reports: Moderate",
|
|
35
|
+
uid: permissions.reports.action,
|
|
36
|
+
pluginName: "comments",
|
|
37
|
+
},
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
await strapi.admin.services.permission.actionProvider.registerMany(actions);
|
|
5
41
|
};
|
package/server/config/index.js
CHANGED
|
@@ -2,10 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
module.exports = {
|
|
4
4
|
default: {
|
|
5
|
+
moderatorRoles: [],
|
|
5
6
|
approvalFlow: [],
|
|
6
7
|
entryLabel: {
|
|
7
8
|
'*': ['Title', 'title', 'Name', 'name', 'Subject', 'subject']
|
|
8
9
|
},
|
|
9
|
-
|
|
10
|
-
|
|
10
|
+
reportReasons: {
|
|
11
|
+
'BAD_LANGUAGE': 'BAD_LANGUAGE',
|
|
12
|
+
'DISCRIMINATION': 'DISCRIMINATION',
|
|
13
|
+
'OTHER': 'OTHER',
|
|
14
|
+
},
|
|
15
|
+
}
|
|
11
16
|
};
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const { getPluginService } = require('./../utils/functions');
|
|
4
4
|
const { parseParams, throwError } = require('./utils/functions');
|
|
5
|
-
const
|
|
5
|
+
const { flatInput } = require('./utils/parsers');
|
|
6
6
|
|
|
7
7
|
module.exports = {
|
|
8
8
|
|
|
@@ -15,16 +15,7 @@ module.exports = {
|
|
|
15
15
|
const { relation } = parseParams(params);
|
|
16
16
|
try {
|
|
17
17
|
return this.getService('common')
|
|
18
|
-
.findAllFlat(
|
|
19
|
-
query: {
|
|
20
|
-
...query,
|
|
21
|
-
$or: [{ removed: { $null: true } }, { removed: false }],
|
|
22
|
-
related: relation,
|
|
23
|
-
},
|
|
24
|
-
populate: {
|
|
25
|
-
threadOf: true,
|
|
26
|
-
},
|
|
27
|
-
});
|
|
18
|
+
.findAllFlat(flatInput(relation, query));
|
|
28
19
|
} catch (e) {
|
|
29
20
|
throwError(ctx, e);
|
|
30
21
|
}
|
|
@@ -36,13 +27,7 @@ module.exports = {
|
|
|
36
27
|
try {
|
|
37
28
|
return await this.getService('common')
|
|
38
29
|
.findAllInHierarchy({
|
|
39
|
-
query
|
|
40
|
-
...query,
|
|
41
|
-
related: relation,
|
|
42
|
-
},
|
|
43
|
-
populate: {
|
|
44
|
-
threadOf: true,
|
|
45
|
-
},
|
|
30
|
+
...flatInput(relation, query),
|
|
46
31
|
dropBlockedThreads: true,
|
|
47
32
|
});
|
|
48
33
|
} catch (e) {
|
|
@@ -97,14 +82,19 @@ module.exports = {
|
|
|
97
82
|
},
|
|
98
83
|
|
|
99
84
|
async removeComment(ctx) {
|
|
100
|
-
const {
|
|
101
|
-
|
|
85
|
+
const {
|
|
86
|
+
params: { relationId, commentId },
|
|
87
|
+
query: { authorId },
|
|
88
|
+
state: { user },
|
|
89
|
+
} = ctx;
|
|
90
|
+
if (authorId || user?.id) {
|
|
102
91
|
try {
|
|
103
92
|
return await this.getService()
|
|
104
93
|
.markAsRemoved(
|
|
105
|
-
relationId,
|
|
106
94
|
commentId,
|
|
95
|
+
relationId,
|
|
107
96
|
authorId,
|
|
97
|
+
user
|
|
108
98
|
);
|
|
109
99
|
} catch (e) {
|
|
110
100
|
if (!e.isBoom) {
|