Skip to content
This repository was archived by the owner on Jun 27, 2019. It is now read-only.

Commit e95b29c

Browse files
authored
Merge pull request #124 from Human-Connection/blacklist_feature
Blacklist other user accounts
2 parents bf3f51b + 385380d commit e95b29c

File tree

16 files changed

+529
-18
lines changed

16 files changed

+529
-18
lines changed

features/api/post.feature

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Feature: Import a post from an organization and publish it in Human Connection
55

66

77
Background:
8-
Given there is a user in Human Connection with these credentials:
8+
Given this is your user account:
99
| email | password |
1010
| user@example.com | 1234 |
1111

features/api/usersettings.feature

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Feature: Save current newsfeed filters to usersettings
44
In order to see the same selection of content next time I log in
55

66
Background:
7-
Given there is a user in Human Connection with these credentials:
7+
Given this is your user account:
88
| email | password | isVerified |
99
| user@example.com | 1234 | true |
1010

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
Feature: Individual Blacklist
2+
As a user
3+
I want to click on a button to blacklist certain user profiles
4+
In order to stop seeing user content of this account, because I don't like them
5+
6+
Background:
7+
Given this is your user account:
8+
| email | password | isVerified |
9+
| user@example.com | 1234 | true |
10+
And these user accounts exist:
11+
| name | email | isVerified |
12+
| Troll | troll@example.com | true |
13+
| Legit | legit@example.com | true |
14+
And you are authenticated
15+
16+
17+
Scenario: Blacklist a user
18+
When you create your user settings via POST request to "/usersettings" with:
19+
"""
20+
{
21+
"blacklist": ["5b5863e8d47c14323165718b"]
22+
}
23+
"""
24+
Then you will stop seeing posts of the user with id "5b5863e8d47c14323165718b"
25+
26+
Scenario: Filter out contributions of a blacklisted user
27+
Given you blacklisted the user "Troll" before
28+
When this user publishes a post
29+
And you read your current news feed
30+
Then this post is not included
31+
32+
Scenario: Show but conceal comments of a blacklisted user
33+
Given you blacklisted the user "Troll" before
34+
And there is a post "Hello World" by user "Legit"
35+
And the blacklisted user wrote a comment on that post:
36+
"""
37+
I hate you
38+
"""
39+
When you read through the comments of that post
40+
Then you will see a hint instead of a comment:
41+
"""
42+
Comments of this blacklisted user are not visible.
43+
"""
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
Feature: Save preferred language settings
2+
As a user of human connection
3+
You would like to have my preferred language saved
4+
So when I log in the next time, the UI switches to my language automatically
5+
6+
Background:
7+
Given this is your user account:
8+
| email | password | isVerified |
9+
| user@example.com | 1234 | true |
10+
11+
Scenario: Save your language
12+
Given you are authenticated
13+
When you create your user settings via POST request to "/usersettings" with:
14+
"""
15+
{
16+
"uiLanguage": "de"
17+
}
18+
"""
19+
Then your language "de" is stored in your user settings
20+
21+
Scenario: Save your filter settings
22+
Given you are authenticated
23+
When you create your user settings via POST request to "/usersettings" with:
24+
"""
25+
{
26+
"contentLanguages" : [ "en" ],
27+
"uiLanguage" : "en",
28+
"filter": {
29+
"categoryIds": [
30+
"5b310ab8b801653c1eb6c426",
31+
"5b310ab8b801653c1eb6c427",
32+
"5b310ab8b801653c1eb6c428"
33+
]
34+
}
35+
}
36+
"""
37+
Then these category ids are stored in your user settings

features/step_definitions/steps.js

Lines changed: 94 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ let currentUser;
1111
let currentUserPassword;
1212
let httpResponse;
1313
let currentUserAccessToken;
14+
let lastPost;
15+
let blacklistedUser;
1416

1517
function authenticate(email, plainTextPassword) {
1618
const formData = {
@@ -35,10 +37,23 @@ function postRequest(route, body, callback) {
3537
body,
3638
headers: { 'Content-Type': 'application/json' },
3739
};
40+
return request(params, route, callback);
41+
}
42+
43+
function getRequest(route, callback){
44+
const params = {
45+
method: 'get',
46+
headers: { 'Content-Type': 'application/json' },
47+
};
48+
return request(params, route, callback);
49+
}
50+
51+
function request(params, route, callback) {
52+
const requestParams = Object.assign({}, params);
3853
if (currentUserAccessToken) {
39-
params.headers.Authorization = `Bearer ${currentUserAccessToken}`;
54+
requestParams.headers.Authorization = `Bearer ${currentUserAccessToken}`;
4055
}
41-
fetch(`${hcBackendUrl}${route}`, params)
56+
fetch(`${hcBackendUrl}${route}`, requestParams)
4257
.then(response => response.json())
4358
.catch((err) => {
4459
throw (err);
@@ -49,14 +64,21 @@ function postRequest(route, body, callback) {
4964
});
5065
}
5166

52-
Given('there is a user in Human Connection with these credentials:', function (dataTable) {
67+
68+
Given('this is your user account:', function (dataTable) {
5369
const params = dataTable.hashes()[0];
5470
currentUserPassword = params.password;
5571
return this.app.service('users').create(params).then((user) => {
5672
currentUser = user;
5773
});
5874
});
5975

76+
Given('these user accounts exist:', function (dataTable) {
77+
return Promise.all(dataTable.hashes().map(params => {
78+
return this.app.service('users').create(params);
79+
}));
80+
});
81+
6082
Given('you are authenticated', () => authenticate(currentUser.email, currentUserPassword).then((accessToken) => {
6183
currentUserAccessToken = accessToken;
6284
}));
@@ -92,7 +114,7 @@ Then('these category ids are stored in your user settings', function () {
92114
});
93115

94116
Then('your language {string} is stored in your user settings', function (lang) {
95-
return this.app.service('usersettings').find({userId: currentUser._id.toString()}).then((settings) => {
117+
return this.app.service('usersettings').find({query: {userId: currentUser._id.toString()}}).then((settings) => {
96118
expect(settings.total).to.eq(1);
97119
expect(settings.data[0].uiLanguage).to.eq(lang);
98120
});
@@ -109,3 +131,71 @@ When('you create your user settings via POST request to {string} with:', functio
109131
postRequest(route, JSON.stringify(jsonBody), callback);
110132
});
111133

134+
Then('you will stop seeing posts of the user with id {string}', function (blacklistedUserId) {
135+
return this.app.service('usersettings').find({userId: currentUser._id.toString()}).then((settings) => {
136+
expect(settings.total).to.eq(1);
137+
expect(settings.data[0].blacklist).to.be.an('array').that.does.include(blacklistedUserId);
138+
});
139+
});
140+
141+
Given('you blacklisted the user {string} before', async function (blacklistedUserName) {
142+
const res = await this.app.service('users').find({query: {name: blacklistedUserName}});
143+
blacklistedUser = res.data[0];
144+
const params = {
145+
userId: currentUser._id,
146+
blacklist: [blacklistedUser._id]
147+
};
148+
return this.app.service('usersettings').create(params);
149+
});
150+
151+
When('this user publishes a post', function () {
152+
const params = {
153+
title: 'Awful title',
154+
content: 'disgusting content',
155+
language: 'en',
156+
type: 'post',
157+
userId: blacklistedUser._id
158+
};
159+
return this.app.service('contributions').create(params);
160+
});
161+
162+
When('you read your current news feed', function (callback) {
163+
getRequest('/contributions', callback);
164+
});
165+
166+
Then('this post is not included', function () {
167+
expect(httpResponse.data).to.be.an('array').that.is.empty;
168+
});
169+
170+
Given('there is a post {string} by user {string}', async function (postTitle, userName) {
171+
const users = await this.app.service('users').find({ query: {name: userName} });
172+
const user = users.data[0];
173+
const params = {
174+
title: postTitle,
175+
content: 'blah',
176+
language: 'en',
177+
type: 'post',
178+
userId: user._id
179+
};
180+
lastPost = await this.app.service('contributions').create(params);
181+
return lastPost;
182+
});
183+
184+
Given('the blacklisted user wrote a comment on that post:', function (comment) {
185+
const commentParams = {
186+
userId: blacklistedUser._id,
187+
content: comment,
188+
contributionId: lastPost._id
189+
};
190+
return this.app.service('comments').create(commentParams);
191+
});
192+
193+
When('you read through the comments of that post', function (callback) {
194+
getRequest('/comments', callback);
195+
});
196+
197+
Then('you will see a hint instead of a comment:', function (hint) {
198+
const comment = httpResponse.data[0];
199+
expect(comment.content).to.eq(hint);
200+
expect(comment.contentExcerpt).to.eq(hint);
201+
});

server/helper/alter-items.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,4 @@ module.exports = func => hook => {
2020
}
2121
replaceItems(hook, items);
2222
return hook;
23-
};
23+
};
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
const alterItems = require('../helper/alter-items');
2+
3+
const defaults = {
4+
blacklist: [],
5+
data: {
6+
content: 'You have blacklisted this user'
7+
}
8+
};
9+
10+
const handleItem = options => item => {
11+
if (options.blacklist){
12+
let found = options.blacklist.find((userId) => {
13+
return String(userId) === item.userId;
14+
});
15+
if (found){
16+
item = {...item, ...options.data};
17+
}
18+
}
19+
return item;
20+
};
21+
22+
module.exports = function concealBlacklistedData(options = defaults) {
23+
return async function(hook){
24+
if (hook.method === 'find' || hook.id === null) {
25+
const authenticatedUser = hook.params.user;
26+
if (!authenticatedUser){
27+
return hook;
28+
}
29+
const usersettings = await hook.app.service('usersettings').find({query: {userId: authenticatedUser._id}});
30+
if (usersettings.total <= 0){
31+
return hook;
32+
}
33+
options.blacklist = usersettings.data[0].blacklist;
34+
return alterItems(handleItem(options))(hook);
35+
}
36+
37+
return hook;
38+
};
39+
};
40+

server/hooks/exclude-blacklisted.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
module.exports = function excludeBlacklisted() {
2+
return async function (hook) {
3+
if (hook.type !== 'before') {
4+
throw new Error('The \'excludeBlacklisted\' hook should only be used as a \'before\' hook.');
5+
}
6+
7+
if (hook.method === 'find' || hook.id === null) {
8+
const authenticatedUser = hook.params.user;
9+
if (!authenticatedUser){
10+
return hook;
11+
}
12+
const usersettings = await hook.app.service('usersettings').find({query: {userId: authenticatedUser._id}});
13+
if (usersettings.total <= 0){
14+
return hook;
15+
}
16+
const blacklist = usersettings.data[0].blacklist;
17+
hook.params.query.userId = {$nin: blacklist};
18+
return hook;
19+
}
20+
21+
return hook;
22+
};
23+
};

server/models/usersettings.model.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ module.exports = function (app) {
77
const mongooseClient = app.get('mongooseClient');
88
const usersettings = new mongooseClient.Schema({
99
userId: {type: String, required: true, unique: true},
10+
blacklist: {type: Array, default: []},
1011
uiLanguage: {type: String, required: true},
1112
contentLanguages: {type: Array, default: []},
1213
filter: {

server/services/comments/comments.hooks.js

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
const { authenticate } = require('@feathersjs/authentication').hooks;
2-
const { unless, isProvider, populate, discard, softDelete, setNow } = require('feathers-hooks-common');
2+
const { iff, unless, isProvider, populate, discard, softDelete, setNow } = require('feathers-hooks-common');
33
const { protect } = require('@feathersjs/authentication-local').hooks;
44
const {
55
//queryWithCurrentUser,
@@ -10,6 +10,7 @@ const {
1010
const { isVerified } = require('feathers-authentication-management').hooks;
1111
const createExcerpt = require('../../hooks/create-excerpt');
1212
const patchDeletedData = require('../../hooks/patch-deleted-data');
13+
const concealBlacklistedData = require('../../hooks/conceal-blacklisted-data');
1314
const keepDeletedDataFields = require('../../hooks/keep-deleted-data-fields');
1415
const createNotifications = require('./hooks/create-notifications');
1516
const createMentionNotifications = require('./hooks/create-mention-notifications');
@@ -41,12 +42,21 @@ module.exports = {
4142
],
4243
find: [
4344
// We want to deleted comments to show up
45+
iff(
46+
hook => hook.params.headers && hook.params.headers.authorization,
47+
authenticate('jwt')
48+
),
4449
hook => {
4550
delete hook.params.query.deleted;
4651
return hook;
4752
}
4853
],
49-
get: [],
54+
get: [
55+
iff(
56+
hook => hook.params.headers && hook.params.headers.authorization,
57+
authenticate('jwt')
58+
)
59+
],
5060
create: [
5161
authenticate('jwt'),
5262
// Allow seeder to seed comments
@@ -109,10 +119,24 @@ module.exports = {
109119
],
110120
find: [
111121
populate({ schema: userSchema }),
112-
protect('content', 'badgeIds')
122+
protect('content', 'badgeIds'),
123+
concealBlacklistedData({
124+
data: {
125+
content: 'Comments of this blacklisted user are not visible.',
126+
contentExcerpt: 'Comments of this blacklisted user are not visible.',
127+
hasMore: false
128+
}
129+
})
113130
],
114131
get: [
115-
populate({ schema: userSchema })
132+
populate({ schema: userSchema }),
133+
concealBlacklistedData({
134+
data: {
135+
content: 'Comments of this blacklisted user are not visible.',
136+
contentExcerpt: 'Comments of this blacklisted user are not visible.',
137+
hasMore: false
138+
}
139+
})
116140
],
117141
create: [
118142
populate({ schema: userSchema }),

0 commit comments

Comments
 (0)