feat(members): allow to fetch up to 60 members at all (#12400)

This commit is contained in:
Matteo Pagliazzi
2020-07-19 18:25:46 +02:00
committed by GitHub
parent 88059f568c
commit fd7c5b3847
4 changed files with 192 additions and 9 deletions

View File

@@ -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);

View File

@@ -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 });

View File

@@ -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() });

View File

@@ -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.