mirror of
https://github.com/wassname/talk.git
synced 2026-08-13 12:40:11 +08:00
Merge branch 'next' into reply
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