public async Task OnTurnAsync(ITurnContext turnContext, NextDelegate next, CancellationToken cancellationToken = default(CancellationToken)) { Activity activity = turnContext.Activity; if (activity.Type is ActivityTypes.Message) { //Add User Context in the turn context ConversationReference selfConversation = activity.GetConversationReference(); ChatUserContext userContext = ChatUserContext.FromConversation(selfConversation); if (activity.ChannelId.ToLower() != _config.AdminChannel || !UserRoleCache.UserRoles.ContainsKey(userContext.Id)) { userContext.Role = ChatUserRole.Consumer; } else { userContext.Role = UserRoleCache.UserRoles[userContext.Id]; } selfConversation.User.Role = userContext.Role.ToString(); turnContext.TurnState.Add(typeof(ChatUserContext).FullName, userContext); //Add Message router in the turn context ConnectorClient connectorClient = turnContext.TurnState.Get <ConnectorClient>(typeof(IConnectorClient).FullName); MessageRouter messageRouter = new MessageRouter(connectorClient, activity, _logger); turnContext.TurnState.Add(typeof(MessageRouter).FullName, messageRouter); //Ensure that each user only has one conversation active, and notify the other sessions where a conversation replaced it. IEnumerable <ConversationReference> otherConversations = await _routingDataManager.GetConversationsFromUser(selfConversation.User.Id); //Remove current conversation otherConversations = _routingDataManager.RemoveSelfConversation(otherConversations, selfConversation); //Send a notification to all old conversations if (otherConversations.Count() > 0) { foreach (var otherConversation in otherConversations) { await messageRouter.SendErrorMessageAsync(otherConversation, "You were disconnected from this instance."); } } //Store the new conversation await _routingDataManager.SaveConversationReference(selfConversation); //Leave this middleware await next(cancellationToken).ConfigureAwait(false); } if (activity.Type is ActivityTypes.EndOfConversation) { ConversationReference selfConversation = activity.GetConversationReference(); _logger.LogInformation($"Conversation Ended: {selfConversation.Conversation.Id}"); } }
private async Task <IEnumerable <ConversationReference> > GetHandoffConversation(ITurnContext turnContext, Activity activity, CommandSendMessageProperties properties, ConversationReference selfConversation) { //Broadcast to many users IEnumerable <ConversationReference> conversations = null; if (properties.From.Role == ChatUserRole.Consumer) { conversations = await _routingDataManager.GetAdminConversations(); //Send event to event processor... if possible if (turnContext.TurnState.TryGetValue(typeof(ChatReportModel).FullName, out object result)) { await PushMessageToEventProcessorSaga(activity.Text, activity.ChannelId, properties, (ChatReportModel)result); } } //To one user only - Admin only else if (properties.From.Role == ChatUserRole.Admin) { if (properties.UserId == "*") { conversations = await _routingDataManager.GetConversations(); } else { conversations = await _routingDataManager.GetConversationsFromUser(properties.UserId); IEnumerable <ConversationReference> conversations2 = await _routingDataManager.GetAdminConversations(); conversations = conversations2.Union(conversations); } } else { throw new Exception("Message handoff not handled"); } //Do not send to self conversations = _routingDataManager.RemoveSelfConversation(conversations, selfConversation); return(conversations); }
protected override async Task HandleTurnAsync(ITurnContext turnContext, ChatUserContext userContext, MessageRouter messageRouter, NextDelegate next, CancellationToken cancellationToken = default(CancellationToken)) { Activity activity = turnContext.Activity; if (activity.TryGetChannelData(out Command command) && command.BaseCommand != Commands.Undefined) { // Check the activity for commands ConversationReference selfConversation = activity.GetConversationReference(); switch (command.BaseCommand) { case Commands.GetTranscript: if (userContext.Role == ChatUserRole.Admin) { var conversations = await _reportDataManager.GetActiveChatReports(); var readUsersStatus = await _routingDataManager.GetUsersReadStatusPerUser(userContext.Id); await messageRouter.SendTranscriptAsync(activity.Conversation.Id, conversations, readUsersStatus); } else { var conversation = await _reportDataManager.GetActiveChatReportFromUser(activity.From.Id); await messageRouter.SendTranscriptAsync(activity.Conversation.Id, new List <ChatReportModel>() { conversation }); } break; case Commands.ReadUserMessages: //Update a date that shows the last time a message was read by an admin if (userContext.Role == ChatUserRole.Admin) { if (JsonConvert.DeserializeObject <CommandReadUserMessages>(command.Data.ToString()) is CommandReadUserMessages properties) { var result = await _routingDataManager.UpdateUserReadMessageStatus(activity.From.Id, new ChatUserReadStatusModel() { Date = properties.Date, UserId = properties.UserId }); if (!result) { throw new Exception("Error while executing command ReadUserMessages"); } } } break; case Commands.EndConversation: //End a conversation by adding an EndDate and delete the user conversation session so broadcast messages aren't sent to them anymore. if (userContext.Role == ChatUserRole.Admin) { if (JsonConvert.DeserializeObject <CommandEndConversation>(command.Data.ToString()) is CommandEndConversation properties) { ChatReportModel userReport = await _reportDataManager.GetActiveChatReportFromUser(properties.UserId); var result = await _reportDataManager.CloseReport(new ChatReportLogCloseModel() { EndDate = DateTime.UtcNow, UserId = properties.UserId }); if (result) { var userConversationReference = await _routingDataManager.GetConversationsFromUser(properties.UserId); if (userConversationReference != null && userConversationReference.Count() > 0) { //Warn the user that the conversation is over await messageRouter.SendMessageAsync(userConversationReference.ToArray()[0], CommandFactoryHelper.CreateCommandSendMessage(selfConversation.Bot.Id, properties.UserId, selfConversation.User) , "The conversation was ended. If you have an issue, please start a new conversation."); //Call EndOfConversation on the user await messageRouter.SendEndConversationAsync(messageRouter.CreateEndOfConversationActivity(userConversationReference.ToArray()[0])); result = await _routingDataManager.DeleteUserConversation(properties.UserId); //Tell all admins about end of the conversation var admins = await _routingDataManager.GetAdminConversations(); admins = _routingDataManager.RemoveSelfConversation(admins, selfConversation); if (admins != null) { foreach (var admin in admins) { await messageRouter.SendMessageAsync(admin, CommandFactoryHelper.CreateCommandEndConversation(selfConversation.Bot.Id, properties.UserId)); } } //Send event to event processor... if possible if (userReport != null) { //Sanitize user string userId = GetDatabaseUserId(userReport.ChannelId, userReport.User.Id); DeviceModel device = await _deviceRestService.GetMobileDeviceFromUserId(userId); //Send close message await PushClosureMessageToEventProcessorSaga(device.DeviceId); } } } if (!result) { throw new Exception("Error while executing command EndConversation"); } } } break; case Commands.SendMessage: if (userContext.Role == ChatUserRole.Admin && !string.IsNullOrWhiteSpace(activity.Text)) { if (JsonConvert.DeserializeObject <CommandSendMessageProperties>(command.Data.ToString()) is CommandSendMessageProperties properties) { properties.UserId = properties.UserId; properties.From = userContext; //Forcing admin, in case it isn't given by user turnContext.TurnState.Add(typeof(CommandSendMessageProperties).FullName, properties); //We forward to the next middleware await next(cancellationToken).ConfigureAwait(false); } else { throw new Exception("Error while executing command SendMessage"); } } break; default: if (userContext.Role == ChatUserRole.Admin) { throw new Exception($"Command not recognized: '{command.BaseCommand}'."); } break; } }