유명현

Merge branch 'feature/line-bot-v2' into 'main'

Feature/line bot v2

## [V2]line bot
- 3사 중고매장 검색 기능, 통합 검색 기능 구현
- Refactor: app.js로 부터 line bot 관련 코드 분리
- Clean up some unessential code

See merge request !18
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 -const { sequelize } = require('./models') 5 +const { sequelize } = require("./models");
7 const database = require("./apis/database"); 6 const database = require("./apis/database");
8 7
9 // Initialize DB connection 8 // Initialize DB connection
10 -sequelize.sync({ force: false }) 9 +sequelize
11 - .then(() => { 10 + .sync({ force: false })
12 - console.log('database connection complete'); 11 + .then(() => {
13 - database.addKeyword("rtx3060", "junseok") 12 + console.log("database connection complete");
14 - database.getKeywordsByUserId("junseok") 13 + database.addKeyword("rtx3060", "junseok");
15 - database.deleteKeyword("phobyjun", "rtx3080") 14 + database.getKeywordsByUserId("junseok");
16 - database.getAllUsers() 15 + database.deleteKeyword("phobyjun", "rtx3080");
17 - database.getUsersByKeyword("rtx3060") 16 + database.getAllUsers();
18 - database.getAllKeywords() 17 + database.getUsersByKeyword("rtx3060");
19 - }) 18 + database.getAllKeywords();
20 - .catch((err) => { 19 + })
21 - console.log('database connection failed'); 20 + .catch((err) => {
22 - }); 21 + console.log("database connection failed");
22 + });
23 23
24 // Load .env configuration 24 // Load .env configuration
25 require("dotenv").config(); 25 require("dotenv").config();
...@@ -33,144 +33,11 @@ const app = express(); ...@@ -33,144 +33,11 @@ const app = express();
33 33
34 // Create post request handler for chatbot 34 // Create post request handler for chatbot
35 app.post("/webhook", line.middleware(config), (req, res) => { 35 app.post("/webhook", line.middleware(config), (req, res) => {
36 - Promise.all(req.body.events.map(handleEvent)).then((result) => 36 + Promise.all(req.body.events.map(handleEvent)).then((result) => {
37 - res.json(result) 37 + res.json(result);
38 - ); 38 + });
39 }); 39 });
40 40
41 -const client = new line.Client(config);
42 -
43 -let waitNewMamulList = []; // 매물 키워드 입력 기다리는 목록
44 -
45 -function handleEvent(event) {
46 - if (event.type !== "message" || event.message.type !== "text") {
47 - console.log(event);
48 - if (event.type == "postback") {
49 - if (event.postback.data == "new") {
50 - var found = waitNewMamulList.indexOf(event.source.userId);
51 - if (found == -1) {
52 - waitNewMamulList.push(event.source.userId);
53 - console.log(waitNewMamulList);
54 - return Promise.resolve(
55 - client.replyMessage(event.replyToken, {
56 - type: "text",
57 - text: "등록할 매물 키워드를 알려주세요!",
58 - })
59 - );
60 - } else {
61 - return Promise.resolve(
62 - client.replyMessage(event.replyToken, {
63 - type: "text",
64 - text: "등록할 매물 키워드를 알려주세요!",
65 - })
66 - );
67 - }
68 - } else if (event.postback.data == "check") {
69 - return Promise.resolve(
70 - client.replyMessage(event.replyToken, {
71 - type: "flex",
72 - altText: "등록된 매물",
73 - contents: setFlexMessage(
74 - "daangn",
75 - "RTX 3080",
76 - "1000000",
77 - "https://dnvefa72aowie.cloudfront.net/origin/article/202205/94cdd237258671d5806a70f64ab2b3c7dcd790da0384b394ef5809fe10c08ced.webp?q=95&s=1440x1440&t=inside",
78 - "https://www.daangn.com/articles/403755360"
79 - ),
80 - })
81 - );
82 - }
83 - }
84 - return Promise.resolve(null);
85 - } else {
86 - console.log(event);
87 - var found = waitNewMamulList.indexOf(event.source.userId);
88 - if (found == -1) {
89 - return Promise.resolve(
90 - client.replyMessage(event.replyToken, {
91 - type: "text",
92 - text: "왼쪽 하단 메뉴버튼(☰)을 클릭해 상호작용 해주세요!",
93 - })
94 - );
95 - } else {
96 - // TODO: 서버에 키워드 등록하는 api
97 - waitNewMamulList.splice(found, 1);
98 - console.log(waitNewMamulList[found]);
99 - return Promise.resolve(
100 - client.replyMessage(event.replyToken, {
101 - type: "text",
102 - text: "매물이 등록되었습니다!\n등록된 매물: " + event.message.text,
103 - })
104 - );
105 - }
106 - }
107 -}
108 -
109 const port = 1231; 41 const port = 1231;
110 app.listen(port); 42 app.listen(port);
111 console.log(`listening...\nport : ${port}`); 43 console.log(`listening...\nport : ${port}`);
112 -
113 -/*Push Message*/
114 -// client.pushMessage(event.source.userId, {
115 -// type: "flex",
116 -// altText: "새로운 매물이 왔어요!",
117 -// contents: setFlexMessage(
118 -// "daangn",
119 -// "RTX 3080",
120 -// "1000000",
121 -// "https://dnvefa72aowie.cloudfront.net/origin/article/202205/94cdd237258671d5806a70f64ab2b3c7dcd790da0384b394ef5809fe10c08ced.webp?q=95&s=1440x1440&t=inside",
122 -// "https://www.daangn.com/articles/403755360"
123 -// ),
124 -// })
125 -
126 -/*리치메뉴 설정*/
127 -// let richMenu = {
128 -// size: {
129 -// width: 2500,
130 -// height: 843,
131 -// },
132 -// selected: false,
133 -// name: "Nice richmenu",
134 -// chatBarText: "Tap to open",
135 -// areas: [
136 -// {
137 -// bounds: {
138 -// x: 0,
139 -// y: 0,
140 -// width: 1250,
141 -// height: 843,
142 -// },
143 -// action: {
144 -// type: "postback",
145 -// label: "new",
146 -// data: "new",
147 -// displayText: "키워드 등록",
148 -// inputOption: "openKeyboard",
149 -// fillInText: "",
150 -// },
151 -// },
152 -// {
153 -// bounds: {
154 -// x: 1250,
155 -// y: 0,
156 -// width: 1250,
157 -// height: 843,
158 -// },
159 -// action: {
160 -// type: "postback",
161 -// label: "check",
162 -// data: "check",
163 -// displayText: "최신 매물 확인",
164 -// inputOption: "openKeyboard",
165 -// fillInText: "",
166 -// },
167 -// },
168 -// ],
169 -// };
170 -//// 등록
171 -// client.createRichMenu(richMenu).then((richMenuId) => console.log(richMenuId));
172 -// client.setRichMenuImage(
173 -// "richmenu-183eff606f059b8244f0a625b54bddf1",
174 -// fs.createReadStream("./static/img/richMenu.jpg")
175 -// );
176 -// 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 + "test설명"
58 + ),
59 + })
60 + );
61 + }
62 + }
63 + return Promise.resolve(null);
64 + } else {
65 + console.log(event);
66 + var found = waitNewMamulList.indexOf(event.source.userId);
67 + if (found == -1) {
68 + return Promise.resolve(
69 + marketMultiSearch(event.message.text).then((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 "mysql2": "^2.3.3", 16 "mysql2": "^2.3.3",
...@@ -33,6 +34,14 @@ ...@@ -33,6 +34,14 @@
33 "node": ">=10" 34 "node": ">=10"
34 } 35 }
35 }, 36 },
37 + "node_modules/@line/bot-sdk/node_modules/axios": {
38 + "version": "0.21.4",
39 + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
40 + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
41 + "dependencies": {
42 + "follow-redirects": "^1.14.0"
43 + }
44 + },
36 "node_modules/@sindresorhus/is": { 45 "node_modules/@sindresorhus/is": {
37 "version": "0.14.0", 46 "version": "0.14.0",
38 "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", 47 "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz",
...@@ -167,11 +176,25 @@ ...@@ -167,11 +176,25 @@
167 "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" 176 "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
168 }, 177 },
169 "node_modules/axios": { 178 "node_modules/axios": {
170 - "version": "0.21.4", 179 + "version": "0.27.2",
171 - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", 180 + "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz",
172 - "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", 181 + "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==",
173 "dependencies": { 182 "dependencies": {
174 - "follow-redirects": "^1.14.0" 183 + "follow-redirects": "^1.14.9",
184 + "form-data": "^4.0.0"
185 + }
186 + },
187 + "node_modules/axios/node_modules/form-data": {
188 + "version": "4.0.0",
189 + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
190 + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
191 + "dependencies": {
192 + "asynckit": "^0.4.0",
193 + "combined-stream": "^1.0.8",
194 + "mime-types": "^2.1.12"
195 + },
196 + "engines": {
197 + "node": ">= 6"
175 } 198 }
176 }, 199 },
177 "node_modules/balanced-match": { 200 "node_modules/balanced-match": {
...@@ -2259,6 +2282,16 @@ ...@@ -2259,6 +2282,16 @@
2259 "body-parser": "^1.20.0", 2282 "body-parser": "^1.20.0",
2260 "file-type": "^15.0.0", 2283 "file-type": "^15.0.0",
2261 "form-data": "^3.0.0" 2284 "form-data": "^3.0.0"
2285 + },
2286 + "dependencies": {
2287 + "axios": {
2288 + "version": "0.21.4",
2289 + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
2290 + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
2291 + "requires": {
2292 + "follow-redirects": "^1.14.0"
2293 + }
2294 + }
2262 } 2295 }
2263 }, 2296 },
2264 "@sindresorhus/is": { 2297 "@sindresorhus/is": {
...@@ -2374,11 +2407,24 @@ ...@@ -2374,11 +2407,24 @@
2374 "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" 2407 "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
2375 }, 2408 },
2376 "axios": { 2409 "axios": {
2377 - "version": "0.21.4", 2410 + "version": "0.27.2",
2378 - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", 2411 + "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz",
2379 - "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", 2412 + "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==",
2380 "requires": { 2413 "requires": {
2381 - "follow-redirects": "^1.14.0" 2414 + "follow-redirects": "^1.14.9",
2415 + "form-data": "^4.0.0"
2416 + },
2417 + "dependencies": {
2418 + "form-data": {
2419 + "version": "4.0.0",
2420 + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
2421 + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
2422 + "requires": {
2423 + "asynckit": "^0.4.0",
2424 + "combined-stream": "^1.0.8",
2425 + "mime-types": "^2.1.12"
2426 + }
2427 + }
2382 } 2428 }
2383 }, 2429 },
2384 "balanced-match": { 2430 "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 "mysql2": "^2.3.3", 22 "mysql2": "^2.3.3",
......