mirror of
https://github.com/wassname/talk.git
synced 2026-08-15 12:55:10 +08:00
Merge branch 'reply' of github.com:coralproject/talk into reply
* 'reply' of github.com:coralproject/talk: (193 commits) Add some margin to loadmore typo updated tests updated tests Fully implement SetUsername removed snakecase fix to optional required param Use correct mutation and show errors refactored mailer service with lodash! Fix live status updates Move ChangeUsername to the appropiate tab Fix change username not displaying errors Remove defunct refetch detection workaround Rename UnBan and UnSuspend hardened configuration user cli patches don't apply configuration from dotfiles during testing applied rename to graph mutation edges reintroduced the errors.ErrSameUsernameProvided fixed wrong query logic ...
This commit is contained in:
@@ -54,24 +54,34 @@ module.exports = {
|
||||
moderateNav: '.talk-admin-nav-moderate',
|
||||
settingsButton: '.talk-admin-header-settings-button',
|
||||
signOutButton: '.talk-admin-header-sign-out',
|
||||
suspendUserDialog: '.talk-admin-suspend-user-dialog',
|
||||
suspendUserConfirmButton: '.talk-admin-suspend-user-dialog-confirm',
|
||||
supendUserSendButton: '.talk-admin-suspend-user-dialog-send',
|
||||
usernameDialog: '.talk-reject-username-dialog',
|
||||
usernameDialogButtons: '.talk-reject-username-dialog-buttons',
|
||||
usernameDialogSuspend: '.talk-reject-username-dialog-button-k',
|
||||
usernameDialogSuspensionMessage: '.talk-reject-username-dialog-suspension-message',
|
||||
toast: '.toastify',
|
||||
toastClose: '.toastify__close',
|
||||
},
|
||||
sections: {
|
||||
suspendUserDialog: {
|
||||
selector: '.talk-admin-suspend-user-dialog',
|
||||
elements: {
|
||||
step0: '.talk-admin-suspend-user-dialog-step-0',
|
||||
step1: '.talk-admin-suspend-user-dialog-step-1',
|
||||
confirmButton: '.talk-admin-suspend-user-dialog-confirm',
|
||||
sendButton: '.talk-admin-suspend-user-dialog-send',
|
||||
}
|
||||
},
|
||||
usernameDialog: {
|
||||
selector: '.talk-admin-reject-username-dialog',
|
||||
elements: {
|
||||
step0: '.talk-admin-reject-username-dialog-step-0',
|
||||
step1: '.talk-admin-reject-username-dialog-step-1',
|
||||
buttons: '.talk-admin-reject-username-dialog-buttons',
|
||||
suspend: '.talk-admin-reject-username-dialog-button-k',
|
||||
suspensionMessage: '.talk-admin-reject-username-dialog-suspension-message',
|
||||
}
|
||||
},
|
||||
moderate: {
|
||||
selector: '.talk-admin-moderation-container',
|
||||
elements: {
|
||||
comment: '.talk-admin-moderate-comment',
|
||||
commentActionMenu: '.talk-admin-moderate-comment-actions-menu',
|
||||
actionItemSuspendUser: '.action-menu-item#suspendUser',
|
||||
actionMenuButton: '.talk-admin-moderate-comment-actions-menu #actions-dropdown-0'
|
||||
commentUsername: '.talk-admin-moderate-comment-username',
|
||||
}
|
||||
},
|
||||
stories: {
|
||||
@@ -109,13 +119,31 @@ module.exports = {
|
||||
firstRow: '.talk-admin-community-people-row:first-child',
|
||||
dropdownStatus: '.talk-admin-community-people-dd-status',
|
||||
dropdownRole: '.talk-admin-community-people-dd-role',
|
||||
dropdownStatusActive: '.talk-admin-community-people-dd-status .dd-list-active',
|
||||
optionActive: '.dd-option#ACTIVE',
|
||||
optionBanned: '.dd-option#BANNED',
|
||||
dropdownStatusActive: '.talk-admin-community-people-dd-status .is-upgraded',
|
||||
optionSuspendUser: '.action-menu-item#suspendUser',
|
||||
optionBanUser: '.action-menu-item#banUser',
|
||||
optionRemoveBan: '.action-menu-item#removeBan',
|
||||
optionRemoveSuspension: '.action-menu-item#removeSuspension',
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
userDetailDrawer: {
|
||||
selector: '.talk-admin-user-detail-drawer',
|
||||
elements: {
|
||||
'closeButton': '.talk-admin-user-detail-drawer-close-button',
|
||||
'tabBar': '.talk-admin-user-detail-tab-bar',
|
||||
'allTab': '.talk-admin-user-detail-all-tab',
|
||||
'rejectedTab': '.talk-admin-user-detail-rejected-tab',
|
||||
'historyTab': '.talk-admin-user-detail-history-tab',
|
||||
'historyPane': '.talk-admin-user-detail-history-tab-pane',
|
||||
'accountHistory': '.talk-admin-account-history',
|
||||
'accountHistoryRowStatus':'.talk-admin-account-history-row-status',
|
||||
'actionsMenu': '.talk-admin-user-detail-actions-button',
|
||||
'actionItemSuspendUser': '.action-menu-item#suspendUser',
|
||||
'actionMenuButton': '.talk-admin-user-detail-actions-menu #actions-dropdown-0',
|
||||
}
|
||||
},
|
||||
drawer: {
|
||||
selector: '.talk-admin-drawer-nav',
|
||||
commands: [{
|
||||
|
||||
@@ -105,8 +105,8 @@ module.exports = {
|
||||
replyButton: '.talk-stream-comment.talk-stream-comment-level-0 .talk-plugin-replies-reply-button',
|
||||
respectButton: '.talk-stream-comment.talk-stream-comment-level-0 .talk-stream-comment-footer .talk-plugin-respect-button',
|
||||
restrictedMessageBox: '.talk-restricted-message-box',
|
||||
suspendedAccountInput: '.talk-suspended-account-username-input',
|
||||
suspendedAccountSubmitButton: '.talk-suspended-account-submit-button',
|
||||
changeUsernameInput: '.talk-change-username-username-input',
|
||||
changeUsernameSubmitButton: '.talk-change-username-submit-button',
|
||||
},
|
||||
sections: {
|
||||
flag: {
|
||||
|
||||
@@ -37,6 +37,7 @@ module.exports = {
|
||||
|
||||
adminPage
|
||||
.openDrawer()
|
||||
.goToCommunity();
|
||||
.goToCommunity();
|
||||
|
||||
},
|
||||
};
|
||||
|
||||
@@ -18,6 +18,7 @@ module.exports = {
|
||||
},
|
||||
|
||||
'creates a new asset': (client) => {
|
||||
|
||||
const asset = 'newAssetTest';
|
||||
const embedStream = client.page.embedStream();
|
||||
|
||||
|
||||
@@ -22,12 +22,10 @@ module.exports = {
|
||||
|
||||
adminPage.navigateAndLogin(admin);
|
||||
},
|
||||
'admin flags user\'s username as offensive': (client) => {
|
||||
'admin flags users username as offensive': (client) => {
|
||||
const embedStream = client.page.embedStream();
|
||||
|
||||
const comments = embedStream
|
||||
.navigate()
|
||||
.ready();
|
||||
const comments = embedStream.navigate().ready();
|
||||
|
||||
comments
|
||||
.waitForElementVisible('@firstComment')
|
||||
@@ -65,17 +63,18 @@ module.exports = {
|
||||
.click('@flaggedUserRejectButton');
|
||||
},
|
||||
'admin suspends the user': (client) => {
|
||||
const adminPage = client.page.admin();
|
||||
const community = client.page.admin().section.community;
|
||||
const usernameDialog = client.page.admin().section.usernameDialog;
|
||||
|
||||
adminPage
|
||||
.waitForElementVisible('@usernameDialog')
|
||||
.waitForElementVisible('@usernameDialogButtons')
|
||||
.waitForElementVisible('@usernameDialogSuspend')
|
||||
.click('@usernameDialogSuspend')
|
||||
.waitForElementVisible('@usernameDialogSuspensionMessage')
|
||||
.click('@usernameDialogSuspend');
|
||||
|
||||
usernameDialog
|
||||
.waitForElementVisible('@buttons')
|
||||
.waitForElementVisible('@step0')
|
||||
.waitForElementVisible('@suspend')
|
||||
.click('@suspend')
|
||||
.waitForElementVisible('@step1')
|
||||
.waitForElementVisible('@suspend')
|
||||
.click('@suspend');
|
||||
|
||||
community
|
||||
.waitForElementNotPresent('@flaggedUser');
|
||||
},
|
||||
@@ -95,8 +94,7 @@ module.exports = {
|
||||
const embedStream = client.page.embedStream();
|
||||
const comments = embedStream.section.comments;
|
||||
|
||||
comments
|
||||
.waitForElementVisible('@restrictedMessageBox');
|
||||
comments.waitForElementVisible('@restrictedMessageBox');
|
||||
},
|
||||
'user should not be able to comment': (client) => {
|
||||
const embedStream = client.page.embedStream();
|
||||
@@ -112,11 +110,11 @@ module.exports = {
|
||||
const {testData: {user}} = client.globals;
|
||||
|
||||
comments
|
||||
.waitForElementVisible('@suspendedAccountInput')
|
||||
.setValue('@suspendedAccountInput', `${user.username}_alternative`)
|
||||
.waitForElementVisible('@suspendedAccountSubmitButton')
|
||||
.click('@suspendedAccountSubmitButton')
|
||||
.waitForElementNotPresent('@suspendedAccountInput');
|
||||
.waitForElementVisible('@changeUsernameInput')
|
||||
.setValue('@changeUsernameInput', `${user.username}_alternative`)
|
||||
.waitForElementVisible('@changeUsernameSubmitButton')
|
||||
.click('@changeUsernameSubmitButton')
|
||||
.waitForElementNotPresent('@changeUsernameInput');
|
||||
},
|
||||
'user should be able to comment': (client) => {
|
||||
const embedStream = client.page.embedStream();
|
||||
|
||||
@@ -84,7 +84,7 @@ module.exports = {
|
||||
|
||||
adminPage
|
||||
.goToCommunity()
|
||||
.goToPeople();
|
||||
.goToPeople();
|
||||
},
|
||||
'admin removes ban from user': (client) => {
|
||||
const people = client.page.admin()
|
||||
@@ -96,7 +96,7 @@ module.exports = {
|
||||
.waitForElementVisible('@dropdownStatus')
|
||||
.click('@dropdownStatus')
|
||||
.waitForElementVisible('@dropdownStatusActive')
|
||||
.click('@optionActive');
|
||||
.click('@optionRemoveBan');
|
||||
},
|
||||
'admin logs out 2': (client) => {
|
||||
client.page.admin().logout();
|
||||
|
||||
@@ -83,7 +83,7 @@ module.exports = {
|
||||
},
|
||||
'admin suspends user': (client) => {
|
||||
const adminPage = client.page.admin();
|
||||
const moderate = adminPage.section.moderate;
|
||||
const {moderate, userDetailDrawer, suspendUserDialog} = adminPage.section;
|
||||
|
||||
adminPage
|
||||
.navigate()
|
||||
@@ -92,18 +92,22 @@ module.exports = {
|
||||
|
||||
moderate
|
||||
.waitForElementVisible('@comment')
|
||||
.waitForElementVisible('@commentActionMenu')
|
||||
.waitForElementVisible('@actionMenuButton')
|
||||
.waitForElementVisible('@commentUsername')
|
||||
.click('@commentUsername');
|
||||
|
||||
userDetailDrawer
|
||||
.waitForElementVisible('@actionsMenu')
|
||||
.click('@actionMenuButton')
|
||||
.waitForElementVisible('@actionItemSuspendUser')
|
||||
.click('@actionItemSuspendUser');
|
||||
|
||||
adminPage
|
||||
.waitForElementVisible('@suspendUserDialog')
|
||||
.waitForElementVisible('@suspendUserConfirmButton')
|
||||
.click('@suspendUserConfirmButton')
|
||||
.waitForElementVisible('@supendUserSendButton')
|
||||
.click('@supendUserSendButton');
|
||||
suspendUserDialog
|
||||
.waitForElementVisible('@step0')
|
||||
.waitForElementVisible('@confirmButton')
|
||||
.click('@confirmButton')
|
||||
.waitForElementVisible('@step1')
|
||||
.waitForElementVisible('@sendButton')
|
||||
.click('@sendButton');
|
||||
|
||||
adminPage
|
||||
.waitForElementVisible('@toast')
|
||||
@@ -111,6 +115,27 @@ module.exports = {
|
||||
.click('@toastClose');
|
||||
|
||||
},
|
||||
'admin checks user status and ban and suspension history': (client) => {
|
||||
const adminPage = client.page.admin();
|
||||
const {moderate, userDetailDrawer} = adminPage.section;
|
||||
|
||||
moderate
|
||||
.waitForElementVisible('@comment')
|
||||
.waitForElementVisible('@commentUsername')
|
||||
.click('@commentUsername');
|
||||
|
||||
userDetailDrawer
|
||||
.waitForElementVisible('@tabBar')
|
||||
.waitForElementVisible('@allTab')
|
||||
.click('@allTab')
|
||||
.waitForElementVisible('@rejectedTab')
|
||||
.click('@rejectedTab')
|
||||
.waitForElementVisible('@historyTab')
|
||||
.click('@historyTab')
|
||||
.waitForElementVisible('@historyPane')
|
||||
.waitForElementVisible('@accountHistory')
|
||||
.click('@closeButton');
|
||||
},
|
||||
'admin logs out': (client) => {
|
||||
const adminPage = client.page.admin();
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@ beforeEach(async () => {
|
||||
}));
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
after(async function() {
|
||||
mongoose.disconnect();
|
||||
done();
|
||||
});
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
process.on('unhandledRejection', function(reason, promise) {
|
||||
console.error(promise);
|
||||
});
|
||||
@@ -13,7 +13,7 @@ describe('graph.Context', () => {
|
||||
let c;
|
||||
|
||||
beforeEach(() => {
|
||||
c = new Context({user: new User({id: '1', roles: ['ADMIN']})});
|
||||
c = new Context({user: new User({id: '1', role: 'ADMIN'})});
|
||||
});
|
||||
|
||||
it('creates a context with a user', (done) => {
|
||||
|
||||
@@ -31,7 +31,7 @@ describe('graph.mutations.addTag', () => {
|
||||
`;
|
||||
|
||||
it('moderators can add tags to comments', async () => {
|
||||
const user = new UserModel({roles: ['MODERATOR']});
|
||||
const user = new UserModel({role: 'MODERATOR'});
|
||||
const context = new Context({user});
|
||||
const res = await graphql(schema, query, {}, context, {id: comment.id, asset_id: asset.id, name: 'BEST'}, 'AddCommentTag');
|
||||
if (res.errors && res.errors.length) {
|
||||
@@ -48,7 +48,7 @@ describe('graph.mutations.addTag', () => {
|
||||
Object.entries({
|
||||
'anonymous': undefined,
|
||||
'regular commenter': new UserModel({}),
|
||||
'banned moderator': new UserModel({roles: ['MODERATOR'], status: 'BANNED'})
|
||||
'banned moderator': new UserModel({role: 'MODERATOR', banned: true})
|
||||
}).forEach(([ userDescription, user ]) => {
|
||||
it(userDescription, async () => {
|
||||
const context = new Context({user});
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
const {graphql} = require('graphql');
|
||||
|
||||
const schema = require('../../../../graph/schema');
|
||||
const Context = require('../../../../graph/context');
|
||||
const SettingsService = require('../../../../services/settings');
|
||||
const UsersService = require('../../../../services/users');
|
||||
|
||||
const {expect} = require('chai');
|
||||
|
||||
describe('graph.mutations.changeUsername', () => {
|
||||
let user;
|
||||
beforeEach(async () => {
|
||||
await SettingsService.init();
|
||||
user = await UsersService.createLocalUser('test@test.com', 'testpassword1!', 'kirk');
|
||||
|
||||
expect(user).to.have.property('username', 'kirk');
|
||||
expect(user).to.have.property('lowercaseUsername', 'kirk');
|
||||
expect(user.status.username.status).to.equal('SET');
|
||||
});
|
||||
|
||||
const changeUsernameMutation = `
|
||||
mutation ChangeUsername($user_id: ID!, $username: String!) {
|
||||
changeUsername(id: $user_id, username: $username) {
|
||||
errors {
|
||||
translation_key
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
query User {
|
||||
me {
|
||||
state {
|
||||
status {
|
||||
username {
|
||||
history {
|
||||
status
|
||||
assigned_by {
|
||||
username
|
||||
}
|
||||
created_at
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
[
|
||||
{role: 'COMMENTER'},
|
||||
{role: 'STAFF'},
|
||||
{role: 'COMMENTER'},
|
||||
{role: 'MODERATOR'},
|
||||
{role: 'ADMIN'},
|
||||
].forEach(({role}) => {
|
||||
it(`can change the username with roles ${role}`, async () => {
|
||||
let username = 'spock';
|
||||
|
||||
// Update the user role.
|
||||
await UsersService.setRole(user.id, role);
|
||||
user.role = role;
|
||||
|
||||
let ctx = new Context({user});
|
||||
|
||||
let res = await graphql(schema, changeUsernameMutation, {}, ctx, {
|
||||
user_id: user.id,
|
||||
username,
|
||||
}, 'ChangeUsername');
|
||||
|
||||
if (res.errors && res.errors.length > 0) {
|
||||
console.error(res.errors);
|
||||
}
|
||||
|
||||
expect(res.errors).to.be.undefined;
|
||||
expect(res.data.changeUsername).to.have.property('errors');
|
||||
expect(res.data.changeUsername.errors).to.have.length(1);
|
||||
expect(res.data.changeUsername.errors[0]).to.have.property('translation_key', 'NOT_AUTHORIZED');
|
||||
|
||||
// Set the user to the desired status.
|
||||
user = await UsersService.setUsernameStatus(user.id, 'REJECTED');
|
||||
|
||||
expect(user.status.username.status, 'REJECTED');
|
||||
|
||||
ctx = new Context({user});
|
||||
|
||||
res = await graphql(schema, changeUsernameMutation, {}, ctx, {
|
||||
user_id: user.id,
|
||||
username,
|
||||
}, 'ChangeUsername');
|
||||
|
||||
if (res.errors && res.errors.length > 0) {
|
||||
console.error(res.errors);
|
||||
}
|
||||
|
||||
expect(res.errors).to.be.undefined;
|
||||
expect(res.data.changeUsername).to.be.null;
|
||||
|
||||
res = await graphql(schema, changeUsernameMutation, {}, ctx, {}, 'User');
|
||||
|
||||
if (res.errors && res.errors.length > 0) {
|
||||
console.error(res.errors);
|
||||
}
|
||||
|
||||
expect(res.errors).to.be.undefined;
|
||||
|
||||
expect(res.data.me.state.status.username.status, 'CHANGED');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -71,27 +71,28 @@ describe('graph.mutations.createComment', () => {
|
||||
beforeEach(() => AssetModel.create({id: '123'}));
|
||||
|
||||
[
|
||||
{user: new UserModel({status: 'ACTIVE'}), error: null},
|
||||
{user: new UserModel({status: 'BANNED'}), error: 'NOT_AUTHORIZED'},
|
||||
{user: new UserModel({status: 'PENDING'}), error: null},
|
||||
{user: new UserModel({status: 'APPROVED'}), error: null}
|
||||
{user: new UserModel({}), error: null},
|
||||
{user: new UserModel({banned: true}), error: 'NOT_AUTHORIZED'},
|
||||
{user: new UserModel({suspended: new Date((new Date()).getTime() - (10 * 86400000))}), error: null},
|
||||
{user: new UserModel({suspended: new Date((new Date()).getTime() + (10 * 86400000))}), error: 'NOT_AUTHORIZED'},
|
||||
].forEach(({user, error}) => {
|
||||
describe(`user.status=${user.status}`, () => {
|
||||
it(error ? 'does not create the comment' : 'creates the comment', () => {
|
||||
describe(`user.banned=${user.banned} user.suspended=${user.suspended}`, () => {
|
||||
it(error ? 'does not create the comment' : 'creates the comment', async () => {
|
||||
const context = new Context({user});
|
||||
const {data, errors} = await graphql(schema, query, {}, context);
|
||||
|
||||
return graphql(schema, query, {}, context)
|
||||
.then(({data, errors}) => {
|
||||
expect(errors).to.be.undefined;
|
||||
if (error) {
|
||||
expect(data.createComment).to.have.property('comment').null;
|
||||
expect(data.createComment).to.have.property('errors').not.null;
|
||||
expect(data.createComment.errors[0]).to.have.property('translation_key', error);
|
||||
} else {
|
||||
expect(data.createComment).to.have.property('comment').not.null;
|
||||
expect(data.createComment).to.have.property('errors').null;
|
||||
}
|
||||
});
|
||||
expect(errors).to.be.undefined;
|
||||
if (error) {
|
||||
expect(data.createComment).to.have.property('comment').null;
|
||||
expect(data.createComment).to.have.property('errors').not.null;
|
||||
expect(data.createComment.errors[0]).to.have.property('translation_key', error);
|
||||
} else {
|
||||
if (data.createComment.errors && data.createComment.errors.length > 0) {
|
||||
console.error(data.createComment.errors);
|
||||
}
|
||||
expect(data.createComment).to.have.property('errors').null;
|
||||
expect(data.createComment).to.have.property('comment').not.null;
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -109,7 +110,7 @@ describe('graph.mutations.createComment', () => {
|
||||
beforeEach(() => asset.save());
|
||||
|
||||
it(error ? 'does not create the comment' : 'creates the comment', () => {
|
||||
const context = new Context({user: new UserModel({status: 'ACTIVE'})});
|
||||
const context = new Context({user: new UserModel({})});
|
||||
|
||||
return graphql(schema, query, {}, context)
|
||||
.then(({data, errors}) => {
|
||||
@@ -142,7 +143,7 @@ describe('graph.mutations.createComment', () => {
|
||||
beforeEach(() => AssetModel.create({id: '123', settings: {moderation}}));
|
||||
|
||||
it(`creates comment with status=${status}`, () => {
|
||||
const context = new Context({user: new UserModel({status: 'ACTIVE'})});
|
||||
const context = new Context({user: new UserModel()});
|
||||
|
||||
return graphql(schema, query, {}, context)
|
||||
.then(({data, errors}) => {
|
||||
@@ -172,33 +173,30 @@ describe('graph.mutations.createComment', () => {
|
||||
].forEach(({message, body, status, flagged}) => {
|
||||
describe(message, () => {
|
||||
|
||||
it(`should create a comment with status=${status} and it ${flagged ? 'should' : 'should not'} be flagged`, () => {
|
||||
const context = new Context({user: new UserModel({status: 'ACTIVE'})});
|
||||
it(`should create a comment with status=${status} and it ${flagged ? 'should' : 'should not'} be flagged`, async () => {
|
||||
const context = new Context({user: new UserModel({})});
|
||||
|
||||
return graphql(schema, query, {}, context, {
|
||||
const {data, errors} = await graphql(schema, query, {}, context, {
|
||||
input: {
|
||||
asset_id: '123',
|
||||
body
|
||||
}
|
||||
})
|
||||
.then(({data, errors}) => {
|
||||
expect(errors).to.be.undefined;
|
||||
expect(data.createComment).to.have.property('comment').not.null;
|
||||
expect(data.createComment.comment).to.have.property('status', status);
|
||||
expect(data.createComment).to.have.property('errors').null;
|
||||
});
|
||||
|
||||
return ActionModel.find({
|
||||
item_id: data.createComment.comment.id,
|
||||
action_type: 'FLAG'
|
||||
});
|
||||
})
|
||||
.then((actions) => {
|
||||
if (flagged) {
|
||||
expect(actions).to.have.length(1);
|
||||
} else {
|
||||
expect(actions).to.have.length(0);
|
||||
}
|
||||
});
|
||||
expect(errors).to.be.undefined;
|
||||
expect(data.createComment).to.have.property('comment').not.null;
|
||||
expect(data.createComment.comment).to.have.property('status', status);
|
||||
expect(data.createComment).to.have.property('errors').null;
|
||||
|
||||
const actions = await ActionModel.find({
|
||||
item_id: data.createComment.comment.id,
|
||||
action_type: 'FLAG'
|
||||
});
|
||||
if (flagged) {
|
||||
expect(actions).to.have.length(1);
|
||||
} else {
|
||||
expect(actions).to.have.length(0);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
@@ -210,37 +208,32 @@ describe('graph.mutations.createComment', () => {
|
||||
beforeEach(() => AssetModel.create({id: '123'}));
|
||||
|
||||
[
|
||||
{roles: [], tag: null},
|
||||
{roles: ['ADMIN'], tag: 'STAFF'},
|
||||
{roles: ['MODERATOR'], tag: 'STAFF'},
|
||||
{roles: ['ADMIN', 'MODERATOR'], tag: 'STAFF'}
|
||||
].forEach(({roles, tag}) => {
|
||||
describe(`user.roles=${JSON.stringify(roles)}`, () => {
|
||||
{role: 'COMMENTER', tag: null},
|
||||
{role: 'ADMIN', tag: 'STAFF'},
|
||||
{role: 'MODERATOR', tag: 'STAFF'},
|
||||
].forEach(({role, tag}) => {
|
||||
describe(`user.role=${JSON.stringify(role)}`, () => {
|
||||
|
||||
it(`creates comment ${tag ? `with tag=${tag}` : 'without tags'}`, () => {
|
||||
const context = new Context({user: new UserModel({roles})});
|
||||
it(`creates comment ${tag ? `with tag=${tag}` : 'without tags'}`, async () => {
|
||||
const context = new Context({user: new UserModel({role})});
|
||||
|
||||
return graphql(schema, query, {}, context)
|
||||
.then(({data, errors}) => {
|
||||
if (errors) {
|
||||
console.error(errors);
|
||||
}
|
||||
expect(errors).to.be.undefined;
|
||||
expect(data.createComment).to.have.property('comment').not.null;
|
||||
expect(data.createComment).to.have.property('errors').null;
|
||||
const {data, errors} = await graphql(schema, query, {}, context);
|
||||
|
||||
return CommentsService.findById(data.createComment.comment.id);
|
||||
})
|
||||
.then(({tags}) => {
|
||||
if (tag) {
|
||||
expect(tags).to.have.length(1);
|
||||
expect(tags[0].tag.name).to.have.equal(tag);
|
||||
} else {
|
||||
expect(tags).length(0);
|
||||
}
|
||||
});
|
||||
if (errors) {
|
||||
console.error(errors);
|
||||
}
|
||||
expect(errors).to.be.undefined;
|
||||
expect(data.createComment).to.have.property('comment').not.null;
|
||||
expect(data.createComment).to.have.property('errors').null;
|
||||
|
||||
const {tags} = await CommentsService.findById(data.createComment.comment.id);
|
||||
if (tag) {
|
||||
expect(tags).to.have.length(1);
|
||||
expect(tags[0].tag.name).to.have.equal(tag);
|
||||
} else {
|
||||
expect(tags).length(0);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ describe('graph.mutations.removeTag', () => {
|
||||
`;
|
||||
|
||||
it('moderators can add remove tags from comments', async () => {
|
||||
const user = new UserModel({roles: ['MODERATOR']});
|
||||
const user = new UserModel({role: 'MODERATOR'});
|
||||
const context = new Context({user});
|
||||
|
||||
// add a tag first
|
||||
@@ -66,7 +66,7 @@ describe('graph.mutations.removeTag', () => {
|
||||
Object.entries({
|
||||
'anonymous': undefined,
|
||||
'regular commenter': new UserModel({}),
|
||||
'banned moderator': new UserModel({roles: ['MODERATOR'], status: 'BANNED'})
|
||||
'banned moderator': new UserModel({role: 'MODERATOR', banned: true})
|
||||
}).forEach(([userDescription, user]) => {
|
||||
it(userDescription, async function () {
|
||||
const context = new Context({user});
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
const {graphql} = require('graphql');
|
||||
|
||||
const schema = require('../../../../graph/schema');
|
||||
const Context = require('../../../../graph/context');
|
||||
const SettingsService = require('../../../../services/settings');
|
||||
const UserModel = require('../../../../models/user');
|
||||
const UsersService = require('../../../../services/users');
|
||||
const mailer = require('../../../../services/mailer');
|
||||
|
||||
const sinon = require('sinon');
|
||||
const chai = require('chai');
|
||||
chai.use(require('sinon-chai'));
|
||||
const {expect} = chai;
|
||||
|
||||
describe('graph.mutations.banUser', () => {
|
||||
let user;
|
||||
beforeEach(async () => {
|
||||
await SettingsService.init();
|
||||
|
||||
user = await UsersService.createLocalUser('usernameA@example.com', 'password', 'usernameA');
|
||||
});
|
||||
|
||||
let spy;
|
||||
before(() => {
|
||||
spy = sinon.spy(mailer, 'send');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
spy.reset();
|
||||
});
|
||||
|
||||
after(() => {
|
||||
spy.restore();
|
||||
});
|
||||
|
||||
const banUserMutation = `
|
||||
mutation BanUser($user_id: ID!, $message: String!) {
|
||||
banUser(input: {
|
||||
id: $user_id,
|
||||
message: $message
|
||||
}) {
|
||||
errors {
|
||||
translation_key
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mutation UnBanUser($user_id: ID!) {
|
||||
unbanUser(input: {
|
||||
id: $user_id
|
||||
}) {
|
||||
errors {
|
||||
translation_key
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
[
|
||||
{self: true, error: 'NOT_AUTHORIZED', role: 'COMMENTER'},
|
||||
{self: true, error: 'NOT_AUTHORIZED', role: 'STAFF'},
|
||||
{self: true, error: 'NOT_AUTHORIZED', role: 'COMMENTER'},
|
||||
{error: 'NOT_AUTHORIZED', role: 'COMMENTER'},
|
||||
{error: 'NOT_AUTHORIZED', role: 'STAFF'},
|
||||
{error: 'NOT_AUTHORIZED', role: 'COMMENTER'},
|
||||
{error: false, role: 'MODERATOR'},
|
||||
{error: false, role: 'ADMIN'},
|
||||
].forEach(({self, error, role}) => {
|
||||
it(`${error ? 'can not' : 'can'} ban ${self ? 'themself' : 'another user'} as a user with role=${role}`, async () => {
|
||||
const actor = new UserModel({role});
|
||||
|
||||
// If we're testing self assign, set the id of the actor to the user
|
||||
// we're acting on.
|
||||
if (self) {
|
||||
actor.id = user.id;
|
||||
}
|
||||
|
||||
const ctx = new Context({user: actor});
|
||||
|
||||
const {data, errors} = await graphql(schema, banUserMutation, {}, ctx, {
|
||||
user_id: user.id,
|
||||
message: 'This is a message'
|
||||
}, 'BanUser');
|
||||
|
||||
if (errors && errors.length > 0) {
|
||||
console.error(errors);
|
||||
}
|
||||
expect(errors).to.be.undefined;
|
||||
if (error) {
|
||||
expect(data.banUser).to.have.property('errors').not.null;
|
||||
expect(data.banUser.errors[0]).to.have.property('translation_key', error);
|
||||
} else {
|
||||
expect(data.banUser).to.be.null;
|
||||
|
||||
user = await UserModel.findOne({id: user.id});
|
||||
|
||||
expect(user.status.banned.status).to.be.true;
|
||||
expect(user.status.banned.history).to.have.length(1);
|
||||
expect(user.status.banned.history[0]).to.have.property('status', true);
|
||||
expect(user.status.banned.history[0]).to.have.property('message', 'This is a message');
|
||||
expect(user.status.banned.history[0]).to.have.property('assigned_by', actor.id);
|
||||
expect(user.status.banned.history[0]).to.have.property('created_at').not.null;
|
||||
|
||||
expect(user.banned).to.be.true;
|
||||
|
||||
expect(spy).to.have.been.calledOnce;
|
||||
|
||||
const res = await graphql(schema, banUserMutation, {}, ctx, {
|
||||
user_id: user.id,
|
||||
}, 'UnBanUser');
|
||||
if (res.errors && res.errors.length > 0) {
|
||||
console.error(res.errors);
|
||||
}
|
||||
expect(res.errors).to.be.undefined;
|
||||
expect(res.data.unbanUser).to.be.null;
|
||||
|
||||
user = await UserModel.findOne({id: user.id});
|
||||
|
||||
expect(user.status.banned.status).to.be.false;
|
||||
expect(user.status.banned.history).to.have.length(2);
|
||||
expect(user.status.banned.history[0]).to.have.property('status').to.be.true;
|
||||
expect(user.status.banned.history[0]).to.have.property('assigned_by', actor.id);
|
||||
expect(user.status.banned.history[0]).to.have.property('created_at').not.null;
|
||||
expect(user.status.banned.history[1]).to.have.property('status').to.be.false;
|
||||
expect(user.status.banned.history[1]).to.have.property('assigned_by', actor.id);
|
||||
expect(user.status.banned.history[1]).to.have.property('created_at').not.null;
|
||||
|
||||
expect(user.banned).to.be.false;
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,145 @@
|
||||
const {graphql} = require('graphql');
|
||||
const timekeeper = require('timekeeper');
|
||||
|
||||
const schema = require('../../../../graph/schema');
|
||||
const Context = require('../../../../graph/context');
|
||||
const SettingsService = require('../../../../services/settings');
|
||||
const UserModel = require('../../../../models/user');
|
||||
const UsersService = require('../../../../services/users');
|
||||
const mailer = require('../../../../services/mailer');
|
||||
|
||||
const sinon = require('sinon');
|
||||
const chai = require('chai');
|
||||
chai.use(require('chai-datetime'));
|
||||
chai.use(require('sinon-chai'));
|
||||
const {expect} = chai;
|
||||
|
||||
describe('graph.mutations.suspendUser', () => {
|
||||
let user;
|
||||
beforeEach(async () => {
|
||||
await SettingsService.init();
|
||||
|
||||
user = await UsersService.createLocalUser('usernameA@example.com', 'password', 'usernameA');
|
||||
});
|
||||
|
||||
let spy;
|
||||
before(() => {
|
||||
spy = sinon.spy(mailer, 'send');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
spy.reset();
|
||||
});
|
||||
|
||||
after(() => {
|
||||
spy.restore();
|
||||
});
|
||||
|
||||
const mutation = `
|
||||
mutation SuspendUser($user_id: ID!, $until: Date!, $message: String!) {
|
||||
suspendUser(input: {
|
||||
id: $user_id,
|
||||
until: $until,
|
||||
message: $message,
|
||||
}) {
|
||||
errors {
|
||||
translation_key
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mutation UnSuspendUser($user_id: ID!) {
|
||||
unsuspendUser(input: {
|
||||
id: $user_id,
|
||||
}) {
|
||||
errors {
|
||||
translation_key
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
[
|
||||
{self: true, error: 'NOT_AUTHORIZED', role: 'COMMENTER'},
|
||||
{self: true, error: 'NOT_AUTHORIZED', role: 'STAFF'},
|
||||
{self: true, error: 'NOT_AUTHORIZED', role: 'COMMENTER'},
|
||||
{error: 'NOT_AUTHORIZED', role: 'COMMENTER'},
|
||||
{error: 'NOT_AUTHORIZED', role: 'STAFF'},
|
||||
{error: 'NOT_AUTHORIZED', role: 'COMMENTER'},
|
||||
{error: false, role: 'MODERATOR'},
|
||||
{error: false, role: 'ADMIN'},
|
||||
].forEach(({self, error, role}) => {
|
||||
it(`${error ? 'can not' : 'can'} suspend ${self ? 'themself' : 'another user'} as a user with role ${role}`, async () => {
|
||||
const actor = new UserModel({role});
|
||||
|
||||
// If we're testing self assign, set the id of the actor to the user
|
||||
// we're acting on.
|
||||
if (self) {
|
||||
actor.id = user.id;
|
||||
}
|
||||
|
||||
const ctx = new Context({user: actor});
|
||||
|
||||
const now = new Date();
|
||||
const oneHourFromNow = new Date(new Date(now).setHours(now.getHours() + 1));
|
||||
|
||||
const {data, errors} = await graphql(schema, mutation, {}, ctx, {
|
||||
user_id: user.id,
|
||||
until: oneHourFromNow,
|
||||
message: 'This is a message'
|
||||
}, 'SuspendUser');
|
||||
|
||||
if (errors && errors.length > 0) {
|
||||
console.error(errors);
|
||||
}
|
||||
expect(errors).to.be.undefined;
|
||||
if (error) {
|
||||
expect(data.suspendUser).to.have.property('errors').not.null;
|
||||
expect(data.suspendUser.errors[0]).to.have.property('translation_key', error);
|
||||
} else {
|
||||
expect(data.suspendUser).to.be.null;
|
||||
|
||||
user = await UserModel.findOne({id: user.id});
|
||||
|
||||
// Mongoose messes with the date, check within a 2 second window.
|
||||
expect(user.status.suspension.until).to.be.withinTime(new Date(oneHourFromNow.getTime() - 1000), new Date(oneHourFromNow.getTime() + 1000));
|
||||
expect(user.status.suspension.history).to.have.length(1);
|
||||
expect(user.status.suspension.history[0]).to.have.property('until').to.be.withinTime(new Date(oneHourFromNow.getTime() - 1000), new Date(oneHourFromNow.getTime() + 1000));
|
||||
expect(user.status.suspension.history[0]).to.have.property('assigned_by', actor.id);
|
||||
expect(user.status.suspension.history[0]).to.have.property('message', 'This is a message');
|
||||
expect(user.status.suspension.history[0]).to.have.property('created_at').not.null;
|
||||
|
||||
expect(user.suspended).to.be.true;
|
||||
timekeeper.travel(new Date(oneHourFromNow.getTime() + 10000));
|
||||
expect(user.suspended).to.be.false;
|
||||
timekeeper.reset();
|
||||
|
||||
expect(spy).to.have.been.calledOnce;
|
||||
|
||||
const res = await graphql(schema, mutation, {}, ctx, {
|
||||
user_id: user.id,
|
||||
until: null
|
||||
}, 'UnSuspendUser');
|
||||
if (res.errors && res.errors.length > 0) {
|
||||
console.error(res.errors);
|
||||
}
|
||||
expect(res.errors).to.be.undefined;
|
||||
expect(res.data.unsuspendUser).to.be.null;
|
||||
|
||||
user = await UserModel.findOne({id: user.id});
|
||||
|
||||
// Mongoose messes with the date, check within a 2 second window.
|
||||
expect(user.status.suspension.until).to.be.null;
|
||||
expect(user.status.suspension.history).to.have.length(2);
|
||||
expect(user.status.suspension.history[0]).to.have.property('until').to.be.withinTime(new Date(oneHourFromNow.getTime() - 1000), new Date(oneHourFromNow.getTime() + 1000));
|
||||
expect(user.status.suspension.history[0]).to.have.property('assigned_by', actor.id);
|
||||
expect(user.status.suspension.history[0]).to.have.property('created_at').not.null;
|
||||
expect(user.status.suspension.history[1]).to.have.property('until').to.be.null;
|
||||
expect(user.status.suspension.history[1]).to.have.property('assigned_by', actor.id);
|
||||
expect(user.status.suspension.history[1]).to.have.property('created_at').not.null;
|
||||
|
||||
expect(user.suspended).to.be.false;
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,86 @@
|
||||
const {graphql} = require('graphql');
|
||||
|
||||
const schema = require('../../../../graph/schema');
|
||||
const Context = require('../../../../graph/context');
|
||||
const SettingsService = require('../../../../services/settings');
|
||||
const UserModel = require('../../../../models/user');
|
||||
const UsersService = require('../../../../services/users');
|
||||
|
||||
const chai = require('chai');
|
||||
chai.use(require('chai-datetime'));
|
||||
const {expect} = chai;
|
||||
|
||||
[
|
||||
{status: 'APPROVED', name: 'approve', mutation: 'approveUsername'},
|
||||
{status: 'REJECTED', name: 'reject', mutation: 'rejectUsername'}
|
||||
].forEach(({status, name, mutation}) => {
|
||||
describe(`graph.mutations.${mutation}`, () => {
|
||||
let user;
|
||||
beforeEach(async () => {
|
||||
await SettingsService.init();
|
||||
|
||||
user = await UsersService.createLocalUser('usernameA@example.com', 'password', 'usernameA');
|
||||
});
|
||||
|
||||
const setUserUsernameStatusMutation = `
|
||||
mutation SetUserUsernameStatus($user_id: ID!) {
|
||||
${mutation}(id: $user_id) {
|
||||
errors {
|
||||
translation_key
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
[
|
||||
{self: true, error: 'NOT_AUTHORIZED', role: 'COMMENTER'},
|
||||
{self: true, error: 'NOT_AUTHORIZED', role: 'STAFF'},
|
||||
{self: true, error: 'NOT_AUTHORIZED', role: 'COMMENTER'},
|
||||
{error: 'NOT_AUTHORIZED', role: 'COMMENTER'},
|
||||
{error: 'NOT_AUTHORIZED', role: 'STAFF'},
|
||||
{error: 'NOT_AUTHORIZED', role: 'COMMENTER'},
|
||||
{error: false, role: 'MODERATOR'},
|
||||
{error: false, role: 'ADMIN'},
|
||||
].forEach(({self, error, role}) => {
|
||||
it(`${error ? 'can not' : 'can'} ${name} a username with the user role ${role}${self ? ' on themself' : ''}`, async () => {
|
||||
const actor = new UserModel({role});
|
||||
|
||||
// If we're testing self assign, set the id of the actor to the user
|
||||
// we're acting on.
|
||||
if (self) {
|
||||
actor.id = user.id;
|
||||
}
|
||||
|
||||
const ctx = new Context({user: actor});
|
||||
|
||||
const {data, errors} = await graphql(schema, setUserUsernameStatusMutation, {}, ctx, {
|
||||
user_id: user.id,
|
||||
});
|
||||
|
||||
if (errors && errors.length > 0) {
|
||||
console.error(errors);
|
||||
}
|
||||
expect(errors).to.be.undefined;
|
||||
if (error) {
|
||||
expect(data[mutation]).to.have.property('errors').not.null;
|
||||
expect(data[mutation].errors[0]).to.have.property('translation_key', error);
|
||||
} else {
|
||||
expect(data[mutation]).to.be.null;
|
||||
|
||||
user = await UserModel.findOne({id: user.id});
|
||||
|
||||
expect(user.status.username.status).to.equal(status);
|
||||
expect(user.status.username.history).to.have.length(2);
|
||||
expect(user.status.username.history[0]).to.have.property('status', 'SET');
|
||||
expect(user.status.username.history[0]).to.have.property('assigned_by').is.null;
|
||||
expect(user.status.username.history[0]).to.have.property('created_at').not.null;
|
||||
expect(user.status.username.history[1]).to.have.property('status', status);
|
||||
expect(user.status.username.history[1]).to.have.property('assigned_by', actor.id);
|
||||
expect(user.status.username.history[1]).to.have.property('created_at').not.null;
|
||||
|
||||
expect(user.status.username.history[1].created_at).afterTime(user.status.username.history[0].created_at);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -22,18 +22,18 @@ describe('graph.mutations.updateAssetSettings', () => {
|
||||
translation_key
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
}`;
|
||||
|
||||
describe('context with different user roles', () => {
|
||||
|
||||
[
|
||||
{error: 'NOT_AUTHORIZED'},
|
||||
{roles: ['ADMIN', 'MODERATOR']},
|
||||
{roles: ['MODERATOR']},
|
||||
].forEach(({roles, error}) => {
|
||||
it(roles ? roles.join(', ') : '<None>', async () => {
|
||||
const user = new UserModel({roles});
|
||||
{role: 'COMMENTER', error: 'NOT_AUTHORIZED'},
|
||||
{role: 'STAFF', error: 'NOT_AUTHORIZED'},
|
||||
{role: 'ADMIN'},
|
||||
{role: 'MODERATOR'},
|
||||
].forEach(({role, error}) => {
|
||||
it(`role = ${role}`, async () => {
|
||||
const user = new UserModel({role});
|
||||
const ctx = new Context({user});
|
||||
|
||||
const settings = {
|
||||
|
||||
@@ -28,12 +28,12 @@ describe('graph.mutations.updateAssetStatus', () => {
|
||||
describe('context with different user roles', () => {
|
||||
|
||||
[
|
||||
{error: 'NOT_AUTHORIZED'},
|
||||
{roles: ['ADMIN', 'MODERATOR']},
|
||||
{roles: ['MODERATOR']},
|
||||
].forEach(({roles, error}) => {
|
||||
it(roles ? roles.join(', ') : '<None>', async () => {
|
||||
const user = new UserModel({roles});
|
||||
{role: 'COMMENTER', error: 'NOT_AUTHORIZED'},
|
||||
{role: 'ADMIN'},
|
||||
{role: 'MODERATOR'},
|
||||
].forEach(({role, error}) => {
|
||||
it(`role = ${role}`, async () => {
|
||||
const user = new UserModel({role});
|
||||
const ctx = new Context({user});
|
||||
|
||||
const closedAt = (new Date()).toISOString();
|
||||
|
||||
@@ -21,23 +21,17 @@ describe('graph.mutations.updateSettings', () => {
|
||||
translation_key
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
}`;
|
||||
|
||||
describe('context with different user roles', () => {
|
||||
|
||||
[
|
||||
{error: 'NOT_AUTHORIZED'},
|
||||
{error: 'NOT_AUTHORIZED', roles: []},
|
||||
{roles: ['ADMIN']},
|
||||
{roles: ['ADMIN', 'MODERATOR']},
|
||||
{roles: ['MODERATOR']},
|
||||
].forEach(({roles, error}) => {
|
||||
it(roles ? roles.join(', ') : '<None>', async () => {
|
||||
let user;
|
||||
if (roles != null) {
|
||||
user = new UserModel({roles});
|
||||
}
|
||||
{error: 'NOT_AUTHORIZED', role: 'COMMENTER'},
|
||||
{role: 'ADMIN'},
|
||||
{role: 'MODERATOR'},
|
||||
].forEach(({role, error}) => {
|
||||
it(`role = ${role}`, async () => {
|
||||
const user = new UserModel({role});
|
||||
const ctx = new Context({user});
|
||||
|
||||
const newSettings = {
|
||||
@@ -75,7 +69,7 @@ describe('graph.mutations.updateSettings', () => {
|
||||
});
|
||||
|
||||
describe('nested objects', () => {
|
||||
const user = new UserModel({roles: ['ADMIN']});
|
||||
const user = new UserModel({role: 'ADMIN'});
|
||||
const ctx = new Context({user});
|
||||
|
||||
it('should handle nested objects', async () => {
|
||||
|
||||
@@ -56,18 +56,12 @@ describe('graph.queries.settings', () => {
|
||||
];
|
||||
|
||||
[
|
||||
{bl: true},
|
||||
{bl: true, roles: []},
|
||||
{bl: false, roles: ['ADMIN']},
|
||||
{bl: false, roles: ['ADMIN', 'MODERATOR']},
|
||||
{bl: false, roles: ['MODERATOR']},
|
||||
].forEach(({bl, roles}) => {
|
||||
it(roles && roles.length > 0 ? roles.join(', ') : '<None>', async () => {
|
||||
let user;
|
||||
if (roles != null) {
|
||||
user = new UserModel({roles});
|
||||
}
|
||||
|
||||
{bl: true, role: 'COMMENTER'},
|
||||
{bl: false, role: 'ADMIN'},
|
||||
{bl: false, role: 'MODERATOR'},
|
||||
].forEach(({bl, role}) => {
|
||||
it(`role = ${role}`, async () => {
|
||||
let user = new UserModel({role});
|
||||
const ctx = new Context({user});
|
||||
|
||||
const res = await graphql(schema, QUERY, {}, ctx);
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
const {graphql} = require('graphql');
|
||||
|
||||
const schema = require('../../../../graph/schema');
|
||||
const Context = require('../../../../graph/context');
|
||||
const SettingsService = require('../../../../services/settings');
|
||||
const UserModel = require('../../../../models/user');
|
||||
const UsersService = require('../../../../services/users');
|
||||
|
||||
const chai = require('chai');
|
||||
chai.use(require('chai-datetime'));
|
||||
const {expect} = chai;
|
||||
|
||||
describe('graph.queries.user', () => {
|
||||
let user;
|
||||
beforeEach(async () => {
|
||||
await SettingsService.init();
|
||||
|
||||
user = await UsersService.createLocalUser('usernameA@example.com', 'password', 'usernameA');
|
||||
});
|
||||
|
||||
describe('state', () => {
|
||||
|
||||
const meQuery = `
|
||||
query Me {
|
||||
me {
|
||||
state {
|
||||
status {
|
||||
username {
|
||||
status
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
it('can query me', async () => {
|
||||
const ctx = new Context({user});
|
||||
|
||||
const {data, errors} = await graphql(schema, meQuery, {}, ctx);
|
||||
|
||||
expect(errors).to.be.undefined;
|
||||
expect(data.me).to.not.be.null;
|
||||
expect(data.me.state).not.to.be.null;
|
||||
expect(data.me.state.status.username.status).to.be.equal('SET');
|
||||
});
|
||||
|
||||
const query = `
|
||||
query User($user_id: ID!) {
|
||||
user(id: $user_id) {
|
||||
state {
|
||||
status {
|
||||
username {
|
||||
status
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
[
|
||||
{role: 'COMMENTER', can: false},
|
||||
{role: 'STAFF', can: false},
|
||||
{role: 'MODERATOR', can: true},
|
||||
{role: 'ADMIN', can: true},
|
||||
].forEach(({role, can}) => {
|
||||
it(`${can ? 'can' : 'can not'} query with role = ${role}`, async () => {
|
||||
const actor = new UserModel({role});
|
||||
const ctx = new Context({user: actor});
|
||||
|
||||
const {data, errors} = await graphql(schema, query, {}, ctx, {
|
||||
user_id: user.id,
|
||||
});
|
||||
|
||||
expect(errors).to.be.undefined;
|
||||
if (!can) {
|
||||
expect(data.user).to.be.null;
|
||||
} else {
|
||||
expect(data.user).to.not.be.null;
|
||||
expect(data.user.state).not.to.be.null;
|
||||
expect(data.user.state.status.username.status).to.be.equal('SET');
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -6,13 +6,13 @@ const authz = require('../../../middleware/authorization');
|
||||
describe('middleware.authorization', () => {
|
||||
describe('#has', () => {
|
||||
it('allows if no roles are specified', () => {
|
||||
expect(authz.has({roles: []})).to.be.true;
|
||||
expect(authz.has({role: 'COMMENTER'})).to.be.true;
|
||||
});
|
||||
it('allows if the correct roles are met', () => {
|
||||
expect(authz.has({roles: ['ADMIN']}, 'ADMIN', 'MODERATOR')).to.be.true;
|
||||
expect(authz.has({role: 'ADMIN'}, 'ADMIN', 'MODERATOR')).to.be.true;
|
||||
});
|
||||
it('disallows if the role required is missing', () => {
|
||||
expect(authz.has({roles: []}, 'ADMIN', 'MODERATOR')).to.be.false;
|
||||
expect(authz.has({role: 'COMMENTER'}, 'ADMIN', 'MODERATOR')).to.be.false;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -24,17 +24,17 @@ describe('middleware.authorization', () => {
|
||||
};
|
||||
|
||||
it('allows if no roles are specified', () => {
|
||||
needed()({user: {roles: []}}, {}, (err) => {
|
||||
needed()({user: {role: 'COMMENTER'}}, {}, (err) => {
|
||||
expect(err).to.be.undefined;
|
||||
});
|
||||
});
|
||||
it('allows if the correct roles are met', () => {
|
||||
needed()({user: {roles: ['ADMIN']}}, {}, (err) => {
|
||||
needed()({user: {role: 'ADMIN'}}, {}, (err) => {
|
||||
expect(err).to.be.undefined;
|
||||
});
|
||||
});
|
||||
it('disallows if the role required is missing', () => {
|
||||
needed('ADMIN', 'MODERATOR')({user: {roles: []}}, {}, (err) => {
|
||||
needed('ADMIN', 'MODERATOR')({user: {role: 'COMMENTER'}}, {}, (err) => {
|
||||
expect(err).to.not.be.undefined;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,203 @@
|
||||
const migration = require('../../../migrations/1510174676_user_status');
|
||||
const UserModel = require('../../../models/user');
|
||||
|
||||
const chai = require('chai');
|
||||
chai.use(require('chai-datetime'));
|
||||
const {expect} = chai;
|
||||
|
||||
describe('migration.1510174676_user_status', () => {
|
||||
describe('active user', () => {
|
||||
beforeEach(async () => {
|
||||
await UserModel.collection.insert({
|
||||
id: '123',
|
||||
username: 'Kirk',
|
||||
lowercaseUsername: 'kirk',
|
||||
status: 'ACTIVE',
|
||||
canEditName: false
|
||||
});
|
||||
});
|
||||
|
||||
it('completes the migration', async () => {
|
||||
|
||||
let user = await UserModel.collection.findOne({id: '123'});
|
||||
|
||||
expect(user).to.have.property('status', 'ACTIVE');
|
||||
expect(user).to.have.property('canEditName', false);
|
||||
|
||||
// Perform the migration.
|
||||
await migration.up();
|
||||
|
||||
user = await UserModel.collection.findOne({id: '123'});
|
||||
|
||||
// Check that it was correct.
|
||||
expect(user).to.have.property('status');
|
||||
expect(user.status).to.have.property('username');
|
||||
expect(user.status.username).to.have.property('status', 'SET');
|
||||
expect(user.status.username.history).to.have.length(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('social user', () => {
|
||||
beforeEach(async () => {
|
||||
await UserModel.collection.insert({
|
||||
id: '123',
|
||||
username: 'Kirk',
|
||||
lowercaseUsername: 'kirk',
|
||||
status: 'ACTIVE',
|
||||
canEditName: true
|
||||
});
|
||||
});
|
||||
|
||||
it('completes the migration', async () => {
|
||||
|
||||
let user = await UserModel.collection.findOne({id: '123'});
|
||||
|
||||
expect(user).to.have.property('status', 'ACTIVE');
|
||||
expect(user).to.have.property('canEditName', true);
|
||||
|
||||
// Perform the migration.
|
||||
await migration.up();
|
||||
|
||||
user = await UserModel.collection.findOne({id: '123'});
|
||||
|
||||
// Check that it was correct.
|
||||
expect(user).to.have.property('status');
|
||||
expect(user.status).to.have.property('username');
|
||||
expect(user.status.username).to.have.property('status', 'UNSET');
|
||||
expect(user.status.username.history).to.have.length(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('rejected username', () => {
|
||||
beforeEach(async () => {
|
||||
await UserModel.collection.insert({
|
||||
id: '123',
|
||||
username: 'Kirk',
|
||||
lowercaseUsername: 'kirk',
|
||||
status: 'BANNED',
|
||||
canEditName: true
|
||||
});
|
||||
});
|
||||
|
||||
it('completes the migration', async () => {
|
||||
|
||||
let user = await UserModel.collection.findOne({id: '123'});
|
||||
|
||||
expect(user).to.have.property('status');
|
||||
expect(user.status).to.equal('BANNED');
|
||||
expect(user.canEditName).to.equal(true);
|
||||
|
||||
// Perform the migration.
|
||||
await migration.up();
|
||||
|
||||
user = await UserModel.collection.findOne({id: '123'});
|
||||
|
||||
// Check that it was correct.
|
||||
expect(user).to.have.property('status');
|
||||
expect(user.status).to.have.property('banned');
|
||||
expect(user.status.banned).to.have.property('status', false);
|
||||
expect(user.status.username).to.have.property('status', 'REJECTED');
|
||||
expect(user.status.username.history).to.have.length(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('approved username', () => {
|
||||
beforeEach(async () => {
|
||||
await UserModel.collection.insert({
|
||||
id: '123',
|
||||
username: 'Kirk',
|
||||
lowercaseUsername: 'kirk',
|
||||
status: 'APPROVED',
|
||||
canEditName: false
|
||||
});
|
||||
});
|
||||
|
||||
it('completes the migration', async () => {
|
||||
|
||||
let user = await UserModel.collection.findOne({id: '123'});
|
||||
|
||||
expect(user).to.have.property('status');
|
||||
expect(user.status).to.equal('APPROVED');
|
||||
expect(user.canEditName).to.equal(false);
|
||||
|
||||
// Perform the migration.
|
||||
await migration.up();
|
||||
|
||||
user = await UserModel.collection.findOne({id: '123'});
|
||||
|
||||
// Check that it was correct.
|
||||
expect(user).to.have.property('status');
|
||||
expect(user.status).to.have.property('banned');
|
||||
expect(user.status.banned).to.have.property('status', false);
|
||||
expect(user.status.username).to.have.property('status', 'APPROVED');
|
||||
expect(user.status.username.history).to.have.length(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('suspended user', () => {
|
||||
beforeEach(async () => {
|
||||
await UserModel.collection.insert({
|
||||
id: '123',
|
||||
username: 'Kirk',
|
||||
lowercaseUsername: 'kirk',
|
||||
status: 'ACTIVE',
|
||||
suspension: {
|
||||
until: new Date()
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('completes the migration', async () => {
|
||||
|
||||
let user = await UserModel.collection.findOne({id: '123'});
|
||||
|
||||
expect(user).to.have.property('suspension');
|
||||
expect(user.suspension).to.have.property('until');
|
||||
expect(user.suspension.until).to.not.be.null;
|
||||
|
||||
const until = user.suspension.until;
|
||||
|
||||
// Perform the migration.
|
||||
await migration.up();
|
||||
|
||||
user = await UserModel.collection.findOne({id: '123'});
|
||||
|
||||
// Check that it was correct.
|
||||
expect(user).to.have.property('status');
|
||||
expect(user.status).to.have.property('suspension');
|
||||
expect(user.status.suspension).to.have.property('until');
|
||||
expect(user.status.suspension.until).to.not.be.null;
|
||||
expect(user.status.suspension.until).to.be.withinTime(new Date(until.getTime() - 1000), new Date(until.getTime() + 1000));
|
||||
});
|
||||
});
|
||||
|
||||
describe('banned user', () => {
|
||||
beforeEach(async () => {
|
||||
await UserModel.collection.insert({
|
||||
id: '123',
|
||||
username: 'Kirk',
|
||||
lowercaseUsername: 'kirk',
|
||||
status: 'BANNED',
|
||||
canEditName: false
|
||||
});
|
||||
});
|
||||
|
||||
it('completes the migration', async () => {
|
||||
|
||||
let user = await UserModel.collection.findOne({id: '123'});
|
||||
|
||||
expect(user).to.have.property('status');
|
||||
expect(user.status).to.equal('BANNED');
|
||||
|
||||
// Perform the migration.
|
||||
await migration.up();
|
||||
|
||||
user = await UserModel.collection.findOne({id: '123'});
|
||||
|
||||
// Check that it was correct.
|
||||
expect(user).to.have.property('status');
|
||||
expect(user.status).to.have.property('banned');
|
||||
expect(user.status.banned).to.have.property('status', true);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,57 +0,0 @@
|
||||
const passport = require('../../../passport');
|
||||
|
||||
const app = require('../../../../../app');
|
||||
|
||||
const UsersService = require('../../../../../services/users');
|
||||
const SettingsService = require('../../../../../services/settings');
|
||||
const settings = {id: '1', moderation: 'PRE', wordlist: {banned: ['bad words'], suspect: ['suspect words']}};
|
||||
|
||||
const chai = require('chai');
|
||||
chai.should();
|
||||
chai.use(require('chai-http'));
|
||||
const expect = chai.expect;
|
||||
|
||||
describe('/api/v1/account/username', () => {
|
||||
let mockUser;
|
||||
beforeEach(async () => {
|
||||
await SettingsService.init(settings);
|
||||
mockUser = await UsersService.createLocalUser('ana@gmail.com', '123321123', 'Ana');
|
||||
});
|
||||
|
||||
describe('#put', () => {
|
||||
it('it should enable a user to edit their username if canEditName is enabled', async () => {
|
||||
await chai.request(app)
|
||||
.post(`/api/v1/users/${mockUser.id}/username-enable`)
|
||||
.set(passport.inject({id: '456', roles: ['ADMIN']}));
|
||||
|
||||
const res = await chai.request(app)
|
||||
.put('/api/v1/account/username')
|
||||
.set(passport.inject({id: mockUser.id, roles: []}))
|
||||
.send({username: 'MojoJojo'});
|
||||
|
||||
expect(res).to.have.status(204);
|
||||
});
|
||||
|
||||
it('it should return an error if the wrong user tries to edit a username', async () => {
|
||||
await chai.request(app)
|
||||
.post(`/api/v1/users/${mockUser.id}/username-enable`)
|
||||
.set(passport.inject({id: '456', roles: ['ADMIN']}));
|
||||
|
||||
let res = chai.request(app)
|
||||
.put('/api/v1/account/username')
|
||||
.set(passport.inject({id: 'wrongid', roles: []}))
|
||||
.send({username: 'MojoJojo'});
|
||||
|
||||
return expect(res).to.eventually.be.rejected;
|
||||
});
|
||||
|
||||
it('it should return an error when the user tries to edit their username if canEditName is disabled', () => {
|
||||
let res = chai.request(app)
|
||||
.put('/api/v1/account/username')
|
||||
.set(passport.inject({id: mockUser.id, roles: []}))
|
||||
.send({username: 'MojoJojo'});
|
||||
|
||||
return expect(res).to.eventually.be.rejected;
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -40,7 +40,7 @@ describe('/api/v1/assets', () => {
|
||||
for (const role of ['ADMIN', 'MODERATOR']) {
|
||||
const res = await chai.request(app)
|
||||
.get('/api/v1/assets')
|
||||
.set(passport.inject({roles: [role]}));
|
||||
.set(passport.inject({role}));
|
||||
|
||||
const body = res.body;
|
||||
|
||||
@@ -57,7 +57,7 @@ describe('/api/v1/assets', () => {
|
||||
for (const role of ['ADMIN', 'MODERATOR']) {
|
||||
const res = await chai.request(app)
|
||||
.get('/api/v1/assets?value=term2')
|
||||
.set(passport.inject({roles: [role]}));
|
||||
.set(passport.inject({role}));
|
||||
|
||||
const body = res.body;
|
||||
|
||||
@@ -79,7 +79,7 @@ describe('/api/v1/assets', () => {
|
||||
for (const role of ['ADMIN', 'MODERATOR']) {
|
||||
const res = await chai.request(app)
|
||||
.get('/api/v1/assets?value=term3')
|
||||
.set(passport.inject({roles: [role]}));
|
||||
.set(passport.inject({role}));
|
||||
const body = res.body;
|
||||
|
||||
expect(body).to.have.property('count', 0);
|
||||
@@ -93,7 +93,7 @@ describe('/api/v1/assets', () => {
|
||||
for (const role of ['ADMIN', 'MODERATOR']) {
|
||||
const res = await chai.request(app)
|
||||
.get('/api/v1/assets?filter=closed')
|
||||
.set(passport.inject({roles: [role]}));
|
||||
.set(passport.inject({role}));
|
||||
const body = res.body;
|
||||
|
||||
expect(body).to.have.property('count', 1);
|
||||
@@ -109,7 +109,7 @@ describe('/api/v1/assets', () => {
|
||||
for (const role of ['ADMIN', 'MODERATOR']) {
|
||||
const res = await chai.request(app)
|
||||
.get('/api/v1/assets?filter=open')
|
||||
.set(passport.inject({roles: [role]}));
|
||||
.set(passport.inject({role}));
|
||||
const body = res.body;
|
||||
|
||||
expect(body).to.have.property('count', 1);
|
||||
@@ -134,7 +134,7 @@ describe('/api/v1/assets', () => {
|
||||
|
||||
const res = await chai.request(app)
|
||||
.put(`/api/v1/assets/${asset.id}/status`)
|
||||
.set(passport.inject({roles: ['ADMIN']}))
|
||||
.set(passport.inject({role: 'ADMIN'}))
|
||||
.send({closedAt: today});
|
||||
|
||||
expect(res).to.have.status(204);
|
||||
@@ -153,7 +153,7 @@ describe('/api/v1/assets', () => {
|
||||
|
||||
const promise = chai.request(app)
|
||||
.put(`/api/v1/assets/${asset.id}/status`)
|
||||
.set(passport.inject({roles: ['MODERATOR']}))
|
||||
.set(passport.inject({role: 'MODERATOR'}))
|
||||
.send({closedAt: today});
|
||||
await expect(promise).to.eventually.be.rejected;
|
||||
});
|
||||
|
||||
@@ -20,9 +20,7 @@ describe('/api/v1/settings', () => {
|
||||
for (let role of ['ADMIN', 'MODERATOR']) {
|
||||
const res = await chai.request(app)
|
||||
.get('/api/v1/settings')
|
||||
.set(passport.inject({
|
||||
roles: [role]
|
||||
}));
|
||||
.set(passport.inject({role}));
|
||||
expect(res).to.have.status(200);
|
||||
expect(res).to.be.json;
|
||||
expect(res.body).to.have.property('moderation', 'PRE');
|
||||
@@ -35,7 +33,7 @@ describe('/api/v1/settings', () => {
|
||||
it('should update the settings', () => {
|
||||
return chai.request(app)
|
||||
.put('/api/v1/settings')
|
||||
.set(passport.inject({roles: ['ADMIN']}))
|
||||
.set(passport.inject({role: 'ADMIN'}))
|
||||
.send({moderation: 'POST'})
|
||||
.then((res) => {
|
||||
expect(res).to.have.status(204);
|
||||
@@ -50,7 +48,7 @@ describe('/api/v1/settings', () => {
|
||||
it('should require ADMIN role', () => {
|
||||
const promise = chai.request(app)
|
||||
.put('/api/v1/settings')
|
||||
.set(passport.inject({roles: ['MODERATOR']}))
|
||||
.set(passport.inject({role: 'MODERATOR'}))
|
||||
.send({moderation: 'POST'});
|
||||
return expect(promise).to.eventually.be.rejected;
|
||||
});
|
||||
|
||||
@@ -30,7 +30,7 @@ describe('/api/v1/users/:user_id/email/confirm', () => {
|
||||
|
||||
return chai.request(app)
|
||||
.post(`/api/v1/users/${mockUser.id}/email/confirm`)
|
||||
.set(passport.inject({roles: ['ADMIN']}))
|
||||
.set(passport.inject({role: 'ADMIN'}))
|
||||
.then((res) => {
|
||||
expect(res).to.have.status(204);
|
||||
expect(mailer.task.tasks).to.have.length(1);
|
||||
@@ -40,7 +40,7 @@ describe('/api/v1/users/:user_id/email/confirm', () => {
|
||||
it('should send a 404 on not matching a user', () => {
|
||||
return chai.request(app)
|
||||
.post(`/api/v1/users/${mockUser.id}/email/confirm`)
|
||||
.set(passport.inject({roles: ['ADMIN']}))
|
||||
.set(passport.inject({role: 'ADMIN'}))
|
||||
.then((res) => {
|
||||
expect(res).to.have.status(204);
|
||||
expect(mailer.task.tasks).to.have.length(1);
|
||||
@@ -48,52 +48,3 @@ describe('/api/v1/users/:user_id/email/confirm', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('/api/v1/users/:user_id/actions', () => {
|
||||
|
||||
let mockUser;
|
||||
|
||||
beforeEach(() => SettingsService.init(settings).then(() => {
|
||||
return UsersService.createLocalUser('ana@gmail.com', '123321123', 'Ana');
|
||||
})
|
||||
.then((user) => {
|
||||
mockUser = user;
|
||||
}));
|
||||
|
||||
describe('#post', () => {
|
||||
it('it should update actions', () => {
|
||||
return chai.request(app)
|
||||
.post(`/api/v1/users/${mockUser.id}/actions`)
|
||||
.set(passport.inject({id: '456', roles: ['ADMIN']}))
|
||||
.send({'action_type': 'FLAG', metadata: {reason: 'Bio is too awesome.'}})
|
||||
.then((res) => {
|
||||
expect(res).to.have.status(201);
|
||||
expect(res).to.have.body;
|
||||
expect(res.body).to.have.property('action_type', 'FLAG');
|
||||
expect(res.body).to.have.property('item_id', mockUser.id);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('/api/v1/users/:user_id/username-enable', () => {
|
||||
let mockUser;
|
||||
|
||||
beforeEach(() => SettingsService.init(settings).then(() => {
|
||||
return UsersService.createLocalUser('ana@gmail.com', '123321123', 'Ana');
|
||||
})
|
||||
.then((user) => {
|
||||
mockUser = user;
|
||||
}));
|
||||
|
||||
describe('#post', () => {
|
||||
it('it should enable a user to edit their username', () => {
|
||||
return chai.request(app)
|
||||
.post(`/api/v1/users/${mockUser.id}/username-enable`)
|
||||
.set(passport.inject({id: '456', roles: ['ADMIN']}))
|
||||
.then((res) => {
|
||||
expect(res).to.have.status(204);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -75,7 +75,7 @@ describe('services.ActionsService', () => {
|
||||
expect(retrievedAction).has.property('item_id', comment.id);
|
||||
});
|
||||
|
||||
it('fires the callback sucesfully', async () => {
|
||||
it('fires the callback successfully', async () => {
|
||||
const srcAction = {
|
||||
action_type: 'LIKE',
|
||||
item_type: 'COMMENTS',
|
||||
@@ -113,7 +113,7 @@ describe('services.ActionsService', () => {
|
||||
expect(retrievedAction).is.null;
|
||||
});
|
||||
|
||||
it('fires the callback sucesfully', async () => {
|
||||
it('fires the callback successfully', async () => {
|
||||
const spy = sinon.spy();
|
||||
events.once(ACTIONS_DELETE, spy);
|
||||
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
const expect = require('chai').expect;
|
||||
const Domainlist = require('../../../services/domainlist');
|
||||
const DomainList = require('../../../services/domain_list');
|
||||
const SettingsService = require('../../../services/settings');
|
||||
|
||||
describe('services.Domainlist', () => {
|
||||
describe('services.DomainList', () => {
|
||||
|
||||
const domainlists = {
|
||||
const domainLists = {
|
||||
whitelist: [
|
||||
'nytimes.com',
|
||||
'wapo.com'
|
||||
]
|
||||
};
|
||||
|
||||
let domainlist = new Domainlist();
|
||||
let domainList = new DomainList();
|
||||
const settings = {id: '1', moderation: 'PRE', domainlist: {whitelist: ['nytimes.com', 'wapo.com']}};
|
||||
|
||||
beforeEach(() => SettingsService.init(settings));
|
||||
|
||||
describe('#init', () => {
|
||||
|
||||
before(() => domainlist.upsert(domainlists));
|
||||
before(() => domainList.upsert(domainLists));
|
||||
|
||||
it('has entries', () => {
|
||||
expect(domainlist.lists.whitelist).to.not.be.empty;
|
||||
expect(domainList.lists.whitelist).to.not.be.empty;
|
||||
});
|
||||
|
||||
});
|
||||
@@ -92,21 +92,21 @@ describe('services.Domainlist', () => {
|
||||
['google.Ca:80', 'google.ca'],
|
||||
['google.Ca:443', 'google.ca'],
|
||||
].forEach(([domain, hostname]) => {
|
||||
expect(Domainlist.parseURL(domain), `domain ${domain} should be parsed as ${hostname}`).to.equal(hostname);
|
||||
expect(DomainList.parseURL(domain), `domain ${domain} should be parsed as ${hostname}`).to.equal(hostname);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#match', () => {
|
||||
|
||||
const whiteList = Domainlist.parseList(domainlists['whitelist']);
|
||||
const whiteList = DomainList.parseList(domainLists['whitelist']);
|
||||
|
||||
it('does match on an included domain', () => {
|
||||
[
|
||||
'http://wapo.com',
|
||||
'nytimes.com'
|
||||
].forEach((domain) => {
|
||||
expect(domainlist.match(whiteList, domain)).to.be.true;
|
||||
expect(domainList.match(whiteList, domain)).to.be.true;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -116,7 +116,7 @@ describe('services.Domainlist', () => {
|
||||
'www.badsite.com',
|
||||
'otherexample.com'
|
||||
].forEach((domain) => {
|
||||
expect(domainlist.match(whiteList, domain)).to.be.false;
|
||||
expect(domainList.match(whiteList, domain)).to.be.false;
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,22 +0,0 @@
|
||||
describe('services.scraper', () => {
|
||||
describe('#create', () => {
|
||||
it('should create a new kue job');
|
||||
});
|
||||
|
||||
describe('#scrape', () => {
|
||||
it('should scrape complete information');
|
||||
it('should scrape what it can');
|
||||
});
|
||||
|
||||
describe('#update', () => {
|
||||
it('should update the database record entries from the meta');
|
||||
});
|
||||
|
||||
describe('#process', () => {
|
||||
it('should start the processor to scrape assets');
|
||||
});
|
||||
|
||||
describe('#shutdown', () => {
|
||||
it('should shutdown the job processor');
|
||||
});
|
||||
});
|
||||
+60
-146
@@ -1,6 +1,6 @@
|
||||
const UsersService = require('../../../services/users');
|
||||
const SettingsService = require('../../../services/settings');
|
||||
const MailerService = require('../../../services/mailer');
|
||||
const mailer = require('../../../services/mailer');
|
||||
|
||||
const chai = require('chai');
|
||||
chai.use(require('chai-as-promised'));
|
||||
@@ -29,11 +29,11 @@ describe('services.UsersService', () => {
|
||||
password: '3Coral!3'
|
||||
}]);
|
||||
|
||||
sinon.spy(MailerService, 'send');
|
||||
sinon.spy(mailer, 'send');
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
MailerService.send.restore();
|
||||
mailer.send.restore();
|
||||
});
|
||||
|
||||
describe('#findById()', () => {
|
||||
@@ -151,21 +151,6 @@ describe('services.UsersService', () => {
|
||||
|
||||
});
|
||||
|
||||
describe('#setStatus', () => {
|
||||
it('should set the status to active', () => {
|
||||
return UsersService
|
||||
.setStatus(mockUsers[0].id, 'ACTIVE')
|
||||
.then(() => UsersService.findById(mockUsers[0].id))
|
||||
.then((user) => {
|
||||
expect(user).to.have.property('status', 'ACTIVE');
|
||||
})
|
||||
.then(() => {
|
||||
expect(MailerService.send).to.not.have.been.called;
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
describe('#ignoreUser', () => {
|
||||
it('should add user id to ignoredUsers set', async () => {
|
||||
const user = mockUsers[0];
|
||||
@@ -183,7 +168,7 @@ describe('services.UsersService', () => {
|
||||
it('should not ignore a staff member', async () => {
|
||||
const user = mockUsers[0];
|
||||
const usersToIgnore = [mockUsers[1]];
|
||||
await UsersService.addRoleToUser(usersToIgnore[0].id, 'STAFF');
|
||||
await UsersService.setRole(usersToIgnore[0].id, 'STAFF');
|
||||
|
||||
try {
|
||||
await UsersService.ignoreUsers(user.id, usersToIgnore.map((u) => u.id));
|
||||
@@ -194,145 +179,75 @@ describe('services.UsersService', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('#ban', () => {
|
||||
it('should set the status to banned', () => {
|
||||
return UsersService
|
||||
.setStatus(mockUsers[0].id, 'BANNED')
|
||||
.then(() => UsersService.findById(mockUsers[0].id))
|
||||
.then((user) => {
|
||||
expect(user).to.have.property('status', 'BANNED');
|
||||
})
|
||||
.then(() => {
|
||||
expect(MailerService.send).to.have.been.calledWithMatch({
|
||||
template: 'banned',
|
||||
to: mockUsers[0].profiles[0].id
|
||||
});
|
||||
[
|
||||
{func: 'changeUsername', okStatus: 'REJECTED', notOKStatus: 'UNSET', newStatus: 'CHANGED'},
|
||||
{func: 'setUsername', okStatus: 'UNSET', notOKStatus: 'REJECTED', newStatus: 'SET'},
|
||||
].forEach(({func, okStatus, notOKStatus, newStatus}) => {
|
||||
describe(`#${func}`, () => {
|
||||
[
|
||||
{status: okStatus},
|
||||
{error: 'EDIT_USERNAME_NOT_AUTHORIZED', status: notOKStatus},
|
||||
{error: 'EDIT_USERNAME_NOT_AUTHORIZED', status: 'SET'},
|
||||
{error: 'EDIT_USERNAME_NOT_AUTHORIZED', status: 'APPROVED'},
|
||||
{error: 'EDIT_USERNAME_NOT_AUTHORIZED', status: 'CHANGED'},
|
||||
].forEach(({status, error}) => {
|
||||
it(`${error ? 'should not' : 'should'} let them change the username if they have the status of ${status}`, async () => {
|
||||
const user = mockUsers[0];
|
||||
|
||||
// Set the user to the desired status.
|
||||
await UsersService.setUsernameStatus(user.id, status);
|
||||
|
||||
try {
|
||||
await UsersService[func](user.id, 'spock');
|
||||
} catch (err) {
|
||||
if (error) {
|
||||
expect(err).have.property('translation_key', error);
|
||||
} else {
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should still disable and ban the user if there is no comment', () => {
|
||||
return UsersService
|
||||
.setStatus(mockUsers[0].id, 'BANNED')
|
||||
.then(() => UsersService.findById(mockUsers[0].id))
|
||||
.then((user) => {
|
||||
expect(user).to.have.property('status', 'BANNED');
|
||||
});
|
||||
});
|
||||
});
|
||||
it(`should change the status to ${newStatus} when changed`, async () => {
|
||||
const user = mockUsers[0];
|
||||
|
||||
describe('#unban', () => {
|
||||
it('should set the status to active', () => {
|
||||
return UsersService
|
||||
.setStatus(mockUsers[0].id, 'ACTIVE')
|
||||
.then(() => UsersService.findById(mockUsers[0].id))
|
||||
.then((user) => {
|
||||
expect(user).to.have.property('status', 'ACTIVE');
|
||||
});
|
||||
});
|
||||
});
|
||||
// Set the user to the desired status.
|
||||
await UsersService.setUsernameStatus(user.id, okStatus);
|
||||
|
||||
describe('#toggleNameEdit', () => {
|
||||
it('should toggle the canEditName field', () => {
|
||||
return UsersService
|
||||
.toggleNameEdit(mockUsers[0].id, true)
|
||||
.then(() => UsersService.findById(mockUsers[0].id))
|
||||
.then((user) => {
|
||||
expect(user).to.have.property('canEditName', true);
|
||||
});
|
||||
});
|
||||
});
|
||||
const editedUser = await UsersService[func](user.id, 'spock');
|
||||
|
||||
describe('#search', () => {
|
||||
it('should return all the results without a value', async () => {
|
||||
expect(await UsersService.search()).to.have.length(3);
|
||||
});
|
||||
expect(editedUser.status.username.status).to.equal(newStatus);
|
||||
|
||||
it('should match the search terms', async () => {
|
||||
const tests = [
|
||||
{
|
||||
search: 'monster',
|
||||
results: 1,
|
||||
id: mockUsers[1].id,
|
||||
},
|
||||
{
|
||||
search: 'Stamp',
|
||||
results: 1,
|
||||
id: mockUsers[0].id,
|
||||
},
|
||||
{
|
||||
search: 'sockmonster@gmail.com',
|
||||
results: 1,
|
||||
id: mockUsers[1].id,
|
||||
},
|
||||
{
|
||||
search: 'marvel',
|
||||
results: 1,
|
||||
id: mockUsers[2].id,
|
||||
},
|
||||
{
|
||||
search: 'gmail.com',
|
||||
results: 3
|
||||
try {
|
||||
await UsersService[func](user.id, 'spock');
|
||||
throw new Error('edit was processed successfully');
|
||||
} catch (err) {
|
||||
expect(err).have.property('translation_key', 'EDIT_USERNAME_NOT_AUTHORIZED');
|
||||
}
|
||||
];
|
||||
});
|
||||
|
||||
for (const test of tests) {
|
||||
const users = await UsersService.search(test.search);
|
||||
it(`${func === 'changeUsername' ? 'should' : 'should not'} refuse changing the username to the same username`, async () => {
|
||||
const user = mockUsers[0];
|
||||
|
||||
expect(users).to.have.length(test.results);
|
||||
if (test.results === 1) {
|
||||
expect(users[0]).to.have.property('id', test.id);
|
||||
// Set the user to the desired status.
|
||||
await UsersService.setUsernameStatus(user.id, okStatus);
|
||||
|
||||
if (func === 'changeUsername') {
|
||||
try {
|
||||
await UsersService[func](user.id, user.username);
|
||||
throw new Error('edit was processed successfully');
|
||||
} catch (err) {
|
||||
expect(err).have.property('translation_key', 'SAME_USERNAME_PROVIDED');
|
||||
}
|
||||
} else {
|
||||
await UsersService[func](user.id, user.username);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('#editName', () => {
|
||||
it('should let the user edit their username if the proper toggle is set', () => {
|
||||
return UsersService
|
||||
.toggleNameEdit(mockUsers[0].id, true)
|
||||
.then(() => UsersService.editName(mockUsers[0].id, 'Jojo'))
|
||||
.then(() => UsersService.findById(mockUsers[0].id))
|
||||
.then((user) => {
|
||||
expect(user).to.have.property('username', 'Jojo');
|
||||
expect(user).to.have.property('canEditName', false);
|
||||
});
|
||||
});
|
||||
|
||||
it('should let the user submit the same username if user is not banned (create username)', () => {
|
||||
return UsersService
|
||||
.toggleNameEdit(mockUsers[0].id, true)
|
||||
.then(() => UsersService.editName(mockUsers[0].id, mockUsers[0].username))
|
||||
.then(() => UsersService.findById(mockUsers[0].id))
|
||||
.then((user) => {
|
||||
expect(user).to.have.property('username', mockUsers[0].username);
|
||||
expect(user).to.have.property('canEditName', false);
|
||||
});
|
||||
});
|
||||
|
||||
it('should return error when a banned user submits the same username (rejected username)', () => {
|
||||
return UsersService
|
||||
.toggleNameEdit(mockUsers[0].id, true)
|
||||
.then(() => UsersService.setStatus(mockUsers[0].id, 'BANNED'))
|
||||
.then(() => UsersService.editName(mockUsers[0].id, mockUsers[0].username))
|
||||
.then(() => UsersService.findById(mockUsers[0].id))
|
||||
.then(() => {
|
||||
throw new Error('Error expected');
|
||||
})
|
||||
.catch((err) => {
|
||||
expect(err.status).to.equal(400);
|
||||
expect(err.translation_key).to.equal('SAME_USERNAME_PROVIDED');
|
||||
});
|
||||
});
|
||||
|
||||
it('should return an error if canEditName is false', async () => {
|
||||
return expect(UsersService.editName(mockUsers[0].id, 'Jojo')).to.eventually.be.rejected;
|
||||
});
|
||||
|
||||
it('should return an error if the username is already taken', async () => {
|
||||
await UsersService.toggleNameEdit(mockUsers[0].id, true);
|
||||
return expect(UsersService.editName(mockUsers[0].id, 'Marvel')).to.eventually.be.rejected;
|
||||
});
|
||||
|
||||
describe('#isValidUsername', () => {
|
||||
it('should not allow non-alphanumeric characters in usernames', () => {
|
||||
return UsersService
|
||||
.isValidUsername('hi🖕')
|
||||
@@ -344,5 +259,4 @@ describe('services.UsersService', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user