diff --git a/src/backend/handlers/item.js b/src/backend/handlers/item.js index 3081ea6..3d51935 100644 --- a/src/backend/handlers/item.js +++ b/src/backend/handlers/item.js @@ -30,7 +30,7 @@ const list = async (event) => { } else if (result.length == 0) { return responseTemplate.itemListFail("등록된 상품이 없습니다."); } else { - return responseTemplate.itemListSuccess(result); + return responseTemplate.itemListSuccess(result, "list"); } }; @@ -44,7 +44,7 @@ const searchCategory = async (event) => { } else if (result.length == 0) { return responseTemplate.itemListFail("등록된 상품이 없습니다."); } else { - return responseTemplate.itemListSuccess(result); + return responseTemplate.itemListSuccess(result, "search"); } }; @@ -58,26 +58,33 @@ const searchKeyword = async (event) => { } else if (result.length == 0) { return responseTemplate.itemListFail("등록된 상품이 없습니다."); } else { - return responseTemplate.itemListSuccess(result); + return responseTemplate.itemListSuccess(result, "search"); } }; const detail = async (event) => { const extras = parser.getExtras(event); + const mode = extras["mode"]; + const userId = extras["userId"]; const itemId = extras["itemId"]; const item = await database.getItem(itemId); if (item != null) { - return responseTemplate.itemDetail(item); + const user = (mode == "search" ? await database.getUser(userId) : null); + if (user != null) { + return responseTemplate.itemDetail(item, mode, user); + } else { + return responseTemplate.itemListFail("상품 조회에 실패했습니다."); + } } else { return responseTemplate.itemListFail("상품 조회에 실패했습니다."); } }; module.exports = { - registration, - list, - searchCategory, - searchKeyword, - detail + registration, + list, + searchCategory, + searchKeyword, + detail }; diff --git a/src/backend/package-lock.json b/src/backend/package-lock.json index 9eeb0d3..ec3d28d 100644 --- a/src/backend/package-lock.json +++ b/src/backend/package-lock.json @@ -54,9 +54,10 @@ "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, "aws-sdk": { - "version": "2.585.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.585.0.tgz", - "integrity": "sha512-T3JG4JZUmELqxT4hwJa93xns/TWIllaeYoyhRPGwXUj78vhCYJUiigtU6WRYLu84AMoZAGT/pVkARH7vfxpq9Q==", + "version": "2.586.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.586.0.tgz", + "integrity": "sha512-Y5AGW8qRaa81jD1YahzLZLpQY62u3pmi2nlBNDMMR0Z4Ra5H90RgPAomKQe2JX+5Z6fzGFU7nNkYaScsZ6XFqw==", + "dev": true, "requires": { "buffer": "4.9.1", "events": "1.1.1", @@ -83,6 +84,7 @@ "version": "4.9.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", + "dev": true, "requires": { "base64-js": "^1.0.2", "ieee754": "^1.1.4", @@ -193,7 +195,8 @@ "events": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", - "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=" + "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=", + "dev": true }, "find-up": { "version": "3.0.0", @@ -282,7 +285,8 @@ "jmespath": { "version": "0.15.0", "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", - "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=" + "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=", + "dev": true }, "jsonfile": { "version": "4.0.0", @@ -383,7 +387,8 @@ "punycode": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", + "dev": true }, "qrcode": { "version": "1.4.4", @@ -423,7 +428,8 @@ "querystring": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "dev": true }, "readable-stream": { "version": "2.3.6", @@ -457,7 +463,8 @@ "sax": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", - "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o=" + "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o=", + "dev": true }, "serverless-plugin-warmup": { "version": "4.7.1-rc.1", @@ -562,6 +569,7 @@ "version": "0.10.3", "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", "integrity": "sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ=", + "dev": true, "requires": { "punycode": "1.3.2", "querystring": "0.2.0" @@ -575,7 +583,8 @@ "uuid": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "dev": true }, "which-module": { "version": "2.0.0", @@ -596,6 +605,7 @@ "version": "0.4.19", "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", + "dev": true, "requires": { "sax": ">=0.6.0", "xmlbuilder": "~9.0.1" @@ -604,7 +614,8 @@ "xmlbuilder": { "version": "9.0.7", "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", - "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=" + "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=", + "dev": true }, "y18n": { "version": "4.0.0", diff --git a/src/backend/package.json b/src/backend/package.json index 26f058c..be23316 100644 --- a/src/backend/package.json +++ b/src/backend/package.json @@ -9,13 +9,13 @@ "author": "hakuhagu", "license": "MIT", "dependencies": { - "aws-sdk": "^2.585.0", "mysql": "^2.17.1", "nodemailer": "^6.4.0", "qrcode": "^1.4.4", "sync-request": "^6.1.0" }, "devDependencies": { + "aws-sdk": "^2.586.0", "serverless-plugin-warmup": "^4.7.1-rc.1" } } diff --git a/src/backend/responses/common.js b/src/backend/responses/common.js index 07e5582..3c1d592 100644 --- a/src/backend/responses/common.js +++ b/src/backend/responses/common.js @@ -26,5 +26,5 @@ module.exports.welcome = () => { const userInfoCardBody = builder.getBasicCardBody("회원 정보", "회원 정보를 조회하거나 수정합니다.", userInfoThumbnail, [userInfoQueryButton, userInfoOpenProfileButton, userInfoTimeTableButton]); // Build response - return builder.buildResponse([builder.getCarousel("basicCard", [buyerCardBody, sellerCardBody, userInfoCardBody])]); + return builder.buildResponse([builder.getCarousel("basicCard", [buyerCardBody, sellerCardBody, userInfoCardBody])], false); }; diff --git a/src/backend/responses/item.js b/src/backend/responses/item.js index fc01903..4dac456 100644 --- a/src/backend/responses/item.js +++ b/src/backend/responses/item.js @@ -28,27 +28,43 @@ module.exports.itemRegistrationFail = (errorMessage) => { return builder.buildResponse([resultCard]); }; -module.exports.itemListSuccess = (itemList) => { - // Construct commerce cards - const bodys = []; - for (var key in itemList) { - if (key > 9) { - break; +module.exports.itemListSuccess = (itemList, mode="search") => { + const modes = ["list", "search"]; + + if (modes.includes(mode)) { + // Construct commerce cards + const bodys = []; + for (var key in itemList) { + if (key > 9) { + break; + } + const item = itemList[key]; + const resultUserId = (item.userId != undefined ? item.userId : null); + const resultItemId = item.itemId; + const resultThumbnail = builder.getThumbnail(item.item_image[0]); + const resultTitle = item.item_name; + const resultDescription = item.item_detail + "\n" + item.item_date; + const resultPrice = item.item_price; + const resultNickname = (item.nickname != undefined ? item.nickname : null); + const buttons = []; + if (mode == "list") { + buttons.push(builder.getButton("상세정보", "block", "상세정보", resource.itemDetailBlockId, {itemId: resultItemId, mode: "list"})); + buttons.push(builder.getButton("삭제", "block", "삭제", resource.itemDeleteBlockId, {itemId: resultItemId})); + } else if (mode == "search") { + buttons.push(builder.getButton("구매", "block", "구매", resource.itemBuyBlockId, {userId: resultUserId, itemId: resultItemId})); + buttons.push(builder.getButton("상세정보", "block", "상세정보", resource.itemDetailBlockId, {userId: resultUserId, itemId: resultItemId, mode: "search"})); + // buttons.push(builder.getButton("신고", "block", "신고", resource.itemReportBlockId, {userId: resultUserId, itemId: resultItemId})); + } else if (mode == "transaction") { + buttons.push(builder.getButton("판매", "block", "판매", resource.itemSellBlockId, {itemId: resultItemId})); + } + bodys.push(builder.getCommerceCardBody(resultTitle, resultDescription, resultPrice, resultThumbnail, resultNickname, buttons)); } - const item = itemList[key]; - const resultItemId = item.itemId; - const resultThumbnail = builder.getThumbnail(item.item_image[0]); - const resultTitle = item.item_name; - const resultDescription = item.item_detail; - const resultPrice = item.item_price; - const resultNickname = (item.nickname != undefined ? item.nickname : null); - const resultOpenprofile = item.openprofile; - const resultMainMenuButton = builder.getButton("상세정보", "block", "상세정보", "5decfa26ffa74800014b098e", {itemId: resultItemId}); - bodys.push(builder.getCommerceCardBody(resultTitle, resultDescription, resultPrice, resultThumbnail, resultNickname, [resultMainMenuButton])); - } - // Build response - return builder.buildResponse([builder.getCarousel("commerceCard", bodys)]); + // Build response + return builder.buildResponse([builder.getCarousel("commerceCard", bodys)]); + } else { + throw "mode type error"; + } }; module.exports.itemListFail = (errorMessage) => { @@ -63,15 +79,17 @@ module.exports.itemListFail = (errorMessage) => { return builder.buildResponse([resultCard]); }; -module.exports.itemDetail = (item) => { +module.exports.itemDetail = (item, mode="list", user=null) => { // Construct registration guide const resultThumbnail = builder.getThumbnail(item.item_image[0]); - const resultTitle = item.item_name; - const resultDescription = item.item_detail; - const resultPrice = item.item_price; - const resultMainMenuButton = builder.getButton("처음으로", "block", "처음으로", resource.welcomeBlockId); - const resultCard = builder.getCommerceCard(resultTitle, resultDescription, resultPrice, resultThumbnail, null, [resultMainMenuButton]); + const resultUserId = (user.userId != undefined ? user.userId : null); + const resultItemId = item.itemId; + const resultTitle = item.item_name + "(" + item.item_price + "원)"; + const resultDescription = item.item_detail + "\n";// + item.item_date; + const resultMainMenuButton = (mode == "list" ? builder.getButton("삭제", "block", "삭제", resource.itemDeleteBlockId) : builder.getButton("구매", "block", "구매", resource.itemBuyBlockId, {userId: resultUserId, itemId: resultItemId})); + const resultCard1 = builder.getBasicCardBody(resultTitle, resultDescription, "", [resultMainMenuButton, resultMainMenuButton]); + const resultCard2 = builder.getBasicCardBody("", "uiiyfiyiyfi", resultThumbnail); // Build response - return builder.buildResponse([resultCard]); + return builder.buildResponse([builder.getCarousel("basicCard", [resultCard1, resultCard2, resultCard2])]); }; diff --git a/src/backend/utils/builder.js b/src/backend/utils/builder.js index 73b36ce..0236d69 100644 --- a/src/backend/utils/builder.js +++ b/src/backend/utils/builder.js @@ -1,12 +1,15 @@ 'use strict'; -const buildResponse = (outputs) => { +const resource = require("./resource"); + +const buildResponse = (outputs, quickMain=true) => { return { statusCode: 200, body: JSON.stringify({ version: "2.0", template: { - outputs: outputs + outputs: outputs, + quickReplies: (quickMain == true ? [getQuickReply("처음으로", "block", "처음으로", resource.welcomeBlockId)] : []) } }) }; @@ -19,6 +22,25 @@ const buildAWSResponse = (body) => { }; } +const getQuickReply = (label, action, message, blockId=undefined, extra=undefined) => { + const actionTypes = ["message", "block"]; + + if (actionTypes.includes(action)) { + var quickReply = { + label: label, + action: action, + messageText: message + }; + switch (action) { + case "block": quickReply["blockId"] = blockId; + if (extra !== undefined) quickReply["extra"] = extra; + } + return quickReply; + } else { + throw "action type error"; + } +} + const getButton = (label, action, data, blockId=undefined, extra=undefined) => { const actionTypes = ["webLink", "osLink", "message", "phone", "share", "block"]; @@ -118,17 +140,26 @@ const getCarousel = (type, cards) => { } } -const getCommerceCardBody = (title, description, price, thumbnail, nickname, buttons=[]) => { - const body = { - description: title + "\n" + description, - price: price, - currency: "won", - thumbnails: [ thumbnail ], - buttons: buttons - }; +const getCommerceCardBody = (title, description, price, thumbnail, nickname, buttons=null) => { + const body = {}; + if (title != null || description != null) { + var str = (title != null ? title + "\n" : ""); + str += (description != null ? description : ""); + body["description"] = str; + } + if (price != null) { + body["price"] = price; + body["currency"] = "won" + } + if (thumbnail != null) { + body["thumbnails"] = [ thumbnail ]; + } if (nickname != null) { body["profile"] = { nickname: nickname } } + if (buttons != null) { + body["buttons"] = buttons; + } return body; } diff --git a/src/backend/utils/resource.js b/src/backend/utils/resource.js index fd74949..18dac01 100644 --- a/src/backend/utils/resource.js +++ b/src/backend/utils/resource.js @@ -27,4 +27,9 @@ module.exports = { userInfoQueryBlockId: "5de3d56d8192ac0001d65d18", userInfoOpenProfileBlockId: "5de3d5958192ac0001d65d1a", userInfoTimeTableBlockId: "5de3d59d8192ac0001d65d1c", + itemDetailBlockId: "5decfa26ffa74800014b098e", + itemDeleteBlockId: "5decfa26ffa74800014b098e", // Temp + itemBuyBlockId: "5decfa26ffa74800014b098e", // Temp + itemReportBlockId: "5decfa26ffa74800014b098e", // Temp + itemSellBlockId: "5decfa26ffa74800014b098e", // Temp };