Cleaned old members stats endpoint (#12821)

no refs

- Removes old `/members/stats` endpoint in favor of new `/members/stats/count` in canary/v4 which captures members counts using new events table
- Removes tests for old `/members/stats` endpoint
- Added test for new `/members/stats/count` endpoint
This commit is contained in:
Rishabh Garg 2021-03-29 13:07:01 +05:30 committed by GitHub
parent 7e51b90792
commit 72e8894eac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 9 additions and 174 deletions

View File

@ -365,27 +365,6 @@ module.exports = {
}
},
stats: {
options: [
'days'
],
permissions: {
method: 'browse'
},
validation: {
options: {
days: {
values: ['30', '90', '365', 'all-time']
}
}
},
async query(frame) {
const days = frame.options.days === 'all-time' ? 'all-time' : Number(frame.options.days || 30);
return await membersService.stats.fetch(days);
}
},
memberStats: {
permissions: {
method: 'browse'

View File

@ -95,7 +95,6 @@ module.exports = function apiRoutes() {
router.get('/members/stats/mrr', mw.authAdminApi, http(apiCanary.members.mrrStats));
router.get('/members/stats/subscribers', mw.authAdminApi, http(apiCanary.members.subscriberStats));
router.get('/members/stats/gross_volume', mw.authAdminApi, http(apiCanary.members.grossVolumeStats));
router.get('/members/stats', mw.authAdminApi, http(apiCanary.members.stats));
router.get('/members/events', mw.authAdminApi, http(apiCanary.members.activityFeed));

View File

@ -376,9 +376,9 @@ describe('Members API', function () {
importedMember2.subscriptions.length.should.equal(0);
});
async function fetchStats() {
it('Can fetch member counts stats', async function () {
const res = await request
.get(localUtils.API.getApiQuery('members/stats/'))
.get(localUtils.API.getApiQuery('members/stats/count/'))
.set('Origin', config.get('url'))
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
@ -386,85 +386,14 @@ describe('Members API', function () {
should.not.exist(res.headers['x-cache-invalidate']);
const jsonResponse = res.body;
should.exist(jsonResponse);
should.exist(jsonResponse.total);
should.exist(jsonResponse.total_in_range);
should.exist(jsonResponse.total_on_date);
should.exist(jsonResponse.new_today);
// 5 from fixtures, 2 from above posts, 2 from above import
jsonResponse.total.should.equal(9);
return jsonResponse;
}
function parseTotalOnDate(jsonResponse) {
// replicate default look back date of 30 days
const days = 30;
// grab the timezone as mocked above
const siteTimezone = settingsCache.get('timezone');
// rebuild a valid response object such that works on any date-time...
// get the start date
let currentRangeDate = moment.tz(siteTimezone).subtract(days - 1, 'days');
// get the end date but ignore today because we want to set that value ourselves
let endDate = moment.tz(siteTimezone).subtract(1, 'hour');
const output = {};
let dateStr;
// set user count to be 1 for all dates before today to match date as outlined
// for the user in valid-members-import.csv who was imported with a start date of '91
while (currentRangeDate.isBefore(endDate)) {
dateStr = currentRangeDate.format('YYYY-MM-DD');
output[dateStr] = 1;
currentRangeDate = currentRangeDate.add(1, 'day');
}
// format the date for the end date (right now)
dateStr = currentRangeDate.format('YYYY-MM-DD');
// set the end date to match the number of members added from fixtures posts and imports
// 5 from fixtures, 2 from above posts, 2 from above import
output[dateStr] = 9;
// deep equality check that the objects match...
jsonResponse.total_on_date.should.eql(output);
}
it('Can fetch stats', function () {
return fetchStats();
});
it('Can render stats in GMT -X timezones', async function () {
// stub the method
const stub = sinon.stub(settingsCache, 'get');
// this was just a GMT -X Timezone picked at random for the test below...
stub
.withArgs('timezone')
.returns('America/Caracas');
const jsonResponse = await fetchStats();
parseTotalOnDate(jsonResponse);
// restore the stub so we can use it in other tests
stub.restore();
});
it('Can render stats in GMT +X timezones', async function () {
// stub the method
const stub = sinon.stub(settingsCache, 'get');
// the tester that wrote this lives in Adelaide so shoutout to this (random) timezone!
stub
.withArgs('timezone')
.returns('Australia/Adelaide');
const jsonResponse = await fetchStats();
parseTotalOnDate(jsonResponse);
// restore the stub so we can use it in other tests
stub.restore();
should.exist(jsonResponse.resource);
should.exist(jsonResponse.data);
const data = jsonResponse.data;
// 2 from above posts, 2 from above import
data[0].free.should.equal(4);
data[0].paid.should.equal(0);
data[0].comped.should.equal(0);
});
});

View File

@ -562,78 +562,6 @@ describe('Members API', function () {
});
});
it('Can fetch stats with no ?days param', function () {
return request
.get(localUtils.API.getApiQuery('members/stats/'))
.set('Origin', config.get('url'))
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
// .expect(200) - doesn't surface underlying errors in tests
.then((res) => {
res.status.should.equal(200, JSON.stringify(res.body));
should.not.exist(res.headers['x-cache-invalidate']);
const jsonResponse = res.body;
should.exist(jsonResponse);
should.exist(jsonResponse.total);
should.exist(jsonResponse.total_in_range);
should.exist(jsonResponse.total_on_date);
should.exist(jsonResponse.new_today);
// 5 from fixtures and 6 imported in previous tests
jsonResponse.total.should.equal(11);
});
});
it('Can fetch stats with ?days=90', function () {
return request
.get(localUtils.API.getApiQuery('members/stats/?days=90'))
.set('Origin', config.get('url'))
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
// .expect(200) - doesn't surface underlying errors in tests
.then((res) => {
res.status.should.equal(200, JSON.stringify(res.body));
should.not.exist(res.headers['x-cache-invalidate']);
const jsonResponse = res.body;
should.exist(jsonResponse);
should.exist(jsonResponse.total);
should.exist(jsonResponse.total_in_range);
should.exist(jsonResponse.total_on_date);
should.exist(jsonResponse.new_today);
// 5 from fixtures and 6 imported in previous tests
jsonResponse.total.should.equal(11);
});
});
it('Can fetch stats with ?days=all-time', function () {
return request
.get(localUtils.API.getApiQuery('members/stats/?days=all-time'))
.set('Origin', config.get('url'))
.expect('Content-Type', /json/)
.expect('Cache-Control', testUtils.cacheRules.private)
// .expect(200) - doesn't surface underlying errors in tests
.then((res) => {
res.status.should.equal(200, JSON.stringify(res.body));
should.not.exist(res.headers['x-cache-invalidate']);
const jsonResponse = res.body;
should.exist(jsonResponse);
should.exist(jsonResponse.total);
should.exist(jsonResponse.total_in_range);
should.exist(jsonResponse.total_on_date);
should.exist(jsonResponse.new_today);
// 5 from fixtures and 6 imported in previous tests
jsonResponse.total.should.equal(11);
});
});
it('Errors when fetching stats with unknown days param value', function () {
return request
.get(localUtils.API.getApiQuery('members/stats/?days=nope'))