diff --git a/test/api/v3/integration/chat/POST-chat.flag.test.js b/test/api/v3/integration/chat/POST-chat.flag.test.js index d2e01398b5..f7e13dcfbe 100644 --- a/test/api/v3/integration/chat/POST-chat.flag.test.js +++ b/test/api/v3/integration/chat/POST-chat.flag.test.js @@ -5,144 +5,181 @@ import { import { find } from 'lodash'; describe('POST /chat/:chatId/flag', () => { - let user, admin, anotherUser, group; - const TEST_MESSAGE = 'Test Message'; + context('Flags a Group Chat', () => { + let user, admin, anotherUser, group; + const TEST_MESSAGE = 'Test Message'; - beforeEach(async () => { - user = await generateUser({balance: 1}); - admin = await generateUser({balance: 1, 'contributor.admin': true}); - anotherUser = await generateUser(); + beforeEach(async () => { + user = await generateUser({balance: 1}); + admin = await generateUser({balance: 1, 'contributor.admin': true}); + anotherUser = await generateUser(); - group = await user.post('/groups', { - name: 'Test Guild', - type: 'guild', - privacy: 'public', - }); - }); - - it('Returns an error when chat message is not found', async () => { - await expect(user.post(`/groups/${group._id}/chat/incorrectMessage/flag`)) - .to.eventually.be.rejected.and.eql({ - code: 404, - error: 'NotFound', - message: t('messageGroupChatNotFound'), + group = await user.post('/groups', { + name: 'Test Guild', + type: 'guild', + privacy: 'public', }); - }); - - it('Allows players to flag their own message', async () => { - let message = await user.post(`/groups/${group._id}/chat`, {message: TEST_MESSAGE}); - await expect(user.post(`/groups/${group._id}/chat/${message.message.id}/flag`)).to.eventually.be.ok; - }); - - it('Flags a chat', async () => { - let { message } = await anotherUser.post(`/groups/${group._id}/chat`, {message: TEST_MESSAGE}); - - let flagResult = await user.post(`/groups/${group._id}/chat/${message.id}/flag`); - expect(flagResult.flags[user._id]).to.equal(true); - expect(flagResult.flagCount).to.equal(1); - - let groupWithFlags = await admin.get(`/groups/${group._id}`); - - let messageToCheck = find(groupWithFlags.chat, {id: message.id}); - expect(messageToCheck.flags[user._id]).to.equal(true); - }); - - it('Flags a chat when the author\'s account was deleted', async () => { - let deletedUser = await generateUser(); - let { message } = await deletedUser.post(`/groups/${group._id}/chat`, {message: TEST_MESSAGE}); - await deletedUser.del('/user', { - password: 'password', }); - let flagResult = await user.post(`/groups/${group._id}/chat/${message.id}/flag`); - expect(flagResult.flags[user._id]).to.equal(true); - expect(flagResult.flagCount).to.equal(1); - - let groupWithFlags = await admin.get(`/groups/${group._id}`); - - let messageToCheck = find(groupWithFlags.chat, {id: message.id}); - expect(messageToCheck.flags[user._id]).to.equal(true); - }); - - it('Flags a chat with a higher flag acount when an admin flags the message', async () => { - let { message } = await user.post(`/groups/${group._id}/chat`, {message: TEST_MESSAGE}); - - let flagResult = await admin.post(`/groups/${group._id}/chat/${message.id}/flag`); - expect(flagResult.flags[admin._id]).to.equal(true); - expect(flagResult.flagCount).to.equal(5); - - let groupWithFlags = await admin.get(`/groups/${group._id}`); - - let messageToCheck = find(groupWithFlags.chat, {id: message.id}); - expect(messageToCheck.flags[admin._id]).to.equal(true); - expect(messageToCheck.flagCount).to.equal(5); - }); - - it('allows admin to flag a message in a private group', async () => { - let privateGroup = await user.post('/groups', { - name: 'Test party', - type: 'party', - privacy: 'private', + it('Returns an error when chat message is not found', async () => { + await expect(user.post(`/groups/${group._id}/chat/incorrectMessage/flag`)) + .to.eventually.be.rejected.and.eql({ + code: 404, + error: 'NotFound', + message: t('messageGroupChatNotFound'), + }); }); - await user.post(`/groups/${privateGroup._id}/invite`, { - uuids: [anotherUser._id], + + it('Allows players to flag their own message', async () => { + let message = await user.post(`/groups/${group._id}/chat`, {message: TEST_MESSAGE}); + await expect(user.post(`/groups/${group._id}/chat/${message.message.id}/flag`)).to.eventually.be.ok; }); - await anotherUser.post(`/groups/${privateGroup._id}/join`); - let { message } = await user.post(`/groups/${privateGroup._id}/chat`, {message: TEST_MESSAGE}); - let flagResult = await admin.post(`/groups/${privateGroup._id}/chat/${message.id}/flag`); + it('Flags a chat', async () => { + let { message } = await anotherUser.post(`/groups/${group._id}/chat`, {message: TEST_MESSAGE}); - expect(flagResult.flags[admin._id]).to.equal(true); - expect(flagResult.flagCount).to.equal(5); + let flagResult = await user.post(`/groups/${group._id}/chat/${message.id}/flag`); + expect(flagResult.flags[user._id]).to.equal(true); + expect(flagResult.flagCount).to.equal(1); - let groupWithFlags = await anotherUser.get(`/groups/${privateGroup._id}`); - let messageToCheck = find(groupWithFlags.chat, {id: message.id}); + let groupWithFlags = await admin.get(`/groups/${group._id}`); - expect(messageToCheck).to.not.exist; - }); - - it('does not allow non member to flag message in private group', async () => { - let privateGroup = await user.post('/groups', { - name: 'Test party', - type: 'party', - privacy: 'private', + let messageToCheck = find(groupWithFlags.chat, {id: message.id}); + expect(messageToCheck.flags[user._id]).to.equal(true); }); - let { message } = await user.post(`/groups/${privateGroup._id}/chat`, {message: TEST_MESSAGE}); - await expect(anotherUser.post(`/groups/${privateGroup._id}/chat/${message.id}/flag`)) - .to.eventually.be.rejected.and.eql({ - code: 404, - error: 'NotFound', - message: t('groupNotFound'), + it('Flags a chat when the author\'s account was deleted', async () => { + let deletedUser = await generateUser(); + let { message } = await deletedUser.post(`/groups/${group._id}/chat`, {message: TEST_MESSAGE}); + await deletedUser.del('/user', { + password: 'password', }); - }); - it('Returns an error when user tries to flag a message that is already flagged', async () => { - let { message } = await anotherUser.post(`/groups/${group._id}/chat`, {message: TEST_MESSAGE}); + let flagResult = await user.post(`/groups/${group._id}/chat/${message.id}/flag`); + expect(flagResult.flags[user._id]).to.equal(true); + expect(flagResult.flagCount).to.equal(1); - await user.post(`/groups/${group._id}/chat/${message.id}/flag`); + let groupWithFlags = await admin.get(`/groups/${group._id}`); - await expect(user.post(`/groups/${group._id}/chat/${message.id}/flag`)) - .to.eventually.be.rejected.and.eql({ - code: 404, - error: 'NotFound', - message: t('messageGroupChatFlagAlreadyReported'), + let messageToCheck = find(groupWithFlags.chat, {id: message.id}); + expect(messageToCheck.flags[user._id]).to.equal(true); + }); + + it('Flags a chat with a higher flag acount when an admin flags the message', async () => { + let { message } = await user.post(`/groups/${group._id}/chat`, {message: TEST_MESSAGE}); + + let flagResult = await admin.post(`/groups/${group._id}/chat/${message.id}/flag`); + expect(flagResult.flags[admin._id]).to.equal(true); + expect(flagResult.flagCount).to.equal(5); + + let groupWithFlags = await admin.get(`/groups/${group._id}`); + + let messageToCheck = find(groupWithFlags.chat, {id: message.id}); + expect(messageToCheck.flags[admin._id]).to.equal(true); + expect(messageToCheck.flagCount).to.equal(5); + }); + + it('allows admin to flag a message in a private group', async () => { + let privateGroup = await user.post('/groups', { + name: 'Test party', + type: 'party', + privacy: 'private', }); + await user.post(`/groups/${privateGroup._id}/invite`, { + uuids: [anotherUser._id], + }); + await anotherUser.post(`/groups/${privateGroup._id}/join`); + let { message } = await user.post(`/groups/${privateGroup._id}/chat`, {message: TEST_MESSAGE}); + + let flagResult = await admin.post(`/groups/${privateGroup._id}/chat/${message.id}/flag`); + + expect(flagResult.flags[admin._id]).to.equal(true); + expect(flagResult.flagCount).to.equal(5); + + let groupWithFlags = await anotherUser.get(`/groups/${privateGroup._id}`); + let messageToCheck = find(groupWithFlags.chat, {id: message.id}); + + expect(messageToCheck).to.not.exist; + }); + + it('does not allow non member to flag message in private group', async () => { + let privateGroup = await user.post('/groups', { + name: 'Test party', + type: 'party', + privacy: 'private', + }); + let { message } = await user.post(`/groups/${privateGroup._id}/chat`, {message: TEST_MESSAGE}); + + await expect(anotherUser.post(`/groups/${privateGroup._id}/chat/${message.id}/flag`)) + .to.eventually.be.rejected.and.eql({ + code: 404, + error: 'NotFound', + message: t('groupNotFound'), + }); + }); + + it('Returns an error when user tries to flag a message that is already flagged', async () => { + let { message } = await anotherUser.post(`/groups/${group._id}/chat`, {message: TEST_MESSAGE}); + + await user.post(`/groups/${group._id}/chat/${message.id}/flag`); + + await expect(user.post(`/groups/${group._id}/chat/${message.id}/flag`)) + .to.eventually.be.rejected.and.eql({ + code: 404, + error: 'NotFound', + message: t('messageGroupChatFlagAlreadyReported'), + }); + }); + + it('shows a hidden message to the original poster', async () => { + let { message } = await user.post(`/groups/${group._id}/chat`, {message: TEST_MESSAGE}); + + await admin.post(`/groups/${group._id}/chat/${message.id}/flag`); + + let groupWithFlags = await user.get(`/groups/${group._id}`); + let messageToCheck = find(groupWithFlags.chat, {id: message.id}); + + expect(messageToCheck).to.exist; + + let auGroupWithFlags = await anotherUser.get(`/groups/${group._id}`); + let auMessageToCheck = find(auGroupWithFlags.chat, {id: message.id}); + + expect(auMessageToCheck).to.not.exist; + }); }); - it('shows a hidden message to the original poster', async () => { - let { message } = await user.post(`/groups/${group._id}/chat`, {message: TEST_MESSAGE}); + context('Flags an inbox chat', () => { + let user; - await admin.post(`/groups/${group._id}/chat/${message.id}/flag`); + beforeEach(async () => { + user = await generateUser(); + }); - let groupWithFlags = await user.get(`/groups/${group._id}`); - let messageToCheck = find(groupWithFlags.chat, {id: message.id}); + it('Flags a chat', async () => { + const messageToSend = 'messageToSend'; + const receiver = await generateUser(); - expect(messageToCheck).to.exist; + await user.post('/members/send-private-message', { + message: messageToSend, + toUserId: receiver._id, + }); - let auGroupWithFlags = await anotherUser.get(`/groups/${group._id}`); - let auMessageToCheck = find(auGroupWithFlags.chat, {id: message.id}); + const updatedReceiver = await receiver.get('/user'); + const sendersMessageInReceiversInbox = find(updatedReceiver.inbox.messages, (message) => { + return message.uuid === user._id && message.text === messageToSend; + }); - expect(auMessageToCheck).to.not.exist; + const flagResult = await receiver.post(`/chat/${sendersMessageInReceiversInbox.id}/flag`); + expect(flagResult.flags[receiver._id]).to.equal(true); + expect(flagResult.flagCount).to.equal(1); + + const updatedReceiverAfterFlag = await receiver.get('/user'); + const receiversInboxAfterFlag = _.find(updatedReceiverAfterFlag.inbox.messages, (message) => { + return message.uuid === user._id && message.text === messageToSend; + }); + + expect(receiversInboxAfterFlag.flags[receiver._id]).to.equal(true); + expect(receiversInboxAfterFlag.flagCount).to.equal(1); + }); }); }); diff --git a/website/client/app.vue b/website/client/app.vue index 28d957bb51..055abf95cc 100644 --- a/website/client/app.vue +++ b/website/client/app.vue @@ -9,6 +9,7 @@ div h2 {{$t('tipTitle', {tipNumber: currentTipNumber})}} p {{currentTip}} #app(:class='{"casting-spell": castingSpell}') + report-flag-modal amazon-payments-modal snackbars router-view(v-if="!isUserLoggedIn || isStaticPage") @@ -118,6 +119,7 @@ import SelectMembersModal from 'client/components/selectMembersModal.vue'; import notifications from 'client/mixins/notifications'; import { setup as setupPayments } from 'client/libs/payments'; import amazonPaymentsModal from 'client/components/payments/amazonModal'; +import reportFlagModal from 'client/components/chat/reportFlagModal'; export default { mixins: [notifications], @@ -131,6 +133,7 @@ export default { BuyModal, SelectMembersModal, amazonPaymentsModal, + reportFlagModal, }, data () { return { diff --git a/website/client/components/chat/chatCard.vue b/website/client/components/chat/chatCard.vue index f588ac8a5f..9f29c18e4e 100644 --- a/website/client/components/chat/chatCard.vue +++ b/website/client/components/chat/chatCard.vue @@ -3,6 +3,7 @@ div .mentioned-icon(v-if='isUserMentioned') .message-hidden(v-if='msg.flagCount === 1 && user.contributor.admin') Message flagged once, not hidden .message-hidden(v-if='msg.flagCount > 1 && user.contributor.admin') Message hidden + .flag-message(v-if='msg.flags && msg.flags[user._id]') {{$t('youFlaggedThisMessage')}} .card-body h3.leader( :class='userLevelStyle(msg)', @@ -23,7 +24,7 @@ div .svg-icon(v-html="icons.copy") | {{$t('copyAsTodo')}} // @TODO make copyAsTodo work in the inbox - span.action(v-if='!inbox && user.flags.communityGuidelinesAccepted && msg.uuid !== "system"', @click='report(msg)') + span.action(v-if='user.flags.communityGuidelinesAccepted && msg.uuid !== "system"', @click='report(msg)') .svg-icon(v-html="icons.report") | {{$t('report')}} // @TODO make flagging/reporting work in the inbox. NOTE: it must work even if the communityGuidelines are not accepted and it MUST work for messages that you have SENT as well as received. -- Alys @@ -49,7 +50,7 @@ div top: -.5em; } - .message-hidden { + .message-hidden, .flag-message { margin-left: 1.5em; margin-top: 1em; color: red; diff --git a/website/client/components/chat/chatMessages.vue b/website/client/components/chat/chatMessages.vue index ddd2480197..065199a0a8 100644 --- a/website/client/components/chat/chatMessages.vue +++ b/website/client/components/chat/chatMessages.vue @@ -3,7 +3,6 @@ .row .col-12 copy-as-todo-modal(:group-name='groupName', :group-id='groupId') - report-flag-modal div(v-for="(msg, index) in messages", v-if='chat && canViewFlag(msg)') // @TODO: is there a different way to do these conditionals? This creates an infinite loop //.hr(v-if='displayDivider(msg)') @@ -83,14 +82,12 @@ import findIndex from 'lodash/findIndex'; import Avatar from '../avatar'; import copyAsTodoModal from './copyAsTodoModal'; -import reportFlagModal from './reportFlagModal'; import chatCard from './chatCard'; export default { props: ['chat', 'groupId', 'groupName', 'inbox'], components: { copyAsTodoModal, - reportFlagModal, chatCard, Avatar, }, diff --git a/website/client/components/chat/reportFlagModal.vue b/website/client/components/chat/reportFlagModal.vue index 96f847eeee..4b3fbe6f44 100644 --- a/website/client/components/chat/reportFlagModal.vue +++ b/website/client/components/chat/reportFlagModal.vue @@ -1,5 +1,5 @@