diff --git a/test/api/v3/integration/chat/POST-chat_seen.test.js b/test/api/v3/integration/chat/POST-chat_seen.test.js new file mode 100644 index 00000000000..9f90ca3296a --- /dev/null +++ b/test/api/v3/integration/chat/POST-chat_seen.test.js @@ -0,0 +1,67 @@ +import { + createAndPopulateGroup, +} from '../../../../helpers/api-v3-integration.helper'; + +describe('POST /groups/:id/chat/seen', () => { + context('Guild', () => { + let guild, guildLeader, guildMember, guildMessage; + + before(async () => { + let { group, groupLeader, members } = await createAndPopulateGroup({ + groupDetails: { + type: 'guild', + privacy: 'public', + }, + members: 1, + }); + + guild = group; + guildLeader = groupLeader; + guildMember = members[0]; + + guildMessage = await guildLeader.post(`/groups/${guild._id}/chat`, { message: 'Some guild message' }); + guildMessage = guildMessage.message; + }); + + it('clears new messages for a guild', async () => { + let user = await guildMember.get('/user'); + + await guildMember.post(`/groups/${guild._id}/chat/seen`); + + let guildThatHasSeenChat = await guildMember.get('/user'); + + expect(guildThatHasSeenChat.newMessages).to.be.empty; + }); + }); + + context('Party', () => { + let party, partyLeader, partyMember, partyMessage; + + before(async () => { + let { group, groupLeader, members } = await createAndPopulateGroup({ + groupDetails: { + type: 'party', + privacy: 'private', + }, + members: 1, + }); + + party = group; + partyLeader = groupLeader; + partyMember = members[0]; + + partyMessage = await partyLeader.post(`/groups/${party._id}/chat`, { message: 'Some party message' }); + partyMessage = partyMessage.message; + }); + + it('clears new messages for a party', async () => { + let user = await partyMember.get('/user'); + + await partyMember.post(`/groups/${party._id}/chat/seen`); + + let partyMemberThatHasSeenChat = await partyMember.get('/user'); + + expect(partyMemberThatHasSeenChat.newMessages).to.be.empty; + }); + }); +}); diff --git a/website/src/controllers/api-v3/chat.js b/website/src/controllers/api-v3/chat.js index 212e0644418..bfca7eb3b7f 100644 --- a/website/src/controllers/api-v3/chat.js +++ b/website/src/controllers/api-v3/chat.js @@ -105,7 +105,7 @@ api.postChat = { * @apiSuccess {Array} chat An array of chat messages */ api.likeChat = { - method: 'Post', + method: 'POST', url: '/groups/:groupId/chat/:chatId/like', middlewares: [authWithHeaders(), cron], async handler (req, res) { @@ -152,7 +152,7 @@ api.likeChat = { * @apiSuccess {Array} chat An array of chat messages */ api.flagChat = { - method: 'Post', + method: 'POST', url: '/groups/:groupId/chat/:chatId/flag', middlewares: [authWithHeaders(), cron], async handler (req, res) { @@ -256,4 +256,40 @@ api.flagChat = { }, }; +/** + * @api {post} /groups/:groupId/chat/:chatId/seen Seen a group chat message + * @apiVersion 3.0.0 + * @apiName SeenChat + * @apiGroup Chat + * + * @apiParam {groupId} groupId The group _id + * + * @apiSuccess {None} + */ +api.seenChat = { + method: 'POST', + url: '/groups/:groupId/chat/seen', + middlewares: [authWithHeaders(), cron], + async handler (req, res) { + let user = res.locals.user; + let groupId = req.params.groupId; + + req.checkParams('groupId', res.t('groupIdRequired')).notEmpty(); + + let validationErrors = req.validationErrors(); + if (validationErrors) throw validationErrors; + + let group = await Group.getGroup({user, groupId}); + if (!group) throw new NotFound(res.t('groupNotFound')); + + // Skip the auth step, we want this to be fast. If !found with uuid/token, then it just doesn't save + let update = { $unset: {} }; + + update.$unset[`newMessages.${groupId}`] = ''; + await User.update({_id: user._id}, update).exec(); + + res.respond(200); + }, +}; + export default api; diff --git a/website/src/models/group.js b/website/src/models/group.js index af592bb332f..246a2f06254 100644 --- a/website/src/models/group.js +++ b/website/src/models/group.js @@ -204,9 +204,17 @@ schema.methods.sendChat = function sendChat (message, user) { // var profileNames = [] // get usernames from regex of @xyz. how to handle space-delimited profile names? // User.update({'profile.name':{$in:profileNames}},lastSeenUpdate,{multi:true}).exec(); } else { - User.update({ - _id: {$in: this.members, $ne: user ? user._id : ''}, - }, lastSeenUpdate, {multi: true}).exec(); + let query = {}; + + if (this.type === 'party') { + query['party._id'] = this._id; + } else { + query.guilds = this._id; + } + + query._id = { $ne: user ? user._id : ''}; + + User.update(query, lastSeenUpdate, {multi: true}).exec(); } };