-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathapp.js
396 lines (342 loc) · 11.9 KB
/
app.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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
/*
* Copyright 2016-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the license found in the
* LICENSE file in the root directory of this source tree.
*
*/
/* jshint node: true, devel: true */
'use strict';
const
bodyParser = require('body-parser'),
config = require('config'),
crypto = require('crypto'),
express = require('express'),
https = require('https'),
request = require('request');
var app = express();
var msgs = ['大聲講話啊', '一起踹共啊', '快點打字啊'];
app.set('port', process.env.PORT || 5000);
app.use(bodyParser.json({ verify: verifyRequestSignature }));
app.use(express.static('public'));
/*
* Be sure to setup your config values before running this code. You can
* set them using environment variables or modifying the config file in /config.
*
*/
// App Secret can be retrieved from the App Dashboard
const APP_SECRET = (process.env.MESSENGER_APP_SECRET) ?
process.env.MESSENGER_APP_SECRET :
config.get('appSecret');
// Arbitrary value used to validate a webhook
const VALIDATION_TOKEN = (process.env.MESSENGER_VALIDATION_TOKEN) ?
(process.env.MESSENGER_VALIDATION_TOKEN) :
config.get('validationToken');
// Generate a page access token for your page from the App Dashboard
const PAGE_ACCESS_TOKEN = (process.env.MESSENGER_PAGE_ACCESS_TOKEN) ?
(process.env.MESSENGER_PAGE_ACCESS_TOKEN) :
config.get('pageAccessToken');
if (!(APP_SECRET && VALIDATION_TOKEN && PAGE_ACCESS_TOKEN)) {
console.error("Missing config values");
process.exit(1);
}
/*
* Use your own validation token. Check that the token used in the Webhook
* setup is the same token used here.
*
*/
app.get('/webhook', function(req, res) {
if (req.query['hub.mode'] === 'subscribe' &&
req.query['hub.verify_token'] === VALIDATION_TOKEN) {
console.log("Validating webhook");
res.status(200).send(req.query['hub.challenge']);
} else {
console.error("Failed validation. Make sure the validation tokens match.");
res.sendStatus(403);
}
});
/*
* All callbacks for Messenger are POST-ed. They will be sent to the same
* webhook. Be sure to subscribe your app to your page to receive callbacks
* for your page.
* https://developers.facebook.com/docs/messenger-platform/implementation#subscribe_app_pages
*
*/
app.post('/webhook', function (req, res) {
var data = req.body;
// Make sure this is a page subscription
if (data.object == 'page') {
// Iterate over each entry
// There may be multiple if batched
data.entry.forEach(function(pageEntry) {
var pageID = pageEntry.id;
var timeOfEvent = pageEntry.time;
// Iterate over each messaging event
pageEntry.messaging.forEach(function(messagingEvent) {
if (messagingEvent.optin) {
receivedAuthentication(messagingEvent);
} else if (messagingEvent.message) {
receivedMessage(messagingEvent);
} else if (messagingEvent.delivery) {
receivedDeliveryConfirmation(messagingEvent);
} else if (messagingEvent.postback) {
receivedPostback(messagingEvent);
} else {
console.log("Webhook received unknown messagingEvent: ", messagingEvent);
}
});
});
// Assume all went well.
//
// You must send back a 200, within 20 seconds, to let us know you've
// successfully received the callback. Otherwise, the request will time out.
res.sendStatus(200);
}
});
/*
* Verify that the callback came from Facebook. Using the App Secret from
* the App Dashboard, we can verify the signature that is sent with each
* callback in the x-hub-signature field, located in the header.
*
* https://developers.facebook.com/docs/graph-api/webhooks#setup
*
*/
function verifyRequestSignature(req, res, buf) {
var signature = req.headers["x-hub-signature"];
if (!signature) {
// For testing, let's log an error. In production, you should throw an
// error.
console.error("Couldn't validate the signature.");
} else {
var elements = signature.split('=');
var method = elements[0];
var signatureHash = elements[1];
var expectedHash = crypto.createHmac('sha1', APP_SECRET)
.update(buf)
.digest('hex');
if (signatureHash != expectedHash) {
throw new Error("Couldn't validate the request signature.");
}
}
}
/*
* Authorization Event
*
* The value for 'optin.ref' is defined in the entry point. For the "Send to
* Messenger" plugin, it is the 'data-ref' field. Read more at
* https://developers.facebook.com/docs/messenger-platform/webhook-reference#auth
*
*/
function receivedAuthentication(event) {
var senderID = event.sender.id;
var recipientID = event.recipient.id;
var timeOfAuth = event.timestamp;
// The 'ref' field is set in the 'Send to Messenger' plugin, in the 'data-ref'
// The developer can set this to an arbitrary value to associate the
// authentication callback with the 'Send to Messenger' click event. This is
// a way to do account linking when the user clicks the 'Send to Messenger'
// plugin.
var passThroughParam = event.optin.ref;
console.log("Received authentication for user %d and page %d with pass " +
"through param '%s' at %d", senderID, recipientID, passThroughParam,
timeOfAuth);
// When an authentication is received, we'll send a message back to the sender
// to let them know it was successful.
sendTextMessage(senderID, "Authentication successful");
}
/*
* Message Event
*
* This event is called when a message is sent to your page. The 'message'
* object format can vary depending on the kind of message that was received.
* Read more at https://developers.facebook.com/docs/messenger-platform/webhook-reference#received_message
*
* For this example, we're going to echo any text that we get. If we get some
* special keywords ('button', 'generic', 'receipt'), then we'll send back
* examples of those bubbles to illustrate the special message bubbles we've
* created. If we receive a message with an attachment (image, video, audio),
* then we'll simply confirm that we've received the attachment.
*
*/
function receivedMessage(event) {
var senderID = event.sender.id;
var sender = event.sender;
var recipientID = event.recipient.id;
var timeOfMessage = event.timestamp;
var message = event.message;
var messageText = message.text;
var messageAttachments = message.attachments;
if (messageText) {
gulis(senderID, messageText, 'text');
} else if (messageAttachments) {
gulis(senderID, messageAttachments, 'attachments');
} else {
// TODO
}
}
/*
* Delivery Confirmation Event
*
* This event is sent to confirm the delivery of a message. Read more about
* these fields at https://developers.facebook.com/docs/messenger-platform/webhook-reference#message_delivery
*
*/
function receivedDeliveryConfirmation(event) {
var senderID = event.sender.id;
var recipientID = event.recipient.id;
var delivery = event.delivery;
var messageIDs = delivery.mids;
var watermark = delivery.watermark;
var sequenceNumber = delivery.seq;
if (messageIDs) {
messageIDs.forEach(function(messageID) {
console.log("Received delivery confirmation for message ID: %s",
messageID);
});
}
console.log("All message before %d were delivered.", watermark);
}
/*
* Postback Event
*
* This event is called when a postback is tapped on a Structured Message. Read
* more at https://developers.facebook.com/docs/messenger-platform/webhook-reference#postback
*
*/
function receivedPostback(event) {
var senderID = event.sender.id;
var recipientID = event.recipient.id;
var timeOfPostback = event.timestamp;
// The 'payload' param is a developer-defined field which is set in a postback
// button for Structured Messages.
var payload = event.postback.payload;
console.log("Received postback for user %d and page %d with payload '%s' " +
"at %d", senderID, recipientID, payload, timeOfPostback);
// When a postback is called, we'll send a message back to the sender to
// let them know it was successful
var msg = msgs[Math.floor(Math.random() * msgs.length)];
sendTextMessage(senderID, '已加入 ' + payload + ',' + msg);
}
/*
* Send a text message using the Send API.
*
*/
function sendTextMessage(recipientId, messageText) {
var messageData = {
recipient: {
id: recipientId
},
message: {
text: messageText
}
};
callSendAPI(messageData);
}
/*
* Call the Send API. The message data goes in the body. If successful, we'll
* get the message id in a response
*
*/
function callSendAPI(messageData) {
request({
uri: 'https://graph.facebook.com/v2.6/me/messages',
qs: { access_token: PAGE_ACCESS_TOKEN },
method: 'POST',
json: messageData
}, function (error, response, body) {
if (!error && response.statusCode == 200) {
var recipientId = body.recipient_id;
var messageId = body.message_id;
console.log("Successfully sent generic message with id %s to recipient %s",
messageId, recipientId);
} else {
console.error("Unable to send message.");
// console.error(response);
// console.error(error);
}
});
}
var carousel = [
{
title: "統一獅",
subtitle: "中韓職棒熱身賽-警察廳vs統一獅",
image_url: "https://i.ytimg.com/vi/pkC6NAvJlCE/hqdefault.jpg",
buttons: [{
type: "postback",
title: "參上",
payload: "#統一獅",
}]
},
{
title: "佼心食堂",
subtitle: "梁家輝、彭于晏",
image_url: "https://s.yimg.com/uu/api/res/1.2/VWWR2E0ETGDrq8zIFfo3gw--/Zmk9ZmlsbDtweW9mZj0wO3c9MjM0O2g9MTU0O3NtPTE7YXBwaWQ9eXRhY2h5b24-/http://media.zenfs.com/en-US/video/video.pd2upload.com/video.yahootwlive.com@0940b788-2c38-3579-9b7d-2f8aca2652c5_FULL.jpg",
buttons: [{
type: "postback",
title: "參上",
payload: "#佼心食堂"
}]
},
{
title: "唐立淇測風向",
subtitle: "勞工問題效應,還會持續至何時?",
image_url: "https://s.yimg.com/uu/api/res/1.2/fuJ1wSLEroKuuFzAm1LyQQ--/Zmk9ZmlsbDtweW9mZj0wO3c9MTQ2O2g9ODI7c209MTthcHBpZD15dGFjaHlvbg--/https://media.zenfs.com/creatr-images/GLB/2016-06-27/444747c0-3c93-11e6-a7e7-ed25d9b81d27_snaps-5-about-on-yahoo-legacy_it.jpg",
buttons: [{
type: "postback",
title: "參上",
payload: "#唐立淇測風向"
}]
},
{
title: "影音名人堂",
subtitle: "【雞排炸新聞】相親後被要求卸妝給對方看",
image_url: "https://s.yimg.com/uu/api/res/1.2/MP8vyb9sINNRuYQNmdy6nA--/Zmk9ZmlsbDtweW9mZj0wO3c9MTQ2O2g9ODI7c209MTthcHBpZD15dGFjaHlvbg--/http://media.zenfs.com/en-US/video/video.pd2upload.com/video.yahooscreen.com@2112bd55-c1ae-35b8-bfaa-816a6381f917_FULL.png",
buttons: [{
type: "postback",
title: "參上",
payload: "#影音名人堂"
}]
}
];
function gulis(recipientId, message, messageType) {
var uri = 'http://hack.wjhuang.net:3000/bot/index';
var messageData;
if (messageType == 'text' && message.indexOf('踹共') === 0) {
messageData = {
recipient :{
id: recipientId
},
message: {
attachment: {
type: "template",
payload: {
template_type: "generic",
elements: carousel
}
}
}
};
callSendAPI(messageData);
}
else {
request.post(uri, {
form: {
userid: recipientId,
message: message || '',
platform: 'facebook',
type: messageType,
user: true
}
}, function (error, response, body) {
// do nothing
});
};
}
// Start server
// Webhooks must be available via SSL with a certificate signed by a valid
// certificate authority.
app.listen(app.get('port'), function() {
console.log('Node app is running on port', app.get('port'));
});
module.exports = app;