From 5905dab39f1138101dcaf1a35a27b9dde81c470a Mon Sep 17 00:00:00 2001 From: jumtech Date: Thu, 31 Aug 2017 15:06:17 +0900 Subject: [PATCH 1/4] decaffeinate --- .gitignore | 3 +- app.coffee | 49 -------- app.js | 59 ++++++++++ bin/www.coffee | 78 ------------- bin/www.js | 90 +++++++++++++++ config.coffee | 9 -- logics/_a3rt.coffee | 30 ----- logics/_a3rt.js | 43 +++++++ logics/_search.coffee | 26 ----- logics/_search.js | 40 +++++++ logics/_send.coffee | 30 ----- logics/_send.js | 44 ++++++++ logics/_send_hmac.coffee | 40 ------- logics/_send_hmac.js | 55 +++++++++ package.json | 3 +- routes/bot.coffee | 189 ------------------------------- routes/bot.js | 234 +++++++++++++++++++++++++++++++++++++++ routes/index.coffee | 22 ---- routes/index.js | 25 +++++ 19 files changed, 593 insertions(+), 476 deletions(-) delete mode 100644 app.coffee create mode 100644 app.js delete mode 100755 bin/www.coffee create mode 100644 bin/www.js delete mode 100644 config.coffee delete mode 100644 logics/_a3rt.coffee create mode 100644 logics/_a3rt.js delete mode 100644 logics/_search.coffee create mode 100644 logics/_search.js delete mode 100644 logics/_send.coffee create mode 100644 logics/_send.js delete mode 100644 logics/_send_hmac.coffee create mode 100644 logics/_send_hmac.js delete mode 100644 routes/bot.coffee create mode 100644 routes/bot.js delete mode 100644 routes/index.coffee create mode 100644 routes/index.js diff --git a/.gitignore b/.gitignore index fb9e7c7..ccb7c7e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /node_modules /npm-debug.log /Procfile -/.buildpacks \ No newline at end of file +/.buildpacks +/config.js \ No newline at end of file diff --git a/app.coffee b/app.coffee deleted file mode 100644 index c3e76fa..0000000 --- a/app.coffee +++ /dev/null @@ -1,49 +0,0 @@ -express = require('express') -path = require('path') -favicon = require('serve-favicon') -logger = require('morgan') -cookieParser = require('cookie-parser') -bodyParser = require('body-parser') -routes = require('./routes/index') -bot = require('./routes/bot') -app = express() -# view engine setup -app.set 'views', path.join(__dirname, 'views') -app.set 'view engine', 'jade' -# uncomment after placing your favicon in /public -#app.use(favicon(path.join(__dirname, 'public', 'favicon.ico'))); -app.use logger('dev') -app.use bodyParser.json() -app.use bodyParser.urlencoded(extended: false) -app.use cookieParser() -app.use express.static(path.join(__dirname, 'public')) -app.use '/', routes -app.use '/bot', bot -# catch 404 and forward to error handler -app.use (req, res, next) -> - err = new Error('Not Found') - err.status = 404 - next err - return -app.use (err, req, res, next) -> - console.log 'err', err - next() -# error handlers -# development error handler -# will print stacktrace -if app.get('env') == 'development' - app.use (err, req, res, next) -> - res.status err.status or 500 - res.render 'error', - message: err.message - error: err - return -# production error handler -# no stacktraces leaked to user -app.use (err, req, res, next) -> - res.status err.status or 500 - res.render 'error', - message: err.message - error: {} - return -module.exports = app diff --git a/app.js b/app.js new file mode 100644 index 0000000..72cb774 --- /dev/null +++ b/app.js @@ -0,0 +1,59 @@ +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const express = require('express'); +const path = require('path'); +const favicon = require('serve-favicon'); +const logger = require('morgan'); +const cookieParser = require('cookie-parser'); +const bodyParser = require('body-parser'); +const routes = require('./routes/index'); +const bot = require('./routes/bot'); +const app = express(); +// view engine setup +app.set('views', path.join(__dirname, 'views')); +app.set('view engine', 'jade'); +// uncomment after placing your favicon in /public +//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico'))); +app.use(logger('dev')); +app.use(bodyParser.json()); +app.use(bodyParser.urlencoded({extended: false})); +app.use(cookieParser()); +app.use(express.static(path.join(__dirname, 'public'))); +app.use('/', routes); +app.use('/bot', bot); +// catch 404 and forward to error handler +app.use(function(req, res, next) { + const err = new Error('Not Found'); + err.status = 404; + next(err); +}); +app.use(function(err, req, res, next) { + console.log('err', err); + return next(); +}); +// error handlers +// development error handler +// will print stacktrace +if (app.get('env') === 'development') { + app.use(function(err, req, res, next) { + res.status(err.status || 500); + res.render('error', { + message: err.message, + error: err + } + ); + }); +} +// production error handler +// no stacktraces leaked to user +app.use(function(err, req, res, next) { + res.status(err.status || 500); + res.render('error', { + message: err.message, + error: {} + }); +}); +module.exports = app; diff --git a/bin/www.coffee b/bin/www.coffee deleted file mode 100755 index ea409a6..0000000 --- a/bin/www.coffee +++ /dev/null @@ -1,78 +0,0 @@ -###* -# Module dependencies. -### - -app = require('../app.coffee') -debug = require('debug')('myapp:server') -http = require('http') - -###* -# Normalize a port into a number, string, or false. -### - -normalizePort = (val) -> - `var port` - port = parseInt(val, 10) - if isNaN(port) - # named pipe - return val - if port >= 0 - # port number - return port - false - -###* -# Get port from environment and store in Express. -### - -port = normalizePort(process.env.PORT or '5000') - - -###* -# Event listener for HTTP server "error" event. -### - -onError = (error) -> - if error.syscall != 'listen' - throw error - bind = if typeof port == 'string' then 'Pipe ' + port else 'Port ' + port - # handle specific listen errors with friendly messages - switch error.code - when 'EACCES' - console.error bind + ' requires elevated privileges' - process.exit 1 - when 'EADDRINUSE' - console.error bind + ' is already in use' - process.exit 1 - else - throw error - return - -###* -# Event listener for HTTP server "listening" event. -### - -onListening = -> - addr = server.address() - bind = if typeof addr == 'string' then 'pipe ' + addr else 'port ' + addr.port - debug 'Listening on ' + bind - return - -app.set 'port', port - -###* -# Create HTTP server. -### - -server = http.createServer(app) - -###* -# Listen on provided port, on all network interfaces. -### - -server.listen port -server.on 'error', onError -server.on 'listening', onListening - -# --- -# generated by js2coffee 2.2.0 \ No newline at end of file diff --git a/bin/www.js b/bin/www.js new file mode 100644 index 0000000..96a44cf --- /dev/null +++ b/bin/www.js @@ -0,0 +1,90 @@ +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +/** + * Module dependencies. + */ + +const app = require('../app'); +const debug = require('debug')('myapp:server'); +const http = require('http'); + +/** + * Normalize a port into a number, string, or false. + */ + +const normalizePort = function(val) { + let port; + port = parseInt(val, 10); + if (isNaN(port)) { + // named pipe + return val; + } + if (port >= 0) { + // port number + return port; + } + return false; +}; + +/** + * Get port from environment and store in Express. + */ + +const port = normalizePort(process.env.PORT || '5000'); + + +/** + * Event listener for HTTP server "error" event. + */ + +const onError = function(error) { + if (error.syscall !== 'listen') { + throw error; + } + const bind = typeof port === 'string' ? `Pipe ${port}` : `Port ${port}`; + // handle specific listen errors with friendly messages + switch (error.code) { + case 'EACCES': + console.error(bind + ' requires elevated privileges'); + process.exit(1); + break; + case 'EADDRINUSE': + console.error(bind + ' is already in use'); + process.exit(1); + break; + default: + throw error; + } +}; + +/** + * Event listener for HTTP server "listening" event. + */ + +const onListening = function() { + const addr = server.address(); + const bind = typeof addr === 'string' ? `pipe ${addr}` : `port ${addr.port}`; + debug(`Listening on ${bind}`); +}; + +app.set('port', port); + +/** + * Create HTTP server. + */ + +var server = http.createServer(app); + +/** + * Listen on provided port, on all network interfaces. + */ + +server.listen(port); +server.on('error', onError); +server.on('listening', onListening); + +// --- +// generated by js2coffee 2.2.0 \ No newline at end of file diff --git a/config.coffee b/config.coffee deleted file mode 100644 index a13cc3c..0000000 --- a/config.coffee +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = { - KARTE_URL: "https://t.karte.io" - KARTE_BOT_APPLICATION_KEY: "" - KARTE_BOT_SECRET_KEY: "" - ALGOLIA_APPLICATION_ID: "" - ALGOLIA_API_KEY: "" - ALGOLIA_INDEX_NAME: "" - A3RT_API_KEY: "" -} \ No newline at end of file diff --git a/logics/_a3rt.coffee b/logics/_a3rt.coffee deleted file mode 100644 index 043e9cb..0000000 --- a/logics/_a3rt.coffee +++ /dev/null @@ -1,30 +0,0 @@ - -request = require 'request' - -module.exports = (text, cb=()->) -> - - {A3RT_API_KEY} = require('../config') - - request.post { - url: "https://api.a3rt.recruit-tech.co.jp/talk/v1/smalltalk" - formData: { - apikey: A3RT_API_KEY - query: text - } - }, (err, res, body) -> - - if err - console.log err - return cb err - - try - body = JSON.parse(body) - catch err - return cb err - - if body.error - return cb new Error(body.error) - - console.log body - - return cb null, body.results[0]?.reply diff --git a/logics/_a3rt.js b/logics/_a3rt.js new file mode 100644 index 0000000..912aaf2 --- /dev/null +++ b/logics/_a3rt.js @@ -0,0 +1,43 @@ +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ + +const request = require('request'); + +module.exports = function(text, cb) { + + if (cb == null) { cb = function(){}; } + const {A3RT_API_KEY} = require('../config'); + + return request.post({ + url: "https://api.a3rt.recruit-tech.co.jp/talk/v1/smalltalk", + formData: { + apikey: A3RT_API_KEY, + query: text + } + }, function(err, res, body) { + + if (err) { + console.log(err); + return cb(err); + } + + try { + body = JSON.parse(body); + } catch (error) { + err = error; + return cb(err); + } + + if (body.error) { + return cb(new Error(body.error)); + } + + console.log(body); + + return cb(null, body.results[0] != null ? body.results[0].reply : undefined); + }); +}; diff --git a/logics/_search.coffee b/logics/_search.coffee deleted file mode 100644 index 479e772..0000000 --- a/logics/_search.coffee +++ /dev/null @@ -1,26 +0,0 @@ -algoliasearch = require('algoliasearch') - -module.exports = ({text, count}, cb=()->) -> - _search_by_algolia {text, count}, (err, result) -> - return cb err if err - return cb null, result - -_search_by_algolia = ({text, count}, cb) -> - {ALGOLIA_APPLICATION_ID, ALGOLIA_API_KEY, ALGOLIA_INDEX_NAME} = require('../config') - ag_client = algoliasearch(ALGOLIA_APPLICATION_ID, ALGOLIA_API_KEY) - ag_index = ag_client.initIndex(ALGOLIA_INDEX_NAME) - - ag_index.search { - query: text - hitsPerPage: count - }, (err, content) -> - return cb err if err - result = - count: 0 - hits: [] - for h of content.hits - result.hits.push - title: content.hits[h].title - url: "https://support.karte.io/hc/ja/articles/#{content.hits[h].id}" - result.count = result.hits.length - return cb null, result diff --git a/logics/_search.js b/logics/_search.js new file mode 100644 index 0000000..efea239 --- /dev/null +++ b/logics/_search.js @@ -0,0 +1,40 @@ +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const algoliasearch = require('algoliasearch'); + +module.exports = function({text, count}, cb) { + if (cb == null) { cb = function(){}; } + return _search_by_algolia({text, count}, function(err, result) { + if (err) { return cb(err); } + return cb(null, result); + }); +}; + +var _search_by_algolia = function({text, count}, cb) { + const {ALGOLIA_APPLICATION_ID, ALGOLIA_API_KEY, ALGOLIA_INDEX_NAME} = require('../config'); + const ag_client = algoliasearch(ALGOLIA_APPLICATION_ID, ALGOLIA_API_KEY); + const ag_index = ag_client.initIndex(ALGOLIA_INDEX_NAME); + + return ag_index.search({ + query: text, + hitsPerPage: count + }, function(err, content) { + if (err) { return cb(err); } + const result = { + count: 0, + hits: [] + }; + for (let h in content.hits) { + result.hits.push({ + title: content.hits[h].title, + url: `https://support.karte.io/hc/ja/articles/${content.hits[h].id}` + }); + } + result.count = result.hits.length; + return cb(null, result); + }); +}; diff --git a/logics/_send.coffee b/logics/_send.coffee deleted file mode 100644 index 7a279f4..0000000 --- a/logics/_send.coffee +++ /dev/null @@ -1,30 +0,0 @@ - -request = require 'request' - -module.exports = (path, body, cb=()->) -> - - {KARTE_URL, KARTE_BOT_APPLICATION_KEY} = require('../config') - - public_key = KARTE_BOT_APPLICATION_KEY - - request.post { - url: KARTE_URL + "/v0/#{path}" - body: JSON.stringify body - headers: - 'Content-Type': 'application/json' - 'X-KARTE-App-Key': "#{public_key}" - }, (err, res, body) -> - - if err - console.log err - return cb err - - try - body = JSON.parse(body) - catch err - return cb err - - if body.error - return cb new Error(body.error) - - return cb null diff --git a/logics/_send.js b/logics/_send.js new file mode 100644 index 0000000..c7830f3 --- /dev/null +++ b/logics/_send.js @@ -0,0 +1,44 @@ +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ + +const request = require('request'); + +module.exports = function(path, body, cb) { + + if (cb == null) { cb = function(){}; } + const {KARTE_URL, KARTE_BOT_APPLICATION_KEY} = require('../config'); + + const public_key = KARTE_BOT_APPLICATION_KEY; + + return request.post({ + url: KARTE_URL + `/v0/${path}`, + body: JSON.stringify(body), + headers: { + 'Content-Type': 'application/json', + 'X-KARTE-App-Key': `${public_key}` + } + }, function(err, res, body) { + + if (err) { + console.log(err); + return cb(err); + } + + try { + body = JSON.parse(body); + } catch (error) { + err = error; + return cb(err); + } + + if (body.error) { + return cb(new Error(body.error)); + } + + return cb(null); + }); +}; diff --git a/logics/_send_hmac.coffee b/logics/_send_hmac.coffee deleted file mode 100644 index 73b2170..0000000 --- a/logics/_send_hmac.coffee +++ /dev/null @@ -1,40 +0,0 @@ - -request = require 'request' -crypto = require('crypto') - -_signature = (secret_key, body) -> - signature = crypto.createHmac('sha256', secret_key).update(new Buffer(body, 'utf8')).digest('base64') - return signature - -module.exports = (path, body, cb=()->) -> - - {KARTE_URL, KARTE_BOT_APPLICATION_KEY, KARTE_BOT_SECRET_KEY} = require('../config') - - public_key = KARTE_BOT_APPLICATION_KEY - timestamp = (new Date()).toISOString() - - body = JSON.stringify body - signature = _signature KARTE_BOT_SECRET_KEY, body - - request.post { - url: KARTE_URL + "/v0/#{path}" - body: body - headers: - 'Content-Type': 'text/plain; charset=utf-8' - 'X-KARTE-App-Key': "#{public_key}" - 'Authorization': "KARTE0-HMAC-SHA256 TimeStamp=\"#{timestamp}\",Signature=\"#{signature}\"" - }, (err, res, body) -> - - if err - console.log err - return cb err - - try - body = JSON.parse(body) - catch err - return cb err - - if body.error - return cb new Error(body.error) - - return cb null \ No newline at end of file diff --git a/logics/_send_hmac.js b/logics/_send_hmac.js new file mode 100644 index 0000000..9934c19 --- /dev/null +++ b/logics/_send_hmac.js @@ -0,0 +1,55 @@ +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ + +const request = require('request'); +const crypto = require('crypto'); + +const _signature = function(secret_key, body) { + const signature = crypto.createHmac('sha256', secret_key).update(new Buffer(body, 'utf8')).digest('base64'); + return signature; +}; + +module.exports = function(path, body, cb) { + + if (cb == null) { cb = function(){}; } + const {KARTE_URL, KARTE_BOT_APPLICATION_KEY, KARTE_BOT_SECRET_KEY} = require('../config'); + + const public_key = KARTE_BOT_APPLICATION_KEY; + const timestamp = (new Date()).toISOString(); + + body = JSON.stringify(body); + const signature = _signature(KARTE_BOT_SECRET_KEY, body); + + return request.post({ + url: KARTE_URL + `/v0/${path}`, + body, + headers: { + 'Content-Type': 'text/plain; charset=utf-8', + 'X-KARTE-App-Key': `${public_key}`, + 'Authorization': `KARTE0-HMAC-SHA256 TimeStamp=\"${timestamp}\",Signature=\"${signature}\"` + } + }, function(err, res, body) { + + if (err) { + console.log(err); + return cb(err); + } + + try { + body = JSON.parse(body); + } catch (error) { + err = error; + return cb(err); + } + + if (body.error) { + return cb(new Error(body.error)); + } + + return cb(null); + }); +}; \ No newline at end of file diff --git a/package.json b/package.json index 027a733..a7c2f0c 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "private": true, "main": "app.coffee", "scripts": { - "start": "$(npm bin)/coffee ./bin/www.coffee", + "start": "node ./bin/www", "test": "echo \"Error: no test specified\" && exit 1" }, "engines": { @@ -14,7 +14,6 @@ "algoliasearch": "3.24.3", "async": "2.0.1", "body-parser": "~1.15.1", - "coffee-script": "1.10.0", "cookie-parser": "~1.4.3", "debug": "~2.2.0", "express": "~4.13.4", diff --git a/routes/bot.coffee b/routes/bot.coffee deleted file mode 100644 index 5748a39..0000000 --- a/routes/bot.coffee +++ /dev/null @@ -1,189 +0,0 @@ -express = require('express') -router = express.Router() -algoliasearch = require('algoliasearch'); -_send = require('../logics/_send') -_a3rt = require('../logics/_a3rt') -_send_hmac = require('../logics/_send_hmac') -_search = require('../logics/_search') - -# webhook -router.post '/echo', (req, res, next) -> - - {KARTE_BOT_APPLICATION_KEY} = require('../config') - - {data, user, event_type} = req.body - {user_id, assignee} = user - - if event_type == 'message' - - {app_name, message_id, thread_id, content} = data - - # 自分がアサインされていたら、メッセージを送る - if assignee == 'bot-' + KARTE_BOT_APPLICATION_KEY - _send 'message', { - app_name - user_id - content: - text: '僕はエコーサーバーです: ' + content.text - }, (err) -> - - if err - console.log err - else - # 自分がアサインされていなければ、有無を言わさずアサインする - _send 'assign', { - user_id - assignee: 'bot-' + KARTE_BOT_APPLICATION_KEY - }, (err) -> - - if err - console.log err - - else if event_type == 'assign' - - if assignee == 'bot-' + KARTE_BOT_APPLICATION_KEY - _send 'message', { - app_name: 'webchat' - user_id - content: - text: 'こんにちわ。わたしKARTE Botが担当します。 ' - } - - return res.json { - status: 'OK' - } - -# webhook -router.post '/a3rt', (req, res, next) -> - - {KARTE_BOT_APPLICATION_KEY} = require('../config') - - {data, user, event_type} = req.body - {user_id, assignee} = user - - if event_type == 'message' - - {app_name, message_id, thread_id, content} = data - - if assignee == 'bot-' + KARTE_BOT_APPLICATION_KEY - _a3rt content.text, (err, text) -> - - if err - console.log err - return - - _send 'message', { - app_name - user_id - content: - text: text - }, (err) -> - - if err - console.log err - - return res.json { - status: 'OK' - } - -# webhook -router.post '/operator', (req, res, next) -> - {KARTE_BOT_APPLICATION_KEY} = require('../config') - {data, user, event_type} = req.body - {user_id, assignee} = user - {app_name, message_id, thread_id, content} = data - if event_type == 'assign' - if assignee is 'bot-' + KARTE_BOT_APPLICATION_KEY - _send_delayed_msgs user_id, [ - 'こんにちは。私たちのチームは、来週の月曜日に戻ってきます。' - '私に手伝えることがあれば、教えてください。' - '`{"type":"buttons","buttons":[{"title":"メールで通知を受け取る"},{"title":"わからない用語を質問する"}]}`' - ] - - else if event_type == 'message' - if assignee is 'bot-' + KARTE_BOT_APPLICATION_KEY - if content?.text == "[#メールで通知を受け取る]" - _send_delayed_msgs user_id, [ - '通知を受け取るメールアドレスを入力してください。' - '`{"type": "input", "input": {"title":"通知を受け取る","placeholder":"example.com","button":"確定","name":"email","event_name":"identify"}}`' - ] - else if (/^\[#(.*)質問する\]$/).test(content?.text) - _send_delayed_msgs user_id, [ - 'ありがとうございます。' - '知りたい用語を入力してください。' - ] - else if (/^\[#email/).test(content?.text) - _send_delayed_msgs user_id, [ - '入力ありがとうございました。' - 'チームメンバーが戻り次第、ご連絡差し上げます。' - '👋' - ] - _unassign user_id - else if (/^\[#質問を終える\]$/).test(content?.text) - _send_delayed_msgs user_id, [ - 'ご質問ありがとうございました。' - '👋' - ] - _unassign user_id - else - _search { - text: content.text - count: 5 - }, (err, result) -> - console.log err if err - if result.count == 0 or err - texts = [ - '申し訳ありません、記事が見つかりませんでした。' - '`{"type":"buttons","buttons":[{"title":"質問を終える"},{"title":"まだ質問する"}]}`' - ] - _send_delayed_msgs user_id, texts - else - texts = [ - 'ご質問ありがとうございます。' - 'もしかしたら、これらの記事が役に立つかもしれません。' - _makeLinkMessageStr(result.hits) - '`{"type":"buttons","buttons":[{"title":"質問を終える"},{"title":"まだ質問する"}]}`' - ] - _send_delayed_msgs user_id, texts - return res.json { - status: 'OK' - } - -_unassign = (user_id) -> - # アサインを外す - _send 'assign', { - user_id - assignee: null - options: { - # 同時に「対応済み」にする - finish_responding: true - } - }, (err) -> - if err - console.log err - -_send_delayed_msgs = (user_id, texts) -> - return if not texts - promises = texts.map (txt, i) -> - return new Promise (resolve, reject) -> - setTimeout () -> - _send 'message', { - app_name: 'webchat' - user_id - content: - text: txt - }, resolve - , i * 1000 - Promise.all(promises) - -_makeLinkMessageStr = (links) -> - # link UI example: - # '`{"type":"links","links":[{"title":"PLAID公式サイト","url":"https://plaid.co.jp/"},{"title":"KARTE公式サイト","url":"https://karte.io/"}]}`' - str = '`{"type":"links","links":[' - for link in links - str += JSON.stringify(link)+',' - str = str.slice(0, -1) - str += ']}`' - return str - -module.exports = router diff --git a/routes/bot.js b/routes/bot.js new file mode 100644 index 0000000..fee95c2 --- /dev/null +++ b/routes/bot.js @@ -0,0 +1,234 @@ +/* + * decaffeinate suggestions: + * DS101: Remove unnecessary use of Array.from + * DS102: Remove unnecessary code created because of implicit returns + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const express = require('express'); +const router = express.Router(); +const algoliasearch = require('algoliasearch'); +const _send = require('../logics/_send'); +const _a3rt = require('../logics/_a3rt'); +const _send_hmac = require('../logics/_send_hmac'); +const _search = require('../logics/_search'); + +// webhook +router.post('/echo', function(req, res, next) { + + let app_name, content; + const {KARTE_BOT_APPLICATION_KEY} = require('../config'); + + const {data, user, event_type} = req.body; + const {user_id, assignee} = user; + + if (event_type === 'message') { + + let message_id, thread_id; + ({app_name, message_id, thread_id, content} = data); + + // 自分がアサインされていたら、メッセージを送る + if (assignee === (`bot-${KARTE_BOT_APPLICATION_KEY}`)) { + _send('message', { + app_name, + user_id, + content: { + text: `僕はエコーサーバーです: ${content.text}` + } + }, function(err) { + + if (err) { + return console.log(err); + } + }); + } else { + // 自分がアサインされていなければ、有無を言わさずアサインする + _send('assign', { + user_id, + assignee: `bot-${KARTE_BOT_APPLICATION_KEY}` + }, function(err) { + + if (err) { + return console.log(err); + } + }); + } + + } else if (event_type === 'assign') { + + if (assignee === (`bot-${KARTE_BOT_APPLICATION_KEY}`)) { + _send('message', { + app_name: 'webchat', + user_id, + content: { + text: 'こんにちわ。わたしKARTE Botが担当します。 ' + } + }); + } + } + + return res.json({ + status: 'OK' + }); +}); + +// webhook +router.post('/a3rt', function(req, res, next) { + + const {KARTE_BOT_APPLICATION_KEY} = require('../config'); + + const {data, user, event_type} = req.body; + const {user_id, assignee} = user; + + if (event_type === 'message') { + + const {app_name, message_id, thread_id, content} = data; + + if (assignee === (`bot-${KARTE_BOT_APPLICATION_KEY}`)) { + _a3rt(content.text, function(err, text) { + + if (err) { + console.log(err); + return; + } + + return _send('message', { + app_name, + user_id, + content: { + text + } + }, function(err) { + + if (err) { + return console.log(err); + } + }); + }); + } + } + + return res.json({ + status: 'OK' + }); +}); + +// webhook +router.post('/operator', function(req, res, next) { + const {KARTE_BOT_APPLICATION_KEY} = require('../config'); + const {data, user, event_type} = req.body; + const {user_id, assignee} = user; + const {app_name, message_id, thread_id, content} = data; + if (event_type === 'assign') { + if (assignee === (`bot-${KARTE_BOT_APPLICATION_KEY}`)) { + _send_delayed_msgs(user_id, [ + 'こんにちは。私たちのチームは、来週の月曜日に戻ってきます。', + '私に手伝えることがあれば、教えてください。', + '`{"type":"buttons","buttons":[{"title":"メールで通知を受け取る"},{"title":"わからない用語を質問する"}]}`' + ]); + } + + } else if (event_type === 'message') { + if (assignee === (`bot-${KARTE_BOT_APPLICATION_KEY}`)) { + if ((content != null ? content.text : undefined) === "[#メールで通知を受け取る]") { + _send_delayed_msgs(user_id, [ + '通知を受け取るメールアドレスを入力してください。', + '`{"type": "input", "input": {"title":"通知を受け取る","placeholder":"example.com","button":"確定","name":"email","event_name":"identify"}}`' + ]); + } else if ((/^\[#(.*)質問する\]$/).test(content != null ? content.text : undefined)) { + _send_delayed_msgs(user_id, [ + 'ありがとうございます。', + '知りたい用語を入力してください。' + ]); + } else if ((/^\[#email/).test(content != null ? content.text : undefined)) { + _send_delayed_msgs(user_id, [ + '入力ありがとうございました。', + 'チームメンバーが戻り次第、ご連絡差し上げます。', + '👋' + ]); + _unassign(user_id); + } else if ((/^\[#質問を終える\]$/).test(content != null ? content.text : undefined)) { + _send_delayed_msgs(user_id, [ + 'ご質問ありがとうございました。', + '👋' + ]); + _unassign(user_id); + } else { + _search({ + text: content.text, + count: 5 + }, function(err, result) { + let texts; + if (err) { console.log(err); } + if ((result.count === 0) || err) { + texts = [ + '申し訳ありません、記事が見つかりませんでした。', + '`{"type":"buttons","buttons":[{"title":"質問を終える"},{"title":"まだ質問する"}]}`' + ]; + return _send_delayed_msgs(user_id, texts); + } else { + texts = [ + 'ご質問ありがとうございます。', + 'もしかしたら、これらの記事が役に立つかもしれません。', + _makeLinkMessageStr(result.hits), + '`{"type":"buttons","buttons":[{"title":"質問を終える"},{"title":"まだ質問する"}]}`' + ]; + return _send_delayed_msgs(user_id, texts); + } + }); + } + } + } + return res.json({ + status: 'OK' + }); +}); + +var _unassign = user_id => + // アサインを外す + _send('assign', { + user_id, + assignee: null, + options: { + // 同時に「対応済み」にする + finish_responding: true + } + }, function(err) { + if (err) { + return console.log(err); + } + }) +; + +var _send_delayed_msgs = function(user_id, texts) { + if (!texts) { return; } + const promises = texts.map((txt, i) => + new Promise(function(resolve, reject) { + return setTimeout(() => + _send('message', { + app_name: 'webchat', + user_id, + content: { + text: txt + } + }, resolve) + + , i * 1000); + }) + ); + return Promise.all(promises); +}; + +var _makeLinkMessageStr = function(links) { + // link UI example: + // '`{"type":"links","links":[{"title":"PLAID公式サイト","url":"https://plaid.co.jp/"},{"title":"KARTE公式サイト","url":"https://karte.io/"}]}`' + let str = '`{"type":"links","links":['; + for (let link of Array.from(links)) { + str += JSON.stringify(link)+','; + } + str = str.slice(0, -1); + str += ']}`'; + return str; +}; + +module.exports = router; diff --git a/routes/index.coffee b/routes/index.coffee deleted file mode 100644 index e0d57b3..0000000 --- a/routes/index.coffee +++ /dev/null @@ -1,22 +0,0 @@ -express = require('express') -router = express.Router() -config = require('../config') -_send = require('../logics/_send') - -### GET home page. ### - -router.get '/', (req, res, next) -> - - {KARTE_BOT_APPLICATION_KEY} = require('../config') - - _send 'track', { - keys: - user_id: 'bot' - event_name: 'bot_sample_server_view_post' - values: - method: 'post' - } - - return res.render 'index', {title: 'karte io bot sample server', KARTE_BOT_APPLICATION_KEY} - -module.exports = router diff --git a/routes/index.js b/routes/index.js new file mode 100644 index 0000000..4747eab --- /dev/null +++ b/routes/index.js @@ -0,0 +1,25 @@ +const express = require('express'); +const router = express.Router(); +const config = require('../config'); +const _send = require('../logics/_send'); + +/* GET home page. */ + +router.get('/', function(req, res, next) { + + const {KARTE_BOT_APPLICATION_KEY} = require('../config'); + + _send('track', { + keys: { + user_id: 'bot' + }, + event_name: 'bot_sample_server_view_post', + values: { + method: 'post' + } + }); + + return res.render('index', {title: 'karte io bot sample server', KARTE_BOT_APPLICATION_KEY}); +}); + +module.exports = router; From e390b463b5aa9716858a98b50929b652ba934402 Mon Sep 17 00:00:00 2001 From: jumtech Date: Thu, 31 Aug 2017 15:43:19 +0900 Subject: [PATCH 2/4] remove unnecessary code --- app.js | 13 ++++--------- bin/www.js | 13 ++++--------- logics/_a3rt.js | 13 +++---------- logics/_search.js | 16 +++++----------- logics/_send.js | 13 +++---------- logics/_send_hmac.js | 15 ++++----------- routes/bot.js | 33 +++++++++++++-------------------- routes/index.js | 17 ++--------------- views/index.jade | 7 +------ views/setting.jade | 14 -------------- 10 files changed, 39 insertions(+), 115 deletions(-) delete mode 100644 views/setting.jade diff --git a/app.js b/app.js index 72cb774..9e2514b 100644 --- a/app.js +++ b/app.js @@ -1,8 +1,3 @@ -/* - * decaffeinate suggestions: - * DS102: Remove unnecessary code created because of implicit returns - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md - */ const express = require('express'); const path = require('path'); const favicon = require('serve-favicon'); @@ -25,12 +20,12 @@ app.use(express.static(path.join(__dirname, 'public'))); app.use('/', routes); app.use('/bot', bot); // catch 404 and forward to error handler -app.use(function(req, res, next) { +app.use((req, res, next) => { const err = new Error('Not Found'); err.status = 404; next(err); }); -app.use(function(err, req, res, next) { +app.use((err, req, res, next) => { console.log('err', err); return next(); }); @@ -38,7 +33,7 @@ app.use(function(err, req, res, next) { // development error handler // will print stacktrace if (app.get('env') === 'development') { - app.use(function(err, req, res, next) { + app.use((err, req, res, next) => { res.status(err.status || 500); res.render('error', { message: err.message, @@ -49,7 +44,7 @@ if (app.get('env') === 'development') { } // production error handler // no stacktraces leaked to user -app.use(function(err, req, res, next) { +app.use((err, req, res, next) => { res.status(err.status || 500); res.render('error', { message: err.message, diff --git a/bin/www.js b/bin/www.js index 96a44cf..4b33f66 100644 --- a/bin/www.js +++ b/bin/www.js @@ -1,8 +1,3 @@ -/* - * decaffeinate suggestions: - * DS102: Remove unnecessary code created because of implicit returns - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md - */ /** * Module dependencies. */ @@ -15,7 +10,7 @@ const http = require('http'); * Normalize a port into a number, string, or false. */ -const normalizePort = function(val) { +const normalizePort = (val) => { let port; port = parseInt(val, 10); if (isNaN(port)) { @@ -40,7 +35,7 @@ const port = normalizePort(process.env.PORT || '5000'); * Event listener for HTTP server "error" event. */ -const onError = function(error) { +const onError = (error) => { if (error.syscall !== 'listen') { throw error; } @@ -64,7 +59,7 @@ const onError = function(error) { * Event listener for HTTP server "listening" event. */ -const onListening = function() { +const onListening = () => { const addr = server.address(); const bind = typeof addr === 'string' ? `pipe ${addr}` : `port ${addr.port}`; debug(`Listening on ${bind}`); @@ -76,7 +71,7 @@ app.set('port', port); * Create HTTP server. */ -var server = http.createServer(app); +const server = http.createServer(app); /** * Listen on provided port, on all network interfaces. diff --git a/logics/_a3rt.js b/logics/_a3rt.js index 912aaf2..dd8903e 100644 --- a/logics/_a3rt.js +++ b/logics/_a3rt.js @@ -1,15 +1,8 @@ -/* - * decaffeinate suggestions: - * DS102: Remove unnecessary code created because of implicit returns - * DS207: Consider shorter variations of null checks - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md - */ - const request = require('request'); -module.exports = function(text, cb) { +module.exports = (text, cb) => { - if (cb == null) { cb = function(){}; } + if (!cb) { cb = () => {}; } const {A3RT_API_KEY} = require('../config'); return request.post({ @@ -18,7 +11,7 @@ module.exports = function(text, cb) { apikey: A3RT_API_KEY, query: text } - }, function(err, res, body) { + }, (err, res, body) => { if (err) { console.log(err); diff --git a/logics/_search.js b/logics/_search.js index efea239..30e0d05 100644 --- a/logics/_search.js +++ b/logics/_search.js @@ -1,20 +1,14 @@ -/* - * decaffeinate suggestions: - * DS102: Remove unnecessary code created because of implicit returns - * DS207: Consider shorter variations of null checks - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md - */ const algoliasearch = require('algoliasearch'); -module.exports = function({text, count}, cb) { - if (cb == null) { cb = function(){}; } - return _search_by_algolia({text, count}, function(err, result) { +module.exports = ({text, count}, cb) => { + if (!cb) { cb = () => {}; } + return _search_by_algolia({text, count}, (err, result) => { if (err) { return cb(err); } return cb(null, result); }); }; -var _search_by_algolia = function({text, count}, cb) { +const _search_by_algolia = ({text, count}, cb) => { const {ALGOLIA_APPLICATION_ID, ALGOLIA_API_KEY, ALGOLIA_INDEX_NAME} = require('../config'); const ag_client = algoliasearch(ALGOLIA_APPLICATION_ID, ALGOLIA_API_KEY); const ag_index = ag_client.initIndex(ALGOLIA_INDEX_NAME); @@ -22,7 +16,7 @@ var _search_by_algolia = function({text, count}, cb) { return ag_index.search({ query: text, hitsPerPage: count - }, function(err, content) { + }, (err, content) => { if (err) { return cb(err); } const result = { count: 0, diff --git a/logics/_send.js b/logics/_send.js index c7830f3..c941ad7 100644 --- a/logics/_send.js +++ b/logics/_send.js @@ -1,15 +1,8 @@ -/* - * decaffeinate suggestions: - * DS102: Remove unnecessary code created because of implicit returns - * DS207: Consider shorter variations of null checks - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md - */ - const request = require('request'); -module.exports = function(path, body, cb) { +module.exports = (path, body, cb) => { - if (cb == null) { cb = function(){}; } + if (!cb) { cb = () => {}; } const {KARTE_URL, KARTE_BOT_APPLICATION_KEY} = require('../config'); const public_key = KARTE_BOT_APPLICATION_KEY; @@ -21,7 +14,7 @@ module.exports = function(path, body, cb) { 'Content-Type': 'application/json', 'X-KARTE-App-Key': `${public_key}` } - }, function(err, res, body) { + }, (err, res, body) => { if (err) { console.log(err); diff --git a/logics/_send_hmac.js b/logics/_send_hmac.js index 9934c19..12e0c5e 100644 --- a/logics/_send_hmac.js +++ b/logics/_send_hmac.js @@ -1,21 +1,14 @@ -/* - * decaffeinate suggestions: - * DS102: Remove unnecessary code created because of implicit returns - * DS207: Consider shorter variations of null checks - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md - */ - const request = require('request'); const crypto = require('crypto'); -const _signature = function(secret_key, body) { +const _signature = (secret_key, body) => { const signature = crypto.createHmac('sha256', secret_key).update(new Buffer(body, 'utf8')).digest('base64'); return signature; }; -module.exports = function(path, body, cb) { +module.exports = (path, body, cb) => { - if (cb == null) { cb = function(){}; } + if (!cb) { cb = () => {}; } const {KARTE_URL, KARTE_BOT_APPLICATION_KEY, KARTE_BOT_SECRET_KEY} = require('../config'); const public_key = KARTE_BOT_APPLICATION_KEY; @@ -32,7 +25,7 @@ module.exports = function(path, body, cb) { 'X-KARTE-App-Key': `${public_key}`, 'Authorization': `KARTE0-HMAC-SHA256 TimeStamp=\"${timestamp}\",Signature=\"${signature}\"` } - }, function(err, res, body) { + }, (err, res, body) => { if (err) { console.log(err); diff --git a/routes/bot.js b/routes/bot.js index fee95c2..ee605d7 100644 --- a/routes/bot.js +++ b/routes/bot.js @@ -1,10 +1,3 @@ -/* - * decaffeinate suggestions: - * DS101: Remove unnecessary use of Array.from - * DS102: Remove unnecessary code created because of implicit returns - * DS207: Consider shorter variations of null checks - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md - */ const express = require('express'); const router = express.Router(); const algoliasearch = require('algoliasearch'); @@ -14,7 +7,7 @@ const _send_hmac = require('../logics/_send_hmac'); const _search = require('../logics/_search'); // webhook -router.post('/echo', function(req, res, next) { +router.post('/echo', (req, res, next) => { let app_name, content; const {KARTE_BOT_APPLICATION_KEY} = require('../config'); @@ -35,7 +28,7 @@ router.post('/echo', function(req, res, next) { content: { text: `僕はエコーサーバーです: ${content.text}` } - }, function(err) { + }, (err) => { if (err) { return console.log(err); @@ -46,7 +39,7 @@ router.post('/echo', function(req, res, next) { _send('assign', { user_id, assignee: `bot-${KARTE_BOT_APPLICATION_KEY}` - }, function(err) { + }, (err) => { if (err) { return console.log(err); @@ -73,7 +66,7 @@ router.post('/echo', function(req, res, next) { }); // webhook -router.post('/a3rt', function(req, res, next) { +router.post('/a3rt', (req, res, next) => { const {KARTE_BOT_APPLICATION_KEY} = require('../config'); @@ -85,7 +78,7 @@ router.post('/a3rt', function(req, res, next) { const {app_name, message_id, thread_id, content} = data; if (assignee === (`bot-${KARTE_BOT_APPLICATION_KEY}`)) { - _a3rt(content.text, function(err, text) { + _a3rt(content.text, (err, text) => { if (err) { console.log(err); @@ -98,7 +91,7 @@ router.post('/a3rt', function(req, res, next) { content: { text } - }, function(err) { + }, (err) => { if (err) { return console.log(err); @@ -114,7 +107,7 @@ router.post('/a3rt', function(req, res, next) { }); // webhook -router.post('/operator', function(req, res, next) { +router.post('/operator', (req, res, next) => { const {KARTE_BOT_APPLICATION_KEY} = require('../config'); const {data, user, event_type} = req.body; const {user_id, assignee} = user; @@ -157,7 +150,7 @@ router.post('/operator', function(req, res, next) { _search({ text: content.text, count: 5 - }, function(err, result) { + }, (err, result) => { let texts; if (err) { console.log(err); } if ((result.count === 0) || err) { @@ -184,7 +177,7 @@ router.post('/operator', function(req, res, next) { }); }); -var _unassign = user_id => +const _unassign = user_id => // アサインを外す _send('assign', { user_id, @@ -193,17 +186,17 @@ var _unassign = user_id => // 同時に「対応済み」にする finish_responding: true } - }, function(err) { + }, (err) => { if (err) { return console.log(err); } }) ; -var _send_delayed_msgs = function(user_id, texts) { +const _send_delayed_msgs = (user_id, texts) => { if (!texts) { return; } const promises = texts.map((txt, i) => - new Promise(function(resolve, reject) { + new Promise((resolve, reject) => { return setTimeout(() => _send('message', { app_name: 'webchat', @@ -219,7 +212,7 @@ var _send_delayed_msgs = function(user_id, texts) { return Promise.all(promises); }; -var _makeLinkMessageStr = function(links) { +const _makeLinkMessageStr = (links) => { // link UI example: // '`{"type":"links","links":[{"title":"PLAID公式サイト","url":"https://plaid.co.jp/"},{"title":"KARTE公式サイト","url":"https://karte.io/"}]}`' let str = '`{"type":"links","links":['; diff --git a/routes/index.js b/routes/index.js index 4747eab..d615075 100644 --- a/routes/index.js +++ b/routes/index.js @@ -5,21 +5,8 @@ const _send = require('../logics/_send'); /* GET home page. */ -router.get('/', function(req, res, next) { - - const {KARTE_BOT_APPLICATION_KEY} = require('../config'); - - _send('track', { - keys: { - user_id: 'bot' - }, - event_name: 'bot_sample_server_view_post', - values: { - method: 'post' - } - }); - - return res.render('index', {title: 'karte io bot sample server', KARTE_BOT_APPLICATION_KEY}); +router.get('/', (req, res, next) => { + return res.render('index', {title: 'karte io bot sample server'}); }); module.exports = router; diff --git a/views/index.jade b/views/index.jade index 7118616..91abb16 100644 --- a/views/index.jade +++ b/views/index.jade @@ -1,9 +1,4 @@ extends layout block content - h1= title - h2 redirect tracking - a(href="http://localhost:8010/v0/track?app_key=#{KARTE_APP_PUBLIC_KEY}&response=redirect&redirect_to=https://google.co.jp&data=%7B%22keys%22%3A%7B%22user_id%22%3A%22bot%22%7D%2C%22event_name%22%3A%22bot_sample_server_view_redirect%22%2C%22values%22%3A%7B%7D%7D" target="_blank") redirect test -> google - h2 1x1 gif tracking - img(src="http://localhost:8010/v0/track?app_key=#{KARTE_APP_PUBLIC_KEY}&response=image&data=%7B%22keys%22%3A%7B%22user_id%22%3A%22bot%22%7D%2C%22event_name%22%3A%22bot_sample_server_view_image%22%2C%22values%22%3A%7B%7D%7D") - + h1= title \ No newline at end of file diff --git a/views/setting.jade b/views/setting.jade deleted file mode 100644 index caa1eb8..0000000 --- a/views/setting.jade +++ /dev/null @@ -1,14 +0,0 @@ -extends layout - -block content - style. - label { - display: block - } - h1= title - form(method="POST", action="/setting") - each i in ['KARTE_URL', 'KARTE_API_KEY', 'KARTE_SECRET_KEY', 'ZENDESK_ACCOUNT_EMAIL', 'ZENDESK_ACCOUNT_PASSWORD'] - label - | #{i} - input(type="text", name="#{i}", value="#{config[i]}") - button(type="submit") 設定 From 572a3c23d2cf1a3acfd67408a9e9a2c27da94e87 Mon Sep 17 00:00:00 2001 From: jumtech Date: Thu, 31 Aug 2017 15:50:41 +0900 Subject: [PATCH 3/4] add sample config file --- config.js | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 config.js diff --git a/config.js b/config.js new file mode 100644 index 0000000..f78fd97 --- /dev/null +++ b/config.js @@ -0,0 +1,9 @@ +module.exports = { + KARTE_URL: "https://t.karte.io", + KARTE_BOT_APPLICATION_KEY: "", + KARTE_BOT_SECRET_KEY: "", + ALGOLIA_APPLICATION_ID: "", + ALGOLIA_API_KEY: "", + ALGOLIA_INDEX_NAME: "", + A3RT_API_KEY: "" +}; \ No newline at end of file From 759f852ca04757049dc5873c24ddbec4ca09a633 Mon Sep 17 00:00:00 2001 From: jumtech Date: Thu, 31 Aug 2017 15:53:14 +0900 Subject: [PATCH 4/4] fix README.md --- README.md | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 83883b4..f5de934 100644 --- a/README.md +++ b/README.md @@ -2,22 +2,24 @@ - KARTEのmessageとassignのWebhookやAPIを使ったbotのサンプルです. ## 使い方 -- [ ] `npm start`で5000番でサーバーを立ち上げる. -- [ ] `_config.coffee`ファイルを作成し、必要な設定値を追加する. +- [ ] KARTE管理画面から、botの設定を行います. +- [ ] `config.js`ファイルに必要な設定値を追加します. - 以下のような内容で作成してください. -```coffee +```js module.exports = { - KARTE_URL: "https://t.karte.io" - KARTE_BOT_APPLICATION_KEY: "bot設定画面のApplicationKeyを設定" - KARTE_BOT_SECRET_KEY: "bot設定画面のSecretKeyを設定" - ALGOLIA_APPLICATION_ID: "AlgoliaのApplicationIdを設定(Algolia検索を使う場合)" - ALGOLIA_API_KEY: "AlgoliaのApiKeyを設定(Algolia検索を使う場合)" - ALGOLIA_INDEX_NAME: "AlgoliaのIndexNameを設定(Algolia検索を使う場合)" + KARTE_URL: "https://t.karte.io", + KARTE_BOT_APPLICATION_KEY: "bot設定画面のApplicationKeyを設定", + KARTE_BOT_SECRET_KEY: "bot設定画面のSecretKeyを設定", + ALGOLIA_APPLICATION_ID: "AlgoliaのApplicationIdを設定(Algolia検索を使う場合)", + ALGOLIA_API_KEY: "AlgoliaのApiKeyを設定(Algolia検索を使う場合)", + ALGOLIA_INDEX_NAME: "AlgoliaのIndexNameを設定(Algolia検索を使う場合)", A3RT_API_KEY: "A3RTのApiKeyを設定(A3RT APIを使う場合)" } ``` +- [ ] `npm start`で、port:5000番でサーバーが立ち上がります. + ## bot仕様 - `/echo` - 来たメッセージをそのまま返します.