Skip to content

Commit 78eac96

Browse files
committed
On import fetch tickets page-by-page
1 parent 635cb8b commit 78eac96

File tree

3 files changed

+132
-13
lines changed

3 files changed

+132
-13
lines changed

index.js

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use strict';
22

33
module.exports.API_URL = 'https://api.assembla.com/v1';
4+
module.exports.TICKET_LIST_PAGE_SIZE = 100;
45

56
module.exports.getGoal = require('./lib/handlers/getGoal');
67
module.exports.createGoal = require('./lib/handlers/createGoal');

lib/makeApiRequest.js

+56-12
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
'use strict';
22

3-
var API_URL = require('..').API_URL;
3+
var async = require('async');
4+
var connector = require('..');
45
var makeRequest = require('./http').makeRequest;
56

67

78
module.exports = function(params) {
8-
var spaceUrl = API_URL + '/spaces/' + params.urlName;
9+
var spaceUrl = connector.API_URL + '/spaces/' + params.urlName;
910
var headers = {
1011
'Content-type': 'application/json',
1112
'Authorization': 'Bearer ' + params.accessToken
@@ -70,26 +71,69 @@ module.exports = function(params) {
7071

7172

7273
module.exports.getTickets = function(callback, results) {
73-
var url = spaceUrl + '/tickets';
74+
var url = getUrl(results);
75+
var pageNumber = 1;
76+
var tickets, fetchedTicketCount;
7477

75-
if (results.currentMilestone) {
76-
url += '/milestone/' + results.currentMilestone.id;
78+
async.doUntil(fetchAnotherPageOfTickets, isLastPage, function(err) {
79+
callback(err, tickets);
80+
});
81+
82+
return;
83+
84+
85+
function getUrl(results) {
86+
var url = spaceUrl + '/tickets';
87+
88+
if (results.currentMilestone) {
89+
url += '/milestone/' + results.currentMilestone.id;
90+
}
91+
92+
url += '.json';
93+
94+
return url;
7795
}
7896

79-
url += '.json';
97+
function fetchAnotherPageOfTickets(callback) {
98+
var requestInfo = getTicketListRequestInfo(url);
8099

81-
var requestInfo = getRequestInfo(url);
100+
makeRequest(requestInfo, function(err, jsend) {
101+
collectTickets(jsend);
102+
fetchedTicketCount = jsend.data.length;
103+
pageNumber += 1;
82104

83-
requestInfo.qs = {
84-
'per_page': 100
85-
};
105+
callback(jsend.status === 'success' ? null : new Error(jsend.message));
106+
});
107+
}
108+
109+
function getTicketListRequestInfo(url) {
110+
var requestInfo = getRequestInfo(url);
111+
112+
requestInfo.qs = {
113+
'page': pageNumber,
114+
'per_page': connector.TICKET_LIST_PAGE_SIZE
115+
};
116+
117+
return requestInfo;
118+
}
119+
120+
function collectTickets(jsend) {
121+
if (tickets) {
122+
tickets.data = tickets.data.concat(jsend.data);
123+
} else {
124+
tickets = jsend;
125+
}
126+
}
127+
128+
function isLastPage() {
129+
return fetchedTicketCount < connector.TICKET_LIST_PAGE_SIZE;
130+
}
86131

87-
makeRequest(requestInfo, callback);
88132
};
89133

90134

91135
module.exports.getSpaces = function(callback) {
92-
var requestInfo = getRequestInfo(API_URL + '/spaces.json');
136+
var requestInfo = getRequestInfo(connector.API_URL + '/spaces.json');
93137

94138
makeRequest(requestInfo, callback);
95139
};

spec/indexSpec.js

+75-1
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,10 @@ describe('AssemblaConnector', function() {
254254
status: 'Fixed'
255255
}];
256256

257-
paginationParams = {'per_page': 100};
257+
paginationParams = {
258+
'page': 1,
259+
'per_page': connector.TICKET_LIST_PAGE_SIZE
260+
};
258261

259262
stubHttpReponseFor('get', ticketsApiUrl + '/statuses.json').andRespondWith(200, apiData.ticketStatuses);
260263
});
@@ -307,6 +310,77 @@ describe('AssemblaConnector', function() {
307310
});
308311

309312

313+
describe('pagination', function() {
314+
var originalConnectorPageSize, page1, page2, page3;
315+
316+
beforeEach(function() {
317+
originalConnectorPageSize = connector.TICKET_LIST_PAGE_SIZE;
318+
});
319+
320+
afterEach(function() {
321+
connector.TICKET_LIST_PAGE_SIZE = originalConnectorPageSize;
322+
});
323+
324+
beforeEach(function() {
325+
stubHttpReponseFor('get', spaceApiUrl + '/milestones/all.json').andRespondWith(200, []);
326+
327+
paginationParams['per_page'] =
328+
connector.TICKET_LIST_PAGE_SIZE = 2;
329+
330+
page1 = [{
331+
number: 1,
332+
summary: 'Summary 1',
333+
description: 'Description 1',
334+
state: 1,
335+
status: 'In-Progress'
336+
}, {
337+
number: 2,
338+
summary: 'Summary 2',
339+
description: 'Description 2',
340+
state: 1,
341+
status: 'Fixed'
342+
}];
343+
paginationParams.page = 1;
344+
stubHttpReponseFor('get', ticketsApiUrl + '.json', paginationParams).andRespondWith(200, page1);
345+
346+
page2 = [{
347+
number: 3,
348+
summary: 'Summary 3',
349+
description: 'Description 3',
350+
state: 1,
351+
status: 'In-Progress'
352+
}, {
353+
number: 4,
354+
summary: 'Summary 4',
355+
description: 'Description 4',
356+
state: 1,
357+
status: 'Fixed'
358+
}];
359+
paginationParams.page = 2;
360+
stubHttpReponseFor('get', ticketsApiUrl + '.json', paginationParams).andRespondWith(200, page2);
361+
362+
page3 = [{
363+
number: 5,
364+
summary: 'Summary 5',
365+
description: 'Description 5',
366+
state: 1,
367+
status: 'Fixed'
368+
}];
369+
paginationParams.page = 3;
370+
stubHttpReponseFor('get', ticketsApiUrl + '.json', paginationParams).andRespondWith(200, page3);
371+
});
372+
373+
it('fetches all the tickets page-by-page', function(done) {
374+
connector.getGoals(params, function(jsendResponse) {
375+
expect(jsendResponse.data.goals.length).toBe(page1.length + page2.length + page3.length);
376+
expect(request.get.callCount).toBe(5); // 1 statuses + 1 milestones + 3 pages of tickets
377+
378+
done();
379+
});
380+
});
381+
});
382+
383+
310384
it('transforms and packs the received tickets into a success JSend response and passes it to the callback', function(done) {
311385
stubHttpReponseFor('get', spaceApiUrl + '/milestones/all.json').andRespondWith(200, []);
312386
stubHttpReponseFor('get', ticketsApiUrl + '.json', paginationParams).andRespondWith(200, apiData.tickets);

0 commit comments

Comments
 (0)