유명현

ADD: Market search function + Refactor code: seperate line bot code from express(app.js)

1 const express = require("express"); 1 const express = require("express");
2 const line = require("@line/bot-sdk"); 2 const line = require("@line/bot-sdk");
3 -const setFlexMessage = require("./apis/setFlexMessage");
4 const fs = require("fs"); 3 const fs = require("fs");
5 - 4 +const { handleEvent } = require("./chatbot/index");
6 -require("dotenv").config(); 5 +const { config } = require("./chatbot/index");
7 -const config = {
8 - channelAccessToken: process.env.channelAccessToken,
9 - channelSecret: process.env.channelSecret,
10 -};
11 6
12 const app = express(); 7 const app = express();
13 app.post("/webhook", line.middleware(config), (req, res) => { 8 app.post("/webhook", line.middleware(config), (req, res) => {
14 - Promise.all(req.body.events.map(handleEvent)).then((result) => 9 + Promise.all(req.body.events.map(handleEvent)).then((result) => {
15 - res.json(result) 10 + res.json(result);
16 - ); 11 + });
17 }); 12 });
18 13
19 -const client = new line.Client(config);
20 -
21 -let waitNewMamulList = []; // 매물 키워드 입력 기다리는 목록
22 -
23 -function handleEvent(event) {
24 - if (event.type !== "message" || event.message.type !== "text") {
25 - console.log(event);
26 - if (event.type == "postback") {
27 - if (event.postback.data == "new") {
28 - var found = waitNewMamulList.indexOf(event.source.userId);
29 - if (found == -1) {
30 - waitNewMamulList.push(event.source.userId);
31 - console.log(waitNewMamulList);
32 - return Promise.resolve(
33 - client.replyMessage(event.replyToken, {
34 - type: "text",
35 - text: "등록할 매물 키워드를 알려주세요!",
36 - })
37 - );
38 - } else {
39 - return Promise.resolve(
40 - client.replyMessage(event.replyToken, {
41 - type: "text",
42 - text: "등록할 매물 키워드를 알려주세요!",
43 - })
44 - );
45 - }
46 - } else if (event.postback.data == "check") {
47 - return Promise.resolve(
48 - client.replyMessage(event.replyToken, {
49 - type: "flex",
50 - altText: "등록된 매물",
51 - contents: setFlexMessage(
52 - "daangn",
53 - "RTX 3080",
54 - "1000000",
55 - "https://dnvefa72aowie.cloudfront.net/origin/article/202205/94cdd237258671d5806a70f64ab2b3c7dcd790da0384b394ef5809fe10c08ced.webp?q=95&s=1440x1440&t=inside",
56 - "https://www.daangn.com/articles/403755360"
57 - ),
58 - })
59 - );
60 - }
61 - }
62 - return Promise.resolve(null);
63 - } else {
64 - console.log(event);
65 - var found = waitNewMamulList.indexOf(event.source.userId);
66 - if (found == -1) {
67 - return Promise.resolve(
68 - client.replyMessage(event.replyToken, {
69 - type: "text",
70 - text: "왼쪽 하단 메뉴버튼(☰)을 클릭해 상호작용 해주세요!",
71 - })
72 - );
73 - } else {
74 - // TODO: 서버에 키워드 등록하는 api
75 - waitNewMamulList.splice(found, 1);
76 - console.log(waitNewMamulList[found]);
77 - return Promise.resolve(
78 - client.replyMessage(event.replyToken, {
79 - type: "text",
80 - text: "매물이 등록되었습니다!\n등록된 매물: " + event.message.text,
81 - })
82 - );
83 - }
84 - }
85 -}
86 -
87 const port = 1231; 14 const port = 1231;
88 app.listen(port); 15 app.listen(port);
89 console.log(`listening...\nport : ${port}`); 16 console.log(`listening...\nport : ${port}`);
90 -
91 -/*Push Message*/
92 -// client.pushMessage(event.source.userId, {
93 -// type: "flex",
94 -// altText: "새로운 매물이 왔어요!",
95 -// contents: setFlexMessage(
96 -// "daangn",
97 -// "RTX 3080",
98 -// "1000000",
99 -// "https://dnvefa72aowie.cloudfront.net/origin/article/202205/94cdd237258671d5806a70f64ab2b3c7dcd790da0384b394ef5809fe10c08ced.webp?q=95&s=1440x1440&t=inside",
100 -// "https://www.daangn.com/articles/403755360"
101 -// ),
102 -// })
103 -
104 -/*리치메뉴 설정*/
105 -// let richMenu = {
106 -// size: {
107 -// width: 2500,
108 -// height: 843,
109 -// },
110 -// selected: false,
111 -// name: "Nice richmenu",
112 -// chatBarText: "Tap to open",
113 -// areas: [
114 -// {
115 -// bounds: {
116 -// x: 0,
117 -// y: 0,
118 -// width: 1250,
119 -// height: 843,
120 -// },
121 -// action: {
122 -// type: "postback",
123 -// label: "new",
124 -// data: "new",
125 -// displayText: "키워드 등록",
126 -// inputOption: "openKeyboard",
127 -// fillInText: "",
128 -// },
129 -// },
130 -// {
131 -// bounds: {
132 -// x: 1250,
133 -// y: 0,
134 -// width: 1250,
135 -// height: 843,
136 -// },
137 -// action: {
138 -// type: "postback",
139 -// label: "check",
140 -// data: "check",
141 -// displayText: "최신 매물 확인",
142 -// inputOption: "openKeyboard",
143 -// fillInText: "",
144 -// },
145 -// },
146 -// ],
147 -// };
148 -//// 등록
149 -// client.createRichMenu(richMenu).then((richMenuId) => console.log(richMenuId));
150 -// client.setRichMenuImage(
151 -// "richmenu-183eff606f059b8244f0a625b54bddf1",
152 -// fs.createReadStream("./static/img/richMenu.jpg")
153 -// );
154 -// client.setDefaultRichMenu("richmenu-183eff606f059b8244f0a625b54bddf1");
......
1 +const line = require("@line/bot-sdk");
2 +const setFlexMessage = require("./message/setFlexMessage");
3 +const setCarouselMessage = require("./message/setCarouselMessage");
4 +const fs = require("fs");
5 +const { daangnSingleSearch } = require("./search/daangnSearch");
6 +const { daangnMultiSearch } = require("./search/daangnSearch");
7 +const { joongnaSingleSearch } = require("./search/joongnaSearch");
8 +const { joongnaMultiSearch } = require("./search/joongnaSearch");
9 +const { bunjangSingleSearch } = require("./search/bunjangSearch");
10 +const { bunjangMultiSearch } = require("./search/bunjangSearch");
11 +const { marketMultiSearch } = require("./search/marketSearch");
12 +
13 +require("dotenv").config({ path: __dirname + "/../.env" });
14 +const config = {
15 + channelAccessToken: process.env.channelAccessToken,
16 + channelSecret: process.env.channelSecret,
17 +};
18 +
19 +const client = new line.Client(config);
20 +
21 +let waitNewMamulList = []; // 매물 키워드 입력 기다리는 목록
22 +
23 +function handleEvent(event) {
24 + if (event.type !== "message" || event.message.type !== "text") {
25 + console.log(event);
26 + if (event.type == "postback") {
27 + if (event.postback.data == "new") {
28 + var found = waitNewMamulList.indexOf(event.source.userId);
29 + if (found == -1) {
30 + waitNewMamulList.push(event.source.userId);
31 + console.log(waitNewMamulList);
32 + return Promise.resolve(
33 + client.replyMessage(event.replyToken, {
34 + type: "text",
35 + text: "등록할 매물 키워드를 알려주세요!",
36 + })
37 + );
38 + } else {
39 + return Promise.resolve(
40 + client.replyMessage(event.replyToken, {
41 + type: "text",
42 + text: "등록할 매물 키워드를 알려주세요!",
43 + })
44 + );
45 + }
46 + } else if (event.postback.data == "check") {
47 + return Promise.resolve(
48 + client.replyMessage(event.replyToken, {
49 + type: "flex",
50 + altText: "등록된 매물",
51 + contents: setFlexMessage(
52 + "daangn",
53 + "RTX 3080",
54 + "1000000",
55 + "https://dnvefa72aowie.cloudfront.net/origin/article/202205/94cdd237258671d5806a70f64ab2b3c7dcd790da0384b394ef5809fe10c08ced.webp?q=95&s=1440x1440&t=inside",
56 + "https://www.daangn.com/articles/403755360"
57 + ),
58 + })
59 + );
60 + }
61 + }
62 + return Promise.resolve(null);
63 + } else {
64 + console.log(event);
65 + var found = waitNewMamulList.indexOf(event.source.userId);
66 + if (found == -1) {
67 + return Promise.resolve(
68 + marketMultiSearch(event.message.text).then((res) => {
69 + console.log(setCarouselMessage(res));
70 + client.pushMessage(event.source.userId, setCarouselMessage(res));
71 + })
72 + );
73 + } else {
74 + // TODO: 서버에 키워드 등록하는 api
75 + waitNewMamulList.splice(found, 1);
76 + console.log(waitNewMamulList[found]);
77 + return Promise.resolve(
78 + client.replyMessage(event.replyToken, {
79 + type: "text",
80 + text: "매물이 등록되었습니다!\n등록된 매물: " + event.message.text,
81 + })
82 + );
83 + }
84 + }
85 +}
86 +
87 +module.exports = { handleEvent, config };
88 +
89 +/*Reply Message*/
90 +// client.replyMessage(event.replyToken, {
91 +// type: "text",
92 +// text: "왼쪽 하단 메뉴버튼(☰)을 클릭해 상호작용 해주세요!",
93 +// })
94 +
95 +/*Push Message*/
96 +// client.pushMessage(event.source.userId, {
97 +// type: "flex",
98 +// altText: "새로운 매물이 왔어요!",
99 +// contents: setFlexMessage(
100 +// "daangn",
101 +// "RTX 3080",
102 +// "1000000",
103 +// "https://dnvefa72aowie.cloudfront.net/origin/article/202205/94cdd237258671d5806a70f64ab2b3c7dcd790da0384b394ef5809fe10c08ced.webp?q=95&s=1440x1440&t=inside",
104 +// "https://www.daangn.com/articles/403755360"
105 +// ),
106 +// })
107 +
108 +/*Carousel Message (flex message 여러개)*/
109 +// client.pushMessage(event.source.userId, {
110 +// type: "carousel",
111 +// contents: [
112 +// setFlexMessage(
113 +// "daangn",
114 +// "RTX 3080",
115 +// "1220000",
116 +// "https://dnvefa72aowie.cloudfront.net/origin/article/202205/a6ed5583ba1c0b206c264a96afcf5c736a1f055ad899c14d8087d0f7cd9e4805.webp?q=95&s=1440x1440&t=inside",
117 +// "https://www.daangn.com/articles/408099984"
118 +// ),
119 +// setFlexMessage(
120 +// "joongna",
121 +// "RTX 2080",
122 +// "1000000",
123 +// "https://cafeptthumb-phinf.pstatic.net/MjAyMjA1MjRfMTM1/MDAxNjUzMzY4MjU1MDUx.D2xeHlHLzhF3BhMD83GAMN7dAiu7YcArtpwL1AVnPR0g.dRILQe9D5XVBPbAtNKimAmYwgG1CKcr-rnSx3CeyFQIg.JPEG/%EA%B0%A4%EB%9F%AD%EC%8B%9C_GTX1060_3G.jpg?type=s3",
124 +// "https://cafe.naver.com/joonggonara/918947018"
125 +// ),
126 +// setFlexMessage(
127 +// "bunjang",
128 +// "RTX 3080",
129 +// "1059800",
130 +// "https://media.bunjang.co.kr/product/179119900_1_1652919446_w856.jpg",
131 +// "https://m.bunjang.co.kr/products/179119900"
132 +// ),
133 +// ],
134 +// });
135 +
136 +/*리치메뉴 설정*/
137 +// let richMenu = {
138 +// size: {
139 +// width: 2500,
140 +// height: 843,
141 +// },
142 +// selected: false,
143 +// name: "Nice richmenu",
144 +// chatBarText: "Tap to open",
145 +// areas: [
146 +// {
147 +// bounds: {
148 +// x: 0,
149 +// y: 0,
150 +// width: 1250,
151 +// height: 843,
152 +// },
153 +// action: {
154 +// type: "postback",
155 +// label: "new",
156 +// data: "new",
157 +// displayText: "키워드 등록",
158 +// inputOption: "openKeyboard",
159 +// fillInText: "",
160 +// },
161 +// },
162 +// {
163 +// bounds: {
164 +// x: 1250,
165 +// y: 0,
166 +// width: 1250,
167 +// height: 843,
168 +// },
169 +// action: {
170 +// type: "postback",
171 +// label: "check",
172 +// data: "check",
173 +// displayText: "최신 매물 확인",
174 +// inputOption: "openKeyboard",
175 +// fillInText: "",
176 +// },
177 +// },
178 +// ],
179 +// };
180 +//// 등록
181 +// client.createRichMenu(richMenu).then((richMenuId) => console.log(richMenuId));
182 +// client.setRichMenuImage(
183 +// "richmenu-183eff606f059b8244f0a625b54bddf1",
184 +// fs.createReadStream("./static/img/richMenu.jpg")
185 +// );
186 +// client.setDefaultRichMenu("richmenu-183eff606f059b8244f0a625b54bddf1");
1 +const setFlexMessage = require("./setFlexMessage");
2 +
3 +function setCarouselMessage(mamuls) {
4 + let flexMessages = [];
5 + let flexMessage = {};
6 + if (
7 + mamuls[0] == undefined &&
8 + mamuls[1] == undefined &&
9 + mamuls[2] == undefined
10 + ) {
11 + let nonMamulMessage = {
12 + type: "flex",
13 + altText: "매물 검색 에러",
14 + contents: setFlexMessage(
15 + "-",
16 + "매물이 없습니다!",
17 + "0",
18 + "https://upload.wikimedia.org/wikipedia/commons/thumb/f/f0/Error.svg/515px-Error.svg.png",
19 + "https://upload.wikimedia.org/wikipedia/commons/thumb/f/f0/Error.svg/515px-Error.svg.png",
20 + "-"
21 + ),
22 + };
23 + return nonMamulMessage;
24 + }
25 + for (i = 0; i < mamuls.length; i++) {
26 + if (mamuls[i] == undefined) {
27 + continue;
28 + }
29 + try {
30 + if (
31 + mamuls[i]["platform"] === "bunjang" ||
32 + mamuls[i]["platform"] === "번개장터"
33 + ) {
34 + mamuls[i]["thumbnailUrl"] = mamuls[i]["thumbnailUrl"].replace(
35 + "{",
36 + "%7B"
37 + );
38 + mamuls[i]["thumbnailUrl"] = mamuls[i]["thumbnailUrl"].replace(
39 + "}",
40 + "%7D"
41 + );
42 + }
43 +
44 + if (
45 + mamuls[i]["thumbnailUrl"] == undefined ||
46 + mamuls[i]["thumbnailUrl"] == ""
47 + ) {
48 + mamuls[i]["thumbnailUrl"] =
49 + "https://upload.wikimedia.org/wikipedia/commons/5/5f/Grey.PNG";
50 + }
51 +
52 + if (mamuls[i]["extraInfo"] == undefined || mamuls[i]["extraInfo"] == "") {
53 + mamuls[i]["extraInfo"] = "없음";
54 + } else if (mamuls[i]["extraInfo"].length > 150) {
55 + mamuls[i]["extraInfo"] = mamuls[i]["extraInfo"].slice(0, 150) + "\n...";
56 + }
57 +
58 + flexMessage = setFlexMessage(
59 + mamuls[i]["platform"],
60 + mamuls[i]["name"],
61 + mamuls[i]["price"],
62 + mamuls[i]["thumbnailUrl"],
63 + mamuls[i]["itemUrl"],
64 + mamuls[i]["extraInfo"]
65 + );
66 + flexMessages.push(flexMessage);
67 + } catch (err) {
68 + console.log(err);
69 + continue;
70 + }
71 + }
72 +
73 + let carouselMessage = {
74 + type: "flex",
75 + altText: "Carousel mamul message",
76 + contents: {
77 + type: "carousel",
78 + contents: flexMessages,
79 + },
80 + };
81 + return carouselMessage;
82 +}
83 +
84 +module.exports = setCarouselMessage;
...@@ -2,14 +2,21 @@ function priceToString(price) { ...@@ -2,14 +2,21 @@ function priceToString(price) {
2 return price.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); 2 return price.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
3 } 3 }
4 4
5 -function setFlexMessage(platform, name, price, thumbnailUrl, itemUrl) { 5 +function setFlexMessage(
6 + platform,
7 + name,
8 + price,
9 + thumbnailUrl,
10 + itemUrl,
11 + extraInfo
12 +) {
6 let koreanPlatformName = ""; 13 let koreanPlatformName = "";
7 - if (platform === "daangn") { 14 + if (platform === "daangn" || platform === "당근마켓") {
8 - koreanPlatformName = "당근"; 15 + koreanPlatformName = "당근마켓";
9 - } else if (platform === "joongna") { 16 + } else if (platform === "joongna" || platform === "중고나라") {
10 koreanPlatformName = "중고나라"; 17 koreanPlatformName = "중고나라";
11 - } else if (platform === "bunjang") { 18 + } else if (platform === "bunjang" || platform === "번개장터") {
12 - koreanPlatformName = "번개나라"; 19 + koreanPlatformName = "번개장터";
13 } else { 20 } else {
14 koreanPlatformName = "Unknown"; 21 koreanPlatformName = "Unknown";
15 } 22 }
...@@ -127,6 +134,28 @@ function setFlexMessage(platform, name, price, thumbnailUrl, itemUrl) { ...@@ -127,6 +134,28 @@ function setFlexMessage(platform, name, price, thumbnailUrl, itemUrl) {
127 }, 134 },
128 ], 135 ],
129 }, 136 },
137 + {
138 + type: "box",
139 + layout: "baseline",
140 + spacing: "sm",
141 + contents: [
142 + {
143 + type: "text",
144 + text: "정보",
145 + color: "#aaaaaa",
146 + size: "sm",
147 + flex: 1,
148 + },
149 + {
150 + type: "text",
151 + text: extraInfo,
152 + wrap: true,
153 + color: "#666666",
154 + size: "sm",
155 + flex: 5,
156 + },
157 + ],
158 + },
130 ], 159 ],
131 }, 160 },
132 ], 161 ],
......
1 +const axios = require("axios").default;
2 +
3 +const bunjangSingleSearch = (keyword) => {
4 + return Promise.resolve(
5 + axios
6 + .get(
7 + `http://43.200.35.46:18082/api/v2/bunjang/${encodeURIComponent(
8 + keyword
9 + )}`
10 + )
11 + .then((res) => res.data[0])
12 + .catch((e) => undefined)
13 + );
14 +};
15 +
16 +const bunjangMultiSearch = (keyword) => {
17 + return Promise.resolve(
18 + axios
19 + .get(
20 + `http://43.200.35.46:18082/api/v2/bunjang/${encodeURIComponent(
21 + keyword
22 + )}`
23 + )
24 + .then((res) => res.data)
25 + .catch((e) => undefined)
26 + );
27 +};
28 +
29 +module.exports = { bunjangSingleSearch, bunjangMultiSearch };
1 +const axios = require("axios").default;
2 +
3 +const daangnSingleSearch = (keyword) => {
4 + return Promise.resolve(
5 + axios
6 + .get(
7 + `http://43.200.35.46:18080/api/v2/daangn/${encodeURIComponent(keyword)}`
8 + )
9 + .then((res) => res.data["items"][0])
10 + .catch((e) => undefined)
11 + );
12 +};
13 +
14 +const daangnMultiSearch = (keyword) => {
15 + return Promise.resolve(
16 + axios
17 + .get(
18 + `http://43.200.35.46:18080/api/v2/daangn/${encodeURIComponent(keyword)}`
19 + )
20 + .then((res) => res.data["items"])
21 + .catch((e) => undefined)
22 + );
23 +};
24 +
25 +module.exports = { daangnSingleSearch, daangnMultiSearch };
1 +const axios = require("axios").default;
2 +
3 +const joongnaSingleSearch = (keyword) => {
4 + return Promise.resolve(
5 + axios
6 + .get(
7 + `http://43.200.35.46:18081/api/v2/joongna/${encodeURIComponent(
8 + keyword
9 + )}`
10 + )
11 + .then((res) => res.data[0])
12 + .catch((e) => undefined)
13 + );
14 +};
15 +
16 +const joongnaMultiSearch = (keyword) => {
17 + return Promise.resolve(
18 + axios
19 + .get(
20 + `http://43.200.35.46:18081/api/v2/joongna/${encodeURIComponent(
21 + keyword
22 + )}`
23 + )
24 + .then((res) => res.data)
25 + .catch((e) => undefined)
26 + );
27 +};
28 +
29 +module.exports = { joongnaSingleSearch, joongnaMultiSearch };
1 +const { daangnSingleSearch } = require("./daangnSearch");
2 +const { bunjangSingleSearch } = require("./bunjangSearch");
3 +const { joongnaSingleSearch } = require("./joongnaSearch");
4 +const setCarouselMessage = require("../message/setCarouselMessage");
5 +
6 +const marketMultiSearch = (keyword) => {
7 + const result = [];
8 + return new Promise((resolve, reject) => {
9 + daangnSingleSearch(keyword).then((res) => {
10 + result.push(res);
11 + bunjangSingleSearch(keyword).then((res) => {
12 + result.push(res);
13 + joongnaSingleSearch(keyword).then((res) => {
14 + result.push(res);
15 + resolve(result);
16 + });
17 + });
18 + });
19 + });
20 +};
21 +
22 +module.exports = { marketMultiSearch };
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
10 "license": "MIT", 10 "license": "MIT",
11 "dependencies": { 11 "dependencies": {
12 "@line/bot-sdk": "^7.5.0", 12 "@line/bot-sdk": "^7.5.0",
13 + "axios": "^0.27.2",
13 "dotenv": "^16.0.1", 14 "dotenv": "^16.0.1",
14 "express": "^4.18.1", 15 "express": "^4.18.1",
15 "nodemon": "^2.0.16" 16 "nodemon": "^2.0.16"
...@@ -31,6 +32,14 @@ ...@@ -31,6 +32,14 @@
31 "node": ">=10" 32 "node": ">=10"
32 } 33 }
33 }, 34 },
35 + "node_modules/@line/bot-sdk/node_modules/axios": {
36 + "version": "0.21.4",
37 + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
38 + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
39 + "dependencies": {
40 + "follow-redirects": "^1.14.0"
41 + }
42 + },
34 "node_modules/@sindresorhus/is": { 43 "node_modules/@sindresorhus/is": {
35 "version": "0.14.0", 44 "version": "0.14.0",
36 "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", 45 "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz",
...@@ -147,11 +156,25 @@ ...@@ -147,11 +156,25 @@
147 "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" 156 "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
148 }, 157 },
149 "node_modules/axios": { 158 "node_modules/axios": {
150 - "version": "0.21.4", 159 + "version": "0.27.2",
151 - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", 160 + "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz",
152 - "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", 161 + "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==",
153 "dependencies": { 162 "dependencies": {
154 - "follow-redirects": "^1.14.0" 163 + "follow-redirects": "^1.14.9",
164 + "form-data": "^4.0.0"
165 + }
166 + },
167 + "node_modules/axios/node_modules/form-data": {
168 + "version": "4.0.0",
169 + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
170 + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
171 + "dependencies": {
172 + "asynckit": "^0.4.0",
173 + "combined-stream": "^1.0.8",
174 + "mime-types": "^2.1.12"
175 + },
176 + "engines": {
177 + "node": ">= 6"
155 } 178 }
156 }, 179 },
157 "node_modules/balanced-match": { 180 "node_modules/balanced-match": {
...@@ -1964,6 +1987,16 @@ ...@@ -1964,6 +1987,16 @@
1964 "body-parser": "^1.20.0", 1987 "body-parser": "^1.20.0",
1965 "file-type": "^15.0.0", 1988 "file-type": "^15.0.0",
1966 "form-data": "^3.0.0" 1989 "form-data": "^3.0.0"
1990 + },
1991 + "dependencies": {
1992 + "axios": {
1993 + "version": "0.21.4",
1994 + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
1995 + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
1996 + "requires": {
1997 + "follow-redirects": "^1.14.0"
1998 + }
1999 + }
1967 } 2000 }
1968 }, 2001 },
1969 "@sindresorhus/is": { 2002 "@sindresorhus/is": {
...@@ -2061,11 +2094,24 @@ ...@@ -2061,11 +2094,24 @@
2061 "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" 2094 "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
2062 }, 2095 },
2063 "axios": { 2096 "axios": {
2064 - "version": "0.21.4", 2097 + "version": "0.27.2",
2065 - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", 2098 + "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz",
2066 - "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", 2099 + "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==",
2067 "requires": { 2100 "requires": {
2068 - "follow-redirects": "^1.14.0" 2101 + "follow-redirects": "^1.14.9",
2102 + "form-data": "^4.0.0"
2103 + },
2104 + "dependencies": {
2105 + "form-data": {
2106 + "version": "4.0.0",
2107 + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
2108 + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
2109 + "requires": {
2110 + "asynckit": "^0.4.0",
2111 + "combined-stream": "^1.0.8",
2112 + "mime-types": "^2.1.12"
2113 + }
2114 + }
2069 } 2115 }
2070 }, 2116 },
2071 "balanced-match": { 2117 "balanced-match": {
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
16 "license": "MIT", 16 "license": "MIT",
17 "dependencies": { 17 "dependencies": {
18 "@line/bot-sdk": "^7.5.0", 18 "@line/bot-sdk": "^7.5.0",
19 + "axios": "^0.27.2",
19 "dotenv": "^16.0.1", 20 "dotenv": "^16.0.1",
20 "express": "^4.18.1", 21 "express": "^4.18.1",
21 "nodemon": "^2.0.16" 22 "nodemon": "^2.0.16"
......