-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'develop' into SumedhAndAlice/NotificationMessaging
- Loading branch information
Showing
14 changed files
with
601 additions
and
78 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,6 +25,7 @@ local.settings.json | |
node_modules | ||
dist | ||
|
||
|
||
__blobstorage__ | ||
__queuestorage__ | ||
__azurite_db_blob__.json | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
{ | ||
"bindings": [ | ||
{ | ||
"authLevel": "function", | ||
"type": "httpTrigger", | ||
"direction": "in", | ||
"name": "req", | ||
"methods": [ | ||
"get", | ||
"post" | ||
] | ||
}, | ||
{ | ||
"type": "http", | ||
"direction": "out", | ||
"name": "res" | ||
} | ||
], | ||
"scriptFile": "../dist/InputData/index.js" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,200 @@ | ||
import { AzureFunction, Context, HttpRequest } from '@azure/functions' | ||
import Mongo from '../ReceiveMessage/Scripts/db' | ||
import xlsxFile from 'read-excel-file/node' | ||
import ChatbotMessage, { IMessage } from '../ReceiveMessage/models/ChatbotMessage' | ||
|
||
type MessageToBeCreated = { | ||
record: IMessage | ||
keywords: string[] | ||
nextMessages: number[] | ||
previousMessage: number | ||
} | ||
|
||
//https://medium.com/javascript-in-plain-english/how-to-read-an-excel-file-in-node-js-6e669e9a3ce1 | ||
const httpTrigger: AzureFunction = async function (context: Context, req: HttpRequest): Promise<void> { | ||
context.log('HTTP trigger function processed a request.') | ||
|
||
const success = true | ||
|
||
const path = req.query.path || (req.body && req.body.path) | ||
|
||
//from the root dir, for whatever reason | ||
let defaultPath = './InputData/messages.xlsx' | ||
if (path) { | ||
defaultPath = path | ||
} | ||
//CHANGE THIS TO MATCH THE CHATBOTMESSAGE SCHEMA | ||
//TODO: FIgure out keywords | ||
const schema = { | ||
ID: { | ||
prop: 'messageId', | ||
type: Number, | ||
required: true, | ||
}, | ||
BODY: { | ||
prop: 'body', | ||
type: String, | ||
required: true, | ||
}, | ||
MULTIMEDIA: { | ||
prop: 'multimedia', | ||
type: String, | ||
}, | ||
'NEXT MESSAGES': { | ||
prop: 'nextMessages', | ||
type: String, | ||
}, | ||
'PREVIOUS MESSAGE': { | ||
prop: 'prevMessage', | ||
type: Number, | ||
}, | ||
MODULE: { | ||
prop: 'module', | ||
type: Number, | ||
}, | ||
'LOW DATA': { | ||
prop: 'lowDataBody', | ||
type: String, // it is possible to validate each of these values. | ||
required: true, | ||
}, | ||
KEYWORDS: { | ||
prop: 'keywords', | ||
type: String, | ||
}, | ||
MESSAGETYPE: { | ||
prop: 'messageType', | ||
type: String, | ||
}, | ||
} | ||
await Mongo() | ||
const readXlsx = await xlsxFile(defaultPath, { schema }) | ||
const rows = readXlsx.rows | ||
const errors = readXlsx.errors | ||
if (errors.length != 0) { | ||
context.log(errors) | ||
let errorBody = `There were ${errors.length} number of errors:\n` | ||
for (const error of errors) { | ||
errorBody += `Row ${error.row}; Col ${error.column}; Error: ${error.error}` | ||
} | ||
context.res = { | ||
// status: 200, /* Defaults to 200 */ | ||
body: errorBody, | ||
} | ||
return | ||
} | ||
const messagesToInsert = new Map<number, MessageToBeCreated>() | ||
// 1.) Make a map based upon all of the messageIds, with the value being a chatbotMessage | ||
for (const [i, row] of rows.entries()) { | ||
// 0.) Convert nextMessages into an array; same with keywords: | ||
const nextMessagesArray: number[] = row.nextMessages | ||
.toString() | ||
.split(',') | ||
.map((x: string) => parseInt(x.trim())) | ||
const nextKeywordsArray: string[] = row.keywords | ||
? row.keywords | ||
.toString() | ||
.split(',') | ||
.map((x: string) => x.trim()) | ||
: ['default'] | ||
|
||
if (nextMessagesArray.length != nextKeywordsArray.length) { | ||
context.res = { | ||
// status: 200, /* Defaults to 200 */ | ||
body: `on probably line ${i + 2} for the message with id ${ | ||
row.messageId | ||
} there was a mismatch between the next messages and number of corresponding keywords.`, | ||
} | ||
return | ||
} | ||
|
||
// 1.) query for the messageId | ||
const existingMessage = await ChatbotMessage.findOne({ | ||
messageId: row.messageId, | ||
}).exec() | ||
|
||
// 2.) If that record exists, set the value to be that chatbotMessage | ||
if (existingMessage) { | ||
existingMessage.body = row.body | ||
existingMessage.image = row.multimedia ? row.multimedia.toString() : '' | ||
existingMessage.module = row.module | ||
existingMessage.messageType = row.messageType | ||
existingMessage.lowData = row.lowDataBody | ||
messagesToInsert.set(row.messageId, { | ||
record: existingMessage, | ||
keywords: nextKeywordsArray, | ||
nextMessages: nextMessagesArray, | ||
previousMessage: row.prevMessage, | ||
}) | ||
} | ||
// 3.) else, create a new one | ||
else { | ||
messagesToInsert.set(row.messageId, { | ||
record: new ChatbotMessage({ | ||
//put stuff here | ||
messageId: row.messageId, | ||
body: row.body, | ||
nextMessages: {}, | ||
image: row.multimedia ? row.multimedia.toString() : '', | ||
module: row.module, | ||
messageType: row.messageType, | ||
lowData: row.lowDataBody, | ||
previousMessage: 'not yet', | ||
}), | ||
keywords: nextKeywordsArray, | ||
nextMessages: nextMessagesArray, | ||
previousMessage: row.prevMessage, | ||
}) | ||
} | ||
} | ||
|
||
// 2.) Iterate through every entry of the map, and make connections between all of the messages. | ||
for (const [key, record] of messagesToInsert) { | ||
for (let i = 0; i < record.nextMessages.length; i++) { | ||
const nextMessage = messagesToInsert.get(record.nextMessages[i]) | ||
const prevMessage = messagesToInsert.get(record.previousMessage) | ||
if (!nextMessage) { | ||
context.res = { | ||
// status: 200, /* Defaults to 200 */ | ||
body: | ||
record.nextMessages[i] + | ||
' is not a valid messageId. Please check to make sure this id was put in properly', | ||
} | ||
return | ||
} | ||
if (!prevMessage) { | ||
context.res = { | ||
// status: 200, /* Defaults to 200 */ | ||
body: | ||
record.previousMessage + | ||
' is not a valid messageId. Please check to make sure this id was put in properly', | ||
} | ||
return | ||
} | ||
record.record.nextMessages.set(record.keywords[i], nextMessage.record['_id']) | ||
record.record.previousMessage = prevMessage.record['_id'] | ||
} | ||
} | ||
|
||
// 3.) Save every record. This could be done in conjunction with (2), but save() is safer than insertMany(), and this function | ||
// won't be constantly called, so we can take the hit in efficiency. | ||
// The one caveat is that if there is an error somehow with saving, then it will keep saving everything else, which probably | ||
// isn't desirable. If we do a good job error checking above, though, that would be fine. | ||
for (const [key, record] of messagesToInsert) { | ||
//context.log(record.record) | ||
await record.record.save() | ||
} | ||
|
||
let responseMessage = path | ||
? 'Input, ' + path + '. This HTTP triggered function executed successfully.' | ||
: 'This HTTP triggered function executed successfully. Pass a path for not the default excel sheet.' | ||
if (!success) { | ||
responseMessage = 'Your upload was incorrect. Please verify the xlsx spreadsheet format matches.' | ||
} | ||
|
||
context.res = { | ||
// status: 200, /* Defaults to 200 */ | ||
body: responseMessage, | ||
} | ||
} | ||
|
||
export default httpTrigger |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"name": "Azure" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,31 +1,25 @@ | ||
import { AzureFunction, Context, HttpRequest } from '@azure/functions'; | ||
import * as twilio from 'twilio'; | ||
import qs from 'qs'; | ||
import MongoConnect from './db'; | ||
import UserState from '../models/UserState'; | ||
|
||
const MessagingResponse = twilio.twiml.MessagingResponse; | ||
import { AzureFunction, Context, HttpRequest } from '@azure/functions' | ||
import * as twilio from 'twilio' | ||
import qs from 'qs' | ||
import MongoConnect from './db' | ||
import UserState from '../models/UserState' | ||
|
||
//change to Promise<UserState> later | ||
const getUserState = async function (req: HttpRequest) { | ||
const body = qs.parse(req.body); | ||
const body = qs.parse(req.body) | ||
// do necessary processing on the request (nothing at this point) | ||
await MongoConnect(); | ||
const userStateResult = await UserState.find({ userId: body.From as string }); | ||
if (userStateResult.length === 0) { | ||
const newUser = new UserState({ userId: body.From }); | ||
await MongoConnect() | ||
const userStateResult = await UserState.findOne({ userId: body.From as string }) | ||
if (!userStateResult) { | ||
const newUser = new UserState({ userId: body.From }) | ||
newUser.save(function (err) { | ||
if (err) { | ||
console.log(err); | ||
console.log(err) | ||
} | ||
``; | ||
}); | ||
}) | ||
} | ||
// retrieve and return the corresponding state | ||
const id = body.AccountSid; | ||
await MongoConnect(); | ||
const result = await UserState.find({ userId: id as string }); | ||
return result[0]; | ||
}; | ||
return userStateResult | ||
} | ||
|
||
export default getUserState; | ||
export default getUserState |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import ChatbotMessage, { IMessage } from './models/ChatbotMessage' | ||
import db from './Scripts/db' | ||
|
||
interface templateFixedMessageHandler { | ||
(messageId: number): Promise<IMessage> | ||
} | ||
|
||
const generalHandler: templateFixedMessageHandler = async function (messageId: number): Promise<IMessage> { | ||
db() | ||
return ChatbotMessage.findOne({ messageId: messageId }) | ||
} | ||
|
||
const fixedMessages: Map<string | qs.ParsedQs | string[] | qs.ParsedQs[], Promise<IMessage>> = new Map< | ||
string | qs.ParsedQs | string[] | qs.ParsedQs[], | ||
Promise<IMessage> | ||
>() | ||
|
||
fixedMessages.set('MessagePermission', generalHandler(-1)) | ||
fixedMessages.set('DataPermission', generalHandler(0)) | ||
fixedMessages.set('Welcome', generalHandler(1)) | ||
fixedMessages.set('ModuleOne', generalHandler(100)) | ||
fixedMessages.set('ModuleTwo', generalHandler(200)) | ||
fixedMessages.set('ModuleThree', generalHandler(300)) | ||
fixedMessages.set('ModuleFour', generalHandler(400)) | ||
fixedMessages.set('ModuleFive', generalHandler(500)) | ||
fixedMessages.set('commands', generalHandler(911)) | ||
fixedMessages.set('Exercise Diagnostic', generalHandler(1100)) | ||
fixedMessages.set('WASH Diagnostic', generalHandler(1200)) | ||
fixedMessages.set('Nutrition Diagnostic', generalHandler(1300)) | ||
fixedMessages.set('Maternal Infant Care Diagnostic', generalHandler(1400)) | ||
fixedMessages.set('Mental Health Diagnostic', generalHandler(1500)) | ||
|
||
export default fixedMessages |
Oops, something went wrong.