mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-17 14:47:53 +01:00
Inbox: Add API to list conversations (#11110)
* Add API to list inbox conversations * fix test + add api doc * use `.lean()` * orderBy after the the grouped conversations are loaded * fix ordering
This commit is contained in:
@@ -60,4 +60,10 @@ describe('GET /inbox/messages', () => {
|
|||||||
|
|
||||||
expect(messages.length).to.equal(4);
|
expect(messages.length).to.equal(4);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('returns only the messages of one conversation', async () => {
|
||||||
|
const messages = await user.get(`/inbox/messages?conversation=${otherUser.id}`);
|
||||||
|
|
||||||
|
expect(messages.length).to.equal(3);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
44
test/api/v4/inbox/GET-inbox-conversations.test.js
Normal file
44
test/api/v4/inbox/GET-inbox-conversations.test.js
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import {
|
||||||
|
generateUser,
|
||||||
|
} from '../../../helpers/api-integration/v4';
|
||||||
|
|
||||||
|
describe('GET /inbox/conversations', () => {
|
||||||
|
let user;
|
||||||
|
let otherUser;
|
||||||
|
let thirdUser;
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
[user, otherUser, thirdUser] = await Promise.all([generateUser(), generateUser(), generateUser()]);
|
||||||
|
|
||||||
|
await otherUser.post('/members/send-private-message', {
|
||||||
|
toUserId: user.id,
|
||||||
|
message: 'first',
|
||||||
|
});
|
||||||
|
await user.post('/members/send-private-message', {
|
||||||
|
toUserId: otherUser.id,
|
||||||
|
message: 'second',
|
||||||
|
});
|
||||||
|
await user.post('/members/send-private-message', {
|
||||||
|
toUserId: thirdUser.id,
|
||||||
|
message: 'third',
|
||||||
|
});
|
||||||
|
await otherUser.post('/members/send-private-message', {
|
||||||
|
toUserId: user.id,
|
||||||
|
message: 'fourth',
|
||||||
|
});
|
||||||
|
|
||||||
|
// message to yourself
|
||||||
|
await user.post('/members/send-private-message', {
|
||||||
|
toUserId: user.id,
|
||||||
|
message: 'fifth',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns the conversations', async () => {
|
||||||
|
const result = await user.get('/inbox/conversations');
|
||||||
|
|
||||||
|
expect(result.length).to.be.equal(3);
|
||||||
|
expect(result[0].user).to.be.equal(user.profile.name);
|
||||||
|
expect(result[0].username).to.be.equal(user.auth.local.username);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -12,6 +12,7 @@ let api = {};
|
|||||||
* @apiDescription Get inbox messages for a user
|
* @apiDescription Get inbox messages for a user
|
||||||
*
|
*
|
||||||
* @apiParam (Query) {Number} page Load the messages of the selected Page - 10 Messages per Page
|
* @apiParam (Query) {Number} page Load the messages of the selected Page - 10 Messages per Page
|
||||||
|
* @apiParam (Query) {GUID} conversation Loads only the messages of a conversation
|
||||||
*
|
*
|
||||||
* @apiSuccess {Array} data An array of inbox messages
|
* @apiSuccess {Array} data An array of inbox messages
|
||||||
*/
|
*/
|
||||||
@@ -22,9 +23,10 @@ api.getInboxMessages = {
|
|||||||
async handler (req, res) {
|
async handler (req, res) {
|
||||||
const user = res.locals.user;
|
const user = res.locals.user;
|
||||||
const page = req.query.page;
|
const page = req.query.page;
|
||||||
|
const conversation = req.query.conversation;
|
||||||
|
|
||||||
const userInbox = await inboxLib.getUserInbox(user, {
|
const userInbox = await inboxLib.getUserInbox(user, {
|
||||||
page,
|
page, conversation,
|
||||||
});
|
});
|
||||||
|
|
||||||
res.respond(200, userInbox);
|
res.respond(200, userInbox);
|
||||||
|
|||||||
@@ -72,4 +72,25 @@ api.clearMessages = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @api {get} /inbox/conversations Get the conversations for a user
|
||||||
|
* @apiName conversations
|
||||||
|
* @apiGroup Inbox
|
||||||
|
* @apiDescription Get the conversations for a user
|
||||||
|
*
|
||||||
|
* @apiSuccess {Array} data An array of inbox conversations
|
||||||
|
*/
|
||||||
|
api.conversations = {
|
||||||
|
method: 'GET',
|
||||||
|
middlewares: [authWithHeaders()],
|
||||||
|
url: '/inbox/conversations',
|
||||||
|
async handler (req, res) {
|
||||||
|
const user = res.locals.user;
|
||||||
|
|
||||||
|
const result = await inboxLib.listConversations(user);
|
||||||
|
|
||||||
|
res.respond(200, result);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
module.exports = api;
|
module.exports = api;
|
||||||
|
|||||||
@@ -1,14 +1,25 @@
|
|||||||
import { inboxModel as Inbox } from '../../models/message';
|
import {inboxModel as Inbox} from '../../models/message';
|
||||||
|
import {
|
||||||
|
model as User,
|
||||||
|
} from '../../models/user';
|
||||||
|
import orderBy from 'lodash/orderBy';
|
||||||
|
import keyBy from 'lodash/keyBy';
|
||||||
|
|
||||||
const PM_PER_PAGE = 10;
|
const PM_PER_PAGE = 10;
|
||||||
|
|
||||||
export async function getUserInbox (user, options = {asArray: true, page: 0}) {
|
export async function getUserInbox (user, options = {asArray: true, page: 0, conversation: null}) {
|
||||||
if (typeof options.asArray === 'undefined') {
|
if (typeof options.asArray === 'undefined') {
|
||||||
options.asArray = true;
|
options.asArray = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const findObj = {ownerId: user._id};
|
||||||
|
|
||||||
|
if (options.conversation) {
|
||||||
|
findObj.uuid = options.conversation;
|
||||||
|
}
|
||||||
|
|
||||||
let query = Inbox
|
let query = Inbox
|
||||||
.find({ownerId: user._id})
|
.find(findObj)
|
||||||
.sort({timestamp: -1});
|
.sort({timestamp: -1});
|
||||||
|
|
||||||
if (typeof options.page !== 'undefined') {
|
if (typeof options.page !== 'undefined') {
|
||||||
@@ -29,12 +40,45 @@ export async function getUserInbox (user, options = {asArray: true, page: 0}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function listConversations (user) {
|
||||||
|
let query = Inbox
|
||||||
|
.aggregate([
|
||||||
|
{
|
||||||
|
$match: {
|
||||||
|
ownerId: user._id,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
$group: {
|
||||||
|
_id: '$uuid',
|
||||||
|
timestamp: {$max: '$timestamp'}, // sort before group doesn't work - use the max value to sort it again after
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
|
const conversationsList = orderBy(await query.exec(), ['timestamp'], ['desc']).map(c => c._id);
|
||||||
|
|
||||||
|
const users = await User.find({_id: {$in: conversationsList}})
|
||||||
|
.select('_id profile.name auth.local.username')
|
||||||
|
.lean()
|
||||||
|
.exec();
|
||||||
|
|
||||||
|
const usersMap = keyBy(users, '_id');
|
||||||
|
const conversations = conversationsList.map(userId => ({
|
||||||
|
uuid: usersMap[userId]._id,
|
||||||
|
user: usersMap[userId].profile.name,
|
||||||
|
username: usersMap[userId].auth.local.username,
|
||||||
|
}));
|
||||||
|
|
||||||
|
return conversations;
|
||||||
|
}
|
||||||
|
|
||||||
export async function getUserInboxMessage (user, messageId) {
|
export async function getUserInboxMessage (user, messageId) {
|
||||||
return Inbox.findOne({ownerId: user._id, _id: messageId}).exec();
|
return Inbox.findOne({ownerId: user._id, _id: messageId}).exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function deleteMessage (user, messageId) {
|
export async function deleteMessage (user, messageId) {
|
||||||
const message = await Inbox.findOne({_id: messageId, ownerId: user._id }).exec();
|
const message = await Inbox.findOne({_id: messageId, ownerId: user._id}).exec();
|
||||||
if (!message) return false;
|
if (!message) return false;
|
||||||
await Inbox.remove({_id: message._id, ownerId: user._id}).exec();
|
await Inbox.remove({_id: message._id, ownerId: user._id}).exec();
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user