strapi-plugin-comments 2.0.0-rc.2 → 2.0.3
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/.husky/pre-commit +4 -0
- package/README.md +53 -9
- package/__mocks__/initSetup.js +82 -0
- package/admin/src/components/ActionButton/styles.js +10 -0
- package/admin/src/components/DiscussionThread/index.js +2 -6
- package/admin/src/components/DiscussionThreadItem/index.js +25 -68
- package/admin/src/components/DiscussionThreadItem/styles.js +4 -79
- package/admin/src/components/DiscussionThreadItemActions/index.js +82 -40
- package/admin/src/components/DiscussionThreadItemActions/styles.js +1 -12
- package/admin/src/components/DiscussionThreadItemApprovalFlowActions/index.js +2 -3
- package/admin/src/components/DiscussionThreadItemFooter/index.js +47 -0
- package/admin/src/components/DiscussionThreadItemFooter/styles.js +13 -0
- package/admin/src/components/DiscussionThreadItemReviewAction/index.js +131 -0
- package/admin/src/components/IconButton/styles.js +14 -0
- package/admin/src/components/ReportsReviewModal/index.js +1 -1
- package/admin/src/components/ReportsReviewTable/index.js +12 -6
- package/admin/src/components/StatusBadge/index.js +17 -0
- package/admin/src/components/StatusBadge/styles.js +17 -0
- package/admin/src/hooks/useConfig.js +43 -0
- package/admin/src/index.js +31 -2
- package/admin/src/pages/Details/components/DetailsEntity/index.js +42 -24
- package/admin/src/pages/Details/components/DetailsFilters/index.js +8 -10
- package/admin/src/pages/Details/index.js +11 -17
- package/admin/src/pages/Discover/components/DiscoverTableRow/index.js +30 -67
- package/admin/src/pages/Settings/index.js +342 -0
- package/admin/src/pages/Settings/utils/api.js +50 -0
- package/admin/src/permissions.js +3 -0
- package/admin/src/translations/en.json +50 -16
- package/admin/src/utils/index.js +2 -1
- package/admin/src/utils/parseRegExp.js +10 -0
- package/admin/src/utils/resolveCommentStatus.js +4 -4
- package/package.json +12 -7
- package/server/bootstrap.js +24 -0
- package/server/config/index.js +1 -0
- package/server/controllers/admin.js +33 -8
- package/server/controllers/client.js +4 -4
- package/server/controllers/utils/__tests__/functions.test.js +2 -2
- package/server/controllers/utils/parsers.js +3 -1
- package/server/graphql/index.js +7 -8
- package/server/graphql/queries/findAllFlat.js +4 -2
- package/server/graphql/queries/findAllInHierarchy.js +3 -3
- package/server/graphql/resolvers-config.js +2 -4
- package/server/graphql/types/comment-nested.js +1 -0
- package/server/graphql/types/report-reason.js +10 -10
- package/server/register.js +1 -3
- package/server/routes/admin.js +24 -0
- package/server/services/__tests__/common.test.js +246 -0
- package/server/services/admin.js +60 -6
- package/server/services/client.js +13 -9
- package/server/services/common.js +86 -11
- package/server/services/utils/__tests__/functions.test.js +20 -73
- package/server/services/utils/functions.js +9 -17
- package/server/utils/__tests__/functions.test.js +17 -0
- package/server/utils/constants.js +10 -0
- package/strapi-server.js +12 -5
- package/.circleci/config.yml +0 -48
- package/.eslintrc +0 -35
- package/.github/pull_request_template.md +0 -13
- package/.nvmrc +0 -1
- package/admin/src/components/DiscussionThreadItemMeta/index.js +0 -42
- package/admin/src/components/DiscussionThreadItemWarnings/index.js +0 -147
- package/admin/src/components/DiscussionThreadItemWarnings/styles.js +0 -7
- package/codecov.yml +0 -4
- package/public/assets/logo.png +0 -0
- package/public/assets/preview.png +0 -0
|
@@ -10,6 +10,39 @@ module.exports = {
|
|
|
10
10
|
return getPluginService(name);
|
|
11
11
|
},
|
|
12
12
|
|
|
13
|
+
async config(ctx) {
|
|
14
|
+
try {
|
|
15
|
+
return await this.getService().config();
|
|
16
|
+
} catch (e) {
|
|
17
|
+
throwError(ctx, e);
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
|
|
21
|
+
async settingsConfig(ctx) {
|
|
22
|
+
try {
|
|
23
|
+
return this.getService().config(true);
|
|
24
|
+
} catch (e) {
|
|
25
|
+
throwError(ctx, e);
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
|
|
29
|
+
async settingsUpdateConfig(ctx) {
|
|
30
|
+
try {
|
|
31
|
+
const { request: { body } } = ctx;
|
|
32
|
+
return this.getService().updateConfig(body);
|
|
33
|
+
} catch (e) {
|
|
34
|
+
throwError(ctx, e);
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
|
|
38
|
+
async settingsRestoreConfig(ctx) {
|
|
39
|
+
try {
|
|
40
|
+
return this.getService().restoreConfig();
|
|
41
|
+
} catch (e) {
|
|
42
|
+
throwError(ctx, e);
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
|
|
13
46
|
async findAll(ctx) {
|
|
14
47
|
return this.getService()
|
|
15
48
|
.findAll(ctx.query);
|
|
@@ -101,14 +134,6 @@ module.exports = {
|
|
|
101
134
|
}
|
|
102
135
|
},
|
|
103
136
|
|
|
104
|
-
async config(ctx) {
|
|
105
|
-
try {
|
|
106
|
-
return await this.getService().config();
|
|
107
|
-
} catch (e) {
|
|
108
|
-
throwError(ctx, e);
|
|
109
|
-
}
|
|
110
|
-
},
|
|
111
|
-
|
|
112
137
|
getContentsTypes() {
|
|
113
138
|
return Object.entries(strapi.contentTypes)
|
|
114
139
|
.filter(([, contentType]) => (
|
|
@@ -11,23 +11,23 @@ module.exports = {
|
|
|
11
11
|
},
|
|
12
12
|
|
|
13
13
|
async findAllFlat(ctx) {
|
|
14
|
-
const { params = {}, query } = ctx;
|
|
14
|
+
const { params = {}, query, sort, pagination } = ctx;
|
|
15
15
|
const { relation } = parseParams(params);
|
|
16
16
|
try {
|
|
17
17
|
return this.getService('common')
|
|
18
|
-
.findAllFlat(flatInput(relation, query));
|
|
18
|
+
.findAllFlat(flatInput(relation, query, sort, pagination));
|
|
19
19
|
} catch (e) {
|
|
20
20
|
throwError(ctx, e);
|
|
21
21
|
}
|
|
22
22
|
},
|
|
23
23
|
|
|
24
24
|
async findAllInHierarchy(ctx) {
|
|
25
|
-
const { params = {}, query } = ctx;
|
|
25
|
+
const { params = {}, query, sort } = ctx;
|
|
26
26
|
const { relation } = parseParams(params);
|
|
27
27
|
try {
|
|
28
28
|
return await this.getService('common')
|
|
29
29
|
.findAllInHierarchy({
|
|
30
|
-
...flatInput(relation, query),
|
|
30
|
+
...flatInput(relation, query, sort),
|
|
31
31
|
dropBlockedThreads: true,
|
|
32
32
|
});
|
|
33
33
|
} catch (e) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
const PluginError = require('../../../
|
|
1
|
+
const PluginError = require('../../../utils/error');
|
|
2
2
|
const ctx = require('koa/lib/context');
|
|
3
|
-
const {
|
|
3
|
+
const { throwError } = require('../functions');
|
|
4
4
|
|
|
5
5
|
jest.mock
|
|
6
6
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
3
|
module.exports = {
|
|
4
|
-
flatInput(relation, query) {
|
|
4
|
+
flatInput(relation, query, sort, pagination) {
|
|
5
5
|
return {
|
|
6
6
|
query: {
|
|
7
7
|
...query,
|
|
@@ -13,6 +13,8 @@ module.exports = {
|
|
|
13
13
|
populate: { authorUser: true },
|
|
14
14
|
},
|
|
15
15
|
},
|
|
16
|
+
pagination,
|
|
17
|
+
sort,
|
|
16
18
|
};
|
|
17
19
|
},
|
|
18
20
|
|
package/server/graphql/index.js
CHANGED
|
@@ -6,17 +6,16 @@ const getMutations = require('./mutations');
|
|
|
6
6
|
const getResolversConfig = require('./resolvers-config');
|
|
7
7
|
const { getModelUid } = require('../services/utils/functions');
|
|
8
8
|
|
|
9
|
-
module.exports = () => {
|
|
9
|
+
module.exports = async ({ strapi, config}) => {
|
|
10
10
|
const extensionService = strapi.plugin('graphql').service('extension');
|
|
11
|
-
|
|
12
11
|
extensionService.shadowCRUD(getModelUid('comment')).disable();
|
|
13
12
|
extensionService.shadowCRUD(getModelUid('comment-report')).disable();
|
|
14
|
-
|
|
15
|
-
extensionService.use(({ nexus }) => {
|
|
16
|
-
const types = getTypes({ strapi, nexus });
|
|
17
|
-
const queries = getQueries({ strapi, nexus });
|
|
18
|
-
const mutations = getMutations({ strapi, nexus });
|
|
19
|
-
const resolversConfig = getResolversConfig({ strapi });
|
|
13
|
+
|
|
14
|
+
extensionService.use(({ strapi, nexus }) => {
|
|
15
|
+
const types = getTypes({ strapi, nexus, config });
|
|
16
|
+
const queries = getQueries({ strapi, nexus, config });
|
|
17
|
+
const mutations = getMutations({ strapi, nexus, config });
|
|
18
|
+
const resolversConfig = getResolversConfig({ strapi, config });
|
|
20
19
|
|
|
21
20
|
return {
|
|
22
21
|
types: [types, queries, mutations],
|
|
@@ -18,11 +18,13 @@ module.exports = ({ strapi, nexus }) => {
|
|
|
18
18
|
sort: args.SortArg,
|
|
19
19
|
},
|
|
20
20
|
async resolve(obj, args) {
|
|
21
|
-
const { relation, filters } = args;
|
|
21
|
+
const { relation, filters, sort, pagination } = args;
|
|
22
22
|
return await getPluginService('common')
|
|
23
23
|
.findAllFlat(flatInput(
|
|
24
24
|
relation,
|
|
25
|
-
getPluginService('gql').graphQLFiltersToStrapiQuery(filters, contentType)
|
|
25
|
+
getPluginService('gql').graphQLFiltersToStrapiQuery(filters, contentType),
|
|
26
|
+
sort,
|
|
27
|
+
pagination
|
|
26
28
|
), undefined);
|
|
27
29
|
},
|
|
28
30
|
};
|
|
@@ -13,16 +13,16 @@ module.exports = ({ strapi, nexus }) => {
|
|
|
13
13
|
type: nonNull(list('CommentNested')),
|
|
14
14
|
args: {
|
|
15
15
|
relation: nonNull(stringArg()),
|
|
16
|
-
// filters: filtersArg,
|
|
17
16
|
sort: args.SortArg,
|
|
18
17
|
},
|
|
19
18
|
async resolve(obj, args) {
|
|
20
|
-
const { relation, filters } = args;
|
|
19
|
+
const { relation, filters, sort } = args;
|
|
21
20
|
return await getPluginService('common')
|
|
22
21
|
.findAllInHierarchy({
|
|
23
22
|
...flatInput(
|
|
24
23
|
relation,
|
|
25
|
-
getPluginService('gql').graphQLFiltersToStrapiQuery(filters, contentType)
|
|
24
|
+
getPluginService('gql').graphQLFiltersToStrapiQuery(filters, contentType),
|
|
25
|
+
sort
|
|
26
26
|
),
|
|
27
27
|
dropBlockedThreads: true,
|
|
28
28
|
});
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
module.exports = () => {
|
|
6
|
-
const auth = getPluginService('common').getConfig('gql.auth', false);
|
|
3
|
+
module.exports = ({ config }) => {
|
|
4
|
+
const { gql: { auth = false } = {}} = config;
|
|
7
5
|
return {
|
|
8
6
|
'Query.findAllFlat': { auth },
|
|
9
7
|
'Query.findAllInHierarchy': { auth },
|
|
@@ -6,6 +6,7 @@ module.exports = ({ nexus }) => nexus.objectType({
|
|
|
6
6
|
t.boolean("blocked")
|
|
7
7
|
t.boolean("blockedThread")
|
|
8
8
|
t.string("approvalStatus")
|
|
9
|
+
t.boolean("removed")
|
|
9
10
|
t.field("threadOf", { type: 'CommentSingle' })
|
|
10
11
|
t.list.field("children", { type: 'CommentNested' })
|
|
11
12
|
t.field("author", { type: 'CommentAuthor' })
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
}
|
|
10
|
-
}
|
|
1
|
+
module.exports = ({ nexus, config }) => {
|
|
2
|
+
const { reportReasons } = config;
|
|
3
|
+
return nexus.enumType({
|
|
4
|
+
name: "ReportReason",
|
|
5
|
+
description: 'Reason of abuse report',
|
|
6
|
+
members: {
|
|
7
|
+
...reportReasons
|
|
8
|
+
},
|
|
9
|
+
})
|
|
10
|
+
};
|
package/server/register.js
CHANGED
package/server/routes/admin.js
CHANGED
|
@@ -89,4 +89,28 @@ module.exports = [
|
|
|
89
89
|
policies: [],
|
|
90
90
|
},
|
|
91
91
|
},
|
|
92
|
+
{
|
|
93
|
+
method: 'GET',
|
|
94
|
+
path: '/settings/config',
|
|
95
|
+
handler: 'admin.settingsConfig',
|
|
96
|
+
config: {
|
|
97
|
+
policies: [],
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
method: 'PUT',
|
|
102
|
+
path: '/settings/config',
|
|
103
|
+
handler: 'admin.settingsUpdateConfig',
|
|
104
|
+
config: {
|
|
105
|
+
policies: [],
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
method: 'DELETE',
|
|
110
|
+
path: '/settings/config',
|
|
111
|
+
handler: 'admin.settingsRestoreConfig',
|
|
112
|
+
config: {
|
|
113
|
+
policies: [],
|
|
114
|
+
},
|
|
115
|
+
},
|
|
92
116
|
];
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
const { CONFIG_PARAMS } = require('../../utils/constants');
|
|
2
|
+
const PluginError = require('../../utils/error');
|
|
3
|
+
const { getPluginService } = require('../../utils/functions');
|
|
4
|
+
|
|
5
|
+
jest.mock
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
const setup = function(config) {
|
|
9
|
+
Object.defineProperty(global, 'strapi', {
|
|
10
|
+
value: require('../../../__mocks__/initSetup')(config),
|
|
11
|
+
writable: true,
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
afterEach(() => {
|
|
16
|
+
Object.defineProperty(global, 'strapi', {});
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
describe('Test Comments service functions utils', () => {
|
|
20
|
+
describe('Get plugin store', () => {
|
|
21
|
+
beforeEach(() => setup());
|
|
22
|
+
|
|
23
|
+
test('Should return store', async () => {
|
|
24
|
+
const pluginStore = await getPluginService('common').getPluginStore();
|
|
25
|
+
expect(pluginStore).toHaveProperty('get');
|
|
26
|
+
expect(pluginStore).toHaveProperty('set');
|
|
27
|
+
expect(pluginStore).toHaveProperty('delete');
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
describe('Get plugin config', () => {
|
|
32
|
+
describe('Local config', () => {
|
|
33
|
+
beforeEach(() => setup({
|
|
34
|
+
test: 'sample',
|
|
35
|
+
}));
|
|
36
|
+
|
|
37
|
+
test('Should return config value', async () => {
|
|
38
|
+
const result = await getPluginService('common').getConfig('test');
|
|
39
|
+
expect(result).toEqual('sample');
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test('Should return default config prop value if not set', async () => {
|
|
43
|
+
const result = await getPluginService('common').getConfig('another', 'defaultValue');
|
|
44
|
+
expect(result).toEqual('defaultValue');
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
describe('Store config', () => {
|
|
49
|
+
beforeEach(() => setup({
|
|
50
|
+
test: 'sample',
|
|
51
|
+
}, true));
|
|
52
|
+
|
|
53
|
+
test('Should return config value', async () => {
|
|
54
|
+
const result = await getPluginService('common').getConfig('test');
|
|
55
|
+
expect(result).toEqual('sample');
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test('Should return default config prop value if not set', async () => {
|
|
59
|
+
const result = await getPluginService('common').getConfig('another', 'defaultValue');
|
|
60
|
+
expect(result).toEqual('defaultValue');
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
describe('Validate user context', () => {
|
|
66
|
+
beforeEach(() => setup());
|
|
67
|
+
|
|
68
|
+
test('Should context be valid', () => {
|
|
69
|
+
expect(getPluginService('common').isValidUserContext({ id: 1 })).toEqual(true);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
test('Should context be invalid', () => {
|
|
73
|
+
expect(getPluginService('common').isValidUserContext({ })).toEqual(false);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test('Should use fallback', () => {
|
|
77
|
+
expect(getPluginService('common').isValidUserContext()).toEqual(true);
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
describe('Sanitize comments entity', () => {
|
|
82
|
+
beforeEach(() => setup());
|
|
83
|
+
|
|
84
|
+
const sample = {
|
|
85
|
+
id: 1,
|
|
86
|
+
content: 'Test text',
|
|
87
|
+
blocked: false,
|
|
88
|
+
removed: true,
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const authorSample = {
|
|
92
|
+
id: 1,
|
|
93
|
+
username: 'Joe Doe',
|
|
94
|
+
email: 'test@example.com',
|
|
95
|
+
password: 'xxx',
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
const authorGenericSample = {
|
|
99
|
+
authorId: 1,
|
|
100
|
+
authorName: 'Joe Doe',
|
|
101
|
+
authorEmail: 'test@example.com',
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
const outputAuthorSample = {
|
|
105
|
+
id: 1,
|
|
106
|
+
name: 'Joe Doe',
|
|
107
|
+
email: 'test@example.com',
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
test('Should return exact the same value', () => {
|
|
111
|
+
const input = { ...sample };
|
|
112
|
+
const output = getPluginService('common').sanitizeCommentEntity(input);
|
|
113
|
+
expect(output).toHaveProperty('id', input.id);
|
|
114
|
+
expect(output).toHaveProperty('content', input.content);
|
|
115
|
+
expect(output).toHaveProperty('blocked', input.blocked);
|
|
116
|
+
expect(output).toHaveProperty('removed', input.removed);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
test('Should return entity with \'author\' property for generic author', () => {
|
|
120
|
+
const input = {
|
|
121
|
+
...sample,
|
|
122
|
+
...authorGenericSample,
|
|
123
|
+
};
|
|
124
|
+
const output = getPluginService('common').sanitizeCommentEntity(input);
|
|
125
|
+
|
|
126
|
+
expect(output).toHaveProperty('author');
|
|
127
|
+
expect(output).toHaveProperty('author.id', input.authorId);
|
|
128
|
+
expect(output).toHaveProperty('author.id', outputAuthorSample.id);
|
|
129
|
+
expect(output).toHaveProperty('author.name', input.authorName);
|
|
130
|
+
expect(output).toHaveProperty('author.name', outputAuthorSample.name);
|
|
131
|
+
expect(output).toHaveProperty('author.email', input.authorEmail);
|
|
132
|
+
expect(output).toHaveProperty('author.email', outputAuthorSample.email);
|
|
133
|
+
|
|
134
|
+
expect(output).not.toHaveProperty('authorId');
|
|
135
|
+
expect(output).not.toHaveProperty('authorName');
|
|
136
|
+
expect(output).not.toHaveProperty('authorEmail');
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
test('Should return entity with \'author\' property for Strapi author', () => {
|
|
140
|
+
const input = {
|
|
141
|
+
...sample,
|
|
142
|
+
authorUser: authorSample,
|
|
143
|
+
};
|
|
144
|
+
const output = getPluginService('common').sanitizeCommentEntity(input);
|
|
145
|
+
|
|
146
|
+
expect(output).toHaveProperty('author');
|
|
147
|
+
expect(output).toHaveProperty('author.id', input.authorUser.id);
|
|
148
|
+
expect(output).toHaveProperty('author.id', outputAuthorSample.id);
|
|
149
|
+
expect(output).toHaveProperty('author.name', input.authorUser.username);
|
|
150
|
+
expect(output).toHaveProperty('author.name', outputAuthorSample.name);
|
|
151
|
+
expect(output).toHaveProperty('author.email', input.authorUser.email);
|
|
152
|
+
expect(output).toHaveProperty('author.email', outputAuthorSample.email);
|
|
153
|
+
|
|
154
|
+
expect(output).not.toHaveProperty('authorUser');
|
|
155
|
+
|
|
156
|
+
expect(output).not.toHaveProperty('author.password');
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
describe('Bad Words filtering', () => {
|
|
161
|
+
beforeEach(() => setup());
|
|
162
|
+
|
|
163
|
+
const text = 'Lorem ipsum dolor sit fuck amet';
|
|
164
|
+
|
|
165
|
+
test('Should find bad words usage and throw error PluginError', async () => {
|
|
166
|
+
expect.assertions(7);
|
|
167
|
+
try {
|
|
168
|
+
await getPluginService('common').checkBadWords(text);
|
|
169
|
+
} catch (e) {
|
|
170
|
+
expect(await getPluginService('common').getConfig('badWords')).toEqual(undefined);
|
|
171
|
+
expect(e).toBeInstanceOf(PluginError);
|
|
172
|
+
expect(e).toHaveProperty('status', 400);
|
|
173
|
+
expect(e).toHaveProperty('name', 'Strapi:Plugin:Comments');
|
|
174
|
+
expect(e).toHaveProperty('message', 'Bad language used! Please polite your comment...');
|
|
175
|
+
expect(e).toHaveProperty('payload');
|
|
176
|
+
expect(e.payload).toEqual(expect.objectContaining({
|
|
177
|
+
content: {
|
|
178
|
+
original: text,
|
|
179
|
+
filtered: text.replace('fuck', '****'),
|
|
180
|
+
}
|
|
181
|
+
}));
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
describe('Bad Words filtering', () => {
|
|
187
|
+
beforeEach(() => setup({ badWords: false }));
|
|
188
|
+
|
|
189
|
+
const text = 'Lorem ipsum dolor sit fuck amet';
|
|
190
|
+
|
|
191
|
+
test('Should skip bad words filtering because of configuration change', async () => {
|
|
192
|
+
expect(await getPluginService('common').getConfig('badWords')).toEqual(false);
|
|
193
|
+
expect(await getPluginService('common').checkBadWords(text)).toEqual(text);
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
describe('Parse relation string (store config)', () => {
|
|
198
|
+
const [uid, id] = ['api::my-collection.my-content-type', '1'];
|
|
199
|
+
const validCollection = `${uid}:${id}`;
|
|
200
|
+
|
|
201
|
+
const [wrongUid, wrongId] = ['api::wrong.type', '2'];
|
|
202
|
+
const testCollection = `${wrongUid}:${wrongId}`;
|
|
203
|
+
|
|
204
|
+
describe('Store config', () => {
|
|
205
|
+
beforeEach(() => setup({ enabledCollections: [uid] }, true));
|
|
206
|
+
|
|
207
|
+
test('Should pass', async () => {
|
|
208
|
+
expect(await getPluginService('common').parseRelationString(validCollection));
|
|
209
|
+
expect(await getPluginService('common').getConfig(CONFIG_PARAMS.ENABLED_COLLECTIONS)).toContain(uid);
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
test('Should fail with 403', async () => {
|
|
213
|
+
|
|
214
|
+
try {
|
|
215
|
+
await getPluginService('common').parseRelationString(testCollection);
|
|
216
|
+
} catch(e) {
|
|
217
|
+
expect(await getPluginService('common').getConfig(CONFIG_PARAMS.ENABLED_COLLECTIONS)).toContain(uid);
|
|
218
|
+
expect(await getPluginService('common').getConfig(CONFIG_PARAMS.ENABLED_COLLECTIONS)).not.toContain(wrongUid);
|
|
219
|
+
expect(e).toBeInstanceOf(PluginError);
|
|
220
|
+
expect(e).toHaveProperty('status', 403);
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
describe('Local config', () => {
|
|
226
|
+
beforeEach(() => setup({ enabledCollections: [uid] }));
|
|
227
|
+
|
|
228
|
+
test('Should pass', async () => {
|
|
229
|
+
expect(await getPluginService('common').parseRelationString(validCollection));
|
|
230
|
+
expect(await getPluginService('common').getConfig(CONFIG_PARAMS.ENABLED_COLLECTIONS)).toContain(uid);
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
test('Should fail with 403', async () => {
|
|
234
|
+
|
|
235
|
+
try {
|
|
236
|
+
await getPluginService('common').parseRelationString(testCollection);
|
|
237
|
+
} catch(e) {
|
|
238
|
+
expect(await getPluginService('common').getConfig(CONFIG_PARAMS.ENABLED_COLLECTIONS)).toContain(uid);
|
|
239
|
+
expect(await getPluginService('common').getConfig(CONFIG_PARAMS.ENABLED_COLLECTIONS)).not.toContain(wrongUid);
|
|
240
|
+
expect(e).toBeInstanceOf(PluginError);
|
|
241
|
+
expect(e).toHaveProperty('status', 403);
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
});
|
package/server/services/admin.js
CHANGED
|
@@ -21,19 +21,73 @@ const { APPROVAL_STATUS, REGEX } = require('./../utils/constants')
|
|
|
21
21
|
},
|
|
22
22
|
|
|
23
23
|
// Config
|
|
24
|
-
async config() {
|
|
25
|
-
const
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
entryLabel,
|
|
29
|
-
approvalFlow,
|
|
24
|
+
async config(viaSettingsPage = false) {
|
|
25
|
+
const pluginStore = await this.getCommonService().getPluginStore();
|
|
26
|
+
const config = await pluginStore.get({ key: 'config' });
|
|
27
|
+
const additionalConfiguration = {
|
|
30
28
|
regex: Object.keys(REGEX).reduce((prev, curr) => ({
|
|
31
29
|
...prev,
|
|
32
30
|
[curr]: REGEX[curr].toString(),
|
|
33
31
|
}), {}),
|
|
34
32
|
};
|
|
33
|
+
|
|
34
|
+
const isGQLPluginEnabled = !isNil(strapi.plugin('graphql'));
|
|
35
|
+
|
|
36
|
+
if (config) {
|
|
37
|
+
return {
|
|
38
|
+
...config,
|
|
39
|
+
...additionalConfiguration,
|
|
40
|
+
isGQLPluginEnabled: viaSettingsPage ? isGQLPluginEnabled : undefined,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const entryLabel = this.getCommonService().getLocalConfig('entryLabel');
|
|
45
|
+
const approvalFlow = this.getCommonService().getLocalConfig('approvalFlow');
|
|
46
|
+
const reportReasons = this.getCommonService().getLocalConfig('reportReasons');
|
|
47
|
+
const result = {
|
|
48
|
+
entryLabel,
|
|
49
|
+
approvalFlow,
|
|
50
|
+
reportReasons,
|
|
51
|
+
...additionalConfiguration,
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
if (viaSettingsPage) {
|
|
55
|
+
const enabledCollections = this.getCommonService().getLocalConfig('enabledCollections');
|
|
56
|
+
const moderatorRoles = this.getCommonService().getLocalConfig('moderatorRoles');
|
|
57
|
+
return {
|
|
58
|
+
...result,
|
|
59
|
+
enabledCollections,
|
|
60
|
+
moderatorRoles,
|
|
61
|
+
isGQLPluginEnabled,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return result;
|
|
35
66
|
},
|
|
36
67
|
|
|
68
|
+
async updateConfig(body) {
|
|
69
|
+
const pluginStore = await this.getCommonService().getPluginStore();
|
|
70
|
+
|
|
71
|
+
await pluginStore.set({ key: 'config', value: body });
|
|
72
|
+
|
|
73
|
+
return this.config();
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
async restoreConfig() {
|
|
77
|
+
const pluginStore = await this.getCommonService().getPluginStore();
|
|
78
|
+
const defaultConfig = this.getCommonService().getLocalConfig();
|
|
79
|
+
|
|
80
|
+
await pluginStore.delete({key: 'config'})
|
|
81
|
+
await pluginStore.set({
|
|
82
|
+
key: 'config',
|
|
83
|
+
value: {
|
|
84
|
+
...defaultConfig,
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
return this.config();
|
|
89
|
+
},
|
|
90
|
+
|
|
37
91
|
// Find all comments
|
|
38
92
|
async findAll({ related, entity, ...query }) {
|
|
39
93
|
const { _q, orderBy, pageSize = 10, page = 1, filters, ...rest } = parseParams(query);
|
|
@@ -8,10 +8,9 @@ const {
|
|
|
8
8
|
isEqualEntity,
|
|
9
9
|
getModelUid,
|
|
10
10
|
getRelatedGroups,
|
|
11
|
-
checkBadWords,
|
|
12
11
|
resolveUserContextError,
|
|
13
12
|
} = require('./utils/functions');
|
|
14
|
-
const { APPROVAL_STATUS, REGEX } = require('./../utils/constants')
|
|
13
|
+
const { APPROVAL_STATUS, REGEX, CONFIG_PARAMS } = require('./../utils/constants')
|
|
15
14
|
|
|
16
15
|
/**
|
|
17
16
|
* Comments Plugin - Client services
|
|
@@ -32,16 +31,14 @@ module.exports = ({ strapi }) => ({
|
|
|
32
31
|
throw new PluginError(400, `Field "related" got incorrect format, use format like "api::<collection name>.<content type name>:<entity id>"`);
|
|
33
32
|
}
|
|
34
33
|
|
|
35
|
-
const [ uid,
|
|
36
|
-
const parsedRelatedId = parseInt(relatedStringId);
|
|
37
|
-
const relatedId = isNumber(parsedRelatedId) ? parsedRelatedId : relatedStringId;
|
|
34
|
+
const [ uid, relatedId ] = await this.getCommonService().parseRelationString(relation);
|
|
38
35
|
|
|
39
36
|
const relatedEntity = await strapi.db.query(uid).findOne(relatedId);
|
|
40
37
|
if (!relatedEntity) {
|
|
41
38
|
throw new PluginError(400, `Relation for field "related" does not exist. Check your payload please.`);
|
|
42
39
|
}
|
|
43
40
|
|
|
44
|
-
const isApprovalFlowEnabled = this.getCommonService().getConfig(
|
|
41
|
+
const isApprovalFlowEnabled = await this.getCommonService().getConfig(CONFIG_PARAMS.APPROVAL_FLOW, []).includes(uid) ||
|
|
45
42
|
relatedEntity.requireCommentsApproval;
|
|
46
43
|
|
|
47
44
|
const linkToThread = !isNil(threadOf) ? await this.getCommonService().findOne({
|
|
@@ -58,7 +55,7 @@ module.exports = ({ strapi }) => ({
|
|
|
58
55
|
throw resolveUserContextError(user);
|
|
59
56
|
}
|
|
60
57
|
|
|
61
|
-
if (checkBadWords(content) && singleRelationFulfilled) {
|
|
58
|
+
if (await this.getCommonService().checkBadWords(content) && singleRelationFulfilled) {
|
|
62
59
|
const { author = {}, ...rest } = data;
|
|
63
60
|
let authorData = {};
|
|
64
61
|
if (validContext && user) {
|
|
@@ -116,6 +113,8 @@ module.exports = ({ strapi }) => ({
|
|
|
116
113
|
throw new PluginError(400, `Request property "relation" got incorrect format, use format like "api::<collection name>.<content type name>:<entity id>"`);
|
|
117
114
|
}
|
|
118
115
|
|
|
116
|
+
await this.getCommonService().parseRelationString(relation);
|
|
117
|
+
|
|
119
118
|
const existingEntity = await this.getCommonService().findOne({
|
|
120
119
|
id,
|
|
121
120
|
related: relation,
|
|
@@ -128,7 +127,7 @@ module.exports = ({ strapi }) => ({
|
|
|
128
127
|
}
|
|
129
128
|
|
|
130
129
|
if (isEqualEntity(existingEntity, data, user) && content) {
|
|
131
|
-
if (checkBadWords(content)) {
|
|
130
|
+
if (await this.getCommonService().checkBadWords(content)) {
|
|
132
131
|
const entity = await strapi.db.query(getModelUid('comment')).update({
|
|
133
132
|
where: { id },
|
|
134
133
|
data: { content },
|
|
@@ -145,6 +144,9 @@ module.exports = ({ strapi }) => ({
|
|
|
145
144
|
if (!this.getCommonService().isValidUserContext(user)) {
|
|
146
145
|
throw resolveUserContextError(user);
|
|
147
146
|
}
|
|
147
|
+
|
|
148
|
+
await this.getCommonService().parseRelationString(relation);
|
|
149
|
+
|
|
148
150
|
const reportAgainstEntity = await this.getCommonService().findOne({
|
|
149
151
|
id,
|
|
150
152
|
related: relation,
|
|
@@ -186,6 +188,8 @@ module.exports = ({ strapi }) => ({
|
|
|
186
188
|
throw new PluginError(403, `You're not allowed to take an action on that entity. Make sure that you've provided proper "authorId" or authenticated your request properly.`);
|
|
187
189
|
}
|
|
188
190
|
|
|
191
|
+
await this.getCommonService().parseRelationString(relation);
|
|
192
|
+
|
|
189
193
|
let entity;
|
|
190
194
|
try {
|
|
191
195
|
const byAuthor = user?.id ? {
|
|
@@ -217,7 +221,7 @@ module.exports = ({ strapi }) => ({
|
|
|
217
221
|
},
|
|
218
222
|
|
|
219
223
|
async sendAbuseReportEmail(reason, content) {
|
|
220
|
-
const rolesToBeNotified = this.getCommonService().getConfig(
|
|
224
|
+
const rolesToBeNotified = await this.getCommonService().getConfig(CONFIG_PARAMS.MODERATOR_ROLES) || ['strapi-super-admin'];
|
|
221
225
|
|
|
222
226
|
const adminUserModel = strapi.db.query('admin::user');
|
|
223
227
|
const emails = await adminUserModel.findMany({
|