Skip to content

Commit 99e3a73

Browse files
committed
Adds getGroupTreeIds(..) method to the Groups service + fixes
1 parent 17e070e commit 99e3a73

File tree

3 files changed

+66
-6
lines changed

3 files changed

+66
-6
lines changed

CHANGELOG.md

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
# Topcoder React Lib
22

3-
### v0.7.3
3+
### v0.7.4
44
- Added `getTcM2mToken()` function to API service, to facilitate handling of
55
TC M2M token;
6-
- Added `reduceGroupIds(..)` function to Groups service, to easily extract all
7-
IDs from a group tree.
6+
- Added `getGroupTreeIds(..)`, `getTokenV3()`, and `reduceGroupIds(..)`
7+
functions to the Groups service, to facilitate deduction of all IDs in a group
8+
(sub-)tree, rooted at a specified group.
89

910
### v0.6.0
1011
A few changes related to fetch of projests visitble to users, and creation of

src/services/api.js

+5-3
Original file line numberDiff line numberDiff line change
@@ -302,15 +302,17 @@ export async function getTcM2mToken() {
302302
const { cached } = getTcM2mToken;
303303
const { TC_M2M } = config.SECRET;
304304
if (!cached || cached.expires < now + getTcM2mToken.MIN_LIFETIME) {
305-
const res = await fetch(`https://${config.AUTH0.DOMAIN}/oauth/token`, {
306-
body: {
305+
let res = await fetch(`https://${config.AUTH0.DOMAIN}/oauth/token`, {
306+
headers: { 'Content-Type': 'application/json' },
307+
body: JSON.stringify({
307308
client_id: TC_M2M.CLIENT_ID,
308309
client_secret: TC_M2M.CLIENT_SECRET,
309310
audience: TC_M2M.AUDIENCE,
310311
grant_type: TC_M2M.GRANT_TYPE,
311-
},
312+
}),
312313
method: 'POST',
313314
});
315+
res = await res.json();
314316
getTcM2mToken.cached = {
315317
expires: now + 1000 * res.expires_in, // [ms]
316318
token: res.access_token,

src/services/groups.js

+57
Original file line numberDiff line numberDiff line change
@@ -191,8 +191,15 @@ class GroupService {
191191
* @param {String} tokenV3 Optional. Auth token for Topcoder API v3.
192192
*/
193193
constructor(tokenV3) {
194+
const now = Date.now();
194195
this.private = {
195196
api: getApiV3(tokenV3),
197+
cache: {
198+
groupTreeIds: {
199+
lastCleanUp: now,
200+
data: {},
201+
},
202+
},
196203
tokenV3,
197204
};
198205
}
@@ -269,6 +276,48 @@ class GroupService {
269276
return Promise.all(promises).then(() => res);
270277
}
271278

279+
/**
280+
* Given a root group ID, returns an ID array that contains the root group ID,
281+
* and IDs of all descendant groups in the group (sub-)tree rooted at the
282+
* specified group.
283+
*
284+
* Results are cached inside the class instance to minimize the load on TC
285+
* Group API. To take advantage of that, be sure to keep and reuse the same
286+
* class instance.
287+
*
288+
* The reason to have such strange method and pay an extra attention to its
289+
* optimization for smaller API load is that it is essential for authorization
290+
* checks.
291+
*
292+
* @param {String} rootGroupId
293+
* @param {Number} maxage Optional. Max age [ms] of records served from the
294+
* cache. Defaults to 5 minutes.
295+
* @return {Promise} Resolves to ID array.
296+
*/
297+
async getGroupTreeIds(rootGroupId, maxage = 5 * 60 * 1000) {
298+
const now = Date.now();
299+
const cache = this.private.cache.groupTreeIds;
300+
301+
/* Clean-up: removes stale records from the cache. */
302+
const CLEAN_UP_INTERVAL = 24 * 60 * 60 * 1000; // 1 day in ms.
303+
if (now - cache.lastCleanUp > CLEAN_UP_INTERVAL) {
304+
_.forOwn(cache, ({ timestamp }, key) => {
305+
if (now - timestamp > CLEAN_UP_INTERVAL) delete cache[key];
306+
});
307+
cache.lastCleanUp = now;
308+
}
309+
310+
/* If result is found in cache, and is fresh enough, return it. */
311+
const cached = cache[rootGroupId];
312+
if (cached && now - cached.timestamp < maxage) return _.clone(cached.data);
313+
314+
/* Otherwise, fetch result from the API, write it to the cache, and
315+
* finally return that. */
316+
const res = reduceGroupIds(await this.getGroup(rootGroupId));
317+
cache[rootGroupId] = { data: res, timestamp: now };
318+
return _.clone(res);
319+
}
320+
272321
/**
273322
* Gets group members.
274323
* @param {String} groupId
@@ -296,6 +345,14 @@ class GroupService {
296345
if (!res.success) throw new Error(res.content);
297346
return Number(res.content);
298347
}
348+
349+
/**
350+
* Returns TC Auth Token V3 used by the service instance.
351+
* @return {String} Token.
352+
*/
353+
getTokenV3() {
354+
return this.private.tokenV3;
355+
}
299356
}
300357

301358
let lastInstance = null;

0 commit comments

Comments
 (0)