Skip to content

Commit e7cfd03

Browse files
Merge pull request #5667 from topcoder-platform/general-referrals
General referrals
2 parents 950950e + e658110 commit e7cfd03

File tree

23 files changed

+774
-171
lines changed

23 files changed

+774
-171
lines changed

Dockerfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ ARG GSHEETS_API_KEY
7373
ARG SENDGRID_API_KEY
7474
ARG GROWSURF_API_KEY
7575
ARG GROWSURF_CAMPAIGN_ID
76+
ARG GOOGLE_SERVICE_ACCOUNT_PRIVATE_KEY
7677

7778
# Optimizely
7879
ARG OPTIMIZELY_SDK_KEY
@@ -137,6 +138,7 @@ ENV SENDGRID_API_KEY=$SENDGRID_API_KEY
137138
ENV GROWSURF_API_KEY=$GROWSURF_API_KEY
138139
ENV GROWSURF_CAMPAIGN_ID=$GROWSURF_CAMPAIGN_ID
139140
ENV GSHEETS_API_KEY=$GSHEETS_API_KEY
141+
ENV GOOGLE_SERVICE_ACCOUNT_PRIVATE_KEY=$GOOGLE_SERVICE_ACCOUNT_PRIVATE_KEY
140142

141143
# Optimizely
142144
ENV OPTIMIZELY_SDK_KEY=$OPTIMIZELY_SDK_KEY

build.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ docker build -t $TAG \
5252
--build-arg GSHEETS_API_KEY=$GSHEETS_API_KEY \
5353
--build-arg OPTIMIZELY_SDK_KEY=$OPTIMIZELY_SDK_KEY \
5454
--build-arg COMMUNITY_APP_URL=$COMMUNITY_APP_URL \
55+
--build-arg GOOGLE_SERVICE_ACCOUNT_PRIVATE_KEY=$GOOGLE_SERVICE_ACCOUNT_PRIVATE_KEY \
5556
--build-arg VALID_ISSUERS=$VALID_ISSUERS .
5657

5758
# Copies "node_modules" from the created image, if necessary for caching.

config/custom-environment-variables.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,4 +113,5 @@ module.exports = {
113113
OPTIMIZELY: {
114114
SDK_KEY: 'OPTIMIZELY_SDK_KEY',
115115
},
116+
GOOGLE_SERVICE_ACCOUNT_PRIVATE_KEY: 'GOOGLE_SERVICE_ACCOUNT_PRIVATE_KEY',
116117
};

config/default.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,10 +263,13 @@ module.exports = {
263263
GROWSURF_COOKIE_SETTINGS: {
264264
secure: true,
265265
domain: '',
266-
expires: 7, // days
266+
expires: 30, // days
267267
},
268268

269269
GSHEETS_API_KEY: 'AIzaSyBRdKySN5JNCb2H6ZxJdTTvp3cWU51jiOQ',
270+
GOOGLE_SERVICE_ACCOUNT_EMAIL: 'communityappserviceacc@tc-sheets-to-contentful.iam.gserviceaccount.com',
271+
GOOGLE_SERVICE_ACCOUNT_PRIVATE_KEY: '',
272+
GIG_REFERRALS_SHEET: '1xilx7NxDAvzAzOTbPpvb3lL3RWv1VD5W24OEMAoF9HU',
270273

271274
AUTH_CONFIG: {
272275
AUTH0_URL: 'TC_M2M_AUTH0_URL',

src/assets/images/icon-facebook.svg

Lines changed: 1 addition & 2 deletions
Loading

src/assets/images/icon-linkedIn.svg

Lines changed: 1 addition & 2 deletions
Loading

src/assets/images/icon-twitter.svg

Lines changed: 1 addition & 2 deletions
Loading

src/server/routes/gSheet.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/* eslint-disable max-len */
12
/**
23
* The routes related to GSheets integration
34
*/
@@ -14,6 +15,7 @@ const routes = express.Router();
1415
routes.use(cors());
1516
routes.options('*', cors());
1617

17-
routes.get('/:id', (req, res) => new GSheetService().getSheet(req, res));
18+
routes.get('/:id', (req, res) => new GSheetService().getSheetAPI(req, res));
19+
// routes.post('/:id', (req, res) => new GSheetService().addToSheetAPI(req, res)); // Enable it for API access to gsheets editing when needed
1820

1921
export default routes;

src/server/services/gSheet.js

Lines changed: 85 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,18 @@ const getCircularReplacer = () => {
2525
* APIs in the same uniform manner.
2626
*/
2727
export default class GSheetService {
28+
constructor() {
29+
this.getSheetAPI = this.getSheetAPI.bind(this);
30+
this.addToSheetAPI = this.getSheetAPI.bind(this);
31+
this.addToSheet = this.getSheetAPI.bind(this);
32+
}
33+
2834
/**
2935
* getSheet
3036
* @param {Object} req the request
3137
* @param {Object} res the response
3238
*/
33-
async getSheet(req, res) {
39+
async getSheetAPI(req, res) {
3440
const { index } = req.query;
3541
const { id } = req.params;
3642
const doc = new GoogleSpreadsheet(id);
@@ -45,8 +51,85 @@ export default class GSheetService {
4551
rows: JSON.parse(rowsJson),
4652
});
4753
} catch (e) {
48-
res.status((e.response && e.response.status) || 500);
54+
const status = (e.response && e.response.status) || 500;
55+
if (status === 429) {
56+
// rate limit issue - wait 15sec and retry
57+
await new Promise(resolve => setTimeout(resolve, 15000));
58+
return this.getSheetAPI(req, res);
59+
}
60+
res.status(status);
4961
return res.send((e.response && e.response.data) || { ...e, message: e.message });
5062
}
5163
}
64+
65+
/**
66+
* Adds rows to gsheet by ID
67+
* Needs to be shared with the service account to work
68+
* This is the controler method with req/res objects
69+
* @param {Object} req the request
70+
* @param {Object} res the response
71+
*/
72+
async addToSheetAPI(req, res) {
73+
const { index } = req.query;
74+
const { id } = req.params;
75+
const doc = new GoogleSpreadsheet(id);
76+
try {
77+
// set credentials for working
78+
await doc.useServiceAccountAuth({
79+
client_email: config.GOOGLE_SERVICE_ACCOUNT_EMAIL,
80+
private_key: config.GOOGLE_SERVICE_ACCOUNT_PRIVATE_KEY.replace(/\\m/g, '\n'),
81+
});
82+
// load doc infos
83+
await doc.loadInfo();
84+
// get 1st sheet
85+
const sheet = doc.sheetsByIndex[index || 0];
86+
const moreRows = await sheet.addRows(req.body);
87+
const rowsJson = JSON.stringify(moreRows, getCircularReplacer());
88+
return res.send({
89+
rows: JSON.parse(rowsJson),
90+
});
91+
} catch (e) {
92+
const status = (e.response && e.response.status) || 500;
93+
if (status === 429) {
94+
// rate limit issue - wait 15sec and retry
95+
await new Promise(resolve => setTimeout(resolve, 15000));
96+
return this.addToSheetAPI(req, res);
97+
}
98+
res.status(status);
99+
return res.send((e.response && e.response.data) || { ...e, message: e.message });
100+
}
101+
}
102+
103+
/**
104+
* Adds rows to gsheet by ID
105+
* Needs to be shared with the service account to work
106+
* @param {string} id the doc id
107+
* @param {Array} paylod the body to send
108+
* @param {string} index sheet index in the doc. Defaults to 0
109+
*/
110+
async addToSheet(id, payload, index = 0) {
111+
const doc = new GoogleSpreadsheet(id);
112+
try {
113+
// set credentials for working
114+
await doc.useServiceAccountAuth({
115+
client_email: config.GOOGLE_SERVICE_ACCOUNT_EMAIL,
116+
private_key: config.GOOGLE_SERVICE_ACCOUNT_PRIVATE_KEY.replace(/\\m/g, '\n'),
117+
});
118+
// load doc infos
119+
await doc.loadInfo();
120+
// get 1st sheet
121+
const sheet = doc.sheetsByIndex[index || 0];
122+
const moreRows = await sheet.addRows(payload);
123+
const rowsJson = JSON.stringify(moreRows, getCircularReplacer());
124+
return rowsJson;
125+
} catch (e) {
126+
const status = (e.response && e.response.status) || 500;
127+
if (status === 429) {
128+
// rate limit issue - wait 15sec and retry
129+
await new Promise(resolve => setTimeout(resolve, 15000));
130+
return this.addToSheet(id, payload, index);
131+
}
132+
return e;
133+
}
134+
}
52135
}

src/server/services/growsurf.js

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,30 @@ export default class GrowsurfService {
2020
};
2121
}
2222

23+
/**
24+
* Gets get participant.
25+
* @return {Promise}
26+
* @param {String} idOrEmail growsurf id or email
27+
*/
28+
async getParticipantByIdOREmail(idOrEmail) {
29+
const response = await fetch(`${this.private.baseUrl}/campaign/${config.GROWSURF_CAMPAIGN_ID}/participant/${idOrEmail}`, {
30+
method: 'GET',
31+
headers: {
32+
'Content-Type': 'application/json',
33+
Authorization: this.private.authorization,
34+
},
35+
});
36+
if (response.status >= 300) {
37+
return {
38+
error: await response.json(),
39+
code: response.status,
40+
url: `${this.private.baseUrl}/campaign/${config.GROWSURF_CAMPAIGN_ID}/participant/${idOrEmail}`,
41+
};
42+
}
43+
const data = await response.json();
44+
return data;
45+
}
46+
2347
/**
2448
* Gets get participant by email or id.
2549
* @return {Promise}
@@ -67,7 +91,6 @@ export default class GrowsurfService {
6791
code: response.status,
6892
url: `${this.private.baseUrl}/campaign/${config.GROWSURF_CAMPAIGN_ID}/participant`,
6993
body,
70-
private: this.private, // to remove in final release
7194
};
7295
}
7396
const data = await response.json();
@@ -96,4 +119,31 @@ export default class GrowsurfService {
96119
}
97120
return result;
98121
}
122+
123+
/**
124+
* Update participant in growSurf
125+
* @param {string} idOrEmail id or email
126+
* @param {string} body payload
127+
* @returns {Promise}
128+
*/
129+
async updateParticipant(idOrEmail, body) {
130+
const response = await fetch(`${this.private.baseUrl}/campaign/${config.GROWSURF_CAMPAIGN_ID}/participant/${idOrEmail}`, {
131+
method: 'POST',
132+
headers: {
133+
'Content-Type': 'application/json',
134+
Authorization: this.private.authorization,
135+
},
136+
body,
137+
});
138+
if (response.status >= 300) {
139+
return {
140+
error: await response.json(),
141+
code: response.status,
142+
url: `${this.private.baseUrl}/campaign/${config.GROWSURF_CAMPAIGN_ID}/participant/${idOrEmail}`,
143+
body,
144+
};
145+
}
146+
const data = await response.json();
147+
return data;
148+
}
99149
}

0 commit comments

Comments
 (0)