Repository: Yoctol/bottender
Pull request #278 (2018-06-03 06:25:21)

fix cross-platform & add example: cross-platform-with-console
- Base on cross-platform, but also support console mode.
- fix messenger verify token.

confirm the fix correct by weather-bot/weather-bot#47

codecov-io: # [Codecov](https://codecov.io/gh/Yoctol/bottender/pull/278?src=pr&el=h1) Report
> Merging [#278](https://codecov.io/gh/Yoctol/bottender/pull/278?src=pr&el=desc) into [master](https://codecov.io/gh/Yoctol/bottender/commit/1fde7822c2d8edc8f8613fa8bc4b668e61f3e767?src=pr&el=desc) will **not change** coverage.
> The diff coverage is `n/a`.

[![Impacted file tree graph](https://codecov.io/gh/Yoctol/bottender/pull/278/graphs/tree.svg?width=650&height=150&src=pr&token=JX3EGtxYH3)](https://codecov.io/gh/Yoctol/bottender/pull/278?src=pr&el=tree)

```diff
@@          Coverage Diff           @@
##           master    #278   +/-   ##
======================================
  Coverage    90.3%   90.3%           
======================================
  Files         107     107           
  Lines        3217    3217           
  Branches      766     766           
======================================
  Hits         2905    2905           
  Misses        274     274           
  Partials       38      38
```



------

[Continue to review full report at Codecov](https://codecov.io/gh/Yoctol/bottender/pull/278?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/Yoctol/bottender/pull/278?src=pr&el=footer). Last update [1fde782...b98b920](https://codecov.io/gh/Yoctol/bottender/pull/278?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

tigercosmos: @chentsulin  fixed

Patch:
diff --git a/examples/cross-platform-with-console/README.md b/examples/cross-platform-with-console/README.md
new file mode 100644
index 00000000..663a7803
--- /dev/null
+++ b/examples/cross-platform-with-console/README.md
@@ -0,0 +1,63 @@
+# Cross Platform
+
+## Install and Run
+
+Download this example or clone [bottender](https://github.com/Yoctol/bottender).
+
+```
+curl https://codeload.github.com/Yoctol/bottender/tar.gz/master | tar -xz --strip=2 bottender-master/examples/cross-platform-with-console
+cd cross-platform-with-console
+```
+
+Install dependencies:
+
+```
+npm install
+```
+
+You must put all needed information into `bottender.config.js`.
+
+After that, you can run the bot with this npm script:
+
+```
+npm run dev
+```
+
+This command will start server for bot developing at `http://localhost:5000`.
+
+Or you can run it in console mode:
+
+```
+npm run console
+```
+
+## Set webhook
+
+You must set webhooks correspond to mounted paths properly:
+
+```
+<YOUR_BASE_URL>/messenger
+<YOUR_BASE_URL>/line
+<YOUR_BASE_URL>/slack
+<YOUR_BASE_URL>/telegram
+<YOUR_BASE_URL>/viber
+```
+
+> Note: See related examples to know how to set webhook on each platform
+
+If you want to expose the server on your local development machine and get a secure URL, [ngrok](https://ngrok.com/) or [localtunnel](https://localtunnel.github.io/www/) may be good tools for you.
+
+## Idea of this example
+
+This example shows the basic idea of building a cross-platform bot. The best
+feature of this example is that you can only develop one handler for five
+different bots, instead of developing one handler for each platform.
+
+## Related examples
+
+* [console-hello-world](../console-hello-world)
+* [messenger-hello-world](../messenger-hello-world)
+* [line-hello-world](../line-hello-world)
+* [slack-hello-world](../slack-hello-world)
+* [telegram-hello-world](../telegram-hello-world)
+* [viber-hello-world](../viber-hello-world)
diff --git a/examples/cross-platform-with-console/bottender.config.js b/examples/cross-platform-with-console/bottender.config.js
new file mode 100644
index 00000000..28d5aad2
--- /dev/null
+++ b/examples/cross-platform-with-console/bottender.config.js
@@ -0,0 +1,21 @@
+module.exports = {
+  messenger: {
+    accessToken: '__FILL_YOUR_TOKEN_HERE__',
+    appSecret: '__FILL_YOUR_SECRET_HERE__',
+    verifyToken: '__FILL_YOUR_VERIFYTOKEN_HERE__',
+  },
+  line: {
+    channelSecret: '__FILL_YOUR_CHANNEL_SECRET_HERE__',
+    accessToken: '__FILL_YOUR_TOKEN_HERE__',
+  },
+  telegram: {
+    accessToken: '__FILL_YOUR_TOKEN_HERE__',
+  },
+  slack: {
+    accessToken: '__FILL_YOUR_TOKEN_HERE__',
+    verificationToken: '__FILL_YOUR_VERIFICATION_TOKEN_HERE__',
+  },
+  viber: {
+    accessToken: '__FILL_YOUR_TOKEN_HERE__',
+  },
+};
diff --git a/examples/cross-platform-with-console/handler.js b/examples/cross-platform-with-console/handler.js
new file mode 100644
index 00000000..a306309d
--- /dev/null
+++ b/examples/cross-platform-with-console/handler.js
@@ -0,0 +1,5 @@
+const handler = async context => {
+  await context.sendText(`Hello World. Platform: ${context.platform}`);
+};
+
+module.exports = handler;
diff --git a/examples/cross-platform-with-console/index.js b/examples/cross-platform-with-console/index.js
new file mode 100644
index 00000000..122ac720
--- /dev/null
+++ b/examples/cross-platform-with-console/index.js
@@ -0,0 +1,52 @@
+const {
+  ConsoleBot,
+  MessengerBot,
+  LineBot,
+  TelegramBot,
+  SlackBot,
+  ViberBot,
+} = require('bottender');
+
+const handler = require('./handler');
+const config = require('./bottender.config');
+
+if (process.env.USE_CONSOLE === 'true') {
+  const bot = new ConsoleBot().onEvent(handler);
+  bot.createRuntime();
+} else {
+  const express = require('express');
+  const bodyParser = require('body-parser');
+
+  const { registerRoutes } = require('bottender/express');
+
+  const server = express();
+
+  server.use(
+    bodyParser.json({
+      verify: (req, res, buf) => {
+        req.rawBody = buf.toString();
+      },
+    })
+  );
+
+  const bots = {
+    messenger: new MessengerBot(config.messenger).onEvent(handler),
+    line: new LineBot(config.line).onEvent(handler),
+    slack: new SlackBot(config.slack).onEvent(handler),
+    telegram: new TelegramBot(config.telegram).onEvent(handler),
+    viber: new ViberBot(config.viber).onEvent(handler),
+  };
+
+  registerRoutes(server, bots.messenger, {
+    path: '/messenger',
+    verifyToken: config.messenger.verifyToken,
+  });
+  registerRoutes(server, bots.line, { path: '/line' });
+  registerRoutes(server, bots.slack, { path: '/slack' });
+  registerRoutes(server, bots.telegram, { path: '/telegram' });
+  registerRoutes(server, bots.viber, { path: '/viber' });
+
+  server.listen(5000, () => {
+    console.log('server is listening on 5000 port...');
+  });
+}
diff --git a/examples/cross-platform-with-console/package.json b/examples/cross-platform-with-console/package.json
new file mode 100644
index 00000000..80ffa323
--- /dev/null
+++ b/examples/cross-platform-with-console/package.json
@@ -0,0 +1,15 @@
+{
+  "dependencies": {
+    "body-parser": "^1.18.2",
+    "express": "^4.16.0",
+    "bottender": "latest"
+  },
+  "devDependencies": {
+    "nodemon": "^1.11.0"
+  },
+  "scripts": {
+    "dev": "nodemon index.js",
+    "start": "node index.js",
+    "console": "USE_CONSOLE=true node index.js"
+  }
+}
diff --git a/examples/cross-platform/bottender.config.js b/examples/cross-platform/bottender.config.js
index e50b566f..28d5aad2 100644
--- a/examples/cross-platform/bottender.config.js
+++ b/examples/cross-platform/bottender.config.js
@@ -2,6 +2,7 @@ module.exports = {
   messenger: {
     accessToken: '__FILL_YOUR_TOKEN_HERE__',
     appSecret: '__FILL_YOUR_SECRET_HERE__',
+    verifyToken: '__FILL_YOUR_VERIFYTOKEN_HERE__',
   },
   line: {
     channelSecret: '__FILL_YOUR_CHANNEL_SECRET_HERE__',
diff --git a/examples/cross-platform/index.js b/examples/cross-platform/index.js
index a7299687..5a208ab1 100644
--- a/examples/cross-platform/index.js
+++ b/examples/cross-platform/index.js
@@ -30,7 +30,10 @@ const bots = {
   viber: new ViberBot(config.viber).onEvent(handler),
 };
 
-registerRoutes(server, bots.messenger, { path: '/messenger' });
+registerRoutes(server, bots.messenger, {
+  path: '/messenger',
+  verifyToken: config.messenger.verifyToken,
+});
 registerRoutes(server, bots.line, { path: '/line' });
 registerRoutes(server, bots.slack, { path: '/slack' });
 registerRoutes(server, bots.telegram, { path: '/telegram' });
diff --git a/src/context/MessengerEvent.js b/src/context/MessengerEvent.js
index dcb6ee64..4b291063 100644
--- a/src/context/MessengerEvent.js
+++ b/src/context/MessengerEvent.js
@@ -701,10 +701,10 @@ export default class MessengerEvent implements Event {
   }
 
   /**
-   * Determine if the event is a request thread control event sent by facebook integrated inbox (appId is 263902037430900).
+   * Determine if the event is a request thread control event sent by facebook integrated 'Page Inbox' (appId is 263902037430900).
    *
    */
-  get isRequestThreadControlFromInbox(): boolean {
+  get isRequestThreadControlFromPageInbox(): boolean {
     return (
       !!this._rawEvent.request_thread_control &&
       typeof this._rawEvent.request_thread_control === 'object' &&


Test patch:
diff --git a/src/context/__tests__/MessengerEvent.spec.js b/src/context/__tests__/MessengerEvent.spec.js
index 43225875..22346feb 100644
--- a/src/context/__tests__/MessengerEvent.spec.js
+++ b/src/context/__tests__/MessengerEvent.spec.js
@@ -1232,19 +1232,19 @@ it('#isRequestThreadControl', () => {
   ).toEqual(true);
 });
 
-it('#isRequestThreadControlFromInbox', () => {
+it('#isRequestThreadControlFromPageInbox', () => {
   expect(
-    new MessengerEvent(textMessage).isRequestThreadControlFromInbox
+    new MessengerEvent(textMessage).isRequestThreadControlFromPageInbox
+  ).toEqual(false);
+  expect(
+    new MessengerEvent(postback).isRequestThreadControlFromPageInbox
   ).toEqual(false);
-  expect(new MessengerEvent(postback).isRequestThreadControlFromInbox).toEqual(
-    false
-  );
   expect(
     new MessengerEvent(requestThreadControlFromInbox).isRequestThreadControl
   ).toEqual(true);
   expect(
     new MessengerEvent(requestThreadControlFromInbox)
-      .isRequestThreadControlFromInbox
+      .isRequestThreadControlFromPageInbox
   ).toEqual(true);
 });