Skip to content

Develop #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 79 commits into from
Mar 30, 2019
Merged
Changes from all commits
Commits
Show all changes
79 commits
Select commit Hold shift + click to select a range
31e84ed
Adds support for v4 API and updates challenge service to use it.
a-lowe Jun 27, 2018
156381b
Updates getUserChallenges to use v4.
a-lowe Jun 28, 2018
c65af46
Merge branch 'master' into new-develop-mm
a-lowe Jun 29, 2018
ba0098e
Fixes issues with track being null and TCO events not displaying on e…
a-lowe Jun 30, 2018
81a0e8b
Adds "prepack" script
birdofpreyru Jul 2, 2018
9379580
Allows "-rcXXX" suffix on release tags
birdofpreyru Jul 2, 2018
d2b3912
Fix previous commit
birdofpreyru Jul 2, 2018
aa1bc0c
Another fix
birdofpreyru Jul 2, 2018
7581820
Update of release config
birdofpreyru Jul 2, 2018
bffd66c
Adds delay to challenge refresh on register/unregister to allow time …
a-lowe Jul 9, 2018
0c39928
Merge branch 'develop' into new-develop-mm
birdofpreyru Jul 10, 2018
405ec60
Adds challenge normalizations for legacy Marathon Matches. Fixes sor…
a-lowe Jul 18, 2018
709de69
Update package lock.
a-lowe Jul 18, 2018
af28491
Update version.
a-lowe Jul 18, 2018
2fdbd85
Merge branch 'develop'
birdofpreyru Jul 31, 2018
4944880
Merge branch 'develop'
birdofpreyru Jul 31, 2018
622e627
Merge branch 'develop'
birdofpreyru Jul 31, 2018
7810efa
Merge branch 'develop'
birdofpreyru Aug 3, 2018
a865387
Merge branch 'develop'
birdofpreyru Aug 6, 2018
fd2a23a
Merge pull request #20 from topcoder-platform/develop
ThomasKranitsas Aug 7, 2018
0d95f10
Merge pull request #22 from topcoder-platform/develop
ThomasKranitsas Aug 15, 2018
8f45e42
Merge branch 'develop' into new-develop-mm
birdofpreyru Aug 16, 2018
fe6e0b4
Merge branch 'develop'
birdofpreyru Aug 27, 2018
1116be7
Merge pull request #26 from topcoder-platform/develop
ThomasKranitsas Oct 3, 2018
bb6b247
After merge
sushilshinde Oct 25, 2018
fabce7b
fixing build issues
sushilshinde Oct 31, 2018
52f94bb
fixing build issues
sushilshinde Oct 31, 2018
3c914fe
Merge pull request #28 from sushilshinde/new-develop-mm
sushilshinde Oct 31, 2018
f05e63e
pushing build artifact - this is for testing only
sushilshinde Oct 31, 2018
14646af
deleting prod build artifacts
sushilshinde Nov 1, 2018
e0250be
issue_1732 fixed linting issues
Nov 1, 2018
d6f3edb
Merge pull request #29 from rashmi73/issue_1732
sushilshinde Nov 3, 2018
ef07dd6
adding prod dist - for testign only
sushilshinde Nov 5, 2018
bc45c27
deleting prod dist
sushilshinde Nov 19, 2018
54b5b14
removing hardcoding
sushilshinde Nov 19, 2018
3e32332
building dev dist
sushilshinde Nov 19, 2018
c761a65
adding prod folder
sushilshinde Nov 22, 2018
726db44
Changed npm version
sushilshinde Nov 28, 2018
1e4b154
Deleting dist folder, updating gitignore
sushilshinde Nov 28, 2018
aae7bd1
Fix eslint configs and tests
ThomasKranitsas Nov 28, 2018
626aa51
Merge pull request #30 from topcoder-platform/new-develop-mm
ThomasKranitsas Nov 28, 2018
a584e81
Merge pull request #31 from topcoder-platform/develop
ThomasKranitsas Nov 28, 2018
6d8dfad
Update members.js
kkartunov Dec 10, 2018
097ccc8
Update package.json
kkartunov Dec 10, 2018
b5e045b
Fix code quality issues from V4 changes
ThomasKranitsas Dec 14, 2018
009d34c
Merge branch 'master' into develop
birdofpreyru Dec 16, 2018
17e070e
Adds `getTcM2mToken()` and `reduceGroupIds(..)` to API and Group serv…
birdofpreyru Dec 16, 2018
99e3a73
Adds `getGroupTreeIds(..)` method to the Groups service + fixes
birdofpreyru Dec 16, 2018
dd92d26
updating gitignore for dist folder - for testing
sushilshinde Dec 17, 2018
43b2ba6
updating gitignore for dist folder - for testing
sushilshinde Dec 17, 2018
26fd3db
updating gitignore for dist folder - for testing
sushilshinde Dec 17, 2018
1bdfa46
Fix DEVELOP_MARATHON_MATCH track
ThomasKranitsas Dec 20, 2018
1769c20
bump npm version
ThomasKranitsas Dec 20, 2018
0d005dd
meta for /challenges and npm bump
kkartunov Jan 8, 2019
79f8960
Fix broken snapshot
kkartunov Jan 8, 2019
3467063
pushing build files
sushilshinde Jan 25, 2019
5e098b5
Resolve conflicts
ThomasKranitsas Jan 29, 2019
f271382
Resolve conflicts
ThomasKranitsas Jan 29, 2019
7f3b805
Fix tests
ThomasKranitsas Jan 29, 2019
8c79b42
Merge pull request #33 from topcoder-platform/code-quality-fixes
ThomasKranitsas Jan 29, 2019
dec3050
Fix issue 39
ThomasKranitsas Feb 4, 2019
ff9341b
Merge pull request #40 from topcoder-platform/fix-39
ThomasKranitsas Feb 4, 2019
34456c3
Code quality improvements
ThomasKranitsas Feb 4, 2019
4067334
Merge pull request #41 from topcoder-platform/code-quality-fixes
sushilshinde Feb 7, 2019
b3bf8b3
deleting dist folder
sushilshinde Feb 7, 2019
b9919c5
upgrading version
sushilshinde Feb 7, 2019
e13c3e2
code 30086294
suppermancool Mar 20, 2019
b65a469
Merge pull request #47 from suppermancool/code-30086294
ThomasKranitsas Mar 20, 2019
0cabdb3
Fix community-app 2056
LieutenantRoger Mar 21, 2019
62ea4ea
Merge pull request #48 from LieutenantRoger/develop
ThomasKranitsas Mar 21, 2019
a614212
fixes community app issue 2259
sumitdaga Mar 24, 2019
480caef
for testing pushing dist folder - temp
sushilshinde Mar 26, 2019
a9c16dd
Update Email Change Flow
Mar 27, 2019
8729d61
Fixed snapshots of test
Mar 27, 2019
14c831f
Merge pull request #49 from sumitdaga/community-app-issue-2259
sushilshinde Mar 28, 2019
744191c
Merge pull request #50 from nauhil/develop
sushilshinde Mar 28, 2019
10cf02c
npm version upgrade
sushilshinde Mar 28, 2019
49c1db7
Fix tests
ThomasKranitsas Mar 28, 2019
cf6886e
Merge branch 'develop' of https://github.com/topcoder-platform/topcod…
ThomasKranitsas Mar 28, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .DS_Store
Binary file not shown.
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -43,6 +43,6 @@ workflows:
branches:
ignore: /.*/
tags:
only: /v[0-9]+(\.[0-9]+)*/
only: /v[0-9]+(\.[0-9]+)*(-[0-9]+)?/
requires:
- test
2 changes: 1 addition & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"extends": "./node_modules/topcoder-react-utils/config/eslint/default.json"
}
}
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
__coverage__
.build-info
.sass-cache
dist
#dist
node_modules
_auto_doc_
.vscode
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v8.11.1
8.11.2
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Topcoder React Lib

### v0.7.4
- Added `getTcM2mToken()` function to API service, to facilitate handling of
TC M2M token;
- Added `getGroupTreeIds(..)`, `getTokenV3()`, and `reduceGroupIds(..)`
functions to the Groups service, to facilitate deduction of all IDs in a group
(sub-)tree, rooted at a specified group.

### v0.6.0
A few changes related to fetch of projests visitble to users, and creation of
new challenges. Minor release to guard against any side-effects.
12 changes: 9 additions & 3 deletions __tests__/__snapshots__/index.js.snap
Original file line number Diff line number Diff line change
@@ -54,6 +54,8 @@ Object {
"getLookerDone": [Function],
},
"lookup": Object {
"getCountriesDone": [Function],
"getCountriesInit": [Function],
"getSkillTagsDone": [Function],
"getSkillTagsInit": [Function],
},
@@ -127,6 +129,8 @@ Object {
"updateProfileInit": [Function],
"uploadPhotoDone": [Function],
"uploadPhotoInit": [Function],
"verifyMemberNewEmailDone": [Function],
"verifyMemberNewEmailInit": [Function],
},
"reviewOpportunity": Object {
"cancelApplicationsDone": [Function],
@@ -237,9 +241,11 @@ Object {
"services": Object {
"api": Object {
"default": [Function],
"getApi": [Function],
"getApiV2": [Function],
"getApiV3": [Function],
"getApiV4": [Function],
"getTcM2mToken": [Function],
},
"billing": Object {
"default": [Function],
@@ -253,7 +259,6 @@ Object {
"getService": [Function],
"normalizeChallenge": [Function],
"normalizeChallengeDetails": [Function],
"normalizeMarathonMatch": [Function],
},
"communities": Object {
"default": undefined,
@@ -269,6 +274,7 @@ Object {
"checkUserGroups": [Function],
"default": undefined,
"getService": [Function],
"reduceGroupIds": [Function],
},
"lookup": Object {
"default": undefined,
@@ -310,8 +316,8 @@ Object {
"Iterative Review": "Iterative Review",
"Spec Review": "Specification Review",
},
"getApiResponsePayloadV3": [Function],
"getApiResponsePayloadV4": [Function],
"getApiResponsePayload": [Function],
"getLookerApiResponsePayload": [Function],
},
"time": Object {
"default": undefined,
20 changes: 20 additions & 0 deletions __tests__/actions/__snapshots__/lookup.js.snap
Original file line number Diff line number Diff line change
@@ -3,12 +3,32 @@
exports[`Module exports 1`] = `
Object {
"lookup": Object {
"getCountriesDone": [Function],
"getCountriesInit": [Function],
"getSkillTagsDone": [Function],
"getSkillTagsInit": [Function],
},
}
`;

exports[`lookup.getCountriesDone 1`] = `
Object {
"payload": Array [
Object {
"country": "Afghanistan",
"countryCode": "AFG",
},
],
"type": "LOOKUP/GET_COUNTRIES_DONE",
}
`;

exports[`lookup.getCountriesInit 1`] = `
Object {
"type": "LOOKUP/GET_COUNTRIES_INIT",
}
`;

exports[`lookup.getSkillTagsDone 1`] = `
Object {
"payload": Array [
2 changes: 2 additions & 0 deletions __tests__/actions/__snapshots__/profile.js.snap
Original file line number Diff line number Diff line change
@@ -45,6 +45,8 @@ Object {
"updateProfileInit": [Function],
"uploadPhotoDone": [Function],
"uploadPhotoInit": [Function],
"verifyMemberNewEmailDone": [Function],
"verifyMemberNewEmailInit": [Function],
},
}
`;
17 changes: 17 additions & 0 deletions __tests__/actions/lookup.js
Original file line number Diff line number Diff line change
@@ -10,9 +10,15 @@ const tag = {
status: 'APPROVED',
};

const country = {
country: 'Afghanistan',
countryCode: 'AFG',
};

// Mock services
const mockLookupService = {
getTags: jest.fn().mockReturnValue(Promise.resolve([tag])),
getCountries: jest.fn().mockReturnValue(Promise.resolve([country])),
};
LookupService.getService = jest.fn().mockReturnValue(mockLookupService);

@@ -28,3 +34,14 @@ test('lookup.getSkillTagsDone', async () => {
expect(actionResult).toMatchSnapshot();
expect(mockLookupService.getTags).toBeCalled();
});

test('lookup.getCountriesInit', async () => {
const actionResult = actions.lookup.getCountriesInit();
expect(actionResult).toMatchSnapshot();
});

test('lookup.getCountriesDone', async () => {
const actionResult = await redux.resolveAction(actions.lookup.getCountriesDone());
expect(actionResult).toMatchSnapshot();
expect(mockLookupService.getCountries).toBeCalled();
});
90 changes: 90 additions & 0 deletions __tests__/reducers/__snapshots__/lookup.js.snap
Original file line number Diff line number Diff line change
@@ -1,7 +1,50 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Default reducer Get countries 1`] = `
Object {
"countries": Array [
Object {
"country": "Afghanistan",
"countryCode": "AFG",
},
],
"loadingCountriesError": false,
"loadingSkillTagsError": true,
"skillTags": Array [
Object {
"domain": "SKILLS",
"id": 251,
"name": "Jekyll",
"status": "APPROVED",
},
],
}
`;

exports[`Default reducer Get countries error 1`] = `
Object {
"countries": Array [
Object {
"country": "Afghanistan",
"countryCode": "AFG",
},
],
"loadingCountriesError": true,
"loadingSkillTagsError": true,
"skillTags": Array [
Object {
"domain": "SKILLS",
"id": 251,
"name": "Jekyll",
"status": "APPROVED",
},
],
}
`;

exports[`Default reducer Get skill tags 1`] = `
Object {
"countries": Array [],
"loadingSkillTagsError": false,
"skillTags": Array [
Object {
@@ -16,6 +59,7 @@ Object {

exports[`Default reducer Get skill tags error 1`] = `
Object {
"countries": Array [],
"loadingSkillTagsError": true,
"skillTags": Array [
Object {
@@ -30,12 +74,56 @@ Object {

exports[`Default reducer Initial state 1`] = `
Object {
"countries": Array [],
"skillTags": Array [],
}
`;

exports[`Factory without server side rendering Get countries 1`] = `
Object {
"countries": Array [
Object {
"country": "Afghanistan",
"countryCode": "AFG",
},
],
"loadingCountriesError": false,
"loadingSkillTagsError": true,
"skillTags": Array [
Object {
"domain": "SKILLS",
"id": 251,
"name": "Jekyll",
"status": "APPROVED",
},
],
}
`;

exports[`Factory without server side rendering Get countries error 1`] = `
Object {
"countries": Array [
Object {
"country": "Afghanistan",
"countryCode": "AFG",
},
],
"loadingCountriesError": true,
"loadingSkillTagsError": true,
"skillTags": Array [
Object {
"domain": "SKILLS",
"id": 251,
"name": "Jekyll",
"status": "APPROVED",
},
],
}
`;

exports[`Factory without server side rendering Get skill tags 1`] = `
Object {
"countries": Array [],
"loadingSkillTagsError": false,
"skillTags": Array [
Object {
@@ -50,6 +138,7 @@ Object {

exports[`Factory without server side rendering Get skill tags error 1`] = `
Object {
"countries": Array [],
"loadingSkillTagsError": true,
"skillTags": Array [
Object {
@@ -64,6 +153,7 @@ Object {

exports[`Factory without server side rendering Initial state 1`] = `
Object {
"countries": Array [],
"skillTags": Array [],
}
`;
116 changes: 116 additions & 0 deletions __tests__/reducers/__snapshots__/profile.js.snap

Large diffs are not rendered by default.

19 changes: 19 additions & 0 deletions __tests__/reducers/lookup.js
Original file line number Diff line number Diff line change
@@ -7,11 +7,19 @@ const tag = {
status: 'APPROVED',
};

const country = {
country: 'Afghanistan',
countryCode: 'AFG',
};

const mockActions = {
lookup: {
getSkillTagsInit: mockAction('LOOKUP/GET_SKILL_TAGS_INIT'),
getSkillTagsDone: mockAction('LOOKUP/GET_SKILL_TAGS_DONE', [tag]),
getSkillTagsDoneError: mockAction('LOOKUP/GET_SKILL_TAGS_DONE', null, 'Unknown error'),
getCountriesInit: mockAction('LOOKUP/GET_COUNTRIES_INIT'),
getCountriesDone: mockAction('LOOKUP/GET_COUNTRIES_DONE', [country]),
getCountriesDoneError: mockAction('LOOKUP/GET_COUNTRIES_DONE', null, 'Unknown error'),
},
};
jest.setMock(require.resolve('actions/lookup'), mockActions);
@@ -38,6 +46,17 @@ function testReducer() {
state = reducer(state, mockActions.lookup.getSkillTagsDoneError());
expect(state).toMatchSnapshot();
});

test('Get countries', () => {
state = reducer(state, mockActions.lookup.getCountriesInit());
state = reducer(state, mockActions.lookup.getCountriesDone());
expect(state).toMatchSnapshot();
});

test('Get countries error', () => {
state = reducer(state, mockActions.lookup.getCountriesDoneError());
expect(state).toMatchSnapshot();
});
}

describe('Default reducer', () => {
18 changes: 9 additions & 9 deletions __tests__/services/api.js
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@ jest.mock(
);

const { config } = require('topcoder-react-utils');
const { getApiV2, getApiV3 } = require('../../src/services/api');
const { getApi } = require('../../src/services/api');

describe('Test api', () => {
const ENDPOINT = '/ENDPOINT';
@@ -79,43 +79,43 @@ describe('Test api', () => {

let api;
test('API v2 service works without auth token', () => {
api = getApiV2();
api = getApi('V2');
return testApi(api, config.API.V2);
});

test('API v2 service works with auth token', () => {
api = getApiV2('TOKEN');
api = getApi('V2', 'TOKEN');
return testApi(api, config.API.V2, 'TOKEN');
});

test(
'API v2 service from the previous call is re-used, if token is the same',
() => expect(getApiV2('TOKEN')).toBe(api),
() => expect(getApi('V2', 'TOKEN')).toBe(api),
);

test('New API v2 service is created if token is new', () => {
const api2 = getApiV2('TOKEN2');
const api2 = getApi('V2', 'TOKEN2');
expect(api2).not.toBe(api);
return testApi(api2, config.API.V2, 'TOKEN2');
});

test('API v3 service works without auth token', () => {
api = getApiV3();
api = getApi('V3');
return testApi(api, config.API.V3);
});

test('API v3 service works with auth token', () => {
api = getApiV3('TOKEN');
api = getApi('V3', 'TOKEN');
return testApi(api, config.API.V3, 'TOKEN');
});

test(
'API v3 service from the previous call is re-used, if token is the same',
() => expect(getApiV3('TOKEN')).toBe(api),
() => expect(getApi('V3', 'TOKEN')).toBe(api),
);

test('New API v3 service is created if token is new', () => {
const api2 = getApiV3('TOKEN2');
const api2 = getApi('V3', 'TOKEN2');
expect(api2).not.toBe(api);
return testApi(api2, config.API.V3, 'TOKEN2');
});
1,421 changes: 1,421 additions & 0 deletions dist/dev/index.js

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions dist/prod/index.js

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions docs/actions.lookup.md
Original file line number Diff line number Diff line change
@@ -7,6 +7,8 @@ Actions related to lookup data.
* [actions.lookup](#module_actions.lookup)
* [.getSkillTagsInit()](#module_actions.lookup.getSkillTagsInit) ⇒ <code>Action</code>
* [.getSkillTagsDone()](#module_actions.lookup.getSkillTagsDone) ⇒ <code>Action</code>
* [.getCountriesInit()](#module_actions.lookup.getCountriesInit) ⇒ <code>Action</code>
* [.getCountriesDone()](#module_actions.lookup.getCountriesDone) ⇒ <code>Action</code>

<a name="module_actions.lookup.getSkillTagsInit"></a>

@@ -20,3 +22,9 @@ Creates an action that signals beginning of getting all skill tags.
Creates an action that gets all skill tags.

**Kind**: static method of [<code>actions.lookup</code>](#module_actions.lookup)
<a name="module_actions.lookup.getCountriesDone"></a>

### actions.lookup.getCountriesDone() ⇒ <code>Action</code>
Creates an action that gets all countries.

**Kind**: static method of [<code>actions.lookup</code>](#module_actions.lookup)
107 changes: 66 additions & 41 deletions docs/actions.profile.md

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions docs/reducers.lookup.md
Original file line number Diff line number Diff line change
@@ -17,6 +17,7 @@ State segment managed by this reducer has the following structure:
* [.factory()](#module_reducers.lookup.factory) ⇒ <code>Promise</code>
* _inner_
* [~onGetSkillTagsDone(state, action)](#module_reducers.lookup..onGetSkillTagsDone) ⇒ <code>Object</code>
* [~onGetCountriesDone(state, action)](#module_reducers.lookup..onGetCountriesDone) ⇒ <code>Object</code>
* [~create(initialState)](#module_reducers.lookup..create) ⇒ <code>function</code>

<a name="module_reducers.lookup.default"></a>
@@ -37,6 +38,13 @@ Factory which creates a new reducer.
### reducers.lookup~onGetSkillTagsDone(state, action) ⇒ <code>Object</code>
Handles LOOKUP/GET_SKILL_TAGS_DONE action.

**Kind**: static method of [<code>reducers.lookup</code>](#module_reducers.lookup)
**Resolves**: <code>Function(state, action): state</code> New reducer.
<a name="module_reducers.lookup..onGetCountriesDone"></a>

### reducers.lookup~onGetCountriesDone(state, action) ⇒ <code>Object</code>
Handles LOOKUP/GET_COUNTRIES_DONE action.

**Kind**: inner method of [<code>reducers.lookup</code>](#module_reducers.lookup)
**Returns**: <code>Object</code> - New state

552 changes: 363 additions & 189 deletions docs/reducers.profile.md

Large diffs are not rendered by default.

24 changes: 6 additions & 18 deletions docs/services.api.md
Original file line number Diff line number Diff line change
@@ -7,8 +7,7 @@ This module provides a service for conventient access to Topcoder APIs.
* [services.api](#module_services.api)
* _static_
* [.default](#module_services.api.default)
* [.getApiV2(token)](#module_services.api.getApiV2) ⇒ <code>Api</code>
* [.getApiV3(token)](#module_services.api.getApiV3) ⇒ <code>Api</code>
* [.getApi(version, token)](#module_services.api.getApi) ⇒ <code>Api</code>
* _inner_
* [~Api](#module_services.api..Api)
* [new Api(base, token)](#new_module_services.api..Api_new)
@@ -30,30 +29,19 @@ The default export from the module is
[Api](#module_services.api..Api) class.

**Kind**: static property of [<code>services.api</code>](#module_services.api)
<a name="module_services.api.getApiV2"></a>
<a name="module_services.api.getApi"></a>

### services.api.getApiV2(token) ⇒ <code>Api</code>
Returns a new or existing Api object for Topcoder API v2.
### services.api.getApi(version, token) ⇒ <code>Api</code>
Returns a new or existing Api object for Topcoder API.

**Kind**: static method of [<code>services.api</code>](#module_services.api)
**Returns**: <code>Api</code> - API v2 service object.
**Returns**: <code>Api</code> - API service object.

| Param | Type | Description |
| --- | --- | --- |
| version | <code>String</code> | The version of the API. |
| token | <code>String</code> | Optional. Auth token for Topcoder API v2. |

<a name="module_services.api.getApiV3"></a>

### services.api.getApiV3(token) ⇒ <code>Api</code>
Returns a new or existing Api object for Topcoder API v3

**Kind**: static method of [<code>services.api</code>](#module_services.api)
**Returns**: <code>Api</code> - API v3 service object.

| Param | Type | Description |
| --- | --- | --- |
| token | <code>String</code> | Optional. Auth token for Topcoder API v3. |

<a name="module_services.api..Api"></a>

### services.api~Api
88 changes: 51 additions & 37 deletions docs/services.members.md
Original file line number Diff line number Diff line change
@@ -28,14 +28,15 @@ members via API V3.
* [.getPresignedUrl(userHandle, file)](#module_services.members..MembersService+getPresignedUrl) ⇒ <code>Promise</code>
* [.updateMemberPhoto(S3Response)](#module_services.members..MembersService+updateMemberPhoto) ⇒ <code>Promise</code>
* [.uploadFileToS3(presignedUrlResponse)](#module_services.members..MembersService+uploadFileToS3) ⇒ <code>Promise</code>
* [.verifyMemberNewEmail(handle, emailVerifyToken)](#module_services.members..MembersService+verifyMemberNewEmail) ⇒ <code>Promise</code>

<a name="module_services.members.getService"></a>

### services.members.getService(tokenV3) ⇒ <code>MembersService</code>
Returns a new or existing members service.

**Kind**: static method of [<code>services.members</code>](#module_services.members)
**Returns**: <code>MembersService</code> - Members service object
**Kind**: static method of [<code>services.members</code>](#module_services.members)
**Returns**: <code>MembersService</code> - Members service object

| Param | Type | Description |
| --- | --- | --- |
@@ -46,7 +47,7 @@ Returns a new or existing members service.
### services.members~MembersService
Service class.

**Kind**: inner class of [<code>services.members</code>](#module_services.members)
**Kind**: inner class of [<code>services.members</code>](#module_services.members)

* [~MembersService](#module_services.members..MembersService)
* [new MembersService(tokenV3)](#new_module_services.members..MembersService_new)
@@ -67,6 +68,7 @@ Service class.
* [.getPresignedUrl(userHandle, file)](#module_services.members..MembersService+getPresignedUrl) ⇒ <code>Promise</code>
* [.updateMemberPhoto(S3Response)](#module_services.members..MembersService+updateMemberPhoto) ⇒ <code>Promise</code>
* [.uploadFileToS3(presignedUrlResponse)](#module_services.members..MembersService+uploadFileToS3) ⇒ <code>Promise</code>
* [.verifyMemberNewEmail(handle, emailVerifyToken)](#module_services.members..MembersService+verifyMemberNewEmail) ⇒ <code>Promise</code>

<a name="new_module_services.members..MembersService_new"></a>

@@ -81,8 +83,8 @@ Service class.
#### membersService.getMemberFinances(handle) ⇒ <code>Promise</code>
Gets member's financial information.

**Kind**: instance method of [<code>MembersService</code>](#module_services.members..MembersService)
**Returns**: <code>Promise</code> - Resolves to the financial information object.
**Kind**: instance method of [<code>MembersService</code>](#module_services.members..MembersService)
**Returns**: <code>Promise</code> - Resolves to the financial information object.

| Param | Type | Description |
| --- | --- | --- |
@@ -95,8 +97,8 @@ Gets public information on a member.

This method does not require any authorization.

**Kind**: instance method of [<code>MembersService</code>](#module_services.members..MembersService)
**Returns**: <code>Promise</code> - Resolves to the data object.
**Kind**: instance method of [<code>MembersService</code>](#module_services.members..MembersService)
**Returns**: <code>Promise</code> - Resolves to the data object.

| Param | Type | Description |
| --- | --- | --- |
@@ -107,8 +109,8 @@ This method does not require any authorization.
#### membersService.getExternalAccounts(handle) ⇒ <code>Promise</code>
Gets member external account info.

**Kind**: instance method of [<code>MembersService</code>](#module_services.members..MembersService)
**Returns**: <code>Promise</code> - Resolves to the stats object.
**Kind**: instance method of [<code>MembersService</code>](#module_services.members..MembersService)
**Returns**: <code>Promise</code> - Resolves to the stats object.

| Param | Type |
| --- | --- |
@@ -119,8 +121,8 @@ Gets member external account info.
#### membersService.getExternalLinks(handle) ⇒ <code>Promise</code>
Gets member external links.

**Kind**: instance method of [<code>MembersService</code>](#module_services.members..MembersService)
**Returns**: <code>Promise</code> - Resolves to the stats object.
**Kind**: instance method of [<code>MembersService</code>](#module_services.members..MembersService)
**Returns**: <code>Promise</code> - Resolves to the stats object.

| Param | Type |
| --- | --- |
@@ -131,8 +133,8 @@ Gets member external links.
#### membersService.getSkills(handle) ⇒ <code>Promise</code>
Gets member skills.

**Kind**: instance method of [<code>MembersService</code>](#module_services.members..MembersService)
**Returns**: <code>Promise</code> - Resolves to the stats object.
**Kind**: instance method of [<code>MembersService</code>](#module_services.members..MembersService)
**Returns**: <code>Promise</code> - Resolves to the stats object.

| Param | Type |
| --- | --- |
@@ -143,8 +145,8 @@ Gets member skills.
#### membersService.getStats(handle) ⇒ <code>Promise</code>
Gets member statistics.

**Kind**: instance method of [<code>MembersService</code>](#module_services.members..MembersService)
**Returns**: <code>Promise</code> - Resolves to the stats object.
**Kind**: instance method of [<code>MembersService</code>](#module_services.members..MembersService)
**Returns**: <code>Promise</code> - Resolves to the stats object.

| Param | Type |
| --- | --- |
@@ -155,8 +157,8 @@ Gets member statistics.
#### membersService.getStatsHistory(handle) ⇒ <code>Promise</code>
Gets member statistics history

**Kind**: instance method of [<code>MembersService</code>](#module_services.members..MembersService)
**Returns**: <code>Promise</code> - Resolves to the stats object.
**Kind**: instance method of [<code>MembersService</code>](#module_services.members..MembersService)
**Returns**: <code>Promise</code> - Resolves to the stats object.

| Param | Type |
| --- | --- |
@@ -167,8 +169,8 @@ Gets member statistics history
#### membersService.getStatsDistribution(handle, track, subTrack) ⇒ <code>Promise</code>
Gets member statistics distribution

**Kind**: instance method of [<code>MembersService</code>](#module_services.members..MembersService)
**Returns**: <code>Promise</code> - Resolves to the stats object.
**Kind**: instance method of [<code>MembersService</code>](#module_services.members..MembersService)
**Returns**: <code>Promise</code> - Resolves to the stats object.

| Param | Type |
| --- | --- |
@@ -183,8 +185,8 @@ Gets a list of suggested member names for the supplied partial.

WARNING: This method requires v3 authorization.

**Kind**: instance method of [<code>MembersService</code>](#module_services.members..MembersService)
**Returns**: <code>Promise</code> - Resolves to the api response content
**Kind**: instance method of [<code>MembersService</code>](#module_services.members..MembersService)
**Returns**: <code>Promise</code> - Resolves to the api response content

| Param | Type | Description |
| --- | --- | --- |
@@ -195,8 +197,8 @@ WARNING: This method requires v3 authorization.
#### membersService.addWebLink(userHandle, webLink) ⇒ <code>Promise</code>
Adds external web link for member.

**Kind**: instance method of [<code>MembersService</code>](#module_services.members..MembersService)
**Returns**: <code>Promise</code> - Resolves to the api response content
**Kind**: instance method of [<code>MembersService</code>](#module_services.members..MembersService)
**Returns**: <code>Promise</code> - Resolves to the api response content

| Param | Type | Description |
| --- | --- | --- |
@@ -208,8 +210,8 @@ Adds external web link for member.
#### membersService.deleteWebLink(userHandle, webLinkHandle) ⇒ <code>Promise</code>
Deletes external web link for member.

**Kind**: instance method of [<code>MembersService</code>](#module_services.members..MembersService)
**Returns**: <code>Promise</code> - Resolves to the api response content
**Kind**: instance method of [<code>MembersService</code>](#module_services.members..MembersService)
**Returns**: <code>Promise</code> - Resolves to the api response content

| Param | Type | Description |
| --- | --- | --- |
@@ -221,8 +223,8 @@ Deletes external web link for member.
#### membersService.addSkill(handle, skillTagId) ⇒ <code>Promise</code>
Adds user skill.

**Kind**: instance method of [<code>MembersService</code>](#module_services.members..MembersService)
**Returns**: <code>Promise</code> - Resolves to operation result
**Kind**: instance method of [<code>MembersService</code>](#module_services.members..MembersService)
**Returns**: <code>Promise</code> - Resolves to operation result

| Param | Type | Description |
| --- | --- | --- |
@@ -234,8 +236,8 @@ Adds user skill.
#### membersService.hideSkill(handle, skillTagId) ⇒ <code>Promise</code>
Hides user skill.

**Kind**: instance method of [<code>MembersService</code>](#module_services.members..MembersService)
**Returns**: <code>Promise</code> - Resolves to operation result
**Kind**: instance method of [<code>MembersService</code>](#module_services.members..MembersService)
**Returns**: <code>Promise</code> - Resolves to operation result

| Param | Type | Description |
| --- | --- | --- |
@@ -247,8 +249,8 @@ Hides user skill.
#### membersService.updateMemberProfile(profile) ⇒ <code>Promise</code>
Updates member profile.

**Kind**: instance method of [<code>MembersService</code>](#module_services.members..MembersService)
**Returns**: <code>Promise</code> - Resolves to the api response content
**Kind**: instance method of [<code>MembersService</code>](#module_services.members..MembersService)
**Returns**: <code>Promise</code> - Resolves to the api response content

| Param | Type | Description |
| --- | --- | --- |
@@ -259,8 +261,8 @@ Updates member profile.
#### membersService.getPresignedUrl(userHandle, file) ⇒ <code>Promise</code>
Gets presigned url for member photo file.

**Kind**: instance method of [<code>MembersService</code>](#module_services.members..MembersService)
**Returns**: <code>Promise</code> - Resolves to the api response content
**Kind**: instance method of [<code>MembersService</code>](#module_services.members..MembersService)
**Returns**: <code>Promise</code> - Resolves to the api response content

| Param | Type | Description |
| --- | --- | --- |
@@ -272,8 +274,8 @@ Gets presigned url for member photo file.
#### membersService.updateMemberPhoto(S3Response) ⇒ <code>Promise</code>
Updates member photo.

**Kind**: instance method of [<code>MembersService</code>](#module_services.members..MembersService)
**Returns**: <code>Promise</code> - Resolves to the api response content
**Kind**: instance method of [<code>MembersService</code>](#module_services.members..MembersService)
**Returns**: <code>Promise</code> - Resolves to the api response content

| Param | Type | Description |
| --- | --- | --- |
@@ -284,10 +286,22 @@ Updates member photo.
#### membersService.uploadFileToS3(presignedUrlResponse) ⇒ <code>Promise</code>
Uploads file to S3.

**Kind**: instance method of [<code>MembersService</code>](#module_services.members..MembersService)
**Returns**: <code>Promise</code> - Resolves to the api response content
**Kind**: instance method of [<code>MembersService</code>](#module_services.members..MembersService)
**Returns**: <code>Promise</code> - Resolves to the api response content

| Param | Type | Description |
| --- | --- | --- |
| presignedUrlResponse | <code>Object</code> | The presigned url response from getPresignedUrl() function. |

<a name="module_services.members..MembersService+verifyMemberNewEmail"></a>

#### membersService.verifyMemberNewEmail(handle, emailVerifyToken) ⇒ <code>Promise</code>
Verify member new email.

**Kind**: instance method of [<code>MembersService</code>](#module_services.members..MembersService)
**Returns**: <code>Promise</code> - Resolves to the api response content

| Param | Type | Description |
| --- | --- | --- |
| handle | <code>String</code> | The member handle |
| emailVerifyToken | <code>String</code> | The verify token of new email |
8 changes: 4 additions & 4 deletions docs/tc.md
Original file line number Diff line number Diff line change
@@ -10,18 +10,18 @@ Collection of small Topcoder-related functions.

* [tc](#module_tc)
* [.REVIEW_OPPORTUNITY_TYPES](#module_tc.REVIEW_OPPORTUNITY_TYPES)
* [.getApiResponsePayloadV3(res)](#module_tc.getApiResponsePayloadV3) ⇒ <code>Promise</code>
* [.getApiResponsePayload(res)](#module_tc.getApiResponsePayload) ⇒ <code>Promise</code>

<a name="module_tc.REVIEW_OPPORTUNITY_TYPES"></a>

### tc.REVIEW_OPPORTUNITY_TYPES
Review Opportunity types

**Kind**: static constant of [<code>tc</code>](#module_tc)
<a name="module_tc.getApiResponsePayloadV3"></a>
<a name="module_tc.getApiResponsePayload"></a>

### tc.getApiResponsePayloadV3(res) ⇒ <code>Promise</code>
Gets payload from a standard success response from TC API v3; or throws
### tc.getApiResponsePayload(res) ⇒ <code>Promise</code>
Gets payload from a standard success response from TC API; or throws
an error in case of a failure response.

**Kind**: static method of [<code>tc</code>](#module_tc)
21,496 changes: 9,283 additions & 12,213 deletions package-lock.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -31,7 +31,7 @@
"lint:js": "./node_modules/.bin/eslint --ext .js,.jsx .",
"test": "npm run lint && npm run jest"
},
"version": "0.6.1",
"version": "0.7.9",
"dependencies": {
"auth0-js": "^6.8.4",
"isomorphic-fetch": "^2.2.1",
@@ -43,6 +43,7 @@
"qs": "^6.5.2",
"react": "^16.4.1",
"react-dom": "^16.4.1",
"react-redux": "^6.0.1",
"redux": "^3.7.2",
"redux-actions": "^2.4.0",
"tc-accounts": "https://github.com/appirio-tech/accounts-app.git#dev",
4 changes: 2 additions & 2 deletions src/actions/auth.js
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@

import { createActions } from 'redux-actions';
import { decodeToken } from 'tc-accounts';
import { getApiV3 } from '../services/api';
import { getApi } from '../services/api';

/**
* @static
@@ -16,7 +16,7 @@ import { getApiV3 } from '../services/api';
function loadProfileDone(userTokenV3) {
if (!userTokenV3) return Promise.resolve(null);
const user = decodeToken(userTokenV3);
const api = getApiV3(userTokenV3);
const api = getApi('V3', userTokenV3);
return Promise.all([
api.get(`/members/${user.handle}`)
.then(res => res.json()).then(res => (res.result.status === 200 ? res.result.content : {})),
25 changes: 19 additions & 6 deletions src/actions/challenge.js
Original file line number Diff line number Diff line change
@@ -4,9 +4,10 @@
*/

import _ from 'lodash';
import { config } from 'topcoder-react-utils';
import { createActions } from 'redux-actions';
import { getService as getChallengesService } from '../services/challenges';
import { getApiV2 } from '../services/api';
import { getApi } from '../services/api';

/**
* @static
@@ -69,7 +70,7 @@ function getSubmissionsInit(challengeId) {
* @return {Action}
*/
function getSubmissionsDone(challengeId, tokenV2) {
return getApiV2(tokenV2)
return getApi('V2', tokenV2)
.fetch(`/challenges/submissions/${challengeId}/mySubmissions`)
.then(response => response.json())
.then(response => ({
@@ -106,7 +107,13 @@ function registerDone(auth, challengeId) {
.register(challengeId)
/* As a part of registration flow we silently update challenge details,
* reusing for this purpose the corresponding action handler. */
.then(() => getDetailsDone(challengeId, auth.tokenV3, auth.tokenV2));
// Uses a delay to allow API time to update
.then(() => new Promise(
resolve => setTimeout(
() => resolve(getDetailsDone(challengeId, auth.tokenV3, auth.tokenV2)),
config.CHALLENGE_DETAILS_REFRESH_DELAY,
),
));
}

/**
@@ -131,7 +138,13 @@ function unregisterDone(auth, challengeId) {
.unregister(challengeId)
/* As a part of unregistration flow we silently update challenge details,
* reusing for this purpose the corresponding action handler. */
.then(() => getDetailsDone(challengeId, auth.tokenV3, auth.tokenV2));
// Uses a delay to allow API time to update
.then(() => new Promise(
resolve => setTimeout(
() => resolve(getDetailsDone(challengeId, auth.tokenV3, auth.tokenV2)),
config.CHALLENGE_DETAILS_REFRESH_DELAY,
),
));
}

/**
@@ -156,7 +169,7 @@ function loadResultsInit(challengeId) {
* @return {Action}
*/
function loadResultsDone(auth, challengeId, type) {
return getApiV2(auth.tokenV2)
return getApi('V2', auth.tokenV2)
.fetch(`/${type}/challenges/result/${challengeId}`)
.then(response => response.json())
.then(response => ({
@@ -181,7 +194,7 @@ function fetchCheckpointsInit() {}
*/
function fetchCheckpointsDone(tokenV2, challengeId) {
const endpoint = `/design/challenges/checkpoint/${challengeId}`;
return getApiV2(tokenV2).fetch(endpoint)
return getApi('V2', tokenV2).fetch(endpoint)
.then((response) => {
if (response.status !== 200) {
throw response.status;
18 changes: 18 additions & 0 deletions src/actions/lookup.js
Original file line number Diff line number Diff line change
@@ -26,9 +26,27 @@ function getSkillTagsDone() {
return getService().getTags(params);
}

/**
* @static
* @desc Creates an action that signals beginning of getting all countries.
* @return {Action}
*/
function getCountriesInit() {}

/**
* @static
* @desc Creates an action that gets all countries.
* @return {Action}
*/
function getCountriesDone() {
return getService().getCountries();
}

export default createActions({
LOOKUP: {
GET_SKILL_TAGS_INIT: getSkillTagsInit,
GET_SKILL_TAGS_DONE: getSkillTagsDone,
GET_COUNTRIES_INIT: getCountriesInit,
GET_COUNTRIES_DONE: getCountriesDone,
},
});
1 change: 0 additions & 1 deletion src/actions/members.js
Original file line number Diff line number Diff line change
@@ -143,7 +143,6 @@ async function getActiveChallengesDone(handle, uuid, tokenV3) {
}
const calls = [
getAll(params => service.getUserChallenges(handle, filter, params)),
getAll(params => service.getUserMarathonMatches(handle, filter, params)),
];

const [challenges] = await Promise.all(calls);
24 changes: 24 additions & 0 deletions src/actions/profile.js
Original file line number Diff line number Diff line change
@@ -412,6 +412,28 @@ function updatePasswordDone(profile, tokenV3, newPassword, oldPassword) {
.then(res => ({ data: res, handle: profile.handle }));
}

/**
* @static
* @desc Creates an action that signals beginning of verify member new email.
* @return {Action}
*/
function verifyMemberNewEmailInit() {}

/**
* @static
* @desc Creates an action that verify member new email.
*
* @param {Object} handle Topcoder member handle.
* @param {String} tokenV3 Topcoder auth token v3.
* @param {String} emailVerifyToken The verify token of new email.
* @return {Action}
*/
function verifyMemberNewEmailDone(handle, tokenV3, emailVerifyToken) {
const service = getMembersService(tokenV3);
return service.verifyMemberNewEmail(handle, emailVerifyToken)
.then(res => ({ data: res }));
}

export default createActions({
PROFILE: {
LOAD_PROFILE: loadProfile,
@@ -456,5 +478,7 @@ export default createActions({
SAVE_EMAIL_PREFERENCES_DONE: saveEmailPreferencesDone,
UPDATE_PASSWORD_INIT: updatePasswordInit,
UPDATE_PASSWORD_DONE: updatePasswordDone,
VERIFY_MEMBER_NEW_EMAIL_INIT: verifyMemberNewEmailInit,
VERIFY_MEMBER_NEW_EMAIL_DONE: verifyMemberNewEmailDone,
},
});
4 changes: 2 additions & 2 deletions src/actions/smp.js
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@

import _ from 'lodash';
import { createActions } from 'redux-actions';
import { getApiV3 } from '../services/api';
import { getApi } from '../services/api';

/**
* @static
@@ -22,7 +22,7 @@ function deleteSubmissionInit() {}
* @return {Action}
*/
function deleteSubmissionDone(tokenV3, submissionId) {
return getApiV3(tokenV3).delete(`/submissions/${submissionId}`)
return getApi('V3', tokenV3).delete(`/submissions/${submissionId}`)
.then(() => submissionId);
}

22 changes: 22 additions & 0 deletions src/reducers/lookup.js
Original file line number Diff line number Diff line change
@@ -29,6 +29,25 @@ function onGetSkillTagsDone(state, { payload, error }) {
});
}

/**
* Handles LOOKUP/GET_COUNTRIES_DONE action.
* @param {Object} state
* @param {Object} action Payload will be JSON from api call
* @return {Object} New state
*/
function onGetCountriesDone(state, { payload, error }) {
if (error) {
logger.error('Failed to get countries', payload);
return { ...state, loadingCountriesError: true };
}

return ({
...state,
loadingCountriesError: false,
countries: payload,
});
}

/**
* Creates a new Lookup reducer with the specified initial state.
* @param {Object} initialState Optional. Initial state.
@@ -39,8 +58,11 @@ function create(initialState = {}) {
return handleActions({
[a.getSkillTagsInit]: state => state,
[a.getSkillTagsDone]: onGetSkillTagsDone,
[a.getCountriesInit]: state => state,
[a.getCountriesDone]: onGetCountriesDone,
}, _.defaults(initialState, {
skillTags: [],
countries: [],
}));
}

39 changes: 37 additions & 2 deletions src/reducers/profile.js
Original file line number Diff line number Diff line change
@@ -215,11 +215,17 @@ function onUpdateProfileDone(state, { payload, error }) {
if (error) {
logger.error('Failed to update user profile', payload);
fireErrorMessage('ERROR: Failed to update user profile!');
return newState;
return {
...newState,
updateProfileSuccess: false,
};
}

if (!newState.info || newState.info.handle !== payload.handle) {
return newState;
return {
...newState,
updateProfileSuccess: true,
};
}

return {
@@ -228,6 +234,7 @@ function onUpdateProfileDone(state, { payload, error }) {
...newState.info,
...payload,
},
updateProfileSuccess: true,
};
}

@@ -420,10 +427,34 @@ function onUpdatePasswordDone(state, { payload, error }) {

if (error) {
logger.error('Failed to update password', payload);
fireErrorMessage('The old password is invalid');
}
return newState;
}

/**
* Handles PROFILE/VERIFY_MEMBER_NEW_EMAIL_DONE action.
* @param {Object} state
* @param {Object} action Payload will be JSON from api call
* @return {Object} New state
*/
function onVerifyMemberNewEmailDone(state, { payload, error }) {
const newState = { ...state, verifyingEmail: false };

if (error) {
logger.error('Failed to verify member new email', payload);
return {
...newState,
verifyError: true,
};
}

return {
...newState,
verifyError: false,
};
}

/**
* Creates a new Profile reducer with the specified initial state.
* @param {Object} initialState Optional. Initial state.
@@ -476,6 +507,8 @@ function create(initialState) {
[a.saveEmailPreferencesDone]: onSaveEmailPreferencesDone,
[a.updatePasswordInit]: state => ({ ...state, updatingPassword: true }),
[a.updatePasswordDone]: onUpdatePasswordDone,
[a.verifyMemberNewEmailInit]: state => ({ ...state, verifyingEmail: true }),
[a.verifyMemberNewEmailDone]: onVerifyMemberNewEmailDone,
}, _.defaults(initialState, {
achievements: null,
copilot: false,
@@ -484,6 +517,8 @@ function create(initialState) {
loadingError: false,
skills: null,
stats: null,
verifyError: null,
updateProfileSuccess: null,
}));
}

44 changes: 20 additions & 24 deletions src/services/__mocks__/api.js
Original file line number Diff line number Diff line change
@@ -103,36 +103,32 @@ export default class Api {
}
}

/**
* Topcoder API v2.
/*
* Topcoder API
*/
const lastApiInstances = {};

/**
* Returns a new or existing Api object for Topcoder API v2.
* @param {String} token Optional. Auth token for Topcoder API v2.
* @return {Api} API v2 service object.
* Returns a new or existing Api object for Topcoder API.
* @param {String} version The API version.
* @param {String} token Optional. Auth token for Topcoder API.
* @return {Api} API service object.
*/
let lastApiV2 = null;
export function getApiV2(token) {
if (!lastApiV2 || lastApiV2.private.token !== token) {
lastApiV2 = new Api(config.API.V2, token);
export function getApi(version, token) {
if (!version || !config.API[version]) {
throw new Error(`${version} is not a valid API version`);
}
if (!lastApiInstances[version] || lastApiInstances[version].private.token !== token) {
lastApiInstances[version] = new Api(config.API[version], token);
}
return lastApiV2;
return lastApiInstances[version];
}

/**
* Topcoder API v3.
* Keep the old API factories for backwards compatibility
* DO NOT USE THEM FOR NEW IMPLEMENTATIONS.
* USE THE getApi(version, token) FACTORY.
*/

/**
* Returns a new or existing Api object for Topcoder API v3
* @param {String} token Optional. Auth token for Topcoder API v3.
* @return {Api} API v3 service object.
*/
let lastApiV3 = null;
export function getApiV3(token) {
if (!lastApiV3 || lastApiV3.private.token !== token) {
lastApiV3 = new Api(config.API.V3, token);
}
return lastApiV3;
}
export const getApiV2 = token => getApi('V2', token);
export const getApiV3 = token => getApi('V3', token);
export const getApiV4 = token => getApi('V4', token);
6 changes: 3 additions & 3 deletions src/services/__mocks__/challenges.js
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@

import _ from 'lodash';
import { COMPETITION_TRACKS } from '../../utils/tc';
import { getApiV2, getApiV3 } from './api';
import { getApi } from './api';

import sampleApiV3Response from './data/challenges-v3.json';
import sampleApiV3ResponseSingle from './data/challenge-v3.json';
@@ -215,8 +215,8 @@ class ChallengesService {
};

this.private = {
api: getApiV3(tokenV3),
apiV2: getApiV2(tokenV2),
api: getApi('V3', tokenV3),
apiV2: getApi('V2', tokenV2),
getChallenges,
tokenV2,
tokenV3,
4 changes: 2 additions & 2 deletions src/services/__mocks__/groups.js
Original file line number Diff line number Diff line change
@@ -17,7 +17,7 @@

import _ from 'lodash';
import { config } from 'topcoder-react-utils';
import { getApiV3 } from './api';
import { getApi } from './api';
import logger from '../../utils/logger';

/* The value of USER_GROUP_MAXAGE constant converted to [ms]. */
@@ -172,7 +172,7 @@ class GroupService {
*/
constructor(tokenV3) {
this.private = {
api: getApiV3(tokenV3),
api: getApi('V3', tokenV3),
tokenV3,
};
}
90 changes: 56 additions & 34 deletions src/services/api.js
Original file line number Diff line number Diff line change
@@ -7,9 +7,10 @@ import _ from 'lodash';
import fetch from 'isomorphic-fetch';
import { config, isomorphy } from 'topcoder-react-utils';
import { delay } from '../utils/time';
import { setErrorIcon, ERROR_ICON_TYPES } from '../utils/errors';

config.API.V4 = 'https://api.topcoder.com/v4';
import {
setErrorIcon,
ERROR_ICON_TYPES,
} from '../utils/errors';

/* The minimal delay [ms] between API calls. To avoid problems with the requests
* rate limits configured in Topcoder APIs, we throttle requests rate at the
@@ -235,48 +236,69 @@ class Api {
export default Api;

/*
* Topcoder API v2.
* Topcoder API
*/
const lastApiInstances = {};

let lastApiV2 = null;
/**
* Returns a new or existing Api object for Topcoder API v2.
* @param {String} token Optional. Auth token for Topcoder API v2.
* @return {Api} API v2 service object.
* Returns a new or existing Api object for Topcoder API.
* @param {String} version The API version.
* @param {String} token Optional. Auth token for Topcoder API.
* @return {Api} API service object.
*/
export function getApiV2(token) {
if (!lastApiV2 || lastApiV2.private.token !== token) {
lastApiV2 = new Api(config.API.V2, token);
export function getApi(version, token) {
if (!version || !config.API[version]) {
throw new Error(`${version} is not a valid API version`);
}
if (!lastApiInstances[version] || lastApiInstances[version].private.token !== token) {
lastApiInstances[version] = new Api(config.API[version], token);
}
return lastApiV2;
return lastApiInstances[version];
}

/*
* Topcoder API v3.
*/

let lastApiV3 = null;
/**
* Returns a new or existing Api object for Topcoder API v3
* @param {String} token Optional. Auth token for Topcoder API v3.
* @return {Api} API v3 service object.
* Keep the old API factories for backwards compatibility
* DO NOT USE THEM FOR NEW IMPLEMENTATIONS.
* USE THE getApi(version, token) FACTORY.
*/
export function getApiV3(token) {
if (!lastApiV3 || lastApiV3.private.token !== token) {
lastApiV3 = new Api(config.API.V3, token);
}
return lastApiV3;
}
export const getApiV2 = token => getApi('V2', token);
export const getApiV3 = token => getApi('V3', token);
export const getApiV4 = token => getApi('V4', token);

let lastApiV4 = null;
/**
* Returns a new or existing Api object for Topcoder API V4
* @param {String} token Optional. Auth token for Topcoder API V4.
* @return {Api} API V4 service object.
* Gets a valid TC M2M token, either requesting one from TC Auth0 API, or
* serving one from internal cache.
*
* @return {Promise} Resolves to a token, valid at least next
* getTcM2mToken.MIN_LIFETIME milliseconds.
*
* @throw if called outside of the server.s
*/
export function getApiV4(token) {
if (!lastApiV4 || lastApiV4.private.token !== token) {
lastApiV4 = new Api(config.API.V4, token);
export async function getTcM2mToken() {
if (!isomorphy.isServerSide()) {
throw new Error('getTcM2mToken() called outside the server');
}
const now = Date.now();
const { cached } = getTcM2mToken;
const { TC_M2M } = config.SECRET;
if (!cached || cached.expires < now + getTcM2mToken.MIN_LIFETIME) {
let res = await fetch(`https://${config.AUTH0.DOMAIN}/oauth/token`, {
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
client_id: TC_M2M.CLIENT_ID,
client_secret: TC_M2M.CLIENT_SECRET,
audience: TC_M2M.AUDIENCE,
grant_type: TC_M2M.GRANT_TYPE,
}),
method: 'POST',
});
res = await res.json();
getTcM2mToken.cached = {
expires: now + 1000 * res.expires_in, // [ms]
token: res.access_token,
};
}
return lastApiV4;
return getTcM2mToken.cached.token;
}

getTcM2mToken.MIN_LIFETIME = 30 * 1000; // [ms]
4 changes: 2 additions & 2 deletions src/services/billing.js
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@
* @module "services.billing"
* @desc Access to Topcoder billing accounts.
*/
import { getApiV3 } from './api';
import { getApi } from './api';

/**
* @static
@@ -21,7 +21,7 @@ class Billing {
*/
constructor(tokenV3) {
this.private = {
api: getApiV3(tokenV3),
api: getApi('V3', tokenV3),
tokenV3,
};
}
439 changes: 145 additions & 294 deletions src/services/challenges.js

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions src/services/direct.js
Original file line number Diff line number Diff line change
@@ -7,7 +7,7 @@

import qs from 'qs';

import { getApiV3 } from './api';
import { getApi } from './api';

/**
* Direct service class.
@@ -21,7 +21,7 @@ class Direct {
*/
constructor(tokenV3) {
this.private = {
api: getApiV3(tokenV3),
api: getApi('V3', tokenV3),
tokenV3,
};
}
78 changes: 75 additions & 3 deletions src/services/groups.js
Original file line number Diff line number Diff line change
@@ -19,8 +19,7 @@
import _ from 'lodash';
import { config } from 'topcoder-react-utils';
import logger from '../utils/logger';
import { getApiV3 } from './api';

import { getApi } from './api';

/* The value of USER_GROUP_MAXAGE constant converted to [ms]. */
const USER_GROUP_MAXAGE = config.USER_GROUP_MAXAGE * 1000;
@@ -168,6 +167,22 @@ function mergeGroup(groups, group) {
/* eslint-enable no-param-reassign */
}

/**
* Given a group tree, reduces it to the array of all group IDs encountered in
* the tree.
* @param {Object} group
* @return {String[]} Array of IDs.
*/
export function reduceGroupIds({ id, subGroups }) {
let res = [id];
if (subGroups) {
subGroups.forEach((g) => {
res = res.concat(reduceGroupIds(g));
});
}
return res;
}

/**
* Service class.
*/
@@ -176,8 +191,15 @@ class GroupService {
* @param {String} tokenV3 Optional. Auth token for Topcoder API v3.
*/
constructor(tokenV3) {
const now = Date.now();
this.private = {
api: getApiV3(tokenV3),
api: getApi('V3', tokenV3),
cache: {
groupTreeIds: {
lastCleanUp: now,
data: {},
},
},
tokenV3,
};
}
@@ -254,6 +276,48 @@ class GroupService {
return Promise.all(promises).then(() => res);
}

/**
* Given a root group ID, returns an ID array that contains the root group ID,
* and IDs of all descendant groups in the group (sub-)tree rooted at the
* specified group.
*
* Results are cached inside the class instance to minimize the load on TC
* Group API. To take advantage of that, be sure to keep and reuse the same
* class instance.
*
* The reason to have such strange method and pay an extra attention to its
* optimization for smaller API load is that it is essential for authorization
* checks.
*
* @param {String} rootGroupId
* @param {Number} maxage Optional. Max age [ms] of records served from the
* cache. Defaults to 5 minutes.
* @return {Promise} Resolves to ID array.
*/
async getGroupTreeIds(rootGroupId, maxage = 5 * 60 * 1000) {
const now = Date.now();
const cache = this.private.cache.groupTreeIds;

/* Clean-up: removes stale records from the cache. */
const CLEAN_UP_INTERVAL = 24 * 60 * 60 * 1000; // 1 day in ms.
if (now - cache.lastCleanUp > CLEAN_UP_INTERVAL) {
_.forOwn(cache, ({ timestamp }, key) => {
if (now - timestamp > CLEAN_UP_INTERVAL) delete cache[key];
});
cache.lastCleanUp = now;
}

/* If result is found in cache, and is fresh enough, return it. */
const cached = cache[rootGroupId];
if (cached && now - cached.timestamp < maxage) return _.clone(cached.data);

/* Otherwise, fetch result from the API, write it to the cache, and
* finally return that. */
const res = reduceGroupIds(await this.getGroup(rootGroupId));
cache[rootGroupId] = { data: res, timestamp: now };
return _.clone(res);
}

/**
* Gets group members.
* @param {String} groupId
@@ -281,6 +345,14 @@ class GroupService {
if (!res.success) throw new Error(res.content);
return Number(res.content);
}

/**
* Returns TC Auth Token V3 used by the service instance.
* @return {String} Token.
*/
getTokenV3() {
return this.private.tokenV3;
}
}

let lastInstance = null;
25 changes: 12 additions & 13 deletions src/services/looker.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
/**
* @module "services.looker"
* @desc This module provides a service to get look data json
* via API V4.
* @desc This module provides a service to get look data json via Topcoder API.
*/
import { getApiResponsePayloadV4 } from '../utils/tc';
import { getApiV4 } from './api';
import { getLookerApiResponsePayload } from '../utils/tc';
import { getApi } from './api';

/**
* Service class.
*/
class LookerService {
/**
* @param {String} tokenV4 Optional. Auth token for Topcoder API v4.
* @param {String} token Optional. Auth token for Topcoder API.
*/
constructor(tokenV4) {
constructor(token) {
this.private = {
api: getApiV4(tokenV4),
tokenV4,
api: getApi('V4', token),
token,
};
}

@@ -27,19 +26,19 @@ class LookerService {
*/
async getLooker(lookerId) {
const res = await this.private.api.get(`/looks/${lookerId}/run/json`);
return getApiResponsePayloadV4(res);
return getLookerApiResponsePayload(res);
}
}

let lastInstance = null;
/**
* Returns a new or existing looker service.
* @param {String} tokenV4 Optional. Auth token for Topcoder API v4.
* @param {String} token Optional. Auth token for Topcoder API.
* @return {LookerService} looker service object
*/
export function getService(tokenV4) {
if (!lastInstance || tokenV4 !== lastInstance.private.tokenV4) {
lastInstance = new LookerService(tokenV4);
export function getService(token) {
if (!lastInstance || token !== lastInstance.private.token) {
lastInstance = new LookerService(token);
}
return lastInstance;
}
18 changes: 14 additions & 4 deletions src/services/lookup.js
Original file line number Diff line number Diff line change
@@ -4,16 +4,16 @@
* via API V3.
*/
import qs from 'qs';
import { getApiResponsePayloadV3 } from '../utils/tc';
import { getApiV3 } from './api';
import { getApiResponsePayload } from '../utils/tc';
import { getApi } from './api';

class LookupService {
/**
* @param {String} tokenV3 Optional. Auth token for Topcoder API v3.
*/
constructor(tokenV3) {
this.private = {
api: getApiV3(tokenV3),
api: getApi('V3', tokenV3),
tokenV3,
};
}
@@ -25,7 +25,17 @@ class LookupService {
*/
async getTags(params) {
const res = await this.private.api.get(`/tags/?${qs.stringify(params)}`);
return getApiResponsePayloadV3(res);
return getApiResponsePayload(res);
}

/**
* Gets countries.
* @param {Object} params Parameters
* @return {Promise} Resolves to the countries.
*/
async getCountries() {
const res = await this.private.api.get('/members/lookup/countries');
return getApiResponsePayload(res);
}
}

52 changes: 32 additions & 20 deletions src/services/members.js
Original file line number Diff line number Diff line change
@@ -8,8 +8,8 @@
import _ from 'lodash';
import qs from 'qs';
import logger from '../utils/logger';
import { getApiResponsePayloadV3 } from '../utils/tc';
import { getApiV3 } from './api';
import { getApiResponsePayload } from '../utils/tc';
import { getApi } from './api';

/**
* Service class.
@@ -20,7 +20,7 @@ class MembersService {
*/
constructor(tokenV3) {
this.private = {
api: getApiV3(tokenV3),
api: getApi('V3', tokenV3),
tokenV3,
};
}
@@ -32,7 +32,7 @@ class MembersService {
*/
async getMemberFinances(handle) {
const res = await this.private.api.get(`/members/${handle}/financial`);
return getApiResponsePayloadV3(res);
return getApiResponsePayload(res);
}

/**
@@ -45,7 +45,7 @@ class MembersService {
*/
async getMemberInfo(handle) {
const res = await this.private.api.get(`/members/${handle}`);
return getApiResponsePayloadV3(res);
return getApiResponsePayload(res);
}

/**
@@ -55,7 +55,7 @@ class MembersService {
*/
async getExternalAccounts(handle) {
const res = await this.private.api.get(`/members/${handle}/externalAccounts`);
return getApiResponsePayloadV3(res);
return getApiResponsePayload(res);
}

/**
@@ -65,7 +65,7 @@ class MembersService {
*/
async getExternalLinks(handle) {
const res = await this.private.api.get(`/members/${handle}/externalLinks`);
return getApiResponsePayloadV3(res);
return getApiResponsePayload(res);
}

/**
@@ -75,7 +75,7 @@ class MembersService {
*/
async getSkills(handle) {
const res = await this.private.api.get(`/members/${handle}/skills`);
return getApiResponsePayloadV3(res);
return getApiResponsePayload(res);
}

/**
@@ -85,7 +85,7 @@ class MembersService {
*/
async getStats(handle) {
const res = await this.private.api.get(`/members/${handle}/stats`);
return getApiResponsePayloadV3(res);
return getApiResponsePayload(res);
}

/**
@@ -95,7 +95,7 @@ class MembersService {
*/
async getStatsHistory(handle) {
const res = await this.private.api.get(`/members/${handle}/stats/history`);
return getApiResponsePayloadV3(res);
return getApiResponsePayload(res);
}

/**
@@ -110,7 +110,7 @@ class MembersService {
track,
subTrack,
}))}`);
return getApiResponsePayloadV3(res);
return getApiResponsePayload(res);
}

/**
@@ -123,7 +123,7 @@ class MembersService {
*/
async getMemberSuggestions(keyword) {
const res = await this.private.api.get(`/members/_suggest/${keyword}`);
return getApiResponsePayloadV3(res);
return getApiResponsePayload(res);
}

/**
@@ -134,7 +134,7 @@ class MembersService {
*/
async addWebLink(userHandle, webLink) {
const res = await this.private.api.postJson(`/members/${userHandle}/externalLinks`, { param: { url: webLink } });
return getApiResponsePayloadV3(res);
return getApiResponsePayload(res);
}

/**
@@ -150,7 +150,7 @@ class MembersService {
},
};
const res = await this.private.api.delete(`/members/${userHandle}/externalLinks/${webLinkHandle}`, JSON.stringify(body));
return getApiResponsePayloadV3(res);
return getApiResponsePayload(res);
}

/**
@@ -170,7 +170,7 @@ class MembersService {
},
};
const res = await this.private.api.patchJson(`/members/${handle}/skills`, body);
return getApiResponsePayloadV3(res);
return getApiResponsePayload(res);
}

/**
@@ -193,7 +193,7 @@ class MembersService {
body: JSON.stringify(body),
method: 'PATCH',
});
return getApiResponsePayloadV3(res);
return getApiResponsePayload(res);
}

/**
@@ -202,8 +202,9 @@ class MembersService {
* @return {Promise} Resolves to the api response content
*/
async updateMemberProfile(profile) {
const res = await this.private.api.putJson(`/members/${profile.handle}`, { param: profile });
return getApiResponsePayloadV3(res);
const url = profile.verifyUrl ? `/members/${profile.handle}?verifyUrl=${profile.verifyUrl}` : `/members/${profile.handle}`;
const res = await this.private.api.putJson(url, { param: profile.verifyUrl ? _.omit(profile, ['verifyUrl']) : profile });
return getApiResponsePayload(res);
}

/**
@@ -214,7 +215,7 @@ class MembersService {
*/
async getPresignedUrl(userHandle, file) {
const res = await this.private.api.postJson(`/members/${userHandle}/photoUploadUrl`, { param: { contentType: file.type } });
const payload = await getApiResponsePayloadV3(res);
const payload = await getApiResponsePayload(res);

return {
preSignedURL: payload.preSignedURL,
@@ -231,7 +232,7 @@ class MembersService {
*/
async updateMemberPhoto(S3Response) {
const res = await this.private.api.putJson(`/members/${S3Response.userHandle}/photo`, { param: S3Response.body });
return getApiResponsePayloadV3(res);
return getApiResponsePayload(res);
}

/**
@@ -274,6 +275,17 @@ class MembersService {
xhr.send(presignedUrlResponse.file);
});
}

/**
* Verify member new email
* @param {String} handle handle Topcoder user handle
* @param {String} emailVerifyToken The verify token of new email
* @returns {Promise} Resolves to the api response content
*/
async verifyMemberNewEmail(handle, emailVerifyToken) {
const res = await this.private.api.get(`/members/${handle}/verify?token=${emailVerifyToken}`);
return getApiResponsePayload(res);
}
}

let lastInstance = null;
4 changes: 2 additions & 2 deletions src/services/reviewOpportunities.js
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@
* @desc This module provides a service for retrieving Review Opportunities and
* submitting applications.
*/
import { getApiV3 } from './api';
import { getApi } from './api';

/**
* Service class.
@@ -14,7 +14,7 @@ class ReviewOpportunitiesService {
*/
constructor(tokenV3) {
this.private = {
api: getApiV3(tokenV3),
api: getApi('V3', tokenV3),
tokenV3,
};
}
4 changes: 2 additions & 2 deletions src/services/terms.js
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@ import _ from 'lodash';
import { config } from 'topcoder-react-utils';

import { getService as getCommunityService } from './communities';
import { getApiV2 } from './api';
import { getApi } from './api';

/**
* Service class.
@@ -19,7 +19,7 @@ class TermsService {
*/
constructor(tokenV2) {
this.private = {
api: getApiV2(tokenV2),
api: getApi('V2', tokenV2),
tokenV2,
};
}
14 changes: 7 additions & 7 deletions src/services/user-traits.js
Original file line number Diff line number Diff line change
@@ -4,8 +4,8 @@
* via API V3.
*/
import toCapitalCase from 'to-capital-case';
import { getApiResponsePayloadV3 } from '../utils/tc';
import { getApiV3 } from './api';
import { getApiResponsePayload } from '../utils/tc';
import { getApi } from './api';

/**
* Service class.
@@ -16,7 +16,7 @@ class UserTraitsService {
*/
constructor(tokenV3) {
this.private = {
api: getApiV3(tokenV3),
api: getApi('V3', tokenV3),
tokenV3,
};
}
@@ -29,7 +29,7 @@ class UserTraitsService {
async getAllUserTraits(handle) {
// FIXME: Remove the .toLowerCase() when the API is fixed to ignore the case in the route params
const res = await this.private.api.get(`/members/${handle.toLowerCase()}/traits`);
return getApiResponsePayloadV3(res);
return getApiResponsePayload(res);
}

/**
@@ -51,7 +51,7 @@ class UserTraitsService {
};

const res = await this.private.api.postJson(`/members/${handle}/traits`, body);
return getApiResponsePayloadV3(res);
return getApiResponsePayload(res);
}

/**
@@ -73,7 +73,7 @@ class UserTraitsService {
};

const res = await this.private.api.putJson(`/members/${handle}/traits`, body);
return getApiResponsePayloadV3(res);
return getApiResponsePayload(res);
}

/**
@@ -84,7 +84,7 @@ class UserTraitsService {
*/
async deleteUserTrait(handle, traitId) {
const res = await this.private.api.delete(`/members/${handle}/traits?traitIds=${traitId}`);
return getApiResponsePayloadV3(res);
return getApiResponsePayload(res);
}
}

24 changes: 12 additions & 12 deletions src/services/user.js
Original file line number Diff line number Diff line change
@@ -6,8 +6,8 @@
import { config, isomorphy } from 'topcoder-react-utils';

import logger from '../utils/logger';
import { getApiResponsePayloadV3 } from '../utils/tc';
import { getApiV2, getApiV3 } from './api';
import { getApiResponsePayload } from '../utils/tc';
import { getApi } from './api';

let auth0;

@@ -112,8 +112,8 @@ class User {
*/
constructor(tokenV3, tokenV2) {
this.private = {
api: getApiV3(tokenV3),
apiV2: getApiV2(tokenV2),
api: getApi('V3', tokenV3),
apiV2: getApi('V2', tokenV2),
tokenV2,
tokenV3,
};
@@ -152,7 +152,7 @@ class User {
async getUser(username) {
const url = `/users?filter=handle%3D${username}`;
const res = await this.private.api.get(url);
return (await getApiResponsePayloadV3(res))[0];
return (await getApiResponsePayload(res))[0];
}

/**
@@ -166,7 +166,7 @@ class User {
async getEmailPreferences(userId) {
const url = `/users/${userId}/preferences/email`;
const res = await this.private.api.get(url);
return getApiResponsePayloadV3(res);
return getApiResponsePayload(res);
}

/**
@@ -193,7 +193,7 @@ class User {
const url = `/users/${userId}/preferences/email`;

const res = await this.private.api.putJson(url, { param: settings });
return getApiResponsePayloadV3(res);
return getApiResponsePayload(res);
}

/**
@@ -207,7 +207,7 @@ class User {
async getCredential(userId) {
const url = `/users/${userId}?fields=credential`;
const res = await this.private.api.get(url);
return getApiResponsePayloadV3(res);
return getApiResponsePayload(res);
}

/**
@@ -228,7 +228,7 @@ class User {

const url = `/users/${userId}`;
const res = await this.private.api.patchJson(url, { param: { credential } });
return getApiResponsePayloadV3(res);
return getApiResponsePayload(res);
}

/**
@@ -242,7 +242,7 @@ class User {
async getLinkedAccounts(userId) {
const url = `/users/${userId}?fields=profiles`;
const res = await this.private.api.get(url);
return getApiResponsePayloadV3(res);
return getApiResponsePayload(res);
}

/**
@@ -254,7 +254,7 @@ class User {
async unlinkExternalAccount(userId, provider) {
const url = `/users/${userId}/profiles/${provider}`;
const res = await this.private.api.delete(url);
return getApiResponsePayloadV3(res);
return getApiResponsePayload(res);
}

/**
@@ -299,7 +299,7 @@ class User {
}
logger.debug(`link API postdata: ${JSON.stringify(postData)}`);
this.private.api.postJson(`/users/${userId}/profiles`, { param: postData })
.then(resp => getApiResponsePayloadV3(resp).then((result) => {
.then(resp => getApiResponsePayload(resp).then((result) => {
logger.debug(`Succesfully linked account: ${JSON.stringify(result)}`);
resolve(postData);
}))
8 changes: 4 additions & 4 deletions src/utils/tc.js
Original file line number Diff line number Diff line change
@@ -26,12 +26,12 @@ export const REVIEW_OPPORTUNITY_TYPES = {
};

/**
* Gets payload from a standard success response from TC API v3; or throws
* Gets payload from a standard success response from TC API; or throws
* an error in case of a failure response.
* @param {Object} res
* @return {Promise} Resolves to the payload.
*/
export async function getApiResponsePayloadV3(res) {
export async function getApiResponsePayload(res) {
if (!res.ok) throw new Error(res.statusText);
const x = (await res.json()).result;
if (!x.success) throw new Error(x.content);
@@ -40,12 +40,12 @@ export async function getApiResponsePayloadV3(res) {


/**
* Gets payload from a standard success response from TC API v4; or throws
* Gets payload from a standard success response from TC LOOKER API; or throws
* an error in case of a failure response.
* @param {Object} res
* @return {Promise} Resolves to the payload.
*/
export async function getApiResponsePayloadV4(res) {
export async function getLookerApiResponsePayload(res) {
const resJson = await res.json();
if (Array.isArray(resJson)) {
return {