node-red-contrib-line-messaging-api 0.1.4 → 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -6,10 +6,11 @@ LINE Messagin APIを利用できるNode-REDのノードです。
6
6
 
7
7
  以下のAPIを利用できます。
8
8
 
9
- * LINE Messaging API
10
- * Reply Message
11
- * Push Message
12
- * LINE Notify
9
+ - LINE Messaging API
10
+ - Webhook & Reply Message
11
+ - Push Message
12
+ - BloadCast Message
13
+ - LINE Notify
13
14
 
14
15
  ## インストール
15
16
 
@@ -23,13 +24,13 @@ AdminタブからInstall
23
24
 
24
25
  ## 利用イメージ
25
26
 
26
- ### Reply Message
27
+ ### Webhook & Reply Message
27
28
 
28
- * HTTP inノードで受け取る
29
- * Functionノードでハンドリング
30
- * Reply Messageノードでリプライ
31
-
32
- ![](https://i.gyazo.com/d3df3a28e010b008043ed80ae6a672ea.gif)
29
+ 1. Webhookノードを配置し、ダブルクリックで設定を開き、指定した `/path` と自身のホスト名の組み合わせ(Webhook URL)を、LINE Developersであらかじめ作成したMessaging APIに登録します。
30
+ 2. ReplyMessageノードを配置し、チャネルのシークレットとアクセストークンを設定します。
31
+ 3. WebhookノードとReplyMessageノードを接続してLINEにメッセージを送るとオウム返しBotができます。
32
+ [![Image from Gyazo](https://i.gyazo.com/7da2dbecfc69515edf852cf7a26d9196.gif)](https://gyazo.com/7da2dbecfc69515edf852cf7a26d9196)
33
+ 4. WebhookノードとReplyMessageノードの中間で `msg.payload` をうまく作成すると様々なメッセージが送れます。文字列を指定すると通常のテキストメッセージに、[LINEで定義されているメッセージオブジェクト](https://developers.line.biz/ja/reference/messaging-api/#message-objects)を指定すればそのメッセージを返信することができます。
33
34
 
34
35
  ### Push Message
35
36
 
@@ -53,6 +54,7 @@ AdminタブからInstall
53
54
 
54
55
  ## release
55
56
 
56
- * 2020/12/17: Bloadcast Messageに対応、Reply MessageがFlex Messageに対応(thanks [@gaomar](https://github.com/gaomar))
57
- * 2019/2/13: PUSH MessageとLINE Notify対応
58
- * 2018/10/11: 現状は簡単なリプライのみ実装されています。
57
+ - 2021/8/1: Reply Messageが画像に対応(thanks [@ukkz](https://github.com/ukkz))
58
+ - 2020/12/17: Bloadcast Messageに対応、Reply MessageがFlex Messageに対応(thanks [@gaomar](https://github.com/gaomar))
59
+ - 2019/2/13: PUSH MessageとLINE Notify対応
60
+ - 2018/10/11: 現状は簡単なリプライのみ実装されています。
@@ -4,20 +4,26 @@
4
4
  color: '#01B301',
5
5
  defaults: {
6
6
  name: {value:""},
7
- channelSecret:{value:"", required:true},
8
- channelAccessToken:{value:"", required:true}
9
7
  },
10
- inputs:1,
11
- outputs:1,
8
+
9
+ credentials: {
10
+ channelSecret:{value:"", type: "password", required:true},
11
+ channelAccessToken:{value:"", type: "password", required:true}
12
+ },
13
+
14
+ inputs: 1,
15
+ outputs: 1,
12
16
  icon: "comment.png",
13
17
  align: "right",
14
- label: function() {
15
- return this.name||"BloadcastMessage";
18
+ paletteLabel: 'Bloadcast',
19
+ label: function () {
20
+ return this.name || 'BloadcastMessage';
16
21
  }
17
22
  });
18
23
  </script>
19
24
 
20
25
  <script type="text/x-red" data-template-name="BloadcastMessage">
26
+
21
27
  <div class="form-row">
22
28
  <label for="node-input-name"><i class="icon-tag"></i> Name</label>
23
29
  <input type="text" id="node-input-name" placeholder="Name">
@@ -11,7 +11,7 @@ module.exports = (RED) => {
11
11
  try {
12
12
  lineconfig = require('../../env');
13
13
  } catch (error) {
14
- lineconfig = { channelSecret: config.channelSecret, channelAccessToken: config.channelAccessToken};
14
+ lineconfig = { channelSecret: node.credentials.channelSecret, channelAccessToken: node.credentials.channelAccessToken};
15
15
  }
16
16
 
17
17
  if(lineconfig.channelSecret === '' || lineconfig.channelAccessToken === '') {
@@ -42,5 +42,10 @@ module.exports = (RED) => {
42
42
  });
43
43
  }
44
44
 
45
- RED.nodes.registerType("BloadcastMessage", main);
45
+ RED.nodes.registerType("BloadcastMessage", main, {
46
+ credentials: {
47
+ channelSecret: {type:"password"},
48
+ channelAccessToken: {type:"password"},
49
+ },
50
+ });
46
51
  }
@@ -0,0 +1,38 @@
1
+ <script>
2
+ RED.nodes.registerType('Limit',{
3
+ category: 'LINE',
4
+ color: '#01B301',
5
+ defaults: {
6
+ name: {value:""},
7
+ },
8
+ credentials: {
9
+ AccessToken: { type: "password", required: true }
10
+ },
11
+ inputs:1,
12
+ outputs:1,
13
+ icon: "comment.png",
14
+ align: "right",
15
+ label: function() {
16
+ return this.name||"Limit";
17
+ }
18
+ });
19
+ </script>
20
+
21
+ <script type="text/x-red" data-template-name="Limit">
22
+ <div class="form-row">
23
+ <label for="node-input-name"><i class="icon-tag"></i> Name</label>
24
+ <input type="text" id="node-input-name" placeholder="Name">
25
+ </div>
26
+
27
+ <div class="form-row">
28
+ <label for="node-input-AccessToken">
29
+ <i class="icon-tag"></i>
30
+ LINE Limit AccessToken
31
+ </label>
32
+ <input type="password" id="node-input-AccessToken" placeholder="LINE Limit AccessToken">
33
+ </div>
34
+ </script>
35
+
36
+ <script type="text/x-red" data-help-name="Limit">
37
+ <p>当月の送信メッセージのリミットを教えてくれます。</p>
38
+ </script>
@@ -0,0 +1,45 @@
1
+ module.exports = (RED) => {
2
+ 'use strict';
3
+
4
+ const axiosBase = require('axios');
5
+
6
+ const main = function(config){
7
+ const node = this;
8
+ RED.nodes.createNode(node, config);
9
+ const LINE_TOKEN = node.credentials.AccessToken;
10
+ const axios = axiosBase.create({
11
+ baseURL: `https://api.line.me/v2/bot/message/quota`,
12
+ headers: {
13
+ 'Content-Type': 'application/x-www-form-urlencoded',
14
+ 'Authorization': `Bearer ${LINE_TOKEN}`
15
+ }
16
+ });
17
+
18
+ node.on('input', async (msg) => {
19
+ const mes = msg.payload;
20
+ try {
21
+ const resLimit = await axios.get(`/`);
22
+ const resCurrent = await axios.get(`/consumption`);
23
+
24
+ const output = {
25
+ type: resLimit.data.type,
26
+ limit: resLimit.data.value,
27
+ totalUsage: resCurrent.data.totalUsage,
28
+ usagePercentage: resCurrent.data.totalUsage / resLimit.data.value
29
+ }
30
+
31
+ msg.payload = output;
32
+ node.send(msg);
33
+ } catch (error) {
34
+ console.log(error);
35
+ }
36
+
37
+ });
38
+ }
39
+
40
+ RED.nodes.registerType("Limit", main, {
41
+ credentials: {
42
+ AccessToken: {type:"password"}
43
+ }
44
+ });
45
+ }
@@ -4,7 +4,9 @@
4
4
  color: '#1ad823',
5
5
  defaults: {
6
6
  name: {value:""},
7
- AccessToken:{value:"", required:true}
7
+ },
8
+ credentials: {
9
+ AccessToken: { type: "password", required: true }
8
10
  },
9
11
  inputs:1,
10
12
  outputs:0,
@@ -6,7 +6,7 @@ module.exports = (RED) => {
6
6
  const main = function(config){
7
7
  const node = this;
8
8
  RED.nodes.createNode(node, config);
9
- const LINE_TOKEN = config.AccessToken;
9
+ const LINE_TOKEN = node.credentials.AccessToken;
10
10
  const axios = axiosBase.create({
11
11
  baseURL: `https://notify-api.line.me`,
12
12
  headers: {
@@ -28,5 +28,9 @@ module.exports = (RED) => {
28
28
  });
29
29
  }
30
30
 
31
- RED.nodes.registerType("Notify", main);
31
+ RED.nodes.registerType("Notify", main, {
32
+ credentials: {
33
+ AccessToken: {type:"password"}
34
+ }
35
+ });
32
36
  }
@@ -4,16 +4,19 @@
4
4
  color: '#01B301',
5
5
  defaults: {
6
6
  name: {value:""},
7
- channelSecret:{value:"", required:true},
8
- channelAccessToken:{value:"", required:true},
9
- targetId:{value:"", required:true},
10
7
  },
11
- inputs:1,
12
- outputs:0,
8
+ credentials: {
9
+ channelSecret: {type:"password", required:true},
10
+ channelAccessToken: {type:"password", required:true},
11
+ targetId:{type:"password", required:true},
12
+ },
13
+ inputs: 1,
14
+ outputs: 0,
13
15
  icon: "comment.png",
14
16
  align: "right",
17
+ paletteLabel: 'Push',
15
18
  label: function() {
16
- return this.name||"PushMessage";
19
+ return this.name || 'PushMessage';
17
20
  }
18
21
  });
19
22
  </script>
@@ -10,7 +10,7 @@ module.exports = (RED) => {
10
10
  try {
11
11
  lineconfig = require('../../env');
12
12
  } catch (error) {
13
- lineconfig = { channelSecret: config.channelSecret, channelAccessToken: config.channelAccessToken};
13
+ lineconfig = { channelSecret: node.credentials.channelSecret, channelAccessToken: node.credentials.channelAccessToken};
14
14
  }
15
15
 
16
16
  if(lineconfig.channelSecret === '' || lineconfig.channelAccessToken === '') {
@@ -20,7 +20,7 @@ module.exports = (RED) => {
20
20
  const client = new line.Client(lineconfig);
21
21
 
22
22
  node.on('input', async (msg) => {
23
- const userId = config.targetId;
23
+ const userId = node.credentials.targetId;
24
24
  try {
25
25
  const res = await client.pushMessage(userId, {
26
26
  type: 'text',
@@ -36,5 +36,11 @@ module.exports = (RED) => {
36
36
  });
37
37
  }
38
38
 
39
- RED.nodes.registerType("PushMessage", main);
39
+ RED.nodes.registerType("PushMessage", main, {
40
+ credentials: {
41
+ channelSecret: {type:"password"},
42
+ channelAccessToken: {type:"password"},
43
+ targetId: {type:"password"},
44
+ },
45
+ });
40
46
  }
@@ -4,16 +4,19 @@
4
4
  color: '#01B301',
5
5
  defaults: {
6
6
  name: {value:""},
7
- channelSecret:{value:"", required:true},
8
- channelAccessToken:{value:"", required:true},
9
7
  replyMessage:{value:""}
10
8
  },
9
+ credentials: {
10
+ channelSecret: {type:"password", required:true},
11
+ channelAccessToken: {type:"password", required:true},
12
+ },
11
13
  inputs:1,
12
14
  outputs:0,
13
15
  icon: "comment.png",
14
16
  align: "right",
15
- label: function() {
16
- return this.name||"ReplyMessage";
17
+ paletteLabel: 'Reply',
18
+ label: function () {
19
+ return this.name || 'ReplyMessage';
17
20
  }
18
21
  });
19
22
  </script>
@@ -36,7 +39,7 @@
36
39
 
37
40
  <div class="form-row">
38
41
  <label for="node-input-replyMessage"><i class="icon-tag"></i> ReplyMessage</label>
39
- <input type="text" id="node-input-replyMessage" placeholder="空の場合はおうむ返しします">
42
+ <input type="text" id="node-input-replyMessage" placeholder="static text message here">
40
43
  </div>
41
44
  </script>
42
45
 
@@ -11,18 +11,18 @@ module.exports = (RED) => {
11
11
  lineconfig = require('../../env');
12
12
  } catch (error) {
13
13
  lineconfig = {
14
- channelSecret: config.channelSecret,
15
- channelAccessToken: config.channelAccessToken
14
+ channelSecret: node.credentials.channelSecret,
15
+ channelAccessToken: node.credentials.channelAccessToken
16
16
  };
17
17
  }
18
18
 
19
- if(lineconfig.channelSecret === '' || lineconfig.channelAccessToken === '') {
20
- this.error(RED._("token not found"));
19
+ if (lineconfig.channelSecret === '' || lineconfig.channelAccessToken === '') {
20
+ this.error(RED._('token not found'));
21
21
  }
22
22
 
23
23
  const client = new line.Client(lineconfig);
24
24
 
25
- //メインの処理
25
+ // 旧仕様
26
26
  const handleEvent = (event) => {
27
27
  if (event.type !== 'message') {
28
28
  return Promise.resolve(null);
@@ -31,37 +31,80 @@ module.exports = (RED) => {
31
31
  if (event.message.type === 'text') {
32
32
  return client.replyMessage(event.replyToken, {
33
33
  type: 'text',
34
- text: config.replyMessage || event.message.text //実際に返信の言葉を入れる箇所
35
- });
34
+ text: config.replyMessage || event.message.text // 実際に返信の言葉を入れる箇所
35
+ });
36
36
  } else if (event.message.type === 'flex') {
37
37
  const message_text = event.message.altText;
38
38
 
39
39
  return client.replyMessage(event.replyToken, {
40
- type: "flex",
40
+ type: 'flex',
41
41
  altText: message_text,
42
42
  contents: event.message.text
43
43
  });
44
+ } else if (event.message.type === 'image') {
45
+ return client.replyMessage(event.replyToken, {
46
+ type: 'image',
47
+ originalContentUrl: event.message.originalContentUrl,
48
+ previewImageUrl: event.message.previewImageUrl || event.message.originalContentUrl
49
+ });
44
50
  } else {
45
51
  return Promise.resolve(null);
46
52
  }
47
53
  }
48
54
 
49
- node.on('input', (msg) => {
50
- Promise
51
- .all(msg.payload.events.map(handleEvent))
52
- .then(result => {
53
- // [{}]が返ってきてる
54
- if (result.length === 1 && 0 === Object.keys(result[0]).length) {
55
- result = {status: 200, message: 'Success'}
56
- }
57
- msg.payload = result;
58
- node.send(msg)
59
- }).catch(err => {
60
- console.log(err);
61
- node.error(err);
55
+ // 新仕様
56
+ const reply = (msg) => {
57
+ if (!msg.line || !msg.line.event || !msg.line.event.type) {
58
+ throw 'no valid LINE event found within msg';
59
+ } else if (!msg.line.event.replyToken) {
60
+ throw 'no replyable LINE event received';
61
+ } else if (!msg.payload) {
62
+ throw 'reply content (msg.payload) is empty';
63
+ } else if (typeof msg.payload === 'object' && msg.payload.type) {
64
+ // payloadがオブジェクトの場合はメッセージオブジェクト扱いで送信される
65
+ return client.replyMessage(msg.line.event.replyToken, msg.payload);
66
+ } else {
67
+ // payloadがそれ以外なら強制的に文字列に変換しテキストメッセージ扱いで送信する
68
+ return client.replyMessage(msg.line.event.replyToken, {
69
+ type: 'text',
70
+ text: config.replyMessage || String(msg.payload)
62
71
  });
72
+ }
73
+ }
74
+
75
+ node.on('input', async (msg) => {
76
+ if (msg.line && msg.line.event) {
77
+ // 新仕様
78
+ try {
79
+ const result = await reply(msg);
80
+ console.info(result);
81
+ } catch (err) {
82
+ console.warn(err);
83
+ node.error(err);
84
+ }
85
+ } else if (msg.payload.events) {
86
+ // 旧仕様
87
+ Promise
88
+ .all(msg.payload.events.map(handleEvent))
89
+ .then(result => {
90
+ // [{}]が返ってきてる
91
+ if (result.length === 1 && 0 === Object.keys(result[0]).length) {
92
+ result = { status: 200, message: 'Success' }
93
+ }
94
+ msg.payload = result;
95
+ node.send(msg)
96
+ }).catch(err => {
97
+ console.log(err);
98
+ node.error(err);
99
+ });
100
+ }
63
101
  });
64
102
  }
65
103
 
66
- RED.nodes.registerType("ReplyMessage", main);
104
+ RED.nodes.registerType('ReplyMessage', main, {
105
+ credentials: {
106
+ channelSecret: { type:'password' },
107
+ channelAccessToken: { type:'password' },
108
+ }
109
+ });
67
110
  }
@@ -0,0 +1,59 @@
1
+ <script type="text/javascript">
2
+ RED.nodes.registerType('Webhook', {
3
+ category: 'LINE',
4
+ color: '#01B301',
5
+ defaults: {
6
+ name: { value: '' },
7
+ url: { value: '', required: true }
8
+ },
9
+ inputs: 0,
10
+ outputs: 1,
11
+ icon: 'inject.svg',
12
+ paletteLabel: 'Webhook',
13
+ label: function () {
14
+ if (this.name) {
15
+ return this.name;
16
+ } else if (this.url) {
17
+ let root = RED.settings.httpNodeRoot;
18
+ if (root.slice(-1) != '/') {
19
+ root = root + '/';
20
+ }
21
+ if (this.url.charAt(0) == '/') {
22
+ root += this.url.slice(1);
23
+ } else {
24
+ root += this.url;
25
+ }
26
+ return root;
27
+ } else {
28
+ return 'Webhook';
29
+ }
30
+ },
31
+ oneditprepare: function () {
32
+ let root = RED.settings.httpNodeRoot;
33
+ if (root.slice(-1) == '/') {
34
+ root = root.slice(0, -1);
35
+ }
36
+ if (root == '') {
37
+ $('#node-input-tip').hide();
38
+ } else {
39
+ $('#node-input-path').html(root);
40
+ $('#node-input-tip').show();
41
+ }
42
+ }
43
+ });
44
+ </script>
45
+
46
+ <script type="text/x-red" data-template-name="Webhook">
47
+ <div class="form-row">
48
+ <label for="node-input-url"><i class="fa fa-globe"></i> Path</label>
49
+ <input id="node-input-url" type="text" placeholder="/webhook">
50
+ </div>
51
+ <div class="form-row">
52
+ <label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
53
+ <input id="node-input-name" type="text" placeholder="Name">
54
+ </div>
55
+ </script>
56
+
57
+ <script type="text/x-red" data-help-name="Webhook">
58
+ <p>A webhook endpoint node that receives from LINE platform when fire any events occurred.</p>
59
+ </script>
@@ -0,0 +1,191 @@
1
+ /**
2
+ * 公式ノード http in ベース
3
+ * @see https://raw.githubusercontent.com/node-red/node-red/master/packages/node_modules/@node-red/nodes/core/network/21-httpin.js
4
+ */
5
+
6
+ module.exports = function (RED) {
7
+ 'use strict';
8
+
9
+ const bodyParser = require('body-parser');
10
+ const cors = require('cors');
11
+
12
+ function createResponseWrapper(node, res) {
13
+ const wrapper = {
14
+ _res: res
15
+ };
16
+ const toWrap = [
17
+ 'append',
18
+ 'attachment',
19
+ 'cookie',
20
+ 'clearCookie',
21
+ 'download',
22
+ 'end',
23
+ 'format',
24
+ 'get',
25
+ 'json',
26
+ 'jsonp',
27
+ 'links',
28
+ 'location',
29
+ 'redirect',
30
+ 'render',
31
+ 'send',
32
+ 'sendfile',
33
+ 'sendFile',
34
+ 'sendStatus',
35
+ 'set',
36
+ 'status',
37
+ 'type',
38
+ 'vary'
39
+ ];
40
+ toWrap.forEach(function (f) {
41
+ wrapper[f] = function () {
42
+ node.warn(RED._('webhook.errors.deprecated-call', { method: 'msg.res.' + f }));
43
+ const result = res[f].apply(res, arguments);
44
+ if (result === res) {
45
+ return wrapper;
46
+ } else {
47
+ return result;
48
+ }
49
+ }
50
+ });
51
+ return wrapper;
52
+ }
53
+
54
+ let corsHandler = function (req, res, next) { next(); }
55
+
56
+ if (RED.settings.httpNodeCors) {
57
+ corsHandler = cors(RED.settings.httpNodeCors);
58
+ RED.httpNode.options('*', corsHandler);
59
+ }
60
+
61
+ // LINEイベント種別から適切な文字列を返す
62
+ function eventToString(event) {
63
+ if (event.type === 'message') {
64
+ // メッセージ系イベント
65
+ switch (event.message.type) {
66
+ case 'text':
67
+ return event.message.text;
68
+ case 'image':
69
+ case 'video':
70
+ case 'audio':
71
+ case 'file':
72
+ // 実装予定
73
+ return '(media)';
74
+ case 'location':
75
+ return event.message.address;
76
+ case 'sticker':
77
+ return '(sticker)';
78
+ default:
79
+ return '(unknown message event)';
80
+ }
81
+ } else {
82
+ // メッセージじゃない
83
+ switch (event.type) {
84
+ case 'unsend':
85
+ return '(unsend)';
86
+ case 'follow':
87
+ return '(follow)';
88
+ case 'unfollow':
89
+ return '(unfollow)';
90
+ case 'join':
91
+ return '(join)';
92
+ case 'leave':
93
+ return '(leave)';
94
+ case 'memberJoined':
95
+ return '(memberJoined)';
96
+ case 'memberLeft':
97
+ return '(memberLeft)';
98
+ case 'postback':
99
+ if (event.postback.params.datetime) return event.postback.params.datetime;
100
+ else if (event.postback.params.newRichMenuAliasId) return event.postback.params.newRichMenuAliasId;
101
+ else '(postback)';
102
+ case 'videoPlayComplete':
103
+ return 'videoPlayComplete';
104
+ case 'beacon':
105
+ return (event.beacon.dm) ? event.beacon.dm : event.beacon.hwid;
106
+ case 'accountLink':
107
+ return '(accountLink)';
108
+ case 'things': // typeによって連携・連携解除・シナリオ実行の3種がある
109
+ return event.things.deviceId;
110
+ default:
111
+ return '(unknown event)';
112
+ }
113
+ }
114
+ }
115
+
116
+ function Webhook(config) {
117
+ RED.nodes.createNode(this, config);
118
+ if (RED.settings.httpNodeRoot !== false) {
119
+
120
+ if (!config.url) {
121
+ this.warn(RED._('webhook.errors.missing-path'));
122
+ return;
123
+ }
124
+ this.url = config.url;
125
+ if (this.url[0] !== '/') {
126
+ this.url = '/' + this.url;
127
+ }
128
+
129
+ const node = this;
130
+
131
+ // エラー時
132
+ this.errorHandler = function (err, req, res, next) {
133
+ node.warn(err);
134
+ res.sendStatus(500);
135
+ };
136
+
137
+ // 受信してmsgを送り出すところ
138
+ this.callback = function (req, res) {
139
+ const msgid = RED.util.generateId();
140
+ res._msgid = msgid;
141
+ // Webhook共通
142
+ if (req.body.destination && req.body.events) {
143
+ // イベントと同数のmsgを送信
144
+ req.body.events.forEach(event => {
145
+ node.send({
146
+ _msgid: msgid,
147
+ req: req,
148
+ res: createResponseWrapper(node, res),
149
+ line: {
150
+ destination: req.body.destination,
151
+ event: event, // 個別のイベント
152
+ events: req.body.events, // 生イベント配列
153
+ },
154
+ payload: eventToString(event)
155
+ });
156
+ });
157
+ }
158
+ // 空データをLINEプラットフォームへ返す (200 OK)
159
+ const wrapper = createResponseWrapper(node, res);
160
+ wrapper._res.set('content-length', 0);
161
+ wrapper._res.status(200).send('');
162
+ };
163
+
164
+ const httpMiddleware = function (req, res, next) { next(); }
165
+
166
+ if (RED.settings.httpNodeMiddleware) {
167
+ if (typeof RED.settings.httpNodeMiddleware === 'function' || Array.isArray(RED.settings.httpNodeMiddleware)) {
168
+ httpMiddleware = RED.settings.httpNodeMiddleware;
169
+ }
170
+ }
171
+
172
+ const maxApiRequestSize = RED.settings.apiMaxLength || '5mb';
173
+ const jsonParser = bodyParser.json({ limit: maxApiRequestSize });
174
+
175
+ // 必ずPOSTで受ける
176
+ RED.httpNode.post(this.url, httpMiddleware, corsHandler, jsonParser, this.callback, this.errorHandler);
177
+
178
+ this.on('close', function () {
179
+ const node = this;
180
+ RED.httpNode._router.stack.forEach(function (route, i, routes) {
181
+ if (route.route && route.route.path === node.url && route.route.methods['post']) {
182
+ routes.splice(i, 1);
183
+ }
184
+ });
185
+ });
186
+ } else {
187
+ this.warn(RED._('webhook.errors.not-created'));
188
+ }
189
+ }
190
+ RED.nodes.registerType('Webhook', Webhook);
191
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-red-contrib-line-messaging-api",
3
- "version": "0.1.4",
3
+ "version": "0.1.9",
4
4
  "description": "LINE Messaging APIです",
5
5
  "main": "line.js",
6
6
  "repository": {
@@ -13,9 +13,11 @@
13
13
  },
14
14
  "node-red": {
15
15
  "nodes": {
16
+ "Webhook": "./nodes/webhook/webhook.js",
16
17
  "ReplyMessage": "./nodes/reply/reply.js",
17
18
  "PushMessage": "./nodes/push/push.js",
18
19
  "BloadcastMessage": "./nodes/bloadcast/bloadcast.js",
20
+ "Limit": "./nodes/limit/limit.js",
19
21
  "Notify": "./nodes/notify/notify.js"
20
22
  }
21
23
  },
@@ -27,6 +29,8 @@
27
29
  "license": "Apache 2.0",
28
30
  "dependencies": {
29
31
  "@line/bot-sdk": "^7.2.0",
32
+ "body-parser": "^1.19.1",
33
+ "cors": "^2.8.5",
30
34
  "express": "^4.17.1"
31
35
  }
32
36
  }