merge master

This commit is contained in:
riley
2017-05-16 16:33:41 -06:00
219 changed files with 3845 additions and 1847 deletions
+1 -1
View File
@@ -11,7 +11,7 @@ describe('graph.mutations.addCommentTag', () => {
let comment;
beforeEach(async () => {
await SettingsService.init();
comment = await CommentsService.publicCreate({body: `hello there! ${ String(Math.random()).slice(2)}`});
comment = await CommentsService.publicCreate({body: `hello there! ${String(Math.random()).slice(2)}`});
});
const query = `
+262
View File
@@ -0,0 +1,262 @@
const expect = require('chai').expect;
const {graphql} = require('graphql');
const timekeeper = require('timekeeper');
const schema = require('../../../../graph/schema');
const Context = require('../../../../graph/context');
const UsersService = require('../../../../services/users');
const AssetModel = require('../../../../models/asset');
const SettingsService = require('../../../../services/settings');
const CommentsService = require('../../../../services/comments');
describe('graph.mutations.editComment', () => {
let asset;
let user;
let settings;
beforeEach(async () => {
timekeeper.reset();
settings = await SettingsService.init();
asset = await AssetModel.create({});
user = await UsersService.createLocalUser(
'usernameA@example.com', 'password', 'usernameA');
});
afterEach(async () => {
await asset.remove();
await user.remove();
await settings.remove();
});
const editCommentMutation = `
mutation EditComment ($id: ID!, $asset_id: ID!, $edit: EditCommentInput) {
editComment(id:$id, asset_id:$asset_id, edit:$edit) {
errors {
translation_key
}
}
}
`;
it('a user can edit their own comment', async () => {
const context = new Context({user});
const testStartedAt = new Date();
const comment = await CommentsService.publicCreate({
asset_id: asset.id,
author_id: user.id,
body: `hello there! ${String(Math.random()).slice(2)}`,
});
// body_history should be there
expect(comment.body_history.length).to.equal(1);
expect(comment.body_history[0].body).to.equal(comment.body);
expect(comment.body_history[0].created_at).to.be.instanceOf(Date);
expect(comment.body_history[0].created_at).to.be.at.least(testStartedAt);
// now edit
const newBody = 'I have been edited.';
const response = await graphql(schema, editCommentMutation, {}, context, {
id: comment.id,
asset_id: asset.id,
edit: {
body: newBody
}
});
if (response.errors && response.errors.length) {
console.error(response.errors);
}
expect(response.errors).to.be.empty;
if (response.data.editComment.errors && response.data.editComment.errors.length > 0) {
console.error(response.data.editComment.errors);
}
expect(response.data.editComment.errors).to.be.null;
// assert body has changed
const commentAfterEdit = await CommentsService.findById(comment.id);
expect(commentAfterEdit.body).to.equal(newBody);
expect(commentAfterEdit.body_history).to.be.instanceOf(Array);
expect(commentAfterEdit.body_history.length).to.equal(2);
expect(commentAfterEdit.body_history[1].body).to.equal(newBody);
expect(commentAfterEdit.body_history[1].created_at).to.be.instanceOf(Date);
expect(commentAfterEdit.body_history[1].created_at).to.be.at.least(testStartedAt);
expect(commentAfterEdit.status).to.equal('NONE');
});
it('A user can\'t edit their comment outside of the edit comment time window', async () => {
const comment = await CommentsService.publicCreate({
asset_id: asset.id,
author_id: user.id,
body: `hello there! ${String(Math.random()).slice(2)}`,
});
const now = new Date();
const oneHourFromNow = new Date(new Date(now).setHours(now.getHours() + 1));
timekeeper.travel(oneHourFromNow);
const newBody = 'This body should never be set';
const context = new Context({user});
const response = await graphql(schema, editCommentMutation, {}, context, {
id: comment.id,
asset_id: asset.id,
edit: {
body: newBody
}
});
if (response.errors && response.errors.length > 0) {
console.error(response.errors);
}
expect(response.errors).to.be.empty;
expect(response.data.editComment.errors).to.not.be.empty;
expect(response.data.editComment.errors[0].translation_key).to.equal('EDIT_WINDOW_ENDED');
const commentAfterEdit = await CommentsService.findById(comment.id);
// it *hasn't* changed from the original
expect(commentAfterEdit.body).to.equal(comment.body);
});
it('A user can\'t edit someone else\'s comment', async () => {
const comment = await CommentsService.publicCreate({
asset_id: asset.id,
author_id: user.id,
body: `hello there! ${String(Math.random()).slice(2)}`,
});
const userB = await UsersService.createLocalUser(
'usernameB@example.com', 'password', 'usernameB');
const newBody = 'This body should never be set';
const context = new Context({user: userB});
const response = await graphql(schema, editCommentMutation, {}, context, {
id: comment.id,
asset_id: asset.id,
edit: {
body: newBody
}
});
expect(response.errors).to.be.empty;
expect(response.data.editComment.errors).to.not.be.empty;
expect(response.data.editComment.errors[0].translation_key).to.equal('NOT_AUTHORIZED');
const commentAfterEdit = await CommentsService.findById(comment.id);
// it *hasn't* changed from the original
expect(commentAfterEdit.body).to.equal(comment.body);
});
it('A user Can\'t edit a comment id that doesn\'t exist', async () => {
const fakeCommentId = 'nooooope';
const newBody = 'This body should never be set';
const context = new Context({user});
const response = await graphql(schema, editCommentMutation, {}, context, {
id: fakeCommentId,
asset_id: asset.id,
edit: {
body: newBody
}
});
if (response.errors && response.errors.length > 0) {
console.error(response.errors);
}
expect(response.errors).to.be.empty;
expect(response.data.editComment.errors[0].translation_key).to.equal('NOT_FOUND');
});
const bannedWord = 'BANNED_WORD';
[
{
description: 'premod: editing a REJECTED comment sets back to PREMOD',
settings: {
moderation: 'PRE',
},
beforeEdit: {
body: 'I was offensive and thus REJECTED',
status: 'REJECTED',
},
edit: {
body: 'I have been edited to be less offensive',
},
afterEdit: {
status: 'PREMOD',
},
},
{
description: 'editing an ACCEPTED comment to add a bad word sets status to REJECTED',
settings: {
moderation: 'POST',
wordlist: {
banned: [bannedWord]
}
},
beforeEdit: {
body: 'I\'m a perfectly acceptable comment',
status: 'ACCEPTED',
},
edit: {
body: `I have been sneakily edited to add a banned word: ${bannedWord}`
},
afterEdit: {
status: 'REJECTED',
},
},
{
description: 'postmod: editing a REJECTED comment with banned word to remove banned word sets status to NONE',
settings: {
moderation: 'POST',
wordlist: {
banned: [bannedWord]
}
},
beforeEdit: {
body: `I'm a rejected comment with bad word ${bannedWord}`,
status: 'REJECTED',
},
edit: {
body: 'I have been edited to remove the bad word'
},
afterEdit: {
status: 'NONE',
},
},
{
description: 'postmod + premodLinksEnable: editing an ACCEPTED comment to add a link sets status to PREMOD',
settings: {
moderation: 'POST',
premodLinksEnable: true,
},
beforeEdit: {
body: 'I\'m a perfectly acceptable comment',
status: 'ACCEPTED',
},
edit: {
body: 'I have been edited to add a link: https://coralproject.net/'
},
afterEdit: {
status: 'PREMOD',
},
},
].forEach(({description, settings, beforeEdit, edit, afterEdit, only}) => {
const test = only ? it.only : it;
test(description, async () => {
await SettingsService.update(settings);
const context = new Context({user});
const comment = await CommentsService.publicCreate(Object.assign(
{
asset_id: asset.id,
author_id: user.id,
},
beforeEdit,
));
// now edit
const newBody = edit.body;
const response = await graphql(schema, editCommentMutation, {}, context, {
id: comment.id,
asset_id: asset.id,
edit: {
body: newBody
}
});
if (response.errors && response.errors.length) {console.error(response.errors);}
expect(response.errors).to.be.empty;
const commentAfterEdit = await CommentsService.findById(comment.id);
expect(commentAfterEdit.body).to.equal(newBody);
expect(commentAfterEdit.status).to.equal(afterEdit.status);
});
});
});
+34 -16
View File
@@ -18,9 +18,11 @@ const ignoreUserMutation = `
const getMyIgnoredUsersQuery = `
query myIgnoredUsers {
myIgnoredUsers {
id,
username
me {
ignoredUsers {
id
username
}
}
}
`;
@@ -30,27 +32,33 @@ describe('graph.mutations.ignoreUser', () => {
await SettingsService.init();
});
// @TODO (bengo) - test a user can't ignore themselves
it('users can ignoreUser', async () => {
const user = await UsersService.createLocalUser('usernameA@example.com', 'password', 'usernameA');
let currentUser = await UsersService.createLocalUser('usernameA@example.com', 'password', 'usernameA');
const userToIgnore = await UsersService.createLocalUser('usernameB@example.com', 'password', 'usernameB');
const context = new Context({user});
let context = new Context({user: currentUser});
const ignoreUserResponse = await graphql(schema, ignoreUserMutation, {}, context, {id: userToIgnore.id});
if (ignoreUserResponse.errors && ignoreUserResponse.errors.length) {
console.error(ignoreUserResponse.errors);
}
expect(ignoreUserResponse.errors).to.be.empty;
// Refresh the user from the database and create the new context for the
// request.
currentUser = await UsersService.findById(currentUser.id);
context = new Context({user: currentUser});
// now check my ignored users
const myIgnoredUsersResponse = await graphql(schema, getMyIgnoredUsersQuery, {}, context, {});
if (myIgnoredUsersResponse.errors && myIgnoredUsersResponse.errors.length) {
console.error(myIgnoredUsersResponse.errors);
}
expect(myIgnoredUsersResponse.errors).to.be.empty;
const myIgnoredUsers = myIgnoredUsersResponse.data.myIgnoredUsers;
expect(myIgnoredUsers.length).to.equal(1);
expect(myIgnoredUsers[0].id).to.equal(userToIgnore.id);
expect(myIgnoredUsers[0].username).to.equal(userToIgnore.username);
const ignoredUsers = myIgnoredUsersResponse.data.me.ignoredUsers;
expect(ignoredUsers.length).to.equal(1);
expect(ignoredUsers[0].id).to.equal(userToIgnore.id);
expect(ignoredUsers[0].username).to.equal(userToIgnore.username);
});
it('users cannot ignore themselves', async () => {
@@ -65,7 +73,7 @@ describe('graph.mutations.ignoreUser', () => {
console.error(myIgnoredUsersResponse.errors);
}
expect(myIgnoredUsersResponse.errors).to.be.empty;
const myIgnoredUsers = myIgnoredUsersResponse.data.myIgnoredUsers;
const myIgnoredUsers = myIgnoredUsersResponse.data.me.ignoredUsers;
expect(myIgnoredUsers.length).to.equal(0);
});
@@ -81,22 +89,27 @@ describe('graph.mutations.stopIgnoringUser', () => {
// We're going to ignore 2 users,
// then stopIgnoring 1 of them
// then assert myIgnoredUsers only lists the one remaining
const user = await UsersService.createLocalUser('usernameA@example.com', 'password', 'usernameA');
let currentUser = await UsersService.createLocalUser('usernameA@example.com', 'password', 'usernameA');
const usersToIgnore = await Promise.all([
UsersService.createLocalUser('usernameB@example.com', 'password', 'usernameB'),
UsersService.createLocalUser('usernameC@example.com', 'password', 'usernameC'),
]);
const context = new Context({user});
let context = new Context({user: currentUser});
// ignore two users
const ignoreUserResponses = await Promise.all(usersToIgnore.map(u => graphql(schema, ignoreUserMutation, {}, context, {id: u.id})));
ignoreUserResponses.forEach(response => {
const ignoreUserResponses = await Promise.all(usersToIgnore.map((u) => graphql(schema, ignoreUserMutation, {}, context, {id: u.id})));
ignoreUserResponses.forEach((response) => {
if (response.errors && response.errors.length) {
console.error(response.errors);
}
expect(response.errors).to.be.empty;
});
// Refresh the user from the database and create the new context for the
// request.
currentUser = await UsersService.findById(currentUser.id);
context = new Context({user: currentUser});
const stopIgnoringUserMutation = `
mutation stopIgnoringUser ($id: ID!) {
stopIgnoringUser(id:$id) {
@@ -114,13 +127,18 @@ describe('graph.mutations.stopIgnoringUser', () => {
}
expect(stopIgnoringUserResponse.errors).to.be.empty;
// Refresh the user from the database and create the new context for the
// request.
currentUser = await UsersService.findById(currentUser.id);
context = new Context({user: currentUser});
// now check my ignored users
const myIgnoredUsersResponse = await graphql(schema, getMyIgnoredUsersQuery, {}, context, {});
if (myIgnoredUsersResponse.errors && myIgnoredUsersResponse.errors.length) {
console.error(myIgnoredUsersResponse.errors);
}
expect(myIgnoredUsersResponse.errors).to.be.empty;
const myIgnoredUsers = myIgnoredUsersResponse.data.myIgnoredUsers;
const myIgnoredUsers = myIgnoredUsersResponse.data.me.ignoredUsers;
expect(myIgnoredUsers.length).to.equal(1);
expect(myIgnoredUsers[0].id).to.equal(usersToIgnore[1].id);
expect(myIgnoredUsers[0].username).to.equal(usersToIgnore[1].username);
@@ -11,7 +11,7 @@ describe('graph.mutations.removeCommentTag', () => {
let comment;
beforeEach(async () => {
await SettingsService.init();
comment = await CommentsService.publicCreate({body: `hello there! ${ String(Math.random()).slice(2)}`});
comment = await CommentsService.publicCreate({body: `hello there! ${String(Math.random()).slice(2)}`});
});
const query = `
+57 -52
View File
@@ -9,85 +9,90 @@ const Asset = require('../../../../models/asset');
const CommentsService = require('../../../../services/comments');
describe('graph.queries.asset', () => {
let asset, users;
beforeEach(async () => {
await SettingsService.init();
asset = await Asset.create({id: '1', url: 'https://example.com'});
users = await UsersService.createLocalUsers([
{
email: 'usernameA@example.com',
password: 'password',
username: 'usernameA'
},
{
email: 'usernameB@example.com',
password: 'password',
username: 'usernameB'
},
{
email: 'usernameC@example.com',
password: 'password',
username: 'usernameC'
}
]);
});
it('can get comments edge', async () => {
const assetId = 'fakeAssetId';
const assetUrl = 'https://bengo.is';
await Asset.create({id: assetId, url: assetUrl});
const user = await UsersService.createLocalUser('usernameA@example.com', 'password', 'usernameA');
const context = new Context({user});
const context = new Context({user: users[0]});
await CommentsService.publicCreate([1, 2].map(() => ({
author_id: user.id,
asset_id: assetId,
body: `hello there! ${ String(Math.random()).slice(2)}`,
author_id: users[0].id,
asset_id: asset.id,
body: `hello there! ${String(Math.random()).slice(2)}`,
})));
const assetCommentsQuery = `
query assetCommentsQuery($assetId: ID!, $assetUrl: String!) {
asset(id: $assetId, url: $assetUrl) {
query assetCommentsQuery($id: ID!) {
asset(id: $id) {
comments(limit: 10) {
id,
body,
id
body
}
}
}
`;
const assetCommentsResponse = await graphql(schema, assetCommentsQuery, {}, context, {assetId, assetUrl});
const comments = assetCommentsResponse.data.asset.comments;
const res = await graphql(schema, assetCommentsQuery, {}, context, {id: asset.id});
expect(res.erros).is.empty;
const comments = res.data.asset.comments;
expect(comments.length).to.equal(2);
});
it('can query comments edge to exclude comments ignored by user', async () => {
const assetId = 'fakeAssetId1';
const assetUrl = 'https://bengo.is/1';
await Asset.create({id: assetId, url: assetUrl});
const context = new Context({user: users[0]});
const userA = await UsersService.createLocalUser('usernameA@example.com', 'password', 'usernameA');
const userB = await UsersService.createLocalUser('usernameB@example.com', 'password', 'usernameB');
const userC = await UsersService.createLocalUser('usernameC@example.com', 'password', 'usernameC');
const context = new Context({user: userA});
// create 2 comments each for userB, userC
await Promise.all([userB, userC].map(user => CommentsService.publicCreate([1, 2].map(() => ({
await Promise.all(users.slice(1, 3).map((user) => CommentsService.publicCreate({
author_id: user.id,
asset_id: assetId,
body: `hello there! ${ String(Math.random()).slice(2)}`,
})))));
asset_id: asset.id,
body: `hello there! ${String(Math.random()).slice(2)}`,
})));
// Add the second user to the list of ignored users.
context.user.ignoresUsers.push(users[1].id);
// ignore userB
const ignoreUserMutation = `
mutation ignoreUser ($id: ID!) {
ignoreUser(id:$id) {
errors {
translation_key
}
}
}
`;
const ignoreUserResponse = await graphql(schema, ignoreUserMutation, {}, context, {id: userB.id});
if (ignoreUserResponse.errors && ignoreUserResponse.errors.length) {
console.error(ignoreUserResponse.errors);
}
expect(ignoreUserResponse.errors).to.be.empty;
const assetCommentsWithoutIgnoredQuery = `
query assetCommentsQuery($assetId: ID!, $assetUrl: String!, $excludeIgnored: Boolean!) {
asset(id: $assetId, url: $assetUrl) {
const query = `
query assetCommentsQuery($id: ID!, $url: String!, $excludeIgnored: Boolean!) {
asset(id: $id, url: $url) {
comments(limit: 10, excludeIgnored: $excludeIgnored) {
id,
body,
id
body
}
}
}
`;
const assetCommentsResponse = await graphql(schema, assetCommentsWithoutIgnoredQuery, {}, context, {assetId, assetUrl, excludeIgnored: true});
const comments = assetCommentsResponse.data.asset.comments;
expect(comments.length).to.equal(2);
{
const res = await graphql(schema, query, {}, context, {
id: asset.id,
url: asset.url,
excludeIgnored: true
});
if (res.errors && res.errors.length) {
console.error(res.errors);
}
expect(res.errors).is.empty;
const comments = res.data.asset.comments;
expect(comments.length).to.equal(1);
}
});
});
+2 -2
View File
@@ -204,7 +204,7 @@ describe('services.CommentsService', () => {
it('should return all comments if admin', () => {
return CommentsService
.findByUserId('456', true)
.then(comments => {
.then((comments) => {
expect(comments).to.have.length(4);
});
});
@@ -212,7 +212,7 @@ describe('services.CommentsService', () => {
it('should not return premod and rejected comments if not admin', () => {
return CommentsService
.findByUserId('456')
.then(comments => {
.then((comments) => {
expect(comments).to.have.length(1);
});
});
+3 -3
View File
@@ -7,13 +7,13 @@ describe('services.SettingsService', () => {
describe('#retrieve()', () => {
it('should have a moderation field defined', () => {
return SettingsService.retrieve().then(settings => {
return SettingsService.retrieve().then((settings) => {
expect(settings).to.have.property('moderation').and.to.equal('PRE');
});
});
it('should have two infoBox fields defined', () => {
return SettingsService.retrieve().then(settings => {
return SettingsService.retrieve().then((settings) => {
expect(settings).to.have.property('infoBoxEnable').and.to.equal(false);
expect(settings).to.have.property('infoBoxContent').and.to.equal('');
});
@@ -23,7 +23,7 @@ describe('services.SettingsService', () => {
describe('#update()', () => {
it('should update the settings with a passed object', () => {
const mockSettings = {moderation: 'POST', infoBoxEnable: true, infoBoxContent: 'yeah'};
return SettingsService.update(mockSettings).then(updatedSettings => {
return SettingsService.update(mockSettings).then((updatedSettings) => {
expect(updatedSettings).to.be.an('object');
expect(updatedSettings).to.have.property('moderation').and.to.equal('POST');
expect(updatedSettings).to.have.property('infoBoxEnable', true);
+2 -5
View File
@@ -170,18 +170,15 @@ describe('services.UsersService', () => {
});
describe('#ignoreUser', () => {
// @TODO: assert cannot ignore yourself
it('should add user id to ignoredUsers set', async () => {
const user = mockUsers[0];
const usersToIgnore = [mockUsers[1], mockUsers[2]];
await UsersService.ignoreUsers(user.id, usersToIgnore.map(u => u.id));
await UsersService.ignoreUsers(user.id, usersToIgnore.map((u) => u.id));
const userAfterIgnoring = await UsersService.findById(user.id);
expect(userAfterIgnoring.ignoresUsers.length).to.equal(2);
// ignore same user another time, make sure it's not added to the list.
await UsersService.ignoreUsers(user.id, usersToIgnore.slice(0, 1).map(u => u.id));
await UsersService.ignoreUsers(user.id, usersToIgnore.slice(0, 1).map((u) => u.id));
const userAfterIgnoring2 = await UsersService.findById(user.id);
expect(userAfterIgnoring2.ignoresUsers.length).to.equal(2);
});