diff --git a/.env.sample b/.env.sample index 29ec50d..dc7d944 100644 --- a/.env.sample +++ b/.env.sample @@ -6,4 +6,5 @@ SERVER_PORT=3001 TWILIO_ACCOUNT_SID= TWILIO_AUTH_TOKEN= TWILIO_NUMBER= -TEST_RECEPIENT_NUMBER= \ No newline at end of file +TEST_RECEPIENT_NUMBER= +STRAPI_TOURISM_TOKEN= \ No newline at end of file diff --git a/config/openai.json b/config/openai.json index 7ca9729..041363b 100644 --- a/config/openai.json +++ b/config/openai.json @@ -11,6 +11,14 @@ { "role": "system", "content": "A typical order flow should be search > select > init > confirm."}, { "role": "system", "content": "Use the response of search from assistant to select items from the list of items provided by the assistant."}, { "role": "system", "content": "Use the response of search request from assistant for filling transaction_id, bpp_id, bpp_uri in the context of all calls except `search`."}, - { "role": "system", "content": "For `select`, `init`, `confirm`, you must use the item `id` as part of the payload for selected item instead of name or any other key."} - ] + { "role": "system", "content": "Use the response from assistant to select items from the list of items provided by the assistant."} + + ], + "PRESETS" : { + "bap_id": "mit-ps-bap.becknprotocol.io", + "bap_uri": "https://mit-ps-bap.becknprotocol.io", + "version": "1.1.0", + "base_url": "https://mit-ps-bap-client.becknprotocol.io", + "TOURISM_STRAPI_URL": "https://mit-bpp-tourism.becknprotocol.io/api" + } } \ No newline at end of file diff --git a/controllers/ControlCenter.js b/controllers/ControlCenter.js index 914da10..e93120a 100644 --- a/controllers/ControlCenter.js +++ b/controllers/ControlCenter.js @@ -1,49 +1,49 @@ -import axios from 'axios' import Actions from '../services/Actions.js' +import { readFileSync } from 'fs'; import logger from '../utils/logger.js' import { ITEM_ID, ITEM_NAME, CAT_ATTR_TAG_RELATIONS, - STRAPI_TOURISM_TOKEN, NEW_CATALOG_AVAILABLE, TRIGGER_BLIZZARD_MESSAGE, CANCEL_BOOKING_MESSAGE } from '../utils/constants.js' +const config = JSON.parse(readFileSync('./config/openai.json')) const action = new Actions() -const TOURISM_STRAPI_URL = process.env.TOURISM_STRAPI_URL || '' -const TWILIO_RECEPIENT_NUMBER = process.env.TOURISM_STRAPI_URL -export const cancelBookingController = async (req, res) => { +const STRAPI_TOURISM_TOKEN = process.env.STRAPI_TOURISM_TOKEN || '' +const TWILIO_RECEPIENT_NUMBER = process.env.TEST_RECEPIENT_NUMBER +export const cancelBooking = async (req, res) => { try { const { orderId } = req.body + if(!orderId){ + return res.status(500).json({message:"Order Id is Required", status:false}) + } + const validOrderId = await action.call_api(`${config.PRESETS.TOURISM_STRAPI_URL}/orders/${orderId}`,'GET',{},{ Authorization: `Bearer ${STRAPI_TOURISM_TOKEN}`}) + if(!validOrderId.status){ + return res.send({ message: `Invalid Order Id`, status:false }) + } const messageBody = CANCEL_BOOKING_MESSAGE; - const getOrderFulfillmentDetails = await axios.get( - `${TOURISM_STRAPI_URL}/order-fulfillments?order_id=${orderId}`, - { - headers: { - Authorization: `Bearer ${STRAPI_TOURISM_TOKEN}`, - }, - } - ) + const getOrderAddressDetails = await action.call_api(`${config.PRESETS.TOURISM_STRAPI_URL}/order-addresses?order_id=${orderId}`,'GET',{},{ Authorization: `Bearer ${STRAPI_TOURISM_TOKEN}`}) + + const getOrderFulfillmentDetails = await action.call_api(`${config.PRESETS.TOURISM_STRAPI_URL}/order-fulfillments?order_id=${orderId}`,'GET',{},{ Authorization: `Bearer ${STRAPI_TOURISM_TOKEN}`}) if (getOrderFulfillmentDetails.data.data.length) { - await axios.put( - `${TOURISM_STRAPI_URL}/order-fulfillments/${getOrderFulfillmentDetails.data.data[0].id}`, - { - data: { - state_code: 'CANCELLED', - state_value: 'CANCELLED BY HOTEL', - }, + await action.call_api(`${config.PRESETS.TOURISM_STRAPI_URL}/order-fulfillments/${getOrderFulfillmentDetails.data.data[0].id}`,'PUT',{ + data: { + state_code: 'CANCELLED', + state_value: 'CANCELLED BY HOTEL', }, - { - headers: { - Authorization: `Bearer ${STRAPI_TOURISM_TOKEN}`, - }, - } - ) - - await action.send_message(TWILIO_RECEPIENT_NUMBER, messageBody) - return res.send({ message: 'Notified' }) + },{ Authorization: `Bearer ${STRAPI_TOURISM_TOKEN}`}) + let statusMessage = ""; + + if(getOrderAddressDetails.data.data[0].attributes.phone){ + statusMessage = (await action.send_message(`+91${getOrderAddressDetails.data.data[0].attributes.phone}`, messageBody)).status.status + } + else{ + statusMessage = (await action.send_message(TWILIO_RECEPIENT_NUMBER, messageBody)).status.status + } + return res.send({ message: `Notification ${statusMessage}` }) } return res.send({ message: 'Cancel Booking Failed' }) @@ -55,22 +55,18 @@ export const cancelBookingController = async (req, res) => { export const updateCatalog = async (req, res) => { try { + const { userNo = TWILIO_RECEPIENT_NUMBER } = req.body; const messageBody = NEW_CATALOG_AVAILABLE; - await axios.put( - `${TOURISM_STRAPI_URL}/items/${ITEM_ID}`, - { - data: { - name: ITEM_NAME, - cat_attr_tag_relations: CAT_ATTR_TAG_RELATIONS, - }, + await action.call_api(`${config.PRESETS.TOURISM_STRAPI_URL}/items/${ITEM_ID}`,'PUT',{ + data: { + name: ITEM_NAME, + cat_attr_tag_relations: CAT_ATTR_TAG_RELATIONS, }, - { - headers: { - Authorization: `Bearer ${STRAPI_TOURISM_TOKEN}`, - }, - } - ) - await action.send_message(TWILIO_RECEPIENT_NUMBER, messageBody) + },{ Authorization: `Bearer ${STRAPI_TOURISM_TOKEN}`}) + const notifyResponse = await action.send_message(userNo, messageBody) + if(notifyResponse.status.status === "failed"){ + throw new Error('Notification Failed') + } return res.send({ message: 'Catalog Updated' }) } catch (error) { logger.error(error.message) @@ -79,11 +75,12 @@ export const updateCatalog = async (req, res) => { } -export const notificationController = async (req, res) => { +export const notify = async (req, res) => { try { + const { userNo = TWILIO_RECEPIENT_NUMBER } = req.body; const messageBody = TRIGGER_BLIZZARD_MESSAGE; const sendWhatsappNotificationResponse = await action.send_message( - TWILIO_RECEPIENT_NUMBER, + userNo, messageBody ) return res.send(sendWhatsappNotificationResponse) diff --git a/server.js b/server.js index b5ef7b9..e3f73a4 100644 --- a/server.js +++ b/server.js @@ -6,10 +6,10 @@ import bodyParser from 'body-parser' import logger from './utils/logger.js' import messageController from './controllers/Bot.js' import DBService from './services/DBService.js' -import { notificationController } from './controllers/Notification.js' import { - cancelBookingController, + cancelBooking, updateCatalog, + notify } from './controllers/ControlCenter.js' const app = express() app.use(cors()) @@ -22,8 +22,8 @@ app.use(bodyParser.json()) // Define endpoints here // app.post('/act', actions.act) app.post('/webhook', messageController.process_wa_webhook) -app.post('/notify', notificationController) -app.post('/cancel-booking', cancelBookingController) +app.post('/notify', notify) +app.post('/cancel-booking', cancelBooking) app.post('/update-catalog', updateCatalog) // Reset all sessions const db = new DBService() diff --git a/services/Actions.js b/services/Actions.js index f522929..e503d17 100644 --- a/services/Actions.js +++ b/services/Actions.js @@ -44,7 +44,7 @@ class Actions { cookies: response.headers['set-cookie'], } logger.info(`API call was successful: , response.status`) - logger.info(JSON.stringify(response.data, null, 2)) + // logger.info(JSON.stringify(response.data, null, 2)) } catch (error) { logger.error(error) diff --git a/services/notificationService.js b/services/notificationService.js deleted file mode 100644 index 0f101ce..0000000 --- a/services/notificationService.js +++ /dev/null @@ -1,30 +0,0 @@ -import logger from '../utils/logger.js' -import Twilio from 'twilio' -const TWILIO_NUMBER = process.env.TWILIO_NUMBER -const TWILIO_AUTH_TOKEN = process.env.TWILIO_AUTH_TOKEN -const TWILIO_ACCOUNT_SID = process.env.TWILIO_ACCOUNT_SID - -const client = Twilio(TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN) - -export const sendWhatsappNotification = async ( - recipientNumber, - messageBody -) => { - try { - const data = await client.messages.create({ - body: messageBody, - from: `whatsapp:${TWILIO_NUMBER}`, - to: `whatsapp:${recipientNumber}`, - }) - - const status = await client.messages(data.sid).fetch() - console.log('data===>', data) - console.log('status===>', status) - if(status?.status!=="failed"){ - return {message:'Notification Sent'} - }return {message:'Failed to Send Notification'} - } catch (error) { - logger.error(error.message) - throw new Error(error.message) - } -} diff --git a/tests/unit/controllers/controlCenter.test.js b/tests/unit/controllers/controlCenter.test.js new file mode 100644 index 0000000..6a54737 --- /dev/null +++ b/tests/unit/controllers/controlCenter.test.js @@ -0,0 +1,78 @@ +import { describe, it} from 'mocha' +import app from '../../../server.js' +import request from 'supertest' +import * as chai from 'chai' +const expect = chai.expect + + +describe('API tests for /notify endpoint for an end to end Notify Request', () => { + it('Should test unsuccess response for invalid whatsapp number.', async () => { + const response = await request(app).post('/notify').send({ + "userNo":"+919123456789" + }) + expect(response._body.status.status).equal('failed') + }) + + it('Should test success response for no whatsapp number provided in the payload and will sent to TEST_RECEPIENT_NUMBER', async () => { + const response = await request(app).post('/notify').send({ + + }) + expect(response._body.status.status).to.not.equal('failed') + }) + + it('Should test success response for valid whatsapp number', async () => { + const response = await request(app).post('/notify').send({ + "userNo":process.env.TEST_RECEPIENT_NUMBER + }) + expect(response._body.status.status).to.not.equal('failed') + }) + + +}) + + + +describe('API tests for /cancel-booking endpoint for an end to end Notify Message', () => { + it('Should test unsuccess response for invalid order Id.', async () => { + const response = await request(app).post('/cancel-booking').send({ + "orderId":"Abcd" + }) + expect(response._body.status).equal(false) + }) + + it('Should test unsuccess response for no order Id.', async () => { + const response = await request(app).post('/cancel-booking').send({}) + expect(response._body.status).equal(false) + }) + + + it('Should test success response for valid order Id.', async () => { + const response = await request(app).post('/cancel-booking').send({ + "orderId":"1" + }) + expect(response._body.message).equal('Notification delivered') + }) + + +}) + +describe('API tests for /update-catalog endpoint for an end to end Notify Message', () => { + it('Should test success response for invalid whatsapp No.', async () => { + const response = await request(app).post('/update-catalog').send({ + "userNo":"+919123456789" + }) + expect(response._body.message).equal('Notification Failed') + }) + + it('Should test success response for no whatsapp number provided in the payload and will sent to TEST_RECEPIENT_NUMBER', async () => { + const response = await request(app).post('/update-catalog').send({}) + expect(response._body.message).equal('Catalog Updated') + }) + + it('Should test success response for valid whatsapp number', async () => { + const response = await request(app).post('/update-catalog').send({ + "userNo":process.env.TEST_RECEPIENT_NUMBER + }) + expect(response._body.message).equal('Catalog Updated') + }) +}) \ No newline at end of file diff --git a/utils/constants.js b/utils/constants.js index af20826..a2219d2 100644 --- a/utils/constants.js +++ b/utils/constants.js @@ -1,6 +1,3 @@ -export const STRAPI_TOURISM_TOKEN = - '82ed7f48afbd0c0605ef36bf4b81259f90c7e6bc357db032a011b1c0ab2bc7db2a753fa84c959f403b256ee66b44174dcc453bd0a40797ce8c22c1b6dab7f416cf3b8a247c19144bc3d019f229612f36b12612223b35f28a1a7fec6ff779228730b45fd93a793399d8f462ba0bada15077725a843d3023cf133838876da3547e' - export const ITEM_ID = '4' export const ITEM_NAME = 'Ticket Pass-Mueseum'