-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
138 lines (117 loc) · 4.52 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
const request = require('request-promise-native');
/**
* This is an example cloud function
* You can modify this funciton and use it with Google Cloud Functions
* to catch and process Raisely Webhooks
*
* When configuing the cloud function you will need to set the two environment
* variables below (WEBHOOK_SECRET and API_KEY) (DO NOT save such values to git
* or other source control)
*
*/
// Insert here a shared secret to use when configuring your webhook with raisely
// Set the same value when setting up the webhook in
// Raisely Admin -> Campaign -> Settings -> API & Webhooks
const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET;
// Secret key to access the campaign, can be found in
// Raisely Admin -> Campaign -> Settings -> API & Webhooks
const API_KEY = process.env.RAISELY_API_KEY;
/**
* Example Cloud Function that catches webhooks from Raisely
*
* @param {!Object} req Cloud Function request context.
* @param {!Object} res Cloud Function response context.
*/
exports.integration = async function integration(req, res) {
// Verify that the webhook is actually from raisely using the shared secret
if (!authenticate(req, res)) return true;
const event = req.body.data;
// Event sources are of the form 'campaign:uuid' or 'organisation:uuid'
const campaignUuid = event.source.split(':')[1];
let response;
// Detect event type and get data off the payload, delete as necessary
if (event.type === 'donation.succeeded') {
const donation = event.data;
const { user, profile } = donation;
// Log that the donation took place
console.log(`Processing ${event.type} for ${donation.uuid}, campaign: ${campaignUuid}, made to profile: ${profile.name} by ${user.fullName}`);
// Save a private custom field `isProcessed` and set it to true
response = await raiselyRequest({
path: `/donations/${donation.uuid}`,
method: 'PATCH',
json: {
data: { private: { isProcessed: true } },
partial: 1,
},
});
} else if (event.type === 'subscription.succeeded') {
const subscription = event.data;
const { user, profile } = subscription;
} else if (event.type === 'profile.created') {
const subscription = event.data;
const { user, profile } = subscription;
} else if (event.type === 'user.registered') {
const user = event.data;
} else if (event.type === 'profile.totalUpdated') {
const profile = event.data;
const { campaign, user } = profile;
// Do something if this is the update that hit the goal
if ((profile.lastTotalPercent < 100) && (profile.totalPercent >= 100)) {
request({
method: 'POST',
url: 'https://celebrate.example/fundraising',
json: {
name: user.fullName,
email: user.email,
message: `Congratulations on reaching your fundraising goal for ${campaign.name}!`,
},
});
}
} else if (event.type === 'profile.exerciseTotalUpdated') {
const profile = event.data;
const { user } = profile;
// Do something if they crossed 10km
if ((profile.lastExerciseTotal < 10000) && (profile.exerciseTotal >= 10000)) {
console.log(`${user.preferredName} ran 10km !`);
}
// Do something if they crossed 10 hours of exercise
if ((profile.lastExerciseTotal < 600) && (profile.exerciseTotal >= 600)) {
console.log(`${user.preferredName} exercised for 10 hours!`);
}
} else {
res.status(200).send({ success: false, error: `Unrecognised event ${event.type}` });
return true;
}
res.status(200).send({ success: true, response });
return true;
};
/**
* Verify that the webhook came from raisely by checking the shared secret
* If authentication fails, will set a 200 response
* (to prevent Raisely from continuing to retry the webhook with a bad secret)
* @param {*} req
* @param {*} res
* @returns {boolean} true if the request is authenticated
*/
function authenticate(req, res) {
const secret = req.body.secret;
if (secret && secret === WEBHOOK_SECRET) return true;
res.status(200).send({ success: false, error: 'invalid shared secret' });
return false;
}
/**
* Wrapper around request-promise-native to send a request to Raisely
* Uses the API key for the authorization header and generates a full Raisely API url
* to the v3 API
*
* @params {string} opts.path Relative path of request (eg '/donations')
* @params {!Object} opts As documented at https://www.npmjs.com/package/request
*/
async function raiselyRequest(opts) {
const options = { ...opts };
options.url = `https://api.raisely.com/v3${opts.path}`
delete options.path;
if (!options.headers) options.headers = {};
options.headers['Authorization'] = `Bearer ${API_KEY}`;
return request(options);
}