-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathmessageParser.js
276 lines (212 loc) · 11.4 KB
/
messageParser.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
const { fileIO } = require('./fileIO');
const jsonfile = require('jsonfile');
const fs = require('fs');
const { ActivityTypes, MessageFactory, TurnContext } = require('botbuilder');
const { profileAccessor } = require('./profileAccessor');
// cassandra database
const CassandraService = require('./service/CassandraService');
const cassandra = require('cassandra-driver');
// for hashing userId for cassandra database
var crypto = require('crypto');
//data structure for chat messages
const MessageQueue = require("./service/MessageQueue");
const Message = require("./model/messageByUser");
// config file
const config = require('./config.json');
//Dialog modules and properties
const { DialogSet, WaterfallDialog, Dialog, DialogTurnStatus } = require('botbuilder-dialogs');
const DIALOG_STATE_PROPERTY = 'dialogState';
//Email Dialog !Only for testing really. Trying to phase out
const { EmailDialog } = require('./emailDialog');
//Profile Dialog
const { ProfileDialog } = require('./profileDialog');
//Quiz Dialog
const { QuizDialog } = require('./quizDialog');
//Task Dialog
const { TaskDialog } = require('./taskDialog');
//Reminder Dialog
const { ReminderDialog } = require('./reminderDialog');
//Role Selection Dialog
const { RoleDialog } = require('./roleDialog');
//Task Assignment Dialog
const { AssignDialog } = require('./assignDialog');
//Task Assignment Dialog
const { MinutesDialog } = require('./minutesDialog');
//Module for pushing xAPI statements
const { xAPI_Statements } = require('./xAPI_Statements');
//Userinfo property
const USER_INFO_PROPERTY = 'userInfoPropertyAccessor';
//Logging
const { log } = require('./logger');
//Message parser will be the bots main turn handler.
class messageParser {
constructor(conversationState, userState){
// //Call super before referencing this
// super();
//Create states
this.conversationState = conversationState;
this.userState = userState;
//Create state property accessors
this.dialogState = this.conversationState.createProperty(DIALOG_STATE_PROPERTY);
this.userInfoAccessor = this.userState.createProperty(USER_INFO_PROPERTY);
//Init database connection
this.cassandraService = new CassandraService();
this.cassandraService.connect();
//Init queue for all messages
this.messageQueue = new MessageQueue(this.cassandraService);
//Add dialogs here
this.dialogs = new DialogSet(this.dialogState)
//Email Reminder
.add(new EmailDialog('emailDialog'))
//Welcome and Build Profile
.add(new ProfileDialog('profileDialog'))
//Displays User Selected tasks
.add(new TaskDialog('taskDialog'))
//Reminder
.add(new ReminderDialog('remindDialog'))
//Role Selection
.add(new RoleDialog('roleDialog'))
//Assignment Selection
.add(new AssignDialog('assignDialog'))
//Meeting Minutes (task progress report)
.add(new MinutesDialog('minutesDialog'));
}
async onTurn(turnContext) {
//Store required information
let channelID = turnContext.activity.channelId;
let name = turnContext.activity.from.name;
let userID = turnContext.activity.from.id;
var txt = turnContext.activity.text;
var val = turnContext.activity.value;
const xAPI_Handler = new xAPI_Statements();
if (turnContext.activity.type === ActivityTypes.Message) {
//Create user object
const user = await this.userInfoAccessor.get(turnContext, {});
//Create dialog controller
const dc = await this.dialogs.createContext(turnContext);
const dialogTurnResult = await dc.continueDialog();
//console.log(user.profile);
//If user profile does not exist in memory start dialog
if(!user.profile) {
if ((config.cassandra.enabled === true) && (dialogTurnResult.status === DialogTurnStatus.empty)) {
// create hash object to create UUID for a user on a channel
let hash = crypto.createHash('md5');
let hash_update = hash.update(`${name} + ${channelID}`, 'utf8');
let generated_hash = Buffer.from(hash_update.digest('hex'), 'hex');
let user_profile = await this.cassandraService.get_profile_by_email_dao().get_user_profile_by_channel(channelID, generated_hash);
try {
var profileComparison = Buffer.compare(generated_hash, user_profile.userId);
}
catch {
var profileComparison = -1;
fileIO.setDialog(channelID, userID);
await dc.beginDialog('profileDialog');
}
if (profileComparison == 0) {
user.profile = user_profile;
await turnContext.sendActivity(`Welcome back ${user.profile.nick}`);
}
}
else if(dialogTurnResult.status === DialogTurnStatus.empty) {
log.info(`Profile for ${name} does not appear to be stored in Casandra DB}`);
fileIO.setDialog(channelID, userID);
await dc.beginDialog('profileDialog');
}
else if(dialogTurnResult.status === DialogTurnStatus.complete) {
user.profile = dialogTurnResult.result;
user.profile.name = turnContext.activity.from.name;
fileIO.buildDB(user.profile.class, user.profile.team);
this.userInfoAccessor.set(turnContext, user);
fileIO.insertProfile(user.profile);
if (config.cassandra.enabled === true) {
let hash = crypto.createHash('md5');
let hash_update = hash.update(`${name} + ${channelID}`, 'utf8');
let generated_hash = Buffer.from(hash_update.digest('hex'), 'hex');
// write profile to cassandraDB
this.cassandraService.get_profile_by_email_dao().insert(generated_hash, user.profile.email, user.profile.class, user.profile.team, user.profile.nick, channelID);
}
await turnContext.sendActivity('Your profile has been stored.');
await xAPI_Handler.recordLogin(user.profile.email);
log.info(`Profile for ${name} has been created.`);
}
}
//If user profile is present grant access to full functionality
else {
//Check to see if message is coming from card
if (!txt && val){
// Check for existence of role selection entry and enter data into user's profile
if(val.Role != undefined){
user.profile.role = val.Role;
fileIO.insertProfile(user.profile);
xAPI_Handler.recordRoleSelection(user.profile.email, user.profile.role);
}
// Check for existence of meeting minutes report and enter students entry into table for team
if(val.taskSelection != undefined && val.progressSelection != undefined){
var minutesTablePath = `Resources/Classes/${user.profile.class}/Teams/${user.profile.team}/minutes.json`
var meetingMinutes = jsonfile.readFileSync(minutesTablePath);
let studentMinutes = meetingMinutes[user.profile.nick];
if(studentMinutes != undefined){
meetingMinutes[user.profile.nick][val.taskSelection] = val.progressSelection;
jsonfile.writeFileSync(minutesTablePath, meetingMinutes);
} else{
meetingMinutes[user.profile.nick] = {};
meetingMinutes[user.profile.nick][val.taskSelection] = val.progressSelection;
jsonfile.writeFileSync(minutesTablePath, meetingMinutes);
}
xAPI_Handler.recordMeetingMinutes(user.profile.email, val.taskSelection, val.progressSelection);
}
}
//Check for the existence of previous messages and process accordingly
var utterance = (turnContext.activity.text || '').trim().toLowerCase();
//Make new message by user object for message queue
let user_message = new Message(userID, user.profile.email, new Date(), utterance,
channelID);
//List of BotCaptains available function plugins
<<<<<<< HEAD
let commands = ['task', 'remind','quiz']
=======
let commands = ['task', 'remind', 'role', 'assign', 'minutes'];
>>>>>>> 1dd8ea8e06000e473ec298824276f101f8566c52
if(utterance[0] === "!" && commands.includes(utterance.slice(1)) && dialogTurnResult.status === DialogTurnStatus.empty){
//Start appropriate dialog
let command = utterance.slice(1);
let dialog = command.concat('Dialog');
fileIO.setDialog(channelID, userID);
log.info(`[INFO] User ${user} initiated a command.`);
await dc.beginDialog(`${dialog}`, user);
}
if(dialogTurnResult.status === DialogTurnStatus.complete){
user.profile = dialogTurnResult.result;
this.userInfoAccessor.set(turnContext, user);
}
// Allow user to cancel or start any dialog
if (utterance === 'cancel') {
if (dc.activeDialog) {
await dc.cancelAllDialogs();
await dc.context.sendActivity(`Ok... canceled.`);
} else {
await dc.context.sendActivity('Nothing to cancel.');
}
}
//Record turnContext data
fileIO.logContext(turnContext, user.profile);
if (config.cassandra.enabled === true) {
log.info(`Enqueued the message object`);
log.info(user_message);
//Enqueue message by user object
this.messageQueue.enqueue(user_message);
}
}
} else if(turnContext.activity.type === ActivityTypes.ConversationUpdate){
//Create dialog controller
const dc = await this.dialogs.createContext(turnContext);
//Begin profileDialog
fileIO.setDialog(channelID, userID);
await dc.beginDialog('profileDialog');
}
//Save changes
await this.userState.saveChanges(turnContext);
await this.conversationState.saveChanges(turnContext);
}
}
module.exports.messageParser = messageParser;