Skip to content

Commit dfd7c74

Browse files
committed
add looker service, action and reducer
1 parent 4dc80a9 commit dfd7c74

File tree

8 files changed

+7323
-6207
lines changed

8 files changed

+7323
-6207
lines changed

package-lock.json

+7,138-6,207
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/actions/index.js

+2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import memberTaskActions from './member-tasks';
1212
import reviewOpportunityActions from './reviewOpportunity';
1313
import lookupActions from './lookup';
1414
import settingsActions from './settings';
15+
import lookerActions from './looker';
1516

1617
export const actions = {
1718
auth: authActions.auth,
@@ -28,6 +29,7 @@ export const actions = {
2829
reviewOpportunity: reviewOpportunityActions.reviewOpportunity,
2930
lookup: lookupActions.lookup,
3031
settings: settingsActions.settings,
32+
looker: lookerActions.looker,
3133
};
3234

3335
export default undefined;

src/actions/looker.js

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/**
2+
* @module "actions.looker"
3+
* @desc Actions related to looker data.
4+
*/
5+
6+
import { createActions } from 'redux-actions';
7+
import { getService } from '../services/looker';
8+
9+
/**
10+
* @static
11+
* @desc Creates an action that gets look data by id.
12+
* @return {Action}
13+
*/
14+
async function getLookerDone(lookerId) {
15+
const data = await getService().getLooker(lookerId);
16+
return { data, lookerId };
17+
}
18+
19+
export default createActions({
20+
LOOKER: {
21+
GET_LOOKER_DONE: getLookerDone,
22+
},
23+
});

src/reducers/index.js

+4
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ import mySubmissionsManagement, { factory as mySubmissionsManagementFactory }
2020
from './my-submissions-management';
2121
import settings, { factory as settingsFactory }
2222
from './settings';
23+
import looker, { factory as lookerFactory }
24+
from './looker';
2325

2426

2527
export function factory(options) {
@@ -38,6 +40,7 @@ export function factory(options) {
3840
reviewOpportunity: reviewOpportunityFactory(options),
3941
mySubmissionsManagement: mySubmissionsManagementFactory(options),
4042
settings: settingsFactory(options),
43+
looker: lookerFactory(options),
4144
});
4245
}
4346

@@ -56,4 +59,5 @@ export default ({
5659
reviewOpportunity,
5760
mySubmissionsManagement,
5861
settings,
62+
looker,
5963
});

src/reducers/looker.js

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/**
2+
* @module "reducers.looker"
3+
* @desc Reducer for {@link module:actions.looker} actions.
4+
*
5+
* State segment managed by this reducer has the following structure:
6+
* @param {Object} dataSet={}, index by lookerId.
7+
*/
8+
import _ from 'lodash';
9+
import { handleActions } from 'redux-actions';
10+
import actions from '../actions/looker';
11+
12+
/**
13+
* Handles LOOKER/GET_LOOKER_DONE action.
14+
* @param {Object} state
15+
* @param {Object} action Payload will be JSON from api call
16+
* @return {Object} New state
17+
*/
18+
function onGetLookerDone(state, { payload }) {
19+
const {
20+
data: {
21+
res,
22+
error,
23+
},
24+
lookerId,
25+
} = payload;
26+
27+
const newDataSet = {
28+
...state.dataSet,
29+
};
30+
newDataSet[lookerId] = {
31+
lookerData: res,
32+
error,
33+
msg: res.message,
34+
};
35+
return ({
36+
...state,
37+
dataSet: newDataSet,
38+
});
39+
}
40+
41+
/**
42+
* Creates a new Looker reducer with the specified initial state.
43+
* @param {Object} initialState Optional. Initial state.
44+
* @return {Function} Looker reducer.
45+
*/
46+
function create(initialState = {}) {
47+
const a = actions.looker;
48+
return handleActions({
49+
[a.getLookerDone]: onGetLookerDone,
50+
}, _.defaults(initialState, {
51+
dataSet: {},
52+
}));
53+
}
54+
55+
/**
56+
* Factory which creates a new reducer.
57+
* @return {Promise}
58+
* @resolves {Function(state, action): state} New reducer.
59+
*/
60+
export function factory() {
61+
return Promise.resolve(create());
62+
}
63+
64+
/**
65+
* @static
66+
* @member default
67+
* @desc Reducer with default initial state.
68+
*/
69+
export default create();

src/services/api.js

+15
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import { config, isomorphy } from 'topcoder-react-utils';
99
import { delay } from '../utils/time';
1010
import { setErrorIcon, ERROR_ICON_TYPES } from '../utils/errors';
1111

12+
config.API.V4 = 'https://api.topcoder.com/v4';
13+
1214
/* The minimal delay [ms] between API calls. To avoid problems with the requests
1315
* rate limits configured in Topcoder APIs, we throttle requests rate at the
1416
* client side, and at server-side, in dev mode (which is meant to be used for
@@ -265,3 +267,16 @@ export function getApiV3(token) {
265267
}
266268
return lastApiV3;
267269
}
270+
271+
let lastApiV4 = null;
272+
/**
273+
* Returns a new or existing Api object for Topcoder API V4
274+
* @param {String} token Optional. Auth token for Topcoder API V4.
275+
* @return {Api} API V4 service object.
276+
*/
277+
export function getApiV4(token) {
278+
if (!lastApiV4 || lastApiV4.private.token !== token) {
279+
lastApiV4 = new Api(config.API.V4, token);
280+
}
281+
return lastApiV4;
282+
}

src/services/looker.js

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/**
2+
* @module "services.looker"
3+
* @desc This module provides a service to get look data json
4+
* via API V4.
5+
*/
6+
import { getApiResponsePayloadV4 } from '../utils/tc';
7+
import { getApiV4 } from './api';
8+
9+
/**
10+
* Service class.
11+
*/
12+
class LookerService {
13+
/**
14+
* @param {String} tokenV4 Optional. Auth token for Topcoder API v4.
15+
*/
16+
constructor(tokenV4) {
17+
this.private = {
18+
api: getApiV4(tokenV4),
19+
tokenV4,
20+
};
21+
}
22+
23+
/**
24+
* Get json look data by id.
25+
* @param {String} lookerId Look id.
26+
* @return {Promise} Resolves to the json data.
27+
*/
28+
async getLooker(lookerId) {
29+
const res = await this.private.api.get(`/looks/${lookerId}/run/json`);
30+
return getApiResponsePayloadV4(res);
31+
}
32+
}
33+
34+
let lastInstance = null;
35+
/**
36+
* Returns a new or existing looker service.
37+
* @param {String} tokenV4 Optional. Auth token for Topcoder API v4.
38+
* @return {LookerService} looker service object
39+
*/
40+
export function getService(tokenV4) {
41+
if (!lastInstance || tokenV4 !== lastInstance.private.tokenV4) {
42+
lastInstance = new LookerService(tokenV4);
43+
}
44+
return lastInstance;
45+
}
46+
47+
/* Using default export would be confusing in this case. */
48+
export default undefined;

src/utils/tc.js

+24
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,27 @@ export async function getApiResponsePayloadV3(res) {
3737
if (!x.success) throw new Error(x.content);
3838
return x.content;
3939
}
40+
41+
42+
/**
43+
* Gets payload from a standard success response from TC API v4; or throws
44+
* an error in case of a failure response.
45+
* @param {Object} res
46+
* @return {Promise} Resolves to the payload.
47+
*/
48+
export async function getApiResponsePayloadV4(res) {
49+
const resJson = await res.json();
50+
if (Array.isArray(resJson)) {
51+
return {
52+
res: resJson,
53+
error: false,
54+
};
55+
}
56+
57+
const x = resJson.result;
58+
return {
59+
res: x.content,
60+
error: !x.success,
61+
status: x.status,
62+
};
63+
}

0 commit comments

Comments
 (0)