유명현

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

Feature/line bot refactor

minor 기능 구현 (UX) 및 코드 수정

See merge request !23
1 -const setKeywordsFlexMessage = require("../message/setKeywordsFlexMessage") 1 +const setKeywordsFlexMessage = require("../message/setKeywordsFlexMessage");
2 2
3 const db = require("../../apis/database"); 3 const db = require("../../apis/database");
4 4
5 const checkKeywords = (client, event) => { 5 const checkKeywords = (client, event) => {
6 db.getKeywordsByUserId(event.source.userId).then((keywords) => { 6 db.getKeywordsByUserId(event.source.userId).then((keywords) => {
7 flexMessage = setKeywordsFlexMessage(keywords); 7 flexMessage = setKeywordsFlexMessage(keywords);
8 - client.replyMessage(event.replyToken, flexMessage) 8 + client.pushMessage(event.source.userId, flexMessage);
9 - }) 9 + });
10 }; 10 };
11 11
12 module.exports = { checkKeywords }; 12 module.exports = { checkKeywords };
......
1 const { marketMultiSearch } = require("../search/marketSearch"); 1 const { marketMultiSearch } = require("../search/marketSearch");
2 const setCarouselMessage = require("../message/setCarouselMessage"); 2 const setCarouselMessage = require("../message/setCarouselMessage");
3 +
3 // Database APIs 4 // Database APIs
4 const db = require("../../apis/database"); 5 const db = require("../../apis/database");
5 -// API List
6 -// database.addKeyword = async function(keyword, userId)
7 -// database.deleteKeyword = async function(userId, keyword)
8 -// database.getKeywordsByUserId = async function(userId)
9 -// database.getUsersByKeyword = async function(keyword)
10 -// database.getAllUsers = async function()
11 -// database.getAllKeywords = async function()
12 6
13 const multiCheckMamul = (client) => { 7 const multiCheckMamul = (client) => {
14 db.getAllKeywords().then((keywords) => { 8 db.getAllKeywords().then((keywords) => {
15 for (let i = 0, pending = Promise.resolve(); i < keywords.length; i++) { 9 for (let i = 0, pending = Promise.resolve(); i < keywords.length; i++) {
16 pending = db.getUsersByKeyword(keywords[i]).then((userIds) => { 10 pending = db.getUsersByKeyword(keywords[i]).then((userIds) => {
17 marketMultiSearch(keywords[i]).then((res) => { 11 marketMultiSearch(keywords[i]).then((res) => {
18 - client.multicast(userIds, [setCarouselMessage(res)]); 12 + client.multicast(userIds, [setCarouselMessage(res, keywords[i])]);
19 }); 13 });
20 }); 14 });
21 } 15 }
...@@ -24,11 +18,11 @@ const multiCheckMamul = (client) => { ...@@ -24,11 +18,11 @@ const multiCheckMamul = (client) => {
24 18
25 const checkMamul = (client, userId) => { 19 const checkMamul = (client, userId) => {
26 db.getKeywordsByUserId(userId).then((keywords) => { 20 db.getKeywordsByUserId(userId).then((keywords) => {
27 - for (let i = 0, pending = Promise.resolve(); i< keywords.length; i++) { 21 + for (let i = 0, pending = Promise.resolve(); i < keywords.length; i++) {
28 pending = marketMultiSearch(keywords[i]).then((res) => { 22 pending = marketMultiSearch(keywords[i]).then((res) => {
29 - client.pushMessage(userId, setCarouselMessage(res)); 23 + client.pushMessage(userId, setCarouselMessage(res, keywords[i]));
30 }); 24 });
31 - }; 25 + }
32 }); 26 });
33 }; 27 };
34 28
......
1 // Line chatbot + Message generate functions 1 // Line chatbot + Message generate functions
2 const line = require("@line/bot-sdk"); 2 const line = require("@line/bot-sdk");
3 -const setFlexMessage = require("./message/setFlexMessage");
4 const setCarouselMessage = require("./message/setCarouselMessage"); 3 const setCarouselMessage = require("./message/setCarouselMessage");
5 -const setKeywordsFlexMessage = require("./message/setKeywordsFlexMessage")
6 4
7 // Market Search 5 // Market Search
8 -const { daangnSingleSearch } = require("./search/daangnSearch");
9 -const { daangnMultiSearch } = require("./search/daangnSearch");
10 -const { joongnaSingleSearch } = require("./search/joongnaSearch");
11 -const { joongnaMultiSearch } = require("./search/joongnaSearch");
12 -const { bunjangSingleSearch } = require("./search/bunjangSearch");
13 -const { bunjangMultiSearch } = require("./search/bunjangSearch");
14 const { marketMultiSearch } = require("./search/marketSearch"); 6 const { marketMultiSearch } = require("./search/marketSearch");
15 7
16 -// File search - Will be deleted (Unused) 8 +// File search
17 const fs = require("fs"); 9 const fs = require("fs");
18 10
19 // Cron for Mamul Notification 11 // Cron for Mamul Notification
...@@ -24,13 +16,6 @@ const job = schedule.scheduleJob("0 */1 * * *", () => { ...@@ -24,13 +16,6 @@ const job = schedule.scheduleJob("0 */1 * * *", () => {
24 16
25 // Database APIs 17 // Database APIs
26 const db = require("../apis/database"); 18 const db = require("../apis/database");
27 -// API List
28 -// database.addKeyword = async function(keyword, userId)
29 -// database.deleteKeyword = async function(userId, keyword)
30 -// database.getKeywordsByUserId = async function(userId)
31 -// database.getUsersByKeyword = async function(keyword)
32 -// database.getAllUsers = async function()
33 -// database.getAllKeywords = async function()
34 19
35 // Import credentials for Line chatbot 20 // Import credentials for Line chatbot
36 require("dotenv").config({ path: __dirname + "/../config/.env" }); 21 require("dotenv").config({ path: __dirname + "/../config/.env" });
...@@ -41,8 +26,7 @@ const config = { ...@@ -41,8 +26,7 @@ const config = {
41 26
42 // Cron for Mamul Notification 27 // Cron for Mamul Notification
43 const { multiCheckMamul, checkMamul } = require("./check/checkMamul"); 28 const { multiCheckMamul, checkMamul } = require("./check/checkMamul");
44 -const { checkKeywords } = require("./check/checkKeywords") 29 +const { checkKeywords } = require("./check/checkKeywords");
45 -
46 30
47 // Line chat bot client & event 31 // Line chat bot client & event
48 const client = new line.Client(config); 32 const client = new line.Client(config);
...@@ -74,9 +58,7 @@ function handleEvent(event) { ...@@ -74,9 +58,7 @@ function handleEvent(event) {
74 ); 58 );
75 } 59 }
76 } else if (event.postback.data == "checkItems") { 60 } else if (event.postback.data == "checkItems") {
77 - return Promise.resolve( 61 + return Promise.resolve(checkMamul(client, event.source.userId));
78 - checkMamul(client, event.source.userId),
79 - );
80 } else if (event.postback.data == "deleteKeyword") { 62 } else if (event.postback.data == "deleteKeyword") {
81 var foundDelete = waitDeleteMamulList.indexOf(event.source.userId); 63 var foundDelete = waitDeleteMamulList.indexOf(event.source.userId);
82 if (foundDelete == -1) { 64 if (foundDelete == -1) {
...@@ -90,9 +72,7 @@ function handleEvent(event) { ...@@ -90,9 +72,7 @@ function handleEvent(event) {
90 ); 72 );
91 } 73 }
92 } else if (event.postback.data == "checkKeywords") { 74 } else if (event.postback.data == "checkKeywords") {
93 - return Promise.resolve( 75 + return Promise.resolve(checkKeywords(client, event));
94 - checkKeywords(client, event)
95 - )
96 } 76 }
97 } 77 }
98 return Promise.resolve(null); 78 return Promise.resolve(null);
...@@ -110,7 +90,10 @@ function handleEvent(event) { ...@@ -110,7 +90,10 @@ function handleEvent(event) {
110 text: `매물이 등록되었습니다!\n등록된 매물: ${event.message.text}`, 90 text: `매물이 등록되었습니다!\n등록된 매물: ${event.message.text}`,
111 }), 91 }),
112 marketMultiSearch(event.message.text).then((res) => { 92 marketMultiSearch(event.message.text).then((res) => {
113 - client.pushMessage(event.source.userId, setCarouselMessage(res)); 93 + client.pushMessage(
94 + event.source.userId,
95 + setCarouselMessage(res, event.message.text)
96 + );
114 }) 97 })
115 ); 98 );
116 } 99 }
...@@ -121,11 +104,15 @@ function handleEvent(event) { ...@@ -121,11 +104,15 @@ function handleEvent(event) {
121 console.log(waitDeleteMamulList[foundDelete]); 104 console.log(waitDeleteMamulList[foundDelete]);
122 return Promise.resolve( 105 return Promise.resolve(
123 db.deleteKeyword(event.source.userId, event.message.text), 106 db.deleteKeyword(event.source.userId, event.message.text),
124 - client.replyMessage(event.replyToken, { 107 + client
108 + .replyMessage(event.replyToken, {
125 type: "text", 109 type: "text",
126 text: `매물이 삭제되었습니다!\n삭제된 매물: ${event.message.text}`, 110 text: `매물이 삭제되었습니다!\n삭제된 매물: ${event.message.text}`,
127 }) 111 })
128 - ) 112 + .then(() => {
113 + checkKeywords(client, event);
114 + })
115 + );
129 } 116 }
130 } 117 }
131 } 118 }
...@@ -253,11 +240,10 @@ module.exports = { handleEvent, config }; ...@@ -253,11 +240,10 @@ module.exports = { handleEvent, config };
253 // }; 240 // };
254 // 등록 241 // 등록
255 // client.createRichMenu(richMenu).then((richMenuId) => { 242 // client.createRichMenu(richMenu).then((richMenuId) => {
256 -// console.log(richMenuId) 243 +// console.log(richMenuId);
257 // }); 244 // });
258 // client.setRichMenuImage( 245 // client.setRichMenuImage(
259 -// "richmenu-ab4bba1c3c9235be50e3e8924fabd940", 246 +// "richmenu-de8d05638cd98d81e765576986376314",
260 // fs.createReadStream("./static/image/richMenu.png") 247 // fs.createReadStream("./static/image/richMenu.png")
261 // ); 248 // );
262 -// client.setDefaultRichMenu("richmenu-ab4bba1c3c9235be50e3e8924fabd940"); 249 +// client.setDefaultRichMenu("richmenu-de8d05638cd98d81e765576986376314");
263 -//
......
1 const setFlexMessage = require("./setFlexMessage"); 1 const setFlexMessage = require("./setFlexMessage");
2 2
3 -function setCarouselMessage(mamuls) { 3 +function setCarouselMessage(mamuls, keyword) {
4 let flexMessages = []; 4 let flexMessages = [];
5 let flexMessage = {}; 5 let flexMessage = {};
6 - if ( 6 + if (mamuls[0] == undefined) {
7 - mamuls[0] == undefined &&
8 - mamuls[1] == undefined &&
9 - mamuls[2] == undefined
10 - ) {
11 let nonMamulMessage = { 7 let nonMamulMessage = {
12 type: "flex", 8 type: "flex",
13 - altText: "매물 검색 에러", 9 + altText: `${keyword} 매물은 아직 없어요!`,
14 contents: setFlexMessage( 10 contents: setFlexMessage(
15 "-", 11 "-",
16 "매물이 없습니다!", 12 "매물이 없습니다!",
...@@ -20,6 +16,20 @@ function setCarouselMessage(mamuls) { ...@@ -20,6 +16,20 @@ function setCarouselMessage(mamuls) {
20 "-" 16 "-"
21 ), 17 ),
22 }; 18 };
19 + nonMamulMessage["contents"]["header"] = {
20 + type: "box",
21 + layout: "horizontal",
22 + contents: [
23 + { type: "text", text: "매무리 봇", size: "sm", color: "#1DB446" },
24 + {
25 + type: "text",
26 + text: `키워드: ${keyword}`,
27 + align: "end",
28 + color: "#1DB446",
29 + weight: "bold",
30 + },
31 + ],
32 + };
23 return nonMamulMessage; 33 return nonMamulMessage;
24 } 34 }
25 for (i = 0; i < mamuls.length; i++) { 35 for (i = 0; i < mamuls.length; i++) {
...@@ -51,9 +61,48 @@ function setCarouselMessage(mamuls) { ...@@ -51,9 +61,48 @@ function setCarouselMessage(mamuls) {
51 61
52 if (mamuls[i]["extraInfo"] == undefined || mamuls[i]["extraInfo"] == "") { 62 if (mamuls[i]["extraInfo"] == undefined || mamuls[i]["extraInfo"] == "") {
53 mamuls[i]["extraInfo"] = "없음"; 63 mamuls[i]["extraInfo"] = "없음";
54 - } else if (mamuls[i]["extraInfo"].length > 150) { 64 + } else {
55 - mamuls[i]["extraInfo"] = mamuls[i]["extraInfo"].slice(0, 150) + "\n..."; 65 + if (
66 + mamuls[i]["platform"] === "joongna" ||
67 + mamuls[i]["platform"] === "중고나라"
68 + ) {
69 + let searchDot = mamuls[i]["extraInfo"].indexOf("...");
70 + if (searchDot !== -1) {
71 + mamuls[i]["extraInfo"] = mamuls[i]["extraInfo"].slice(0, searchDot);
72 + }
73 + }
74 +
75 + console.log(`unparsed extraInfo : \n${mamuls[i]["extraInfo"]}`);
76 + let searchValue = "\n";
77 + let pos = 0;
78 + let foundPos = 0;
79 + for (let j = 0; j < 4 && foundPos !== -1; j++) {
80 + foundPos = mamuls[i]["extraInfo"].indexOf(searchValue, pos);
81 + pos = foundPos + 1;
82 + }
83 + console.log(`pos: ${pos}`);
84 + if (foundPos !== -1) {
85 + mamuls[i]["extraInfo"] =
86 + mamuls[i]["extraInfo"].slice(0, foundPos) + "\n...";
87 + console.log(`parsed extraInfo : \n${mamuls[i]["extraInfo"]}`);
88 + }
89 + if (mamuls[i]["extraInfo"].length > 40) {
90 + mamuls[i]["extraInfo"] =
91 + mamuls[i]["extraInfo"].slice(0, 40) + "\n...";
92 + console.log(`parsed extraInfo : \n${mamuls[i]["extraInfo"]}`);
93 + }
56 } 94 }
95 + // } else if (mamuls[i]["extraInfo"].length > 70) {
96 + // mamuls[i]["extraInfo"] = mamuls[i]["extraInfo"].slice(0, 70) + "\n...";
97 + // } else {
98 +
99 + // }
100 + // else if (mamuls[i]["extraInfo"].indexOf("\n") !== -1) {
101 + // console.log(mamuls[i]["extraInfo"].indexOf("\n", 4));
102 + // let slicePoint = mamuls[i]["extraInfo"].indexOf("\n", 4);
103 + // mamuls[i]["extraInfo"] =
104 + // mamuls[i]["extraInfo"].slice(0, slicePoint) + "\n...";
105 + // }
57 106
58 flexMessage = setFlexMessage( 107 flexMessage = setFlexMessage(
59 mamuls[i]["platform"], 108 mamuls[i]["platform"],
...@@ -69,10 +118,23 @@ function setCarouselMessage(mamuls) { ...@@ -69,10 +118,23 @@ function setCarouselMessage(mamuls) {
69 continue; 118 continue;
70 } 119 }
71 } 120 }
72 - 121 + flexMessages[0]["header"] = {
122 + type: "box",
123 + layout: "horizontal",
124 + contents: [
125 + { type: "text", text: "매무리 봇", size: "sm", color: "#1DB446" },
126 + {
127 + type: "text",
128 + text: `키워드: ${keyword}`,
129 + align: "end",
130 + color: "#1DB446",
131 + weight: "bold",
132 + },
133 + ],
134 + };
73 let carouselMessage = { 135 let carouselMessage = {
74 type: "flex", 136 type: "flex",
75 - altText: "Carousel mamul message", 137 + altText: `${keyword} 매무리가 도착했어요!`,
76 contents: { 138 contents: {
77 type: "carousel", 139 type: "carousel",
78 contents: flexMessages, 140 contents: flexMessages,
......
...@@ -44,46 +44,6 @@ function setFlexMessage( ...@@ -44,46 +44,6 @@ function setFlexMessage(
44 weight: "bold", 44 weight: "bold",
45 size: "xl", 45 size: "xl",
46 }, 46 },
47 - // {
48 - // type: "box",
49 - // layout: "baseline",
50 - // margin: "md",
51 - // contents: [
52 - // {
53 - // type: "icon",
54 - // size: "sm",
55 - // url: "https://scdn.line-apps.com/n/channel_devcenter/img/fx/review_gold_star_28.png",
56 - // },
57 - // {
58 - // type: "icon",
59 - // size: "sm",
60 - // url: "https://scdn.line-apps.com/n/channel_devcenter/img/fx/review_gold_star_28.png",
61 - // },
62 - // {
63 - // type: "icon",
64 - // size: "sm",
65 - // url: "https://scdn.line-apps.com/n/channel_devcenter/img/fx/review_gold_star_28.png",
66 - // },
67 - // {
68 - // type: "icon",
69 - // size: "sm",
70 - // url: "https://scdn.line-apps.com/n/channel_devcenter/img/fx/review_gold_star_28.png",
71 - // },
72 - // {
73 - // type: "icon",
74 - // size: "sm",
75 - // url: "https://scdn.line-apps.com/n/channel_devcenter/img/fx/review_gray_star_28.png",
76 - // },
77 - // {
78 - // type: "text",
79 - // text: "4.0",
80 - // size: "sm",
81 - // color: "#999999",
82 - // margin: "md",
83 - // flex: 0,
84 - // },
85 - // ],
86 - // },
87 { 47 {
88 type: "box", 48 type: "box",
89 layout: "vertical", 49 layout: "vertical",
......
...@@ -17,19 +17,19 @@ function setKeywordsFlexMessage(keywords) { ...@@ -17,19 +17,19 @@ function setKeywordsFlexMessage(keywords) {
17 text: "등록된 키워드", 17 text: "등록된 키워드",
18 weight: "bold", 18 weight: "bold",
19 size: "xxl", 19 size: "xxl",
20 - margin: "md" 20 + margin: "md",
21 }, 21 },
22 { 22 {
23 type: "separator", 23 type: "separator",
24 - margin: "xxl" 24 + margin: "xxl",
25 }, 25 },
26 { 26 {
27 type: "box", 27 type: "box",
28 layout: "vertical", 28 layout: "vertical",
29 contents: [], 29 contents: [],
30 - margin: "md" 30 + margin: "md",
31 - } 31 + },
32 - ] 32 + ],
33 }, 33 },
34 }; 34 };
35 35
...@@ -40,9 +40,9 @@ function setKeywordsFlexMessage(keywords) { ...@@ -40,9 +40,9 @@ function setKeywordsFlexMessage(keywords) {
40 40
41 return { 41 return {
42 type: "flex", 42 type: "flex",
43 - altText: "키워드 조회 오류", 43 + altText: "매무리 키워드 확인",
44 - contents: flexMessage 44 + contents: flexMessage,
45 - } 45 + };
46 } 46 }
47 47
48 function createKeywordTextBox(keyword) { 48 function createKeywordTextBox(keyword) {
...@@ -51,8 +51,8 @@ function createKeywordTextBox(keyword) { ...@@ -51,8 +51,8 @@ function createKeywordTextBox(keyword) {
51 text: keyword, 51 text: keyword,
52 size: "lg", 52 size: "lg",
53 align: "center", 53 align: "center",
54 - margin: "md" 54 + margin: "md",
55 - } 55 + };
56 } 56 }
57 57
58 module.exports = setKeywordsFlexMessage; 58 module.exports = setKeywordsFlexMessage;
......
1 -const { daangnSingleSearch } = require("./daangnSearch"); 1 +const { daangnMultiSearch } = require("./daangnSearch");
2 -const { bunjangSingleSearch } = require("./bunjangSearch"); 2 +const { bunjangMultiSearch } = require("./bunjangSearch");
3 -const { joongnaSingleSearch } = require("./joongnaSearch"); 3 +const { joongnaMultiSearch } = require("./joongnaSearch");
4 -const setCarouselMessage = require("../message/setCarouselMessage");
5 4
6 const marketMultiSearch = (keyword) => { 5 const marketMultiSearch = (keyword) => {
7 const result = []; 6 const result = [];
8 return new Promise((resolve, reject) => { 7 return new Promise((resolve, reject) => {
9 - daangnSingleSearch(keyword).then((res) => { 8 + daangnMultiSearch(keyword).then((res) => {
10 - result.push(res); 9 + console.log(`daangn: ${res}`);
11 - bunjangSingleSearch(keyword).then((res) => { 10 + if (res !== undefined && res !== null) {
12 - result.push(res); 11 + for (let i = 0; i < res.length && i < 4; i++) {
13 - joongnaSingleSearch(keyword).then((res) => { 12 + result.push(res[i]);
14 - result.push(res); 13 + }
14 + }
15 + bunjangMultiSearch(keyword).then((res) => {
16 + console.log(`bunjang: ${res}`);
17 + if (res !== undefined && res !== null) {
18 + for (let i = 0; i < res.length && i < 4; i++) {
19 + result.push(res[i]);
20 + }
21 + }
22 + joongnaMultiSearch(keyword).then((res) => {
23 + console.log(`joongna: ${res}`);
24 + if (res !== undefined && res !== null) {
25 + for (let i = 0; i < res.length && i < 4; i++) {
26 + result.push(res[i]);
27 + }
28 + }
15 resolve(result); 29 resolve(result);
16 }); 30 });
17 }); 31 });
......