mirror of
https://github.com/HabitRPG/habitica.git
synced 2025-12-16 22:27:26 +01:00
feat(members): allow to fetch up to 60 members at all (#12400)
This commit is contained in:
@@ -117,7 +117,7 @@ describe('GET /challenges/:challengeId/members', () => {
|
||||
expect(res[0].profile).to.have.all.keys(['name']);
|
||||
});
|
||||
|
||||
it('returns only first 30 members if req.query.includeAllMembers is not true', async () => {
|
||||
it('returns only first 30 members if req.query.includeAllMembers is not true and req.query.limit is undefined', async () => {
|
||||
const group = await generateGroup(user, { type: 'party', name: generateUUID() });
|
||||
const challenge = await generateChallenge(user, group);
|
||||
await user.post(`/challenges/${challenge._id}/join`);
|
||||
@@ -136,7 +136,7 @@ describe('GET /challenges/:challengeId/members', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('returns only first 30 members if req.query.includeAllMembers is not defined', async () => {
|
||||
it('returns only first 30 members if req.query.includeAllMembers is not defined and req.query.limit is undefined', async () => {
|
||||
const group = await generateGroup(user, { type: 'party', name: generateUUID() });
|
||||
const challenge = await generateChallenge(user, group);
|
||||
await user.post(`/challenges/${challenge._id}/join`);
|
||||
@@ -155,6 +155,68 @@ describe('GET /challenges/:challengeId/members', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('returns an error if req.query.limit is over 60', async () => {
|
||||
const group = await generateGroup(user, { type: 'party', privacy: 'private' });
|
||||
const challenge = await generateChallenge(user, group);
|
||||
const anotherUser = await generateUser();
|
||||
|
||||
await expect(anotherUser.get(`/challenges/${challenge._id}/members?limit=61`)).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('invalidReqParams'),
|
||||
});
|
||||
});
|
||||
|
||||
it('returns an error if req.query.limit is under 1', async () => {
|
||||
const group = await generateGroup(user, { type: 'party', privacy: 'private' });
|
||||
const challenge = await generateChallenge(user, group);
|
||||
const anotherUser = await generateUser();
|
||||
|
||||
await expect(anotherUser.get(`/challenges/${challenge._id}/members?limit=-13`)).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('invalidReqParams'),
|
||||
});
|
||||
});
|
||||
|
||||
it('returns an error if req.query.limit is not an integer', async () => {
|
||||
const group = await generateGroup(user, { type: 'party', privacy: 'private' });
|
||||
const challenge = await generateChallenge(user, group);
|
||||
const anotherUser = await generateUser();
|
||||
|
||||
await expect(anotherUser.get(`/challenges/${challenge._id}/members?limit=true`)).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('invalidReqParams'),
|
||||
});
|
||||
});
|
||||
|
||||
it('returns up to 60 members when req.query.limit is specified', async () => {
|
||||
const group = await generateGroup(user, { type: 'party', name: generateUUID() });
|
||||
const challenge = await generateChallenge(user, group);
|
||||
await user.post(`/challenges/${challenge._id}/join`);
|
||||
|
||||
const usersToGenerate = [];
|
||||
for (let i = 0; i < 62; i += 1) {
|
||||
usersToGenerate.push(generateUser({ challenges: [challenge._id] }));
|
||||
}
|
||||
await Promise.all(usersToGenerate);
|
||||
|
||||
let res = await user.get(`/challenges/${challenge._id}/members?limit=57`);
|
||||
expect(res.length).to.equal(57);
|
||||
res.forEach(member => {
|
||||
expect(member).to.have.all.keys(['_id', 'auth', 'flags', 'id', 'profile']);
|
||||
expect(member.profile).to.have.all.keys(['name']);
|
||||
});
|
||||
|
||||
res = await user.get(`/challenges/${challenge._id}/members?limit=60&lastId=${res[res.length - 1]._id}`);
|
||||
expect(res.length).to.equal(6);
|
||||
res.forEach(member => {
|
||||
expect(member).to.have.all.keys(['_id', 'auth', 'flags', 'id', 'profile']);
|
||||
expect(member.profile).to.have.all.keys(['name']);
|
||||
});
|
||||
}).timeout(30000);
|
||||
|
||||
it('returns all members if req.query.includeAllMembers is true', async () => {
|
||||
const group = await generateGroup(user, { type: 'party', name: generateUUID() });
|
||||
const challenge = await generateChallenge(user, group);
|
||||
|
||||
@@ -70,7 +70,7 @@ describe('GET /groups/:groupId/invites', () => {
|
||||
expect(res[0].profile).to.have.all.keys(['name']);
|
||||
});
|
||||
|
||||
it('returns only first 30 invites', async () => {
|
||||
it('returns only first 30 invites by default (req.query.limit not specified)', async () => {
|
||||
const leader = await generateUser({ balance: 4 });
|
||||
const group = await generateGroup(leader, { type: 'guild', privacy: 'public', name: generateUUID() });
|
||||
|
||||
@@ -89,6 +89,65 @@ describe('GET /groups/:groupId/invites', () => {
|
||||
});
|
||||
}).timeout(10000);
|
||||
|
||||
it('returns an error if req.query.limit is over 60', async () => {
|
||||
const leader = await generateUser({ balance: 4 });
|
||||
const group = await generateGroup(leader, { type: 'guild', privacy: 'public', name: generateUUID() });
|
||||
|
||||
await expect(leader.get(`/groups/${group._id}/invites?limit=61`)).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('invalidReqParams'),
|
||||
});
|
||||
});
|
||||
|
||||
it('returns an error if req.query.limit is under 1', async () => {
|
||||
const leader = await generateUser({ balance: 4 });
|
||||
const group = await generateGroup(leader, { type: 'guild', privacy: 'public', name: generateUUID() });
|
||||
|
||||
await expect(leader.get(`/groups/${group._id}/invites?limit=-1`)).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('invalidReqParams'),
|
||||
});
|
||||
});
|
||||
|
||||
it('returns an error if req.query.limit is not an integer', async () => {
|
||||
const leader = await generateUser({ balance: 4 });
|
||||
const group = await generateGroup(leader, { type: 'guild', privacy: 'public', name: generateUUID() });
|
||||
|
||||
await expect(leader.get(`/groups/${group._id}/invites?limit=1.3`)).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('invalidReqParams'),
|
||||
});
|
||||
});
|
||||
|
||||
it('returns up to 60 invites when req.query.limit is specified', async () => {
|
||||
const leader = await generateUser({ balance: 4 });
|
||||
const group = await generateGroup(leader, { type: 'guild', privacy: 'public', name: generateUUID() });
|
||||
|
||||
const invitesToGenerate = [];
|
||||
for (let i = 0; i < 31; i += 1) {
|
||||
invitesToGenerate.push(generateUser());
|
||||
}
|
||||
const generatedInvites = await Promise.all(invitesToGenerate);
|
||||
await leader.post(`/groups/${group._id}/invite`, { uuids: generatedInvites.map(invite => invite._id) });
|
||||
|
||||
let res = await leader.get(`/groups/${group._id}/invites?limit=14`);
|
||||
expect(res.length).to.equal(14);
|
||||
res.forEach(member => {
|
||||
expect(member).to.have.all.keys(['_id', 'auth', 'flags', 'id', 'profile']);
|
||||
expect(member.profile).to.have.all.keys(['name']);
|
||||
});
|
||||
|
||||
res = await leader.get(`/groups/${group._id}/invites?limit=31`);
|
||||
expect(res.length).to.equal(31);
|
||||
res.forEach(member => {
|
||||
expect(member).to.have.all.keys(['_id', 'auth', 'flags', 'id', 'profile']);
|
||||
expect(member.profile).to.have.all.keys(['name']);
|
||||
});
|
||||
}).timeout(30000);
|
||||
|
||||
it('supports using req.query.lastId to get more invites', async function test () {
|
||||
this.timeout(30000); // @TODO: times out after 8 seconds
|
||||
const leader = await generateUser({ balance: 4 });
|
||||
|
||||
@@ -116,7 +116,7 @@ describe('GET /groups/:groupId/members', () => {
|
||||
expect(memberRes.inbox.messages).to.not.exist;
|
||||
});
|
||||
|
||||
it('returns only first 30 members', async () => {
|
||||
it('returns only first 30 members by default (req.query.limit not specified)', async () => {
|
||||
const group = await generateGroup(user, { type: 'party', name: generateUUID() });
|
||||
|
||||
const usersToGenerate = [];
|
||||
@@ -133,6 +133,60 @@ describe('GET /groups/:groupId/members', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('returns an error if req.query.limit is over 60', async () => {
|
||||
await generateGroup(user, { type: 'party', name: generateUUID() });
|
||||
|
||||
await expect(user.get('/groups/party/members?limit=61')).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('invalidReqParams'),
|
||||
});
|
||||
});
|
||||
|
||||
it('returns an error if req.query.limit is under 1', async () => {
|
||||
await generateGroup(user, { type: 'party', name: generateUUID() });
|
||||
|
||||
await expect(user.get('/groups/party/members?limit=0')).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('invalidReqParams'),
|
||||
});
|
||||
});
|
||||
|
||||
it('returns an error if req.query.limit is not an integer', async () => {
|
||||
await generateGroup(user, { type: 'party', name: generateUUID() });
|
||||
|
||||
await expect(user.get('/groups/party/members?limit=1.1')).to.eventually.be.rejected.and.eql({
|
||||
code: 400,
|
||||
error: 'BadRequest',
|
||||
message: t('invalidReqParams'),
|
||||
});
|
||||
});
|
||||
|
||||
it('returns up to 60 members when req.query.limit is specified', async () => {
|
||||
const group = await generateGroup(user, { type: 'party', name: generateUUID() });
|
||||
|
||||
const usersToGenerate = [];
|
||||
for (let i = 0; i < 62; i += 1) {
|
||||
usersToGenerate.push(generateUser({ party: { _id: group._id } }));
|
||||
}
|
||||
await Promise.all(usersToGenerate);
|
||||
|
||||
let res = await user.get('/groups/party/members?limit=60');
|
||||
expect(res.length).to.equal(60);
|
||||
res.forEach(member => {
|
||||
expect(member).to.have.all.keys(['_id', 'auth', 'flags', 'id', 'profile']);
|
||||
expect(member.profile).to.have.all.keys(['name']);
|
||||
});
|
||||
|
||||
res = await user.get(`/groups/party/members?limit=60&lastId=${res[res.length - 1]._id}`);
|
||||
expect(res.length).to.equal(3);
|
||||
res.forEach(member => {
|
||||
expect(member).to.have.all.keys(['_id', 'auth', 'flags', 'id', 'profile']);
|
||||
expect(member.profile).to.have.all.keys(['name']);
|
||||
});
|
||||
}).timeout(30000);
|
||||
|
||||
it('returns only first 30 members even when ?includeAllMembers=true', async () => {
|
||||
const group = await generateGroup(user, { type: 'party', name: generateUUID() });
|
||||
|
||||
|
||||
@@ -289,6 +289,8 @@ function _getMembersForItem (type) {
|
||||
req.checkParams('groupId', res.t('groupIdRequired')).notEmpty();
|
||||
}
|
||||
req.checkQuery('lastId').optional().notEmpty().isUUID();
|
||||
// Allow an arbitrary number of results (up to 60)
|
||||
req.checkQuery('limit', res.t('groupIdRequired')).optional().notEmpty().isInt({ min: 1, max: 60 });
|
||||
|
||||
const validationErrors = req.validationErrors();
|
||||
if (validationErrors) throw validationErrors;
|
||||
@@ -379,7 +381,7 @@ function _getMembersForItem (type) {
|
||||
|
||||
if (lastId) query._id = { $gt: lastId };
|
||||
|
||||
let limit = 30;
|
||||
let limit = req.query.limit ? Number(req.query.limit) : 30;
|
||||
|
||||
// Allow for all challenges members to be returned
|
||||
if (type === 'challenge-members' && req.query.includeAllMembers === 'true') {
|
||||
@@ -402,9 +404,9 @@ function _getMembersForItem (type) {
|
||||
|
||||
/**
|
||||
* @api {get} /api/v3/groups/:groupId/members Get members for a group
|
||||
* @apiDescription With a limit of 30 member per request.
|
||||
* @apiDescription With a limit of 30 member per request (by default).
|
||||
* To get all members run requests against this routes (updating the lastId query parameter)
|
||||
* until you get less than 30 results.
|
||||
* until you get less than 30 results (or the specified limit).
|
||||
* @apiName GetMembersForGroup
|
||||
* @apiGroup Member
|
||||
*
|
||||
@@ -412,6 +414,8 @@ function _getMembersForItem (type) {
|
||||
* @apiParam (Query) {UUID} lastId Query parameter to specify the last member
|
||||
* returned in a previous request to this route and
|
||||
* get the next batch of results.
|
||||
* @apiParam (Query) {Number} limit=30 BETA Query parameter
|
||||
* to specify the number of results to return. Max is 60.
|
||||
* @apiParam (Query) {Boolean} includeAllPublicFields Query parameter available
|
||||
* only when fetching a party. If === `true`
|
||||
* then all public fields for members
|
||||
@@ -446,7 +450,7 @@ api.getMembersForGroup = {
|
||||
|
||||
/**
|
||||
* @api {get} /api/v3/groups/:groupId/invites Get invites for a group
|
||||
* @apiDescription With a limit of 30 member per request. To get all invites run
|
||||
* @apiDescription With a limit of 30 member per request (by default). To get all invites run
|
||||
* requests against this routes (updating the lastId query parameter)
|
||||
* until you get less than 30 results.
|
||||
* @apiName GetInvitesForGroup
|
||||
@@ -456,6 +460,8 @@ api.getMembersForGroup = {
|
||||
* @apiParam (Query) {UUID} lastId Query parameter to specify the last invite
|
||||
* returned in a previous request to this route and
|
||||
* get the next batch of results.
|
||||
* @apiParam (Query) {Number} limit=30 BETA Query parameter
|
||||
* to specify the number of results to return. Max is 60.
|
||||
*
|
||||
* @apiSuccess {array} data An array of invites, sorted by _id
|
||||
*
|
||||
@@ -486,7 +492,7 @@ api.getInvitesForGroup = {
|
||||
|
||||
/**
|
||||
* @api {get} /api/v3/challenges/:challengeId/members Get members for a challenge
|
||||
* @apiDescription With a limit of 30 member per request.
|
||||
* @apiDescription With a limit of 30 member per request (by default).
|
||||
* To get all members run requests against this routes (updating the lastId query parameter)
|
||||
* until you get less than 30 results.
|
||||
* BETA You can also use ?includeAllMembers=true. This option is currently in BETA
|
||||
@@ -500,6 +506,8 @@ api.getInvitesForGroup = {
|
||||
* @apiParam (Query) {UUID} lastId Query parameter to specify the last member returned
|
||||
* in a previous request to this route and
|
||||
* get the next batch of results.
|
||||
* @apiParam (Query) {Number} limit=30 BETA Query parameter to
|
||||
* specify the number of results to return. Max is 60.
|
||||
* @apiParam (Query) {String} includeAllMembers BETA Query parameter - If 'true' all
|
||||
* challenge members are returned.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user