Const, service, and model updates

- Updated enum values to be uppercase
- Updated services to expose service models
- Updated models to only export the mongoose model
- Moved all mongoose static methods over to new services
- Updated tests to refelct new setup

BREAKING

- Status that were uppercased (caps) have caused issues with the
  admin pages
This commit is contained in:
Wyatt Johnson
2017-01-24 12:10:32 -07:00
parent 0994023864
commit a7e9c0c776
54 changed files with 1831 additions and 2499 deletions
+5 -4
View File
@@ -8,12 +8,13 @@ const expect = chai.expect;
chai.should();
chai.use(require('chai-http'));
const Asset = require('../../../../models/asset');
const AssetModel = require('../../../../models/asset');
const AssetsService = require('../../../../services/assets');
describe('/api/v1/assets', () => {
beforeEach(() => {
return Asset.create([
return AssetModel.create([
{
url: 'https://coralproject.net/news/asset1',
title: 'Asset 1',
@@ -121,7 +122,7 @@ describe('/api/v1/assets', () => {
const today = Date.now();
return Asset.findOrCreateByUrl('http://test.com')
return AssetsService.findOrCreateByUrl('http://test.com')
.then((asset) => {
expect(asset).to.have.property('isClosed', null);
expect(asset).to.have.property('closedAt', null);
@@ -135,7 +136,7 @@ describe('/api/v1/assets', () => {
expect(res).to.have.status(204);
return Asset.findByUrl('http://test.com');
return AssetsService.findByUrl('http://test.com');
})
.then((asset) => {
expect(asset).to.have.property('isClosed', true);
+7 -7
View File
@@ -4,7 +4,7 @@ const expect = chai.expect;
chai.use(require('chai-http'));
const User = require('../../../../models/user');
const UsersService = require('../../../../services/users');
describe('/api/v1/auth', () => {
describe('#get', () => {
@@ -19,15 +19,15 @@ describe('/api/v1/auth', () => {
});
});
const Setting = require('../../../../models/setting');
const SettingsService = require('../../../../services/settings');
describe('/api/v1/auth/local', () => {
let mockUser;
beforeEach(() => {
const settings = {requireEmailConfirmation: false, wordlist: {banned: ['bad'], suspect: ['naughty']}};
return Setting.init(settings).then(() => {
return User.createLocalUser('maria@gmail.com', 'password!', 'Maria')
return SettingsService.init(settings).then(() => {
return UsersService.createLocalUser('maria@gmail.com', 'password!', 'Maria')
.then((user) => {
mockUser = user;
});
@@ -66,7 +66,7 @@ describe('/api/v1/auth/local', () => {
describe('email confirmation enabled', () => {
beforeEach(() => Setting.init({requireEmailConfirmation: true}));
beforeEach(() => SettingsService.init({requireEmailConfirmation: true}));
describe('#post', () => {
it('should not allow a login from a user that is not confirmed', () => {
@@ -76,9 +76,9 @@ describe('/api/v1/auth/local', () => {
.catch((err) => {
err.response.should.have.status(401);
return User.createEmailConfirmToken(mockUser.id, mockUser.profiles[0].id);
return UsersService.createEmailConfirmToken(mockUser.id, mockUser.profiles[0].id);
})
.then(User.verifyEmailConfirmation)
.then(UsersService.verifyEmailConfirmation)
.then(() => {
return chai.request(app)
.post('/api/v1/auth/local')
+43 -206
View File
@@ -8,18 +8,19 @@ const expect = chai.expect;
chai.should();
chai.use(require('chai-http'));
const Comment = require('../../../../models/comment');
const Asset = require('../../../../models/asset');
const Action = require('../../../../models/action');
const User = require('../../../../models/user');
const CommentModel = require('../../../../models/comment');
const ActionModel = require('../../../../models/action');
const CommentsService = require('../../../../services/comments');
const UsersService = require('../../../../services/users');
const SettingsService = require('../../../../services/settings');
const Setting = require('../../../../models/setting');
const settings = {id: '1', moderation: 'pre', wordlist: {banned: ['bad words'], suspect: ['suspect words']}};
describe('/api/v1/comments', () => {
// Ensure that the settings are always available.
beforeEach(() => Setting.init(settings));
beforeEach(() => SettingsService.init(settings));
describe('#get', () => {
const comments = [{
@@ -34,16 +35,16 @@ describe('/api/v1/comments', () => {
body: 'comment 20',
asset_id: 'asset',
author_id: '456',
status: 'rejected',
status: 'REJECTED',
status_history: [{
type: 'rejected'
type: 'REJECTED'
}]
}, {
body: 'comment 30',
asset_id: '456',
status: 'accepted',
status: 'ACCEPTED',
status_history: [{
type: 'accepted'
type: 'ACCEPTED'
}]
}];
@@ -58,18 +59,18 @@ describe('/api/v1/comments', () => {
}];
const actions = [{
action_type: 'flag',
action_type: 'FLAG',
item_id: 'abc',
item_type: 'comments'
item_type: 'COMMENTS'
}, {
action_type: 'like',
action_type: 'LIKE',
item_id: 'hij',
item_type: 'comments'
item_type: 'COMMENTS'
}];
beforeEach(() => {
return Promise.all([
Comment.create(comments).then((newComments) => {
CommentModel.create(comments).then((newComments) => {
newComments.forEach((comment, i) => {
comments[i].id = comment.id;
});
@@ -77,9 +78,9 @@ describe('/api/v1/comments', () => {
actions[0].item_id = comments[0].id;
actions[1].item_id = comments[1].id;
return Action.create(actions);
return ActionModel.create(actions);
}),
User.createLocalUsers(users)
UsersService.createLocalUsers(users)
]);
});
@@ -119,7 +120,7 @@ describe('/api/v1/comments', () => {
it('should return all the rejected comments', () => {
return chai.request(app)
.get('/api/v1/comments?status=rejected')
.get('/api/v1/comments?status=REJECTED')
.set(passport.inject({roles: ['admin']}))
.then((res) => {
expect(res).to.have.status(200);
@@ -131,7 +132,7 @@ describe('/api/v1/comments', () => {
it('should return all the approved comments', () => {
return chai.request(app)
.get('/api/v1/comments?status=accepted')
.get('/api/v1/comments?status=ACCEPTED')
.set(passport.inject({roles: ['admin']}))
.then((res) => {
expect(res).to.have.status(200);
@@ -142,7 +143,7 @@ describe('/api/v1/comments', () => {
it('should return all the new comments', () => {
return chai.request(app)
.get('/api/v1/comments?status=new')
.get('/api/v1/comments?status=NEW')
.set(passport.inject({roles: ['admin']}))
.then((res) => {
expect(res).to.have.status(200);
@@ -152,7 +153,7 @@ describe('/api/v1/comments', () => {
it('should return all the flagged comments', () => {
return chai.request(app)
.get('/api/v1/comments?action_type=flag')
.get('/api/v1/comments?action_type=FLAG')
.set(passport.inject({roles: ['admin']}))
.then((res) => {
expect(res).to.have.status(200);
@@ -162,174 +163,6 @@ describe('/api/v1/comments', () => {
});
});
});
describe('#post', () => {
let asset_id;
let postmod_asset_id;
beforeEach(() => Promise.all([
Asset.findOrCreateByUrl('https://coralproject.net/section/article-is-the-best').then((asset) => {
// Update the asset id.
asset_id = asset.id;
}),
Asset.findOrCreateByUrl('https://coralproject.net/section/postmod-article-is-the-best').then((asset) => {
// Update the asset id.
postmod_asset_id = asset.id;
return Asset.overrideSettings(postmod_asset_id, {moderation: 'post'});
}),
]));
it('should create a comment', () => {
return chai.request(app)
.post('/api/v1/comments')
.set(passport.inject({roles: []}))
.send({'body': 'Something body.', 'author_id': '123', 'asset_id': asset_id, 'parent_id': ''})
.then((res) => {
expect(res).to.have.status(201);
expect(res.body).to.have.property('id');
expect(res.body).to.have.property('status', 'premod');
});
});
it('should create a comment with a rejected status if it contains a bad word', () => {
return chai.request(app).post('/api/v1/comments')
.set(passport.inject({roles: []}))
.send({'body': 'bad words are the baddest', 'author_id': '123', 'asset_id': asset_id, 'parent_id': ''})
.then((res) => {
expect(res).to.have.status(201);
expect(res.body).to.have.property('id');
expect(res.body).to.have.property('status', 'rejected');
});
});
it('should create a comment with no status and a flag if it contains a suspected word', () => {
return chai.request(app).post('/api/v1/comments')
.set(passport.inject({roles: []}))
.send({'body': 'suspect words are the most suspicious', 'author_id': '123', 'asset_id': postmod_asset_id, 'parent_id': ''})
.then((res) => {
expect(res).to.have.status(201);
expect(res.body).to.have.property('id');
expect(res.body).to.have.property('status', null);
return Promise.all([
res.body,
Action.findByType('flag', 'comments')
]);
})
.then(([comment, actions]) => {
expect(actions).to.have.length(1);
let action = actions[0];
expect(action).to.have.property('item_id', comment.id);
expect(action).to.have.property('metadata');
expect(action.metadata).to.have.property('field', 'body');
expect(action.metadata).to.have.property('details', 'Matched suspect word filters.');
});
});
it('should create a comment with a premod status if it\'s asset is has pre-moderation enabled', () => {
return Asset
.findOrCreateByUrl('https://coralproject.net/article1')
.then((asset) => {
return Asset
.overrideSettings(asset.id, {moderation: 'pre'})
.then(() => asset);
})
.then((asset) => {
return chai.request(app).post('/api/v1/comments')
.set(passport.inject({roles: []}))
.send({'body': 'Something body.', 'author_id': '123', 'asset_id': asset.id, 'parent_id': ''});
})
.then((res) => {
expect(res).to.have.status(201);
expect(res.body).to.have.property('id');
expect(res.body).to.have.property('asset_id');
expect(res.body).to.have.property('status', 'premod');
});
});
it('should create a comment with null status if it\'s asset is has post-moderation enabled', () => {
return Asset
.findOrCreateByUrl('https://coralproject.net/article1')
.then((asset) => {
return Asset
.overrideSettings(asset.id, {moderation: 'post'})
.then(() => asset);
})
.then((asset) => {
return chai.request(app).post('/api/v1/comments')
.set(passport.inject({roles: []}))
.send({'body': 'Something body.', 'author_id': '123', 'asset_id': asset.id, 'parent_id': ''});
})
.then((res) => {
expect(res).to.have.status(201);
expect(res.body).to.have.property('id');
expect(res.body).to.have.property('asset_id');
expect(res.body).to.have.property('status', null);
});
});
it('should create a rejected comment if the body is above the character count', () => {
return Asset
.findOrCreateByUrl('https://coralproject.net/article1')
.then((asset) => {
return Asset
.overrideSettings(asset.id, {charCountEnable: true, charCount: 10})
.then(() => asset);
})
.then((asset) => {
return chai.request(app).post('/api/v1/comments')
.set(passport.inject({roles: []}))
.send({'body': 'This is way way way way way too long.', 'author_id': '123', 'asset_id': asset.id, 'parent_id': ''});
})
.then((res) => {
expect(res).to.have.status(201);
expect(res.body).to.have.property('id');
expect(res.body).to.have.property('asset_id');
expect(res.body).to.have.property('status', 'rejected');
});
});
it('shouldn\'t create a comment when the asset has expired commenting', () => {
return Asset.create({
closedAt: new Date().setDate(0),
closedMessage: 'tests said expired!'
})
.then((asset) => {
return chai.request(app).post('/api/v1/comments')
.set(passport.inject({roles: []}))
.send({'body': 'Something body.', 'author_id': '123', 'asset_id': asset.id, 'parent_id': ''});
})
.then((res) => {
expect(res).to.have.status(500);
})
.catch((err) => {
expect(err.response.body).to.not.be.null;
expect(err.response.body).to.have.property('message');
expect(err.response.body.error.metadata.closedMessage).to.be.equal('tests said expired!');
});
});
it('should create a comment when the asset has not expired yet', () => {
return Asset.create({
closedAt: new Date().setDate(32),
closedMessage: 'tests said expired!'
})
.then((asset) => {
return chai.request(app).post('/api/v1/comments')
.set(passport.inject({roles: []}))
.send({'body': 'Something body.', 'author_id': '123', 'asset_id': asset.id, 'parent_id': ''});
})
.then((res) => {
expect(res).to.have.status(201);
});
});
});
});
describe('/api/v1/comments/:comment_id', () => {
@@ -360,21 +193,21 @@ describe('/api/v1/comments/:comment_id', () => {
}];
const actions = [{
action_type: 'flag',
action_type: 'FLAG',
item_id: 'abc',
item_type: 'comment'
item_type: 'COMMENTS'
}, {
action_type: 'like',
action_type: 'LIKE',
item_id: 'hij',
item_type: 'comment'
item_type: 'COMMENTS'
}];
beforeEach(() => {
return Setting.init(settings).then(() => {
return SettingsService.init(settings).then(() => {
return Promise.all([
Comment.create(comments),
User.createLocalUsers(users),
Action.create(actions)
CommentModel.create(comments),
UsersService.createLocalUsers(users),
ActionModel.create(actions)
]);
});
});
@@ -400,7 +233,7 @@ describe('/api/v1/comments/:comment_id', () => {
.set(passport.inject({roles: ['admin']}))
.then((res) => {
expect(res).to.have.status(204);
return Comment.findById('abc');
return CommentsService.findById('abc');
})
.then((comment) => {
expect(comment).to.be.null;
@@ -448,15 +281,17 @@ describe('/api/v1/comments/:comment_id/actions', () => {
body: 'comment 20',
asset_id: 'asset',
author_id: '456',
status: 'REJECTED',
status_history: [{
type: 'rejected'
type: 'REJECTED'
}]
}, {
id: 'hij',
body: 'comment 30',
asset_id: '456',
status: 'ACCEPTED',
status_history: [{
type: 'accepted'
type: 'ACCEPTED'
}]
}];
@@ -471,19 +306,21 @@ describe('/api/v1/comments/:comment_id/actions', () => {
}];
const actions = [{
action_type: 'flag',
action_type: 'FLAG',
item_type: 'COMMENTS',
item_id: 'abc'
}, {
action_type: 'like',
action_type: 'LIKE',
item_type: 'COMMENTS',
item_id: 'hij'
}];
beforeEach(() => {
return Setting.init(settings).then(() => {
return SettingsService.init(settings).then(() => {
return Promise.all([
Comment.create(comments),
User.createLocalUsers(users),
Action.create(actions)
CommentModel.create(comments),
UsersService.createLocalUsers(users),
ActionModel.create(actions)
]);
});
});
+15 -15
View File
@@ -10,9 +10,9 @@ chai.use(require('chai-http'));
const Comment = require('../../../../models/comment');
const Action = require('../../../../models/action');
const User = require('../../../../models/user');
const UsersService = require('../../../../services/users');
const Setting = require('../../../../models/setting');
const SettingsService = require('../../../../services/settings');
const settings = {id: '1', moderation: 'pre', wordlist: {banned: ['banned'], suspect: ['suspect']}};
describe('/api/v1/queue', () => {
@@ -21,26 +21,26 @@ describe('/api/v1/queue', () => {
body: 'comment 10',
asset_id: 'asset',
author_id: '123',
status: 'rejected',
status: 'REJECTED',
status_history: [{
type: 'rejected'
type: 'REJECTED'
}]
}, {
id: 'def',
body: 'comment 20',
asset_id: 'asset',
author_id: '456',
status: 'premod',
status: 'PREMOD',
status_history: [{
type: 'premod'
type: 'PREMOD'
}]
}, {
id: 'hij',
body: 'comment 30',
asset_id: '456',
status: 'accepted',
status: 'ACCEPTED',
status_history: [{
type: 'accepted'
type: 'ACCEPTED'
}]
}];
@@ -55,18 +55,18 @@ describe('/api/v1/queue', () => {
}];
const actions = [{
action_type: 'flag',
action_type: 'FLAG',
item_id: 'abc',
item_type: 'comment'
item_type: 'COMMENTS'
}, {
action_type: 'like',
action_type: 'LIKE',
item_id: 'hij',
item_type: 'comment'
item_type: 'COMMENTS'
}];
beforeEach(() => {
return Setting.init(settings).then(() => {
return User.createLocalUsers(users)
return SettingsService.init(settings).then(() => {
return UsersService.createLocalUsers(users)
.then((u) => {
comments[0].author_id = u[0].id;
comments[1].author_id = u[1].id;
@@ -80,7 +80,7 @@ describe('/api/v1/queue', () => {
return Promise.all([
Action.create(actions),
Setting.init(settings)
SettingsService.init(settings)
]);
});
});
+3 -3
View File
@@ -7,12 +7,12 @@ const expect = chai.expect;
chai.should();
chai.use(require('chai-http'));
const Setting = require('../../../../models/setting');
const SettingsService = require('../../../../services/settings');
const defaults = {id: '1', moderation: 'pre'};
describe('/api/v1/settings', () => {
beforeEach(() => Setting.init(defaults));
beforeEach(() => SettingsService.init(defaults));
describe('#get', () => {
@@ -40,7 +40,7 @@ describe('/api/v1/settings', () => {
.then((res) => {
expect(res).to.have.status(204);
return Setting.retrieve();
return SettingsService.retrieve();
})
.then((settings) => {
expect(settings).to.have.property('moderation', 'post');
-225
View File
@@ -1,225 +0,0 @@
const app = require('../../../../app');
const chai = require('chai');
const expect = chai.expect;
// Setup chai.
chai.should();
chai.use(require('chai-http'));
const Action = require('../../../../models/action');
const User = require('../../../../models/user');
const Comment = require('../../../../models/comment');
const Asset = require('../../../../models/asset');
const Setting = require('../../../../models/setting');
describe('/api/v1/stream', () => {
describe('#get', () => {
const settings = {
id: '1',
moderation: 'post',
wordlist: {
banned: ['banned'],
suspect: ['suspect']
}
};
const assets = [
{
url: 'https://example.com/article/1'
},
{
url: 'https://example.com/article/2',
settings: {
moderation: 'pre'
}
},
{
url: 'https://example.com/article/3'
}
];
const comments = [{
id: 'abc',
body: 'comment 10',
author_id: '',
parent_id: '',
status: 'accepted',
status_history: [{
type: 'accepted'
}]
}, {
id: 'def',
body: 'comment 20',
author_id: '',
parent_id: '',
status: null,
status_history: []
}, {
id: 'uio',
body: 'comment 30',
asset_id: 'asset',
author_id: '456',
parent_id: '',
status: 'accepted',
status_history: [{
type: 'accepted'
}]
}, {
id: 'hij',
body: 'comment 40',
asset_id: '456',
status: 'rejected',
status_history: [{
type: 'rejected'
}]
}, {
body: 'comment 50',
status: 'premod',
status_history: [{
type: 'premod'
}]
}, {
body: 'comment 60',
status: 'accepted',
status_history: [{
type: 'accepted'
}]
}, {
body: 'comment 70',
status: 'rejected',
status_history: [{
type: 'rejected'
}]
}, {
body: 'comment 70',
status: null,
status_history: []
}];
const users = [{
displayName: 'Ana',
email: 'ana@gmail.com',
password: '123456789'
}, {
displayName: 'Maria',
email: 'maria@gmail.com',
password: '123456789'
}];
const actions = [{
action_type: 'flag',
item_id: 'abc'
}, {
action_type: 'like',
item_id: 'hij'
}];
beforeEach(() => {
return Setting.init(settings)
.then(() => Promise.all([
User.createLocalUsers(users),
Promise.all(assets.map((asset) => Asset.create(asset)))
]))
.then(([mockUsers, mockAssets]) => {
// Map the id's over.
mockAssets.forEach((asset, i) => {
assets[i].id = asset.id;
});
mockUsers.forEach((user, i) => {
users[i].id = user.id;
});
comments.forEach((comment, i) => {
comments[i].author_id = users[(i % 2) === 0 ? 0 : 1].id;
});
comments[0].asset_id = assets[0].id;
comments[1].asset_id = assets[0].id;
comments[2].asset_id = assets[1].id;
comments[3].asset_id = assets[1].id;
comments[4].asset_id = assets[2].id;
comments[5].asset_id = assets[2].id;
comments[6].asset_id = assets[2].id;
comments[7].asset_id = assets[2].id;
return Promise.all([
Comment.create(comments),
Action.create(actions)
]);
});
});
it('should return a stream with comments, users and actions for an existing asset', () => {
return chai.request(app)
.get('/api/v1/stream')
.query({asset_url: assets[0].url})
.then(res => {
expect(res).to.have.status(200);
expect(res.body.assets.length).to.equal(1);
expect(res.body.comments.length).to.equal(2);
expect(res.body.users.length).to.equal(2);
expect(res.body.actions.length).to.equal(1);
expect(res.body.settings).to.have.property('moderation', 'post');
});
});
it('should reject requests without a scheme in the asset_url', () => {
return chai.request(app)
.get('/api/v1/stream')
.query({asset_url: 'test.com'})
.catch((err) => {
expect(err).to.have.status(400);
expect(err.response.body.message).to.contain('asset_url is invalid');
});
});
it('should merge the settings when the asset contains settings to override it with', () => {
return chai.request(app)
.get('/api/v1/stream')
.query({asset_url: assets[1].url})
.then((res) => {
expect(res).to.have.status(200);
expect(res.body.assets).to.have.length(1);
expect(res.body.comments).to.have.length(1);
expect(res.body.users).to.have.length(1);
expect(res.body.settings).to.have.property('moderation', 'pre');
expect(res.body.settings).to.not.have.property('wordlist');
});
});
it('should not change the previously displayed comments based on moderation state changes', () => {
let preComments, postComments;
return chai.request(app)
.get('/api/v1/stream')
.query({asset_url: assets[2].url})
.then((res) => {
expect(res).to.have.status(200);
expect(res.body.comments.length).to.equal(2);
expect(res.body.settings).to.have.property('moderation', 'post');
preComments = res.body.comments;
return Asset.overrideSettings(assets[2].id, {moderation: 'pre'});
})
.then(() => {
return chai.request(app)
.get('/api/v1/stream')
.query({asset_url: assets[2].url});
})
.then((res) => {
expect(res).to.have.status(200);
expect(res.body.comments.length).to.equal(2);
expect(res.body.settings).to.have.property('moderation', 'pre');
postComments = res.body.comments;
expect(preComments).to.deep.equal(postComments);
});
});
});
});
+6 -6
View File
@@ -5,21 +5,21 @@ const mailer = require('../../../../services/mailer');
const chai = require('chai');
const expect = chai.expect;
const Setting = require('../../../../models/setting');
const SettingsService = require('../../../../services/settings');
const settings = {id: '1', moderation: 'pre', wordlist: {banned: ['bad words'], suspect: ['suspect words']}};
// Setup chai.
chai.should();
chai.use(require('chai-http'));
const User = require('../../../../models/user');
const UsersService = require('../../../../services/users');
describe('/api/v1/users/:user_id/email/confirm', () => {
let mockUser;
beforeEach(() => Setting.init(settings).then(() => {
return User.createLocalUser('ana@gmail.com', '123321123', 'Ana');
beforeEach(() => SettingsService.init(settings).then(() => {
return UsersService.createLocalUser('ana@gmail.com', '123321123', 'Ana');
})
.then((user) => {
mockUser = user;
@@ -63,8 +63,8 @@ describe('/api/v1/users/:user_id/actions', () => {
}];
beforeEach(() => {
return Setting.init(settings).then(() => {
return User.createLocalUsers(users);
return SettingsService.init(settings).then(() => {
return UsersService.createLocalUsers(users);
});
});