From acd978c7497f629a4f37797ba95caaf5a8c142a8 Mon Sep 17 00:00:00 2001 From: sjsjmine129 Date: Wed, 24 Jan 2024 21:02:36 +0900 Subject: [PATCH] init --- .github/workflows/deploy_to_lambda.yml | 40 + .gitignore | 8 + .npmignore | 1 + .prettierrc | 3 + actinoFunnelLogger.js | 31 + authtoken.js | 49 + db.js | 86 ++ events/.DS_Store | Bin 0 -> 8196 bytes events/apple_login_test.json | 12 + events/auth/get_auth_checkToken.json | 10 + events/auth/get_auth_event.json | 8 + events/auth/get_auth_version.json | 11 + .../post_auth_IdDuplicationCheck-Dup.json | 10 + .../post_auth_IdDuplicationCheck-long.json | 10 + events/auth/post_auth_IdDuplicationCheck.json | 10 + events/auth/post_auth_appleLogin.json | 10 + events/auth/post_auth_appleRegister.json | 11 + events/auth/post_auth_loginKakao.json | 16 + .../auth/post_auth_phoneCheck-existNum.json | 10 + events/auth/post_auth_phoneCheck-newNum.json | 10 + .../post_auth_phoneCheck-wrongFormat.json | 10 + events/auth/post_auth_registerUser.json | 15 + .../post_auth_tokenGenerate-deleteUser.json | 10 + events/auth/post_auth_tokenGenerate.json | 10 + events/friend/block_event.json | 13 + events/friend/data_event.json | 10 + events/friend/event_event.json | 10 + events/friend/get_friend_searchPhone.json | 10 + events/friend/phonecheck_event.json | 15 + events/friend/search_event.json | 10 + events/image/get_image_deleteProfile.json | 10 + events/image/get_image_profileSaveUrl.json | 10 + events/image/post_image_profileUrl.json | 13 + .../notification/get_notification_list.json | 10 + .../notification/post_notification_send.json | 13 + .../post_notification_send_3.json | 13 + .../notification/put_notification_delete.json | 12 + events/payment/fail_event.json | 12 + events/payment/finalize_event.json | 14 + events/payment/get_payment_apiToken.json | 10 + events/payment/init_event.json | 14 + events/payment/post_payment_getData.json | 12 + events/payment/put_payment_refund.json | 13 + events/product/get_product_options.json | 10 + events/product/post_product_brand.json | 16 + events/product/post_product_enrollment.json | 138 +++ events/product/post_product_id.json | 12 + events/product/post_product_images.json | 12 + events/product/post_product_info.json | 12 + events/product/post_product_inputInfo.json | 26 + events/product/post_product_list.json | 18 + events/product/put_product_viewIncrease.json | 12 + events/seller/startdelivery_event.json | 15 + events/tikkling/cancel_event.json | 12 + events/tikkling/create_event.json | 18 + events/tikkling/deliveryconfirm_event.json | 12 + events/tikkling/deliveryinfo_event.json | 10 + events/tikkling/end_event.json | 14 + events/tikkling/friendinfo_event.json | 10 + events/tikkling/info_event.json | 10 + .../tikkling/post_user_getTikklingDetail.json | 12 + events/tikkling/receivedTikkle_event.json | 12 + events/tikkling/refundinfo_event.json | 10 + events/tikkling/sendmessage_event.json | 13 + events/tikkling/stop_event.json | 12 + events/user/delete_user_wishlist.json | 12 + events/user/get_bank_data.json | 10 + events/user/get_user_checkTikkling-no.json | 10 + events/user/get_user_checkTikkling-yes.json | 10 + events/user/get_user_deleteUser.json | 10 + events/user/get_user_endTikklings.json | 10 + events/user/get_user_info.json | 10 + events/user/get_user_myWishlist.json | 10 + events/user/get_user_paymentHistory.json | 10 + events/user/post_user_friend.json | 12 + events/user/post_user_wishlist.json | 12 + events/user/put_user_account.json | 13 + events/user/put_user_address.json | 14 + events/user/put_user_birthday.json | 12 + events/user/put_user_kakaoImage.json | 12 + events/user/put_user_lastpresentamount.json | 12 + events/user/put_user_nick.json | 12 + events/user/put_user_token.json | 12 + features/ActionFunnelLogManager.js | 143 +++ features/BankDetail.js | 35 + features/Delivery.js | 248 +++++ features/ExpectedError.js | 9 + features/InviteEventManager.js | 173 +++ features/Notice.js | 133 +++ features/Product.js | 849 +++++++++++++++ features/Refund.js | 62 ++ features/Response.js | 8 + features/Tikkle.js | 550 ++++++++++ features/Tikkling.js | 525 ++++++++++ features/User.js | 310 ++++++ index.js | 274 +++++ lambda_layer/db.js | 42 + lambda_layer/fcm.js | 111 ++ lambda_layer/ssm.js | 22 + lambda_layer/token.js | 93 ++ schema.sql | 985 ++++++++++++++++++ tikkle_auth/.DS_Store | Bin 0 -> 8196 bytes tikkle_auth/get_auth_checkToken/index.js | 76 ++ tikkle_auth/get_auth_event/index.js | 35 + tikkle_auth/get_auth_kToken/index.js | 5 + .../post_auth_IdDuplicationCheck/index.js | 61 ++ tikkle_auth/post_auth_appleLogin/index.js | 122 +++ tikkle_auth/post_auth_appleRegister/index.js | 80 ++ tikkle_auth/post_auth_loginKakao/index.js | 421 ++++++++ tikkle_auth/post_auth_phoneCheck/index.js | 84 ++ tikkle_auth/post_auth_registerUser/index.js | 41 + tikkle_auth/post_auth_tokenGenerate/index.js | 153 +++ tikkle_auth/post_auth_version/index.js | 74 ++ tikkle_friend/.DS_Store | Bin 0 -> 8196 bytes tikkle_friend/get_friend_data/index.js | 70 ++ tikkle_friend/get_friend_event/index.js | 59 ++ tikkle_friend/get_friend_search/index.js | 63 ++ tikkle_friend/get_friend_searchPhone/index.js | 68 ++ tikkle_friend/post_friend_phonecheck/index.js | 65 ++ tikkle_friend/post_user_friendDeep/index.js | 111 ++ tikkle_friend/put_friend_block/index.js | 63 ++ tikkle_image/.DS_Store | Bin 0 -> 6148 bytes tikkle_image/get_image_deleteProfile/index.js | 117 +++ .../get_image_profileSaveUrl/index.js | 51 + tikkle_image/post_image_profileUrl/index.js | 88 ++ tikkle_notification/.DS_Store | Bin 0 -> 6148 bytes .../get_notification_list/index.js | 66 ++ .../post_notification_send/index.js | 302 ++++++ .../put_notification_delete/index.js | 46 + tikkle_payment/.DS_Store | Bin 0 -> 8196 bytes tikkle_payment/get_payment_apiToken/index.js | 34 + tikkle_payment/post_payment_finalize/index.js | 156 +++ tikkle_payment/post_payment_getData/index.js | 53 + tikkle_payment/post_payment_init/index.js | 65 ++ tikkle_payment/put_payment_fail/index.js | 39 + tikkle_payment/put_payment_refund/index.js | 129 +++ tikkle_product/.DS_Store | Bin 0 -> 8196 bytes tikkle_product/get_product_options/index.js | 36 + tikkle_product/post_product_brand/index.js | 30 + .../post_product_enrollment/index.js | 53 + tikkle_product/post_product_id/index.js | 61 ++ tikkle_product/post_product_images/index.js | 47 + tikkle_product/post_product_info/index.js | 191 ++++ .../post_product_inputInfo/index.js | 125 +++ tikkle_product/post_product_list/index.js | 217 ++++ .../put_product_viewIncrease/index.js | 54 + tikkle_tikkling/.DS_Store | Bin 0 -> 10244 bytes .../get_tikkling_deliveryinfo/index.js | 35 + .../get_tikkling_friendinfo/index.js | 51 + tikkle_tikkling/get_tikkling_info/index.js | 162 +++ .../get_tikkling_refundinfo/index.js | 42 + .../post_tikkilng_buymytikkle/index.js | 71 ++ tikkle_tikkling/post_tikkling_create/index.js | 64 ++ .../post_tikkling_receivedTikkle/index.js | 50 + .../post_tikkling_sendmessage/index.js | 124 +++ .../post_tikkling_sendtikkle/index.js | 131 +++ .../post_user_getTikklingDetail/index.js | 77 ++ tikkle_tikkling/put_tikkling_cancel/index.js | 48 + .../put_tikkling_deliveryconfirm/index.js | 34 + tikkle_tikkling/put_tikkling_end/index.js | 111 ++ tikkle_tikkling/put_tikkling_stop/index.js | 66 ++ tikkle_user/.DS_Store | Bin 0 -> 10244 bytes tikkle_user/delete_user_wishlist/index.js | 48 + tikkle_user/get_bank_data/index.js | 49 + tikkle_user/get_user_checkTikkling/index.js | 49 + tikkle_user/get_user_deleteUser/index.js | 46 + tikkle_user/get_user_endTikklings/index.js | 51 + tikkle_user/get_user_info/index.js | 82 ++ tikkle_user/get_user_isNotice/index.js | 56 + tikkle_user/get_user_myWishlist/index.js | 49 + tikkle_user/get_user_paymentHistory/index.js | 57 + tikkle_user/post_user_friend/index.js | 79 ++ tikkle_user/post_user_wishlist/index.js | 79 ++ tikkle_user/put_user_account/index.js | 85 ++ tikkle_user/put_user_address/index.js | 71 ++ tikkle_user/put_user_birthday/index.js | 91 ++ tikkle_user/put_user_kakaoImage/index.js | 59 ++ .../put_user_lastpresentamount/index.js | 35 + tikkle_user/put_user_nick/index.js | 60 ++ tikkle_user/put_user_token/index.js | 61 ++ 180 files changed, 11590 insertions(+) create mode 100644 .github/workflows/deploy_to_lambda.yml create mode 100644 .gitignore create mode 100644 .npmignore create mode 100644 .prettierrc create mode 100644 actinoFunnelLogger.js create mode 100644 authtoken.js create mode 100644 db.js create mode 100644 events/.DS_Store create mode 100644 events/apple_login_test.json create mode 100644 events/auth/get_auth_checkToken.json create mode 100644 events/auth/get_auth_event.json create mode 100644 events/auth/get_auth_version.json create mode 100644 events/auth/post_auth_IdDuplicationCheck-Dup.json create mode 100644 events/auth/post_auth_IdDuplicationCheck-long.json create mode 100644 events/auth/post_auth_IdDuplicationCheck.json create mode 100644 events/auth/post_auth_appleLogin.json create mode 100644 events/auth/post_auth_appleRegister.json create mode 100644 events/auth/post_auth_loginKakao.json create mode 100644 events/auth/post_auth_phoneCheck-existNum.json create mode 100644 events/auth/post_auth_phoneCheck-newNum.json create mode 100644 events/auth/post_auth_phoneCheck-wrongFormat.json create mode 100644 events/auth/post_auth_registerUser.json create mode 100644 events/auth/post_auth_tokenGenerate-deleteUser.json create mode 100644 events/auth/post_auth_tokenGenerate.json create mode 100644 events/friend/block_event.json create mode 100644 events/friend/data_event.json create mode 100644 events/friend/event_event.json create mode 100644 events/friend/get_friend_searchPhone.json create mode 100644 events/friend/phonecheck_event.json create mode 100644 events/friend/search_event.json create mode 100644 events/image/get_image_deleteProfile.json create mode 100644 events/image/get_image_profileSaveUrl.json create mode 100644 events/image/post_image_profileUrl.json create mode 100644 events/notification/get_notification_list.json create mode 100644 events/notification/post_notification_send.json create mode 100644 events/notification/post_notification_send_3.json create mode 100644 events/notification/put_notification_delete.json create mode 100644 events/payment/fail_event.json create mode 100644 events/payment/finalize_event.json create mode 100644 events/payment/get_payment_apiToken.json create mode 100644 events/payment/init_event.json create mode 100644 events/payment/post_payment_getData.json create mode 100644 events/payment/put_payment_refund.json create mode 100644 events/product/get_product_options.json create mode 100644 events/product/post_product_brand.json create mode 100644 events/product/post_product_enrollment.json create mode 100644 events/product/post_product_id.json create mode 100644 events/product/post_product_images.json create mode 100644 events/product/post_product_info.json create mode 100644 events/product/post_product_inputInfo.json create mode 100644 events/product/post_product_list.json create mode 100644 events/product/put_product_viewIncrease.json create mode 100644 events/seller/startdelivery_event.json create mode 100644 events/tikkling/cancel_event.json create mode 100644 events/tikkling/create_event.json create mode 100644 events/tikkling/deliveryconfirm_event.json create mode 100644 events/tikkling/deliveryinfo_event.json create mode 100644 events/tikkling/end_event.json create mode 100644 events/tikkling/friendinfo_event.json create mode 100644 events/tikkling/info_event.json create mode 100644 events/tikkling/post_user_getTikklingDetail.json create mode 100644 events/tikkling/receivedTikkle_event.json create mode 100644 events/tikkling/refundinfo_event.json create mode 100644 events/tikkling/sendmessage_event.json create mode 100644 events/tikkling/stop_event.json create mode 100644 events/user/delete_user_wishlist.json create mode 100644 events/user/get_bank_data.json create mode 100644 events/user/get_user_checkTikkling-no.json create mode 100644 events/user/get_user_checkTikkling-yes.json create mode 100644 events/user/get_user_deleteUser.json create mode 100644 events/user/get_user_endTikklings.json create mode 100644 events/user/get_user_info.json create mode 100644 events/user/get_user_myWishlist.json create mode 100644 events/user/get_user_paymentHistory.json create mode 100644 events/user/post_user_friend.json create mode 100644 events/user/post_user_wishlist.json create mode 100644 events/user/put_user_account.json create mode 100644 events/user/put_user_address.json create mode 100644 events/user/put_user_birthday.json create mode 100644 events/user/put_user_kakaoImage.json create mode 100644 events/user/put_user_lastpresentamount.json create mode 100644 events/user/put_user_nick.json create mode 100644 events/user/put_user_token.json create mode 100644 features/ActionFunnelLogManager.js create mode 100644 features/BankDetail.js create mode 100644 features/Delivery.js create mode 100644 features/ExpectedError.js create mode 100644 features/InviteEventManager.js create mode 100644 features/Notice.js create mode 100644 features/Product.js create mode 100644 features/Refund.js create mode 100644 features/Response.js create mode 100644 features/Tikkle.js create mode 100644 features/Tikkling.js create mode 100644 features/User.js create mode 100644 index.js create mode 100644 lambda_layer/db.js create mode 100644 lambda_layer/fcm.js create mode 100644 lambda_layer/ssm.js create mode 100644 lambda_layer/token.js create mode 100644 schema.sql create mode 100644 tikkle_auth/.DS_Store create mode 100644 tikkle_auth/get_auth_checkToken/index.js create mode 100644 tikkle_auth/get_auth_event/index.js create mode 100644 tikkle_auth/get_auth_kToken/index.js create mode 100644 tikkle_auth/post_auth_IdDuplicationCheck/index.js create mode 100644 tikkle_auth/post_auth_appleLogin/index.js create mode 100644 tikkle_auth/post_auth_appleRegister/index.js create mode 100644 tikkle_auth/post_auth_loginKakao/index.js create mode 100644 tikkle_auth/post_auth_phoneCheck/index.js create mode 100644 tikkle_auth/post_auth_registerUser/index.js create mode 100644 tikkle_auth/post_auth_tokenGenerate/index.js create mode 100644 tikkle_auth/post_auth_version/index.js create mode 100644 tikkle_friend/.DS_Store create mode 100644 tikkle_friend/get_friend_data/index.js create mode 100644 tikkle_friend/get_friend_event/index.js create mode 100644 tikkle_friend/get_friend_search/index.js create mode 100644 tikkle_friend/get_friend_searchPhone/index.js create mode 100644 tikkle_friend/post_friend_phonecheck/index.js create mode 100644 tikkle_friend/post_user_friendDeep/index.js create mode 100644 tikkle_friend/put_friend_block/index.js create mode 100644 tikkle_image/.DS_Store create mode 100644 tikkle_image/get_image_deleteProfile/index.js create mode 100644 tikkle_image/get_image_profileSaveUrl/index.js create mode 100644 tikkle_image/post_image_profileUrl/index.js create mode 100644 tikkle_notification/.DS_Store create mode 100644 tikkle_notification/get_notification_list/index.js create mode 100644 tikkle_notification/post_notification_send/index.js create mode 100644 tikkle_notification/put_notification_delete/index.js create mode 100644 tikkle_payment/.DS_Store create mode 100644 tikkle_payment/get_payment_apiToken/index.js create mode 100644 tikkle_payment/post_payment_finalize/index.js create mode 100644 tikkle_payment/post_payment_getData/index.js create mode 100644 tikkle_payment/post_payment_init/index.js create mode 100644 tikkle_payment/put_payment_fail/index.js create mode 100644 tikkle_payment/put_payment_refund/index.js create mode 100644 tikkle_product/.DS_Store create mode 100644 tikkle_product/get_product_options/index.js create mode 100644 tikkle_product/post_product_brand/index.js create mode 100644 tikkle_product/post_product_enrollment/index.js create mode 100644 tikkle_product/post_product_id/index.js create mode 100644 tikkle_product/post_product_images/index.js create mode 100644 tikkle_product/post_product_info/index.js create mode 100644 tikkle_product/post_product_inputInfo/index.js create mode 100644 tikkle_product/post_product_list/index.js create mode 100644 tikkle_product/put_product_viewIncrease/index.js create mode 100644 tikkle_tikkling/.DS_Store create mode 100644 tikkle_tikkling/get_tikkling_deliveryinfo/index.js create mode 100644 tikkle_tikkling/get_tikkling_friendinfo/index.js create mode 100644 tikkle_tikkling/get_tikkling_info/index.js create mode 100644 tikkle_tikkling/get_tikkling_refundinfo/index.js create mode 100644 tikkle_tikkling/post_tikkilng_buymytikkle/index.js create mode 100644 tikkle_tikkling/post_tikkling_create/index.js create mode 100644 tikkle_tikkling/post_tikkling_receivedTikkle/index.js create mode 100644 tikkle_tikkling/post_tikkling_sendmessage/index.js create mode 100644 tikkle_tikkling/post_tikkling_sendtikkle/index.js create mode 100644 tikkle_tikkling/post_user_getTikklingDetail/index.js create mode 100644 tikkle_tikkling/put_tikkling_cancel/index.js create mode 100644 tikkle_tikkling/put_tikkling_deliveryconfirm/index.js create mode 100644 tikkle_tikkling/put_tikkling_end/index.js create mode 100644 tikkle_tikkling/put_tikkling_stop/index.js create mode 100644 tikkle_user/.DS_Store create mode 100644 tikkle_user/delete_user_wishlist/index.js create mode 100644 tikkle_user/get_bank_data/index.js create mode 100644 tikkle_user/get_user_checkTikkling/index.js create mode 100644 tikkle_user/get_user_deleteUser/index.js create mode 100644 tikkle_user/get_user_endTikklings/index.js create mode 100644 tikkle_user/get_user_info/index.js create mode 100644 tikkle_user/get_user_isNotice/index.js create mode 100644 tikkle_user/get_user_myWishlist/index.js create mode 100644 tikkle_user/get_user_paymentHistory/index.js create mode 100644 tikkle_user/post_user_friend/index.js create mode 100644 tikkle_user/post_user_wishlist/index.js create mode 100644 tikkle_user/put_user_account/index.js create mode 100644 tikkle_user/put_user_address/index.js create mode 100644 tikkle_user/put_user_birthday/index.js create mode 100644 tikkle_user/put_user_kakaoImage/index.js create mode 100644 tikkle_user/put_user_lastpresentamount/index.js create mode 100644 tikkle_user/put_user_nick/index.js create mode 100644 tikkle_user/put_user_token/index.js diff --git a/.github/workflows/deploy_to_lambda.yml b/.github/workflows/deploy_to_lambda.yml new file mode 100644 index 0000000..c4be9c1 --- /dev/null +++ b/.github/workflows/deploy_to_lambda.yml @@ -0,0 +1,40 @@ +name: Deploy to AWS Lambda + +on: + push: + branches: + - main + - develop + +jobs: + deploy: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Use Node.js + uses: actions/setup-node@v2 + with: + node-version: "18" + + - name: Package Lambda function + run: zip -r lambda.zip . + + - name: Configure AWS credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: ap-northeast-2 + + - name: Deploy to Lambda tikkle_dev + if: github.ref == 'refs/heads/develop' + run: | + aws lambda update-function-code --function-name tikkle_dev --zip-file fileb://lambda.zip + + - name: Deploy to Lambda tikkle + if: github.ref == 'refs/heads/main' + run: | + aws lambda update-function-code --function-name tikkle --zip-file fileb://lambda.zip diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a5b463c --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +/README.TOOLKIT.md +/reqs/ +/.aws-sam/ +/.vscode/ +/samconfig.toml +/template.yaml +/.DS_Store +tikkle-c9666-firebase-adminsdk-knplx-fcb6d4f595.json diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..e7e1fb0 --- /dev/null +++ b/.npmignore @@ -0,0 +1 @@ +tests/* diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..a4ead52 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,3 @@ +{ + "printWidth": 200 +} \ No newline at end of file diff --git a/actinoFunnelLogger.js b/actinoFunnelLogger.js new file mode 100644 index 0000000..7768dbb --- /dev/null +++ b/actinoFunnelLogger.js @@ -0,0 +1,31 @@ +const { ActionFunnelLogManager } = require("./features/ActionFunnelLogManager"); +const { DBManager } = require("./db"); +exports.actionFunnelLogger = async (req, res, next) => { + const db = new DBManager(); + await db.openTransaction(); + try { + const user_id = req.id; + + const funnel_log_manager = await ActionFunnelLogManager.createActionFunnelLogManager({ user_id, db }); + + // console.error(req.path); + // console.error(req.method); + // console.error(req.route); + if (req.route == "/post_product_list") { + if (req.body.search == null || req.body.search == undefined || req.body.search == "") { + await funnel_log_manager.logControllInterface(req.route); + } else { + await funnel_log_manager.logControllInterface("/post_product_search"); + } + } else { + await funnel_log_manager.logControllInterface(req.route); + } + await db.commitTransaction(); + } catch (error) { + await db.rollbackTransaction(); + //return invalid when token is invalid + console.error(`🚨 error -> ⚡️ actionFunnelLogger : 🐞${error}`); + } + + next(); +}; diff --git a/authtoken.js b/authtoken.js new file mode 100644 index 0000000..e60475b --- /dev/null +++ b/authtoken.js @@ -0,0 +1,49 @@ +const { checkToken } = require("token.js"); + +exports.authtoken = async (req, res, next) => { + const headers = req.headers; + const authorization = headers.authorization; + const [accessToken, refreshToken] = authorization.split(","); + + //-------- check token & get user id --------------------------------------------------------------------------------------// + + let tokenCheck; + let returnBody; + let id; + + try { + tokenCheck = await checkToken(accessToken, refreshToken); + returnBody = JSON.parse(tokenCheck.body); + id = returnBody.tokenData.id; + } catch (error) { + //return invalid when token is invalid + console.log("authtoken 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "99", + message: "login again", + returnToken: null, + }; + return res.status(401).send(return_body); + } + + //return invalid when token is invalid + if (tokenCheck.statusCode !== 200) { + console.log("authtoken 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "99", + message: "login again", + returnToken: null, + }; + return res.status(401).send(return_body); + } + + const returnToken = returnBody.accessToken; + + //-------- sucess result --------------------------------------------------------------------------------------// + + req.id = id; + req.returnToken = returnToken; + next(); +}; diff --git a/db.js b/db.js new file mode 100644 index 0000000..ac6ce9b --- /dev/null +++ b/db.js @@ -0,0 +1,86 @@ +const mysql = require("mysql2/promise"); +const { getDatabaseCredentials } = require("db.js"); + +class DBManager { + /** + * @description 트랜잭션을 열고, connection을 반환한다. + * @returns {Promise} + * @memberof DBManager + * @example + * const db = new DBManager(); + * await db.openTransaction(); + * try { + * const result = await db.executeQuery(sql, params); + * await db.commitTransaction(); + * } + * catch(err) { + * await db.rollbackTransaction(); + * } + */ + async openTransaction() { + const credentials = await getDatabaseCredentials(); + console.log(credentials); + this.connection = await mysql.createConnection(credentials); + await this.connection.beginTransaction(); + } + /** + * @description 쿼리를 실행한다. + * @returns {Promise} + * @memberof DBManager + * @example + * const db = new DBManager(); + * await db.openTransaction(); + * try { + * const result = await db.executeQuery(sql, params); + * await db.commitTransaction(); + * } + * catch(err) { + * await db.rollbackTransaction(); + * } + */ + async executeQuery(sql, params) { + const [rows] = await this.connection.execute(sql, params); + return rows; + } + /** + * @description 트랜잭션을 커밋하고, connection을 종료한다. + * @returns {Promise} + * @memberof DBManager + * @example + * const db = new DBManager(); + * await db.openTransaction(); + * try { + * const result = await db.executeQuery(sql, params); + * await db.commitTransaction(); + * } + * catch(err) { + * await db.rollbackTransaction(); + * } + */ + async commitTransaction() { + console.log("commit"); + await this.connection.commit(); + await this.connection.end(); + } + /** + * @description 트랜잭션을 롤백하고, connection을 종료한다. + * @returns {Promise} + * @memberof DBManager + * @example + * const db = new DBManager(); + * await db.openTransaction(); + * try { + * const result = await db.executeQuery(sql, params); + * await db.commitTransaction(); + * } + * catch(err) { + * await db.rollbackTransaction(); + * } + */ + async rollbackTransaction() { + await this.connection.rollback(); + await this.connection.end(); + } +} + +module.exports = { DBManager }; diff --git a/events/.DS_Store b/events/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..8c39f911b316b734280535f5ff9720d90a6b7a30 GIT binary patch literal 8196 zcmeI1L2DC16vyAxn67Q5xd=r>7xd(z*oz>gu$C0O2tw;cP;0Ym8j^HFnrI^;d-md2 z@a)lxf=3ZABKQ&X3n<b((A2jkMbJu%We)wVAQ-peeHy)+|-F#875A=0h77 zS(_PamXor@hq9TKtx%NCj{QR&PAW21Mo~Z%C@R3Udxh@NkOs8x*Y788yS{E(ukUrz zJ zoiLQe_#8Kw<2V?)(4a|)Pf@M!j_zJddv_T;rhP+UwJa-@uDVoRe6-p(_@}09YUE7 zehKw`b>@!pewXFx`o{Y=cQlK)hpS9kjL)IphJn7H+SCR~3s&@v^jg)^|>6EKP=t7c&ItXYh6vI`Te}#IIlEOKolT4 zW<*%w`hTnZ`@cvf3Wx&#umY-5->z@s1Z{0yI90B-L-bvAZXA~xtCwKl5T4iNIPCZj aLmY?J7g?Jb3lExn2+%UfAPW3Z1%3i3CMZ?_ literal 0 HcmV?d00001 diff --git a/events/apple_login_test.json b/events/apple_login_test.json new file mode 100644 index 0000000..1e64fce --- /dev/null +++ b/events/apple_login_test.json @@ -0,0 +1,12 @@ +{ + "resource": "/apple_login_test", + "path": "/apple_login_test", + "httpMethod": "POST", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": { + "productId": 7 + } +} \ No newline at end of file diff --git a/events/auth/get_auth_checkToken.json b/events/auth/get_auth_checkToken.json new file mode 100644 index 0000000..3a2fffa --- /dev/null +++ b/events/auth/get_auth_checkToken.json @@ -0,0 +1,10 @@ +{ + "resource": "/get_auth_checkToken", + "path": "/get_auth_checkToken", + "httpMethod": "GET", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": {} +} \ No newline at end of file diff --git a/events/auth/get_auth_event.json b/events/auth/get_auth_event.json new file mode 100644 index 0000000..1420f74 --- /dev/null +++ b/events/auth/get_auth_event.json @@ -0,0 +1,8 @@ +{ + "resource": "/get_auth_event", + "path": "/get_auth_event", + "httpMethod": "GET", + "headers": {}, + "queryStringParameters": null, + "body": {} +} diff --git a/events/auth/get_auth_version.json b/events/auth/get_auth_version.json new file mode 100644 index 0000000..955f371 --- /dev/null +++ b/events/auth/get_auth_version.json @@ -0,0 +1,11 @@ +{ + "resource": "/post_auth_version", + "path": "/post_auth_version", + "httpMethod": "POST", + "headers": {}, + "queryStringParameters": null, + "body": { + "os": "ios", + "version": "1.0.12" + } +} diff --git a/events/auth/post_auth_IdDuplicationCheck-Dup.json b/events/auth/post_auth_IdDuplicationCheck-Dup.json new file mode 100644 index 0000000..6ddd767 --- /dev/null +++ b/events/auth/post_auth_IdDuplicationCheck-Dup.json @@ -0,0 +1,10 @@ +{ + "resource": "/post_auth_IdDuplicationCheck", + "path": "/post_auth_IdDuplicationCheck", + "httpMethod": "POST", + "headers": {}, + "queryStringParameters": null, + "body": { + "inputId": "sup1214" + } +} diff --git a/events/auth/post_auth_IdDuplicationCheck-long.json b/events/auth/post_auth_IdDuplicationCheck-long.json new file mode 100644 index 0000000..7df7e28 --- /dev/null +++ b/events/auth/post_auth_IdDuplicationCheck-long.json @@ -0,0 +1,10 @@ +{ + "resource": "/post_auth_IdDuplicationCheck", + "path": "/post_auth_IdDuplicationCheck", + "httpMethod": "POST", + "headers": {}, + "queryStringParameters": null, + "body": { + "inputId": "supasdfasdfsadfsadfsadfsadfsdfasdfsdfsadfasdfsadfarevrbveargaenlbjrelvjnrvjeaborunevjsevnaskjevbaeosijvnsaoevnsejvn1214" + } +} diff --git a/events/auth/post_auth_IdDuplicationCheck.json b/events/auth/post_auth_IdDuplicationCheck.json new file mode 100644 index 0000000..fd0adef --- /dev/null +++ b/events/auth/post_auth_IdDuplicationCheck.json @@ -0,0 +1,10 @@ +{ + "resource": "/post_auth_IdDuplicationCheck", + "path": "/post_auth_IdDuplicationCheck", + "httpMethod": "POST", + "headers": {}, + "queryStringParameters": null, + "body": { + "inputId": "su" + } +} diff --git a/events/auth/post_auth_appleLogin.json b/events/auth/post_auth_appleLogin.json new file mode 100644 index 0000000..d1d0393 --- /dev/null +++ b/events/auth/post_auth_appleLogin.json @@ -0,0 +1,10 @@ +{ + "resource": "/post_auth_appleLogin", + "path": "/post_auth_appleLogin", + "httpMethod": "POST", + "headers": {}, + "queryStringParameters": null, + "body": { + "apple_id": "000724.0c2036c2d27b4f239826ac8af3fb9de0.0402" + } +} diff --git a/events/auth/post_auth_appleRegister.json b/events/auth/post_auth_appleRegister.json new file mode 100644 index 0000000..8579b51 --- /dev/null +++ b/events/auth/post_auth_appleRegister.json @@ -0,0 +1,11 @@ +{ + "resource": "/post_auth_appleRegister", + "path": "/post_auth_appleRegister", + "httpMethod": "POST", + "headers": {}, + "queryStringParameters": null, + "body": { + "apple_id": "000724.0c2036c2d27b4f239826ac8af3fb9de0.0402", + "phone": "01041286666" + } +} diff --git a/events/auth/post_auth_loginKakao.json b/events/auth/post_auth_loginKakao.json new file mode 100644 index 0000000..1690bac --- /dev/null +++ b/events/auth/post_auth_loginKakao.json @@ -0,0 +1,16 @@ +{ + "resource": "/post_auth_loginKakao", + "path": "/post_auth_loginKakao", + "httpMethod": "POST", + "headers": {}, + "queryStringParameters": null, + "body": { + "name": "12eff", + "birthday": "2007-08-22", + "phone": "01044444444", + "gender": "male", + "source_tikkling_id": "34", + "kakao_email": "Ddddd@dddd", + "kakao_image": "https://asdasdasdasd" + } +} diff --git a/events/auth/post_auth_phoneCheck-existNum.json b/events/auth/post_auth_phoneCheck-existNum.json new file mode 100644 index 0000000..0b4322f --- /dev/null +++ b/events/auth/post_auth_phoneCheck-existNum.json @@ -0,0 +1,10 @@ +{ + "resource": "/post_auth_phoneCheck", + "path": "/post_auth_phoneCheck", + "httpMethod": "POST", + "headers": {}, + "queryStringParameters": null, + "body": { + "phone": "01011111111" + } +} diff --git a/events/auth/post_auth_phoneCheck-newNum.json b/events/auth/post_auth_phoneCheck-newNum.json new file mode 100644 index 0000000..b44ba23 --- /dev/null +++ b/events/auth/post_auth_phoneCheck-newNum.json @@ -0,0 +1,10 @@ +{ + "resource": "/post_auth_phoneCheck", + "path": "/post_auth_phoneCheck", + "httpMethod": "POST", + "headers": {}, + "queryStringParameters": null, + "body": { + "phone": "01012347778" + } +} diff --git a/events/auth/post_auth_phoneCheck-wrongFormat.json b/events/auth/post_auth_phoneCheck-wrongFormat.json new file mode 100644 index 0000000..7a6ec06 --- /dev/null +++ b/events/auth/post_auth_phoneCheck-wrongFormat.json @@ -0,0 +1,10 @@ +{ + "resource": "/post_auth_phoneCheck", + "path": "/post_auth_phoneCheck", + "httpMethod": "POST", + "headers": {}, + "queryStringParameters": null, + "body": { + "phone": "010-1234-7778" + } +} diff --git a/events/auth/post_auth_registerUser.json b/events/auth/post_auth_registerUser.json new file mode 100644 index 0000000..eccdb4b --- /dev/null +++ b/events/auth/post_auth_registerUser.json @@ -0,0 +1,15 @@ +{ + "resource": "/post_auth_registerUser", + "path": "/post_auth_registerUser", + "httpMethod": "POST", + "headers": {}, + "queryStringParameters": null, + "body": { + "name": "12e", + "birthday": "2007-08-22", + "nick": "12111", + "phone": "01053783522", + "gender": "male", + "source_tikkling_id": "293" + } +} \ No newline at end of file diff --git a/events/auth/post_auth_tokenGenerate-deleteUser.json b/events/auth/post_auth_tokenGenerate-deleteUser.json new file mode 100644 index 0000000..d687faa --- /dev/null +++ b/events/auth/post_auth_tokenGenerate-deleteUser.json @@ -0,0 +1,10 @@ +{ + "resource": "/post_auth_tokenGenerate", + "path": "/post_auth_tokenGenerate", + "httpMethod": "POST", + "headers": {}, + "queryStringParameters": null, + "body": { + "id": 27 + } +} \ No newline at end of file diff --git a/events/auth/post_auth_tokenGenerate.json b/events/auth/post_auth_tokenGenerate.json new file mode 100644 index 0000000..d687faa --- /dev/null +++ b/events/auth/post_auth_tokenGenerate.json @@ -0,0 +1,10 @@ +{ + "resource": "/post_auth_tokenGenerate", + "path": "/post_auth_tokenGenerate", + "httpMethod": "POST", + "headers": {}, + "queryStringParameters": null, + "body": { + "id": 27 + } +} \ No newline at end of file diff --git a/events/friend/block_event.json b/events/friend/block_event.json new file mode 100644 index 0000000..ee48274 --- /dev/null +++ b/events/friend/block_event.json @@ -0,0 +1,13 @@ +{ + "resource": "/put_friend_block", + "path": "/put_friend_block", + "httpMethod": "PUT", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": { + "friend_id": "21", + "blocked": false + } +} \ No newline at end of file diff --git a/events/friend/data_event.json b/events/friend/data_event.json new file mode 100644 index 0000000..c0c83d3 --- /dev/null +++ b/events/friend/data_event.json @@ -0,0 +1,10 @@ +{ + "resource": "/get_friend_data/{mode}", + "path": "/get_friend_data/unblock", + "httpMethod": "GET", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": "{}" +} \ No newline at end of file diff --git a/events/friend/event_event.json b/events/friend/event_event.json new file mode 100644 index 0000000..829ba43 --- /dev/null +++ b/events/friend/event_event.json @@ -0,0 +1,10 @@ +{ + "resource": "/get_friend_event", + "path": "/get_friend_event", + "httpMethod": "GET", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": "{}" +} \ No newline at end of file diff --git a/events/friend/get_friend_searchPhone.json b/events/friend/get_friend_searchPhone.json new file mode 100644 index 0000000..5966965 --- /dev/null +++ b/events/friend/get_friend_searchPhone.json @@ -0,0 +1,10 @@ +{ + "resource": "/get_friend_searchPhone/{phone}", + "path": "/get_friend_searchPhone/1112223333", + "httpMethod": "GET", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": {} +} \ No newline at end of file diff --git a/events/friend/phonecheck_event.json b/events/friend/phonecheck_event.json new file mode 100644 index 0000000..fbc5ffe --- /dev/null +++ b/events/friend/phonecheck_event.json @@ -0,0 +1,15 @@ +{ + "resource": "/post_friend_phonecheck", + "path": "/post_friend_phonecheck", + "httpMethod": "POST", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": { + "phone_list": [ + "01012345678", + "01053783514" + ] + } +} \ No newline at end of file diff --git a/events/friend/search_event.json b/events/friend/search_event.json new file mode 100644 index 0000000..8cf980e --- /dev/null +++ b/events/friend/search_event.json @@ -0,0 +1,10 @@ +{ + "resource": "/get_friend_search/{nick}", + "path": "/get_friend_search/younghee95", + "httpMethod": "GET", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": "{}" +} \ No newline at end of file diff --git a/events/image/get_image_deleteProfile.json b/events/image/get_image_deleteProfile.json new file mode 100644 index 0000000..9726661 --- /dev/null +++ b/events/image/get_image_deleteProfile.json @@ -0,0 +1,10 @@ +{ + "resource": "/get_image_deleteProfile", + "path": "/get_image_deleteProfile", + "httpMethod": "GET", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": {} +} \ No newline at end of file diff --git a/events/image/get_image_profileSaveUrl.json b/events/image/get_image_profileSaveUrl.json new file mode 100644 index 0000000..99a4d1f --- /dev/null +++ b/events/image/get_image_profileSaveUrl.json @@ -0,0 +1,10 @@ +{ + "resource": "/get_image_profileSaveUrl", + "path": "/get_image_profileSaveUrl", + "httpMethod": "GET", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": {} +} \ No newline at end of file diff --git a/events/image/post_image_profileUrl.json b/events/image/post_image_profileUrl.json new file mode 100644 index 0000000..4d441da --- /dev/null +++ b/events/image/post_image_profileUrl.json @@ -0,0 +1,13 @@ +{ + "resource": "/post_image_profileUrl", + "path": "/post_image_profileUrl", + "httpMethod": "POST", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": { + "imageSize": 0, + "userId": 5 + } +} \ No newline at end of file diff --git a/events/notification/get_notification_list.json b/events/notification/get_notification_list.json new file mode 100644 index 0000000..e98bf6a --- /dev/null +++ b/events/notification/get_notification_list.json @@ -0,0 +1,10 @@ +{ + "resource": "/get_notification_list", + "path": "/get_notification_list", + "httpMethod": "GET", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": {} +} \ No newline at end of file diff --git a/events/notification/post_notification_send.json b/events/notification/post_notification_send.json new file mode 100644 index 0000000..4ff31a6 --- /dev/null +++ b/events/notification/post_notification_send.json @@ -0,0 +1,13 @@ +{ + "resource": "/post_notification_send", + "path": "/post_notification_send", + "httpMethod": "POST", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": { + "receive_user_id": 78, + "notification_type_id": 9 + } +} \ No newline at end of file diff --git a/events/notification/post_notification_send_3.json b/events/notification/post_notification_send_3.json new file mode 100644 index 0000000..e3e6632 --- /dev/null +++ b/events/notification/post_notification_send_3.json @@ -0,0 +1,13 @@ +{ + "resource": "/post_notification_send", + "path": "/post_notification_send", + "httpMethod": "POST", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": { + "tikkling_id": 15, + "notification_type_id": 3 + } +} \ No newline at end of file diff --git a/events/notification/put_notification_delete.json b/events/notification/put_notification_delete.json new file mode 100644 index 0000000..bb1f678 --- /dev/null +++ b/events/notification/put_notification_delete.json @@ -0,0 +1,12 @@ +{ + "resource": "/put_notification_delete", + "path": "/put_notification_delete", + "httpMethod": "PUT", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": { + "notificationId": 3 + } +} \ No newline at end of file diff --git a/events/payment/fail_event.json b/events/payment/fail_event.json new file mode 100644 index 0000000..3c5073e --- /dev/null +++ b/events/payment/fail_event.json @@ -0,0 +1,12 @@ +{ + "resource": "/put_payment_fail", + "path": "/put_payment_fail", + "httpMethod": "PUT", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": { + "merchant_uid": "test_lncj36r7" + } +} \ No newline at end of file diff --git a/events/payment/finalize_event.json b/events/payment/finalize_event.json new file mode 100644 index 0000000..aa56477 --- /dev/null +++ b/events/payment/finalize_event.json @@ -0,0 +1,14 @@ +{ + "resource": "/post_payment_finalize/{tikkleAction}", + "path": "/post_payment_finalize/sendtikkle", + "httpMethod": "POST", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": { + "imp_uid": "imp_697619053908", + "merchant_uid": "4bf6525b4034a4038682a18bb3a79731", + "status": "paid" + } +} \ No newline at end of file diff --git a/events/payment/get_payment_apiToken.json b/events/payment/get_payment_apiToken.json new file mode 100644 index 0000000..b919a84 --- /dev/null +++ b/events/payment/get_payment_apiToken.json @@ -0,0 +1,10 @@ +{ + "resource": "/get_payment_apiToken", + "path": "/get_payment_apiToken", + "httpMethod": "GET", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": {} +} \ No newline at end of file diff --git a/events/payment/init_event.json b/events/payment/init_event.json new file mode 100644 index 0000000..c528382 --- /dev/null +++ b/events/payment/init_event.json @@ -0,0 +1,14 @@ +{ + "resource": "/post_payment_init/{tikkleAction}", + "path": "/post_payment_init/sendtikkle", + "httpMethod": "POST", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": { + "tikkling_id": 39, + "tikkle_quantity": 1, + "message": "test" + } +} \ No newline at end of file diff --git a/events/payment/post_payment_getData.json b/events/payment/post_payment_getData.json new file mode 100644 index 0000000..0ae658f --- /dev/null +++ b/events/payment/post_payment_getData.json @@ -0,0 +1,12 @@ +{ + "resource": "/post_payment_getData", + "path": "/post_payment_getData", + "httpMethod": "POST", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": { + "merchant_uid": "mid_1696556775916" + } +} \ No newline at end of file diff --git a/events/payment/put_payment_refund.json b/events/payment/put_payment_refund.json new file mode 100644 index 0000000..c496d2d --- /dev/null +++ b/events/payment/put_payment_refund.json @@ -0,0 +1,13 @@ +{ + "resource": "/put_payment_refund", + "path": "/put_payment_refund", + "httpMethod": "PUT", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": { + "merchant_uid": "214fb2156895c5622873dfbb57afd893", + "reason": "단순 변심" + } +} \ No newline at end of file diff --git a/events/product/get_product_options.json b/events/product/get_product_options.json new file mode 100644 index 0000000..3173a70 --- /dev/null +++ b/events/product/get_product_options.json @@ -0,0 +1,10 @@ +{ + "resource": "/get_product_options/{product_id}", + "path": "/get_product_options/4", + "httpMethod": "GET", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": "{}" +} \ No newline at end of file diff --git a/events/product/post_product_brand.json b/events/product/post_product_brand.json new file mode 100644 index 0000000..36c177a --- /dev/null +++ b/events/product/post_product_brand.json @@ -0,0 +1,16 @@ +{ + "resource": "/post_product_brand", + "path": "/post_product_brand", + "httpMethod": "POST", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": { + "brand_name_list": [ + "brand1", + "brand5", + "brand3" + ] + } +} \ No newline at end of file diff --git a/events/product/post_product_enrollment.json b/events/product/post_product_enrollment.json new file mode 100644 index 0000000..ebdb9df --- /dev/null +++ b/events/product/post_product_enrollment.json @@ -0,0 +1,138 @@ +{ + "resource": "/post_product_enrollment", + "path": "/post_product_enrollment", + "httpMethod": "POST", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": { + "product_list": [ + { + "name": "test6", + "price": 350000, + "category_id": 3, + "brand_id": 3, + "thumbnail_image": "https://www.biztrend.co.kr/company_img_folder/dream1356/img_500/GUCCI/74d26cb4c0974301f4d910f8c24480db.jpg", + "images": { + "1": "https://www.biztrend.co.kr/company_img_folder/dream1356/GUCCI/cd5c025c2ef7693b446b98004ab75635.jpg", + "2": "https://www.biztrend.co.kr/company_img_folder/dream1356/GUCCI/71e3cc95647b082cf1721b9ee65eabc1.jpg", + "3": "https://www.biztrend.co.kr/company_img_folder/dream1356/img_500/GUCCI/74d26cb4c0974301f4d910f8c24480db.jpg", + "4": "https://www.biztrend.co.kr/company_img_folder/dream1356/GUCCI/9eede9c6189cf5a58c7cbae9e3720421.jpg", + "5": "https://www.biztrend.co.kr/company_img_folder/dream1356/GUCCI/88ad0ec69e79a97f9a65da8582dd4544.jpg", + "6": "https://www.biztrend.co.kr/company_img_folder/dream1356/GUCCI/96139eeb87fa17f6bcf904a7ef7417c3.jpg", + "7": "https://www.biztrend.co.kr/company_img_folder/dream1356/GUCCI/39aa8578bddb5beca281da620533be8f.jpg", + "8": "https://www.biztrend.co.kr/company_img_folder/dream1356/GUCCI/09d2ac856e3ed99170d663a1f44666aa.jpg", + "9": "https://www.biztrend.co.kr/company_img_folder/dream1356/GUCCI/56278903d3cd2c29ebb78bc17c095c26.jpg", + "10": "https://www.biztrend.co.kr/company_img_folder/dream1356/GUCCI/edd4f4710e91bf5c18f2d5aa18271704.jpg", + "11": "https://www.biztrend.co.kr/company_img_folder/dream1356/GUCCI/dd13b6a253082b61ea7ba6496a7b4241.jpg", + "12": "https://www.biztrend.co.kr/company_img_folder/dream1356/GUCCI/27854a867f2c670517a56edd78f8b6d8.jpg" + }, + "description": "", + "product_option_list": [ + { + "category": "color", + "option": "red", + "additional_amount": 0 + }, + { + "category": "color", + "option": "yellow", + "additional_amount": 0 + }, + { + "category": "color", + "option": "blue", + "additional_amount": 0 + }, + { + "category": "size", + "option": "S", + "additional_amount": 5000 + }, + { + "category": "size", + "option": "L", + "additional_amount": 10000 + } + ], + "option_combination_list": [ + { + "color": { + "category": "color", + "option": "red", + "additional_amount": 0 + }, + "size": { + "category": "size", + "option": "L", + "additional_amount": 5000 + }, + "quantity": 100 + }, + { + "color": { + "category": "color", + "option": "yellow", + "additional_amount": 0 + }, + "size": { + "category": "size", + "option": "L", + "additional_amount": 5000 + } + }, + { + "color": { + "category": "color", + "option": "blue", + "additional_amount": 0 + }, + "size": { + "category": "size", + "option": "L", + "additional_amount": 5000 + } + }, + { + "color": { + "category": "color", + "option": "red", + "additional_amount": 0 + }, + "size": { + "category": "size", + "option": "S", + "additional_amount": 5000 + }, + "quantity": 100 + }, + { + "color": { + "category": "color", + "option": "yellow", + "additional_amount": 0 + }, + "size": { + "category": "size", + "option": "S", + "additional_amount": 5000 + } + }, + { + "color": { + "category": "color", + "option": "blue", + "additional_amount": 0 + }, + "size": { + "category": "size", + "option": "S", + "additional_amount": 5000 + } + } + ] + } + ] + } +} \ No newline at end of file diff --git a/events/product/post_product_id.json b/events/product/post_product_id.json new file mode 100644 index 0000000..ad75c1a --- /dev/null +++ b/events/product/post_product_id.json @@ -0,0 +1,12 @@ +{ + "resource": "/post_product_id", + "path": "/post_product_id", + "httpMethod": "POST", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": { + "p_name": "베아트리체 카프리 호주산 양모이불 1종 PBT-1025 슈퍼싱글(SS) + 베개커버 1장 (그레이,블루 색상택일)" + } +} \ No newline at end of file diff --git a/events/product/post_product_images.json b/events/product/post_product_images.json new file mode 100644 index 0000000..7194b50 --- /dev/null +++ b/events/product/post_product_images.json @@ -0,0 +1,12 @@ +{ + "resource": "/post_product_images", + "path": "/post_product_images", + "httpMethod": "POST", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": { + "productId": 4 + } +} \ No newline at end of file diff --git a/events/product/post_product_info.json b/events/product/post_product_info.json new file mode 100644 index 0000000..327fd14 --- /dev/null +++ b/events/product/post_product_info.json @@ -0,0 +1,12 @@ +{ + "resource": "/post_product_info", + "path": "/post_product_info", + "httpMethod": "POST", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": { + "productId": 11 + } +} \ No newline at end of file diff --git a/events/product/post_product_inputInfo.json b/events/product/post_product_inputInfo.json new file mode 100644 index 0000000..778c0fe --- /dev/null +++ b/events/product/post_product_inputInfo.json @@ -0,0 +1,26 @@ +{ + "resource": "/post_product_inputInfo", + "path": "/post_product_inputInfo", + "httpMethod": "POST", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": { + "data": { + "product_id": 90, + "p_name": "[구찌 GUCCI] 510302 CAO0G 1000 여성 숄더백", + "type": "숄더백", + "material": "소가죽", + "color": "블랙", + "size": "SIZE - 26cmx18cmx9cm", + "manufacturer_importer": "구찌/(주)트랜드메카-병행수입", + "origin_country": "브랜드국-이탈리아(ITALY)(원산지:이탈리아)", + "precautions": "화장품,향수,마찰등으로 변색,탈색,이염등 상품이 손상 될수 있으니 주의하세요. / 충격과 비틀림에 의한 파손에 주의하세요. / 피부가 민감하여 알러지 반응이 있을시 착용을 중지하세요. / 천연가죽 특성상 작은상처나 가죽결 및 약간의 색조차이가 발생할 수 있으므로, 이점은 결함으로 볼 수 없습니다. / 취급시 수분(물, 땀, 향수 등), 기름, 습기(여름철 습도 등), 온도와 직사광선을 피하여 보관, 사용하시기 바랍니다.", + "quality_assurance_standard": "관련 법 및 소비자분쟁해결 규정에 따름", + "as_manager": "(주)트랜드메카", + "as_phone": "1599-8246" + }, + "table_id": 3 + } +} \ No newline at end of file diff --git a/events/product/post_product_list.json b/events/product/post_product_list.json new file mode 100644 index 0000000..1486083 --- /dev/null +++ b/events/product/post_product_list.json @@ -0,0 +1,18 @@ +{ + "resource": "/post_product_list", + "path": "/post_product_list", + "httpMethod": "POST", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": { + "category_id": 0, + "priceMin": 0, + "priceMax": null, + "sortAttribute": "price", + "sortWay": "DESC", + "search": null, + "getNum": 1 + } +} \ No newline at end of file diff --git a/events/product/put_product_viewIncrease.json b/events/product/put_product_viewIncrease.json new file mode 100644 index 0000000..6d9aa89 --- /dev/null +++ b/events/product/put_product_viewIncrease.json @@ -0,0 +1,12 @@ +{ + "resource": "/put_product_viewIncrease", + "path": "/put_product_viewIncrease", + "httpMethod": "PUT", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": { + "productId": 5 + } +} \ No newline at end of file diff --git a/events/seller/startdelivery_event.json b/events/seller/startdelivery_event.json new file mode 100644 index 0000000..51796cc --- /dev/null +++ b/events/seller/startdelivery_event.json @@ -0,0 +1,15 @@ +{ + "resource": "/post_seller_startdelivery", + "path": "/post_seller_startdelivery", + "httpMethod": "POST", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": { + "delivery_id": 1, + "invoice_number": "12345", + "courier_company_code": "110", + "delivery_period": 3 + } +} \ No newline at end of file diff --git a/events/tikkling/cancel_event.json b/events/tikkling/cancel_event.json new file mode 100644 index 0000000..65e6fb4 --- /dev/null +++ b/events/tikkling/cancel_event.json @@ -0,0 +1,12 @@ +{ + "resource": "/put_tikkling_cancel", + "path": "/put_tikkling_cancel", + "httpMethod": "PUT", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": { + "tikkling_id": 34 + } +} \ No newline at end of file diff --git a/events/tikkling/create_event.json b/events/tikkling/create_event.json new file mode 100644 index 0000000..d527d31 --- /dev/null +++ b/events/tikkling/create_event.json @@ -0,0 +1,18 @@ +{ + "resource": "/post_tikkling_create", + "path": "/post_tikkling_create", + "httpMethod": "POST", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": { + "funding_limit": "2023-12-18", + "tikkle_quantity": 169, + "product_id": 345, + "type": "기타", + "product_option": { + "색상": "그린" + } + } +} \ No newline at end of file diff --git a/events/tikkling/deliveryconfirm_event.json b/events/tikkling/deliveryconfirm_event.json new file mode 100644 index 0000000..e45034f --- /dev/null +++ b/events/tikkling/deliveryconfirm_event.json @@ -0,0 +1,12 @@ +{ + "resource": "/put_tikkling_deliveryconfirm", + "path": "/put_tikkling_deliveryconfirm", + "httpMethod": "PUT", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": { + "tikkling_id": 22 + } +} \ No newline at end of file diff --git a/events/tikkling/deliveryinfo_event.json b/events/tikkling/deliveryinfo_event.json new file mode 100644 index 0000000..1d8bb8d --- /dev/null +++ b/events/tikkling/deliveryinfo_event.json @@ -0,0 +1,10 @@ +{ + "resource": "/get_tikkling_deliveryinfo/{tikkling_id}", + "path": "/get_tikkling_deliveryinfo/26", + "httpMethod": "GET", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": {} +} \ No newline at end of file diff --git a/events/tikkling/end_event.json b/events/tikkling/end_event.json new file mode 100644 index 0000000..7193fad --- /dev/null +++ b/events/tikkling/end_event.json @@ -0,0 +1,14 @@ +{ + "resource": "/put_tikkling_end/{type}", + "path": "/put_tikkling_end/refund", + "httpMethod": "PUT", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": { + "tikkling_id": 37, + "bank_code": 2, + "account": "1212314124" + } +} \ No newline at end of file diff --git a/events/tikkling/friendinfo_event.json b/events/tikkling/friendinfo_event.json new file mode 100644 index 0000000..809e014 --- /dev/null +++ b/events/tikkling/friendinfo_event.json @@ -0,0 +1,10 @@ +{ + "resource": "/get_tikkling_friendinfo", + "path": "/get_tikkling_friendinfo", + "httpMethod": "GET", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": {} +} \ No newline at end of file diff --git a/events/tikkling/info_event.json b/events/tikkling/info_event.json new file mode 100644 index 0000000..e63bb34 --- /dev/null +++ b/events/tikkling/info_event.json @@ -0,0 +1,10 @@ +{ + "resource": "/get_tikkling_info/{tikkling_id}", + "path": "/get_tikkling_info/450", + "httpMethod": "GET", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": {} +} \ No newline at end of file diff --git a/events/tikkling/post_user_getTikklingDetail.json b/events/tikkling/post_user_getTikklingDetail.json new file mode 100644 index 0000000..7e0708e --- /dev/null +++ b/events/tikkling/post_user_getTikklingDetail.json @@ -0,0 +1,12 @@ +{ + "resource": "/post_user_getTikklingDetail", + "path": "/post_user_getTikklingDetail", + "httpMethod": "POST", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": { + "tikkling_id": 6 + } +} \ No newline at end of file diff --git a/events/tikkling/receivedTikkle_event.json b/events/tikkling/receivedTikkle_event.json new file mode 100644 index 0000000..f281ef8 --- /dev/null +++ b/events/tikkling/receivedTikkle_event.json @@ -0,0 +1,12 @@ +{ + "resource": "/post_tikkling_receivedTikkle", + "path": "/post_tikkling_receivedTikkle", + "httpMethod": "POST", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": { + "tikkling_id": 6 + } +} \ No newline at end of file diff --git a/events/tikkling/refundinfo_event.json b/events/tikkling/refundinfo_event.json new file mode 100644 index 0000000..79b9453 --- /dev/null +++ b/events/tikkling/refundinfo_event.json @@ -0,0 +1,10 @@ +{ + "resource": "/get_tikkling_refundinfo/{tikkling_id}", + "path": "/get_tikkling_refundinfo/40", + "httpMethod": "GET", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": {} +} \ No newline at end of file diff --git a/events/tikkling/sendmessage_event.json b/events/tikkling/sendmessage_event.json new file mode 100644 index 0000000..450e6b5 --- /dev/null +++ b/events/tikkling/sendmessage_event.json @@ -0,0 +1,13 @@ +{ + "resource": "/post_tikkling_sendmessage", + "path": "/post_tikkling_sendmessage", + "httpMethod": "POST", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": { + "tikkling_id": 592, + "message": "Hello" + } +} \ No newline at end of file diff --git a/events/tikkling/stop_event.json b/events/tikkling/stop_event.json new file mode 100644 index 0000000..99e7755 --- /dev/null +++ b/events/tikkling/stop_event.json @@ -0,0 +1,12 @@ +{ + "resource": "/put_tikkling_stop", + "path": "/put_tikkling_stop", + "httpMethod": "PUT", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": { + "tikkling_id": 31 + } +} \ No newline at end of file diff --git a/events/user/delete_user_wishlist.json b/events/user/delete_user_wishlist.json new file mode 100644 index 0000000..3e0c9ae --- /dev/null +++ b/events/user/delete_user_wishlist.json @@ -0,0 +1,12 @@ +{ + "resource": "/delete_user_wishlist", + "path": "/delete_user_wishlist", + "httpMethod": "DELETE", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "body": { + "productid": 4 + }, + "queryStringParameters": {} +} \ No newline at end of file diff --git a/events/user/get_bank_data.json b/events/user/get_bank_data.json new file mode 100644 index 0000000..55e4ce4 --- /dev/null +++ b/events/user/get_bank_data.json @@ -0,0 +1,10 @@ +{ + "resource": "/get_bank_data", + "path": "/get_bank_data", + "httpMethod": "GET", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": "{}" +} \ No newline at end of file diff --git a/events/user/get_user_checkTikkling-no.json b/events/user/get_user_checkTikkling-no.json new file mode 100644 index 0000000..2258943 --- /dev/null +++ b/events/user/get_user_checkTikkling-no.json @@ -0,0 +1,10 @@ +{ + "resource": "/get_user_checkTikkling", + "path": "/get_user_checkTikkling", + "httpMethod": "GET", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": "{}" +} \ No newline at end of file diff --git a/events/user/get_user_checkTikkling-yes.json b/events/user/get_user_checkTikkling-yes.json new file mode 100644 index 0000000..2258943 --- /dev/null +++ b/events/user/get_user_checkTikkling-yes.json @@ -0,0 +1,10 @@ +{ + "resource": "/get_user_checkTikkling", + "path": "/get_user_checkTikkling", + "httpMethod": "GET", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": "{}" +} \ No newline at end of file diff --git a/events/user/get_user_deleteUser.json b/events/user/get_user_deleteUser.json new file mode 100644 index 0000000..c065d4e --- /dev/null +++ b/events/user/get_user_deleteUser.json @@ -0,0 +1,10 @@ +{ + "resource": "/get_user_deleteUser", + "path": "/get_user_deleteUser", + "httpMethod": "GET", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": "{}" +} \ No newline at end of file diff --git a/events/user/get_user_endTikklings.json b/events/user/get_user_endTikklings.json new file mode 100644 index 0000000..b51cc36 --- /dev/null +++ b/events/user/get_user_endTikklings.json @@ -0,0 +1,10 @@ +{ + "resource": "/get_user_endTikklings", + "path": "/get_user_endTikklings", + "httpMethod": "GET", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": "{}" +} \ No newline at end of file diff --git a/events/user/get_user_info.json b/events/user/get_user_info.json new file mode 100644 index 0000000..87eb4d2 --- /dev/null +++ b/events/user/get_user_info.json @@ -0,0 +1,10 @@ +{ + "resource": "/get_user_info", + "path": "/get_user_info", + "httpMethod": "GET", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": "{}" +} \ No newline at end of file diff --git a/events/user/get_user_myWishlist.json b/events/user/get_user_myWishlist.json new file mode 100644 index 0000000..fe51ed3 --- /dev/null +++ b/events/user/get_user_myWishlist.json @@ -0,0 +1,10 @@ +{ + "resource": "/get_user_myWishlist", + "path": "/get_user_myWishlist", + "httpMethod": "GET", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": "{}" +} \ No newline at end of file diff --git a/events/user/get_user_paymentHistory.json b/events/user/get_user_paymentHistory.json new file mode 100644 index 0000000..0ba1146 --- /dev/null +++ b/events/user/get_user_paymentHistory.json @@ -0,0 +1,10 @@ +{ + "resource": "/get_user_paymentHistory", + "path": "/get_user_paymentHistory", + "httpMethod": "GET", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": "{}" +} \ No newline at end of file diff --git a/events/user/post_user_friend.json b/events/user/post_user_friend.json new file mode 100644 index 0000000..65ae94f --- /dev/null +++ b/events/user/post_user_friend.json @@ -0,0 +1,12 @@ +{ + "resource": "/post_user_friend", + "path": "/post_user_friend", + "httpMethod": "POST", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": { + "friendId": 19 + } +} \ No newline at end of file diff --git a/events/user/post_user_wishlist.json b/events/user/post_user_wishlist.json new file mode 100644 index 0000000..96b8468 --- /dev/null +++ b/events/user/post_user_wishlist.json @@ -0,0 +1,12 @@ +{ + "resource": "/post_user_wishlist", + "path": "/post_user_wishlist", + "httpMethod": "POST", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": { + "productId": 7 + } +} \ No newline at end of file diff --git a/events/user/put_user_account.json b/events/user/put_user_account.json new file mode 100644 index 0000000..28e6a05 --- /dev/null +++ b/events/user/put_user_account.json @@ -0,0 +1,13 @@ +{ + "resource": "/put_user_account", + "path": "/put_user_account", + "httpMethod": "PUT", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": { + "bank_code": 2, + "account": "1234567890" + } +} \ No newline at end of file diff --git a/events/user/put_user_address.json b/events/user/put_user_address.json new file mode 100644 index 0000000..760f509 --- /dev/null +++ b/events/user/put_user_address.json @@ -0,0 +1,14 @@ +{ + "resource": "/put_user_address", + "path": "/put_user_address", + "httpMethod": "PUT", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": { + "zonecode": "16881", + "address": "경기 용인시 수지구 실험로 111", + "detail_address": "반포자이아파트 111동 6301호" + } +} \ No newline at end of file diff --git a/events/user/put_user_birthday.json b/events/user/put_user_birthday.json new file mode 100644 index 0000000..f2d4cc6 --- /dev/null +++ b/events/user/put_user_birthday.json @@ -0,0 +1,12 @@ +{ + "resource": "/put_user_birthday", + "path": "/put_user_birthday", + "httpMethod": "PUT", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": { + "birthday": "1999-01-01" + } +} \ No newline at end of file diff --git a/events/user/put_user_kakaoImage.json b/events/user/put_user_kakaoImage.json new file mode 100644 index 0000000..e8a52e0 --- /dev/null +++ b/events/user/put_user_kakaoImage.json @@ -0,0 +1,12 @@ +{ + "resource": "/put_user_kakaoImage", + "path": "/put_user_kakaoImage", + "httpMethod": "PUT", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": { + "image": "tedddd" + } +} \ No newline at end of file diff --git a/events/user/put_user_lastpresentamount.json b/events/user/put_user_lastpresentamount.json new file mode 100644 index 0000000..7565da6 --- /dev/null +++ b/events/user/put_user_lastpresentamount.json @@ -0,0 +1,12 @@ +{ + "resource": "/put_user_lastpresentamount", + "path": "/put_user_lastpresentamount", + "httpMethod": "PUT", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": { + "last_present_amount": 100000 + } +} \ No newline at end of file diff --git a/events/user/put_user_nick.json b/events/user/put_user_nick.json new file mode 100644 index 0000000..3ec6d4a --- /dev/null +++ b/events/user/put_user_nick.json @@ -0,0 +1,12 @@ +{ + "resource": "/put_user_nick", + "path": "/put_user_nick", + "httpMethod": "PUT", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": { + "nick": "te" + } +} \ No newline at end of file diff --git a/events/user/put_user_token.json b/events/user/put_user_token.json new file mode 100644 index 0000000..00cf5be --- /dev/null +++ b/events/user/put_user_token.json @@ -0,0 +1,12 @@ +{ + "resource": "/put_user_token", + "path": "/put_user_token", + "httpMethod": "PUT", + "headers": { + "authorization": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjo5MDAwMDAwMDAxNzAzNzMzMDAwLCJpc3MiOiJMaUZvbGkifQ.XKvRcbkWP9a4J-lfDvcZ6O01patJzvuS1n11d4VPtBQ,eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MjcsImlhdCI6MTcwMzczMjc5MywiZXhwIjoxNzA2MzI0NzkzLCJpc3MiOiJMaUZvbGkifQ.6Pox2D4qm0ABi_w2AjY8hbkbIDODR8arDi7p9pNs12g" + }, + "queryStringParameters": null, + "body": { + "token": "test" + } +} \ No newline at end of file diff --git a/features/ActionFunnelLogManager.js b/features/ActionFunnelLogManager.js new file mode 100644 index 0000000..5e2d2cb --- /dev/null +++ b/features/ActionFunnelLogManager.js @@ -0,0 +1,143 @@ +const { ExpectedError } = require("./ExpectedError.js"); + +class ActionFunnelLogManager { + constructor({ user_id, db }) { + this.user_id = user_id; + this.signup = false; + this.move_to_home = false; + this.move_to_product = false; + this.move_to_product_detail = false; + this.search_product = false; + this.start_tikkling = false; + this.send_tikkle = false; + this.db = db; + } + + static async createActionFunnelLogManager({ user_id, db }) { + try { + const action_funnel_log_manager = new ActionFunnelLogManager({ user_id, db }); + await action_funnel_log_manager.getUserLog(); + return action_funnel_log_manager; + } catch (error) { + console.error(`🚨 error -> ⚡️ createActionFunnelLogManager : 🐞 ${error}`); + throw new ExpectedError(error); + } + } + + async markFunnelLog(action) { + try { + switch (action) { + case "signup": + this.signup = true; + break; + case "move_to_home": + console; + this.move_to_home = true; + break; + case "move_to_product": + this.move_to_product = true; + break; + case "move_to_product_detail": + this.move_to_tikkling = true; + break; + case "search_product": + this.search_product = true; + break; + case "start_tikkling": + this.start_tikkling = true; + break; + case "send_tikkle": + this.send_tikkle = true; + break; + default: + break; + } + } catch (error) { + console.error(`🚨 error -> ⚡️ markFunnelLog : 🐞 ${error}`); + throw new ExpectedError(error); + } + } + async getUserLog() { + try { + const user_logs = await this.db.executeQuery(`SELECT * FROM funnel_log WHERE user_id = ?`, [this.user_id]); + const log_id_dic = { + 1: "signup", + 2: "move_to_home", + 3: "move_to_product", + 4: "move_to_product_detail", + 5: "search_product", + 6: "start_tikkling", + 8: "send_tikkle", + }; + for (const log of user_logs) { + await this.markFunnelLog(log_id_dic[log.funnel_action_id]); + } + if (this.signup == false) { + await this.db.executeQuery(`INSERT INTO funnel_log (user_id, funnel_action_id) VALUES (?, ?)`, [this.user_id, 1]); + this.signup = true; + } + } catch (error) { + console.error(`🚨 error -> ⚡️ getUserLog : 🐞 ${error}`); + throw new ExpectedError(error); + } + } + + async logControllInterface(route) { + try { + switch (route) { + case "/post_auth_registerUser": + if (this.signup == false) { + this.signup = true; + await this.db.executeQuery(`INSERT INTO funnel_log (user_id, funnel_action_id) VALUES (?, ?)`, [this.user_id, 1]); + } + break; + + case "/get_user_myWishlist": + if (this.move_to_home == false) { + this.move_to_tikkling = true; + await this.db.executeQuery(`INSERT INTO funnel_log (user_id, funnel_action_id) VALUES (?, ?)`, [this.user_id, 2]); + } + break; + case "/post_product_list": + if (this.move_to_product == false) { + this.move_to_home = true; + await this.db.executeQuery(`INSERT INTO funnel_log (user_id, funnel_action_id) VALUES (?, ?)`, [this.user_id, 3]); + } + + break; + case "/post_product_info": + if (this.move_to_product_detail == false) { + this.move_to_product_detail = true; + await this.db.executeQuery(`INSERT INTO funnel_log (user_id, funnel_action_id) VALUES (?, ?)`, [this.user_id, 4]); + } + break; + + case "/post_product_search": + if (this.search_product == false) { + this.search_product = true; + await this.db.executeQuery(`INSERT INTO funnel_log (user_id, funnel_action_id) VALUES (?, ?)`, [this.user_id, 5]); + } + break; + case "/post_tikkling_create": + if (this.start_tikkling == false) { + this.start_tikkling = true; + await this.db.executeQuery(`INSERT INTO funnel_log (user_id, funnel_action_id) VALUES (?, ?)`, [this.user_id, 6]); + } + break; + case "/post_payment_init/:tikkleAction": + if (this.send_tikkle == false) { + this.send_tikkle = true; + await this.db.executeQuery(`INSERT INTO funnel_log (user_id, funnel_action_id) VALUES (?, ?)`, [this.user_id, 8]); + } + break; + default: + break; + } + } catch (error) { + console.error(`🚨 error -> ⚡️ logControllInterface : 🐞 ${error}`); + throw new ExpectedError(error); + } + } +} + +module.exports = { ActionFunnelLogManager }; diff --git a/features/BankDetail.js b/features/BankDetail.js new file mode 100644 index 0000000..4e024a2 --- /dev/null +++ b/features/BankDetail.js @@ -0,0 +1,35 @@ +const { queryDatabase, queryDatabase_multi } = require("db.js"); +const { getSSMParameter } = require("ssm.js"); +const crypto = require("crypto"); +const { ExpectedError } = require("./ExpectedError.js"); + +class BankDetail { + constructor({ bank_code, bank_name, account, db }) { + this.bank_code = bank_code || null; + this.bank_name = bank_name || null; + this.account = account || null; + this.db = db || null; + } + + async validateBankData() {} + + async encryptAccount() { + try { + const algorithm = "aes-256-cbc"; // Use the same algorithm that was used for encryption + const accountkeyHex = await getSSMParameter("accountkeyHex"); + const accountivHex = await getSSMParameter("accountivHex"); + + const key = Buffer.from(accountkeyHex, "hex"); + const iv = Buffer.from(accountivHex, "hex"); + const cipher = crypto.createCipheriv(algorithm, key, iv); + + let encryptedAccount = cipher.update(this.account, "utf-8", "hex"); + encryptedAccount += cipher.final("hex"); + this.account = encryptedAccount; + } catch (error) { + throw error; + } + } +} + +module.exports = { BankDetail }; diff --git a/features/Delivery.js b/features/Delivery.js new file mode 100644 index 0000000..3e326a7 --- /dev/null +++ b/features/Delivery.js @@ -0,0 +1,248 @@ +const { ExpectedError } = require("./ExpectedError.js"); +const { getSSMParameter } = require("ssm.js"); +//=========================================Model======================================================= +class Delivery { + constructor({ + id, + invoice_number, + courier_company_code, + tikkling_id, + state_id, + zonecode, + address, + detail_address, + created_at, + start_delivery_date, + expected_delivery_date, + actual_delivery_date, + courier_company_name, + db, + }) { + this.id = id || null; + this.invoice_number = invoice_number || null; + this.courier_company_code = courier_company_code || null; + this.tikkling_id = tikkling_id || null; + this.state_id = state_id || null; + this.zonecode = zonecode || null; + this.address = address || null; + this.detail_address = detail_address || null; + this.created_at = created_at || null; + this.start_delivery_date = start_delivery_date || null; + this.expected_delivery_date = expected_delivery_date || null; + this.actual_delivery_date = actual_delivery_date || null; + this.courier_company_name = courier_company_name || null; + this.db = db || null; + } + + /** + * @description 객체를 json으로 변환하는 함수 + */ + + toJSON() { + return { + id: this.id, + invoice_number: this.invoice_number, + courier_company_code: this.courier_company_code, + tikkling_id: this.tikkling_id, + state_id: this.state_id, + zonecode: this.zonecode, + address: this.address, + detail_address: this.detail_address, + created_at: this.created_at, + start_delivery_date: this.start_delivery_date, + expected_delivery_date: this.expected_delivery_date, + actual_delivery_date: this.actual_delivery_date, + courier_company_name: this.courier_company_name, + }; + } + + /** + * delivery_info정보를 통해 스마트 택배 api에서 제공하는 배송정보 확인 링크를 생성 + * @returns {string} 배송조회 링크 + */ + async createDeliveryCheckLink() { + const t_key = await getSSMParameter("t_key"); + return `http://info.sweettracker.co.kr/tracking/5?t_key=${t_key}&t_code=${this.courier_company_code}&t_invoice=${this.invoice_number}`; + } + + updateDelivery(row_of_delivery) { + try { + this.id = row_of_delivery.id; + this.invoice_number = row_of_delivery.invoice_number; + this.courier_company_code = row_of_delivery.courier_company_code; + this.tikkling_id = row_of_delivery.tikkling_id; + this.state_id = row_of_delivery.state_id; + this.zonecode = row_of_delivery.zonecode; + this.address = row_of_delivery.address; + this.detail_address = row_of_delivery.detail_address; + this.created_at = row_of_delivery.created_at; + this.start_delivery_date = row_of_delivery.start_delivery_date; + this.expected_delivery_date = row_of_delivery.expected_delivery_date; + this.actual_delivery_date = row_of_delivery.actual_delivery_date; + this.courier_company_name = row_of_delivery.courier_company_name; + } catch (error) { + console.error(`🚨 error -> ⚡️ updateDelivery : 🐞객체의 모든 값이 전달되지 않았습니다.`); + throw ExpectedError({ + status: 500, + detail_code: "00", + message: "서버에러", + }); + } + } + + async loadDeliveryInfoByTikklingId() { + try { + if (this.tikkling_id == null) { + throw new ExpectedError({ + status: 500, + detail_code: "00", + message: "tikkling_id가 없습니다.", + }); + } + const rows = await this.db.executeQuery( + ` + SELECT delivery_info.*, courier_company.name as courier_company_name + FROM delivery_info as delivery_info + INNER JOIN courier_company AS courier_company ON delivery_info.courier_company_code = courier_company.code + WHERE tikkling_id = ?`, + [this.tikkling_id] + ); + + if (rows.length === 0) { + throw new ExpectedError({ + status: 404, + detail_code: "01", + message: "해당 티클링의 시작된 배송 기록이 없습니다.", + }); + } + this.updateDelivery(rows[0]); + } catch (error) { + console.error(`🚨 error -> ⚡️ loadDeliveryInfoByTikklingId : 🐞${error}`); + throw error; + } + } + + /** + * 유저아이디를 받고 해당 유저의 가장 최근 티클링에 대한 배송정보를 가져옴 + * @param {number} user_id + * @returns {void} + * @async + * + */ + async getRecentDeliveryInfoOfUser(user_id) { + try { + const rows = await this.db.executeQuery( + ` + SELECT delivery_info.*, courier_company.name as courier_company_name + FROM delivery_info as delivery_info + INNER JOIN (SELECT * FROM tikkling WHERE user_id = ?) AS user_tikkling ON delivery_info.tikkling_id = user_tikkling.id + INNER JOIN (SELECT * FROM courier_company) AS courier_company ON delivery_info.courier_company_code = courier_company.code + ORDER BY delivery_info.created_at DESC LIMIT 1`, + [user_id] + ); + if (rows.length === 0) { + throw new ExpectedError({ + status: 404, + detail_code: "01", + message: "해당 유저의 배송 기록이 없습니다.", + }); + } + this.updateDelivery(rows[0]); + return; + } catch (error) { + console.error(`🚨 error -> ⚡️ getRecentDeliveryInfoOfUser : 🐞${error}`); + throw error; + } + } + + async updateDeliveryToConfirmed() { + try { + if(this.tikkling_id == null){ + throw new ExpectedError({ + status: 500, + detail_code: "00", + message: "tikkling_id가 없습니다.", + }); + } + if (this.state_id == 4) { + throw new ExpectedError({ + status: 400, + detail_code: "00", + message: "이미 수령처리된 배송정보입니다.", + }); + } + const result = await this.db.executeQuery(`UPDATE delivery_info SET state_id = 4, actual_delivery_date = NOW() WHERE tikkling_id = ?`, [this.tikkling_id]); + + if (result.affectedRows === 0) { + throw new ExpectedError({ + status: 500, + detail_code: "00", + message: "배송 정보 저장 실패", + }); + } + this.state_id = 4; + return; + } catch (error) { + console.error(`🚨 error -> ⚡️ updateDeliveryToConrimed : 🐞${error}`); + throw error; + } + } + + /** + * @description 주어진 티클링 아이디에 해당하는 배송정보를 가져오는 함수 + * @param {number} tikkling_id + * @returns + */ + + async getDeliveryInfoByTikklingId(tikkling_id) { + try { + const rows = await this.db.executeQuery( + ` + SELECT delivery_info.*, courier_company.name as courier_company_name + FROM delivery_info + INNER JOIN courier_company on delivery_info.courier_company_code = courier_company.code + WHERE tikkling_id = ?`, + [tikkling_id] + ); + if (rows.length === 0) { + throw new ExpectedError({ + status: 404, + etail_code: "02", + message: "해당 티클링의 배송 기록이 없습니다.", + }); + } + this.updateDelivery(rows[0]); + return; + } catch (error) { + console.error(`🚨 error -> ⚡️ getDeliveryInfoByTikklingId : 🐞${error}`); + throw error; + } + } + + async saveDeliveryData() { + try { + const result = await this.db.executeQuery(`INSERT INTO delivery_info (tikkling_id, state_id, zonecode, address, detail_address) VALUES (?, ?, ?, ?, ?)`, [ + this.tikkling_id, + this.state_id, + this.zonecode, + this.address, + this.detail_address, + ]); + if (result.affectedRows === 0) { + throw new ExpectedError({ + status: 500, + detail_code: "00", + message: "배송 정보 저장 실패", + }); + } + this.id = result.insertId; + } catch (error) { + console.error(`🚨 error -> ⚡️ saveDeleveryData : 🐞${error}`); + throw error; + } + } +} + +//=========================================Repository======================================================= + +module.exports = { Delivery }; diff --git a/features/ExpectedError.js b/features/ExpectedError.js new file mode 100644 index 0000000..9ade3e3 --- /dev/null +++ b/features/ExpectedError.js @@ -0,0 +1,9 @@ +class ExpectedError extends Error { + constructor({ status, message, detail_code }) { + super(message); + this.status = status; + this.detail_code = detail_code; + } +} + +module.exports = { ExpectedError }; diff --git a/features/InviteEventManager.js b/features/InviteEventManager.js new file mode 100644 index 0000000..763ef8d --- /dev/null +++ b/features/InviteEventManager.js @@ -0,0 +1,173 @@ +const { ExpectedError } = require("./ExpectedError.js"); +const crypto = require("crypto"); +class InviteEventManager { + constructor({ db }) { + this.is_event = true; + this.invited_user_id = null; + this.sent_tikkle_id = null; + this.bonus_tikkle_id = null; + this.tikkling_id = null; + this.inviter_user_id = null; + this.db = db; + } + + async eventProcessAfterTikkleSent(merchant_uid, tikkling_obj, tikkle) { + try { + // 이벤트가 진행중인지 확인 + if (this.is_event === false) return; + // 해당 티클의 정보를 가져옴 + await this._getSentTikkleInfoByMerchantUid(merchant_uid); + // 자기 자신에게 보낸 티클이라면 보너스 티클을 전송하지 않음 + if (this.invited_user_id === this.inviter_user_id) return; + // 해당 유저가 이벤트에 참여한 이력이 있는지 확인 + const userAttendedEvent = await this._checkUserAttendanceForEvent(this.invited_user_id); + // 만약에 없다면 보너스 티클을 전송 + if (userAttendedEvent === false) { + // 전체 보너스 티클이 200만원 이상이라면 보너스 티클을 전송하지 않음 + const bonus_tikkle_amount = await this._carculateBonusTikkleAmount(); + if (bonus_tikkle_amount >= 2000000) { + return; + } + if (bonus_tikkle_amount < 2000000) { + // 보너스 티클을 전송 + await this._sendBonusTikkle(); + // 전송한 보너스 티클을 event table에 기록 + await this._markBonusTikkle(); + await tikkling_obj.checkAndUpdateTikklingStateToEnd({ tikkle_quantity: tikkle.quantity + 1 }); + } + } + return; + } catch (error) { + console.error(`🚨 error -> ⚡️ eventProcessAfterTikkleSent : 🐞 ${error}`); + throw new ExpectedError(error); + } + } + + async eventProcessAfterTikkleRefunded(sent_tikkle_id) { + try { + this.sent_tikkle_id = sent_tikkle_id; + // 엮여있는 보너스 티클을 취소 + await this._cancelBonusTikkleOfTikkle(); + } catch (error) { + console.error(`🚨 error -> ⚡️ eventProcessAfterTikkleRefunded : 🐞 ${error}`); + throw new ExpectedError(error); + } + } + + async eventProcessBeforeTikklingRefund(tikkling_id) { + try { + this.tikkling_id = tikkling_id; + //보너스 티클은 취소 + await this._cancelBonusTikkleOfTikkling(); + } catch (error) { + console.error(`🚨 error -> ⚡️ eventProcessAfterTikkleRefunded : 🐞 ${error}`); + throw new ExpectedError(error); + } + } + + async _getSentTikkleInfoByMerchantUid(merchant_uid) { + try { + const rows = await this.db.executeQuery("SELECT sending_tikkle.id as sent_tikkle_id, sending_tikkle.tikkling_id as tikkling_id, sending_tikkle.user_id as invited_user_id, tikkling.user_id as inviter_user_id FROM sending_tikkle inner join tikkling on sending_tikkle.tikkling_id = tikkling.id WHERE merchant_uid = ?", [merchant_uid]); + this.sent_tikkle_id = rows[0].sent_tikkle_id; + this.tikkling_id = rows[0].tikkling_id; + this.invited_user_id = rows[0].invited_user_id; + this.inviter_user_id = rows[0].inviter_user_id; + } catch (error) { + console.error(`🚨 error -> ⚡️ _getSentTikkleInfoByMerchantUid : 🐞 ${error}`); + throw new ExpectedError(error); + } + } + + //tikkle구매유저가 이전에 티클을 구매한 이력이 있는지 확인 + async _checkUserAttendanceForEvent() { + try { + const rows = await this.db.executeQuery("SELECT * FROM user_invite_event_attandance WHERE invited_user_id = ?", [this.invited_user_id]); + if (rows.length === 0) { + return false; + } + if (rows.length > 0) { + return true; + } + } catch (error) { + console.error(`🚨 error -> ⚡️ _checkUserAttendanceForEvent : 🐞 ${error}`); + throw new ExpectedError(error); + } + } + + //보너스 티클을 전송 + async _sendBonusTikkle() { + try { + const message = "1+1이벤트 보너스 티클!"; + const quantity = 1; + const user_id = 0; + + const timestamp = new Date().getTime(); + const data = `${user_id}${this.sent_tikkle_id}${timestamp}`; + const merchant_uid = crypto.createHash("md5").update(data).digest("hex"); + + const rows = await this.db.executeQuery("SELECT tikkling_id FROM sending_tikkle WHERE id = ?", [this.sent_tikkle_id]); + + const tikkling_id = rows[0].tikkling_id; + const result = await this.db.executeQuery("INSERT INTO sending_tikkle (tikkling_id, user_id, message, quantity, merchant_uid) VALUES (?, ?, ?, ?, ?)", [ + tikkling_id, + user_id, + message, + quantity, + merchant_uid, + ]); + this.bonus_tikkle_id = result.insertId; + } catch (error) { + console.error(`🚨 error -> ⚡️ _sendBonusTikkle : 🐞 ${error}`); + throw new ExpectedError(error); + } + } + + //전송한 보너스 티클을 event table에 기록 + async _markBonusTikkle() { + try { + await this.db.executeQuery("INSERT INTO user_invite_event_attandance (invited_user_id, sending_tikkle_id, bonus_tikkle_id) VALUES (?, ?, ?)", [ + this.invited_user_id, + this.sent_tikkle_id, + this.bonus_tikkle_id, + ]); + } catch (error) { + console.error(`🚨 error -> ⚡️ _markBonusTikkle : 🐞 ${error}`); + throw new ExpectedError(error); + } + } + + //환급시 티클링에 대한 보너스 티클을 결제 취소 처리 + async _cancelBonusTikkleOfTikkling() { + try { + await this.db.executeQuery("UPDATE sending_tikkle SET state_id = 3 WHERE tikkling_id = ? AND user_id = 0", [this.tikkling_id]); + } catch (error) { + console.error(`🚨 error -> ⚡️ _cancelBonusTikkleOfTikkling : 🐞 ${error}`); + throw new ExpectedError(error); + } + } + // + async _cancelBonusTikkleOfTikkle() { + try { + const rows = await this.db.executeQuery("SELECT * FROM user_invite_event_attandance WHERE sending_tikkle_id = ?;", [this.sent_tikkle_id]); + if (rows.length === 0) return; + const bonus_tikkle_id = rows[0].bonus_tikkle_id; + await this.db.executeQuery("UPDATE sending_tikkle SET state_id = 3 WHERE id = ?", [bonus_tikkle_id]); + } catch (error) { + console.error(`🚨 error -> ⚡️ _cancelBonusTikkleOfTikkle : 🐞 ${error}`); + throw new ExpectedError(error); + } + } + + //제공한 보너스 티클이 얼마인지 확인 + async _carculateBonusTikkleAmount() { + try { + const rows = await this.db.executeQuery("SELECT * FROM sending_tikkle WHERE user_id = 0 AND state_id in (1, 2)"); + return rows.length * 5000; + } catch (error) { + console.error(`🚨 error -> ⚡️ _carculateBonusTikkleAmount : 🐞 ${error}`); + throw new ExpectedError(error); + } + } +} + +module.exports = { InviteEventManager }; diff --git a/features/Notice.js b/features/Notice.js new file mode 100644 index 0000000..bff5912 --- /dev/null +++ b/features/Notice.js @@ -0,0 +1,133 @@ +const { queryDatabase, queryDatabase_multi } = require("db.js"); +const { getSSMParameter } = require("ssm.js"); +const axios = require("axios"); +const { ExpectedError } = require("./ExpectedError.js"); + +class Notice { + constructor({ type_id, receive_user_id, send_user_id }) { + this.type_id = type_id; + this.send_user_id = send_user_id; + this.deep_link = "deep_link"; + this.link = "link"; + + this.sender_name = null; //쿼리로 가져옴 + this.message = null; //정보로 조합 + this.receive_user_id = receive_user_id || null; //대신 티클링 아이디가 오는 경우 존재 + } + + /** + * 결제 취소 알림 정보 세팅 & 알림 보냄 + * @example + * const notice = new Notice({ + type_id: 9, + receive_user_id: id, + send_user_id: id, + }); + + await notice.sendPayCancleNoti(merchant_uid); + */ + async sendPayCancleNoti(merchant_uid) { + //----------- set data ----------------------------------------------------------------------// + this.type_id = 9; + this.receive_user_id = this.send_user_id; + + let sqlResult; + try { + const rows = await queryDatabase("select * from sending_tikkle where merchant_uid = ?", [merchant_uid]); + sqlResult = rows; + } catch (err) { + console.error(`🚨 error -> ⚡️getUserById : 🐞${err}`); + throw new ExpectedError({ + status: "500", + message: `서버에러: class Notice sendPayCancleNoti 쿼리 에러`, + detail_code: "00", + }); + } + + if (sqlResult[0].user_id !== this.send_user_id) { + console.error(`🚨 error -> ⚡️getUserById : 🐞본인의 결제가 아님`); + throw new ExpectedError({ + status: "500", + message: `서버에러: class Notice sendPayCancleNoti 본인의 결제가 아님`, + detail_code: "01", + }); + } else if (sqlResult[0].state_id !== 3) { + console.error(`🚨 error -> ⚡️getUserById : 🐞환불된 결제가 아님`); + throw new ExpectedError({ + status: "500", + message: `서버에러: class Notice sendPayCancleNoti 환불된 결제가 아님`, + detail_code: "02", + }); + } + + this.message = sqlResult[0].created_at + "에 결제된 티클의 결제가 서버 문제로 취소 되었어요"; + + //----------- send ----------------------------------------------------------------------// + try { + await queryDatabase( + `INSERT INTO notification + (user_id, message, is_deleted, is_read, notification_type_id, deep_link, link, meta_data, source_user_id) + VALUES (?, ?, 0, 0, 9, ?, ?, ?, ?)`, + [this.receive_user_id, this.message, this.deep_link, this.link, null, this.send_user_id] + ); + } catch (err) { + console.error(`🚨 error -> ⚡️getUserById : 🐞${err}`); + throw new ExpectedError({ + status: "500", + message: `서버에러: class Notice sendPayCancleNoti 에러 전송 쿼리 실패`, + detail_code: "03", + }); + } + } + + /** + * 알림 보내기 + */ + async send() {} + + /** + * + * @returns Notice 객체의 모든 데이터를 str로 반환 + */ + async printData() { + // console.log("type_id : ", this.type_id); + // console.log("send_user_id : ", this.send_user_id); + // console.log("tikkling_id : ", this.tikkling_id); + // console.log("receive_user_id : ", this.receive_user_id); + // console.log("deep_link : ", this.deep_link); + // console.log("link : ", this.link); + // console.log("sender_name : ", this.sender_name); + // console.log("message : ", this.message); + + return ( + "type_id : " + + this.type_id + + "\n" + + "send_user_id : " + + this.send_user_id + + "\n" + + "tikkling_id : " + + this.tikkling_id + + "\n" + + "receive_user_id : " + + this.receive_user_id + + "\n" + + "deep_link : " + + this.deep_link + + "\n" + + "link : " + + this.link + + "\n" + + "sender_name : " + + this.sender_name + + "\n" + + "message : " + + this.message + + "\n" + ); + } + + ///// +} + +module.exports = { Notice }; diff --git a/features/Product.js b/features/Product.js new file mode 100644 index 0000000..ef4adec --- /dev/null +++ b/features/Product.js @@ -0,0 +1,849 @@ +const { ExpectedError } = require("./ExpectedError.js"); + +class OptionCombination { + constructor({ id, product_id, sales_volume, quantity, db }) { + this.id = id || null; + this.product_id = product_id || null; + this.sales_volume = sales_volume || null; + this.quantity = quantity || null; + //TODO: 이것을 사용하는 것으로 모든 옵션 변경 + this.option_combination_detail = {}; + this.db = db || null; + } + + async uploadOptionCombination() { + try { + //TODO: 트렌드메카 재고 업데이트 구현 + + const result = await this.db.executeQuery(`INSERT INTO option_combination (product_id, quantity) values (?, ?)`, [this.product_id, this.quantity]); + for (const category of Object.keys(this.option_combination_detail)) { + const option_id = this.option_combination_detail[category].id; + const query = `INSERT INTO option_combination_detail (combination_id, option_id) VALUES (?, ?)`; + await this.db.executeQuery(query, [result.insertId, option_id]); + } + this.id = result.insertId; + return; + + return; + } catch (error) { + console.error(`🚨 error -> ⚡️ uploadOptionCombination : 🐞${error}`); + throw error; + } + } + + static createOptionCombination(product_id, db) { + try { + return new OptionCombination({ product_id, db }); + } catch (error) { + console.error(`🚨 error -> ⚡️ createOptionCombination : 🐞${error}`); + throw error; + } + } + + /** + * productid에 대한 새로운 option combination을 생성 + * @param {number} quantity 100000 + * @returns void + */ + async insertNewOptionCombination(quantity = 100000) { + try { + const result = await this.db.executeQuery(`INSERT INTO option_combination (product_id, quantity) values (?, ?)`, [this.product_id, quantity]); + this.id = result.insertId; + return; + } catch (error) { + console.error(`🚨 error -> ⚡️ insertNewOptionCombination : 🐞${error}`); + throw error; + } + } + + /** + * 재고를 감소시키는 함수 + * @memberof OptionCombination + * @instance + * @async + * @example + * const option_combination = new OptionCombination({id: 1, db}); + * await option_combination.decreaseQuantity(); + * // => option_combination = { + * // id: 1, + * // product_id: 1, + * // sales_volume: 0, + * // quantity: 99, + * // } + * @returns {Promise} - A promise that resolves with nothing. + * @throws {ExpectedError} Throws an ExpectedError with status 500 if the database query fails. + * @throws {ExpectedError} Throws an ExpectedError with status 400 if the option combination is not valid. + */ + + async decreaseQuantity() { + try { + if (this.quantity) { + this.quantity -= 1; + } + const result = this.db.executeQuery(`UPDATE option_combination SET quantity = quantity - 1 WHERE id = ?`, [this.id]); + if (result.affectedRows === 0) { + throw error; + } + } catch (error) { + console.error(`🚨 error -> ⚡️ decreaseQuantity : 🐞${error}`); + throw error; + } + } + /** + * 재고를 증가시키는 함수 + * @memberof OptionCombination + * @instance + * @async + * @example + * const option_combination = new OptionCombination({id: 1, db}); + * await option_combination.increaseQuantity(); + * // => option_combination = { + * // id: 1, + * // product_id: 1, + * // sales_volume: 0, + * // quantity: 101, + * // } + * @returns {Promise} - A promise that resolves with nothing. + * @throws {ExpectedError} Throws an ExpectedError with status 500 if the database query fails. + * @throws {ExpectedError} Throws an ExpectedError with status 400 if the option combination is not valid. + */ + async increaseQuantity() { + try { + if (this.quantity) { + this.quantity += 1; + } + const result = this.db.executeQuery(`UPDATE option_combination SET quantity = quantity + 1 WHERE id = ?`, [this.id]); + if (result.affectedRows === 0) { + throw error; + } + } catch (error) { + console.error(`🚨 error -> ⚡️ decreaseQuantity : 🐞${error}`); + throw error; + } + } +} + +class ProductOption { + constructor({ id, product_id, category, option, additional_amount, is_deleted, db }) { + this.id = id || null; + this.product_id = product_id || null; + this.category = category; + this.option = option; + this.additional_amount = additional_amount; + this.is_deleted = is_deleted || 0; + this.db = db; + } + + async uploadProductOption() { + try { + const result = await this.db.executeQuery(`INSERT INTO product_option (product_id, category, \`option\`, additional_amount) values (?, ?, ?, ?)`, [ + this.product_id, + this.category, + this.option, + this.additional_amount, + ]); + this.id = result.insertId; + } catch (error) { + console.error(`🚨 error -> ⚡️ uploadProductOption : 🐞${error}`); + throw error; + } + } + + /** + * 해당 옵션이 이미 업로드 되었는지 확인 + * @returns bool + */ + checkIsUploaded() { + try { + if (this.id == null) { + return false; + } + if (this.id != null) { + return true; + } + } catch (error) { + console.error(`🚨 error -> ⚡️ checkIsUploaded : 🐞${error}`); + throw error; + } + } +} +class ProductOptions { + constructor({ product_id, db }) { + this.product_id = product_id; + this.formatted_option = null; + this.formatted_option_combination = null; + this.product_option_list = null; + this.option_combination_list = null; + this.db = db; + } + + //옵션 객체를 받아서 옵션을 업데이터 + // 현재 가지고 있는 옵션 객체로 db없데이트 + // 특정 product_id에 대해 옵션을 가져오기 + // option_list를 받아서 옵션 형태로 수정 + // 현재 가지고 있는 옵션 객체로 db추가 + + /** + * 상품의 모든 옵션을 가져와 list로 반환 + * @returns + */ + async loadProductOptions() { + try { + const rows = await this.db.executeQuery(`SELECT * FROM product_option WHERE product_id = ?;`, [this.product_id]); + return rows; + } catch (error) { + console.error(`🚨 error -> ⚡️ ProductOptions.loadProductOptions : 🐞${error}`); + throw error; + } + } + //TODO: 이름 길이 줄이기, product빼기 + updateProductOptionList(product_option_list) { + try { + this.product_option_list = product_option_list; + } catch (error) { + console.error(`🚨 error -> ⚡️ updateProductOptionList : 🐞${error}`); + throw error; + } + } + + async uploadProductOptionCombinations() { + try { + if (this.formatted_option_combination == null) { + throw new ExpectedError({ + status: 500, + message: "ProductOptions.formatCombinationList()를 먼저 실행해야합니다.", + detail_code: "00", + }); + } + for (const option_combination of this.formatted_option_combination) { + await option_combination.uploadOptionCombination(); + } + } catch (error) { + console.error(`🚨 error -> ⚡️ uploadProductOptionCombinations : 🐞${error}`); + throw error; + } + } + + updateOptionCombinationList(option_combination_list) { + try { + this.option_combination_list = option_combination_list; + } catch (error) { + console.error(`🚨 error -> ⚡️ updateProductOptionCombinationList : 🐞${error}`); + throw error; + } + } + /** + * 이미 서버상에 존재하는 옵션인지 확인 + * @returns bool + */ + async checkIsUploaded() { + try { + for (const options of Object.values(this.formatted_option)) { + // 배열 내 어떤 객체라도 id가 null이 아니면 false 반환 + if (options.some((option) => option.checkIsUploaded())) { + return true; + } + } + // 모든 객체의 id가 null인 경우 + return false; + } catch (error) { + console.error(`🚨 error -> ⚡️ checkIsUploaded : 🐞${error}`); + throw error; + } + } + /** + * 해당 상품 옵션의 옵션 조합 수를 계산 + * @returns number + */ + async getNumOfCombination() { + try { + const num_of_combination = 1; + if (this.formatted_option == null) { + throw new ExpectedError({ + status: 500, + message: "ProductOptions.formatOptionlist()를 먼저 실행해야합니다.", + detail_code: "00", + }); + } + for (category of Object.keys(this.formatted_option)) { + num_of_combination *= this.getFormattedOption().category.length; + } + return num_of_combination; + } catch (error) { + console.error(`🚨 error -> ⚡️ getNumOfCombination : 🐞${error}`); + throw error; + } + } + /** + * productOption을 db상에 업로드 + * 1. 각 옵션을 업로드 + * 2. 각 옵션 갯수에 맞는 option combination생성 + * 3. 각 option combination에 맞는 option combination detail생성 + */ + async uploadProductOptions() { + try { + if (this.formatted_option == null) { + throw new ExpectedError({ + status: 500, + message: "ProductOptions.formatOptionlist()를 먼저 실행해야합니다.", + detail_code: "00", + }); + } + //각 옵션 항목을 업로드 + for (const category of Object.keys(this.formatted_option)) { + for (const option of this.formatted_option[category]) { + await option.uploadProductOption(); + } + } + //옵션 갯수에 맞는 option combination생성 + } catch (error) { + console.error(`🚨 error -> ⚡️ uploadProductOptions : 🐞${error}`); + throw error; + } + } + + /** + * ProductOptions.formatedOption값을 불러옴 + * @returns List + */ + async getFormattedOption() { + try { + if (this.formatted_option == null) { + throw new ExpectedError({ + status: "500", + message: `product.loadProductOptions()를 먼저 실행해야합니다.`, + detail_code: "00", + }); + } + + return this.formatted_option; + } catch (error) { + console.error(`🚨 error -> ⚡️ getFormattedOption : 🐞${error}`); + throw error; + } + } + //FIXME: 복잡성 높음 좀 더 쉬운 코드로 수정 요함 + formatCombinationList() { + try { + if (this.option_combination_list == null) { + throw new ExpectedError({ + stauts: "500", + message: "option_combination_list가 먼저 채워져있어야합니다.", + detail_code: "00", + }); + } + if (this.formatted_option == null) { + throw new ExpectedError({ + status: "500", + message: "formatted_option이 먼저 채워져있어야합니다. ProductOptions.formatOptionList를 먼저 실행하세요.", + detail_code: "00", + }); + } + + let formatted_option_combination = []; + // option_combination_list = [ + // { color: { category: color, option: red }, size: { category: size, option: L } }, + // { color: { category: color, option: red }, size: { category: size, option: L } }, + // { color: { category: color, option: red }, size: { category: size, option: L } }, + // ]; + //option_combination = {color: {category: color, option:red}, size: {category: size, option: L}, quantity: 10} + for (const option_combination of this.option_combination_list) { + const new_option_combination = new OptionCombination({ product_id: this.product_id, db: this.db }); + new_option_combination.quantity = option_combination.quantity || 100000; + let combination_option_obj = {}; + //option_category = color + + //option_combination을 좀 더 체계화 + for (const option_category of Object.keys(option_combination)) { + if (option_category === "quantity") { + continue; + } + const selected_option_list = this.formatted_option[option_category].filter((option_obj) => { + return option_combination[option_category]["option"] == option_obj["option"]; + }); + + if (selected_option_list.length !== 1) { + throw new ExpectedError({ + status: "500", + message: "formatted_option이 이상하게 형성되어있습니다.", + detail_code: "00", + }); + } + + combination_option_obj[option_category] = selected_option_list[0]; + } + new_option_combination.option_combination_detail = combination_option_obj; + formatted_option_combination.push(new_option_combination); + } + this.formatted_option_combination = formatted_option_combination; + } catch (error) { + console.error(`🚨 error -> ⚡️ formatCombinationList : 🐞${error}`); + throw error; + } + } + + async formatOptionList() { + try { + if (this.product_option_list == null) { + throw new ExpectedError({ + status: "500", + message: `product_option_list가 먼저 채워져있어야합니다.`, + detail_code: "00", + }); + } + const option_category_dict = {}; + + this.product_option_list.forEach((option) => { + // 옵션에서 카테고리 추출 + const category = option.category; + // 해당 카테고리가 사전에 아직 존재하지 않으면 초기화 + if (!option_category_dict[category]) { + option_category_dict[category] = []; + } + // 해당 카테고리 리스트에 옵션 추가 + option_category_dict[category].push(new ProductOption({ product_id: this.product_id, ...option, db: this.db })); + }); + this.formatted_option = option_category_dict; + } catch (error) { + console.error(`🚨 error -> ⚡️ formatOptionList : 🐞${error}`); + throw error; + } + } +} + +class Brand { + constructor({ id, brand_name, is_deleted, db }) { + this.id = id || null; + this.brand_name = brand_name || null; + this.is_deleted = is_deleted || null; + this.db = db || null; + } + toJSON() { + return { + id: this.id, + brand_name: this.brand_name, + is_deleted: this.is_deleted, + // 다른 프로퍼티들도 포함시킵니다. + }; + } + + static async checkBrandNameList(brand_name_list, db) { + try { + //brand_name_list에서 중복을 제거 + brand_name_list = [...new Set(brand_name_list)]; + //기존에 존재하는 브랜드인지 확인 + const placeholders = brand_name_list.map(() => "?").join(", "); + // 쿼리를 실행할 때 placeholders를 사용하고 배열의 요소들을 전달합니다. + const result = await db.executeQuery(`SELECT * FROM brands WHERE brand_name IN (${placeholders})`, [...brand_name_list]); + //존재하지 않는브랜드는 새로 생성 + let brand_obj_list = []; + + for (const brand_name of brand_name_list) { + const brandExists = result.some((brand) => brand.brand_name === brand_name); + if (!brandExists) { + const temp_result = await db.executeQuery(`INSERT INTO brands (brand_name) VALUES (?)`, [brand_name]); + const newBrand = new Brand({ id: temp_result.insertId, brand_name: brand_name, db }); + const newBrandObj = newBrand.toJSON(); + brand_obj_list.push(newBrandObj); + } else { + const brand = result.find((brand) => brand.brand_name === brand_name); + const existingBrand = new Brand({ id: brand.id, brand_name: brand_name, db }); + const existingBrandObj = existingBrand.toJSON(); + brand_obj_list.push(existingBrandObj); + } + } + + return brand_obj_list; + } catch (error) { + console.error(`🚨 error -> ⚡️ checkBrandNameList : 🐞${error}`); + throw error; + } + } +} + +class Product { + constructor({ id, name, price, description = null, category_id, thumbnail_image, brand_id, created_at, views, is_deleted, wishlist_count, images, db }) { + this.id = id || null; + this.name = name || null; + this.price = price || null; + this.description = description || ""; + this.category_id = category_id || null; + this.brand_id = brand_id || null; + this.created_at = created_at || null; + this.views = views || null; + this.is_deleted = is_deleted || null; + this.wishlist_count = wishlist_count || null; + this.thumbnail_image = thumbnail_image || null; + this.images = images || null; + this.product_options = id == null ? null : new ProductOptions({ product_id: id, db: db }); + this.selected_options = null; + this.selected_option_combination = null; + this.db = db; + } + + static async checkIsUploaded(product_name, db) { + try { + const result = await db.executeQuery(`SELECT * FROM products WHERE name = ?`, [product_name]); + if (result.length === 0) { + return false; + } + return true; + } catch (error) { + console.error(`🚨 error -> ⚡️ checkIsUploaded : 🐞${error}`); + throw error; + } + } + + static async createUnregisteredProduct(product, db) { + try { + if (product.product_option_list == null || product.option_combination_list == null) { + throw new ExpectedError({ + status: 500, + message: "새로운 상품 등록일 경우 product.product_option_list, product.option_combination_list가 있어야합니다.", + detail_code: "00", + }); + } + //product 등록 + const newProduct = new Product({ ...product, db }); + await newProduct.enrollProduct(); + newProduct.product_options = new ProductOptions({ product_id: newProduct.id, db: newProduct.db }); + newProduct.product_options.updateOptionCombinationList(product.option_combination_list); + newProduct.product_options.updateProductOptionList(product.product_option_list); + return newProduct; + } catch (error) { + console.error(`🚨 error -> ⚡️ createUnregisteredProduct : 🐞${error}`); + throw error; + } + } + + /** + * 상품이 갖고있는 모든 옵션을 로드하고 해당 옵션을 product_options에 저장한다. + * @memberof Product + */ + async loadProductOptions() { + try { + const product_option_list = await this.product_options.loadProductOptions(); + this.product_options.updateProductOptionList(product_option_list); + + await this.product_options.formatOptionList(); + + return; + } catch (error) { + console.error(`🚨 error -> ⚡️ loadProductOptions : 🐞${error}`); + throw new ExpectedError({ + status: "500", + message: `서버에러`, + detail_code: "00", + }); + } + } + + async uploadProduct() { + try { + const result = await this.db.executeQuery( + `INSERT INTO products (name, price, description, category_id, brand_id, views, is_deleted, thumbnail_image, images) values (?, ?, ?, ?, ?, ?, ?, ?, ?)` + ); + this.id = result.insertId; + return; + } catch (error) { + console.error(`🚨 error -> ⚡️ uploadProduct : 🐞${error}`); + throw error; + } + } + //selected option이 실제 존재하는 option인지 검증하는 함수 + async validateProductOption(selectedOption) { + try { + for (const [category, option] of Object.entries(selectedOption)) { + // 선택된 옵션의 카테고리와 일치하는 제품 옵션을 찾는다. + + const formatted_option = await this.product_options.getFormattedOption(); + // 일치하는 카테고리가 없으면, 선택된 옵션은 유효하지 않다. + if (category in Object.keys(formatted_option)) { + throw new ExpectedError({ + status: "400", + message: `해당 옵션은 존재하지 않습니다.`, + detail_code: "01", + }); + } + // 일치하는 카테고리가 있다면, 선택된 옵션이 유효한지 확인한다. + if (!formatted_option[category].some((productOption) => productOption.option === option)) { + throw new ExpectedError({ + status: "400", + message: `해당 옵션은 존재하지 않습니다.`, + detail_code: "01", + }); + } + } + } catch (error) { + console.error(`🚨 error -> ⚡️ validateProductOption : 🐞${error}`); + throw error; + } + } + + // 선택한 option_combination의 재고가 남아있는지 확인하는 함수 + /** + * 선택한 옵션 조합의 재고가 남아있는지 확인하는 함수 + * @memberof Product + * @instance + * @async + * @example + * const product = await Product.createById(1); + * await product.loadSelectedProductOptionCombination(); + * product.validateProductOptionCombination(); + * // => product.selected_option_combination = { + * // id: 1, + * // sales_volume: 0, + * // quantity: 100, + + * // } + * @returns {Promise} - A promise that resolves with nothing. + * @throws {ExpectedError} Throws an ExpectedError with status 400 if the selected option combination is not valid. + */ + validateProductOptionCombination() { + if (this.selected_option_combination.quantity === 0) { + throw new ExpectedError({ + status: "400", + message: `해당 옵션 조합의 재고가 없습니다.`, + detail_code: "02", + }); + } + } + + //TODO: 서브쿼리 사용하여 최적화 요함 + async loadSelectedProductOptionCombination() { + try { + const selected_option_values = Object.values(this.selected_options); + const count = selected_option_values.length; + const formattedValues = selected_option_values.map((val) => `'${val}'`).join(", "); + const findCombinationQuery = ` + SELECT oc.* + FROM option_combination AS oc + INNER JOIN option_combination_detail AS ocd ON oc.id = ocd.combination_id + INNER JOIN product_option AS po ON po.id = ocd.option_id + WHERE po.option IN (${formattedValues}) AND oc.product_id = ? + GROUP BY oc.id + HAVING COUNT(*) = ?; + `; + + const result = await this.db.executeQuery(findCombinationQuery, [this.id, count]); + if (result.length === 0) { + throw new ExpectedError({ + status: "400", + message: `해당 옵션 조합이 존재하지 않습니다.`, + detail_code: "01", + }); + } + + const option_combination = new OptionCombination({ ...result[0], db: this.db }); + this.selected_option_combination = option_combination; + } catch (error) { + console.error(`🚨 error -> ⚡️ loadSelectedProductOptionCombination : 🐞${error}`); + throw new ExpectedError({ + status: "500", + message: `서버에러`, + detail_code: "00", + }); + } + } + + //product의 가격을 계산하고 해당 가격을 input값과 비교 + /** + * 상품의 가격을 계산하고 해당 가격을 input값과 비교하는 함수 + * @memberof Product + * @instance + * @async + * @example + * const product = await Product.createById(1); + * await product.loadSelectedProductOptionCombination(); + * product.validateProductOptionCombination(); + * product.validateProductPrice(10000); + * // => product.selected_option_combination = { + * // id: 1, + * // product_id: 1, + * // sales_volume: 0, + * // quantity: 100, + * // } + * @returns {Promise} - A promise that resolves with nothing. + * @throws {ExpectedError} Throws an ExpectedError with status 400 if the product price is not valid. + * @param {number} input_price - The price of the product to validate. + */ + async validateProductPrice(input_price) { + try { + const totalPrice = await this.calculateTotalPrice(); + if (totalPrice !== input_price) { + throw new ExpectedError({ + status: "400", + message: `상품의 가격이 일치하지 않습니다.`, + detail_code: "03", + }); + } + } catch (error) { + console.error(`🚨 error -> ⚡️ validateProductPrice : 🐞${error}`); + if (error.status) { + throw error; + } + throw new ExpectedError({ + status: "500", + message: `서버에러`, + detail_code: "00", + }); + } + } + + async lockProduct() { + try { + this.db.executeQuery(`SELECT * FROM products WHERE id = ? FOR UPDATE;`, [this.id]); + } catch (err) { + console.error(`🚨 error -> ⚡️ lockProductForStartTIkkling : 🐞 ${err}`); + throw new ExpectedError({ + status: "500", + message: `서버에러`, + detail_code: "00", + }); + } + } + + async updateSelectedOption(product_option) { + this.selected_options = product_option; + } + + //product_option의 addition_amount와 selectedoption을 고려하여 product의 전체 가격을 계산하는 함수 + async calculateTotalPrice() { + try { + let additionalAmount = 0; + const formatted_option = await this.product_options.getFormattedOption(); + for (const category of Object.keys(formatted_option)) { + additionalAmount += await formatted_option[category].find((option) => { + return option.option == this.selected_options[category]; + }).additional_amount; + } + return this.price + additionalAmount; + } catch (error) { + console.error(`🚨 error -> ⚡️ calculateTotalPrice : 🐞${error}`); + throw new ExpectedError({ + status: "500", + message: `서버에러`, + detail_code: "00", + }); + } + } + + /** + * id를 사용하여 Product 인스턴스를 생성한다. + * @memberof Product + * @static + * @async + * @example + * const db = new DBManager(); + * await db.openTransaction(); + * const product = await Product.createById(1, db); + * // => product = { + * // id: 1, + * // name: "티클링 상품", + * // price: 10000, + * // description: "티클링 상품입니다.", + * // category_id: 1, + * // brand_id: 1, + * // created_at: "2020-01-01 00:00:00", + * // views: 0, + * // is_deleted: 0, + * // wishlist_count: 0, + * // thumbnail_image: "https://tikkle-image.s3.ap-northeast-2.amazonaws.com/1.jpg", + * // images: [ + * // "https://tikkle-image.s3.ap-northeast-2.amazonaws.com/1.jpg", + * // "https://tikkle-image.s3.ap-northeast-2.amazonaws.com/2.jpg", + * // "https://tikkle-image.s3.ap-northeast-2.amazonaws.com/3.jpg", + * // ], + * // product_options: [], + * // selected_options: null, + * // selected_option_combination: null, + * // } + * @throws {ExpectedError} Throws an ExpectedError with status 500 if the database query fails. + * @param {number} id - The id of the product to create. + * @returns {Promise} - A promise that resolves with a Product instance. + */ + static createById = async ({ id, db }) => { + try { + const query = `SELECT * FROM products WHERE id = ?`; + const rows = await db.executeQuery(query, [id]); + return new Product({ ...rows[0], db }); + } catch (error) { + console.error(`🚨 error -> ⚡️ createById : 🐞${error}`); + throw new ExpectedError({ + status: "500", + message: `서버에러`, + detail_code: "00", + }); + } + }; + + async decreaseProductQuantity() { + try { + this.selected_option_combination.decreaseQuantity(); + } catch (error) { + console.error(`🚨 error -> ⚡️ decreaseProductQuantity : 🐞${error}`); + throw error; + } + } + async increaseProductSalesVolume() { + try { + if (this.sales_volume) { + this.sales_volume += 1; + } + const result = this.db.executeQuery(`UPDATE products SET sales_volume = sales_volume + 1 WHERE id = ?`, [this.id]); + if (result.affectedRows === 0) { + throw ExpectedError({ + status: 500, + detail_code: "00", + message: "상품 판매량 증가 실패", + }); + } + } catch (error) { + console.error(`🚨 error -> ⚡️ increaseQuantity : 🐞${error}`); + throw error; + } + } + + static async createProductList(product_list, db) { + try { + const product_obj_list = []; + for (const product of product_list) { + product_obj_list.push(new Product(product, db)); + } + return product_obj_list; + } catch (error) { + console.error(`🚨 error -> ⚡️ createProductList : 🐞${error}`); + throw error; + } + } + /** + * 개별 상품 등록 + */ + async enrollProduct() { + try { + const rows = await this.db.executeQuery(`SELECT * FROM products WHERE name = ?`, [this.name]); + if (rows.length == 0) { + const result_of_insert_product = await this.db.executeQuery(`INSERT INTO products (name, price, description, category_id, brand_id, thumbnail_image, images) VALUES (?, ?, ?, ?, ?, ?, ?)`, [ + this.name, + this.price, + this.description, + this.category_id, + this.brand_id, + this.thumbnail_image, + this.images, + ]); + this.id = result_of_insert_product.insertId; + return result_of_insert_product.insertId; + } + if (rows.length == 1) { + this.id = rows[0].id; + return rows[0].id; + } + } catch (error) { + console.error(`🚨 error -> ⚡️ enrollProduct : 🐞${error}`); + throw error; + } + } +} + +module.exports = { Product, OptionCombination, Brand }; diff --git a/features/Refund.js b/features/Refund.js new file mode 100644 index 0000000..da76e7e --- /dev/null +++ b/features/Refund.js @@ -0,0 +1,62 @@ +const { getSSMParameter } = require("ssm.js"); +const crypto = require("crypto"); +const { ExpectedError } = require("./ExpectedError.js"); + +class Refund { + constructor({ id, tikkling_id, bank_code, account, created_at, state_id, expected_refund_amount, actual_refund_amount, refund_date, db }) { + this.id = id || null; + this.tikkling_id = tikkling_id || null; + this.bank_code = bank_code || null; + this.account = account || null; + this.created_at = created_at || null; + this.state_id = state_id || null; + this.expected_refund_amount = expected_refund_amount || null; + this.actual_refund_amount = actual_refund_amount || null; + this.refund_date = refund_date || null; + this.db = db || null; + } + + async saveRefund() { + try { + const result = await this.db.executeQuery(`INSERT INTO refund (tikkling_id, bank_code, account, expected_refund_amount) VALUES (?, ?, ?, ?)`, [ + this.tikkling_id, + this.bank_code, + this.account, + this.expected_refund_amount, + ]); + this.id = result.insertId; + } catch (error) { + throw error; + } + } + + async loadDataByTikklingId() { + try { + const rows = await this.db.executeQuery(`SELECT * FROM refund WHERE tikkling_id = ?`, [this.tikkling_id]); + if (rows.length === 0) { + throw new ExpectedError({ + status: 404, + detail_code: "01", + message: "해당 티클링에 대한 환불 정보를 찾을 수 없습니다.", + }); + } + const refund = rows[0]; + this.id = refund.id; + this.tikkling_id = refund.tikkling_id; + this.bank_code = refund.bank_code; + this.account = refund.account; + this.created_at = refund.created_at; + this.state_id = refund.state_id; + this.expected_refund_amount = refund.expected_refund_amount; + this.actual_refund_amount = refund.actual_refund_amount; + this.refund_date = refund.refund_date; + + return; + } catch (error) { + console.error(`🚨 error -> ⚡️ loadDataByTikklingId : 🐞${error}`); + throw error; + } + } +} + +module.exports = { Refund }; diff --git a/features/Response.js b/features/Response.js new file mode 100644 index 0000000..8904ae8 --- /dev/null +++ b/features/Response.js @@ -0,0 +1,8 @@ + +class Response { + static create = (success, detail_code, message, data, token) => { + return{success, detail_code, message, data, token}; + } +} + +module.exports = { Response }; \ No newline at end of file diff --git a/features/Tikkle.js b/features/Tikkle.js new file mode 100644 index 0000000..af4a800 --- /dev/null +++ b/features/Tikkle.js @@ -0,0 +1,550 @@ +const { getSSMParameter } = require("ssm.js"); +const axios = require("axios"); +const { ExpectedError } = require("./ExpectedError.js"); +const crypto = require("crypto"); + +//TODO: 매일 밤 12시에 결제 되지 않았고 12시간이 지났으면 해당 결제 실패 처리 + +class PaymentParam { + constructor({ user_name, user_phone, amount, merchant_uid, notice_url }) { + this.pg = getSSMParameter("pg"); + this.pay_method = "trans"; + this.merchant_uid = merchant_uid; + this.name = "티클"; + this.buyer_name = user_name; + this.buyer_tel = user_phone; + //TODO: redirect url 필요한 파라미터인지 다시 체크 + this.m_redirect_url = "https://www.naver.com/"; + this.app_scheme = "example"; + this.amount = amount; + this.notice_url = notice_url; + } +} + +class Tikkle { + constructor({ id, tikkling_id, user_id, message, quantity = null, state_id, merchant_uid, created_at = null, db }) { + this.id = id || null; + this.tikkling_id = tikkling_id || null; + this.user_id = user_id || null; + this.message = message || null; + this.quantity = quantity; + this.state_id = state_id || null; + this.merchant_uid = merchant_uid || this.generateMerchantUid(); + this.amount = quantity * 5000; + this.created_at = created_at; + this.db = db; + } + + updateFromDatabaseResult(dbResult) { + Object.keys(this).forEach((key) => { + if (dbResult.hasOwnProperty(key)) { + this[key] = dbResult[key]; + } + }); + } + + validateSendMessageRequest() { + try { + if (this.state_id !== 7) { + throw new ExpectedError({ + status: "403", + message: `메세지 전송용 티클은 state_id가 7이어야 합니다.`, + detail_code: "00", + }); + } + if (this.message == null) { + throw new ExpectedError({ + status: "403", + message: `메세지 전송용 티클은 메세지가 필요합니다.`, + detail_code: "00", + }); + } + } catch (error) { + console.error(`🚨 error -> ⚡️ validateSendMessageRequest : 🐞${error}`); + throw error; + } + } + + /** + * 티클 결제정보를 결제 대기 상태로 DB에 저장 + * @returns {Promise} - A promise that resolves with the results of the query, including affectedRows, insertId, and warningStatus. + * @throws {ExpectedError} Throws an ExpectedError with status 500 if the database query fails. + * @memberof Tikkle + * @instance + * @async + * @example + * const tikkle = new Tikkle({ tikkling_id: 1, user_id: 1, message: '티클 메시지', quantity: 1, state_id: 5 }); + * await tikkle.initTikklePayment(); + */ + async initTikklePayment() { + try { + if (this.state_id != 5) { + console.error(`🚨 error -> ⚡️ getUserById : 🐞 ${"미결제 상태의 티클만 해당 함수를 호출가능"}`); + throw new Error("서버에러"); + } + return await this.db.executeQuery(`INSERT INTO sending_tikkle (tikkling_id, user_id, message, quantity, state_id, merchant_uid) VALUES (?, ?, ?, ?, ?, ?)`, [ + this.tikkling_id, + this.user_id, + this.message, + this.quantity, + this.state_id, + this.merchant_uid, + ]); + } catch (err) { + console.error(`🚨 error -> ⚡️ getUserById : 🐞 ${err}`); + throw new ExpectedError({ + status: "500", + message: `서버에러 :getUserById`, + detail_code: "00", + }); + } + } + + async increaseTikklingTicket() { + try { + const result = await this.db.executeQuery(`UPDATE users SET tikkling_ticket = tikkling_ticket + 1 WHERE id = ?`, [this.user_id]); + if (result.affectedRows == 0) { + throw new ExpectedError({ + status: "500", + message: `서버에러`, + detail_code: "00", + }); + } + } catch (error) { + console.error(`🚨 error -> ⚡️ increaseTikklingTicket : 🐞${error}`); + throw error; + } + } + + async sendMessage() { + try { + const result = await this.db.executeQuery(`INSERT INTO sending_tikkle (tikkling_id, user_id, message, quantity, state_id, merchant_uid) VALUES (?, ?, ?, ?, ?, ?)`, [ + this.tikkling_id, + this.user_id, + this.message, + this.quantity, + this.state_id, + this.merchant_uid, + ]); + if (result.affectedRows == 0) { + throw new ExpectedError({ + status: "500", + message: `서버에러`, + detail_code: "00", + }); + } + } catch (error) { + console.error(`🚨 error -> ⚡️ sendMessage : 🐞${error}`); + throw error; + } + } + + /** + * Asynchronously updates the sending_tikkle state_id to 6, "결제 실패" in the database. + * @returns {Promise} - A promise that resolves with the results of the query, including affectedRows, insertId, and warningStatus. + * @throws {ExpectedError} Throws an ExpectedError with status 500 if the database query fails. + * @memberof Payment + * @instance + * @async + * @example + * const payment = new Payment({ user_id: 1, amount: 10000 }); + + * await payment.updateTikkleToFail(); + * // => { affectedRows: 1, insertId: 1, warningStatus: 0 } + * // => sending_tikkle.state_id = 6 + */ + async updateTikkleToFail() { + try { + const result = await this.db.executeQuery(`UPDATE sending_tikkle SET state_id = 6 WHERE merchant_uid = ?`, [this.merchant_uid]); + if (result.affectedRows == 0) { + throw new ExpectedError({ + status: "500", + message: `서버에러 : updateTikkleToFail`, + detail_code: "00", + }); + } else { + this.state_id = 6; + } + } catch (err) { + console.error(`🚨 error -> ⚡️ updatePaymentToCancle : 🐞 ${err}`); + throw new ExpectedError({ + status: "500", + message: `서버에러 : updateTikkleToFail`, + detail_code: "00", + }); + } + } + + /** + * Asynchronously updates the sending_tikkle state_id to 3, "환불" in the database. + * @returns {Promise} - A promise that resolves with the results of the query, including affectedRows, insertId, and warningStatus. + * @throws {ExpectedError} Throws an ExpectedError with status 500 if the database query fails. + * @memberof Payment + * @instance + * @async + * @example + * const payment = new Payment({ user_id: 1, amount: 10000 }); + * await payment.updateTikkleToRefund(); + * // => { affectedRows: 1, insertId: 1, warningStatus: 0 } + * // => sending_tikkle.state_id = 3 + */ + async updateTikkleToRefund() { + try { + const result = await this.db.executeQuery(`UPDATE sending_tikkle SET state_id = 3 WHERE merchant_uid = ?`, [this.merchant_uid]); + + if (result.affectedRows == 0) { + console.error(`🚨 error -> ⚡️ updateTikkleToRefund : 🐞 ${"데이터가 DB상에 반영되지 않음"}`); + throw new ExpectedError({ + status: "500", + message: `서버에러 : updateTikkleToRefund 쿼리결과`, + detail_code: "00", + }); + } else { + this.state_id = 3; + } + } catch (err) { + console.error(`🚨 error -> ⚡️ updateTikkleToRefund : 🐞 ${err}`); + throw new ExpectedError({ + status: "500", + message: `서버에러: updateTikkleToRefund 쿼리`, + detail_code: "00", + }); + } + } + + /** + * //state 가 4이고 terminate 가 없으면 state->4 + * @returns {Promise} - A promise that resolves with the results of the query, including affectedRows, insertId, and warningStatus. + * @throws {ExpectedError} Throws an ExpectedError with status 500 if the database query fails. + * @memberof Payment + * @instance + * @async + * @example + * const payment = new Payment({ user_id: 1, amount: 10000 }); + * await payment.updateTikkleToRefund(); + * // => { affectedRows: 1, insertId: 1, warningStatus: 0 } + * // => sending_tikkle.state_id = 3 + */ + async restart_tikkling() { + try { + //console.log("this.tikkling_id: ", this.tikkling_id); + const result = await this.db.executeQuery(`SELECT * FROM tikkling WHERE id = ?`, [this.tikkling_id]); + + const res = result[0]; + // console.log("res: ", res.user_id); + // funding_limit의 날짜가 오늘보다 이후일때만 재개 + if (res.state_id == 4 && res.terminated_at == null && res.funding_limit > new Date().getTime()) { + const temp = await this.db.executeQuery(`UPDATE tikkling SET state_id = 1 WHERE id = ?`, [this.tikkling_id]); + + if (temp.affectedRows == 0) { + console.error(`🚨 error -> ⚡️ restart_tikkling : 🐞 ${"데이터가 DB상에 반영되지 않음"}`); + throw new ExpectedError({ + status: "500", + message: `서버에러 : restart_tikkling 쿼리결과`, + detail_code: "00", + }); + } + return res.user_id; + } else { + return null; + } + } catch (err) { + console.error(`🚨 error -> ⚡️ restart_tikkling : 🐞 ${err}`); + throw err; + } + } + + /** + * Asynchronously updates the sending_tikkle state_id to 6, "결제 실패" in the database. + * @returns {Promise} - A promise that resolves with the results of the query, including affectedRows, insertId, and warningStatus. + * @throws {ExpectedError} Throws an ExpectedError with status 500 if the database query fails. + * @memberof Tikkle + * @instance + * @async + * @example + * const Tikkle = new Tikkle({ user_id: 1, amount: 10000 }); + * await Tikkle.updateTikkleToFail(); + * // => { affectedRows: 1, insertId: 1, warningStatus: 0 } + * // => sending_tikkle.state_id = 6 + */ + async updateTikkleToFail() { + try { + const result = await this.db.executeQuery(`UPDATE sending_tikkle SET state_id = 6 WHERE merchant_uid = ?`, [this.merchant_uid]); + + if (result.affectedRows == 0) { + console.error(`🚨 error -> ⚡️ updateTikkleToFail : 🐞 ${"데이터가 DB상에 반영되지 않음"}`); + throw new ExpectedError({ + status: "500", + message: `서버에러 : updateTikkleToFail 쿼리결과`, + detail_code: "00", + }); + } else { + this.state_id = 3; + } + } catch (err) { + console.error(`🚨 error -> ⚡️ updateTikkleToFail : 🐞 ${err}`); + throw new ExpectedError({ + status: "500", + message: `서버에러: updateTikkleToFail 쿼리`, + detail_code: "00", + }); + } + } + + /** + * create payment info + * @param {string} user_name + * @param {string} user_phone_number + * @returns {PaymentParam} + * @memberof Payment + * @instance + * @example + * const payment = new Payment({ user_id: 1, amount: 10000 }); + * payment.createPaymentParam('홍길동', '01012345678'); + */ + createPaymentParam({ user_name, user_phone, notice_url }) { + const amount = this.amount; + const merchant_uid = this.merchant_uid; + return new PaymentParam({ + user_name, + user_phone, + amount, + merchant_uid, + notice_url, + }); + } + + /** + * Asynchronously update sending_tikkle state_id to 1, "미사용" in the database. + * @returns {Promise} - A promise that resolves with the results of the query, including affectedRows, insertId, and warningStatus. + * @throws {ExpectedError} Throws an ExpectedError with status 500 if the database query fails. + * @memberof Payment + * @instance + * @async + * @example + * const payment = new Payment({ user_id: 1, amount: 10000 }); + * await payment.completeTikklePayment(); + * // => { affectedRows: 1, insertId: 1, warningStatus: 0 } + * // => sending_tikkle.state_id = 1 + */ + async completeTikklePayment() { + try { + const result = await this.db.executeQuery(`UPDATE sending_tikkle SET state_id = 1 WHERE merchant_uid = ?`, [this.merchant_uid]); + if (result.affectedRows == 0) { + throw new ExpectedError({ + status: "500", + message: `서버에러`, + detail_code: "00", + }); + } else { + this.state_id = 1; + } + } catch (err) { + console.error(`🚨 error -> ⚡️ completeTikklePayment : 🐞 ${err}`); + throw new ExpectedError({ + status: "500", + message: `서버에러:completeTikklePayment`, + detail_code: "00", + }); + } + } + + /** + * Compare stored payment info and request payment info. + * @param {string} user_id - The merchant UID to compare. + * @param {string} amount - The amount to compare. + * + * @returns {void} + * @throws {ExpectedError} Throws an ExpectedError with status 401 if the request is invalid. + * @memberof Payment + * @instance + * @example + * const payment = new Payment({ user_id: 1, amount: 10000 }); + + * payment.compareStoredTikkleData({merchant_uid, amount}); + * // => throw ExpectedError with status 401 if the request is invalid. + */ + compareStoredTikkleData({ user_id }) { + if (this.user_id !== user_id) { + console.error(`🚨 error -> ⚡️ compareStoredTikkleData : 🐞사용자가 일치하지 않습니다.`); + throw new ExpectedError({ + status: "401", + message: `비정상적 접근 : 다른 사용자의 결제 정보`, + detail_code: "00", + }); + } + } + + // + + static async getTikkleByMerchantUid({ merchant_uid, db }) { + try { + const rows = await db.executeQuery(`SELECT * FROM sending_tikkle WHERE merchant_uid = ?`, [merchant_uid]); + if (!Tikkle.checkRowExists(rows)) { + console.error(`🚨 error -> ⚡️ getTikkleByMerchantUid : 🐞 ${"사용자가 존재하지 않는 티클을 검색하였습니다."}`); + throw new ExpectedError({ + status: "403", + message: `비정상적 접근 : 존재하지 않는 티클`, + detail_code: "00", + }); + } + return rows[0]; + } catch (err) { + console.error(`🚨 error -> ⚡️ getTikkleByMerchantUid : 🐞 ${err}`); + throw new ExpectedError({ + status: "500", + message: `서버에러`, + detail_code: "00", + }); + } + } + + static checkRowExists(rows) { + if (rows.length == 0) { + console.error(`🚨 error -> ⚡️ checkRowExists : 🐞 쿼리의 결과가 존재하지 않음`); + return false; + } + return true; + } + + /** + * generate merchant_uid + * @returns {string} - merchant_uid + * @memberof Payment + * @instance + * @example + * const payment = new Payment({ user_id: 1, amount: 10000 }); + * payment.generateMerchantUid(); + * // => 'tikkling_1581234567890' + */ + generateMerchantUid(userID, productID) { + // 입력 파라미터를 하나의 문자열로 합칩니다. + const timestamp = new Date().getTime(); + const data = `${userID}${productID}${timestamp}`; + + const hash = crypto.createHash("md5").update(data).digest("hex"); + + return hash; + } + + /** + * Asynchronously gets the payment api token from iamport. + * @returns {Promise} - A promise that resolves with the access_token. + * @throws {ExpectedError} Throws an ExpectedError with status 500 if the database query fails. + * @memberof Payment + * @instance + * @async + * @example + + * const token = await Payment.getPortOneApiToken(); + */ + static async getPortOneApiToken() { + try { + const imp_key = await getSSMParameter("imp_key"); + const imp_secret = await getSSMParameter("imp_secret"); + + const axios_ret = await axios({ + url: "https://api.iamport.kr/users/getToken", + method: "post", + headers: { "Content-Type": "application/json" }, + data: { + imp_key: imp_key, + imp_secret: imp_secret, + }, + }); + + const response = axios_ret.data; + + return "Bearer " + response.response.access_token; + } catch (error) { + console.error(`🚨 error -> ⚡️ getPortOneApiToken : 🐞import token get error`); + throw new ExpectedError({ + status: "500", + message: `서버에러: 아임포트 토큰 가져오기 실패`, + detail_code: "00", + }); + } + } + + //port one의 특정 결제 취소 api를 호출 + async callPortOneCancelPaymentAPI({ port_one_token, reason }) { + try { + const response = await axios({ + url: "https://api.iamport.kr/payments/cancel", + method: "post", + headers: { + "Content-Type": "application/json", + Authorization: port_one_token, + }, + data: { + merchant_uid: this.merchant_uid, + checksum: this.amount, + reason, + }, + }); + //FIXME: 조건 수정 요함 + if (!response.data) { + console.error(`🚨 error -> ⚡️ callPortOneCancelPaymentAPI : 🐞import token get error`); + throw new ExpectedError({ + status: "500", + message: `서버에러 : 아임포트 결제 취소 실패`, + detail_code: "07", + }); + } + } catch (err) { + console.error(`🚨 error -> ⚡️ callPortOneCancelPaymentAPI : 🐞 ${err}`); + throw new ExpectedError({ + status: "500", + message: `서버에러 아임포트 결제 취소 실패`, + detail_code: "07", + }); + } + } + + /** + * 결제 환불 전에 완료된 결제인지 확인 + * @throws {ExpectedError} Throws an ExpectedError with status 500 if payment state is not "PAYMENT_COMPLETED". + * @memberof Payment + * @instance + * @async + * @example + * await tikkle.checkTikkleCanRefund(); + */ + async checkTikkleCanRefund() { + try { + if (this.state_id !== 1) { + console.error(`🚨 error -> ⚡️ checkTikkleCanRefund : 🐞payment state is not 1`); + throw new ExpectedError({ + status: "403", + message: `사용 혹은 결제되지 않은 티클에 대한 환불 신청`, + detail_code: "01", + }); + } + } catch (err) { + console.error(`🚨 error -> ⚡️ checkTikkleCanRefund : 🐞 ${err}`); + throw new ExpectedError({ + status: "500", + message: `서버에러 : checkTikkleCanRefund`, + + detail_code: "00", + }); + } + } + + assertTikkleIsNotPaid() { + try { + if (this.state_id !== 5) { + throw new ExpectedError({ + status: "403", + message: `비정상적 접근 : 결제가 완료된 티클`, + detail_code: "00", + }); + } + } catch (error) { + console.error(`🚨 error -> ⚡️ assertTikkleIsNotPaid : 🐞${error}`); + throw error; + } + } +} + +module.exports = { Tikkle }; diff --git a/features/Tikkling.js b/features/Tikkling.js new file mode 100644 index 0000000..80add8b --- /dev/null +++ b/features/Tikkling.js @@ -0,0 +1,525 @@ +const { ExpectedError } = require("./ExpectedError.js"); +const { getSSMParameter } = require("ssm.js"); +const axios = require("axios"); + +class Tikkling { + constructor({ id, user_id, funding_limit, created_at = null, tikkle_quantity, product_id, terminated_at, state_id, type, resolution_type, tikkle_count, option_combination_id, db }) { + this.id = id || null; + this.user_id = user_id || null; + this.funding_limit = funding_limit || null; + this.created_at = created_at || null; + this.tikkle_quantity = tikkle_quantity || null; + this.product_id = product_id || null; + this.terminated_at = terminated_at || null; + this.state_id = state_id || null; + this.type = type || null; + this.resolution_type = resolution_type || null; + this.tikkle_count = tikkle_count || null; + this.option_combination_id = option_combination_id || null; + this.db = db; + } + + updateFromDatabaseResult(dbResult) { + Object.keys(this).forEach((key) => { + if (dbResult.hasOwnProperty(key)) { + this[key] = dbResult[key]; + } + }); + } + /** + * Asynchronously loads the active tikkling view info from the database by Tikkling ID. + * @returns {Promise} - A promise that resolves with the results of the query, including affectedRows, insertId, and warningStatus. + * @throws {ExpectedError} Throws an ExpectedError with status 500 if the database query fails. + * @memberof Tikkling + * @instance + * @async + * @example + * const tikkling = new Tikkling({ id: 1 }); + * await tikkling.loadActiveTikklingViewByTikkling_id(); + */ + async loadActiveTikklingViewByUserId() { + try { + const rows = await this.db.executeQuery(`SELECT * FROM tikkling_detail_view WHERE user_id = ? AND terminated_at IS NULL`, [this.user_id]); + if (!Tikkling.checkRowExists(rows)) { + throw new ExpectedError({ + status: "404", + message: `비정상적 요청, 티클링이 존재하지 않습니다.`, + detail_code: "00", + }); + } + let active_tikkling = rows[0]; + active_tikkling.id = active_tikkling.tikkling_id; + this.updateFromDatabaseResult(active_tikkling); + } catch (error) { + console.error(`🚨 error -> ⚡️ loadActiveTikklingViewByUserId : 🐞 ${error}`); + throw error; + } + } + + async loadActiveTikklingViewByTikklingId() { + try { + const rows = await this.db.executeQuery(`SELECT * FROM tikkling_detail_view WHERE tikkling_id = ? AND terminated_at IS NULL`, [this.id]); + if (!Tikkling.checkRowExists(rows)) { + throw new ExpectedError({ + status: "404", + message: `비정상적 요청, 활성화된 티클링이 존재하지 않습니다.`, + detail_code: "00", + }); + } + let active_tikkling = rows[0]; + active_tikkling.id = active_tikkling.tikkling_id; + this.updateFromDatabaseResult(active_tikkling); + } catch (error) { + console.error(`🚨 error -> ⚡️ loadActiveTikklingViewByTikklingId : 🐞 ${error}`); + throw error; + } + } + + static checkRowExists(rows) { + if (rows.length == 0) { + console.error(`🚨 error -> ⚡️ checkRowExists : 🐞 쿼리의 결과가 존재하지 않음`); + return false; + } + return true; + } + + /** + * check if the request is valid + * @returns {void} + * @throws {ExpectedError} Throws an ExpectedError with status 403 if the request is invalid. + * @memberof Tikkling + * @instance + * @example + * const tikkling = new Tikkling({ id: 1 }); + * await tikkling.loadActiveTikklingViewByTikkling_id(); + * tikkling.validateBuyMyTikkleRequest(); + * // => throw ExpectedError with status 403 if the request is invalid. + */ + validateBuyMyTikkleRequest({ user_id, tikkle_quantity }) { + try { + if (parseInt(this.tikkle_quantity) != parseInt(this.tikkle_count) + parseInt(tikkle_quantity)) { + throw new ExpectedError({ + status: "403", + message: `남은 티클의 구매 수량이 정확하지 않습니다.`, + detail_code: "03", + }); + } + if (this.user_id !== user_id) { + throw new ExpectedError({ + status: "403", + message: `비정상적 요청, 해당 티클링의 소유자가 아닙니다.`, + detail_code: "00", + }); + } + if (parseInt(this.tikkle_quantity) == parseInt(this.tikkle_count)) { + throw new ExpectedError({ + status: "403", + message: `이미 모든 티클을 수집한 티클링입니다.`, + detail_code: "01", + }); + } else if (this.state_id !== 3 && this.state_id != 5) { + throw new ExpectedError({ + status: "403", + message: `비정상적 요청, 아직 티클링이 중단되지 않았거나 이미 종료되었습니다.`, + detail_code: "02", + }); + } + } catch (error) { + console.error(`🚨 error -> ⚡️ validateBuyMyTikkleRequest : 🐞 ${error}`); + throw error; + } + } + + assertTikklingIsStopped() { + try { + if (this.state_id == 1) { + throw new ExpectedError({ + status: "403", + message: `비정상적 요청, 아직 진행중인 티클링입니다. 먼저 중단한 뒤 해당 api를 요청하세요`, + detail_code: "01", + }); + } + } catch (error) { + console.error(`🚨 error -> ⚡️ assertMyTikklingIsNotEnded : 🐞 ${error}`); + throw error; + } + } + + assertTikklingisMine({ user_id }) { + try { + if (this.user_id !== user_id) { + throw new ExpectedError({ + status: "401", + message: `비정상적 요청, 해당 티클링의 소유자가 아닙니다.`, + detail_code: "00", + }); + } + } catch (error) { + console.error(`🚨 error -> ⚡️ validateMyTikkling : 🐞 ${error}`); + throw error; + } + } + + validateSendMessageRequest({ sent_user_id }) { + try{ + if (this.user_id == sent_user_id) { + throw new ExpectedError({ + status: "403", + message: `비정상적 요청, 자신에게 티클을 보낼 수 없습니다.`, + detail_code: "00", + }); + } + if (this.terminated_at != null) { + throw new ExpectedError({ + status: "403", + message: `비정상적 요청, 티클링이 진행중이 아닙니다.`, + detail_code: "01", + }); + } + } catch (error) { + console.error(`🚨 error -> ⚡️ validateSendMessageRequest : 🐞 ${error}`); + throw error; + + } + + + } + + async validateSendTikkleRequest({ tikkle_quantity }) { + try { + //티클링이 현재 진행중인지 확인 + if (this.state_id !== 1) { + throw new ExpectedError({ + status: "403", + message: `티클링이 진행중이 아닙니다.`, + detail_code: "01", + }); + } + //보내려는 티클 수량을 받을 수 있는지 확인 + if (parseInt(this.tikkle_quantity) < parseInt(this.tikkle_count) + parseInt(tikkle_quantity)) { + throw new ExpectedError({ + status: "403", + message: `티클을 받을 수 있는 수량을 초과하였습니다.${typeof this.tikkle_quantity} ${typeof this.tikkle_count} ${typeof tikkle_quantity}`, + detail_code: "02", + }); + } + } catch (error) { + console.error(`🚨 error -> ⚡️ validateSendTikkleRequest : 🐞 ${error}`); + throw error; + } + } + + /** + * Asynchronously lock tikkling row for insert tikkle + */ + async lockTikklingForInsertTikkle() { + try { + this.db.executeQuery(`SELECT * FROM tikkling WHERE id = ? FOR UPDATE;`, [this.id]); + } catch (error) { + console.error(`🚨 error -> ⚡️ lockTikklingForInsertTikkle : 🐞 ${error}`); + throw error; + } + } + + async checkAndUpdateTikklingStateToEnd({ tikkle_quantity }) { + try { + if (parseInt(this.tikkle_quantity) == parseInt(this.tikkle_count) + parseInt(tikkle_quantity)) { + await this.db.executeQuery(`UPDATE tikkling SET state_id = 4 WHERE id = ?;`, [this.id]); + } + } catch (error) { + console.error(`🚨 error -> ⚡️ checkAndUpdateTikklingStateToEnd : 🐞 ${error}`); + throw error; + } + } + + async buyMyTikkle({ merchant_uid }) { + try { + const results = await this.db.executeQuery(`INSERT INTO sending_tikkle (tikkling_id, user_id, quantity, merchant_uid) VALUES (?, ?, ?, ?); `, [ + this.id, + this.user_id, + this.tikkle_quantity - this.tikkle_count, + merchant_uid, + ]); + if (results.affectedRows == 0) { + console.error(`🚨 error -> ⚡️ buyMyTikkle : 🐞 티클의 구매가 이루어지지않음`); + throw new ExpectedError({ + status: "500", + message: `서버에러`, + detail_code: "00", + }); + } + } catch (error) { + console.error(`🚨 error -> ⚡️ buyMyTikkle : 🐞 ${error}`); + throw error; + } + } + + /** + * Asynchronously check validation of create tikkling request + * @returns {void} + * @throws {ExpectedError} Throws an ExpectedError with status 403 if the request is invalid. + * @memberof Tikkling + * @instance + * @async + * @example + * const new_tikkling = new Tikkling({ user_id: id, funding_limit, tikkle_quantity, product_id, type, db }); + * tikkling.validateBuyMyTikkleRequest(); + * // => throw ExpectedError with status 403 if the request is invalid. + * + */ + async validateCreaetTikklingRequest() { + try { + //funding_limit 검증 + const difUnit = 8; + const today = new Date(); + const funding_limit = new Date(this.funding_limit); + const diff = funding_limit.getTime() - today.getTime(); + const diffDays = Math.ceil(diff / (1000 * 3600 * 24)); + if (diffDays > difUnit || diffDays < 0) { + throw new ExpectedError({ + status: "403", + message: `잘못된 요청, 티클링 마감일은 ${difUnit}일 이내여야 합니다. 이를 수정하고 싶다면 diffUnit의 변경을 요청해주세요`, + detail_code: "04", + }); + } + } catch (error) { + console.error(`🚨 error -> ⚡️ validateSendTikkleRequest : 🐞 ${error}`); + throw error; + } + } + + async createShareLink(tikkling_id, user_name) { + try{ + const FIREBASE_WEB_API_KEY = await getSSMParameter("FIREBASE_WEB_API_KEY"); + const uriKey = `https://firebasedynamiclinks.googleapis.com/v1/shortLinks?key=${FIREBASE_WEB_API_KEY}`; + const result = await axios({ + method: 'post', + url: uriKey, + data: { + dynamicLinkInfo: { + domainUriPrefix: 'https://tikkle.lifoli.co.kr', + link: `https://tikkle.lifoli.co.kr/tikkling/${tikkling_id}`, + androidInfo: { + androidPackageName: 'com.tikkle_revive_ios', + }, + iosInfo: { + iosBundleId: 'org.reactjs.native.example.tikkle-revive-ios', + iosAppStoreId: '6471217574', + }, + socialMetaTagInfo: { + socialTitle: `${user_name}님의 티클링!`, + socialDescription: `${user_name}님의 티클링을 확인해보세요!`, + socialImageLink: + 'https://d2da4yi19up8sp.cloudfront.net/share_link_image.jpg', + }, + }, + suffix: { + option: 'SHORT', + }, + }, + }); + return result.data.shortLink; + } catch (error) { + console.error(`🚨 error -> ⚡️ createShareLink : 🐞 ${error}`); + throw error; + } + } + /** + * 티클링 생성 + * @returns {void} + * @throws {ExpectedError} Throws an ExpectedError with status 403 if the request is invalid. + * @memberof Tikkling + * @instance + * @async + * @return {number} - 생성된 티클링의 id + * @example + * const new_tikkling = new Tikkling({ user_id: id, funding_limit, tikkle_quantity, product_id, type, db }); + * new_tikkling.saveTikkling(); + * // => throw ExpectedError with status 403 if the request is invalid. + */ + async saveTikkling(user_name) { + try { + const results = await this.db.executeQuery(`INSERT INTO tikkling (user_id, funding_limit, tikkle_quantity, product_id, type, option_combination_id) VALUES (?, ?, ?, ?, ?, ?); `, [ + this.user_id, + this.funding_limit, + this.tikkle_quantity, + this.product_id, + this.type, + this.option_combination_id, + ]); + //tikkling_id와 user_name을 이용하여 share_link 생성 + const share_link = await this.createShareLink(results.insertId, user_name); + //tikkling에 share_linke 추가 + await this.db.executeQuery(`UPDATE tikkling SET share_link = ? WHERE id = ?;`, [share_link, results.insertId]); + if (results.affectedRows == 0) { + console.error(`🚨 error -> ⚡️ createTikkling : 🐞 티클링 생성 실패`); + throw error; + } + return results.insertId; + } catch (error) { + console.error(`🚨 error -> ⚡️ createTikkling : 🐞 ${error}`); + throw error; + } + } + + //받은 티클이 0인지 확인 + assertTikkleCountIsZero() { + try { + if (this.tikkle_count != 0) { + throw new ExpectedError({ + status: "401", + message: `티클을 받은 상태입니다.`, + detail_code: "00", + }); + } + } catch (error) { + console.error(`🚨 error -> ⚡️ assertTikkleCountIsZero : 🐞 ${error}`); + throw error; + } + } + + //받은 티클이 0인지 확인 + assertTikkleCountIsNotZero() { + try { + if (this.tikkle_count == 0) { + throw new ExpectedError({ + status: "401", + message: `티클을 받지 않은 상태입니다.`, + detail_code: "00", + }); + } + } catch (error) { + console.error(`🚨 error -> ⚡️ assertTikkleCountIsZero : 🐞 ${error}`); + throw error; + } + } + + decreaseTikklingTicket() { + try { + this.db.executeQuery(`UPDATE users SET tikkling_ticket = tikkling_ticket - 1 WHERE id = ?`, [this.user_id]); + } catch (error) { + console.error(`🚨 error -> ⚡️ decreaseTikkleQuantity : 🐞 ${error}`); + throw error; + } + } + + async increaseTikklingTicket() { + try { + await this.db.executeQuery(`UPDATE users SET tikkling_ticket = tikkling_ticket + 1 WHERE id = ?`, [this.user_id]); + } catch (error) { + console.error(`🚨 error -> ⚡️ increaseTikklingTicket : 🐞 ${error}`); + throw error; + } + } + + async decreaseOptionCombinationQuantity() { + try { + await this.db.executeQuery(`UPDATE option_combination SET quantity = quantity + 1 WHERE id = ?`, [this.option_combination_id]); + } catch (error) { + console.error(`🚨 error -> ⚡️ increaseOptionCombinationQuantity : 🐞 ${error}`); + throw error; + } + } + + increaseOptionCombinationQuantity() { + try { + this.db.executeQuery(`UPDATE option_combination SET quantity = quantity + 1 WHERE id = ?`, [this.option_combination_id]); + } catch (error) { + console.error(`🚨 error -> ⚡️ increaseOptionCombinationQuantity : 🐞 ${error}`); + throw error; + } + } + + //티클링을 취소상태로 만드는 함수 + async cancelTikkling() { + try { + if (this.state_id && this.terminated_at && this.resolution_type) { + this.state_id = 2; + this.terminated_at = new Date(); + this.resolution_type = "cancel"; + } + const results = await this.db.executeQuery(`UPDATE tikkling SET state_id = 2, terminated_at = now(), resolution_type = 'cancel' WHERE id = ?;`, [this.id]); + if (results.affectedRows == 0) { + console.error(`🚨 error -> ⚡️ cancelTikkling : 🐞 티클링 취소 실패`); + throw error; + } + } catch (error) { + console.error(`🚨 error -> ⚡️ cancelTikkling : 🐞 ${error}`); + throw error; + } + } + + async updateTikklingToRefund() { + try { + const results = await this.db.executeQuery(`UPDATE tikkling SET terminated_at = now(), resolution_type = 'refund' WHERE id = ?;`, [this.id]); + if (results.affectedRows == 0) { + throw error; + } + this.resolution_type = "refund"; + } catch (error) { + console.error(`🚨 error -> ⚡️ updateTikklingToRefund : 🐞 ${error}`); + throw error; + } + } + + async updateTikklingToGoods() { + try { + const results = await this.db.executeQuery(`UPDATE tikkling SET terminated_at = now(), resolution_type = 'goods' WHERE id = ?;`, [this.id]); + if (results.affectedRows == 0) { + throw error; + } + this.resolution_type = "goods"; + } catch (error) { + console.error(`🚨 error -> ⚡️ updateTikklingToRefund : 🐞 ${error}`); + throw error; + } + } + + async assertAllTikkleIsArrived() { + try { + if (this.tikkle_count != this.tikkle_quantity) { + throw new ExpectedError({ + status: "400", + message: `아직 모든 티클이 도착하지 않았습니다.`, + detail_code: "01", + }); + } + } catch (error) { + console.error(`🚨 error -> ⚡️ assertAllTikkleIsArrived : 🐞 ${error}`); + throw error; + } + } + + async updateAllTikkleToUsed() { + try { + const result = await this.db.executeQuery(`UPDATE sending_tikkle SET state_id = 2 WHERE tikkling_id = ? AND state_id = 1;`, [this.id]); + if (result.affectedRows == 0) { + throw new ExpectedError({ + status: "400", + message: `사용할 수 있는 티클이 없습니다.`, + detail_code: "01", + }); + } + } catch (error) { + console.error(`🚨 error -> ⚡️ updateTikklingToUsed : 🐞 ${error}`); + throw error; + } + } + async updateAllTikkleToRefund() { + try { + const result = await this.db.executeQuery(`UPDATE sending_tikkle SET state_id = 4 WHERE tikkling_id = ? AND state_id = 1;`, [this.id]); + if (result.affectedRows == 0) { + throw new ExpectedError({ + status: "400", + message: `사용할 수 있는 티클이 없습니다.`, + detail_code: "01", + }); + } + } catch (error) { + console.error(`🚨 error -> ⚡️ updateTikklingToUsed : 🐞 ${error}`); + throw error; + } + } +} + +module.exports = { Tikkling }; diff --git a/features/User.js b/features/User.js new file mode 100644 index 0000000..60fc657 --- /dev/null +++ b/features/User.js @@ -0,0 +1,310 @@ +const { getSSMParameter } = require("ssm.js"); +const { ExpectedError } = require("./ExpectedError.js"); + +class User { + constructor({ + id = null, + name, + birthday, + nick = " ", + phone, + is_deleted = false, + gender, + image = "https://d2da4yi19up8sp.cloudfront.net/profile/profile.png", + zonecode = null, + address = null, + detail_address = null, + created_at = null, + is_tikkling = false, + device_token = null, + tikkling_ticket = 2, + account = null, + bank_code = null, + last_present_amount = null, + funnel = "meta_ad", + source_tikkling_id = null, + db, + }) { + this.id = id; + this.name = name; + this.birthday = birthday; + this.nick = nick; + this.phone = phone; + this.is_deleted = is_deleted; + this.gender = gender; + this.image = image; + this.zonecode = zonecode; + this.address = address; + this.detail_address = detail_address; + this.created_at = created_at; + this.is_tikkling = is_tikkling; + this.device_token = device_token; + this.tikkling_ticket = tikkling_ticket; + this.account = account; + this.bank_code = bank_code; + this.funnel = source_tikkling_id ? "share_link" : funnel; + this.source_tikkling_id = source_tikkling_id; + this.db = db; + this.last_present_amount = last_present_amount; + } + + /** + * Asynchronously creates a new user with the given ID. + * @param {number} id - User ID + * @returns {Promise} - A promise that resolves with a new User instance. + * @throws {ExpectedError} Throws an ExpectedError with status 500 if the database query fails. + * @memberof User + * @static + * @async + * @example + * const user = await User.createById(1); + * // => User { id: 1, name: '홍길동', ... } + */ + static createById = async ({ id, db }) => { + try { + const query = `SELECT * FROM users WHERE id = ?`; + const [user] = await db.executeQuery(query, [id]); + return new User({ ...user, db }); + } catch (error) { + console.error(`🚨 error -> createById : 🐞${error}`); + throw error; + } + }; + + async updateLastPresentAmount(last_present_amount) { + try { + const result = await this.db.executeQuery(`UPDATE users SET last_present_amount = ? WHERE id = ?`, [last_present_amount, this.id]); + if (result.affectedRows !== 1) { + throw new ExpectedError({ + status: 500, + detail_code: "00", + message: "last_present_amount 수정 실패", + }); + } + this.last_present_amount = last_present_amount; + return; + + } + catch (error) { + console.error(`🚨 error -> updateLastPresentAmount : 🐞${error}`); + throw error; + } + } + + + async registerUser() { + try { + const result = await this.db.executeQuery(`INSERT INTO users + (name, birthday, nick, phone, gender, image, address, detail_address, is_tikkling, tikkling_ticket, funnel) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [ + this.name, + this.birthday, + this.nick, + this.phone, + this.gender, + this.image, + this.address, + this.detail_address, + this.is_tikkling, + this.tikkling_ticket, + this.funnel, + ]) + if (result.affectedRows !== 1) { + throw new ExpectedError({ + status: 500, + detail_code: "00", + message: "유저 등록 실패", + }); + } + this.id = result.insertId; + } + catch (error) { + console.error(`🚨 error -> ⚡️ registerUser : 🐞${error}`); + throw error; + } + } + + async logIfUserFromTikkling() { + try { + if (this.source_tikkling_id) { + const result = await this.db.executeQuery(`INSERT INTO shared_tikkling_signup_log (tikkling_id, user_id) VALUES (?, ?)`, [this.source_tikkling_id, this.id]); + if (result.affectedRows !== 1) { + throw new ExpectedError({ + status: 500, + detail_code: "00", + message: "유저 등록 실패", + }); + } + } + } + catch (error) { + console.error(`🚨 error -> logIfUserFromTikkling : 🐞${error}`); + throw error; + } + } + + async validateUserForRegister() { + try { + //유저 이름 유효성 검증 + if (!this.name || typeof this.name !== "string" || this.name.length > 30) { + //return invalid + throw new ExpectedError({ + status: "400", + message: `비정상적 요청, 이름 데이터가 올바르지 않습니다.`, + detail_code: "01", + }); + } + + //유저 생일 유효성 검증 + const parsedDate = new Date(this.birthday); + if (isNaN(parsedDate) || Object.prototype.toString.call(parsedDate) !== "[object Date]") { + throw new ExpectedError({ + status: "400", + message: `비정상적 요청, 생일 데이터가 올바르지 않습니다.`, + detail_code: "02", + }); + } + + // Check if the string matches the numeric pattern and its length is between 9 and 12 + const numericPattern = /^\d+$/; + if (!this.phone || typeof this.phone !== "string" || this.phone.length < 9 || this.phone.length > 11 || !numericPattern.test(this.phone)) { + throw new ExpectedError({ + status: "400", + message: `비정상적 요청, 전화번호 데이터가 올바르지 않습니다.`, + detail_code: "05", + }); + } + // 성별 데이터 체크 + if (!this.gender || typeof this.gender !== "string" || !(this.gender === "male" || this.gender === "female" || this.gender === "others")) { + throw new ExpectedError({ + status: "400", + message: `비정상적 요청, 성별 데이터가 올바르지 않습니다.`, + detail_code: "06", + }); + } + + //닉네임 유효성 검증 + // if (!this.nick || typeof this.nick !== "string" || this.nick.length > 30) { + // throw new ExpectedError({ + // status: "400", + // message: `비정상적 요청, 닉네임 데이터가 올바르지 않습니다.`, + // detail_code: "04", + // }); + // } + } + catch (error) { + console.error(`🚨 error -> validateUserForRegister : 🐞${error}`); + throw error; + } + } + + async restrictUserUnder14() { + try { + const dob = new Date(this.birthday); + const today = new Date(); + let age = today.getFullYear() - dob.getFullYear(); + + // Check if birthday hasn't occurred yet this year + if (today.getMonth() < dob.getMonth() || (today.getMonth() === dob.getMonth() && today.getDate() < dob.getDate())) { + age--; + } + if (age < 14) { + throw new ExpectedError({ + status: "400", + message: `회원가입 실패, 만 14세 미만은 가입할 수 없습니다.`, + detail_code: "03", + }); + } + } catch (error) { + console.error(`🚨 error -> restrictUserForRegister : 🐞${error}`); + throw error; + } + } + + + async validatteUserForStartTikkling() { + try { + // 현재 티클링이 진행중인지 확인 + if (this.is_tikkling) { + throw new ExpectedError({ + status: "403", + message: `비정상적 요청, 이미 티클링중인 유저입니다.`, + detail_code: "01", + }); + } + // 티클링 티켓이 남아있는지 확인 + if (this.tikkling_ticket == 0) { + throw new ExpectedError({ + status: "403", + message: `비정상적 요청, 티클링 티켓이 없습니다.`, + detail_code: "02", + }); + } + } catch (error) { + console.error(`🚨 error -> ⚡️ validatteUser : 🐞 ${error}`); + throw error; + } + } + async decreaseTikkleTicket() { + try { + if (this.tikkling_ticket) { + this.tikkling_ticket -= 1; + } + const query = `UPDATE users SET tikkling_ticket = tikkling_ticket - 1 WHERE id = ?`; + await this.db.executeQuery(query, [this.id]); + } catch (error) { + console.error(`🚨 error -> decreaseTikkleTicket : 🐞${error}`); + throw error; + } + } + + async increaseTikkleTicket() { + try { + if (this.tikkling_ticket) { + this.tikkling_ticket += 1; + } + const query = `UPDATE users SET tikkling_ticket = tikkling_ticket + 1 WHERE id = ?`; + await this.db.executeQuery(query, [this.id]); + } catch (error) { + console.error(`🚨 error -> decreaseTikkleTicket : 🐞${error}`); + throw error; + } + } + + async deleteWishlist(product_id) { + try { + const query = `DELETE FROM user_wish_list WHERE user_id = ? AND product_id = ?`; + await this.db.executeQuery(query, [this.id, product_id]); + } catch (error) { + console.error(`🚨 error -> deleteWishlist : 🐞${error}`); + throw error; + } + } + + validateAddress() { + try { + if ( + !this.zonecode || + !this.address || + !this.detail_address || + typeof this.zonecode !== "string" || + typeof this.address !== "string" || + typeof this.detail_address !== "string" || + this.zonecode.length !== 5 || + this.address.length > 250 || + this.detail_address.length > 250 + ) { + throw new ExpectedError({ + status: "400", + message: `비정상적 요청, 주소 데이터가 올바르지 않습니다.`, + detail_code: "05", + }); + } + } catch (error) { + console.error(`🚨 error -> validateAddress : 🐞${error}`); + throw error; + } + } +} + +module.exports = { User }; diff --git a/index.js b/index.js new file mode 100644 index 0000000..eed4b8c --- /dev/null +++ b/index.js @@ -0,0 +1,274 @@ +"use strict"; +const api = require("lambda-api")(); +const { authtoken } = require("authtoken.js"); + +//-------- require modules ------------------------------------------------// +// +//auth +const { get_auth_checkToken } = require("./tikkle_auth/get_auth_checkToken/index.js"); +const { get_auth_event } = require("./tikkle_auth/get_auth_event/index.js"); +const { get_auth_kToken } = require("./tikkle_auth/get_auth_kToken/index.js"); +const { post_auth_IdDuplicationCheck } = require("./tikkle_auth/post_auth_IdDuplicationCheck/index.js"); +const { post_auth_phoneCheck } = require("./tikkle_auth/post_auth_phoneCheck/index.js"); +const { post_auth_registerUser } = require("./tikkle_auth/post_auth_registerUser/index.js"); +const { post_auth_tokenGenerate } = require("./tikkle_auth/post_auth_tokenGenerate/index.js"); +const { post_auth_version } = require("./tikkle_auth/post_auth_version/index.js"); +const { post_auth_loginKakao } = require("./tikkle_auth/post_auth_loginKakao/index.js"); +const { post_auth_appleLogin } = require("./tikkle_auth/post_auth_appleLogin/index.js"); +const { post_auth_appleRegister } = require("./tikkle_auth/post_auth_appleRegister/index.js"); + +//friend +const { get_friend_data } = require("./tikkle_friend/get_friend_data/index.js"); +const { get_friend_event } = require("./tikkle_friend/get_friend_event/index.js"); +const { get_friend_search } = require("./tikkle_friend/get_friend_search/index.js"); +const { get_friend_searchPhone } = require("./tikkle_friend/get_friend_searchPhone/index.js"); +const { post_friend_phonecheck } = require("./tikkle_friend/post_friend_phonecheck/index.js"); +const { put_friend_block } = require("./tikkle_friend/put_friend_block/index.js"); +const { post_user_friendDeep } = require("./tikkle_friend/post_user_friendDeep/index.js"); + +//image +const { get_image_deleteProfile } = require("./tikkle_image/get_image_deleteProfile/index.js"); +const { get_image_profileSaveUrl } = require("./tikkle_image/get_image_profileSaveUrl/index.js"); +const { post_image_profileUrl } = require("./tikkle_image/post_image_profileUrl/index.js"); +const { post_product_id } = require("./tikkle_product/post_product_id/index.js"); + +//notification +const { get_notification_list } = require("./tikkle_notification/get_notification_list/index.js"); +const { post_notification_send } = require("./tikkle_notification/post_notification_send/index.js"); +const { put_notification_delete } = require("./tikkle_notification/put_notification_delete/index.js"); + +//post +const { post_product_images } = require("./tikkle_product/post_product_images/index.js"); +const { post_product_info } = require("./tikkle_product/post_product_info/index.js"); +const { post_product_list } = require("./tikkle_product/post_product_list/index.js"); +const { post_product_inputInfo } = require("./tikkle_product/post_product_inputInfo/index.js"); +const { put_product_viewIncrease } = require("./tikkle_product/put_product_viewIncrease/index.js"); + +//tikkling +const { get_tikkling_friendinfo } = require("./tikkle_tikkling/get_tikkling_friendinfo/index.js"); +const { get_tikkling_info } = require("./tikkle_tikkling/get_tikkling_info/index.js"); +const { post_tikkling_receivedTikkle } = require("./tikkle_tikkling/post_tikkling_receivedTikkle/index.js"); +const { post_tikkling_create } = require("./tikkle_tikkling/post_tikkling_create/index.js"); +const { post_user_getTikklingDetail } = require("./tikkle_tikkling/post_user_getTikklingDetail/index.js"); +const { put_tikkling_end } = require("./tikkle_tikkling/put_tikkling_end/index.js"); +const { post_tikkling_sendtikkle } = require("./tikkle_tikkling/post_tikkling_sendtikkle/index.js"); +const { put_tikkling_cancel } = require("./tikkle_tikkling/put_tikkling_cancel/index.js"); + +//user +const { delete_user_wishlist } = require("./tikkle_user/delete_user_wishlist/index.js"); +const { get_user_checkTikkling } = require("./tikkle_user/get_user_checkTikkling/index.js"); +const { get_bank_data } = require("./tikkle_user/get_bank_data/index.js"); +const { get_user_endTikklings } = require("./tikkle_user/get_user_endTikklings/index.js"); +const { get_user_info } = require("./tikkle_user/get_user_info/index.js"); +const { get_user_myWishlist } = require("./tikkle_user/get_user_myWishlist/index.js"); +const { get_user_paymentHistory } = require("./tikkle_user/get_user_paymentHistory/index.js"); +const { post_user_friend } = require("./tikkle_user/post_user_friend/index.js"); +const { post_user_wishlist } = require("./tikkle_user/post_user_wishlist/index.js"); +const { get_user_isNotice } = require("./tikkle_user/get_user_isNotice/index.js"); +const { get_user_deleteUser } = require("./tikkle_user/get_user_deleteUser/index.js"); +const { put_user_address } = require("./tikkle_user/put_user_address/index.js"); +const { put_user_nick } = require("./tikkle_user/put_user_nick/index.js"); +const { put_user_account } = require("./tikkle_user/put_user_account/index.js"); +const { put_user_token } = require("./tikkle_user/put_user_token/index.js"); +const { put_tikkling_stop } = require("./tikkle_tikkling/put_tikkling_stop/index.js"); +const { put_user_birthday } = require("./tikkle_user/put_user_birthday/index.js"); +const { put_user_kakaoImage } = require("./tikkle_user/put_user_kakaoImage/index.js"); + +//payment +const { get_payment_apiToken } = require("./tikkle_payment/get_payment_apiToken/index.js"); + +const { post_payment_init } = require("./tikkle_payment/post_payment_init/index.js"); + +const { put_payment_fail } = require("./tikkle_payment/put_payment_fail/index.js"); + +const { post_payment_finalize } = require("./tikkle_payment/post_payment_finalize/index.js"); + +const { post_payment_getData } = require("./tikkle_payment/post_payment_getData/index.js"); + +const { put_payment_refund } = require("./tikkle_payment/put_payment_refund/index.js"); +const { get_product_options } = require("./tikkle_product/get_product_options/index.js"); +const { post_product_brand } = require("./tikkle_product/post_product_brand/index.js"); +const { post_product_enrollment } = require("./tikkle_product/post_product_enrollment/index.js"); +const { get_tikkling_deliveryinfo } = require("./tikkle_tikkling/get_tikkling_deliveryinfo/index.js"); +const { actionFunnelLogger } = require("./actinoFunnelLogger.js"); +const { get_tikkling_refundinfo } = require("./tikkle_tikkling/get_tikkling_refundinfo/index.js"); +const { put_user_lastpresentamount } = require("./tikkle_user/put_user_lastpresentamount/index.js"); +const { put_tikkling_deliveryconfirm } = require("./tikkle_tikkling/put_tikkling_deliveryconfirm/index.js"); +const { post_tikkling_sendmessage } = require("./tikkle_tikkling/post_tikkling_sendmessage/index.js"); + +// + +//-------- API's ------------------------------------------------// + +//------- auth +api.get("/get_auth_checkToken", get_auth_checkToken); + +api.get("/get_auth_event", get_auth_event); +api.get("/get_auth_kToken", get_auth_kToken); + +api.post("/post_auth_IdDuplicationCheck", post_auth_IdDuplicationCheck); + +api.post("/post_auth_phoneCheck", post_auth_phoneCheck); +// 유저 funnel logging +api.post("/post_auth_registerUser", post_auth_registerUser); + +api.post("/post_auth_tokenGenerate", post_auth_tokenGenerate); + +api.post("/post_auth_version", post_auth_version); + +api.post("/post_auth_loginKakao", post_auth_loginKakao); + +api.post("/post_auth_appleLogin", post_auth_appleLogin); + +api.post("/post_auth_appleRegister", post_auth_appleRegister); + +// + +//------- friend + +api.get("/get_friend_data/:mode", authtoken, get_friend_data); + +api.get("/get_friend_event", authtoken, get_friend_event); + +api.get("/get_friend_search/:nick", authtoken, get_friend_search); + +api.post("/post_friend_phonecheck", authtoken, post_friend_phonecheck); + +api.post("/post_user_friendDeep", authtoken, post_user_friendDeep); + +api.get("/get_friend_searchPhone/:phone", authtoken, get_friend_searchPhone); + +api.put("/put_friend_block", authtoken, put_friend_block); + +// + +//------- image + +api.get("/get_image_deleteProfile", authtoken, get_image_deleteProfile); + +api.get("/get_image_profileSaveUrl", authtoken, get_image_profileSaveUrl); + +api.post("/post_image_profileUrl", authtoken, post_image_profileUrl); + +// + +//------- notification + +api.get("/get_notification_list", authtoken, get_notification_list); + +api.post("/post_notification_send", authtoken, post_notification_send); + +api.put("/put_notification_delete", authtoken, put_notification_delete); + +// + +//------- product +api.post("/post_product_images", authtoken, post_product_images); +// 유저 funnel logging +api.post("/post_product_info", authtoken, actionFunnelLogger, post_product_info); + +api.post("/post_product_inputInfo", authtoken, post_product_inputInfo); +// 유저 funnel logging +api.post("/post_product_list", authtoken, actionFunnelLogger, post_product_list); + +api.post("/post_product_id", authtoken, post_product_id); + +api.put("/put_product_viewIncrease", authtoken, put_product_viewIncrease); + +api.get("/get_product_options/:product_id", authtoken, get_product_options); + +api.post("/post_product_brand", authtoken, post_product_brand); + +api.post("/post_product_enrollment", authtoken, post_product_enrollment); +// + +//------- tikkling +api.get("/get_tikkling_friendinfo", authtoken, get_tikkling_friendinfo); +// 유저 funnel logging +api.get("/get_tikkling_info/:tikkling_id", authtoken, get_tikkling_info); + +api.post("/post_tikkling_receivedTikkle", authtoken, post_tikkling_receivedTikkle); +// 유저 funnel logging +api.post("/post_tikkling_create", authtoken, actionFunnelLogger, post_tikkling_create); + +api.post("/post_user_getTikklingDetail", authtoken, post_user_getTikklingDetail); + +api.put("/put_tikkling_end/:type", authtoken, put_tikkling_end); + +api.put("/put_tikkling_cancel", authtoken, put_tikkling_cancel); + +api.put("/put_tikkling_stop", authtoken, put_tikkling_stop); + +api.get("/get_tikkling_deliveryinfo/:tikkling_id", authtoken, get_tikkling_deliveryinfo); + +api.get("/get_tikkling_refundinfo/:tikkling_id", authtoken, get_tikkling_refundinfo); + +api.put("/put_tikkling_deliveryconfirm", authtoken, put_tikkling_deliveryconfirm); + +api.post("/post_tikkling_sendmessage", authtoken, post_tikkling_sendmessage); +// + +//------- user +api.delete("/delete_user_wishlist", authtoken, delete_user_wishlist); + +api.get("/get_user_checkTikkling", authtoken, get_user_checkTikkling); + +api.get("/get_user_endTikklings", authtoken, get_user_endTikklings); + +api.get("/get_user_info", authtoken, get_user_info); + +api.get("/get_user_myWishlist", authtoken, actionFunnelLogger, get_user_myWishlist); + +api.get("/get_user_paymentHistory", authtoken, get_user_paymentHistory); + +api.get("/get_bank_data", authtoken, get_bank_data); + +api.post("/post_user_friend", authtoken, post_user_friend); + +api.post("/post_user_wishlist", authtoken, post_user_wishlist); + +api.get("/get_user_isNotice", authtoken, get_user_isNotice); + +api.get("/get_user_deleteUser", authtoken, get_user_deleteUser); + +api.put("/put_user_address", authtoken, put_user_address); + +api.put("/put_user_nick", authtoken, put_user_nick); + +api.put("/put_user_account", authtoken, put_user_account); + +api.put("/put_user_token", authtoken, put_user_token); + +api.put("/put_user_birthday", authtoken, put_user_birthday); + +api.put("put_user_lastpresentamount", authtoken, put_user_lastpresentamount); + +api.put("put_user_kakaoImage", authtoken, put_user_kakaoImage); + +// + +//------- payment +api.get("/get_payment_apiToken", authtoken, get_payment_apiToken); + +api.post("/post_payment_init/:tikkleAction", authtoken, post_payment_init); + +api.put("/put_payment_fail", authtoken, put_payment_fail); + +api.post("/post_payment_getData", authtoken, post_payment_getData); + +api.post("/post_payment_finalize/:tikkleAction", post_payment_finalize); + +api.put("/put_payment_refund", authtoken, put_payment_refund); + +// + +api.post("/apple_login_test", (req, res) => { + console.log(req.body); + res.status(200).json({ message: "success" }); +}); + +//-------- handler ------------------------------------------------// + +exports.handler = async (req, context) => { + return await api.run(req, context); +}; diff --git a/lambda_layer/db.js b/lambda_layer/db.js new file mode 100644 index 0000000..097695c --- /dev/null +++ b/lambda_layer/db.js @@ -0,0 +1,42 @@ +const mysql = require("mysql2/promise"); +const { getSSMParameter } = require("ssm.js"); + +async function getDatabaseCredentials() { + const host = "61.109.238.126"; + const user = "HeungkyuLee"; + const password = "GpRYnSzxuv59"; + const database = "tikkle_db_dev"; + return { host, user, password, database, multipleStatements: true}; +} + +async function queryDatabase_multi(sql, params) { + let connection; + try { + const credentials = await getDatabaseCredentials(); + connection = await mysql.createConnection(credentials); + const [rows] = await connection.query(sql, params); + return rows; + } catch (error) { + throw error; + } finally { + if (connection) await connection.end(); + } +} + +async function queryDatabase(sql, params) { + let connection; + try { + const credentials = await getDatabaseCredentials(); + connection = await mysql.createConnection(credentials); + const [rows] = await connection.execute(sql, params); + return rows; + } catch (error) { + throw error; + } finally { + if (connection) await connection.end(); + } +} + +exports.queryDatabase_multi = queryDatabase_multi; +exports.queryDatabase = queryDatabase; +exports.getDatabaseCredentials = getDatabaseCredentials; \ No newline at end of file diff --git a/lambda_layer/fcm.js b/lambda_layer/fcm.js new file mode 100644 index 0000000..679e6bf --- /dev/null +++ b/lambda_layer/fcm.js @@ -0,0 +1,111 @@ +const admin = require("firebase-admin"); +const serviceAccount = require("./tikkle-c9666-firebase-adminsdk-knplx-fcb6d4f595.json"); + +const firebaseKeys = { + type: serviceAccount.type, + projectId: serviceAccount.project_id, + privateKeyId: serviceAccount.private_key_id, + privateKey: serviceAccount.private_key, + clientEmail: serviceAccount.client_email, + clientId: serviceAccount.client_id, + authUri: serviceAccount.auth_uri, + tokenUri: serviceAccount.token_uri, + authProviderX509CertUrl: serviceAccount.auth_provider_x509_cert_url, + clientC509CertUrl: serviceAccount.client_x509_cert_url, +}; + +admin.initializeApp({ + credential: admin.credential.cert(firebaseKeys), +}); + +exports.fcm_send = async (token, title, body, link) => { + const message = { + token, + android: { + priority: "high", + notification: { + sound: "default", + title: title, //기기 푸시 알림 제목 + body: body, //기기 푸시알림 내용 + }, + data: { + link: link, + }, + }, + apns: { + payload: { + aps: { + sound: "default", + "content-available": 1, + alert: { + //아이폰 알림 창 + title: title, + body: body, + "action-loc-key": "PLAY", + }, + }, + link: link, + title: title, + body: body, + }, + }, + }; + + admin + .messaging() + .send(message) + .then((response) => { + console.log("push success: ", response); + return true; + }) + .catch((error) => { + console.log("push error: ", error); + return false; + }); +}; + +exports.fcm_send_many = async (tokens, title, body, link) => { + const message = { + android: { + priority: "high", + notification: { + sound: "default", + title: title, //기기 푸시 알림 제목 + body: body, //기기 푸시알림 내용 + }, + data: { + link: link, + }, + }, + apns: { + payload: { + aps: { + sound: "default", + "content-available": 1, + alert: { + //아이폰 알림 창 + title: title, + body: body, + "action-loc-key": "PLAY", + }, + }, + link: link, + title: title, + body: body, + }, + }, + tokens: tokens, + }; + + admin + .messaging() + .sendMulticast(message) + .then(function (res) { + console.log("Successfully sent message: : ", res); + return; + }) + .catch(function (err) { + console.log("Error Sending message!!! : ", err); + return; + }); +}; diff --git a/lambda_layer/ssm.js b/lambda_layer/ssm.js new file mode 100644 index 0000000..f823e5b --- /dev/null +++ b/lambda_layer/ssm.js @@ -0,0 +1,22 @@ +const AWS = require("aws-sdk"); + +exports.getSSMParameter = async (input) => { + // Create an SSM client + //console.log("input : ", input); + + const ssm = new AWS.SSM(); + + try { + // Get the parameter value + const response = await ssm + .getParameter({ Name: input, WithDecryption: true }) + .promise(); + + // Access the parameter value from the response + const parameterValue = response.Parameter.Value; + + return parameterValue; + } catch { + return null; + } +}; diff --git a/lambda_layer/token.js b/lambda_layer/token.js new file mode 100644 index 0000000..186373d --- /dev/null +++ b/lambda_layer/token.js @@ -0,0 +1,93 @@ +const jwt = require("jsonwebtoken"); +const { getSSMParameter } = require("ssm.js"); + + +exports.checkToken = async (accessToken, refreshToken) => { + /////// Token check ////////////////////////////////////////////////////////////////// + let ReturnToken = null; + let tokenData = null; + + const accessTokenSecret = await getSSMParameter("accessTokenSecret"); + + try { + const decodedToken = jwt.decode(accessToken, accessTokenSecret); + tokenData = decodedToken; + + // Step 2: Validate the access token + if (decodedToken.exp < getCurrentTimeInSeconds()) { + //엑세스 만료 시 + if (!refreshToken) { + //리프레쉬 토큰 없는 경우 + return { + statusCode: 401, + body: "Log in again", + }; + } + + const refreshTokenSecret = await getSSMParameter("refreshTokenSecret"); + const decodedRefreshToken = jwt.decode( + refreshToken, + refreshTokenSecret + ); + + // Step 4: Validate the refresh token + if (decodedRefreshToken.exp < getCurrentTimeInSeconds()) { + //리프레쉬 만료시 + return { + statusCode: 401, + body: "Log in again", + }; + } + + // Step 5: Refresh the access token + const newAccessToken = await generateAccessToken( + decodedRefreshToken.id, + accessTokenSecret + ); + ReturnToken = newAccessToken; + tokenData = jwt.decode(newAccessToken, accessTokenSecret); + } + + } catch (error) { + return { + statusCode: 401, + body: "Invalid token", + }; + } + + /////// return success ////////////////////////////////////////////////////////////////// + + const returnBody = JSON.stringify({ + accessToken: ReturnToken, + tokenData: tokenData, + }); + return { + statusCode: 200, + body: returnBody, + }; +}; + +const generateAccessToken = async ( + id, + accessTokenSecret +) => { + const issuer = await getSSMParameter("issuer"); + + const accessTokenPayload = { + id, + iat: Math.floor(Date.now() / 1000), // Issued At timestamp in seconds + exp: Math.floor(Date.now() / 1000) + 15 * 60, // Expiration time in seconds (15 minutes) + iss: issuer, // Use the environment variable directly + + }; + + // Generate the access token + const accessToken = jwt.sign(accessTokenPayload, accessTokenSecret); + + return accessToken; +}; + + +function getCurrentTimeInSeconds() { + return Math.floor(Date.now() / 1000); +} diff --git a/schema.sql b/schema.sql new file mode 100644 index 0000000..cb224a3 --- /dev/null +++ b/schema.sql @@ -0,0 +1,985 @@ +CREATE DATABASE tikkle_db + CHARACTER SET utf8mb4 + COLLATE utf8mb4_general_ci; + +use tikkle_db; +-- CREATE USER 'HeungkyuLee'@'%' IDENTIFIED BY 'password'; +-- GRANT ALL PRIVILEGES ON tikkle_db.* TO 'HeungkyuLee'@'%' WITH GRANT OPTION; +-- FLUSH PRIVILEGES; + + +-- SET GLOBAL time_zone = 'Asia/Seoul'; + +CREATE TABLE invalid_version ( + os ENUM('android', 'ios') NOT NULL, + version VARCHAR(255) NOT NULL, + PRIMARY KEY (os, version) +); + + +CREATE TABLE bank ( + bank_code INT PRIMARY KEY, + bank_name VARCHAR(255), + UNIQUE (`bank_name`) +); + +INSERT INTO bank (bank_code, bank_name) VALUES +(2,'산업은행'), +(3,'기업은행'), +(92,'토스뱅크'), +(4,'국민은행'), +(5,'외환은행'), +(7,'수협은행/수협중앙회'), +(11,'NH농협'), +(12,'농협중앙회'), +(20,'우리은행'), +(23,'SC 제일은행'), +(27,'한국씨티은행'), +(31,'대구은행'), +(32,'부산은행'), +(34,'광주은행'), +(35,'제주은행'), +(37,'전북은행'), +(39,'경남은행'), +(45,'새마을금고중앙회'), +(48,'신협중앙회'), +(50,'상호저축은행'), +(54,'HSBC 은행'), +(55,'도이치은행'), +(57,'제이피모간체이스은행'), +(60,'BOA은행'), +(62,'중국공상은행'), +(64,'산림조합중앙회'), +(71,'우체국'), +(81,'KEB 하나은행'), +(88,'신한은행'), +(89,'K뱅크'), +(271,'토스증권'), +(90,'카카오뱅크'), +(209,'유안타증권'), +(218,'KB증권'), +(238,'미래에셋증권'), +(240,'삼성증권'), +(243,'한국투자증권'), +(247,'NH 투자증권'), +(261,'교보증권'), +(262,'하이투자증권'), +(263,'현대차투자증권'), +(264,'키움증권'), +(265,'이베스트투자증권'), +(266,'SK 증권'), +(267,'대신증권'), +(269,'한화투자증권'), +(270,'하나금융투자'), +(278,'신한금융투자'), +(279,'동부증권'), +(280,'유진투자증권'), +(287,'메리츠종합금융증권'), +(290,'부국증권'), +(291,'신영증권'), +(292,'케이프투자증권'), +(103,'SBI 저축은행'); + + +CREATE TABLE `users` ( + `id` INT NOT NULL AUTO_INCREMENT, + `name` VARCHAR(30) NOT NULL, + `birthday` DATE NOT NULL, + `nick` VARCHAR(30), + `phone` VARCHAR(30) NOT NULL, + `is_deleted` BOOLEAN NOT NULL DEFAULT false, + `gender` ENUM('male', 'female', 'others') NOT NULL, + `image` TEXT, + `zonecode` VARCHAR(255), + `address` VARCHAR(255), + `detail_address` VARCHAR(255), + `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + `is_tikkling` BOOL NOT NULL DEFAULT false, + `device_token` VARCHAR(255), + `tikkling_ticket` INT NOT NULL DEFAULT 0, + `account` VARCHAR(255) DEFAULT NULL, + `bank_code` INT, + `funnel` ENUM('share_link', 'meta_ad', 'unknown', 'friend') DEFAULT 'meta_ad', + `kakao_email` VARCHAR(255), + `apple_id` VARCHAR(255), + `last_present_amount` INT NOT NULL DEFAULT 0, + PRIMARY KEY (`id`), + FOREIGN KEY (`bank_code`) REFERENCES `bank`(`bank_code`), + UNIQUE (`phone`), + UNIQUE (`kakao_email`), + UNIQUE (`apple_id`) +); + +CREATE TABLE `phones` ( + `phone` VARCHAR(11) NOT NULL, + `user_id` INT NOT NULL, + PRIMARY KEY (`phone`), + FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE +) ENGINE=MEMORY; + +DELIMITER // +-- 새로운 사용자가 추가되면, phones 테이블에 해당 사용자의 id와 phone을 추가 +CREATE TRIGGER `after_insert_user` +AFTER INSERT ON `users` +FOR EACH ROW +BEGIN + INSERT INTO `phones` (`phone`, `user_id`) + VALUES (NEW.`phone`, NEW.`id`); +END; +// +-- 사용자의 전화번호가 변경되면, phones 테이블에서 기존의 전화번호를 삭제하고, 새 전화번호와 id를 추가 +CREATE TRIGGER `after_update_user` +AFTER UPDATE ON `users` +FOR EACH ROW +BEGIN + IF OLD.`phone` <> NEW.`phone` THEN + DELETE FROM `phones` + WHERE `phone` = OLD.`phone`; + + INSERT INTO `phones` (`phone`, `user_id`) + VALUES (NEW.`phone`, NEW.`id`); + END IF; +END; +// +-- 사용자가 삭제되면, phones 테이블에서 해당 사용자의 전화번호를 삭제 +CREATE TRIGGER `after_delete_user` +AFTER DELETE ON `users` +FOR EACH ROW +BEGIN + DELETE FROM `phones` + WHERE `phone` = OLD.`phone`; +END; +// + +DELIMITER ; + +CREATE TABLE `brands` ( + `id` INT NOT NULL AUTO_INCREMENT, + `brand_name` VARCHAR(30) NOT NULL, + `is_deleted` BOOL NOT NULL DEFAULT false, + PRIMARY KEY (`id`) +); + + +-- instance 추가 요함 +CREATE TABLE `product_category` ( + `id` INT NOT NULL AUTO_INCREMENT, + `name` VARCHAR(30) NOT NULL, + PRIMARY KEY (`id`) +); + +CREATE TABLE `products` ( + `id` INT NOT NULL AUTO_INCREMENT, + `name` VARCHAR(255) NOT NULL, + `price` INT NOT NULL, + `description` TEXT NOT NULL, + `category_id` INT NOT NULL, + `brand_id` INT NOT NULL, + `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + `views` INT NOT NULL DEFAULT 0, + `is_deleted` BOOL NOT NULL DEFAULT false, + `wishlist_count` INT NOT NULL DEFAULT 0, + `thumbnail_image` TEXT NOT NULL, + `images` TEXT, + `sales_volume` INT NOT NULL DEFAULT 0, + `noti_id` INT NOT NULL, + PRIMARY KEY (`id`), + FOREIGN KEY (`category_id`) REFERENCES `product_category`(`id`), + FOREIGN KEY (`brand_id`) REFERENCES `brands`(`id`) +); + + +-- 상품 고시정보 테이블들 + +--3 +CREATE TABLE notice_bags ( +product_id INT PRIMARY KEY COMMENT '제품 ID', +p_name VARCHAR(255) NOT NULL COMMENT '상품명', +type VARCHAR(255) NOT NULL COMMENT '종류', +material VARCHAR(255) NOT NULL COMMENT '소재', +color VARCHAR(255) NOT NULL COMMENT '색상', +size VARCHAR(255) NOT NULL COMMENT '크기', +manufacturer_importer VARCHAR(255) NOT NULL COMMENT '제조자/수입자', +origin_country VARCHAR(255) NOT NULL COMMENT '제조국', +precautions TEXT NOT NULL COMMENT '취급시 주의사항', +quality_assurance_standard VARCHAR(255) NOT NULL COMMENT '품질보증기준', +as_manager VARCHAR(255) NOT NULL COMMENT 'A/S 책임자', +as_phone VARCHAR(255) NOT NULL COMMENT 'A/S 전화번호', +FOREIGN KEY (product_id) REFERENCES products(id) +); + +--4 +CREATE TABLE notice_fashionaccessories ( +product_id INT PRIMARY KEY COMMENT '제품 ID', +p_name VARCHAR(255) NOT NULL COMMENT '상품명', +type VARCHAR(255) NOT NULL COMMENT '종류', +material VARCHAR(255) NOT NULL COMMENT '소재', +dimensions VARCHAR(255) NOT NULL COMMENT '치수', +manufacturer_importer VARCHAR(255) NOT NULL COMMENT '제조자/수입자', +origin_country VARCHAR(255) NOT NULL COMMENT '제조국', +precautions TEXT NOT NULL COMMENT '취급시 주의사항', +quality_assurance_standard VARCHAR(255) NOT NULL COMMENT '품질보증기준', +as_manager VARCHAR(255) NOT NULL COMMENT 'A/S 책임자', +as_phone VARCHAR(255) NOT NULL COMMENT 'A/S 전화번호', +FOREIGN KEY (product_id) REFERENCES products(id) +); + +--5 +CREATE TABLE notice_beddingscurtains ( +product_id INT PRIMARY KEY COMMENT '제품 ID', +p_name VARCHAR(255) NOT NULL COMMENT '상품명', +material TEXT NOT NULL COMMENT '제품 소재', +color VARCHAR(255) NOT NULL COMMENT '색상', +dimensions VARCHAR(255) NOT NULL COMMENT '치수', +composition TEXT NOT NULL COMMENT '제품구성', +manufacturer_importer VARCHAR(255) NOT NULL COMMENT '제조자/수입자', +origin_country VARCHAR(255) NOT NULL COMMENT '제조국', +washing_instructions_precautions TEXT NOT NULL COMMENT '세탁방법 및 취급시 주의사항', +quality_assurance_standard VARCHAR(255) NOT NULL COMMENT '품질보증 기준', +as_manager VARCHAR(255) NOT NULL COMMENT 'A/S 책임자', +as_phone VARCHAR(255) NOT NULL COMMENT 'A/S 전화번호', +FOREIGN KEY (product_id) REFERENCES products(id) +); + +--6 +CREATE TABLE notice_furniture ( +product_id INT PRIMARY KEY COMMENT '제품 ID', +p_name VARCHAR(255) NOT NULL COMMENT '상품명', +product_model VARCHAR(255) NOT NULL COMMENT '품명', +kc_certification VARCHAR(255) NOT NULL COMMENT 'KC 인증정보', +color VARCHAR(255) NOT NULL COMMENT '색상', +composition TEXT NOT NULL COMMENT '구성품', +main_material TEXT NOT NULL COMMENT '주요 소재', +manufacturer_importer TEXT NOT NULL COMMENT '제조자/수입자', +origin_country TEXT NOT NULL COMMENT '제조국', +size VARCHAR(255) NOT NULL COMMENT '크기', +refurbish_detail TEXT NOT NULL COMMENT '재공급 가구 정보', +additional_installation_cost VARCHAR(255) NOT NULL COMMENT '배송/설치비용', +quality_assurance_standard VARCHAR(255) NOT NULL COMMENT '품질보증기준', +as_manager VARCHAR(255) NOT NULL COMMENT 'A/S 책임자', +as_phone VARCHAR(255) NOT NULL COMMENT 'A/S 전화번호', +FOREIGN KEY (product_id) REFERENCES products(id) +); + +--7 +CREATE TABLE notice_video_appliances ( +product_id INT PRIMARY KEY COMMENT '제품 ID', +p_name VARCHAR(255) NOT NULL COMMENT '상품명', +product_model VARCHAR(255) NOT NULL COMMENT '품명 및 모델명', +kc_certification VARCHAR(255) NOT NULL COMMENT 'KC 인증정보', +rated_voltage VARCHAR(255) NOT NULL COMMENT '정격전압', +power_consumption VARCHAR(255) NOT NULL COMMENT '소비전력', +energy_efficiency_rating VARCHAR(255) NOT NULL COMMENT '에너지소비효율등급', +release_date VARCHAR(255) NOT NULL COMMENT '동일모델의 출시년월', +manufacturer_importer VARCHAR(255) NOT NULL COMMENT '제조자/수입자', +origin_country VARCHAR(255) NOT NULL COMMENT '제조국', +size VARCHAR(255) NOT NULL COMMENT '크기', +shape TEXT NOT NULL COMMENT '형태', +screen_specifications TEXT NOT NULL COMMENT '화면사양 (화면크기, 해상도, 화면비율 등)', +additional_installation_cost VARCHAR(255) NOT NULL COMMENT '추가설치비용', +quality_assurance_standard VARCHAR(255) NOT NULL COMMENT '품질보증기준', +as_manager VARCHAR(255) NOT NULL COMMENT 'A/S 책임자', +as_phone VARCHAR(255) NOT NULL COMMENT 'A/S 전화번호', +FOREIGN KEY (product_id) REFERENCES products(id) +); + +--8 +CREATE TABLE notice_homeappliances ( +product_id INT PRIMARY KEY COMMENT '제품 ID', +p_name VARCHAR(255) NOT NULL COMMENT '상품명', +product_model VARCHAR(255) NOT NULL COMMENT '품명 및 모델명', +kc_certification VARCHAR(255) NOT NULL COMMENT 'KC 인증정보', +rated_voltage VARCHAR(255) NOT NULL COMMENT '정격전압', +power_consumption VARCHAR(255) NOT NULL COMMENT '소비전력', +energy_efficiency_rating VARCHAR(255) NOT NULL COMMENT '에너지소비효율등급', +release_date VARCHAR(255) NOT NULL COMMENT '동일모델의 출시년월', +manufacturer_importer VARCHAR(255) NOT NULL COMMENT '제조자/수입자', +origin_country VARCHAR(255) NOT NULL COMMENT '제조국', +size VARCHAR(255) NOT NULL COMMENT '크기', +capacity VARCHAR(255) NOT NULL COMMENT '용량', +shape TEXT NOT NULL COMMENT '형태', +additional_installation_cost VARCHAR(255) NOT NULL COMMENT '추가설치비용', +quality_assurance_standard VARCHAR(255) NOT NULL COMMENT '품질보증기준', +as_manager VARCHAR(255) NOT NULL COMMENT 'A/S 책임자', +as_phone VARCHAR(255) NOT NULL COMMENT 'A/S 전화번호', +FOREIGN KEY (product_id) REFERENCES products(id) +); + +--9 +CREATE TABLE notice_seasonalappliances ( +product_id INT PRIMARY KEY COMMENT '제품 ID', +p_name VARCHAR(255) NOT NULL COMMENT '상품명', +product_model VARCHAR(255) NOT NULL COMMENT '품명 및 모델명', +kc_certification VARCHAR(255) NOT NULL COMMENT 'KC 인증정보', +rated_voltage VARCHAR(255) NOT NULL COMMENT '정격전압', +power_consumption VARCHAR(255) NOT NULL COMMENT '소비전력', +energy_efficiency_rating VARCHAR(255) NOT NULL COMMENT '에너지소비효율등급', +release_date VARCHAR(255) NOT NULL COMMENT '동일모델의 출시년월', +manufacturer_importer VARCHAR(255) NOT NULL COMMENT '제조자/수입자', +origin_country VARCHAR(255) NOT NULL COMMENT '제조국', +size TEXT NOT NULL COMMENT '크기 (실외기 포함)', +shape TEXT NOT NULL COMMENT '형태 (실외기 포함)', +heating_cooling_area VARCHAR(255) NOT NULL COMMENT '냉난방면적', +additional_installation_cost VARCHAR(255) NOT NULL COMMENT '추가설치비용', +quality_assurance_standard VARCHAR(255) NOT NULL COMMENT '품질보증기준', +as_manager VARCHAR(255) NOT NULL COMMENT 'A/S 책임자', +as_phone VARCHAR(255) NOT NULL COMMENT 'A/S 전화번호', +FOREIGN KEY (product_id) REFERENCES products(id) +); + +--10 +CREATE TABLE notice_officeequipment ( +product_id INT PRIMARY KEY COMMENT '제품 ID', +p_name VARCHAR(255) NOT NULL COMMENT '상품명', +product_model VARCHAR(255) NOT NULL COMMENT '품명 및 모델명', +kc_certification VARCHAR(255) NOT NULL COMMENT 'KC 인증정보', +rated_voltage VARCHAR(255) NOT NULL COMMENT '정격전압', +power_consumption VARCHAR(255) NOT NULL COMMENT '소비전력', +energy_efficiency_rating VARCHAR(255) NOT NULL COMMENT '에너지소비효율등급', +release_date VARCHAR(255) NOT NULL COMMENT '동일모델의 출시년월', +manufacturer_importer VARCHAR(255) NOT NULL COMMENT '제조자/수입자', +origin_country VARCHAR(255) NOT NULL COMMENT '제조국', +size TEXT NOT NULL COMMENT '크기', +weight VARCHAR(255) NOT NULL COMMENT '무게 (노트북 등 휴대형 기기에 한함)', +major_specifications TEXT NOT NULL COMMENT '주요 사양', +quality_assurance_standard VARCHAR(255) NOT NULL COMMENT '품질보증기준', +as_manager VARCHAR(255) NOT NULL COMMENT 'A/S 책임자', +as_phone VARCHAR(255) NOT NULL COMMENT 'A/S 전화번호', +FOREIGN KEY (product_id) REFERENCES products(id) +); + +--11 +CREATE TABLE notice_opticalequipment ( +product_id INT PRIMARY KEY COMMENT '제품 ID', +p_name VARCHAR(255) NOT NULL COMMENT '상품명', +product_model VARCHAR(255) NOT NULL COMMENT '품명 및 모델명', +kc_certification VARCHAR(255) NOT NULL COMMENT 'KC 인증정보', +release_date VARCHAR(255) NOT NULL COMMENT '동일모델의 출시년월', +manufacturer_importer VARCHAR(255) NOT NULL COMMENT '제조자/수입자', +origin_country VARCHAR(255) NOT NULL COMMENT '제조국', +size VARCHAR(255) NOT NULL COMMENT '크기', +weight VARCHAR(255) NOT NULL COMMENT '무게', +major_specifications TEXT NOT NULL COMMENT '주요 사양', +quality_assurance_standard VARCHAR(255) NOT NULL COMMENT '품질보증기준', +as_manager VARCHAR(255) NOT NULL COMMENT 'A/S 책임자', +as_phone VARCHAR(255) NOT NULL COMMENT 'A/S 전화번호', +FOREIGN KEY (product_id) REFERENCES products(id) +); + +--12 +CREATE TABLE notice_smallelectronics ( +product_id INT PRIMARY KEY COMMENT '제품 ID', +p_name VARCHAR(255) NOT NULL COMMENT '상품명', +product_model VARCHAR(255) NOT NULL COMMENT '품명 및 모델명', +kc_certification VARCHAR(255) NOT NULL COMMENT 'KC 인증정보', +rated_voltage VARCHAR(255) NOT NULL COMMENT '정격전압', +power_consumption VARCHAR(255) NOT NULL COMMENT '소비전력', +release_date VARCHAR(255) NOT NULL COMMENT '동일모델의 출시년월', +manufacturer_importer VARCHAR(255) NOT NULL COMMENT '제조자, 수입자 정보', +origin_country VARCHAR(255) NOT NULL COMMENT '제조국', +size VARCHAR(255) NOT NULL COMMENT '크기', +weight VARCHAR(255) NOT NULL COMMENT '무게', +major_specifications TEXT NOT NULL COMMENT '주요 사양', +quality_assurance_standard VARCHAR(255) NOT NULL COMMENT '품질보증기준', +as_manager VARCHAR(255) NOT NULL COMMENT 'A/S 책임자', +as_phone VARCHAR(255) NOT NULL COMMENT 'A/S 전화번호', +FOREIGN KEY (product_id) REFERENCES products(id) +); + +--13 +CREATE TABLE notice_portablecommunicationdevices ( +product_id INT PRIMARY KEY COMMENT '제품 ID', +p_name VARCHAR(255) NOT NULL COMMENT '상품명', +product_model VARCHAR(255) NOT NULL COMMENT '품명 및 모델명', +kc_certification VARCHAR(255) NOT NULL COMMENT 'KC 인증정보', +release_date VARCHAR(255) NOT NULL COMMENT '동일모델의 출시년월', +manufacturer_importer VARCHAR(255) NOT NULL COMMENT '제조자, 수입자 정보', +origin_country VARCHAR(255) NOT NULL COMMENT '제조국', +size VARCHAR(255) NOT NULL COMMENT '크기', +weight VARCHAR(255) NOT NULL COMMENT '무게', +mobile_carrier VARCHAR(255) NOT NULL COMMENT '이동통신사', +registration_process TEXT NOT NULL COMMENT '가입절차', +additional_burden TEXT NOT NULL COMMENT '소비자의 추가적인 부담사항', +major_specifications TEXT NOT NULL COMMENT '주요 사양', +quality_assurance_standard VARCHAR(255) NOT NULL COMMENT '품질보증기준', +as_manager VARCHAR(255) NOT NULL COMMENT 'A/S 책임자', +as_phone VARCHAR(255) NOT NULL COMMENT 'A/S 전화번호', +FOREIGN KEY (product_id) REFERENCES products(id) +); + +--17 +CREATE TABLE notice_kitchenware ( +product_id INT PRIMARY KEY COMMENT '제품 ID', +p_name VARCHAR(255) NOT NULL COMMENT '상품명', +product_model VARCHAR(255) NOT NULL COMMENT '품명 및 모델명', +material VARCHAR(255) NOT NULL COMMENT '재질', +composition TEXT NOT NULL COMMENT '구성품', +size VARCHAR(255) NOT NULL COMMENT '크기', +release_date VARCHAR(255) NOT NULL COMMENT '동일모델의 출시년월', +manufacturer_importer VARCHAR(255) NOT NULL COMMENT '제조자 및 수입자 정보', +origin_country VARCHAR(255) NOT NULL COMMENT '제조국', +import_food_safety_management_law_statement VARCHAR(255) NOT NULL COMMENT '수입식품안전관리 특별법에 따른 문구', +quality_assurance_standard VARCHAR(255) NOT NULL COMMENT '품질보증기준', +as_manager VARCHAR(255) NOT NULL COMMENT 'A/S 책임자', +as_phone VARCHAR(255) NOT NULL COMMENT 'A/S 전화번호', +FOREIGN KEY (product_id) REFERENCES products(id) +); + +--18 +CREATE TABLE notice_cosmetics ( +product_id INT PRIMARY KEY COMMENT '제품 ID', +p_name VARCHAR(255) NOT NULL COMMENT '상품명', +content_weight VARCHAR(255) NOT NULL COMMENT '내용물의 용량 또는 중량', +major_specifications TEXT NOT NULL COMMENT '제품 주요 사양', +expiry_date_usage_period TEXT NOT NULL COMMENT '사용기한 또는 개봉 후 사용기간', +directions_for_use TEXT NOT NULL COMMENT '사용방법', +manufacturer_importer VARCHAR(255) NOT NULL COMMENT '화장품제조업자, 화장품책임판매업자', +origin_country VARCHAR(255) NOT NULL COMMENT '제조국', +ingredients TEXT NOT NULL COMMENT '모든 성분', +functional_cosmetics_statement VARCHAR(255) NOT NULL COMMENT '기능성 화장품에 대한 문구', +precautions TEXT NOT NULL COMMENT '사용할 때의 주의사항', +quality_assurance_standard VARCHAR(255) NOT NULL COMMENT '품질보증기준', +as_phone VARCHAR(255) NOT NULL COMMENT '소비자 상담 관련 전화번호', +FOREIGN KEY (product_id) REFERENCES products(id) +); + +--19 +CREATE TABLE notice_jewelry_watches ( +product_id INT PRIMARY KEY COMMENT '제품 ID', +p_name VARCHAR(255) NOT NULL COMMENT '상품명', +material_purity_band_material VARCHAR(255) NOT NULL COMMENT '소재 / 순도 / 밴드재질', +weight VARCHAR(255) NOT NULL COMMENT '중량', +manufacturer_importer VARCHAR(255) NOT NULL COMMENT '제조자 / 수입자', +origin_country VARCHAR(255) NOT NULL COMMENT '제조국', +dimensions VARCHAR(255) NOT NULL COMMENT '치수', +wearing_cautions TEXT NOT NULL COMMENT '착용시 주의사항', +major_specifications TEXT NOT NULL COMMENT '주요 사양', +jewelry_grade VARCHAR(255) NOT NULL COMMENT '귀금속, 보석류 등급', +watches_features VARCHAR(255) NOT NULL COMMENT '시계 기능, 방수 등', +warranty_provided VARCHAR(255) NOT NULL COMMENT '보증서 제공 여부', +quality_assurance_standard VARCHAR(255) NOT NULL COMMENT '품질보증기준', +as_manager VARCHAR(255) NOT NULL COMMENT 'A/S 책임자', +as_phone VARCHAR(255) NOT NULL COMMENT 'A/S 전화번호', +FOREIGN KEY (product_id) REFERENCES products(id) +); + + +--24 +CREATE TABLE notice_musical_instruments ( +product_id INT PRIMARY KEY COMMENT '제품 ID', +p_name VARCHAR(255) NOT NULL COMMENT '상품명', +product_model VARCHAR(255) NOT NULL COMMENT '품명 및 모델명', +size VARCHAR(255) NOT NULL COMMENT '크기', +color VARCHAR(255) NOT NULL COMMENT '색상', +material VARCHAR(255) NOT NULL COMMENT '재질', +composition TEXT NOT NULL COMMENT '제품 구성', +release_date VARCHAR(255) NOT NULL COMMENT '동일모델의 출시년월', +manufacturer_importer VARCHAR(255) NOT NULL COMMENT '제조자 / 수입자', +origin_country VARCHAR(255) NOT NULL COMMENT '제조국', +specific_specifications TEXT NOT NULL COMMENT '상품별 세부 사양', +quality_assurance_standard VARCHAR(255) NOT NULL COMMENT '품질보증기준', +as_manager VARCHAR(255) NOT NULL COMMENT 'A/S 책임자', +as_phone VARCHAR(255) NOT NULL COMMENT 'A/S 전화번호', +FOREIGN KEY (product_id) REFERENCES products(id) +); + +--25 +CREATE TABLE notice_sports_equipment ( +product_id INT PRIMARY KEY COMMENT '제품 ID', +p_name VARCHAR(255) NOT NULL COMMENT '상품명', +product_model VARCHAR(255) NOT NULL COMMENT '품명 및 모델명', +kc_certification TEXT NOT NULL COMMENT 'KC 인증정보', +size VARCHAR(255) NOT NULL COMMENT '크기', +weight VARCHAR(255) NOT NULL COMMENT '중량', +color VARCHAR(255) NOT NULL COMMENT '색상', +material VARCHAR(255) NOT NULL COMMENT '재질', +composition TEXT NOT NULL COMMENT '제품 구성', +release_date VARCHAR(255) NOT NULL COMMENT '동일모델의 출시년월', +manufacturer_importer VARCHAR(255) NOT NULL COMMENT '제조자, 수입자 정보', +origin_country VARCHAR(255) NOT NULL COMMENT '제조국', +specific_specifications TEXT NOT NULL COMMENT '상품별 세부 사양', +quality_assurance_standard VARCHAR(255) NOT NULL COMMENT '품질보증기준', +as_manager VARCHAR(255) NOT NULL COMMENT 'A/S 책임자', +as_phone VARCHAR(255) NOT NULL COMMENT 'A/S 전화번호', +FOREIGN KEY (product_id) REFERENCES products(id) +); + + +CREATE TABLE `user_wish_list` ( + `user_id` INT NOT NULL, + `product_id` INT NOT NULL, + `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (`user_id`, `product_id`), + FOREIGN KEY (`user_id`) REFERENCES `users`(`id`), + FOREIGN KEY (`product_id`) REFERENCES `products`(`id`) +); + + + +-- 1: 친구의가입, 2: 친구의생일, 3: 친구티끌링시작, 4: 내생일다가옴, 5:띠끌수령, 6: 마지막티끌수령, 7: 티끌링기간마감, 8: 받은티끌환불 +CREATE TABLE `notification_type` ( + `id` INT NOT NULL AUTO_INCREMENT, + `name` VARCHAR(255) NOT NULL, + PRIMARY KEY (`id`) +); +INSERT INTO notification_type (name) values ('새로운 친구'); +INSERT INTO notification_type (name) values ('친구의 생일'); +INSERT INTO notification_type (name) values ('티클링 시작'); +INSERT INTO notification_type (name) values ('다가오는 나의 생일'); +INSERT INTO notification_type (name) values ('티클 도착'); +INSERT INTO notification_type (name) values ('티클링 완료'); +INSERT INTO notification_type (name) values ('티클링 종료'); +INSERT INTO notification_type (name) values ('받은 티클 환불'); +INSERT INTO notification_type (name) values ('결제 취소'); + +CREATE TABLE `notification` ( + `id` INT NOT NULL AUTO_INCREMENT, + `user_id` INT NOT NULL, + `message` TEXT NOT NULL, + `is_deleted` BOOL NOT NULL DEFAULT false, + `is_read` BOOL NOT NULL DEFAULT false, + `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + `notification_type_id` INT NOT NULL, + `deep_link` VARCHAR(255), + `link` VARCHAR(255), + `meta_data` TEXT, + `source_user_id` INT, + PRIMARY KEY (`id`), + FOREIGN KEY (`user_id`) REFERENCES `users`(`id`), + FOREIGN KEY (`notification_type_id`) REFERENCES `notification_type`(`id`), + FOREIGN KEY (`source_user_id`) REFERENCES `users`(`id`) +); + +CREATE TABLE `product_option` ( + `id` INT NOT NULL AUTO_INCREMENT, + `product_id` INT NOT NULL, + `category` VARCHAR(255), + `option` VARCHAR(255), + `additional_amount` INT NOT NULL DEFAULT 0, + `is_deleted` BOOL NOT NULL DEFAULT false, + PRIMARY KEY (`id`), + FOREIGN KEY (`product_id`) REFERENCES `products`(`id`) +); + + + +CREATE TABLE `option_combination` ( + `id` INT NOT NULL AUTO_INCREMENT, + `product_id` INT NOT NULL, + `sales_volume` INT NOT NULL DEFAULT 0, + `quantity` INT NOT NULL DEFAULT 100000, + PRIMARY KEY (`id`), + FOREIGN KEY (`product_id`) REFERENCES `products`(`id`) +); + +CREATE TABLE `option_combination_detail` ( + `combination_id` INT NOT NULL, + `option_id` INT NOT NULL, + FOREIGN KEY (`combination_id`) REFERENCES `option_combination`(`id`), + FOREIGN KEY (`option_id`) REFERENCES `product_option`(`id`) +); + + + +-- 1: 진행중, 2: 시작 이전 종료, 3: 완료되기 전 종료, 4: 조각을 모두 모은 후 종료 +CREATE TABLE `tikkling_state` ( + `id` INT NOT NULL AUTO_INCREMENT, + `name` VARCHAR(255) NOT NULL, + PRIMARY KEY (`id`) +); +INSERT INTO tikkling_state (id, name) values (1, '진행중'); +INSERT INTO tikkling_state (id, name) values (2, '시작 이전 종료'); +INSERT INTO tikkling_state (id, name) values (3, '완료되기 전 종료'); +INSERT INTO tikkling_state (id, name) values (4, '조각을 모두 모은 후 종료'); +INSERT INTO tikkling_state (id, name) values (5, '기간 종료'); + + +CREATE TABLE `tikkling` ( + `id` INT NOT NULL AUTO_INCREMENT, + `user_id` INT NOT NULL, + `funding_limit` DATE NOT NULL, + `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + `tikkle_quantity` INT NOT NULL, + `product_id` INT NOT NULL, + `terminated_at` TIMESTAMP NULL, + `state_id` INT NOT NULL DEFAULT 1, + `type` VARCHAR(255) NOT NULL, + `resolution_type` ENUM('goods', 'refund', 'cancel') NULL, + `option_combination_id` INT NULL, + `share_link` VARCHAR(255), + PRIMARY KEY (`id`), + FOREIGN KEY (`user_id`) REFERENCES `users`(`id`), + FOREIGN KEY (`product_id`) REFERENCES `products`(`id`), + FOREIGN KEY (`state_id`) REFERENCES `tikkling_state`(`id`) ON UPDATE CASCADE, + FOREIGN KEY (`option_combination_id`) REFERENCES `option_combination`(`id`), + UNIQUE (`id`) +); + +CREATE TABLE share_link_funnel_log ( + `tikkling_id` INT NOT NULL, + `click` INT NOT NULL DEFAULT 0, + `app_open` INT NOT NULL DEFAULT 0, + `sign_up` INT NOT NULL DEFAULT 0, + `send_tikkle` INT NOT NULL DEFAULT 0, + PRIMARY KEY (`tikkling_id`), + FOREIGN KEY (`tikkling_id`) REFERENCES `tikkling`(`id`) +); + + +CREATE TABLE shared_tikkling_signup_log( + `tikkling_id` INT NOT NULL, + `user_id` INT NOT NULL, + PRIMARY KEY (`tikkling_id`, `user_id`), + FOREIGN KEY (`tikkling_id`) REFERENCES `tikkling`(`id`), + FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) +); + +DELIMITER // +-- 티클링이 하나 추가될 때 해당 유저의 is_tikkling을 true로 바꿈 +CREATE TRIGGER `after_insert_tikkling` +AFTER INSERT ON `tikkling` +FOR EACH ROW +BEGIN + UPDATE `users` + SET `is_tikkling` = true + WHERE `id` = NEW.`user_id`; +END; +// +DELIMITER ; + +CREATE TABLE `courier_company` ( + `name` VARCHAR(255) NOT NULL, + `code` VARCHAR(10) NOT NULL, + PRIMARY KEY (`code`) +); + +INSERT INTO `courier_company` (name, code) VALUES ('CJ대한통운', '04'); +INSERT INTO `courier_company` (name, code) VALUES ('한진택배', '05'); +INSERT INTO `courier_company` (name, code) VALUES ('롯데택배', '08'); +INSERT INTO `courier_company` (name, code) VALUES ('우체국택배', '01'); +INSERT INTO `courier_company` (name, code) VALUES ('로젠택배', '06'); +INSERT INTO `courier_company` (name, code) VALUES ('일양로지스', '11'); +INSERT INTO `courier_company` (name, code) VALUES ('한덱스', '20'); +INSERT INTO `courier_company` (name, code) VALUES ('대신택배', '22'); +INSERT INTO `courier_company` (name, code) VALUES ('경동택배', '23'); +INSERT INTO `courier_company` (name, code) VALUES ('합동택배', '32'); +INSERT INTO `courier_company` (name, code) VALUES ('CU 편의점택배', '46'); +INSERT INTO `courier_company` (name, code) VALUES ('GS Postbox 택배', '24'); +INSERT INTO `courier_company` (name, code) VALUES ('한의사랑택배', '16'); +INSERT INTO `courier_company` (name, code) VALUES ('천일택배', '17'); +INSERT INTO `courier_company` (name, code) VALUES ('건영택배', '18'); +INSERT INTO `courier_company` (name, code) VALUES ('굿투럭', '40'); +INSERT INTO `courier_company` (name, code) VALUES ('애니트랙', '43'); +INSERT INTO `courier_company` (name, code) VALUES ('SLX택배', '44'); +INSERT INTO `courier_company` (name, code) VALUES ('우리택배(구호남택배)', '45'); +INSERT INTO `courier_company` (name, code) VALUES ('우리한방택배', '47'); +INSERT INTO `courier_company` (name, code) VALUES ('농협택배', '53'); +INSERT INTO `courier_company` (name, code) VALUES ('홈픽택배', '54'); +INSERT INTO `courier_company` (name, code) VALUES ('IK물류', '71'); +INSERT INTO `courier_company` (name, code) VALUES ('성훈물류', '72'); +INSERT INTO `courier_company` (name, code) VALUES ('용마로지스', '74'); +INSERT INTO `courier_company` (name, code) VALUES ('원더스퀵', '75'); +INSERT INTO `courier_company` (name, code) VALUES ('로지스밸리택배', '79'); +INSERT INTO `courier_company` (name, code) VALUES ('컬리넥스트마일', '82'); +INSERT INTO `courier_company` (name, code) VALUES ('풀앳홈', '85'); +INSERT INTO `courier_company` (name, code) VALUES ('삼성전자물류', '86'); +INSERT INTO `courier_company` (name, code) VALUES ('큐런택배', '88'); +INSERT INTO `courier_company` (name, code) VALUES ('두발히어로', '89'); +INSERT INTO `courier_company` (name, code) VALUES ('위니아딤채', '90'); +INSERT INTO `courier_company` (name, code) VALUES ('지니고 당일배송', '92'); +INSERT INTO `courier_company` (name, code) VALUES ('오늘의픽업', '94'); +INSERT INTO `courier_company` (name, code) VALUES ('로지스밸리', '96'); +INSERT INTO `courier_company` (name, code) VALUES ('한샘서비스원 택배', '101'); +INSERT INTO `courier_company` (name, code) VALUES ('NDEX KOREA', '103'); +INSERT INTO `courier_company` (name, code) VALUES ('도도플렉스(dodoflex)', '104'); +INSERT INTO `courier_company` (name, code) VALUES ('LG전자(판토스)', '107'); +INSERT INTO `courier_company` (name, code) VALUES ('부릉', '110'); +INSERT INTO `courier_company` (name, code) VALUES ('1004홈', '112'); +INSERT INTO `courier_company` (name, code) VALUES ('썬더히어로', '113'); +INSERT INTO `courier_company` (name, code) VALUES ('(주)팀프레시', '116'); +INSERT INTO `courier_company` (name, code) VALUES ('롯데칠성', '118'); +INSERT INTO `courier_company` (name, code) VALUES ('핑퐁', '119'); +INSERT INTO `courier_company` (name, code) VALUES ('발렉스 특수물류', '120'); +INSERT INTO `courier_company` (name, code) VALUES ('엔티엘피스', '123'); +INSERT INTO `courier_company` (name, code) VALUES ('GTS로지스', '125'); +INSERT INTO `courier_company` (name, code) VALUES ('로지스팟', '127'); +INSERT INTO `courier_company` (name, code) VALUES ('홈픽 오늘도착', '129'); +INSERT INTO `courier_company` (name, code) VALUES ('로지스파트너', '130'); +INSERT INTO `courier_company` (name, code) VALUES ('딜리래빗', '131'); +INSERT INTO `courier_company` (name, code) VALUES ('지오피', '132'); +INSERT INTO `courier_company` (name, code) VALUES ('에이치케이홀딩스', '134'); +INSERT INTO `courier_company` (name, code) VALUES ('HTNS', '135'); +INSERT INTO `courier_company` (name, code) VALUES ('케이제이티', '136'); +INSERT INTO `courier_company` (name, code) VALUES ('더바오', '137'); +INSERT INTO `courier_company` (name, code) VALUES ('라스트마일', '138'); +INSERT INTO `courier_company` (name, code) VALUES ('오늘회 러쉬', '139'); +INSERT INTO `courier_company` (name, code) VALUES ('탱고앤고', '142'); +INSERT INTO `courier_company` (name, code) VALUES ('투데이', '143'); +INSERT INTO `courier_company` (name, code) VALUES ('현대글로비스', '145'); +INSERT INTO `courier_company` (name, code) VALUES ('ARGO', '148'); +INSERT INTO `courier_company` (name, code) VALUES ('자이언트', '151'); +INSERT INTO `courier_company` (name, code) VALUES ('HY', '155'); +INSERT INTO `courier_company` (name, code) VALUES ('유피로지스', '156'); +INSERT INTO `courier_company` (name, code) VALUES ('우진인터로지스', '157'); +INSERT INTO `courier_company` (name, code) VALUES ('삼다수 가정배송', '159'); +INSERT INTO `courier_company` (name, code) VALUES ('와이드테크', '160'); +INSERT INTO `courier_company` (name, code) VALUES ('위니온로지스', '163'); +INSERT INTO `courier_company` (name, code) VALUES ('딜리박스', '167'); +INSERT INTO `courier_company` (name, code) VALUES ('이스트라', '168'); + + + +-- 1: 배송 준비, 2: 출발, 3: 도착, 4: 수령 +CREATE TABLE `delivery_state` ( + `id` INT NOT NULL AUTO_INCREMENT, + `name` VARCHAR(255) NOT NULL, + PRIMARY KEY (`id`) +); + +INSERT INTO delivery_state (name) values ('배송 준비'); +INSERT INTO delivery_state (name) values ('출발'); +INSERT INTO delivery_state (name) values ('도착'); +INSERT INTO delivery_state (name) values ('수령'); + +drop table if exists delivery_info; +CREATE TABLE `delivery_info` ( + `id` INT NOT NULL AUTO_INCREMENT, + `invoice_number` VARCHAR(255) NULL, + `courier_company_code` VARCHAR(10) NULL, + `tikkling_id` INT NOT NULL, + `state_id` INT NOT NULL DEFAULT 1, + `zonecode` VARCHAR(255), + `address` VARCHAR(255) NOT NULL, + `detail_address` VARCHAR(255) NOT NULL, + `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + `start_delivery_date` DATE NULL, + `expected_delivery_date` DATE NULL, + `actual_delivery_date` DATE NULL, + PRIMARY KEY (`id`), + FOREIGN KEY (`tikkling_id`) REFERENCES `tikkling`(`id`), + FOREIGN KEY (`state_id`) REFERENCES `delivery_state`(`id`), + FOREIGN KEY (`courier_company_code`) REFERENCES `courier_company`(`code`) +); + + +CREATE TABLE `refund_state` ( + `id` INT NOT NULL AUTO_INCREMENT, + `name` VARCHAR(255) NOT NULL, + PRIMARY KEY (`id`) +); + +INSERT INTO refund_state (name) values ('환불 요청'); +INSERT INTO refund_state (name) values ('환불 완료'); + + +CREATE TABLE `refund` ( + `id` INT NOT NULL AUTO_INCREMENT, + `tikkling_id` INT NOT NULL, + `bank_code` INT NOT NULL, + `account` VARCHAR(255) NOT NULL, + `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + `state_id` INT NOT NULL DEFAULT 1, + `expected_refund_amount` INT NOT NULL, + `actual_refund_amount` INT NULL, + `refund_date` DATE NULL, + PRIMARY KEY (`id`), + FOREIGN KEY (`tikkling_id`) REFERENCES `tikkling`(`id`), + FOREIGN KEY (`state_id`) REFERENCES `refund_state`(`id`), + FOREIGN KEY (`bank_code`) REFERENCES `bank`(`bank_code`) +); + +-- 1: 친구, 2: 친구 대기, 3: 차단 +CREATE TABLE `relation_state` ( + `id` INT NOT NULL AUTO_INCREMENT, + `name` VARCHAR(30) NOT NULL, + PRIMARY KEY (`id`) +); + +INSERT INTO relation_state (name) values ('친구'); +INSERT INTO relation_state (name) values ('친구 대기'); +INSERT INTO relation_state (name) values ('차단'); + +CREATE TABLE `friends_relation` ( + `id` INT NOT NULL AUTO_INCREMENT COMMENT 'AUTO_INCREMENT', + `central_user_id` INT NOT NULL, + `friend_user_id` INT NOT NULL, + `relation_state_id` INT NOT NULL, + PRIMARY KEY (`id`), + UNIQUE (`central_user_id`, `friend_user_id`), + FOREIGN KEY (`central_user_id`) REFERENCES `users`(`id`), + FOREIGN KEY (`friend_user_id`) REFERENCES `users`(`id`), + FOREIGN KEY (`relation_state_id`) REFERENCES `relation_state`(`id`) +); + + + +CREATE TABLE sending_tikkle_state ( + id INT(11) PRIMARY KEY, + name VARCHAR(255) +); +INSERT INTO sending_tikkle_state (id, name) +VALUES + (1, '미사용'), + (2, '사용'), + (3, '환불'), + (4, '환급'), + (5, '결제 대기'), + (6, '결제 실패'); + + +CREATE TABLE `sending_tikkle` ( + `id` INT NOT NULL AUTO_INCREMENT, + `tikkling_id` INT NOT NULL, + `user_id` INT NOT NULL, + `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + `message` TEXT NULL, + `quantity` INT NOT NULL, + `state_id` INT NOT NULL DEFAULT 1, + `merchant_uid` VARCHAR(64) NOT NULL, + PRIMARY KEY (`id`), + FOREIGN KEY (`tikkling_id`) REFERENCES `tikkling`(`id`), + FOREIGN KEY (`user_id`) REFERENCES `users`(`id`), + FOREIGN KEY (`state_id`) REFERENCES `sending_tikkle_state`(`id`) +); + +-- tikkling_id에 index 추가 +ALTER TABLE `sending_tikkle` ADD INDEX `idx_tikkling_id` (`tikkling_id`); + +-- central_user_id에 index 추가 +ALTER TABLE `friends_relation` ADD INDEX `idx_central_user_id` (`central_user_id`); + +-- tikkling에 index 추가 +ALTER TABLE tikkling ADD INDEX idx_user_id (user_id); + +-- 티클링의 상품이름, 브랜드, 티클 개수를 함께 볼 수 있음 +DROP VIEW IF EXISTS tikkling_detail_view; +CREATE VIEW tikkling_detail_view AS +SELECT + tikkling.id as tikkling_id, + tikkling.user_id, + tikkling.funding_limit, + tikkling.created_at, + tikkling.tikkle_quantity, + tikkling.product_id, + tikkling.terminated_at, + tikkling.state_id, + tikkling.type, + tikkling.option_combination_id, + tikkling.share_link, + COALESCE(SUM(sending_tikkle.quantity), 0) as tikkle_count, + products.name as product_name, + products.thumbnail_image, + brands.brand_name, + products.category_id +FROM tikkling +LEFT JOIN sending_tikkle ON tikkling.id = sending_tikkle.tikkling_id and sending_tikkle.state_id = 1 +INNER JOIN products ON tikkling.product_id = products.id +INNER JOIN brands ON products.brand_id = brands.id +GROUP BY tikkling.id; + + +--tikkling의 terminated_at이 변경시 이를 user의 is_tikkling을 0으로 변경 +DELIMITER // +CREATE TRIGGER after_update_tikkling AFTER UPDATE ON tikkling +FOR EACH ROW +BEGIN + IF NEW.`terminated_at` IS NOT NULL AND OLD.`terminated_at` IS NULL THEN + UPDATE `users` + SET `is_tikkling` = false + WHERE `id` = NEW.`user_id`; + END IF; +END// +DELIMITER ; + + +-- 기존의 create_tikkling 저장 프로시저 삭제 +DROP PROCEDURE IF EXISTS `create_tikkling`; + +-- 새로운 create_tikkling 저장 프로시저 추가 +DELIMITER // + +CREATE PROCEDURE `create_tikkling`( + IN input_user_id INT, + IN funding_limit VARCHAR(255), + IN tikkle_quantity INT, + IN input_product_id INT, + IN type VARCHAR(255), + OUT out_result BOOLEAN +) +BEGIN + DECLARE product_quantity INT; + DECLARE user_tikkling_ticket INT; + DECLARE user_is_tikkling BOOL; + + -- 오류 핸들러 정의: 어떠한 오류가 발생하면 ROLLBACK 후 종료 + DECLARE EXIT HANDLER FOR SQLEXCEPTION + BEGIN + ROLLBACK; + SET out_result = FALSE; + END; + + START TRANSACTION; + + SELECT quantity INTO product_quantity FROM products WHERE id = input_product_id FOR UPDATE; + SELECT tikkling_ticket, is_tikkling INTO user_tikkling_ticket, user_is_tikkling FROM users WHERE id = input_user_id FOR UPDATE; + + IF product_quantity > 0 AND user_tikkling_ticket > 0 AND user_is_tikkling <> true THEN + INSERT INTO `tikkling` (`user_id`, `funding_limit`, `tikkle_quantity`, `product_id`, `type`) + VALUES (input_user_id, funding_limit, tikkle_quantity, input_product_id, type); + UPDATE products SET quantity = quantity-1 WHERE id = input_product_id; + UPDATE users SET tikkling_ticket = tikkling_ticket-1 WHERE id = input_user_id; + DELETE FROM user_wish_list WHERE user_id = input_user_id AND product_id = input_product_id; + SET out_result = TRUE; + ELSE + SET out_result = FALSE; + END IF; + + COMMIT; +END // + +DELIMITER ; + + + + + +CREATE TABLE funnel_action ( + id int NOT NULL, + description varchar(255) NOT NULL, + level int NOT NULL, + PRIMARY KEY(`id`) +); +INSERT INTO funnel_action (id, description, level) VALUES (1, '회원가입, 로그인', 1); +INSERT INTO funnel_action (id, description, level) VALUES (2, '홈화면 이동', 1); +INSERT INTO funnel_action (id, description, level) VALUES (3, '상품탭으로 이동', 2); +INSERT INTO funnel_action (id, description, level) VALUES (4, '상품 상세 페이지로 이동', 2); +INSERT INTO funnel_action (id, description, level) VALUES (5, '상품 검색', 2); +INSERT INTO funnel_action (id, description, level) VALUES (6, '티클링 시작', 3); +-- 직접 업데이트 +INSERT INTO funnel_action (id, description, level) VALUES (7, '첫 티클 수령 ', 4); +-- 직접 업데이트 +INSERT INTO funnel_action (id, description, level) VALUES (8, '티클링 구매 및 전송', 4); + +CREATE TABLE funnel_log( + id int NOT NULL AUTO_INCREMENT, + user_id int NOT NULL, + funnel_action_id int NOT NULL, + created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY(`id`), + FOREIGN KEY (`user_id`) REFERENCES `users` (`id`), + FOREIGN KEY (`funnel_action_id`) REFERENCES `funnel_action` (`id`) +); + +CREATE TABLE user_invite_event_attandance ( + id int NOT NULL AUTO_INCREMENT, + invited_user_id int NOT NULL, + sending_tikkle_id int NOT NULL, + bonus_tikkle_id int NOT NULL, + created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY(`id`), + FOREIGN KEY (`invited_user_id`) REFERENCES `users` (`id`), + FOREIGN KEY (`sending_tikkle_id`) REFERENCES `sending_tikkle` (`id`), + FOREIGN KEY (`bonus_tikkle_id`) REFERENCES `sending_tikkle` (`id`) +); + +INSERT INTO users (id, name, birthday, nick, phone, gender,image) values (0, 'TIKKLE', '2023-12-01', 'TIKKLE', '01000000000', 'male', 'https://d2da4yi19up8sp.cloudfront.net/profile/profile.png'); diff --git a/tikkle_auth/.DS_Store b/tikkle_auth/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..b18378c7d2429c1fd5b30d847f77195b18a43dd8 GIT binary patch literal 8196 zcmeI1!EVz)5QhJS3L?QF5`p%>!Q8p@$jvQA2#G^QL4s3h5|dO-YAdt{F35*I124dh z@(KuX;6Zo=?nwMIyKQXZNO6h~g;{C$x7PblJYP3<#s%OukNWGt8h{qNX!{z6nkMI^ z&$LTnrbBh~1G_lFA%@sNZ)UYk7y%<-1dMI$c|@tAdhdZM6l(88-)8Pit}E?8YCF`T#ad?d@ManQo6x5Ifm zT=--cDio)mPG6+U;bN~g8UZ6POF(M(8yFyE-M&+)--n#*VINPCaZGVA8mw>kvT^Q% zT>ZYdbDSkfca(MMXx+W}x%=hG*NrCb{yE(Fuzb~ecest5IlcZR<45Qt;rojmBkVEr zU7p|Lx&z$j8x3VqC2-{t>tiddVjz}<}dqTqTijgN}~O)d4w{H7sqFNq2YCmvnh?` zqtx&aCf1C=MI~_AU-+8T{}1NB|G%i|*>xKMBd`Dgw~}lpn_L)b>lusG+7bIpc4@M% w@TwLLT8>k-9H*ZB!;r@jmx?D2T6pCQ+aG@saQcg~;jajL{_CI1hJS>>PukHr<^TWy literal 0 HcmV?d00001 diff --git a/tikkle_auth/get_auth_checkToken/index.js b/tikkle_auth/get_auth_checkToken/index.js new file mode 100644 index 0000000..fcb1a60 --- /dev/null +++ b/tikkle_auth/get_auth_checkToken/index.js @@ -0,0 +1,76 @@ +const { checkToken } = require("token.js"); + +exports.get_auth_checkToken = async (req, res) => { + const headers = req.headers; + const authorization = headers.authorization; + const [accessToken, refreshToken] = authorization.split(","); + + // console.log("headers : ", headers); + // console.log("accessToken : ", accessToken); + // console.log("refreshToken : ", refreshToken); + + //---- check token is exist ----// + + const maxLength = 500; + + //check input value + if ( + !accessToken || + !refreshToken || + typeof accessToken !== "string" || + typeof refreshToken !== "string" || + accessToken.length > maxLength || + refreshToken.length > maxLength + ) { + //return invalid + console.log("get_auth_checkToken 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "99", + message: "the token value is null or invalid : Log in again", + returnToken: null, + }; + return res.status(401).send(return_body); + } + + //---- check token is valid & refresh Access token ----// + + const tokenCheck = await checkToken(accessToken, refreshToken); + + //return invalid when token is invalid + if (tokenCheck.statusCode !== 200) { + console.log("get_auth_checkToken 에서 에러가 발생했습니다.", err); + const return_body = { + success: false, + detail_code: "99", + message: "the token value is null or invalid : Log in again", + returnToken: null, + }; + return res.status(401).send(return_body); + } + + const returnBody = JSON.parse(tokenCheck.body); + // console.log("tokenCheck : ", typeof returnBody); + + //---- return success ----// + + const returnToken = returnBody.accessToken; + //console.log(returnToken); + if (!refreshToken) { + const return_body = { + success: true, + detail_code: "10", + message: "success : no new access token", + returnToken: null, + }; + return res.status(200).send(return_body); + } + + const return_body = { + success: true, + detail_code: "11", + message: "success : new access token", + returnToken: returnToken, + }; + return res.status(200).send(return_body); +}; diff --git a/tikkle_auth/get_auth_event/index.js b/tikkle_auth/get_auth_event/index.js new file mode 100644 index 0000000..fc7a6d8 --- /dev/null +++ b/tikkle_auth/get_auth_event/index.js @@ -0,0 +1,35 @@ +const { queryDatabase } = require("db.js"); +const { getSSMParameter } = require("ssm.js"); + +exports.get_auth_event = async (req, res) => { + const body = req.body; + + //---- check ssm there is number or not ----// + let get = "event"; + let image = "event_image"; + + const event = await getSSMParameter(get); + const image_url = await getSSMParameter(image); + + //---- return result ----// + + if (!event || !image_url) { + console.log("get_auth_event 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "99", + message: "요청을 처리할 수 없습니다.", + returnToken: null, + }; + return res.status(401).send(return_body); + } + + const return_body = { + success: true, + detail_code: "00", + message: "event get success", + data: { event: event, image_url: image_url }, + returnToken: null, + }; + return res.status(200).send(return_body); +}; diff --git a/tikkle_auth/get_auth_kToken/index.js b/tikkle_auth/get_auth_kToken/index.js new file mode 100644 index 0000000..d12a551 --- /dev/null +++ b/tikkle_auth/get_auth_kToken/index.js @@ -0,0 +1,5 @@ +const { checkToken } = require("token.js"); + +exports.get_auth_kToken = async (req, res) => { + console.log("####### get_auth_kToken ########\n", req); +}; diff --git a/tikkle_auth/post_auth_IdDuplicationCheck/index.js b/tikkle_auth/post_auth_IdDuplicationCheck/index.js new file mode 100644 index 0000000..88d040a --- /dev/null +++ b/tikkle_auth/post_auth_IdDuplicationCheck/index.js @@ -0,0 +1,61 @@ +const { queryDatabase } = require("db.js"); + +exports.post_auth_IdDuplicationCheck = async (req, res) => { + const body = req.body; + const inputId = body.inputId; + + //---- check id format ----// + + if (!inputId || typeof inputId !== "string" || inputId.length > 12 || inputId.length < 5) { + //return invalid + console.log("post_auth_IdDuplicationCheck 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "00", + message: "inputId value is null or invalid: input data again", + returnToken: null, + }; + return res.status(400).send(return_body); + } + + //---- check DB there is nick or not ----// + + let sqlResult; + + try { + const rows = await queryDatabase("select * from users where nick = ?", [inputId]); + sqlResult = rows; + //console.log("SQL result : ", sqlResult); + } catch (err) { + console.log("post_auth_IdDuplicationCheck 에서 에러가 발생했습니다 : ", err); + const return_body = { + success: false, + detail_code: "00", + message: "Database connection error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + //---- return result ----// + + if (sqlResult.length === 0) { + //no duplication + const return_body = { + success: true, + detail_code: "10", + message: "No duplication", + returnToken: null, + }; + return res.status(200).send(return_body); + } else { + //duplication + const return_body = { + success: true, + detail_code: "11", + message: "Duplicate ID", + returnToken: null, + }; + return res.status(200).send(return_body); + } +}; diff --git a/tikkle_auth/post_auth_appleLogin/index.js b/tikkle_auth/post_auth_appleLogin/index.js new file mode 100644 index 0000000..9c72f88 --- /dev/null +++ b/tikkle_auth/post_auth_appleLogin/index.js @@ -0,0 +1,122 @@ +const jwt = require("jsonwebtoken"); +const { queryDatabase } = require("db.js"); +const { getSSMParameter } = require("ssm.js"); + +exports.post_auth_appleLogin = async (req, res) => { + const body = req.body; + const apple_id = body.apple_id; + + //---- check database ----// + + let sqlResult; + + try { + const rows = await queryDatabase("SELECT * FROM users WHERE apple_id = ?", [apple_id]); + sqlResult = rows; + + //console.log("SQL result : ", sqlResult); + } catch (err) { + console.log("post_auth_appleLogin 에서 에러가 발생했습니다 : ", err); + const return_body = { + success: false, + detail_code: "02", + message: "Database connection error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + // no data + if (sqlResult.length !== 1) { + const return_body = { + success: false, + detail_code: "01", + message: "There is no user of input apple_id", + returnToken: null, + }; + return res.status(200).send(return_body); + } + + if (sqlResult[0].is_deleted === 1) { + console.log("post_auth_appleLogin 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "02", + message: "deleted user", + returnToken: null, + }; + return res.status(404).send(return_body); + } + + //---- generate tokken ----// + + const userId = sqlResult[0].id; + + let accessToken = null; + let refreshToken = null; + + // generate token + try { + accessToken = await generateAccessToken(userId); + refreshToken = await generateRefreshToken(userId); + } catch (error) { + console.log("post_auth_appleLogin 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "05", + message: "cannot make token", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + //---- return success ----// + + const return_body = { + success: true, + data: JSON.stringify({ + accessToken: accessToken, + refreshToken: refreshToken, + }), + detail_code: "00", + message: "success to generate token", + returnToken: null, + }; + return res.status(200).send(return_body); +}; + +const generateAccessToken = async (id) => { + const issuer = await getSSMParameter("issuer"); + const accessTokenSecret = await getSSMParameter("accessTokenSecret"); + + const accessTokenPayload = { + id, + iat: Math.floor(Date.now() / 1000), // Issued At timestamp in seconds + exp: Math.floor(Date.now() / 1000) + 15 * 60, // Expiration time in seconds (15 minutes) + iss: issuer, // Use the environment variable directly + // Add any additional claims as needed + }; + + // Generate the access token + const accessToken = jwt.sign(accessTokenPayload, accessTokenSecret); + + return accessToken; +}; + +// Helper function to generate a refresh token +const generateRefreshToken = async (id) => { + const issuer = await getSSMParameter("issuer"); + const refreshTokenSecret = await getSSMParameter("refreshTokenSecret"); + + const refreshTokenPayload = { + id, + iat: Math.floor(Date.now() / 1000), // Issued At timestamp in seconds + exp: Math.floor(Date.now() / 1000) + 30 * 24 * 60 * 60, // Expiration time in seconds (30 days) + iss: issuer, + }; + + // Generate the refresh token + const refreshToken = jwt.sign(refreshTokenPayload, refreshTokenSecret); + + return refreshToken; +}; diff --git a/tikkle_auth/post_auth_appleRegister/index.js b/tikkle_auth/post_auth_appleRegister/index.js new file mode 100644 index 0000000..902cc87 --- /dev/null +++ b/tikkle_auth/post_auth_appleRegister/index.js @@ -0,0 +1,80 @@ +const { queryDatabase } = require("db.js"); + +exports.post_auth_appleRegister = async (req, res) => { + const body = req.body; + const apple_id = body.apple_id; + const phone = body.phone; + + //---- check DB there is number or not ----// + + let sqlResult; + + try { + const rows = await queryDatabase("select * from users where phone = ?", [phone]); + sqlResult = rows; + //console.log("SQL result : ", sqlResult); + } catch (err) { + console.log(" post_auth_appleRegister 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "02", + message: "Database connection error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + //---- return result ----// + + if (sqlResult.length != 1) { + console.log(" post_auth_appleRegister 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "02", + message: "Database connection error", + returnToken: null, + }; + return res.status(500).send(return_body); + } else if (sqlResult[0].apple_id != null) { + console.log(" post_auth_appleRegister 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "33", + message: "already registered apple_id", + returnToken: null, + }; + return res.status(400).send(return_body); + } + + //----------- update apple_id --------------------------------------// + let sqlResult_update; + + try { + const rows = await queryDatabase( + ` UPDATE users + SET apple_id = ? + WHERE phone = ? + `, + [apple_id, phone] + ); + + sqlResult_update = rows; + } catch (err) { + console.error(`🚨 error -> ⚡️ post_auth_appleRegister : 🐞 ${err}`); + const return_body = { + success: false, + detail_code: "00", + message: "SQL error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + const return_body = { + success: true, + detail_code: "00", + message: "update apple id", + returnToken: null, + }; + return res.status(200).send(return_body); +}; diff --git a/tikkle_auth/post_auth_loginKakao/index.js b/tikkle_auth/post_auth_loginKakao/index.js new file mode 100644 index 0000000..0b7dbb8 --- /dev/null +++ b/tikkle_auth/post_auth_loginKakao/index.js @@ -0,0 +1,421 @@ +const { queryDatabase } = require("db.js"); +const jwt = require("jsonwebtoken"); +const { getSSMParameter } = require("ssm.js"); +/** + * 카카오톡으로 로그인시 카카오톡 id있는지 확인하고 있으면 로그인, 없으면 전화번호 있는지 확인하고 계정 통합 or 회원가입 + * @param {*} req + * @param {*} res + * @returns + */ +exports.post_auth_loginKakao = async (req, res) => { + const body = req.body; + + const name = body.name; + + //TODO : 카카오 회원가입시 생일이 없는 경우 + let birthday = body.birthday; + if (birthday == "0000-00-00") { + birthday = "2023-12-13"; + } + + const phone = body.phone; + const gender = body.gender; + const source_tikkling_id = body.source_tikkling_id; + const kakao_email = body.kakao_email; + let kakao_image = body.kakao_image; + + if (kakao_image == null) { + kakao_image = "https://d2da4yi19up8sp.cloudfront.net/profile/profile.png"; + } + + // console.log("body : ", body); + + //-------- check if kakao id exists in DB --------------------------------------------------------------------------------------// + + let sqlResult_kakao; + + try { + const rows = await queryDatabase("select * from users where kakao_email = ?", [kakao_email]); + sqlResult_kakao = rows; + } catch (err) { + console.log(" post_auth_loginKakao 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "00", + message: "Database connection error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + if (sqlResult_kakao.length >= 1 && sqlResult_kakao[0].is_deleted === 1) { + console.log("post_auth_appleLogin 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "04", + message: "Deleted user", + returnToken: null, + }; + return res.status(404).send(return_body); + } + + //카카오 회원인 경우 + if (sqlResult_kakao.length === 1) { + const userId = sqlResult_kakao[0].id; + + let accessToken = null; + let refreshToken = null; + + // generate token + try { + accessToken = await generateAccessToken(userId); + refreshToken = await generateRefreshToken(userId); + } catch (error) { + console.log("post_auth_loginKakao 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "12", + message: "cannot make token", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + //---- return success ----// + + const return_body = { + success: true, + data: JSON.stringify({ + accessToken: accessToken, + refreshToken: refreshToken, + }), + detail_code: "00", + message: "success to generate token", + returnToken: null, + }; + return res.status(200).send(return_body); + } else if (sqlResult_kakao.length != 0) { + console.log(" post_auth_loginKakao 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "00", + message: "Database connection error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + //-------- 카카오 회원이 아닌 경우 check phone number --------------------------------------------------------------------------------------// + // Check if the string matches the numeric pattern and its length is between 9 and 12 + const numericPattern = /^\d+$/; + if (!phone || typeof phone !== "string" || phone.length < 9 || phone.length > 11 || !numericPattern.test(phone)) { + //return invalid + console.log(" post_auth_loginKakao 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "05", + message: "phone value is null or invalid : input phone again", + returnToken: null, + }; + return res.status(400).send(return_body); + } + + let sqlResult_phone; + + try { + const rows = await queryDatabase("select * from users where phone = ?", [phone]); + sqlResult_phone = rows; + //console.log("SQL result : ", sqlResult_phone); + } catch (err) { + console.log(" post_auth_phoneCheck 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "02", + message: "Database connection error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + //아예 등록된 번호가 아닌 경우 새로 회원가입 + if (sqlResult_phone.length === 0) { + //-------- check data format --------------------------------------------------------------------------------------// + + //check name + if (!name || typeof name !== "string" || name.length > 30) { + //return invalid + console.log("ERROR : name value is null or invalid"); + const return_body = { + success: false, + detail_code: "01", + message: "input name again", + returnToken: null, + }; + return res.status(400).send(return_body); + } + + //check birthday + const parsedDate = new Date(birthday); + if (isNaN(parsedDate) || Object.prototype.toString.call(parsedDate) !== "[object Date]") { + //return invalid + console.log(" post_auth_loginKakao 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "02", + message: "birthday value is null or invalid : input birthday again", + returnToken: null, + }; + return res.status(400).send(return_body); + } + + if (!isUserAgeValid(birthday)) { + console.log("post_auth_loginKakao 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "03", + message: "if your age is under 14 you cannot use this servise!", + returnToken: null, + }; + return res.status(400).send(return_body); + } + + //check gender + if (!gender || typeof gender !== "string" || !(gender === "male" || gender === "female" || gender === "others")) { + //return invalid + console.log("post_auth_loginKakao 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "06", + message: "gender value is null or invalid : input gender again", + returnToken: null, + }; + return res.status(400).send(return_body); + } + + //-------- add user data to DB --------------------------------------------------------------------------------------// + + let sqlResult; + + const insertQuery = ` + INSERT INTO users + (name, birthday, nick, phone, gender, image, address, detail_address, is_tikkling, tikkling_ticket, funnel, kakao_email) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + `; + let funnel; + if (source_tikkling_id) { + funnel = "share_link"; + } else { + funnel = "meta_ad"; + } + + const values = [name, birthday, " ", phone, gender, kakao_image, null, null, false, 2, funnel, kakao_email]; + + try { + const rows = await queryDatabase(insertQuery, values); + sqlResult = rows; + if (source_tikkling_id) { + const insertQuery_2 = ` + INSERT INTO shared_tikkling_signup_log (tikkling_id, user_id) + VALUES (?, ?) + `; + const values = [source_tikkling_id, sqlResult.insertId]; + await queryDatabase(insertQuery_2, values); + } + + //console.log("SQL result : ", sqlResult.insertId); + } catch (err) { + console.log("🚨 post_auth_loginKakao 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "00", + message: err, + returnToken: null, + }; + return res.status(500).send(return_body); + } + + //-------- make token ----------------------------------------------------------------// + + const userId_2 = sqlResult.insertId; + + let accessToken = null; + let refreshToken = null; + + // generate token + try { + accessToken = await generateAccessToken(userId_2); + refreshToken = await generateRefreshToken(userId_2); + } catch (error) { + console.log("post_auth_loginKakao 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "12", + message: "cannot make token", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + //---- return success ----// + + const return_body = { + success: true, + data: JSON.stringify({ + accessToken: accessToken, + refreshToken: refreshToken, + }), + detail_code: "01", + message: "sign up and login success!", + returnToken: null, + }; + return res.status(200).send(return_body); + + // + //회원가입이 다른 걸로 되어있는 경우 + } else if (sqlResult_phone.length === 1) { + if (sqlResult_phone[0].is_deleted === 1) { + console.log("post_auth_appleLogin 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "04", + message: "Deleted user", + returnToken: null, + }; + return res.status(404).send(return_body); + } + + if (sqlResult_phone[0].kakao_email != null) { + console.log("post_auth_appleLogin 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "22", + message: "Already kakao user", + returnToken: null, + }; + return res.status(400).send(return_body); + } + + const phone_userID = sqlResult_phone[0].id; + + let sqlResult_update; + + try { + const rows = await queryDatabase( + ` UPDATE users + SET kakao_email = ? + WHERE id = ? + `, + [kakao_email, phone_userID] + ); + + sqlResult_update = rows; + } catch (err) { + console.error(`🚨 error -> ⚡️ put_user_nick : 🐞 ${err}`); + const return_body = { + success: false, + detail_code: "00", + message: "SQL error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + let accessToken = null; + let refreshToken = null; + + // generate token + try { + accessToken = await generateAccessToken(phone_userID); + refreshToken = await generateRefreshToken(phone_userID); + } catch (error) { + console.log("post_auth_loginKakao 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "12", + message: "cannot make token", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + //---- return success ----// + + const return_body = { + success: true, + data: JSON.stringify({ + accessToken: accessToken, + refreshToken: refreshToken, + }), + detail_code: "02", + message: "updata kakao email and login success!", + returnToken: null, + }; + return res.status(200).send(return_body); + + // + } else { + console.log(" post_auth_phoneCheck 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "02", + message: "Database connection error", + returnToken: null, + }; + return res.status(500).send(return_body); + } +}; + +const generateAccessToken = async (id) => { + const issuer = await getSSMParameter("issuer"); + const accessTokenSecret = await getSSMParameter("accessTokenSecret"); + + const accessTokenPayload = { + id, + iat: Math.floor(Date.now() / 1000), // Issued At timestamp in seconds + exp: Math.floor(Date.now() / 1000) + 15 * 60, // Expiration time in seconds (15 minutes) + iss: issuer, // Use the environment variable directly + // Add any additional claims as needed + }; + + // Generate the access token + const accessToken = jwt.sign(accessTokenPayload, accessTokenSecret); + + return accessToken; +}; + +// Helper function to generate a refresh token +const generateRefreshToken = async (id) => { + const issuer = await getSSMParameter("issuer"); + const refreshTokenSecret = await getSSMParameter("refreshTokenSecret"); + + const refreshTokenPayload = { + id, + iat: Math.floor(Date.now() / 1000), // Issued At timestamp in seconds + exp: Math.floor(Date.now() / 1000) + 30 * 24 * 60 * 60, // Expiration time in seconds (30 days) + iss: issuer, + }; + + // Generate the refresh token + const refreshToken = jwt.sign(refreshTokenPayload, refreshTokenSecret); + + return refreshToken; +}; + +function isUserAgeValid(dateOfBirth) { + // Convert dateOfBirth string to a Date object + const dob = new Date(dateOfBirth); + + // Calculate current date + const currentDate = new Date(); + + // Calculate age + let age = currentDate.getFullYear() - dob.getFullYear(); + + // Check if birthday hasn't occurred yet this year + if (currentDate.getMonth() < dob.getMonth() || (currentDate.getMonth() === dob.getMonth() && currentDate.getDate() < dob.getDate())) { + age--; + } + + // Compare age with minimum age requirement (14) + return age >= 14; +} diff --git a/tikkle_auth/post_auth_phoneCheck/index.js b/tikkle_auth/post_auth_phoneCheck/index.js new file mode 100644 index 0000000..6d4a3ae --- /dev/null +++ b/tikkle_auth/post_auth_phoneCheck/index.js @@ -0,0 +1,84 @@ +const { queryDatabase } = require("db.js"); + +exports.post_auth_phoneCheck = async (req, res) => { + const body = req.body; + const phone = body.phone; + + //---- check number format ----// + + const numericPattern = /^\d+$/; + + // Check if the string matches the numeric pattern and its length is between 9 and 12 + if ( + !phone || + typeof phone !== "string" || + phone.length < 9 || + phone.length > 11 || + !numericPattern.test(phone) + ) { + //return invalid + + console.log("post_auth_phoneCheck 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "00", + message: "phone number value is null or invalid : input data again", + returnToken: null, + }; + return res.status(400).send(return_body); + } + + //---- check DB there is number or not ----// + + let sqlResult; + + try { + const rows = await queryDatabase("select * from users where phone = ?", [ + phone, + ]); + sqlResult = rows; + //console.log("SQL result : ", sqlResult); + } catch (err) { + console.log(" post_auth_phoneCheck 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "02", + message: "Database connection error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + //---- return result ----// + + if (sqlResult.length === 1) { + //already sign in + const return_body = { + success: true, + detail_code: "10", + message: "login", + returnToken: null, + userId: sqlResult[0].id, + }; + return res.status(200).send(return_body); + } else if (sqlResult.length === 0) { + //not sign in + + const return_body = { + success: true, + detail_code: "11", + message: "sign up", + returnToken: null, + }; + return res.status(200).send(return_body); + } else { + console.log(" post_auth_phoneCheck 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "03", + returnToken: null, + message: "many same number", + }; + return res.status(500).send(return_body); + } +}; diff --git a/tikkle_auth/post_auth_registerUser/index.js b/tikkle_auth/post_auth_registerUser/index.js new file mode 100644 index 0000000..2fe8d9e --- /dev/null +++ b/tikkle_auth/post_auth_registerUser/index.js @@ -0,0 +1,41 @@ + +const { User } = require("../../features/User"); +const { Response } = require("../../features/Response"); +const { DBManager } = require("../../db"); + + +exports.post_auth_registerUser = async (req, res) => { + const { body } = req; + const { name, birthday, nick, phone, gender, source_tikkling_id } = body; + + //main logic------------------------------------------------------------------------------------------------------------------// + const db = new DBManager(); + await db.openTransaction(); + try { + + //유저 객체 생성 + const user = new User({ name, birthday, nick, phone, gender, source_tikkling_id, db }); + //유저 정보 검증 + await user.validateUserForRegister(); + // 14세 미만 유저 제한 + await user.restrictUserUnder14(); + + // 유저 등록 + await user.registerUser(); + + // 티클링 공유 유저 로깅 + await user.logIfUserFromTikkling(); + + await db.commitTransaction(); + + return res.status(200).send(Response.create(true, "00", "sign up success!", user.id, null)); + } catch (err) { + await db.rollbackTransaction(); + console.error(`🚨 error -> ⚡️ post_auth_registerUser : 🐞${err}`); + if (err.status) { + return res.status(err.status).send(Response.create(false, err.detail_code, err.message, null, null)); + } else { + return res.status(500).send(Response.create(false, "00", "서버 에러", null, null)); + } + } +}; \ No newline at end of file diff --git a/tikkle_auth/post_auth_tokenGenerate/index.js b/tikkle_auth/post_auth_tokenGenerate/index.js new file mode 100644 index 0000000..285409d --- /dev/null +++ b/tikkle_auth/post_auth_tokenGenerate/index.js @@ -0,0 +1,153 @@ +const jwt = require("jsonwebtoken"); +const { queryDatabase } = require("db.js"); +const { getSSMParameter } = require("ssm.js"); + +exports.post_auth_tokenGenerate = async (req, res) => { + const body = req.body; + const userId = body.id; + + //---- check user id ----// + + //check input value + if (typeof userId !== "number" || isNaN(userId)) { + console.log("post_auth_tokenGenerate 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "01", + message: "id value is null or invalid", + returnToken: null, + }; + return res.status(400).send(return_body); + } else { + const idString = userId.toString(); + if (idString.length > 11) { + console.log("post_auth_tokenGenerate 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "00", + message: "id value is null or invalid", + returnToken: null, + }; + return res.status(400).send(return_body); + } + } + + //---- check database ----// + + let sqlResult; + + try { + const rows = await queryDatabase("SELECT * FROM users WHERE id = ?", [ + userId, + ]); + sqlResult = rows; + + //console.log("SQL result : ", sqlResult); + } catch (err) { + console.log("post_auth_tokenGenerate 에서 에러가 발생했습니다 : ", err); + const return_body = { + success: false, + detail_code: "02", + message: "Database connection error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + // no data + if (sqlResult.length !== 1) { + console.log("post_auth_tokenGenerate 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "03", + message: "There is no user of input id", + returnToken: null, + }; + return res.status(404).send(return_body); + } + + // deleted user + // console.log("type: ", typeof sqlResult); + // console.log("data: ", sqlResult[0].is_deleted); + + if (sqlResult[0].is_deleted === 1) { + console.log("post_auth_tokenGenerate 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "04", + message: "Deleted user", + returnToken: null, + }; + return res.status(404).send(return_body); + } + + //---- generate tokken ----// + + let accessToken = null; + let refreshToken = null; + + // generate token + try { + accessToken = await generateAccessToken(userId); + refreshToken = await generateRefreshToken(userId); + } catch (error) { + console.log("post_auth_tokenGenerate 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "05", + message: "cannot make token", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + //---- return success ----// + + const return_body = { + success: true, + data: JSON.stringify({ + accessToken: accessToken, + refreshToken: refreshToken, + }), + detail_code: "00", + message: "success to generate token", + returnToken: null, + }; + return res.status(200).send(return_body); +}; + +const generateAccessToken = async (id) => { + const issuer = await getSSMParameter("issuer"); + const accessTokenSecret = await getSSMParameter("accessTokenSecret"); + + const accessTokenPayload = { + id, + iat: Math.floor(Date.now() / 1000), // Issued At timestamp in seconds + exp: Math.floor(Date.now() / 1000) + 15 * 60, // Expiration time in seconds (15 minutes) + iss: issuer, // Use the environment variable directly + // Add any additional claims as needed + }; + + // Generate the access token + const accessToken = jwt.sign(accessTokenPayload, accessTokenSecret); + + return accessToken; +}; + +// Helper function to generate a refresh token +const generateRefreshToken = async (id) => { + const issuer = await getSSMParameter("issuer"); + const refreshTokenSecret = await getSSMParameter("refreshTokenSecret"); + + const refreshTokenPayload = { + id, + iat: Math.floor(Date.now() / 1000), // Issued At timestamp in seconds + exp: Math.floor(Date.now() / 1000) + 30 * 24 * 60 * 60, // Expiration time in seconds (30 days) + iss: issuer, + }; + + // Generate the refresh token + const refreshToken = jwt.sign(refreshTokenPayload, refreshTokenSecret); + + return refreshToken; +}; diff --git a/tikkle_auth/post_auth_version/index.js b/tikkle_auth/post_auth_version/index.js new file mode 100644 index 0000000..d1457b2 --- /dev/null +++ b/tikkle_auth/post_auth_version/index.js @@ -0,0 +1,74 @@ +const { queryDatabase } = require("db.js"); +const { getSSMParameter } = require("ssm.js"); + +exports.post_auth_version = async (req, res) => { + const body = req.body; + const os = body.os; + const version = body.version; + + //---- check inspection_time ----// + let inspection; + try { + inspection = await getSSMParameter("inspection_time"); + } catch (err) { + console.log("get_notification_list 에서 에러가 발생했습니다.", err); + const return_body = { + success: false, + detail_code: "01", + message: "SSM error : check parameter error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + //---- check DB ----// + let sqlResult; + + try { + const rows = await queryDatabase( + ` SELECT * + FROM invalid_version + WHERE os = ? AND version = ? + `, + [os, version] + ); + sqlResult = rows; + } catch (err) { + console.log("get_notification_list 에서 에러가 발생했습니다.", err); + const return_body = { + success: false, + detail_code: "01", + message: "SQL error : check DB error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + const retData = sqlResult; + + //---- return result ----// + + if (retData.length > 0) { + const return_body = { + success: true, + data: { + inspection_time: inspection, + }, + detail_code: "10", + message: "이 앱 버전은 더 이상 지원되지 않습니다.", + returnToken: null, + }; + return res.status(201).send(return_body); + } + + const return_body = { + success: true, + data: { + inspection_time: inspection, + }, + detail_code: "00", + message: "이 앱 버전은 지원됩니다.", + returnToken: null, + }; + return res.status(200).send(return_body); +}; diff --git a/tikkle_friend/.DS_Store b/tikkle_friend/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..ebe77de3ac794073c4c595dc15cb2d70170761d8 GIT binary patch literal 8196 zcmeHMO-{l<82v_xmbefTLs<3-cmXSc4T*7qd*n}0eu@IR?b3J#kKo$q+IR#PF1&>Y z@Xb%4r6sg1z{GEonb*wB>&$y?XZQvp5`{@KPn07f3t3`j4@E?h?J|ebmZ>=e3h;?8 z>6WgjMFVPvdUFLkzz(nj>;OB!4*UfNuxHC;E!g*UE0^p5JMb?Zkn4kuEYUIOX;e!G z3KaqXQ>a!6*N6iY$2RB~^fW3e?x~{(VW`4{7(&z0Zp-dK$DpTC(@AJL2{W=V5sFZw zgJ-MmBpi)gvIFcu*Z~>4?^7Ew`cNEu&1v72zu%W~{CdAXk4yQk zd4HFT)putalkmd2JWLb&Iq(0{2Ttt3rXASU6UfQ+ql6`d&jB|5M0k95VEqn=RIySl zU|bVhhh`vSZ5#OlSti-f)2JvYR5%V);W%*mhas+Qbd?;(pr;WvNPG~WY~X?&SgQlS Dsw4t8 literal 0 HcmV?d00001 diff --git a/tikkle_friend/get_friend_data/index.js b/tikkle_friend/get_friend_data/index.js new file mode 100644 index 0000000..f26d6f8 --- /dev/null +++ b/tikkle_friend/get_friend_data/index.js @@ -0,0 +1,70 @@ +const { queryDatabase } = require("db.js"); + +exports.get_friend_data = async (req, res) => { + const body = req.body; + const id = req.id; + const returnToken = req.returnToken; + + //main logic------------------------------------------------------------------------------------------------------------------// + + try { + //차단된 친구 목록 + let rows; + let message; + let detail_code; + if (req.params.mode === "block") { + rows = await queryDatabase( + `SELECT u.id, u.name, u.image, u.nick, fr.relation_state_id + FROM users u + INNER JOIN friends_relation fr ON u.id = fr.friend_user_id + WHERE fr.relation_state_id = 3 AND fr.central_user_id = ? AND u.is_deleted = 0 + ORDER BY u.name;`, + [id] + ); + message = "차단된 친구 목록 조회 성공"; + detail_code = "01"; + //차단되지 않은 친구 목록 + } else if (req.params.mode === "unblock") { + rows = await queryDatabase( + `SELECT u.id, u.name, u.image, u.nick, fr.relation_state_id + FROM users u + INNER JOIN friends_relation fr ON u.id = fr.friend_user_id + WHERE fr.relation_state_id != 3 AND fr.central_user_id = ? AND u.is_deleted = 0 + ORDER BY u.name;`, + [id] + ); + message = "차단되지 않은 친구 목록 조회 성공"; + detail_code = "02"; + //확인한 친구에 대해 모두 친구로 전환 + await queryDatabase("UPDATE friends_relation SET relation_state_id = 1 WHERE relation_state_id = 2 AND central_user_id = ?", [id]); + } else { + // parameter잘못된 mode를 전송 + console.log("비정상적 요청-get_friend_data: 잘못된 mode를 parameter로 전송했습니다."); + const return_body = { + success: false, + detail_code: "00", + message: "비정상적 요청, 잘못된 유효하지 않은 mode를 parameter로 전송했습니다.", + returnToken: null, + }; + return res.status(400).send(return_body); + } + + const return_body = { + success: true, + detail_code, + message, + data: rows, + returnToken, + }; + return res.status(200).send(return_body); + } catch (err) { + console.error(`🚨 error -> ⚡️ post_friend_data : 🐞${err}`); + const return_body = { + success: false, + detail_code: "00", + message: "서버 에러", + returnToken: null, + }; + return res.status(500).send(return_body); + } +}; diff --git a/tikkle_friend/get_friend_event/index.js b/tikkle_friend/get_friend_event/index.js new file mode 100644 index 0000000..5c2ba8c --- /dev/null +++ b/tikkle_friend/get_friend_event/index.js @@ -0,0 +1,59 @@ +const { queryDatabase } = require("db.js"); + +exports.get_friend_event = async (req, res) => { + const body = req.body; + const id = req.id; + const returnToken = req.returnToken; + + //main logic------------------------------------------------------------------------------------------------------------------// + + try { + //유저의 차단되지 않은 친구중 다가오는 7일 이내에 생일이 있는 친구의 정보를 가져옴 + const rows = await queryDatabase( + `SELECT + u.name, + u.birthday, + u.image, + u.is_tikkling + FROM users u + JOIN friends_relation fr ON u.id = fr.friend_user_id + WHERE fr.central_user_id = ? + AND fr.relation_state_id <> 3 + AND DATE_ADD(u.birthday, + INTERVAL YEAR(CURDATE())-YEAR(u.birthday) + + IF(DAYOFYEAR(CURDATE()) > DAYOFYEAR(u.birthday), 1, 0) + YEAR) + BETWEEN CURDATE() AND DATE_ADD(CURDATE(), INTERVAL 7 DAY);`, + [id] + ); + let retrun_body; + if (rows.length == 0) { + return_body = { + success: true, + data: rows, + detail_code: "01", + message: "생일인 친구가 없습니다.", + returnToken, + }; + } else { + return_body = { + success: true, + data: rows, + detail_code: "02", + message: "성공적으로 생일인 친구를 불러왔습니다.", + returnToken, + }; + } + + return res.status(200).send(return_body); + } catch (err) { + console.error(`🚨 error -> ⚡️ post_friend_event : 🐞${err}`); + const return_body = { + success: false, + detail_code: "00", + message: "서버에러", + returnToken: null, + }; + return res.status(500).send(return_body); + } +}; diff --git a/tikkle_friend/get_friend_search/index.js b/tikkle_friend/get_friend_search/index.js new file mode 100644 index 0000000..51b56c5 --- /dev/null +++ b/tikkle_friend/get_friend_search/index.js @@ -0,0 +1,63 @@ +const { queryDatabase } = require("db.js"); + +exports.get_friend_search = async (req, res) => { + const body = req.body; + const id = req.id; + const returnToken = req.returnToken; + + //main logic------------------------------------------------------------------------------------------------------------------// + + try { + // body에서 nick을 추출하고 문자열인지 확인 + const nick = req.params.nick; + + if (typeof nick !== "string") { + throw new Error("입력 오류: nick은 문자열이어야 합니다."); + } + // nick이 빈 문자열인지 확인 + if (nick.trim().length === 0) { + throw new Error("입력 오류: nick은 빈 문자열이면 안 됩니다."); + } + + // nick이 일치하는 사용자를 DB에서 조회 + const query = `SELECT users.id, users.name, users.nick, users.image, friends_relation.relation_state_id FROM users LEFT JOIN friends_relation on central_user_id = ? AND users.id = friends_relation.friend_user_id WHERE nick = ?`; + const rows = await queryDatabase(query, [id, nick]); + + const return_body = { + success: true, + data: { ...rows, central_user_id: id }, + detail_code: "00", + message: "성공적으로 친구를 찾았습니다.", + returnToken, + }; + return res.status(200).send(return_body); + } catch (error) { + console.log("에러 : ", error); + if (error.message === "입력 오류: nick은 빈 문자열이면 안 됩니다.") { + const return_body = { + success: false, + detail_code: "01", + message: "비정상적 요청, nick은 빈 문자열이면 안 됩니다.", + returnToken: null, + }; + return res.status(400).send(return_body); + } else if (error.message === "입력 오류: nick은 문자열이어야 합니다.") { + const return_body = { + success: false, + detail_code: "02", + message: "비정상적 요청, nick은 문자열이어야 합니다.", + returnToken: null, + }; + return res.status(400).send(return_body); + } else { + console.error(`🚨 error -> ⚡️ post_friend_search : 🐞${err}`); + const return_body = { + success: false, + detail_code: "00", + message: "서버 에러", + returnToken: null, + }; + return res.status(500).send(return_body); + } + } +}; diff --git a/tikkle_friend/get_friend_searchPhone/index.js b/tikkle_friend/get_friend_searchPhone/index.js new file mode 100644 index 0000000..0dfa9a4 --- /dev/null +++ b/tikkle_friend/get_friend_searchPhone/index.js @@ -0,0 +1,68 @@ +const { queryDatabase } = require("db.js"); + +exports.get_friend_searchPhone = async (req, res) => { + const body = req.body; + const id = req.id; + const returnToken = req.returnToken; + + //main logic------------------------------------------------------------------------------------------------------------------// + + try { + // body에서 nick을 추출하고 문자열인지 확인 + const phone = req.params.phone; + + if (typeof phone !== "string") { + throw new Error("입력 오류: phone은 문자열이어야 합니다."); + } + // phone이 빈 문자열인지 확인 + if (phone.trim().length === 0) { + throw new Error("입력 오류: phone은 빈 문자열이면 안 됩니다."); + } + + // nick이 일치하는 사용자를 DB에서 조회 + const query = ` + SELECT users.id, users.name, users.nick, users.image, friends_relation.relation_state_id + FROM users + LEFT JOIN friends_relation on central_user_id = ? + AND users.id = friends_relation.friend_user_id + WHERE phone = ?`; + const rows = await queryDatabase(query, [id, phone]); + + const return_body = { + success: true, + data: { ...rows, central_user_id: id }, + detail_code: "00", + message: "성공적으로 친구를 찾았습니다.", + returnToken, + }; + return res.status(200).send(return_body); + } catch (error) { + console.log("에러 : ", error); + if (error.message === "입력 오류: phone은 빈 문자열이면 안 됩니다.") { + const return_body = { + success: false, + detail_code: "01", + message: "검색할 전화번호가 입력되지 않았어요.", + returnToken: null, + }; + return res.status(400).send(return_body); + } else if (error.message === "입력 오류: phone은 문자열이어야 합니다.") { + const return_body = { + success: false, + detail_code: "02", + message: "입력값에 오류가 있습니다.", + returnToken: null, + }; + return res.status(400).send(return_body); + } else { + console.error(`🚨 error -> ⚡️ get_friend_searchPhone : 🐞${err}`); + const return_body = { + success: false, + detail_code: "00", + message: "서버 에러", + returnToken: null, + }; + return res.status(500).send(return_body); + } + } +}; diff --git a/tikkle_friend/post_friend_phonecheck/index.js b/tikkle_friend/post_friend_phonecheck/index.js new file mode 100644 index 0000000..8dec351 --- /dev/null +++ b/tikkle_friend/post_friend_phonecheck/index.js @@ -0,0 +1,65 @@ +const { queryDatabase } = require("db.js"); + +exports.post_friend_phonecheck = async (req, res) => { + const body = req.body; + const id = req.id; + const returnToken = req.returnToken; + + //main logic------------------------------------------------------------------------------------------------------------------// + try { + // phone_list가 문자열 배열인지 확인 + const phone_list = body.phone_list; + + if (!Array.isArray(phone_list) || !phone_list.every((phone) => typeof phone === "string")) { + throw new Error("입력 오류: phone_list는 문자열의 배열이어야 합니다."); + } + + // 배열이 비어 있는지 확인 + if (phone_list.length === 0) { + throw new Error("입력 오류: phone_list는 빈 배열이면 안 됩니다."); + } + // phone_list에 있는 전화번호들을 DB에서 조회 + let phoneListStr = phone_list.map((phone) => `'${phone}'`).join(","); + const query = `SELECT * FROM phones WHERE phone IN (${phoneListStr})`; + const rows = await queryDatabase(query); + + const return_body = { + success: true, + data: rows, + detail_code: "00", + message: "전화번호 조회 성공", + returnToken, + }; + return res.status(200).send(return_body); + } catch (error) { + console.log("에러 : ", error); + if (error.message === "입력 오류: phone_list는 문자열의 배열이어야 합니다.") { + console.log("비정상적 요청-post_friend_phonecheck: phone_list는 문자열의 배열이어야 합니다."); + const return_body = { + success: false, + detail_code: "01", + message: "비정상적 요청, phone_list는 문자열의 배열이어야 합니다.", + returnToken: null, + }; + return res.status(400).send(return_body); + } else if (error.message === "입력 오류: phone_list는 빈 배열이면 안 됩니다.") { + const return_body = { + success: false, + detail_code: "01", + message: "전화번호부에 적절한 형식의 전화번호가 없습니다.", + returnToken, + }; + return res.status(200).send(return_body); + } else { + console.error(`🚨 error -> ⚡️ post_friend_phonecheck : 🐞${err}`); + const return_body = { + success: false, + detail_code: "00", + message: "서버 오류", + returnToken: null, + }; + + return res.status(500).send(return_body); + } + } +}; diff --git a/tikkle_friend/post_user_friendDeep/index.js b/tikkle_friend/post_user_friendDeep/index.js new file mode 100644 index 0000000..4db9183 --- /dev/null +++ b/tikkle_friend/post_user_friendDeep/index.js @@ -0,0 +1,111 @@ +const { queryDatabase } = require("db.js"); + +exports.post_user_friendDeep = async (req, res) => { + const body = req.body; + const id = req.id; + const returnToken = req.returnToken; + + const tikkling_id = body.tikkling_id; + + //-------- is the tikkling_id valid? --------------------------------------------------------------------------------------// + + let sqlResult; + + try { + const rows = await queryDatabase("select * from tikkling where id = ?", [tikkling_id]); + sqlResult = rows; + // console.log("SQL result : ", sqlResult); + } catch (err) { + console.log("post_user_friendDeep 에서 에러가 발생했습니다.", err); + const return_body = { + success: false, + detail_code: "01", + message: "SQL error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + // check data is one + if (sqlResult.length !== 1) { + console.error(`🚨 error -> ⚡️ get_user_info : 🐞 ${err}`); + const return_body = { + success: false, + detail_code: "00", + message: "SQL error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + //-------- is the friendId valid? --------------------------------------------------------------------------------------// + const friendId = sqlResult[0].user_id; + + if (id === friendId) { + // console.log("post_user_friendDeep 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "00", + message: "You cannot be friend yourself", + returnToken: null, + }; + return res.status(400).send(return_body); + } + + //-------- get friend data & check, post friend data to DB if there is no friend data --------------------------------------------------------------------------------------// + + const insertQuery = `INSERT INTO friends_relation (central_user_id, friend_user_id, relation_state_id) + SELECT ?, ?, ? + WHERE NOT EXISTS ( + SELECT 1 + FROM friends_relation + WHERE central_user_id = ? AND friend_user_id = ? + );`; + + const values1 = [id, friendId, 1, id, friendId]; + const values2 = [friendId, id, 2, friendId, id]; + + let ret1 = null; + let ret2 = null; + + try { + //데이터 없으면 추가 + ret1 = await queryDatabase(insertQuery, values1); + + //데이터 없으면 추가 + ret2 = await queryDatabase(insertQuery, values2); + } catch (err) { + console.error(`🚨 error -> ⚡️ post_user_friendDeep : 🐞 ${err}`); + + const return_body = { + success: false, + detail_code: "00", + message: "SQL error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + //-------- return result --------------------------------------------------------------------------------------// + + // console.log("ret1 : ", ret1); + // console.log("ret2 : ", ret2); + + if (ret1.affectedRows !== 1) { + const return_body = { + success: true, + detail_code: "10", + message: "already friend", + returnToken: returnToken, + }; + return res.status(200).send(return_body); + } else { + const return_body = { + success: true, + detail_code: "11", + message: "success post user friend", + returnToken: returnToken, + }; + return res.status(200).send(return_body); + } +}; diff --git a/tikkle_friend/put_friend_block/index.js b/tikkle_friend/put_friend_block/index.js new file mode 100644 index 0000000..3fb52e9 --- /dev/null +++ b/tikkle_friend/put_friend_block/index.js @@ -0,0 +1,63 @@ +const { queryDatabase } = require("db.js"); + +exports.put_friend_block = async (req, res) => { + //재설정하고자 하는 친구의 user_id + + const body = req.body; + const id = req.id; + const returnToken = req.returnToken; + + //main logic------------------------------------------------------------------------------------------------------------------// + //TODO: 로직 분리 + try { + const target_friend_id = body.friend_id; + const blocked = body.blocked; + + //이미 차단한 친구라면 차단을 해제, 아니라면 차단 + let result; + if (blocked) { + result = await queryDatabase( + `UPDATE friends_relation + SET relation_state_id = 1 + WHERE central_user_id = ? and friend_user_id = ?`, + [id, target_friend_id] + ); + } else { + result = await queryDatabase( + `UPDATE friends_relation + SET relation_state_id = 3 + WHERE central_user_id = ? and friend_user_id = ?`, + [id, target_friend_id] + ); + } + + //해당 친구가 존재하지 않음 + if (result.affectRows == 0) { + console.log("비정상적 요청-put_friend_block: 해당 친구가 존재하지 않습니다."); + const return_body = { + success: false, + detail_code: "00", + message: "비정상적 요청, 해당 친구가 존재하지 않습니다.", + returnToken, + }; + return res.status(404).send(return_body); + } + + const return_body = { + success: true, + detail_code: "00", + message: "친구 차단 혹은 해제 성공", + returnToken, + }; + return res.status(200).send(return_body); + } catch (err) { + console.error(`🚨 error -> ⚡️ post_friend_block : 🐞${err}`); + const return_body = { + success: false, + detail_code: "00", + message: "서버 에러", + returnToken: null, + }; + return res.status(500).send(return_body); + } +}; diff --git a/tikkle_image/.DS_Store b/tikkle_image/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..82ceae130bb56420d38fb5b11d79645fd9ef4aaa GIT binary patch literal 6148 zcmeH~zfQwI490y>qyinvfan+=fT3>?s<1Iss#sWnQYeT-iJ&ksNa@B7PC8T~+&?5a2#-Uq2u$s;Q=paJ%|2aq{JG%gcadtIhRk;&WB zbhm#fOltp@B%M?FPMr!a+mvAz++jwPXG)n&1(EeV5UG(}WbyJmV^OQZoWgPyD#p)q z<3AbBY_{g6s;jeG(?8wiWxTFy{tzyWCJHCIIh<}?+m zsm_05I88@9@clxsxvHj { + const body = req.body; + const id = req.id; + const returnToken = req.returnToken; + + //get old image url + let pastUrl; + + try { + const rows = await queryDatabase( + ` SELECT image + FROM users + WHERE id = ? + `, + [id] + ); + + pastUrl = rows[0].image; + } catch (err) { + console.log("SQL error: ", err); + return { + statusCode: 501, + body: "SQL error: ", + }; + } + + //-------- delete user image data --------------------------------------------------------------------------------------// + let sqlResult; + + try { + const rows = await queryDatabase("UPDATE users SET image = ? WHERE id = ?", ["https://d2da4yi19up8sp.cloudfront.net/profile/default.JPG", id]); + + sqlResult = rows; + //console.log("SQL result : ", sqlResult); + } catch (err) { + console.log(" get_image_deleteProfile 에서 에러가 발생했습니다.", err); + const return_body = { + success: false, + detail_code: "01", + message: "SQL error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + //-------- delete user image s3 file --------------------------------------------------------------------------------------// + + const src_filename = "tikkle-profile-" + id.toString() + ".JPG"; + const bucket_src = await getSSMParameter("tikkleprofileS3"); + + // Delete src image + try { + const deleteParams = { + Bucket: bucket_src, + Key: src_filename, + }; + + await s3.deleteObject(deleteParams).promise(); + + // console.log("Src Object deleted successfully"); + } catch (error) { + console.log("get_image_deleteProfile 에서 에러가 발생했습니다.", error); + const return_body = { + success: false, + detail_code: "02", + message: "Error deleting src object in s3", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + // delete resized image + const timeStamp = pastUrl.split("-")[1].split(".")[0]; + + // console.log("timeStamp : ", timeStamp); + + const dstBucket = "tikkle-s3.online/profile"; + const fileName = id + "-" + timeStamp + ".JPG"; + + //console.log("dstBucket : ", dstBucket); + //console.log("fileName : ", fileName); + + try { + const params = { + Bucket: dstBucket, + Key: fileName, + }; + + const result = await s3.deleteObject(params).promise(); + } catch (err) { + console.log("get_image_deleteProfile 에서 에러가 발생했습니다.", error); + const return_body = { + success: false, + detail_code: "02", + message: "Error deleting src object in s3", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + //-------- return result --------------------------------------------------------------------------------------// + + const return_body = { + success: true, + data: sqlResult, + detail_code: "00", + message: "success to delete profile image", + returnToken: returnToken, + }; + return res.status(200).send(return_body); +}; diff --git a/tikkle_image/get_image_profileSaveUrl/index.js b/tikkle_image/get_image_profileSaveUrl/index.js new file mode 100644 index 0000000..81b7262 --- /dev/null +++ b/tikkle_image/get_image_profileSaveUrl/index.js @@ -0,0 +1,51 @@ +const AWS = require("aws-sdk"); + +const { getSSMParameter } = require("ssm.js"); + +exports.get_image_profileSaveUrl = async (req, res) => { + const body = req.body; + const id = req.id; + const returnToken = req.returnToken; + + //-------- get url --------------------------------------------------------------------------------------// + + // Instantiate the S3 SDK client + const s3 = new AWS.S3(); + const bucketname = await getSSMParameter("tikkleprofileS3"); + const filename = "tikkle-profile-" + id.toString() + ".JPG"; + + //console.log("filename: ", filename); + + // Set the parameters for the pre-signed URL + const params = { + Bucket: bucketname, + Key: filename, + Expires: 360, // URL expiration time in seconds (e.g., 0.1 hour) + }; + + let url = null; + + try { + url = await s3.getSignedUrl("putObject", params); + } catch (error) { + console.log("get_image_profileSaveUrl 에서 에러가 발생했습니다.", error); + const return_body = { + success: false, + detail_code: "00", + message: "url making fail", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + //-------- return data --------------------------------------------------------------------------------------// + + const return_body = { + success: true, + data: url, + detail_code: "00", + message: "success to make url", + returnToken: returnToken, + }; + return res.status(200).send(return_body); +}; diff --git a/tikkle_image/post_image_profileUrl/index.js b/tikkle_image/post_image_profileUrl/index.js new file mode 100644 index 0000000..05a69e0 --- /dev/null +++ b/tikkle_image/post_image_profileUrl/index.js @@ -0,0 +1,88 @@ +const { queryDatabase } = require("db.js"); + +exports.post_image_profileUrl = async (req, res) => { + const body = req.body; + const id = req.id; + const returnToken = req.returnToken; + + const imageSize = body.imageSize.toString(); + const userId = body.userId; + + //-------- check body data --------------------------------------------------------------------------------------// + + if ( + !imageSize || + (imageSize !== "36" && + imageSize !== "48" && + imageSize !== "64" && + imageSize !== "128" && + imageSize !== "0") + ) { + console.log("ERROR : size value is null or invalid"); + const return_body = { + success: false, + detail_code: "00", + body: "input image size again", + returnToken: null, + }; + return res.status(400).send(return_body); + } + + //-------- get profile urls --------------------------------------------------------------------------------------// + + let sqlResult; + + try { + const rows = await queryDatabase("select * from users where id = ?", [ + userId, + ]); + sqlResult = rows; + //console.log("SQL result : ", sqlResult); + } catch (err) { + console.log("post_image_profileUrl 에서 에러가 발생했습니다.", err); + const return_body = { + success: false, + detail_code: "00", + message: "SQL error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + // check data is one + if (sqlResult.length !== 1) { + console.log("post_image_profileUrl 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "00", + message: "SQL error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + const retData = JSON.parse(sqlResult[0].image); + const url = retData[imageSize]; + + //-------- return data --------------------------------------------------------------------------------------// + + if (imageSize === "0") { + const return_body = { + success: true, + data: JSON.stringify(retData), + detail_code: "10", + message: "success - return all image urls", + returnToken: returnToken, + }; + return res.status(200).send(return_body); + } + + const return_body = { + success: true, + data: url, + detail_code: "11", + message: "success - return one image url", + returnToken: returnToken, + }; + return res.status(200).send(return_body); +}; diff --git a/tikkle_notification/.DS_Store b/tikkle_notification/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..608bbd718b09c73027624374498b8aa19178f4b3 GIT binary patch literal 6148 zcmeH~%}T>S5XWaVU{MbR@#7dTf;amHX^A%vLhn}F)K*Blg|^^9B=6$Uy9e)HeG?Bp zfYATUE}Bq3NClBH1GE2Rl9^qEVD zBMeHt!@zz}ShPlw!x3}X1&8Sm6cSKKukFUNAgOYt6D4A(+FfJR<3 Rr-;DxM?f%WqXhnxzzhu|yGj56 literal 0 HcmV?d00001 diff --git a/tikkle_notification/get_notification_list/index.js b/tikkle_notification/get_notification_list/index.js new file mode 100644 index 0000000..3b29af7 --- /dev/null +++ b/tikkle_notification/get_notification_list/index.js @@ -0,0 +1,66 @@ +const { queryDatabase } = require("db.js"); + +exports.get_notification_list = async (req, res) => { + const body = req.body; + const id = req.id; + const returnToken = req.returnToken; + + //-------- check DB --------------------------------------------------------------------------------------// + + let sqlResult; + + try { + const rows1 = await queryDatabase( + ` SELECT n.*, nt.name AS notification_type_name + FROM notification AS n + INNER JOIN notification_type AS nt ON n.notification_type_id = nt.id + LEFT JOIN friends_relation AS fr ON (n.user_id = fr.central_user_id AND n.source_user_id = fr.friend_user_id) + WHERE n.user_id = ? AND n.is_deleted <> ? + AND (fr.relation_state_id IS NULL OR fr.relation_state_id <> 3 OR n.source_user_id = 0) + ORDER BY n.created_at DESC; + `, + [id, 1] + ); + sqlResult = rows1; + } catch (err) { + console.log("get_notification_list 에서 에러가 발생했습니다.", err); + const return_body = { + success: false, + detail_code: "01", + message: "SQL error : check DB error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + const retData = sqlResult; + + try { + const rows = await queryDatabase( + ` UPDATE notification + SET is_read = 1 + WHERE user_id = ? AND is_deleted <> ?;`, + [id, 1] + ); + } catch (err) { + console.log("get_notification_list 에서 에러가 발생했습니다.", err); + const return_body = { + success: false, + detail_code: "02", + message: "SQL error: error when update data", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + //-------- return result --------------------------------------------------------------------------------------// + + const return_body = { + success: true, + data: retData, + detail_code: "00", + message: "success get notification list", + returnToken: returnToken, + }; + return res.status(200).send(return_body); +}; diff --git a/tikkle_notification/post_notification_send/index.js b/tikkle_notification/post_notification_send/index.js new file mode 100644 index 0000000..25937c9 --- /dev/null +++ b/tikkle_notification/post_notification_send/index.js @@ -0,0 +1,302 @@ +const { queryDatabase } = require("db.js"); +const { fcm_send, fcm_send_many } = require("fcm.js"); + +exports.post_notification_send = async (req, res) => { + const body = req.body; + const id = req.id; + const returnToken = req.returnToken; + + let receive_user_id = body.receive_user_id; + const notification_type_id = body.notification_type_id; + const tikkling_id = body.tikkling_id; + let title = "알림"; + + //-------- get user data from DB --------------------------------------------------------------------------------------// + + let sqlResult; + + try { + const rows = await queryDatabase("select * from users where id = ?", [id]); + sqlResult = rows; + //console.log("SQL result : ", sqlResult); + } catch (err) { + console.log("post_notification_send 에서 에러가 발생했습니다.", err); + const return_body = { + success: false, + detail_code: "02", + message: "SQL error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + // check data is one + if (sqlResult.length !== 1) { + console.log("post_notification_send 에서 에러가 발생했습니다.", err); + const return_body = { + success: false, + detail_code: "02", + message: "SQL error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + const name = sqlResult[0].name; + const profile = sqlResult[0].image; + //console.log("name : ", name); + + //-------- check notification_type_id and make message --------------------------------------------------------------------------------------// + const meta_data = profile; + + let message; + let deep_link; + let link; + let source_user_id; + + if (notification_type_id === 1) { + message = name + "님이 가입했어요."; + title = "새로운 친구"; + link = "link_for_1"; + deep_link = "tikkle://notification"; + source_user_id = id; + // + } else if (notification_type_id === 3) { + message = name + "님의 티클링이 시작되었어요."; + title = "✨ 티클링 시작"; + link = "link_for_3"; + source_user_id = id; + deep_link = "tikkle://tikklingDetail/" + tikkling_id.toString(); + // + } else if (notification_type_id === 5) { + message = name + "님이 보낸 티클을 확인해보세요."; + if (receive_user_id == id) { + message = "직접 구매한 티클을 확인해보세요."; + } + title = "🎁 티클 선물"; + link = "link_for_5"; + deep_link = "tikkle://tikklingDetail/" + tikkling_id.toString(); + source_user_id = id; + // + } else if (notification_type_id === 6) { + message = "티클링 상품 교환이 완료되었어요."; + link = "link_for_6"; + title = "📦 배송 시작"; + deep_link = "tikkle://main"; + source_user_id = id; + receive_user_id = id; + // + } else if (notification_type_id === 8) { + message = name + "님이 티클을 환불했어요."; + title = "환불된 티클"; + link = "dlink_for_8"; + deep_link = "tikkle://tikklingDetail/" + receive_user_id.toString(); + source_user_id = id; + + //receive_user_id 대신 tikkling id 가오는 상황이라 쿼리로 바꿔줌 + let sqlResult_tikkling; + + try { + const rows = await queryDatabase("select user_id from tikkling where id = ?", [receive_user_id]); + sqlResult_tikkling = rows; + //console.log("SQL result : ", sqlResult_tikkling); + } catch (err) { + console.log("post_notification_send 에서 에러가 발생했습니다.", err); + const return_body = { + success: false, + detail_code: "02", + message: "SQL error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + receive_user_id = sqlResult_tikkling[0].user_id; + + if (receive_user_id == id) { + message = "직접 구매하신 티클의 환불이 완료되었어요."; + } + // + } else if (notification_type_id === 9) { + message = "티클링 환급 신청이 완료되었어요."; + title = "💵 환급 신청 완료"; + deep_link = "tikkle://notification"; + link = "link_for_9"; + source_user_id = id; + receive_user_id = id; + } else { + } + + //-------- get friend ID from DB or set receive user ID --------------------------------------------------------------------------------------// + let receiver; + + if (notification_type_id === 1 && receive_user_id === null) { + try { + const rows = await queryDatabase( + ` + SELECT friend_user_id + FROM friends_relation + WHERE central_user_id = ? + AND relation_state_id = 2 + `, + [id] + ); + receiver = rows; + // console.log("SQL result : ", receiver); + } catch (err) { + console.log("post_notification_send 에서 에러가 발생했습니다.", err); + const return_body = { + success: false, + detail_code: "02", + message: "SQL error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + } else if (notification_type_id === 3) { + try { + const rows = await queryDatabase( + ` + SELECT friend_user_id + FROM friends_relation + WHERE central_user_id = ? + AND relation_state_id <> 3 + `, + [id] + ); + receiver = rows; + // console.log("SQL result : ", receiver); + } catch (err) { + console.log("post_notification_send 에서 에러가 발생했습니다.", err); + const return_body = { + success: false, + detail_code: "02", + message: "SQL error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + } else if ((notification_type_id === 1 && receive_user_id !== null) || notification_type_id === 5 || notification_type_id === 6 || notification_type_id === 8 || notification_type_id === 9) { + receiver = []; + const a = { friend_user_id: receive_user_id }; + receiver.push(a); + } + + //console.log("reciver : ", receiver); + + //-------- add notification data to DB --------------------------------------------------------------------------------------// + + if (receiver.length > 0) { + let notificationValues = ""; + for (let i = 0; i < receiver.length; i++) { + notificationValues += "("; + notificationValues += `${receiver[i].friend_user_id},`; + notificationValues += `'${message}', `; + notificationValues += `0, `; + notificationValues += `0, `; + notificationValues += `${notification_type_id}, `; + notificationValues += `'${deep_link}', `; + notificationValues += `'${link}', `; + notificationValues += `'${meta_data}', `; + notificationValues += `${source_user_id} `; + notificationValues += ")"; + if (i < receiver.length - 1) notificationValues += ", "; + } + + console.log("notification : ", notificationValues); + + await queryDatabase( + `INSERT INTO notification + (user_id, message, is_deleted, is_read, notification_type_id, deep_link, link, meta_data, source_user_id) + VALUES ${notificationValues}` + ); + } + + //-------- send notification by FCM --------------------------------------------------------------------------------------// + + if (!(notification_type_id == 1 && receive_user_id === null) && notification_type_id !== 3) { + //resiver 1명 + let token_sqlResult; + + try { + const rows = await queryDatabase("select * from users where id = ?", [receive_user_id]); + token_sqlResult = rows; + //console.log("SQL result : ", token_sqlResult); + } catch (err) { + console.log("post_notification_send token확인 에서 에러가 발생했습니다.", err); + const return_body = { + success: false, + detail_code: "02", + message: "SQL error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + // check data is one + if (token_sqlResult.length !== 1) { + console.log("post_notification_send token확인 에서 에러가 발생했습니다.", err); + const return_body = { + success: false, + detail_code: "02", + message: "SQL error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + const device_token = token_sqlResult[0].device_token; + + //send notification + await fcm_send(device_token, "알림", message, deep_link); + } else if (notification_type_id === 3) { + //resiver 여러명 + const device_tokens = []; + + try { + const temp_token = await queryDatabase( + ` + SELECT users.device_token + FROM friends_relation + LEFT JOIN users ON users.id = friends_relation.friend_user_id + WHERE central_user_id = ? + AND relation_state_id <> 3 + `, + [id] + ); + + for (let i = 0; i < temp_token.length; i++) { + if (temp_token[i].device_token !== null) { + device_tokens.push(temp_token[i].device_token); + } + } + } catch (err) { + console.log("post_notification_send 에서 에러가 발생했습니다.", err); + const return_body = { + success: false, + detail_code: "02", + message: "SQL error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + //알림 보내기 + if (device_tokens.length > 0) { + // console.log("@@@SQL result : ", device_tokens); + console.log("@@@ : ", deep_link); + await fcm_send_many(device_tokens, title, message, deep_link); + } + } else { + } //일단 1인 경우는 알림 x + + //-------- return result --------------------------------------------------------------------------------------// + + const return_body = { + success: true, + detail_code: "00", + message: "send notification success!", + returnToken: returnToken, + }; + return res.status(200).send(return_body); +}; diff --git a/tikkle_notification/put_notification_delete/index.js b/tikkle_notification/put_notification_delete/index.js new file mode 100644 index 0000000..5e5bc7d --- /dev/null +++ b/tikkle_notification/put_notification_delete/index.js @@ -0,0 +1,46 @@ +const { queryDatabase } = require("db.js"); + +exports.put_notification_delete = async (req, res) => { + const body = req.body; + const id = req.id; + const returnToken = req.returnToken; + + const notificationId = body.notificationId; + + //-------- check DB --------------------------------------------------------------------------------------// + + let sqlResult; + + try { + const rows = await queryDatabase( + ` UPDATE notification + SET is_deleted = 1 + WHERE user_id = ? AND id = ?;`, + [id, notificationId] + ); + sqlResult = rows; + console.log("SQL result : ", sqlResult); + } catch (err) { + console.log("put_notification_delete 에서 에러가 발생했습니다.", err); + const return_body = { + success: false, + detail_code: "00", + message: "SQL error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + const retData = sqlResult; + + //-------- return result --------------------------------------------------------------------------------------// + + const return_body = { + success: true, + data: retData, + detail_code: "00", + message: "success delete notification", + returnToken: returnToken, + }; + return res.status(200).send(return_body); +}; diff --git a/tikkle_payment/.DS_Store b/tikkle_payment/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..40e15d1ed27af06806eadc471a3ddf35befb2b09 GIT binary patch literal 8196 zcmeHM!EVz)5S@iUB6=wlq#_~VOF34`fg_Sz%z+zH+jE;XNeQ*%2vVe074k>qEBXn& zap1s(Kj6TXU+AT8c2?M{#I2nis9;vwea?E{*zbA0n@NbsY#w*pM5{#9LS+UFqqRdFPzTfjbwC|Z2X2D{*t5B`O7?v@tF1bq4*Zu6 z@cIy-GKLN_LA!LIu_*wsfo@xHj6A?{0*9f)OwdvhQ?du+sK%ujM(8*n@Ni)0FcTCy z8KIMLS2iv~G4|@<1$H=@P*7WSKpmKNfOGf9bcl?7OuJtG&YwHz8PGPRbi_G*eAwPP zNRyF-X{^-YCTSGy$LT&etrwH*>)WGm8}<0zh4`cQ#e27_#1p7X>C;T*edr!Se+)dO zp09l6JMO#&yQqErqPgBXv)XG#$kopm!Pg%^0G@lfewh&w92ir_SAYLU9d1$kU%!8X#N&`6}h>_y4)E$ z?IhJ^VF&I?gjLS}-<1FUzwmW5fI6TK++GJvBif2Kaepqip1M=cwFA^WR4zO&6SNdG vHXR4rbR78S4?`RW7|NW`VJ3(kl)vypz>Rydzeno+&)*w#|F_fipJ}cDdfwl5 literal 0 HcmV?d00001 diff --git a/tikkle_payment/get_payment_apiToken/index.js b/tikkle_payment/get_payment_apiToken/index.js new file mode 100644 index 0000000..fdfcbea --- /dev/null +++ b/tikkle_payment/get_payment_apiToken/index.js @@ -0,0 +1,34 @@ +const { Tikkle } = require("../../features/Tikkle"); + +// +exports.get_payment_apiToken = async (req, res) => { + const body = req.body; + const id = req.id; + const returnToken = req.returnToken; + + //-------- get token --------------------------------------------------------------------------------------// + // console.log("#####################################"); + try { + const token = await Tikkle.getPortOneApiToken(); + + //-------- return result --------------------------------------------------------------------------------------// + + const return_body = { + success: true, + data: token, + detail_code: "00", + message: "success get token info", + //returnToken: returnToken, + }; + return res.status(200).send(return_body); + } catch (err) { + console.log("get_payment_apiToken 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "00", + message: "import token get error", + returnToken: null, + }; + return res.status(500).send(return_body); + } +}; diff --git a/tikkle_payment/post_payment_finalize/index.js b/tikkle_payment/post_payment_finalize/index.js new file mode 100644 index 0000000..b4a9a07 --- /dev/null +++ b/tikkle_payment/post_payment_finalize/index.js @@ -0,0 +1,156 @@ +const { Tikkling } = require("../../features/Tikkling"); +const { Tikkle } = require("../../features/Tikkle"); +const { Response } = require("../../features/Response"); +const { ExpectedError } = require("../../features/ExpectedError"); +const { DBManager } = require("../../db"); +const { queryDatabase } = require("db.js"); +const { fcm_send, fcm_send_many } = require("fcm.js"); +const { InviteEventManager } = require("../../features/InviteEventManager"); + +exports.post_payment_finalize = async (req, res) => { + const { body, id, returnToken, params } = req; + const { tikkleAction } = params; + const { merchant_uid, imp_uid, status } = body; + //main logic------------------------------------------------------------------------------------------------------------------// + const db = new DBManager(); + await db.openTransaction(); + + let receive_user_id; + let tikkling_id; + let send_user_id; + + try { + //티클 객체 생성 + const tikkle_info = await Tikkle.getTikkleByMerchantUid({ merchant_uid, db }); + + const tikkle = new Tikkle({ ...tikkle_info, db }); + + //결제 이전인지 확인 + tikkle.assertTikkleIsNotPaid(); + + //티클링 객체 생성 + const tikkling = new Tikkling({ id: tikkle.tikkling_id, db }); + + //해당 티클링 락 + await tikkling.lockTikklingForInsertTikkle(); + //티클링 정보 가져오기 + await tikkling.loadActiveTikklingViewByTikklingId(); + + //티클링이 티클을 받을 수 있는 상태인지 검사 + if (tikkleAction == "sendtikkle") { + await tikkling.validateSendTikkleRequest({ tikkle_quantity: tikkle.quantity }); + await tikkling.checkAndUpdateTikklingStateToEnd({ tikkle_quantity: tikkle.quantity }); + } else if (tikkleAction == "buymytikkle") { + tikkling.validateBuyMyTikkleRequest({ user_id: tikkle.user_id, tikkle_quantity: tikkle.quantity }); + } + + receive_user_id = tikkling.user_id; + tikkling_id = tikkling.id; + send_user_id = tikkle.user_id; + + //DB상 결제 완료 처리 + // 보너스티클이 전체 티클 개수를 초과하면 미지급 + // 보너스 티클이 만약 마지막 조각이라면 티클링 (완료)중단처리 + // 나의 티클 결제일경우 미지급 + await tikkle.completeTikklePayment(); + if (tikkleAction == "sendtikkle") { + if (parseInt(tikkle.quantity) + parseInt(tikkling.tikkle_count) < parseInt(tikkling.tikkle_quantity)) { + // TODO: event가 끝난 뒤 제거 + const invite_event_manager = new InviteEventManager({ db }); + await invite_event_manager.eventProcessAfterTikkleSent(merchant_uid, tikkling, tikkle); + // await tikkling.checkAndUpdateTikklingStateToEnd({ tikkle_quantity: tikkle.quantity + 1 }); + } + } + //줄 수 있을 때만 제공 + + //트랜잭션 종료 + await db.commitTransaction(); + } catch (err) { + //티클 정보 가져오기 + const tikkle_info = await Tikkle.getTikkleByMerchantUid({ merchant_uid, db }); + + //티클 객체 생성 + const tikkle = new Tikkle({ ...tikkle_info, db }); + + //확실한 결제 직후의 상태 + if (tikkle.state_id == 5) { + //포트원 토큰 가져오기 + const port_one_token = await Tikkle.getPortOneApiToken(); + + //포트원 환불 api 호출 + await tikkle.callPortOneCancelPaymentAPI({ reason: "buymytikkle 처리중 에러", port_one_token }); + } + + //트랜잭션 롤백 + await db.rollbackTransaction(); + + console.error(`🚨 error -> ⚡️ post_payment_finalize/${tikkleAction} : 🐞${err}`); + if (err.status) { + return res.status(err.status).send(Response.create(false, err.detail_code, err.message)); + } + return res.status(500).send(Response.create(false, "00", "서버 에러")); + } + + //-------- send notification --------------------------------------------------------------------------------------// + // console.log("sned noti ", receive_user_id, tikkling_id, send_user_id); + try { + //보내는 사람 정보 + try { + const rows = await queryDatabase("select * from users where id = ?", [send_user_id]); + sqlResult = rows; + //console.log("SQL result : ", sqlResult); + } catch (err) { + console.log("post_notification_send 에서 에러가 발생했습니다.", err); + } + + // check data is one + if (sqlResult.length !== 1) { + console.log("post_notification_send 에서 에러가 발생했습니다.", err); + } + + const name = sqlResult[0].name; + + //DB에 알림 저장 + message = name + "님이 보낸 티클을 확인해보세요."; + if (send_user_id == receive_user_id) { + message = "직접 구매한 티클을 확인해보세요."; + } + title = "티클 선물 🎁"; + link = "link_for_5"; + deep_link = "tikkle://tikklingDetail/" + tikkling_id.toString(); + source_user_id = send_user_id; + + const notiDB = await queryDatabase( + `INSERT INTO notification + (user_id, message, is_deleted, is_read, notification_type_id, deep_link, link, meta_data, source_user_id) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, + [receive_user_id, message, 0, 0, 5, deep_link, link, null, source_user_id] + ); + // console.log("notiDB : ", notiDB); + + ////푸시 알림 + //resiver 1명 + let token_sqlResult; + + try { + const rows = await queryDatabase("select * from users where id = ?", [receive_user_id]); + token_sqlResult = rows; + //console.log("SQL result : ", token_sqlResult); + } catch (err) { + console.log("post_notification_send token확인 에서 에러가 발생했습니다.", err); + } + + // check data is one + if (token_sqlResult.length !== 1) { + console.log("post_notification_send token확인 에서 에러가 발생했습니다.", err); + } + + const device_token = token_sqlResult[0].device_token; + + //send notification + + await fcm_send(device_token, "알림", message, deep_link); + } catch {} + + return res.status(200).send(Response.create(true, "00", "결제 데이터 저장 완료")); +}; diff --git a/tikkle_payment/post_payment_getData/index.js b/tikkle_payment/post_payment_getData/index.js new file mode 100644 index 0000000..138f03f --- /dev/null +++ b/tikkle_payment/post_payment_getData/index.js @@ -0,0 +1,53 @@ +const { Tikkle } = require("../../features/Tikkle"); +const { User } = require("../../features/User"); +const { Response } = require("../../features/Response"); +const axios = require("axios"); + +exports.post_payment_getData = async (req, res) => { + const { body, id, returnToken } = req; + const { merchant_uid } = body; + + //-------- get portone token 2 --------------------------------------------------------------------------------------// + let Authorization = null; + try { + Authorization = await Tikkle.getPortOneApiToken(); + } catch (err) { + console.error(`🚨 error -> ⚡️ post_payment_getData : 🐞${err}`); + if (err.status) { + return res.status(err.status).send(createResponseBody(false, err.detail_code, err.message)); + } + + return res.status(500).send(createResponseBody(false, "00", "서버 에러")); + } + + //-------- call port one AI for data --------------------------------------------------------------------------------------// + let result = null; + + try { + const axios_result = await axios({ + url: "https://api.iamport.kr/payments/find/" + merchant_uid, + method: "get", + headers: { + "Content-Type": "application/json", + Authorization: Authorization, + }, + }); + + // console.log("RES : ", axios_result.data); + result = axios_result.data.response; + } catch (error) { + console.error("Error:", error); + return res.status(500).send(createResponseBody(false, "01", "서버 에러")); + } + + //-------- return result --------------------------------------------------------------------------------------// + + const return_body = { + success: true, + data: result, + detail_code: "00", + message: "success get product info", + returnToken: returnToken, + }; + return res.status(200).send(return_body); +}; diff --git a/tikkle_payment/post_payment_init/index.js b/tikkle_payment/post_payment_init/index.js new file mode 100644 index 0000000..e1cb78a --- /dev/null +++ b/tikkle_payment/post_payment_init/index.js @@ -0,0 +1,65 @@ +const { Tikkle } = require("../../features/Tikkle"); +const { User } = require("../../features/User"); +const { Response } = require("../../features/Response"); +const { DBManager } = require("../../db"); +const { Tikkling } = require("../../features/Tikkling"); +const { ExpectedError } = require("../../features/ExpectedError"); +const { getSSMParameter } = require("ssm.js"); + +exports.post_payment_init = async (req, res) => { + const { body, id, returnToken, params } = req; + const { tikkleAction } = params; + const { tikkling_id, tikkle_quantity, message } = body; + //main logic------------------------------------------------------------------------------------------------------------------// + const db = new DBManager(); + await db.openTransaction(); + try { + //user정보 가져옴 + const user = await User.createById({ id, db }); + + //티클링 객체 생성 + const tikkling = new Tikkling({ id: tikkling_id, db }); + + //해당 티클링 락 + await tikkling.lockTikklingForInsertTikkle(); + + //티클링 정보 가져오기 + await tikkling.loadActiveTikklingViewByTikklingId(); + + if (tikkleAction == "sendtikkle") { + //요청의 유효성 겅사 + await tikkling.validateSendTikkleRequest({ tikkle_quantity }); + } else if (tikkleAction == "buymytikkle") { + //요청의 유효성 겅사 + tikkling.validateBuyMyTikkleRequest({ user_id: id, tikkle_quantity }); + } else { + throw new ExpectedError({ + status: "403", + message: `잘못된 요청, 해당 기능을 찾을 수 없습니다.`, + detail_code: "00", + }); + } + //티클링이 정보를 받을 수 있는 상태라면 티클 객체 생성 + const tikkle = new Tikkle({ tikkling_id, user_id: id, message, quantity: tikkle_quantity, state_id: 5, db }); + + //해당 티클정보를 db에 저장 + await tikkle.initTikklePayment(); + + //payment param 객체 생성 + const TIKKLE_API_ADDRESS = await getSSMParameter("TIKKLE_API_ADDRESS"); + const notice_url = `${TIKKLE_API_ADDRESS}/post_payment_finalize/${tikkleAction}`; + const payment_param = tikkle.createPaymentParam({ user_name: user.name, user_phone: user.phone, notice_url }); + + //transaction commit + await db.commitTransaction(); + + return res.status(200).send(Response.create(true, "00", "결제 데이터 저장 완료", payment_param, returnToken)); + } catch (err) { + await db.rollbackTransaction(); + console.error(`🚨 error -> ⚡️ post_payment_init/${tikkleAction} : 🐞${err}`); + if (err.status) { + return res.status(err.status).send(Response.create(false, err.detail_code, err.message)); + } + return res.status(500).send(Response.create(false, "00", "서버 에러")); + } +}; diff --git a/tikkle_payment/put_payment_fail/index.js b/tikkle_payment/put_payment_fail/index.js new file mode 100644 index 0000000..4f457e7 --- /dev/null +++ b/tikkle_payment/put_payment_fail/index.js @@ -0,0 +1,39 @@ +const { Tikkle } = require("../../features/Tikkle"); +const { User } = require("../../features/User"); +const { Response } = require("../../features/Response"); +const { DBManager } = require("../../db"); + +exports.put_payment_fail = async (req, res) => { + const { body, id, returnToken } = req; + const { merchant_uid } = body; + + const db = new DBManager(); + await db.openTransaction(); + + //main logic------------------------------------------------------------------------------------------------------------------// + try { + //payment를 생성 + const tikkle_info = await Tikkle.getTikkleByMerchantUid({ merchant_uid, db }); + + //payment 객체 생성 + const tikkle = new Tikkle({ ...tikkle_info, db }); + + //DB상의 결제정보와 비교 + tikkle.compareStoredTikkleData({ user_id: id }); + + //결제 실패 처리 + await tikkle.updateTikkleToFail(); + + await db.commitTransaction(); + + return res.status(200).send(Response.create(true, "00", "결제 실패 처리 완료", null, returnToken)); + } catch (err) { + await db.rollbackTransaction(); + + console.error(`🚨 error -> ⚡️ put_payment_fail : 🐞 ${err}`); + if (err.status) { + return res.status(err.status).send(Response.create(false, err.detail_code, err.message)); + } + return res.status(500).send(Response.create(false, "00", "서버 에러")); + } +}; diff --git a/tikkle_payment/put_payment_refund/index.js b/tikkle_payment/put_payment_refund/index.js new file mode 100644 index 0000000..feee934 --- /dev/null +++ b/tikkle_payment/put_payment_refund/index.js @@ -0,0 +1,129 @@ +const { Tikkle } = require("../../features/Tikkle"); +const { User } = require("../../features/User"); +const { Response } = require("../../features/Response"); +const { Notice } = require("../../features/Notice"); +const { DBManager } = require("../../db"); +const { queryDatabase } = require("db.js"); +const { InviteEventManager } = require("../../features/InviteEventManager"); + +exports.put_payment_refund = async (req, res) => { + const { body, id, returnToken } = req; + const { merchant_uid, reason } = body; + + const db = new DBManager(); + await db.openTransaction(); + let receive_user_id; + let tikkling_id; + let send_user_id; + + //main logic------------------------------------------------------------------------------------------------------------------// + try { + //Tikkle 생성 + + const tikkle_info = await Tikkle.getTikkleByMerchantUid({ + merchant_uid, + db, + }); + + //payment 객체 생성 + const tikkle = new Tikkle({ ...tikkle_info, db }); + tikkling_id = tikkle.tikkling_id; + send_user_id = tikkle.user_id; + //DB상의 결제정보와 비교 + tikkle.compareStoredTikkleData({ user_id: id }); + + //환불 가능한 티클인지 확인 + await tikkle.checkTikkleCanRefund(); + + //포트원 토큰 가져오기 + const port_one_token = await Tikkle.getPortOneApiToken(); + + // //결제 환불 처리 in Tikkle DB (sendingTikkle state = 3, payment state = PAYMENT_CANCELLED) + await tikkle.updateTikkleToRefund(); + // TODO: event끝난뒤 제거 + const user_invite_event_manager = new InviteEventManager({ db }); + await user_invite_event_manager.eventProcessAfterTikkleRefunded(tikkle.id); + //만약 종료된 상태였다면 티클링 재개 + receive_user_id = await tikkle.restart_tikkling(); + + // //아이엠 포트 결제 취소 + await tikkle.callPortOneCancelPaymentAPI({ + port_one_token: port_one_token, + reason: reason, + }); + + await db.commitTransaction(); + + //-------- send notification --------------------------------------------------------------------------------------// + //console.log("sned noti ", receive_user_id, tikkling_id, send_user_id); + if (receive_user_id != null) { + try { + //보내는 사람 정보 + try { + const rows = await queryDatabase("select * from users where id = ?", [send_user_id]); + sqlResult = rows; + //console.log("SQL result : ", sqlResult); + } catch (err) { + console.log("1. send notification 에서 에러가 발생했습니다.", err); + } + + // check data is one + if (sqlResult.length !== 1) { + console.log("2. send notification 에서 에러가 발생했습니다.", err); + } + + const name = sqlResult[0].name; + + //DB에 알림 저장 + message = name + "님이 티클을 환불하여 티클이 재개되었어요."; + + title = "티클링 재개"; + link = "link_for_5"; + deep_link = "tikkle://tikklingDetail/" + tikkling_id.toString(); + source_user_id = send_user_id; + + const notiDB = await queryDatabase( + `INSERT INTO notification + (user_id, message, is_deleted, is_read, notification_type_id, deep_link, link, meta_data, source_user_id) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, + [receive_user_id, message, 0, 0, 10, deep_link, link, null, source_user_id] + ); + // console.log("notiDB : ", notiDB); + + ////푸시 알림 + //resiver 1명 + let token_sqlResult; + + try { + const rows = await queryDatabase("select * from users where id = ?", [receive_user_id]); + token_sqlResult = rows; + //console.log("SQL result : ", token_sqlResult); + } catch (err) { + console.log("post_notification_send token확인 에서 에러가 발생했습니다.", err); + } + + // check data is one + if (token_sqlResult.length !== 1) { + console.log("post_notification_send token확인 에서 에러가 발생했습니다.", err); + } + + const device_token = token_sqlResult[0].device_token; + + //send notification + + await fcm_send(device_token, "티클링 재개", message, deep_link); + } catch {} + } + + // //리텅 + return res.status(200).send(Response.create(true, "00", "결제 환불 처리 완료", null, returnToken)); + } catch (err) { + await db.rollbackTransaction(); + + console.error(`🚨 error -> ⚡️ put_payment_refund : 🐞 ${err}`); + if (err.status) { + return res.status(err.status).send(Response.create(false, err.detail_code, err.message)); + } + return res.status(500).send(Response.create(false, "00", "서버 : 결제 환불 처리 실패")); + } +}; diff --git a/tikkle_product/.DS_Store b/tikkle_product/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..887b5423ca3ad993ed6484e0dc9acb82d459de33 GIT binary patch literal 8196 zcmeHMF>ezw82t=M6bT7Ii_{`99O}T_k?p7s1QHTRUD%*Wj!-GdMI@z6<$gwIegW;k z%G8k`0RI3nGBBVb-e+5PHo2tdMnaYN9N91N`T6`_e0DyEh}70zZxB1+12iYH7+cH@YAX6P(Sx#7WkU>Q=(rwnb6{*S zH)!aj44ss{v$7G2(su_h(#=W52Bj1S#DQ4{ICfv9KBY9J=U)8IpEJ}-X| zUv0CA@z&zGT7UjH-MD+8wbta8N<+C7I@cEHOrep_Y6f@>@$HXj>ML%1gW|v*TFuYF?L4o^E_H{qEA(Dp zsCPs!Df7Sc)@Nv~!E$vzeE;F}mxUX;R!5R82%hmVmXyeYo z+cWhQ%u-(%)7KYapg5Er<0Q3eU48>~DecoEJhxpu$0_FSgi>E^>+n2%xZ1y-6mvLu zEW@mHVwrw?U+k|tc1O~(4qP@JtaJQ-fByOZvbPbwI3NyOUAsvCvKM;)D#pt90%%f99aBei1!hiGAFi}8$=D#KR*aq^ed&<#gii92;0ToT`!F3 T?{g7b6TIij{?E2as^h>P!UymS literal 0 HcmV?d00001 diff --git a/tikkle_product/get_product_options/index.js b/tikkle_product/get_product_options/index.js new file mode 100644 index 0000000..38ab561 --- /dev/null +++ b/tikkle_product/get_product_options/index.js @@ -0,0 +1,36 @@ +const { Tikkling } = require("../../features/Tikkling"); +const { Response } = require("../../features/Response"); +const { User } = require("../../features/User"); +const { ExpectedError } = require("../../features/ExpectedError"); +const { DBManager } = require("../../db"); +const { Product, Brand } = require("../../features/Product"); + +exports.get_product_options = async (req, res) => { + const id = req.id; + const returnToken = req.returnToken; + const { product_id } = req.params; + + const db = new DBManager(); + await db.openTransaction(); + try { + const product = new Product({ id: product_id, db }); + await product.loadProductOptions(); + //db객체 전부 삭제 + // TODO: 함수화 시켜서 사용하기 + for (const category of Object.keys(product.product_options.formatted_option)) { + for (const option of product.product_options.formatted_option[category]) option.db = null; + } + + const product_options = await product.product_options.getFormattedOption(); + return res.status(200).send(Response.create(true, "00", "성공적으로 상품 옵션을 조회하였습니다.", product_options, returnToken)); + } catch (err) { + console.error(`🚨 error -> ⚡️ get_product_options : 🐞${err}`); + const return_body = { + success: false, + detail_code: "00", + message: "SQL error", + returnToken: null, + }; + return res.status(500).send(return_body); + } +}; diff --git a/tikkle_product/post_product_brand/index.js b/tikkle_product/post_product_brand/index.js new file mode 100644 index 0000000..2e969b2 --- /dev/null +++ b/tikkle_product/post_product_brand/index.js @@ -0,0 +1,30 @@ +const { Tikkling } = require("../../features/Tikkling"); +const { Response } = require("../../features/Response"); +const { User } = require("../../features/User"); +const { ExpectedError } = require("../../features/ExpectedError"); +const { DBManager } = require("../../db"); +const { Product, Brand } = require("../../features/Product"); + +exports.post_product_brand = async (req, res) => { + const id = req.id; + const returnToken = req.returnToken; + const { brand_name_list } = req.body; + + //main logic------------------------------------------------------------------------------------------------------------------// + const db = new DBManager(); + await db.openTransaction(); + try { + const list_of_brand = await Brand.checkBrandNameList(brand_name_list, db); + + await db.commitTransaction(); + + return res.status(200).send(Response.create(true, "00", "브랜드 id를 성공적으로 불러왔습니다", list_of_brand, returnToken)); + } catch (err) { + await db.rollbackTransaction(); + console.error(`🚨 error -> ⚡️ post_product_brand : 🐞${err}`); + if (err.status) { + return res.status(err.status).send(Response.create(false, err.detail_code, err.message)); + } + return res.status(500).send(Response.create(false, "00", "서버 에러")); + } +}; diff --git a/tikkle_product/post_product_enrollment/index.js b/tikkle_product/post_product_enrollment/index.js new file mode 100644 index 0000000..8196b38 --- /dev/null +++ b/tikkle_product/post_product_enrollment/index.js @@ -0,0 +1,53 @@ +const { Tikkling } = require("../../features/Tikkling"); +const { Response } = require("../../features/Response"); +const { User } = require("../../features/User"); +const { ExpectedError } = require("../../features/ExpectedError"); +const { DBManager } = require("../../db"); +const { Product, Brand } = require("../../features/Product"); + +exports.post_product_enrollment = async (req, res) => { + const id = req.id; + const returnToken = req.returnToken; + const { product_list } = req.body; + //main logic------------------------------------------------------------------------------------------------------------------// + const db = new DBManager(); + await db.openTransaction(); + try { + //모든 상품 등록 + let flag; + let product_obj_list = await Promise.all( + product_list.map(async (product) => { + const is_uploaded = await Product.checkIsUploaded(product.name, db); + //이미 업로드 된 것은 Null로 반환 + if (is_uploaded) { + return null; + } + // 업로드 된 적이 없으면 새로 등록 + const new_product = await Product.createUnregisteredProduct(product, db); + return new_product; + }) + ); + + //이미 등록되어 null값으로 반환된 상품들 제거 + product_obj_list = product_obj_list.filter((product) => product !== null); + // const product_obj_list = await Product.createProductList(product_list, db); + // console.log(product_obj_list); + //옵션들 등록 + for (const product_obj of product_obj_list) { + await product_obj.product_options.formatOptionList(); + await product_obj.product_options.formatCombinationList(); + await product_obj.product_options.uploadProductOptions(); + await product_obj.product_options.uploadProductOptionCombinations(); + } + await db.commitTransaction(); + + return res.status(200).send(Response.create(true, "00", "상품을 성공적으로 추가하였습니다.", null, returnToken)); + } catch (err) { + await db.rollbackTransaction(); + console.error(`🚨 error -> ⚡️ post_product_enrollment : 🐞${err}`); + if (err.status) { + return res.status(err.status).send(Response.create(false, err.detail_code, err.message)); + } + return res.status(500).send(Response.create(false, "00", "서버 에러")); + } +}; diff --git a/tikkle_product/post_product_id/index.js b/tikkle_product/post_product_id/index.js new file mode 100644 index 0000000..87fb144 --- /dev/null +++ b/tikkle_product/post_product_id/index.js @@ -0,0 +1,61 @@ +const { queryDatabase } = require("db.js"); + +exports.post_product_id = async (req, res) => { + const id = req.id; + const returnToken = req.returnToken; + const { p_name } = req.body; + + //main logic------------------------------------------------------------------------------------------------------------------// + //-------- check DB --------------------------------------------------------------------------------------// + + let sqlResult; + + try { + const rows = await queryDatabase( + // 고시정보 데이터 추가하기(인덱스) + ` SELECT p.id + FROM products p + WHERE p.name = ? ; + `, + [p_name] + ); + sqlResult = rows; + //console.log("SQL result : ", sqlResult); + } catch (err) { + console.log("post_product_id 에서 에러가 발생했습니다.", err); + const return_body = { + success: false, + detail_code: "00", + data: err, + message: "SQL error 1 ", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + // check data is one + if (sqlResult.length !== 1) { + console.log(" post_product_id 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "00", + data: sqlResult, + p_name: p_name, + message: "SQL error 2 ", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + const ret = sqlResult[0]; + + const return_body = { + success: true, + data: ret, + detail_code: "00", + p_name: p_name, + message: "success get product info", + returnToken: returnToken, + }; + return res.status(200).send(return_body); +}; diff --git a/tikkle_product/post_product_images/index.js b/tikkle_product/post_product_images/index.js new file mode 100644 index 0000000..db1a8ac --- /dev/null +++ b/tikkle_product/post_product_images/index.js @@ -0,0 +1,47 @@ +const { queryDatabase } = require("db.js"); + +exports.post_product_images = async (req, res) => { + const body = req.body; + const id = req.id; + const returnToken = req.returnToken; + + const productId = body.productId; + + //-------- check DB --------------------------------------------------------------------------------------// + + let sqlResult; + + try { + const rows = await queryDatabase("select * from product_images where product_id = ?", [productId]); + sqlResult = rows; + //console.log("SQL result : ", sqlResult); + } catch (err) { + console.error(`🚨 error -> ⚡️ post_product_images : 🐞${err}`); + const return_body = { + success: false, + detail_code: "00", + message: "SQL error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + const urls = []; + + for (let i = 0; i < sqlResult.length; i++) { + urls.push(sqlResult[i].product_picture); + } + + //console.log("urls : ", urls); + + //-------- return result --------------------------------------------------------------------------------------// + + const return_body = { + success: true, + data: urls, + detail_code: "00", + message: "success get product images", + returnToken: returnToken, + }; + return res.status(200).send(return_body); +}; diff --git a/tikkle_product/post_product_info/index.js b/tikkle_product/post_product_info/index.js new file mode 100644 index 0000000..ccbd4f7 --- /dev/null +++ b/tikkle_product/post_product_info/index.js @@ -0,0 +1,191 @@ +const { queryDatabase } = require("db.js"); + +exports.post_product_info = async (req, res) => { + const body = req.body; + const id = req.id; + const returnToken = req.returnToken; + + const productId = body.productId; + + //-------- check DB --------------------------------------------------------------------------------------// + + let sqlResult; + + try { + const rows = await queryDatabase( + // 고시정보 데이터 추가하기(인덱스) + ` SELECT p.*, b.brand_name, pc.name AS cat_name, uwl.product_id AS wishlisted + FROM products p + INNER JOIN brands b ON p.brand_id = b.id + INNER JOIN product_category pc ON p.category_id = pc.id + LEFT JOIN user_wish_list uwl ON p.id = uwl.product_id AND uwl.user_id = ? + WHERE p.id = ? ; + `, + [id, productId] + ); + sqlResult = rows; + //console.log("SQL result : ", sqlResult); + } catch (err) { + console.log("post_product_info 에서 에러가 발생했습니다.", err); + const return_body = { + success: false, + detail_code: "00", + message: "SQL error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + // check data is one + if (sqlResult.length !== 1) { + console.log(" post_product_info 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "00", + message: "SQL error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + const retData = sqlResult[0]; + + //-------- check DB for product info --------------------------------------------------------------------------// + let sqlResult_2; + + try { + // //고시정보 인덱스로 데이터 가져오기 + const category = retData.noti_id; + // const category = 25; + let table = ""; + switch (category) { + case 3: + table = "notice_bags"; + break; + case 4: + table = "notice_fashionaccessories"; + break; + case 5: + table = "notice_beddingscurtains"; + break; + case 6: + table = "notice_furniture"; + break; + case 7: + table = "notice_video_appliances"; + break; + case 8: + table = "notice_homeappliances"; + break; + case 9: + table = "notice_seasonalappliances"; + break; + case 10: + table = "notice_officeequipment"; + break; + case 11: + table = "notice_opticalequipment"; + break; + case 12: + table = "notice_smallelectronics"; + break; + case 13: + table = "notice_portablecommunicationdevices"; + break; + case 17: + table = "notice_kitchenware"; + break; + case 18: + table = "notice_cosmetics"; + break; + case 19: + table = "notice_jewelry_watches"; + break; + case 24: + table = "notice_musical_instruments"; + break; + case 25: + table = "notice_sports_equipment"; + break; + default: + break; + } + + const columns = await queryDatabase(`SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = ? AND COLUMN_NAME != ? `, [table, "product_id"]); + + // Fetch data from the table + const rows = await queryDatabase( + ` + SELECT * + FROM ${table} AS t + WHERE t.product_id = ?`, + [productId] + ); + + const commentsQuery = await queryDatabase( + `SELECT COLUMN_NAME, COLUMN_COMMENT + FROM INFORMATION_SCHEMA.COLUMNS + WHERE TABLE_NAME = ? AND COLUMN_NAME != ?`, + [table, "product_id"] + ); + + // Create a map of column comments + const columnCommentsMap = {}; + commentsQuery.forEach((commentRow) => { + const columnName = commentRow.COLUMN_NAME; + const columnComment = commentRow.COLUMN_COMMENT; + columnCommentsMap[columnName] = columnComment; + }); + + // Create an array of objects with {key: value} format using comments as keys + const data = rows.map((row) => { + const rowData = {}; + columns.forEach((column) => { + const columnName = column.COLUMN_NAME; + const columnComment = columnCommentsMap[columnName]; // Get the comment for the column + rowData[columnComment] = row[columnName]; + }); + return rowData; + }); + + sqlResult_2 = data; + // sqlResult_2 = rows; + //console.log("SQL result : ", sqlResult_2); + } catch (err) { + console.log("post_product_info 에서 에러가 발생했습니다.", err); + const return_body = { + success: false, + detail_code: "00", + message: "SQL error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + // check data is one + if (sqlResult_2.length !== 1) { + console.log(" post_product_info 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "00", + message: "SQL error: NO DATA", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + const retData_2 = sqlResult_2[0]; + + //-------- return result --------------------------------------------------------------------------------------// + + const return_body = { + success: true, + data: retData, + //FIXME: 예쁘게... + data_2: retData_2, + detail_code: "00", + message: "success get product info", + returnToken: returnToken, + }; + return res.status(200).send(return_body); +}; diff --git a/tikkle_product/post_product_inputInfo/index.js b/tikkle_product/post_product_inputInfo/index.js new file mode 100644 index 0000000..ce19f62 --- /dev/null +++ b/tikkle_product/post_product_inputInfo/index.js @@ -0,0 +1,125 @@ +const { queryDatabase } = require("db.js"); + +exports.post_product_inputInfo = async (req, res) => { + const id = req.id; + const returnToken = req.returnToken; + const { data, table_id } = req.body; + + let table = ""; + switch (table_id) { + case 3: + table = "notice_bags"; + break; + case 4: + table = "notice_fashionaccessories"; + break; + case 5: + table = "notice_beddingscurtains"; + break; + case 6: + table = "notice_furniture"; + break; + case 7: + table = "notice_video_appliances"; + break; + case 8: + table = "notice_homeappliances"; + break; + case 9: + table = "notice_seasonalappliances"; + break; + case 10: + table = "notice_officeequipment"; + break; + case 11: + table = "notice_opticalequipment"; + break; + case 12: + table = "notice_smallelectronics"; + break; + case 13: + table = "notice_portablecommunicationdevices"; + break; + case 17: + table = "notice_kitchenware"; + break; + case 18: + table = "notice_cosmetics"; + break; + case 19: + table = "notice_jewelry_watches"; + break; + case 24: + table = "notice_musical_instruments"; + break; + case 25: + table = "notice_sports_equipment"; + break; + default: + break; + } + //main logic------------------------------------------------------------------------------------------------------------------// + //-------- check DB --------------------------------------------------------------------------------------// + + let sqlResult; + + try { + const columns = Object.keys(data); + const values = Object.values(data); + + const placeholders = Array.from({ length: columns.length }, () => "?").join(", "); + const query = `INSERT INTO ${table} (${columns.join(", ")}) VALUES (${placeholders})`; + + const rows = await queryDatabase(query, values); + sqlResult = rows; + //console.log("SQL result : ", sqlResult); + } catch (err) { + console.log("post_product_inputInfo 에서 에러가 발생했습니다.", err); + const return_body = { + success: false, + detail_code: "00", + message: "SQL error 1 ", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + const ret = sqlResult; + + //-------- check DB --------------------------------------------------------------------------------------// + + let sqlResult_2; + + try { + const rows = await queryDatabase( + ` + UPDATE products + SET noti_id = ? + WHERE id = ?; + `, + [table_id, data.product_id] + ); + sqlResult_2 = rows; + //console.log("SQL result : ", sqlResult_2); + } catch (err) { + console.log("post_product_inputInfo 에서 에러가 발생했습니다.", err); + const return_body = { + success: false, + detail_code: "00", + message: "SQL error 22 ", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + const ret_2 = sqlResult_2; + + const return_body = { + success: true, + data: ret_2, + detail_code: "00", + message: "success get product info", + returnToken: returnToken, + }; + return res.status(200).send(return_body); +}; diff --git a/tikkle_product/post_product_list/index.js b/tikkle_product/post_product_list/index.js new file mode 100644 index 0000000..65277b7 --- /dev/null +++ b/tikkle_product/post_product_list/index.js @@ -0,0 +1,217 @@ +const { queryDatabase } = require("db.js"); + +exports.post_product_list = async (req, res) => { + const body = req.body; + const id = req.id; + const returnToken = req.returnToken; + + let category_id = body.category_id; + let priceMin = body.priceMin; + let priceMax = body.priceMax; + const sortAttribute = body.sortAttribute; + const sortWay = body.sortWay; + let search = body.search; + const getNum = body.getNum; + + //-------- check input --------------------------------------------------------------------------------------// + + //check category_id + if (category_id == null || typeof category_id !== "number" || !Number.isInteger(category_id) || category_id > 20) { + // console.log("post_product_list 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "01", + message: "category_id value is null or invalid", + returnToken: null, + }; + return res.status(400).send(return_body); + } + //check priceMin, priceMax + if (!priceMin) { + priceMin = 0; + } + if (!priceMax) { + priceMax = 9999999999; + } + + if ( + typeof priceMin !== "number" || + typeof priceMax !== "number" || + !Number.isInteger(priceMin) || + !Number.isInteger(priceMax) || + priceMin < 0 || + priceMax < priceMin || + priceMax > 9999999999 || + priceMax < 0 + ) { + // console.log("post_product_list 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "02", + message: "priceMin or priceMax value is null or invalid", + returnToken: null, + }; + return res.status(400).send(return_body); + } + + //check sortAttribute + if (!sortAttribute || typeof sortAttribute !== "string" || sortAttribute.length > 30) { + //return invalid + // console.log(" post_product_list 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "03", + message: "sortAttribute value is null or invalid", + returnToken: null, + }; + return res.status(400).send(return_body); + } + + if (sortAttribute != "sales_volume" && sortAttribute != "price" && sortAttribute != "views" && sortAttribute != "wishlist_count") { + //return invalid + // console.log("post_product_list 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "03", + message: "sortAttribute value is null or invalid", + returnToken: null, + }; + return res.status(400).send(return_body); + } + + //check sortWay + if (!sortWay || typeof sortWay !== "string" || (sortWay !== "ASC" && sortWay !== "DESC")) { + //return invalid + // console.log("post_product_list 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "04", + message: "sortWay value is null or invalid", + returnToken: null, + }; + return res.status(400).send(return_body); + } + + //check search + if (search && (typeof search !== "string" || search.length > 100)) { + //return invalid + // console.log("post_product_list 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "05", + message: "search value is invalid", + returnToken: null, + }; + return res.status(400).send(return_body); + } + + //check getNum + if (!getNum || typeof getNum !== "number" || !Number.isInteger(getNum) || getNum < 0) { + // console.log("post_product_list 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "06", + message: "getNum value is null or invalid", + returnToken: null, + }; + return res.status(400).send(return_body); + } + + //-------- check DB --------------------------------------------------------------------------------------// + + let sqlResult; + + try { + let rows; + if (!search) { + if (category_id == 0) { + rows = await queryDatabase( + ` SELECT p.*, b.brand_name, pc.name AS cat_name, uwl.product_id AS wishlisted + FROM products p + INNER JOIN brands b ON p.brand_id = b.id + INNER JOIN product_category pc ON p.category_id = pc.id + LEFT JOIN user_wish_list uwl ON p.id = uwl.product_id AND uwl.user_id = ? + WHERE p.price BETWEEN ? AND ? + AND p.is_deleted = 0 + ORDER BY ${sortAttribute} ${sortWay} + LIMIT 20 OFFSET ?; + `, + [id, priceMin, priceMax, (getNum - 1) * 20] + ); + } else { + rows = await queryDatabase( + ` SELECT p.*, b.brand_name, pc.name AS cat_name, uwl.product_id AS wishlisted + FROM products p + INNER JOIN brands b ON p.brand_id = b.id + INNER JOIN product_category pc ON p.category_id = pc.id + LEFT JOIN user_wish_list uwl ON p.id = uwl.product_id AND uwl.user_id = ? + WHERE p.category_id = ? + AND p.price BETWEEN ? AND ? + AND p.is_deleted = 0 + ORDER BY ${sortAttribute} ${sortWay} + LIMIT 20 OFFSET ?; + `, + [id, category_id, priceMin, priceMax, (getNum - 1) * 20] + ); + } + } else { + if (category_id == 0) { + rows = await queryDatabase( + ` SELECT p.*, b.brand_name, pc.name AS cat_name, uwl.product_id AS wishlisted + FROM products p + INNER JOIN brands b ON p.brand_id = b.id + INNER JOIN product_category pc ON p.category_id = pc.id + LEFT JOIN user_wish_list uwl ON p.id = uwl.product_id AND uwl.user_id = ? + WHERE p.price BETWEEN ? AND ? + AND p.is_deleted = 0 + AND (p.name LIKE '%${search}%' OR description LIKE '%${search}%') + ORDER BY ${sortAttribute} ${sortWay} + LIMIT 20 OFFSET ?; + `, + [id, priceMin, priceMax, (getNum - 1) * 20] + ); + } else { + rows = await queryDatabase( + ` SELECT p.*, b.brand_name, pc.name AS cat_name, uwl.product_id AS wishlisted + FROM products p + INNER JOIN brands b ON p.brand_id = b.id + INNER JOIN product_category pc ON p.category_id = pc.id + LEFT JOIN user_wish_list uwl ON p.id = uwl.product_id AND uwl.user_id = ? + WHERE p.category_id = ? + AND p.price BETWEEN ? AND ? + AND p.is_deleted = 0 + AND (p.name LIKE '%${search}%' OR description LIKE '%${search}%') + ORDER BY ${sortAttribute} ${sortWay} + LIMIT 20 OFFSET ?; + `, + [id, category_id, priceMin, priceMax, (getNum - 1) * 20] + ); + } + } + + sqlResult = rows; + //console.log("SQL result : ", sqlResult); + } catch (err) { + console.error(`🚨 error -> ⚡️ post_product_info : 🐞${err}`); + const return_body = { + success: false, + detail_code: "00", + message: "SQL error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + const retData = sqlResult; + + //-------- return result --------------------------------------------------------------------------------------// + + const return_body = { + success: true, + data: retData, + detail_code: "00", + message: "success get product list", + returnToken: returnToken, + }; + return res.status(200).send(return_body); +}; diff --git a/tikkle_product/put_product_viewIncrease/index.js b/tikkle_product/put_product_viewIncrease/index.js new file mode 100644 index 0000000..5078946 --- /dev/null +++ b/tikkle_product/put_product_viewIncrease/index.js @@ -0,0 +1,54 @@ +const { queryDatabase } = require("db.js"); + +exports.put_product_viewIncrease = async (req, res) => { + const body = req.body; + const id = req.id; + const returnToken = req.returnToken; + + const productId = body.productId; + + //-------- check input --------------------------------------------------------------------------------------// + + //check productId + if (!productId || typeof productId !== "number" || !Number.isInteger(productId)) { + // console.log("put_product_viewIncrease 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "00", + message: "productId value is null or invalid", + returnToken: null, + }; + return res.status(400).send(return_body); + } + + //-------- increase view --------------------------------------------------------------------------------------// + + let sqlResult; + + try { + const rows = await queryDatabase("UPDATE products SET views = views + ? WHERE id = ?", [1, productId]); + + sqlResult = rows; + //console.log("SQL result : ", sqlResult); + } catch (err) { + console.error(`🚨 error -> ⚡️ put_product_viewIncrease : 🐞${err}`); + const return_body = { + success: false, + detail_code: "00", + message: "SQL error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + //-------- return result --------------------------------------------------------------------------------------// + + const return_body = { + success: true, + data: sqlResult, + detail_code: "00", + message: "success increase product view", + returnToken: returnToken, + }; + return res.status(200).send(return_body); +}; diff --git a/tikkle_tikkling/.DS_Store b/tikkle_tikkling/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..3eafac487ded0813dbf2232acf9cbf50e3d8575d GIT binary patch literal 10244 zcmeI1zityj5XR?7fFnV|BuEK@;-nx!K|xA7CzyhYB2ZBn{D)v-`>Z%dq_M6+JOL$C zREQTqLP#knD0u)R3Q8&$6cmVWc2~Y#`|RAEBSECuXm6bJedC?q?XGXeMC5JuYU@M+ z5&7tB3ukdiX#76+v3A0oxd!V&Pqar3+QDBFR+ya$t!9rM|sJKmEdg-+lUdBafHb5qRl5v7=GD z$N4Ed5*aML!RS+{?6`j~{#m=(S8=CO#<6Boy72`VC|#ruh17NKcmp*Xea9=*qkU?j z$JLy=d(Y3j%jd<8|LxD{;LeVUKgW1lVa#JTPc9#I|1Tu);fj{#Q^ks?(<9Isp|bE2 zR8nhg7T>RbIQMm5vB;p03FOfy#C>^c+#Gcky+O}#tkFHZ(zU)34yRVYA-6A^%dZFD z`nN*GWd?sSr=#$fz-@IZw=QV$?m2NaEpx3jvk#loU@%-uIsC+YX7S^42@n!pvbglH z-_)^k%4TnkXOCW2CA_u-dQe+7I}Ds3Ls!H?Hp^q!Mi9nX~P>V$X;Q{q)?#+?a;SBUgbjUD6a z-Qm8PLKjDuMd!v9V2F4Un0z1kTQ{VR8=3zpoyv}F?&I*eDaGg6b2ppPjZe)}j!~Kr z5CTF#2pnGmb9(3j*Z*%%{{8>>1}GyJ0z%+W0^WRStF(#BOl^Hkz_s=O{UJIxzAn;M zNpMi*cvw}A$3I+-=h`A)dxI@Eye=9WX^S&x|KP`f-1UTn=i$sbxBK)j`9Ep`lK-d9 L;@#PkH~;?&ulVjW literal 0 HcmV?d00001 diff --git a/tikkle_tikkling/get_tikkling_deliveryinfo/index.js b/tikkle_tikkling/get_tikkling_deliveryinfo/index.js new file mode 100644 index 0000000..2158831 --- /dev/null +++ b/tikkle_tikkling/get_tikkling_deliveryinfo/index.js @@ -0,0 +1,35 @@ +const { Response } = require("../../features/Response"); +const { DBManager } = require("../../db"); +const { Delivery } = require("../../features/Delivery"); +const { ExpectedError } = require("../../features/ExpectedError"); + +exports.get_tikkling_deliveryinfo = async (req, res) => { + const id = req.id; + const returnToken = req.returnToken; + const { tikkling_id } = req.params; + //main logic------------------------------------------------------------------------------------------------------------------// + const db = new DBManager(); + await db.openTransaction(); + try { + const delivery_info = new Delivery({ db: db }); + // api를 호출한 유저의 가장 최근 배송목록 확인 + if (Number(tikkling_id) === 0) { + await delivery_info.getRecentDeliveryInfoOfUser(id); + } + if (Number(tikkling_id) >= 1) { + await delivery_info.getDeliveryInfoByTikklingId(tikkling_id); + } + + const delivery_check_link = await delivery_info.createDeliveryCheckLink(); + await db.commitTransaction(); + + return res.status(200).send(Response.create(true, "00", "성공적으로 배송정보를 조회하였습니다.", { delivery_info: delivery_info.toJSON(), delivery_check_link }, returnToken)); + } catch (err) { + await db.rollbackTransaction(); + console.error(`🚨 error -> ⚡️ get_tikkling_deliveryinfo : 🐞${err}`); + if (err.status) { + return res.status(err.status).send(Response.create(false, err.detail_code, err.message)); + } + return res.status(500).send(Response.create(false, "00", "서버 에러")); + } +}; diff --git a/tikkle_tikkling/get_tikkling_friendinfo/index.js b/tikkle_tikkling/get_tikkling_friendinfo/index.js new file mode 100644 index 0000000..8939c6d --- /dev/null +++ b/tikkle_tikkling/get_tikkling_friendinfo/index.js @@ -0,0 +1,51 @@ +const { queryDatabase } = require("db.js"); + +exports.get_tikkling_friendinfo = async (req, res) => { + const body = req.body; + const id = req.id; + const returnToken = req.returnToken; + + //main logic------------------------------------------------------------------------------------------------------------------// + + try { + const rows = await queryDatabase( + `SELECT + atv.*, + u.id AS user_id, + u.name AS user_name, + u.birthday, + u.nick, + u.phone, + u.gender, + u.image AS friend_image, + u.address, + u.detail_address, + u.is_tikkling + FROM tikkling_detail_view atv + JOIN users u ON atv.user_id = u.id + WHERE atv.state_id = 1 and u.id IN ( + SELECT fr.friend_user_id + FROM friends_relation fr + WHERE fr.central_user_id = ? AND fr.relation_state_id IN (1, 2));`, + [id] + ); + + const return_body = { + success: true, + data: rows, + detail_code: "00", + message: "친구의 티클링 정보 조회 성공", + returnToken, + }; + return res.status(200).send(return_body); + } catch (err) { + console.error(`🚨 error -> ⚡️ post_tikkling_friendinfo : 🐞${err}`); + const return_body = { + success: false, + detail_code: "00", + message: "서버 에러", + returnToken: null, + }; + return res.status(500).send(return_body); + } +}; diff --git a/tikkle_tikkling/get_tikkling_info/index.js b/tikkle_tikkling/get_tikkling_info/index.js new file mode 100644 index 0000000..81ab899 --- /dev/null +++ b/tikkle_tikkling/get_tikkling_info/index.js @@ -0,0 +1,162 @@ +const { queryDatabase } = require("db.js"); + +exports.get_tikkling_info = async (req, res) => { + const body = req.body; + const id = req.id; + const returnToken = req.returnToken; + + //main logic------------------------------------------------------------------------------------------------------------------// + + try { + // 쿼리 스트링 파라미터에서 tikkling_id를 추출, 숫자인지 확인 + const tikkling_id = req.params ? req.params.tikkling_id : null; + + if (tikkling_id == 0) { + //tikkling_id 파라미터가 없을 경우 자신의 tikkling 정보를 DB에서 조회 + const query = `SELECT + u.id AS user_id, + u.name AS user_name, + a.tikkling_id, + a.funding_limit, + a.tikkle_quantity, + a.tikkle_count, + a.thumbnail_image, + a.brand_name, + a.product_name, + a.category_id, + a.type, + a.state_id, + a.option_combination_id, + pc.name AS category_name, + a.product_id AS product_id, + a.share_link + FROM tikkling_detail_view a + JOIN users u ON a.user_id = u.id + JOIN product_category pc ON a.category_id = pc.id + WHERE u.id = ? AND terminated_at IS NULL;`; + let rows = await queryDatabase(query, [id]); + if(rows.length == 0){ + return res.status(404).send({ + success: false, + detail_code: "00", + message: "티클링 정보가 없습니다.", + returnToken: null, + }); + } + const rows_of_selected_options = await queryDatabase( + `select * from option_combination_detail inner join product_option on option_combination_detail.option_id = product_option.id where option_combination_detail.combination_id = ?;`, + [rows[0].option_combination_id] + ); + + const selected_options = rows_of_selected_options.reduce((acc, cur) => { + acc[cur.category] = cur.option; + return acc; + }, {}); + rows[0]["selected_options"] = selected_options; + + if (rows.length == 0) { + return res.status(404).send({ + success: false, + detail_code: "00", + message: "티클링 정보가 없습니다.", + returnToken: null, + }); + } + + const return_body = { + success: true, + data: rows, + detail_code: "01", + message: "나의 티클링 정보 조회 성공", + returnToken, + }; + return res.status(200).send(return_body); + } else { + const parsedId = parseInt(tikkling_id, 10); + + if (isNaN(parsedId)) { + throw new Error("입력 오류: tikkling_id는 숫자여야 합니다."); + } + + // tikkling_id와 일치하는 tikkling의 정보를 DB에서 조회(내가 아닌 유저, state_id = 1만 조회 가능) + const query = `SELECT + u.id AS user_id, + u.name AS user_name, + a.tikkling_id, + a.funding_limit, + a.tikkle_quantity, + a.tikkle_count, + a.thumbnail_image, + a.brand_name, + a.product_name, + a.category_id, + a.type, + a.state_id, + a.option_combination_id, + pc.name AS category_name, + a.product_id AS product_id, + a.share_link + FROM tikkling_detail_view a + JOIN users u ON a.user_id = u.id + JOIN product_category pc ON a.category_id = pc.id + WHERE a.tikkling_id = ?; + `; + + let rows = await queryDatabase(query, [parsedId]); + if(rows.length == 0){ + return res.status(404).send({ + success: false, + detail_code: "00", + message: "티클링 정보가 없습니다.", + returnToken: null, + }); + } + const rows_of_selected_options = await queryDatabase( + `select * from option_combination_detail inner join product_option on option_combination_detail.option_id = product_option.id where option_combination_detail.combination_id = ?;`, + [rows[0].option_combination_id] + ); + + const selected_options = rows_of_selected_options.reduce((acc, cur) => { + acc[cur.category] = cur.option; + return acc; + }, {}); + rows[0]["selected_options"] = selected_options; + + if (rows.length == 0) { + return res.status(404).send({ + success: false, + detail_code: "00", + message: "티클링 정보가 없습니다.", + returnToken: null, + }); + } + const return_body = { + success: true, + data: rows, + detail_code: "02", + message: `tikkling_id = ${tikkling_id}의 티클링 정보 조회 성공`, + returnToken, + }; + return res.status(200).send(return_body); + } + } catch (error) { + if (error.message === "입력 오류: tikkling_id는 숫자여야 합니다.") { + const return_body = { + success: false, + detail_code: "00", + message: "tikkling_id는 숫자여야 합니다.", + returnToken, + }; + return res.status(400).send(return_body); + } else { + console.error(`🚨 error -> ⚡️ get_tikkling_info : 🐞${error}`); + const return_body = { + success: false, + detail_code: "00", + message: "서버 오류", + returnToken, + }; + return res.status(500).send(return_body); + } + } +}; diff --git a/tikkle_tikkling/get_tikkling_refundinfo/index.js b/tikkle_tikkling/get_tikkling_refundinfo/index.js new file mode 100644 index 0000000..ddfd125 --- /dev/null +++ b/tikkle_tikkling/get_tikkling_refundinfo/index.js @@ -0,0 +1,42 @@ +const { Response } = require("../../features/Response"); +const { DBManager } = require("../../db"); +const { Delivery } = require("../../features/Delivery"); +const { Refund } = require("../../features/Refund"); +const { ExpectedError } = require("../../features/ExpectedError"); + +exports.get_tikkling_refundinfo = async (req, res) => { + const id = req.id; + const returnToken = req.returnToken; + const { tikkling_id } = req.params; + //main logic------------------------------------------------------------------------------------------------------------------// + const db = new DBManager(); + await db.openTransaction(); + try { + const refund = new Refund({ db: db, tikkling_id: tikkling_id }); + + // api를 호출한 유저의 가장 최근 배송목록 확인 + if (Number(tikkling_id) <= 0) { + throw new ExpectedError({ + status: 400, + detail_code: "01", + message: "잘못된 요청입니다.", + }); + } + + if (Number(tikkling_id) >= 1) { + await refund.loadDataByTikklingId(); + } + await db.commitTransaction(); + //TODO: 이부분 내장함수화 + refund.db = null; + return res.status(200).send(Response.create(true, "00", "성공적으로 환급정보를 조회하였습니다.", {refund:refund}, returnToken)); + } catch (err) { + console.error(`🚨 error -> ⚡️ get_tikkling_refundinfo : 🐞${err}`); + + await db.rollbackTransaction(); + if (err.status) { + return res.status(err.status).send(Response.create(false, err.detail_code, err.message)); + } + return res.status(500).send(Response.create(false, "00", "서버 에러")); + } +}; diff --git a/tikkle_tikkling/post_tikkilng_buymytikkle/index.js b/tikkle_tikkling/post_tikkilng_buymytikkle/index.js new file mode 100644 index 0000000..b23da96 --- /dev/null +++ b/tikkle_tikkling/post_tikkilng_buymytikkle/index.js @@ -0,0 +1,71 @@ +const { queryDatabase } = require("db.js"); +const { Tikkling } = require("../../features/Tikkling"); +const { Tikkle } = require("../../features/Tikkle"); +const { Response } = require("../../features/Response"); +const { ExpectedError } = require("../../features/ExpectedError"); +const { DBManager } = require("../../db"); +//남은 티클 개수만 충족되면 티클 줄 수 있음 +//TODO: 결제 실패 api +exports.post_tikkling_buymytikkle = async (req, res) => { + const { body, id, returnToken } = req; + const { merchant_uid, imp_uid, status } = body; + //main logic------------------------------------------------------------------------------------------------------------------// + + const db = new DBManager(); + await db.openTransaction(); + + try { + //결제정보 가져오기 + const tikkle_info = await Tikkle.getTikkleByMerchantUid({ + merchant_uid, + db + }); + //payment 객체 생성 + const tikkle = new Tikkle({...tikkle_info, db}); + //DB상의 결제정보와 비교 + tikkle.compareStoredTikkleData({ user_id: id }); + //줄 수 있는 상태인지 확인 + const tikkling = new Tikkling({ user_id: id , db}); + //티클링 정보 가져오기 + await tikkling.loadActiveTikklingViewByUserId(); + //요청 정보 유효성 검사 + tikkling.validateBuyMyTikkleRequest(); + //나의 남은 티클 구매 + await tikkling.buyMyTikkle({ merchant_uid }); + //결제 완료 처리 + await tikkle.completeTikklePayment(); + const buy_tikkle_quantity = + tikkling.tikkle_quantity - tikkling.tikkle_count; + // 트랜잭션 커밋 + await db.commitTransaction(); + return res + .status(200) + .send( + Response.create( + true, + "00", + "나의 모든 티클 구매 성공", + { buy_tikkle_quantity }, + returnToken + ) + ); + } catch (err) { + + const tikkle_info = await Tikkle.getTikkleByMerchantUid({merchant_uid, db}); + const tikkle = new Tikkle(tikkle_info); + const port_one_token = await Tikkle.getPortOneApiToken(); + //포트원 환불 api 호출 + await tikkle.callPortOneCancelPaymentAPI({reason: "buymytikkle 처리중 에러", port_one_token}); + //트랜잭션 롤백 + await db.rollbackTransaction(); + + console.error(`🚨 error -> ⚡️ post_tikkling_buymytikkle : 🐞 ${err}`); + if (err instanceof ExpectedError) { + return res + .status(err.status) + .send(Response.create(false, err.detail_code, err.message)); + } + return res.status(500).send(Response.create(false, "00", "서버 에러")); + } + }; + diff --git a/tikkle_tikkling/post_tikkling_create/index.js b/tikkle_tikkling/post_tikkling_create/index.js new file mode 100644 index 0000000..13a6d5e --- /dev/null +++ b/tikkle_tikkling/post_tikkling_create/index.js @@ -0,0 +1,64 @@ +const { Tikkling } = require("../../features/Tikkling"); +const { Response } = require("../../features/Response"); +const { User } = require("../../features/User"); +const { ExpectedError } = require("../../features/ExpectedError"); +const { DBManager } = require("../../db"); +const { Product } = require("../../features/Product"); + +exports.post_tikkling_create = async (req, res) => { + const id = req.id; + const returnToken = req.returnToken; + const { funding_limit, tikkle_quantity, product_id, type, product_option } = req.body; + + //main logic------------------------------------------------------------------------------------------------------------------// + const db = new DBManager(); + await db.openTransaction(); + try { + const product = await Product.createById({ id: product_id, db }); + await product.loadProductOptions(); + await product.updateSelectedOption(product_option); + await product.loadSelectedProductOptionCombination(); + + const user = await User.createById({ id, db }); + const new_tikkling = new Tikkling({ user_id: id, funding_limit, tikkle_quantity, product_id, type, option_combination_id: product.selected_option_combination.id, db }); + + //해당 상품에 대해서 lock + product.lockProduct(); + + //유효성 검사 + await Promise.all([ + //상품 옵션에 대한 유효성 검사 + product.validateProductOption(product_option), + //상품 수량에 대한 유효성 검사 + product.validateProductOptionCombination(), + //상품 가격에 대한 유효성 검사 + product.validateProductPrice(tikkle_quantity * 5000), + //티클링 요청에 대한 유효성 검사 -> 취소 + // new_tikkling.validateCreaetTikklingRequest(), + //유저에 대한 유효성 검사 + user.validatteUserForStartTikkling(), + ]); + let tikkling_id = null; + [tikkling_id] = await Promise.all([ + //티클링 생성 + new_tikkling.saveTikkling(user.name), + //상품의 재고를 감소시킴 + product.decreaseProductQuantity(), + //유저의 티클링 티켓을 감소시킴 + user.decreaseTikkleTicket(), + //위시리스트 제거 + user.deleteWishlist(product_id), + ]); + + await db.commitTransaction(); + + return res.status(200).send(Response.create(true, "00", "티클링 생성을 성공하였습니다.", { tikkling_id }, returnToken)); + } catch (err) { + await db.rollbackTransaction(); + console.error(`🚨 error -> ⚡️ post_tikkling_create : 🐞${err}`); + if (err.status) { + return res.status(err.status).send(Response.create(false, err.detail_code, err.message)); + } + return res.status(500).send(Response.create(false, "00", "서버 에러")); + } +}; diff --git a/tikkle_tikkling/post_tikkling_receivedTikkle/index.js b/tikkle_tikkling/post_tikkling_receivedTikkle/index.js new file mode 100644 index 0000000..b02f298 --- /dev/null +++ b/tikkle_tikkling/post_tikkling_receivedTikkle/index.js @@ -0,0 +1,50 @@ +const { queryDatabase } = require("db.js"); + +exports.post_tikkling_receivedTikkle = async (req, res) => { + const body = req.body; + const id = req.id; + const returnToken = req.returnToken; + + //main logic------------------------------------------------------------------------------------------------------------------// + + try { + const tikkling_id = req.body ? req.body.tikkling_id : null; + const parsedId = parseInt(tikkling_id, 10); + if (isNaN(parsedId)) { + const return_body = { + success: false, + detail_code: "00", + message: "잘못된 요청, tikkling_id는 숫자여야 합니다.", + returnToken: null, + }; + return res.status(400).send(return_body); + } + const rows = await queryDatabase( + `SELECT sending_tikkle.*, + users.id, + users.NAME, + users.image + FROM sending_tikkle + INNER JOIN users ON sending_tikkle.user_id = users.id + WHERE sending_tikkle.tikkling_id = ? AND sending_tikkle.state_id in (1, 2, 3, 4); `, + [body.tikkling_id] + ); + const return_body = { + success: true, + data: rows, + detail_code: "00", + message: "특정 티클링의 받은 티클 정보 조회 성공", + returnToken, + }; + return res.status(200).send(return_body); + } catch (err) { + console.error(`🚨 error -> ⚡️ post_tikkling_receivedTikkle : 🐞${err}`); + const return_body = { + success: false, + detail_code: "00", + returnToken: null, + message: "서버 에러", + }; + return res.status(500).send(return_body); + } +}; diff --git a/tikkle_tikkling/post_tikkling_sendmessage/index.js b/tikkle_tikkling/post_tikkling_sendmessage/index.js new file mode 100644 index 0000000..160b60f --- /dev/null +++ b/tikkle_tikkling/post_tikkling_sendmessage/index.js @@ -0,0 +1,124 @@ +const { queryDatabase, queryDatabase_multi } = require("db.js"); +const { Response } = require("../../features/Response"); +const { ExpectedError } = require("../../features/ExpectedError"); +const { Tikkling } = require("../../features/Tikkling"); +const { Tikkle } = require("../../features/Tikkle"); +const { DBManager } = require("../../db"); +const { User } = require("../../features/User"); +const { send } = require("process"); + +exports.post_tikkling_sendmessage = async (req, res) => { + const { body, returnToken } = req; + const { message, tikkling_id } = body; + let id = 28; + //main logic------------------------------------------------------------------------------------------------------------------// + const db = new DBManager(); + await db.openTransaction(); + let receive_user_id; + let send_user_id; + try { + //티클링 객체 생성 + const tikkling = new Tikkling({ id: tikkling_id, db }); + + //해당 티클링 락 + await tikkling.lockTikklingForInsertTikkle(); + + //티클링 정보 가져오기 + await tikkling.loadActiveTikklingViewByTikklingId(); + + //티클링 검증 + tikkling.validateSendMessageRequest({ sent_user_id:id }); + + //tikkle 객체 생성 + const tikkle = new Tikkle({ tikkling_id, user_id: id, message, quantity: 0, state_id: 7, db }); + + //티클 검증 + tikkle.validateSendMessageRequest(); + + // 메세지 전송 + await tikkle.sendMessage(); + + // 티켓 1개 지급 + await tikkle.increaseTikklingTicket(); + receive_user_id = tikkling.user_id; + send_user_id = tikkle.user_id; + await db.commitTransaction(); + + } catch (err) { + console.error(`🚨 error -> ⚡️ post_tikkling_sendmessage : 🐞${err}`); + const return_body = { + success: false, + detail_code: "00", + message: "서버 에러", + returnToken: null, + }; + return res.status(500).send(return_body); + } + //-------- send notification --------------------------------------------------------------------------------------// + // console.log("sned noti ", receive_user_id, tikkling_id, send_user_id); + try { + //보내는 사람 정보 + try { + const rows = await queryDatabase("select * from users where id = ?", [send_user_id]); + sqlResult = rows; + //console.log("SQL result : ", sqlResult); + } catch (err) { + console.log("post_notification_send 에서 에러가 발생했습니다.", err); + } + + // check data is one + if (sqlResult.length !== 1) { + console.log("post_notification_send 에서 에러가 발생했습니다.", err); + } + + const name = sqlResult[0].name; + + //DB에 알림 저장 + message = name + "님이 보낸 티클을 확인해보세요."; + if (send_user_id == receive_user_id) { + message = "직접 구매한 티클을 확인해보세요."; + } + title = "티클 선물 🎁"; + link = "link_for_5"; + deep_link = "tikkle://tikklingDetail/" + tikkling_id.toString(); + source_user_id = send_user_id; + + const notiDB = await queryDatabase( + `INSERT INTO notification + (user_id, message, is_deleted, is_read, notification_type_id, deep_link, link, meta_data, source_user_id) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, + [receive_user_id, message, 0, 0, 5, deep_link, link, null, source_user_id] + ); + // console.log("notiDB : ", notiDB); + + ////푸시 알림 + //resiver 1명 + let token_sqlResult; + + try { + const rows = await queryDatabase("select * from users where id = ?", [receive_user_id]); + token_sqlResult = rows; + //console.log("SQL result : ", token_sqlResult); + } catch (err) { + console.log("post_notification_send token확인 에서 에러가 발생했습니다.", err); + } + + // check data is one + if (token_sqlResult.length !== 1) { + console.log("post_notification_send token확인 에서 에러가 발생했습니다.", err); + } + + const device_token = token_sqlResult[0].device_token; + + //send notification + + await fcm_send(device_token, "알림", message, deep_link); + } catch {} + + return res.status(200).send(Response.create(true, "00", "메세지 데이터 저장 완료")); +}; + + + + +//알림보내기 로직 구현 요함 \ No newline at end of file diff --git a/tikkle_tikkling/post_tikkling_sendtikkle/index.js b/tikkle_tikkling/post_tikkling_sendtikkle/index.js new file mode 100644 index 0000000..a68b4d4 --- /dev/null +++ b/tikkle_tikkling/post_tikkling_sendtikkle/index.js @@ -0,0 +1,131 @@ +const { queryDatabase, queryDatabase_multi } = require("db.js"); +const { Response } = require("../../features/Response"); +const { ExpectedError } = require("../../features/ExpectedError"); +const { Tikkling } = require("../../features/Tikkling"); +const { Tikkle } = require("../../features/Tikkle"); +const { DBManager } = require("../../db"); + +exports.post_tikkling_sendtikkle = async (req, res) => { + const { body, id, returnToken } = req; + const { merchant_uid, imp_uid, status } = body; + //main logic------------------------------------------------------------------------------------------------------------------// + const db = new DBManager(); + await db.openTransaction(); + try { + //결제정보 가져오기 + const tikkle_info = await Tikkle.getTikkleByMerchantUid({ + merchant_uid, + db, + }); + //payment 객체 생성 + const tikkle = new Tikkle({ ...tikkle_info, db }); + //DB상의 결제정보와 비교 + tikkle.compareStoredTikkleData({ user_id: id }); + //tikkling 객체 생성 + const tikkling = new Tikkling({ user_id: id }); + //티클링 정보 가져오기 + await tikkling.loadActiveTikklingViewByUserId(); + //줄 수 있는 상태인지 확인 + const check_tikkling = await queryDatabase( + `SELECT t.id AS tikkling_id, t.user_id AS user_id, t.tikkle_quantity AS total_tikkle_quantity, IFNULL((SELECT SUM(s.quantity) FROM sending_tikkle s WHERE s.tikkling_id = ?), 0) AS received_tikkle_quantity, t.state_id + FROM tikkling t + WHERE t.id = ?;`, + [req.body.tikkling_id, req.body.tikkling_id] + ); + + if (check_tikkling.length == 0) { + const return_body = { + success: false, + detail_code: "00", + message: "잘못된 요청, 티클링을 찾을 수 없습니다.", + returnToken: null, + }; + return res.status(404).send(return_body); + } else if (check_tikkling[0].state_id != 1) { + const return_body = { + success: false, + detail_code: "01", + message: "티클을 보낼 수 없습니다. (티클을 줄 수 있는 상태가 아닙니다.)", + returnToken, + }; + return res.status(403).send(return_body); + } else if (check_tikkling[0].total_tikkle_quantity < check_tikkling[0].received_tikkle_quantity + req.body.quantity) { + const return_body = { + success: false, + detail_code: "02", + message: "티클을 보낼 수 없습니다. (줄 수 있는 티클링 조각 수 초과)", + returnToken, + }; + return res.status(403).send(return_body); + } + //줄 수 있는 상태라면 티클 전송 + const results = await queryDatabase_multi( + `CALL insert_sending_tikkle(?, ?, ?, ?, @success); + select @success as success;`, + [req.body.tikkling_id, id, req.body.tikkle_quantity, req.body.message] + ); + + let ticket_message = "자신의 티클 보내기에서는 티켓을 받을 수 없습니다."; + let detail_code = "01"; + //보내는 사람과 받는 사람이 다를 때 티켓 지급 및 알림 + if (check_tikkling[0].user_id != id) { + const [is_already_send, sender_info] = await queryDatabase_multi( + `SELECT id FROM sending_tikkle WHERE tikkling_id = ? AND user_id = ?; + SELECT name, image FROM users WHERE id = ?; + `, + + [req.body.tikkling_id, id, id] + ); + ticket_message = "이미 티켓을 지급 받았습니다."; + detail_code = "02"; + //티클을 처음 보낼때만 티켓을 1개 지급 + if (is_already_send.length == 1) { + await queryDatabase(`UPDATE users SET tikkling_ticket = tikkling_ticket + 1 WHERE id = ?;`, [id]); + ticket_message = "티클링 티켓 1개를 획득하였습니다."; + detail_code = "03"; + } + + /* 알림 보내기는 send notification 에서 */ + // //티클을 보낼 때마다 알림을 보냄 + // await queryDatabase( + // `INSERT INTO notification (user_id, notification_type_id, message, meta_data, source_user_id) VALUES (?, ?, ?, ?, ?);`, + + // [ + // check_tikkling[0].user_id, + // 5, + // `${sender_info[0].name}님이 보낸 티클을 확인해보세요.`, + // `${sender_info[0].image}`, + // id, + // ] + // ); + } + + const success = results[1][0].success; + if (success === 1) { + const return_body = { + success: true, + detail_code, + message: `티클을 성공적으로 보냈습니다. ${ticket_message}}`, + returnToken, + }; + return res.status(200).send(return_body); + } else { + const return_body = { + success: false, + detail_code: "03", + message: "티클전송중 타인이 먼저 티클전송을 하였습니다. 티클을 보낼 수 없습니다. (줄 수 있는 티클링 조각 수 초과 or 티클을 줄 수 있는 상태가 아닙니다.)", + returnToken, + }; + return res.status(403).send(return_body); + } + } catch (err) { + console.error(`🚨 error -> ⚡️ post_tikkling_sendtikkle : 🐞${err}`); + const return_body = { + success: false, + detail_code: "00", + message: "서버 에러", + returnToken: null, + }; + return res.status(500).send(return_body); + } +}; diff --git a/tikkle_tikkling/post_user_getTikklingDetail/index.js b/tikkle_tikkling/post_user_getTikklingDetail/index.js new file mode 100644 index 0000000..5dc77be --- /dev/null +++ b/tikkle_tikkling/post_user_getTikklingDetail/index.js @@ -0,0 +1,77 @@ +const { queryDatabase } = require("db.js"); + +exports.post_user_getTikklingDetail = async (req, res) => { + const body = req.body; + const id = req.id; + const returnToken = req.returnToken; + + const tikkling_id = body.tikkling_id; + + //-------- check DB --------------------------------------------------------------------------------------// + + let sqlResult; + + try { + const rows = await queryDatabase( + `SELECT tikkling.id AS tikkling_id, tikkling.user_id, tikkling.resolution_type AS resolution_type, tikkling.type AS tikkling_type, tikkling.funding_limit, tikkling.created_at, tikkling.tikkle_quantity, tikkling.terminated_at, tikkling.product_id, tikkling.terminated_at, + tikkling.state_id, tikkling_state.name AS state_name, + products.name AS product_name, products.price, products.description, products.views, + products.is_deleted, products.wishlist_count, products.thumbnail_image, brands.brand_name, + users.nick AS user_nick, users.image AS user_image, users.name AS user_name + FROM tikkling + INNER JOIN tikkling_state ON tikkling.state_id = tikkling_state.id + INNER JOIN products ON tikkling.product_id = products.id + INNER JOIN brands ON products.brand_id = brands.id + INNER JOIN users ON tikkling.user_id = users.id + WHERE tikkling.id = ? + ORDER BY tikkling.created_at DESC`, + [tikkling_id] + ); + sqlResult = rows; + //console.log("SQL result : ", sqlResult); + } catch (err) { + console.error(`🚨 error -> ⚡️ post_user_getTikklingDetail : 🐞${err}`); + const return_body = { + success: false, + detail_code: "00", + message: "SQL error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + if (sqlResult.length != 1) { + console.error(`🚨 error -> ⚡️ post_user_getTikklingDetail : 🐞 쿼리의 결과가 1개가 아닙니다.`); + const return_body = { + success: false, + detail_code: "00", + message: "SQL error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + const retData_temp = sqlResult; + + let is_mine; + if (retData_temp[0].user_id == id) { + is_mine = true; + } else { + is_mine = false; + } + + retData_temp[0] = { ...retData_temp[0], is_mine: is_mine }; + + const retData = retData_temp; + + //-------- return result --------------------------------------------------------------------------------------// + + const return_body = { + success: true, + data: retData, + detail_code: "00", + message: "success get Tiikkling detail", + returnToken: returnToken, + }; + return res.status(200).send(return_body); +}; diff --git a/tikkle_tikkling/put_tikkling_cancel/index.js b/tikkle_tikkling/put_tikkling_cancel/index.js new file mode 100644 index 0000000..8c88390 --- /dev/null +++ b/tikkle_tikkling/put_tikkling_cancel/index.js @@ -0,0 +1,48 @@ +const { queryDatabase, queryDatabase_multi } = require("db.js"); +const { Tikkling } = require("../../features/Tikkling"); +const { Response } = require("../../features/Response"); +const { User } = require("../../features/User"); +const { ExpectedError } = require("../../features/ExpectedError"); +const { DBManager } = require("../../db"); +const { OptionCombination } = require("../../features/Product"); + +exports.put_tikkling_cancel = async (req, res) => { + const id = req.id; + const returnToken = req.returnToken; + const { tikkling_id } = req.body; + + //main logic------------------------------------------------------------------------------------------------------------------// + //FIXME: 티클링취소 직전 티클링 조각이 도착한 경우가 생길 수 있음 조금 더 하나의 트랜잭션으로 처리해야할 필요성이 있음 + const db = new DBManager(); + await db.openTransaction(); + try { + //티클링 객체 생성 + const tikkling = new Tikkling({ id: tikkling_id, db }); + + //티클링 정보 로드 + await tikkling.loadActiveTikklingViewByTikklingId(); + + //도착한 티클링 조각이 있는지 확인 + tikkling.assertTikkleCountIsZero(); + + //option combination 객체 생성 + const option_combination = new OptionCombination({ id: tikkling.option_combination_id, db }); + + //user 객체 생성 + const user = new User({ id, db }); + + //티클링 취소, 티클링 티켓 환급, 상품 수량 복구 + await Promise.all([user.increaseTikkleTicket(), option_combination.increaseQuantity(), tikkling.cancelTikkling()]); + + await db.commitTransaction(); + + return res.status(200).send(Response.create(true, "00", "티클링 취소를 성공하였습니다.", returnToken)); + } catch (err) { + await db.rollbackTransaction(); + console.error(`🚨 error -> ⚡️ post_tikkling_create : 🐞${err}`); + if (err.status) { + return res.status(err.status).send(Response.create(false, err.detail_code, err.message)); + } + return res.status(500).send(Response.create(false, "00", "서버 에러")); + } +}; diff --git a/tikkle_tikkling/put_tikkling_deliveryconfirm/index.js b/tikkle_tikkling/put_tikkling_deliveryconfirm/index.js new file mode 100644 index 0000000..08fb83b --- /dev/null +++ b/tikkle_tikkling/put_tikkling_deliveryconfirm/index.js @@ -0,0 +1,34 @@ +const { queryDatabase, queryDatabase_multi } = require("db.js"); +const { Tikkling } = require("../../features/Tikkling"); +const { Response } = require("../../features/Response"); +const { User } = require("../../features/User"); +const { Delivery } = require("../../features/Delivery"); +const { ExpectedError } = require("../../features/ExpectedError"); +const { DBManager } = require("../../db"); +const { OptionCombination } = require("../../features/Product"); + +exports.put_tikkling_deliveryconfirm = async (req, res) => { + const id = req.id; + const returnToken = req.returnToken; + const { tikkling_id } = req.body; + + //main logic------------------------------------------------------------------------------------------------------------------// + const db = new DBManager(); + await db.openTransaction(); + try { + //배송정보 객체 생성 + const delivery_info = new Delivery({ tikkling_id, db: db }); + await delivery_info.loadDeliveryInfoByTikklingId(); + await delivery_info.updateDeliveryToConfirmed(); + await db.commitTransaction(); + + return res.status(200).send(Response.create(true, "00", "배송정보 수령처리를 성공하였습니다.", returnToken)); + } catch (err) { + await db.rollbackTransaction(); + console.error(`🚨 error -> ⚡️ put_tikkling_deliveryconfirm : 🐞${err}`); + if (err.status) { + return res.status(err.status).send(Response.create(false, err.detail_code, err.message)); + } + return res.status(500).send(Response.create(false, "00", "서버 에러")); + } +}; diff --git a/tikkle_tikkling/put_tikkling_end/index.js b/tikkle_tikkling/put_tikkling_end/index.js new file mode 100644 index 0000000..ade9879 --- /dev/null +++ b/tikkle_tikkling/put_tikkling_end/index.js @@ -0,0 +1,111 @@ +const { queryDatabase, queryDatabase_multi } = require("db.js"); +const { Tikkling } = require("../../features/Tikkling"); +const { Response } = require("../../features/Response"); +const { User } = require("../../features/User"); +const { ExpectedError } = require("../../features/ExpectedError"); +const { DBManager } = require("../../db"); +const { OptionCombination, Product } = require("../../features/Product"); +const { BankDetail } = require("../../features/BankDetail"); +const { Refund } = require("../../features/Refund"); +const { Delivery } = require("../../features/Delivery"); +const { InviteEventManager } = require("../../features/InviteEventManager"); +exports.put_tikkling_end = async (req, res) => { + const id = req.id; + const returnToken = req.returnToken; + const { tikkling_id, bank_code, account, zonecode, address, detail_address } = req.body; + const { type } = req.params; + + //main logic------------------------------------------------------------------------------------------------------------------// + //FIXME: 티클링취소 직전 티클링 조각이 도착한 경우가 생길 수 있음 조금 더 하나의 트랜잭션으로 처리해야할 필요성이 있음 + const db = new DBManager(); + await db.openTransaction(); + try { + //티클링 객체 생성 + const tikkling = new Tikkling({ id: tikkling_id, db }); + + //티클링 정보 로드 + await tikkling.loadActiveTikklingViewByTikklingId(); + await Promise.all([ + //나의 티클링인지 확인 + tikkling.assertTikklingisMine({ user_id: id }), + + //티클링이 종료되었는지 확인 + tikkling.assertTikklingIsStopped(), + + //도착한 티클링 조각이 있는지 확인 + tikkling.assertTikkleCountIsNotZero(), + ]); + if (type == "refund") { + //TODO: event끝난뒤 제거 + const invite_event_manager = new InviteEventManager({ db }); + await invite_event_manager.eventProcessBeforeTikklingRefund(tikkling_id); + + await tikkling.loadActiveTikklingViewByTikklingId(); + const bank_detail = new BankDetail({ bank_code, account, db }); + //input은행 데이터 검증 + await bank_detail.validateBankData(); + + //암호화 + await bank_detail.encryptAccount(); + + //모든 티클을 환급 상태로 변경 + await Promise.all([ + await tikkling.updateAllTikkleToRefund(), + + //티클링을 종료시키기 + await tikkling.updateTikklingToRefund(), + ]); + + // 재고를 복구하기 + const option_combination = new OptionCombination({ id: tikkling.option_combination_id, db }); + await option_combination.increaseQuantity(); + + //환불을 요청하기 + const refund = new Refund({ + tikkling_id: tikkling.id, + bank_code: bank_detail.bank_code, + account: bank_detail.account, + expected_refund_amount: tikkling.tikkle_count * 5000 * 0.9, + db, + }); + + await refund.saveRefund(); + + await db.commitTransaction(); + + return res.status(200).send(Response.create(true, "01", "티클링에 대해 성공적으로 환급을 요청하였습니다.", returnToken)); + } else if (type == "goods") { + const user = new User({ id, db, zonecode, address, detail_address }); + //주소 데이터 검증 + user.validateAddress(); + //모든 티클이 모여있는지 확인 + tikkling.assertAllTikkleIsArrived(); + + //판매량 증가 + const product = new Product({ id: tikkling.product_id, db }); + await product.increaseProductSalesVolume(); + + await Promise.all([ + //모든 티클을 사용된 상태로 변경 + tikkling.updateAllTikkleToUsed(), + //티클링을 종료시키기 + tikkling.updateTikklingToGoods(), + ]); + + //상품 발송 요청하기 + const delivery = new Delivery({ tikkling_id: tikkling.id, zonecode: user.zonecode, address: user.detail_address, detail_address: user.detail_address, state_id: 1, db }); + await delivery.saveDeliveryData(); + await db.commitTransaction(); + return res.status(200).send(Response.create(true, "02", "티클링을 성공적으로 종료하였습니다. 배송요청을 완료하였습니다.", returnToken)); + } + } catch (err) { + await db.rollbackTransaction(); + + console.error(`🚨 error -> ⚡️ post_tikkling_end : 🐞${err}`); + + if (err.status) { + return res.status(err.status).send(Response.create(false, err.detail_code, err.message)); + } + return res.status(500).send(Response.create(false, "00", "서버 에러")); + } +}; diff --git a/tikkle_tikkling/put_tikkling_stop/index.js b/tikkle_tikkling/put_tikkling_stop/index.js new file mode 100644 index 0000000..22acd64 --- /dev/null +++ b/tikkle_tikkling/put_tikkling_stop/index.js @@ -0,0 +1,66 @@ +const { queryDatabase } = require("db.js"); + +exports.put_tikkling_stop = async (req, res) => { + const body = req.body; + const id = req.id; + const returnToken = req.returnToken; + //main logic------------------------------------------------------------------------------------------------------------------// + try { + //티클링이 상태가 이미 변화했는지 확인 + const check_tikkling = await queryDatabase(`select * from tikkling_detail_view where tikkling_id = ?`, [req.body.tikkling_id]); + //티클링이 없는 경우 + if (check_tikkling.length == 0) { + console.log("비정상적 요청-put_tikkling_end: 티클링을 찾을 수 없습니다."); + const return_body = { + success: false, + detail_code: "00", + message: "비정상적 요청, 티클링을 찾을 수 없습니다.", + returnToken: null, + }; + return res.status(404).send(return_body); + } + //티클링이 종료된 경우 + else if (check_tikkling[0].terminated_at != null || check_tikkling[0].state_id != 1) { + console.log("bad_request-put_tikkling_stop: 이미 종료된 티클링에 대해서 중단을 요청"); + const return_body = { + success: false, + detail_code: "00", + message: "이미 종료된 티클링입니다.", + returnToken, + }; + return res.status(400).send(return_body); + } else if (check_tikkling[0].tikkle_count == 0) { + console.log("bad_request-put_tikkling_stop: 티클링 조각이 없는 티클링에 대해서 중단을 요청"); + const return_body = { + success: false, + detail_code: "00", + message: "티클링 조각이 없는 티클링입니다.", + returnToken, + }; + return res.status(401).send(return_body); + } + + const rows = await queryDatabase("UPDATE tikkling SET state_id = 3 WHERE id = ?;", [req.body.tikkling_id]); + + if (rows.affectedRows == 1) { + const return_body = { + success: true, + detail_code: "00", + message: `티클링을 성공적으로 중단하였습니다.`, + returnToken, + }; + return res.status(200).send(return_body); + } + } catch (err) { + console.error("Failed to connect or execute query:", err); + console.log("put_tikkling_end에서 에러가 발생했습니다."); + console.error(`🚨 error -> ⚡️ put_tikkling_end : 🐞${err}`); + const return_body = { + success: false, + detail_code: "00", + message: "서버 에러", + returnToken: null, + }; + return res.status(500).send(return_body); + } +}; diff --git a/tikkle_user/.DS_Store b/tikkle_user/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..0f0c433c5a6ad8b8650f6dfe9fbc582dad4085c6 GIT binary patch literal 10244 zcmeI1Noy2A6vto3Nt|e+iTlkF5hQpp#DfRXNf<#eE|7?L$~Ke5S($|);9Rqb^3OiiaMA{wX;-EY!e|C;)}*R{MFBJ##+>0zP- z5yf$`9q7YFbMSLM+m0^(&N)~QdZH?2Xo_l7fpv%Tfb)R!fb)R!fb+or=mE^xe8hK4 z>#oiN&I8T^O%L$+kif|{>Dz|1V(7p{qyVrn+!hBuBM%Uogm06+ZAdGms8ePSo-g(M z6vLBpJWp_O*rab8(n>jbQcj-#&7Pm3c;efkONip+C8c#&=K<$|b`Nmwet^=**K;`4 z{Jo4!zD`TXZqMQ{YU!J zqS|&bO7zo$V4k8`nxO(^L7c{?D$TTzj-jOyrB$}iC(f^}P7Ah3ML=Vw(6s+hv;A_% zg(EhHXk~EC(j;P*#UID6KnpEI4?tw4R~e7IYR1p9j(~crb!hysU*iY$jlLoFqsn0q z#GbVn&< zhJbx*HE8&Qeigj;{Ep94G0eM*cQhkPt9-}DH=c~hxJD`h9y5ie{eznL@%Va`iWqyA z(0emsj_!4E7^qa9>G#b(YNQOf?35ZlUBAfFGTjujNQc>^=XQtws8On%-%`!@((rrp z#emgbt>HbaiDwD($THiE`M*mt%fe#N#LBu$p@Ef zNGl|`a1p*Qw&U>+?+u>x@117L2c9Q=+mKesabL(`7b%e*@r+kch+{{ouJs4)Nl literal 0 HcmV?d00001 diff --git a/tikkle_user/delete_user_wishlist/index.js b/tikkle_user/delete_user_wishlist/index.js new file mode 100644 index 0000000..1b1bbd1 --- /dev/null +++ b/tikkle_user/delete_user_wishlist/index.js @@ -0,0 +1,48 @@ +const { queryDatabase } = require("db.js"); + +exports.delete_user_wishlist = async (req, res) => { + const body = req.body; + const productId = body.productid; + + const id = req.id; + const returnToken = req.returnToken; + + //-------- delete data from DB --------------------------------------------------------------------------------------// + let sqlResult = null; + + const deleteQuery = ` + DELETE FROM user_wish_list + WHERE user_id = ? AND product_id = ? + `; + + const values = [id, productId]; + + try { + const rows = await queryDatabase(deleteQuery, values); + sqlResult = rows; + } catch (err) { + console.error(`🚨 error -> ⚡️ delete_user_whishlist : 🐞 ${err}`); + const return_body = { + success: false, + detail_code: "00", + message: "Database post error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + // console.log("result : ", sqlResult); + + const retData = sqlResult; + + //-------- return result --------------------------------------------------------------------------------------// + + const return_body = { + success: true, + data: retData, + detail_code: "00", + message: "success delete user wishlist", + returnToken: returnToken, + }; + return res.status(200).send(return_body); +}; diff --git a/tikkle_user/get_bank_data/index.js b/tikkle_user/get_bank_data/index.js new file mode 100644 index 0000000..194ca38 --- /dev/null +++ b/tikkle_user/get_bank_data/index.js @@ -0,0 +1,49 @@ +const { queryDatabase } = require("db.js"); + +exports.get_bank_data = async (req, res) => { + const body = req.body; + const id = req.id; + const returnToken = req.returnToken; + + //-------- get bank data --------------------------------------------------------------------------------------// + + let sqlResult; + + try { + const rows = await queryDatabase("select * from bank", []); + sqlResult = rows; + // console.log("SQL result : ", sqlResult); + } catch (err) { + console.error(`🚨 error -> ⚡️ get_bank_data : 🐞 ${err}`); + const return_body = { + success: false, + detail_code: "01", + message: "SQL error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + // check data is one + if (sqlResult.length === 0) { + console.error(`🚨 error -> ⚡️ get_bank_data : 🐞 bankdata db조회 실패`); + const return_body = { + success: false, + detail_code: "01", + message: "SQL error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + //-------- return result --------------------------------------------------------------------------------------// + + const return_body = { + success: true, + data: sqlResult, + detail_code: "00", + message: "success get bank info", + returnToken: returnToken, + }; + return res.status(200).send(return_body); +}; diff --git a/tikkle_user/get_user_checkTikkling/index.js b/tikkle_user/get_user_checkTikkling/index.js new file mode 100644 index 0000000..363001d --- /dev/null +++ b/tikkle_user/get_user_checkTikkling/index.js @@ -0,0 +1,49 @@ +const { queryDatabase } = require("db.js"); + +exports.get_user_checkTikkling = async (req, res) => { + const body = req.body; + + const id = req.id; + const returnToken = req.returnToken; + + //-------- check DB --------------------------------------------------------------------------------------// + + let sqlResult; + + try { + const rows = await queryDatabase("SELECT * FROM tikkling WHERE user_id = ? AND terminated_at IS NULL;", [id]); + sqlResult = rows; + //console.log("SQL result : ", sqlResult); + } catch (err) { + console.error(`🚨 error -> ⚡️ get_user_checkTikkling : 🐞 ${err}`); + const return_body = { + success: false, + detail_code: "00", + message: "SQL error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + //-------- if tikkling --------------------------------------------------------------------------------------// + if (sqlResult.length !== 0) { + const return_body = { + success: true, + data: sqlResult[0].id, + detail_code: "10", + message: "Tikkling", + returnToken: returnToken, + }; + return res.status(200).send(return_body); + } + + //-------- return --------------------------------------------------------------------------------------// + const return_body = { + success: true, + data: 0, + detail_code: "11", + message: "Not Tikkling", + returnToken: returnToken, + }; + return res.status(200).send(return_body); +}; diff --git a/tikkle_user/get_user_deleteUser/index.js b/tikkle_user/get_user_deleteUser/index.js new file mode 100644 index 0000000..999f564 --- /dev/null +++ b/tikkle_user/get_user_deleteUser/index.js @@ -0,0 +1,46 @@ +const { queryDatabase } = require("db.js"); +const crypto = require("crypto"); +const { getSSMParameter } = require("ssm.js"); + +exports.get_user_deleteUser = async (req, res) => { + const body = req.body; + const id = req.id; + const returnToken = req.returnToken; + + //-------- change delete state in 1 --------------------------------------------------------------------------------------// + + let sqlResult; + + try { + const rows = await queryDatabase( + ` UPDATE users + SET is_deleted = ? + WHERE id = ? + `, + [1, id] + ); + + sqlResult = rows; + //console.log("SQL result : ", sqlResult); + } catch (err) { + console.error(`🚨 error -> ⚡️ get_user_deleteUser : 🐞 ${err}`); + const return_body = { + success: false, + detail_code: "00", + message: "SQL error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + //-------- return result --------------------------------------------------------------------------------------// + + const return_body = { + success: true, + data: null, + detail_code: "00", + message: "success to delete user", + returnToken: returnToken, + }; + return res.status(200).send(return_body); +}; diff --git a/tikkle_user/get_user_endTikklings/index.js b/tikkle_user/get_user_endTikklings/index.js new file mode 100644 index 0000000..4d6aeb7 --- /dev/null +++ b/tikkle_user/get_user_endTikklings/index.js @@ -0,0 +1,51 @@ +const { queryDatabase } = require("db.js"); + +exports.get_user_endTikklings = async (req, res) => { + const body = req.body; + const id = req.id; + const returnToken = req.returnToken; + + //-------- check DB --------------------------------------------------------------------------------------// + + let sqlResult; + + try { + const rows = await queryDatabase( + `SELECT tikkling.id AS tikkling_id, tikkling.user_id, tikkling.resolution_type AS resolution_type, tikkling.type AS tikkling_type, tikkling.funding_limit, tikkling.created_at, tikkling.tikkle_quantity, tikkling.terminated_at, tikkling.product_id, tikkling.terminated_at, + tikkling.state_id, tikkling_state.name AS state_name, + products.name AS product_name, products.price, products.description, products.views, + products.is_deleted, products.wishlist_count, products.thumbnail_image, brands.brand_name + FROM tikkling + INNER JOIN tikkling_state ON tikkling.state_id = tikkling_state.id + INNER JOIN products ON tikkling.product_id = products.id + INNER JOIN brands ON products.brand_id = brands.id + WHERE user_id = ? + ORDER BY tikkling.created_at DESC`, + [id] + ); + sqlResult = rows; + //console.log("SQL result : ", sqlResult); + } catch (err) { + console.error(`🚨 error -> ⚡️ get_user_endTikklings : 🐞 ${err}`); + const return_body = { + success: false, + detail_code: "00", + message: "SQL error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + const retData = sqlResult; + + //-------- return result --------------------------------------------------------------------------------------// + + const return_body = { + success: true, + data: retData, + detail_code: "00", + message: "success get user endTikklings", + returnToken: returnToken, + }; + return res.status(200).send(return_body); +}; diff --git a/tikkle_user/get_user_info/index.js b/tikkle_user/get_user_info/index.js new file mode 100644 index 0000000..59ea3ce --- /dev/null +++ b/tikkle_user/get_user_info/index.js @@ -0,0 +1,82 @@ +const { queryDatabase } = require("db.js"); +const crypto = require("crypto"); +const { getSSMParameter } = require("ssm.js"); + +exports.get_user_info = async (req, res) => { + const body = req.body; + const id = req.id; + const returnToken = req.returnToken; + + let sqlResult; + + try { + const rows = await queryDatabase("select * from users where id = ?", [id]); + sqlResult = rows; + console.log("SQL result : ", sqlResult); + } catch (err) { + console.log("get_user_info 에서 에러가 발생했습니다.", err); + const return_body = { + success: false, + detail_code: "01", + message: "SQL error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + // check data is one + if (sqlResult.length !== 1) { + console.error(`🚨 error -> ⚡️ get_user_info : 🐞 ${err}`); + const return_body = { + success: false, + detail_code: "00", + message: "SQL error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + // console.log("sqlResult : ", sqlResult); + //-------- decode account --------------------------------------------------------------------------------------// + if (sqlResult[0].account !== null) { + const encryptedData = sqlResult[0].account; + const algorithm = "aes-256-cbc"; // Use the same algorithm that was used for encryption + + const accountkeyHex = await getSSMParameter("accountkeyHex"); + const accountivHex = await getSSMParameter("accountivHex"); + + const iv = Buffer.from(accountivHex, "hex"); + const key = Buffer.from(accountkeyHex, "hex"); + + // Decryption + const decipher = crypto.createDecipheriv(algorithm, key, iv); + + let decryptedData = decipher.update(encryptedData, "hex", "utf-8"); + decryptedData += decipher.final("utf-8"); + + sqlResult[0].account = decryptedData; + } + + // //-------- bank_code --------------------------------------------------------------------------------------// + + if (sqlResult[0].bank_code !== null) { + const bank_code = sqlResult[0].bank_code; + + const bank_name = await queryDatabase("select * from bank where bank_code = ?", [bank_code]); + + sqlResult[0].bank_name = bank_name[0].bank_name; + } else { + sqlResult[0].bank_name = null; + } + + //-------- return result --------------------------------------------------------------------------------------// + + const return_body = { + success: true, + data: sqlResult[0], + detail_code: "00", + message: "success get user info", + returnToken: returnToken, + }; + return res.status(200).send(return_body); +}; diff --git a/tikkle_user/get_user_isNotice/index.js b/tikkle_user/get_user_isNotice/index.js new file mode 100644 index 0000000..70127f4 --- /dev/null +++ b/tikkle_user/get_user_isNotice/index.js @@ -0,0 +1,56 @@ +const { queryDatabase } = require("db.js"); + +exports.get_user_isNotice = async (req, res) => { + const body = req.body; + const id = req.id; + const returnToken = req.returnToken; + + //-------- check DB --------------------------------------------------------------------------------------// + + let sqlResult; + + try { + const rows = await queryDatabase( + ` SELECT * + FROM notification + WHERE user_id = ? AND is_read = 0 + ORDER BY created_at DESC;`, + [id] + ); + sqlResult = rows; + //console.log("SQL result : ", sqlResult); + } catch (err) { + console.error(`🚨 error -> ⚡️ get_user_isNotice : 🐞 ${err}`); + const return_body = { + success: false, + detail_code: "00", + message: "SQL error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + const retlen = sqlResult.length; + + //-------- return result --------------------------------------------------------------------------------------// + + if (retlen === 0) { + const return_body = { + success: true, + detail_code: "10", + message: "No notification!", + data: { is_notification: false }, + returnToken: returnToken, + }; + return res.status(200).send(return_body); + } else { + const return_body = { + success: true, + detail_code: "11", + message: "There is notification you should read!", + data: { is_notification: true }, + returnToken: returnToken, + }; + return res.status(200).send(return_body); + } +}; diff --git a/tikkle_user/get_user_myWishlist/index.js b/tikkle_user/get_user_myWishlist/index.js new file mode 100644 index 0000000..a2e06d2 --- /dev/null +++ b/tikkle_user/get_user_myWishlist/index.js @@ -0,0 +1,49 @@ +const { queryDatabase } = require("db.js"); + +exports.get_user_myWishlist = async (req, res) => { + const body = req.body; + const id = req.id; + const returnToken = req.returnToken; + + //-------- check DB --------------------------------------------------------------------------------------// + + let sqlResult; + + try { + const rows = await queryDatabase( + `SELECT user_wish_list.product_id, user_wish_list.created_at, + products.name, products.price, products.description, products.category_id, products.created_at, products.views, + products.is_deleted, products.wishlist_count, products.thumbnail_image, brands.brand_name + FROM user_wish_list + INNER JOIN products ON user_wish_list.product_id = products.id + INNER JOIN brands ON products.brand_id = brands.id + WHERE user_wish_list.user_id = ? + ORDER BY user_wish_list.created_at DESC`, + [id] + ); + sqlResult = rows; + console.log("SQL result : ", sqlResult); + } catch (err) { + console.error(`🚨 error -> ⚡️ get_user_myWishlist : 🐞 ${err}`); + const return_body = { + success: false, + detail_code: "00", + message: "SQL error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + const retData = sqlResult; + + //-------- return result --------------------------------------------------------------------------------------// + + const return_body = { + success: true, + data: retData, + detail_code: "00", + message: "success get user myWishlist", + returnToken: returnToken, + }; + return res.status(200).send(return_body); +}; diff --git a/tikkle_user/get_user_paymentHistory/index.js b/tikkle_user/get_user_paymentHistory/index.js new file mode 100644 index 0000000..e162e0c --- /dev/null +++ b/tikkle_user/get_user_paymentHistory/index.js @@ -0,0 +1,57 @@ +const { queryDatabase } = require("db.js"); + +exports.get_user_paymentHistory = async (req, res) => { + const body = req.body; + const id = req.id; + const returnToken = req.returnToken; + + //-------- check DB --------------------------------------------------------------------------------------// + + let sqlResult; + + try { + const rows = await queryDatabase( + ` SELECT st.id AS sending_id, st.created_at AS send_at, st.message, st.quantity AS send_quantity, st.merchant_uid AS merchant_uid, + st.tikkling_id, t.type AS tikkling_type ,t.funding_limit, t.created_at AS tikkling_created_at , t.tikkle_quantity, t.terminated_at AS tikkling_terminated_at, + sts.id AS tikkle_state_id , sts.name AS tikkle_state_name, + t.state_id, ts.name AS state_name, + t.product_id, p.name AS product_name, p.price AS product_price, p.thumbnail_image AS product_image, + st.user_id AS receiver_id, u.name AS user_name, u.nick AS user_nick, u.image AS user_image, b.brand_name + FROM sending_tikkle as st + INNER JOIN tikkling as t ON st.tikkling_id = t.id + INNER JOIN tikkling_state as ts ON t.state_id = ts.id + INNER JOIN products as p ON t.product_id = p.id + INNER JOIN brands as b ON p.brand_id = b.id + INNER JOIN users as u ON t.user_id = u.id + INNER JOIN sending_tikkle_state as sts ON st.state_id = sts.id + WHERE st.user_id = ? and st.state_id != 5 and st.state_id != 6 + ORDER BY st.created_at DESC + `, + [id] + ); + sqlResult = rows; + //console.log("SQL result : ", sqlResult); + } catch (err) { + console.error(`🚨 error -> ⚡️ get_user_paymentHistory : 🐞 ${err}`); + const return_body = { + success: false, + detail_code: "00", + message: "SQL error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + const retData = sqlResult; + + //-------- return result --------------------------------------------------------------------------------------// + + const return_body = { + success: true, + data: retData, + detail_code: "00", + message: "success get user paymentHistory", + returnToken: returnToken, + }; + return res.status(200).send(return_body); +}; diff --git a/tikkle_user/post_user_friend/index.js b/tikkle_user/post_user_friend/index.js new file mode 100644 index 0000000..39e301b --- /dev/null +++ b/tikkle_user/post_user_friend/index.js @@ -0,0 +1,79 @@ +const { queryDatabase } = require("db.js"); + +exports.post_user_friend = async (req, res) => { + const body = req.body; + const id = req.id; + const returnToken = req.returnToken; + + const friendId = body.friendId; + + //-------- is the friendId valid? --------------------------------------------------------------------------------------// + + if (id === friendId) { + // console.log("post_user_friend 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "00", + message: "You cannot be friend yourself", + returnToken: null, + }; + return res.status(400).send(return_body); + } + + //-------- get friend data & check, post friend data to DB if there is no friend data --------------------------------------------------------------------------------------// + + const insertQuery = `INSERT INTO friends_relation (central_user_id, friend_user_id, relation_state_id) + SELECT ?, ?, ? + WHERE NOT EXISTS ( + SELECT 1 + FROM friends_relation + WHERE central_user_id = ? AND friend_user_id = ? + );`; + + const values1 = [id, friendId, 1, id, friendId]; + const values2 = [friendId, id, 2, friendId, id]; + + let ret1 = null; + let ret2 = null; + + try { + //데이터 없으면 추가 + ret1 = await queryDatabase(insertQuery, values1); + + //데이터 없으면 추가 + ret2 = await queryDatabase(insertQuery, values2); + } catch (err) { + console.error(`🚨 error -> ⚡️ post_user_friend : 🐞 ${err}`); + + const return_body = { + success: false, + detail_code: "00", + message: "SQL error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + //-------- return result --------------------------------------------------------------------------------------// + + // console.log("ret1 : ", ret1); + // console.log("ret2 : ", ret2); + + if (ret1.affectedRows !== 1) { + const return_body = { + success: true, + detail_code: "10", + message: "already friend", + returnToken: returnToken, + }; + return res.status(200).send(return_body); + } else { + const return_body = { + success: true, + detail_code: "11", + message: "success post user friend", + returnToken: returnToken, + }; + return res.status(200).send(return_body); + } +}; diff --git a/tikkle_user/post_user_wishlist/index.js b/tikkle_user/post_user_wishlist/index.js new file mode 100644 index 0000000..e0f39fb --- /dev/null +++ b/tikkle_user/post_user_wishlist/index.js @@ -0,0 +1,79 @@ +const { queryDatabase } = require("db.js"); + +exports.post_user_wishlist = async (req, res) => { + const body = req.body; + const id = req.id; + const returnToken = req.returnToken; + + const productId = body.productId; + + //-------- get product data & check --------------------------------------------------------------------------------------// + + let sqlResult; + + const insertQuery = ` + INSERT INTO user_wish_list (user_id, product_id) + SELECT ?, p.id + FROM products p + WHERE p.id = ? AND p.is_deleted = 0`; + + const values = [id, productId]; + + try { + const rows = await queryDatabase(insertQuery, values); + sqlResult = rows; + //console.log("SQL result : ", sqlResult.insertId); + } catch (err) { + console.error(`🚨 error -> ⚡️ post_user_wishlist : 🐞 ${err}`); + const return_body = { + success: false, + detail_code: "01", + message: "SQL error : while insert into user_wish_list", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + // console.log("result : ", sqlResult); + const retData = sqlResult; + + if (sqlResult.affectedRows === 0) { + // console.log("post_user_wishlist 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "02", + message: "deleted product or already exist in wishlist", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + //-------- add wishlist_count --------------------------------------------------------------------------------------// + + try { + const rows = await queryDatabase("UPDATE products SET wishlist_count = wishlist_count + ? WHERE id = ?", [1, productId]); + + sqlResult = rows; + //console.log("SQL result : ", sqlResult); + } catch (err) { + console.error(`🚨 error -> ⚡️ post_user_wishlist : 🐞 ${err}`); + const return_body = { + success: false, + detail_code: "03", + message: "SQL error: while update wishlist_count", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + //-------- return result --------------------------------------------------------------------------------------// + + const return_body = { + success: true, + data: retData, + detail_code: "00", + message: "success post user wishlist", + returnToken: returnToken, + }; + return res.status(200).send(return_body); +}; diff --git a/tikkle_user/put_user_account/index.js b/tikkle_user/put_user_account/index.js new file mode 100644 index 0000000..6c3e737 --- /dev/null +++ b/tikkle_user/put_user_account/index.js @@ -0,0 +1,85 @@ +const { queryDatabase } = require("db.js"); +const crypto = require("crypto"); +const { getSSMParameter } = require("ssm.js"); + +exports.put_user_account = async (req, res) => { + const body = req.body; + const id = req.id; + const returnToken = req.returnToken; + + const bank_code = body.bank_code; + const account = body.account; + + //-------- check account --------------------------------------------------------------------------------------// + + //check productId + if ( + !bank_code || + !account || + typeof bank_code !== "number" || // Check if bank_code is a number + !Number.isInteger(bank_code) || + typeof account !== "string" + ) { + console.log("put_user_account의 입력 데이터에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "00", + message: "input value is null or invalid", + returnToken: null, + }; + return res.status(400).send(return_body); + } + + //-------- encrypt account --------------------------------------------------------------------------------------// + const algorithm = "aes-256-cbc"; // Use the same algorithm that was used for encryption + const accountkeyHex = await getSSMParameter("accountkeyHex"); + const accountivHex = await getSSMParameter("accountivHex"); + + const key = Buffer.from(accountkeyHex, "hex"); + const iv = Buffer.from(accountivHex, "hex"); + const cipher = crypto.createCipheriv(algorithm, key, iv); + + // console.log("key : ", key); + // console.log("iv : ", iv); + + let encryptedAccount = cipher.update(account, "utf-8", "hex"); + encryptedAccount += cipher.final("hex"); + + //console.log("Encrypted Data:", encryptedAccount); + + //-------- update account --------------------------------------------------------------------------------------// + + let sqlResult; + + try { + const rows = await queryDatabase( + ` UPDATE users + SET bank_code = ?, account = ? + WHERE id = ? + `, + [bank_code, encryptedAccount, id] + ); + + sqlResult = rows; + //console.log("SQL result : ", sqlResult); + } catch (err) { + console.error(`🚨 error -> ⚡️ put_user_account : 🐞 ${err}`); + const return_body = { + success: false, + detail_code: "00", + message: "SQL error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + //-------- return result --------------------------------------------------------------------------------------// + + const return_body = { + success: true, + detail_code: "00", + message: "success to update account info", + returnToken: returnToken, + }; + return res.status(200).send(return_body); +}; diff --git a/tikkle_user/put_user_address/index.js b/tikkle_user/put_user_address/index.js new file mode 100644 index 0000000..23bbd48 --- /dev/null +++ b/tikkle_user/put_user_address/index.js @@ -0,0 +1,71 @@ +const { queryDatabase } = require("db.js"); + +exports.put_user_address = async (req, res) => { + const body = req.body; + const id = req.id; + const returnToken = req.returnToken; + + const zonecode = body.zonecode; + const address = body.address; + const detail_address = body.detail_address; + + //-------- check address --------------------------------------------------------------------------------------// + + //check productId + if ( + !zonecode || + !address || + !detail_address || + typeof zonecode !== "string" || + typeof address !== "string" || + typeof detail_address !== "string" || + zonecode.length !== 5 || + address.length > 250 || + detail_address.length > 250 + ) { + console.log("put_user_addressd의 입력 데이터에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "00", + message: "address value is null or invalid", + returnToken: null, + }; + return res.status(400).send(return_body); + } + + //-------- update address --------------------------------------------------------------------------------------// + + let sqlResult; + + try { + const rows = await queryDatabase( + ` UPDATE users + SET zonecode = ?, address = ?, detail_address = ? + WHERE id = ? + `, + [zonecode, address, detail_address, id] + ); + + sqlResult = rows; + //console.log("SQL result : ", sqlResult); + } catch (err) { + console.error(`🚨 error -> ⚡️ put_user_address : 🐞 ${err}`); + const return_body = { + success: false, + detail_code: "00", + message: "SQL error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + //-------- return result --------------------------------------------------------------------------------------// + + const return_body = { + success: true, + detail_code: "00", + message: "success to update address", + returnToken: returnToken, + }; + return res.status(200).send(return_body); +}; diff --git a/tikkle_user/put_user_birthday/index.js b/tikkle_user/put_user_birthday/index.js new file mode 100644 index 0000000..351a993 --- /dev/null +++ b/tikkle_user/put_user_birthday/index.js @@ -0,0 +1,91 @@ +const { queryDatabase } = require("db.js"); + +exports.put_user_birthday = async (req, res) => { + const body = req.body; + const id = req.id; + const returnToken = req.returnToken; + + const birthday = body.birthday; + + //-------- check birthday --------------------------------------------------------------------------------------// + //check birthday + const parsedDate = new Date(birthday); + if (isNaN(parsedDate) || Object.prototype.toString.call(parsedDate) !== "[object Date]") { + //return invalid + console.log(" put_user_birthday 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "02", + message: "birthday value is null or invalid : input birthday again", + returnToken: null, + }; + return res.status(400).send(return_body); + } + + if (!isUserAgeValid(birthday)) { + console.log("post_auth_registerUser 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "03", + message: "if your age is under 14 you cannot use this servise!", + returnToken: null, + }; + return res.status(400).send(return_body); + } + + //-------- update birthday --------------------------------------------------------------------------------------// + + let sqlResult; + + try { + const rows = await queryDatabase( + ` UPDATE users + SET birthday = ? + WHERE id = ? + `, + [birthday, id] + ); + + sqlResult = rows; + //console.log("SQL result : ", sqlResult); + } catch (err) { + console.error(`🚨 error -> ⚡️ put_user_birthday : 🐞 ${err}`); + const return_body = { + success: false, + detail_code: "00", + message: "SQL error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + //-------- return result --------------------------------------------------------------------------------------// + + const return_body = { + success: true, + data: birthday, + detail_code: "00", + message: "success to update birthday", + returnToken: returnToken, + }; + return res.status(200).send(return_body); +}; + +function isUserAgeValid(dateOfBirth) { + // Convert dateOfBirth string to a Date object + const dob = new Date(dateOfBirth); + + // Calculate current date + const currentDate = new Date(); + + // Calculate age + let age = currentDate.getFullYear() - dob.getFullYear(); + + // Check if birthday hasn't occurred yet this year + if (currentDate.getMonth() < dob.getMonth() || (currentDate.getMonth() === dob.getMonth() && currentDate.getDate() < dob.getDate())) { + age--; + } + + // Compare age with minimum age requirement (14) + return age >= 14; +} diff --git a/tikkle_user/put_user_kakaoImage/index.js b/tikkle_user/put_user_kakaoImage/index.js new file mode 100644 index 0000000..281ec19 --- /dev/null +++ b/tikkle_user/put_user_kakaoImage/index.js @@ -0,0 +1,59 @@ +const { queryDatabase } = require("db.js"); + +exports.put_user_kakaoImage = async (req, res) => { + const body = req.body; + const id = req.id; + const returnToken = req.returnToken; + + const image = body.image; + + //-------- check image --------------------------------------------------------------------------------------// + + if (!image) { + console.log("put_user_kakaoImage 에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "03", + message: "이미지 없음", + returnToken: null, + }; + return res.status(400).send(return_body); + } + + //-------- update image --------------------------------------------------------------------------------------// + + let sqlResult; + + try { + const rows = await queryDatabase( + ` UPDATE users + SET image = ? + WHERE id = ? + `, + [image, id] + ); + + sqlResult = rows; + //console.log("SQL result : ", sqlResult); + } catch (err) { + console.error(`🚨 error -> ⚡️ put_user_kakaoImage : 🐞 ${err}`); + const return_body = { + success: false, + detail_code: "00", + message: "SQL error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + //-------- return result --------------------------------------------------------------------------------------// + + const return_body = { + success: true, + data: image, + detail_code: "00", + message: "success to update image", + returnToken: returnToken, + }; + return res.status(200).send(return_body); +}; diff --git a/tikkle_user/put_user_lastpresentamount/index.js b/tikkle_user/put_user_lastpresentamount/index.js new file mode 100644 index 0000000..06674b2 --- /dev/null +++ b/tikkle_user/put_user_lastpresentamount/index.js @@ -0,0 +1,35 @@ +const { queryDatabase, queryDatabase_multi } = require("db.js"); +const { Tikkling } = require("../../features/Tikkling"); +const { Response } = require("../../features/Response"); +const { User } = require("../../features/User"); +const { Delivery } = require("../../features/Delivery"); +const { ExpectedError } = require("../../features/ExpectedError"); +const { DBManager } = require("../../db"); +const { OptionCombination } = require("../../features/Product"); + +exports.put_user_lastpresentamount = async (req, res) => { + const id = req.id; + const returnToken = req.returnToken; + const { last_present_amount } = req.body; + + //main logic------------------------------------------------------------------------------------------------------------------// + const db = new DBManager(); + await db.openTransaction(); + try { + //유저 객체 생성 + const user = await User.createById({ id, db }); + + //유저의 last_present_amount수정 + await user.updateLastPresentAmount(req.body.last_present_amount); + await db.commitTransaction(); + + return res.status(200).send(Response.create(true, "00", "유저의 마지막 선물 금액 수정에 성공하였습니다.", returnToken)); + } catch (err) { + await db.rollbackTransaction(); + console.error(`🚨 error -> ⚡️ put_user_lastpresentamount : 🐞${err}`); + if (err.status) { + return res.status(err.status).send(Response.create(false, err.detail_code, err.message)); + } + return res.status(500).send(Response.create(false, "00", "서버 에러")); + } +}; diff --git a/tikkle_user/put_user_nick/index.js b/tikkle_user/put_user_nick/index.js new file mode 100644 index 0000000..35e21f5 --- /dev/null +++ b/tikkle_user/put_user_nick/index.js @@ -0,0 +1,60 @@ +const { queryDatabase } = require("db.js"); + +exports.put_user_nick = async (req, res) => { + const body = req.body; + const id = req.id; + const returnToken = req.returnToken; + + const nick = body.nick; + + //-------- check nick --------------------------------------------------------------------------------------// + + //check nick + if (!nick || typeof nick !== "string" || nick.length > 12 || nick.length < 5) { + console.log("put_user_nick의 입력 데이터에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "00", + message: "nick value is null or invalid", + returnToken: null, + }; + return res.status(400).send(return_body); + } + + //-------- update nick --------------------------------------------------------------------------------------// + + let sqlResult; + + try { + const rows = await queryDatabase( + ` UPDATE users + SET nick = ? + WHERE id = ? + `, + [nick, id] + ); + + sqlResult = rows; + //console.log("SQL result : ", sqlResult); + } catch (err) { + console.error(`🚨 error -> ⚡️ put_user_nick : 🐞 ${err}`); + const return_body = { + success: false, + detail_code: "00", + message: "SQL error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + //-------- return result --------------------------------------------------------------------------------------// + + const return_body = { + success: true, + data: nick, + detail_code: "00", + message: "success to update nick", + returnToken: returnToken, + }; + return res.status(200).send(return_body); +}; diff --git a/tikkle_user/put_user_token/index.js b/tikkle_user/put_user_token/index.js new file mode 100644 index 0000000..f959439 --- /dev/null +++ b/tikkle_user/put_user_token/index.js @@ -0,0 +1,61 @@ +const { queryDatabase } = require("db.js"); +const crypto = require("crypto"); +const { getSSMParameter } = require("ssm.js"); + +exports.put_user_token = async (req, res) => { + const body = req.body; + const id = req.id; + const returnToken = req.returnToken; + + const token = body.token; + + //-------- check account --------------------------------------------------------------------------------------// + + //check productId + if (!token || typeof token !== "string") { + console.log("put_user_token의 입력 데이터에서 에러가 발생했습니다."); + const return_body = { + success: false, + detail_code: "00", + message: "input value is null or invalid", + returnToken: null, + }; + return res.status(400).send(return_body); + } + + //-------- update token --------------------------------------------------------------------------------------// + + let sqlResult; + + try { + const rows = await queryDatabase( + ` UPDATE users + SET device_token = ? + WHERE id = ? + `, + [token, id] + ); + + sqlResult = rows; + //console.log("SQL result : ", sqlResult); + } catch (err) { + console.error(`🚨 error -> ⚡️ put_user_token : 🐞 ${err}`); + const return_body = { + success: false, + detail_code: "00", + message: "SQL error", + returnToken: null, + }; + return res.status(500).send(return_body); + } + + //-------- return result --------------------------------------------------------------------------------------// + + const return_body = { + success: true, + detail_code: "00", + message: "success to update token info", + returnToken: returnToken, + }; + return res.status(200).send(return_body); +};