Ejemplo n.º 1
0
        /// <summary>
        /// Checks the given activity for a possible command.
        ///
        /// All messages that start with a specific command keyword or contain a mention of the bot
        /// ("@<bot name>") are checked for possible commands.
        /// </summary>
        /// <param name="activity">An Activity instance containing a possible command.</param>
        /// <returns>True, if a command was detected and handled. False otherwise.</returns>
        public async virtual Task <bool> HandleCommandAsync(Activity activity)
        {
            bool     wasHandled    = false;
            Activity replyActivity = null;
            Command  command       = ExtractCommand(activity);

            if (command != null)
            {
                Party senderParty = MessagingUtils.CreateSenderParty(activity);

                switch (command.BaseCommand.ToLower())
                {
                case string baseCommand when(baseCommand.Equals(Commands.CommandListOptions)):
                    // Present all command options in a card
                    replyActivity = CommandCardFactory.AddCardToActivity(
                        activity.CreateReply(), CommandCardFactory.CreateCommandOptionsCard(activity.Recipient?.Name));

                    wasHandled = true;
                    break;

                case string baseCommand when(baseCommand.Equals(Commands.CommandAddAggregationChannel)):
                    // Establish the sender's channel/conversation as an aggreated one if not already exists
                    Party aggregationPartyToAdd =
                        new Party(activity.ServiceUrl, activity.ChannelId, null, activity.Conversation);

                    if (_messageRouterManager.RoutingDataManager.AddAggregationParty(aggregationPartyToAdd))
                    {
                        replyActivity = activity.CreateReply(ConversationText.AggregationChannelSet);
                    }
                    else
                    {
                        replyActivity = activity.CreateReply(ConversationText.AggregationChannelAlreadySet);
                    }

                    wasHandled = true;
                    break;

                case string baseCommand when(baseCommand.Equals(Commands.CommandRemoveAggregationChannel)):
                    // Remove the sender's channel/conversation from the list of aggregation channels
                    if (_messageRouterManager.RoutingDataManager.IsAssociatedWithAggregation(senderParty))
                    {
                        Party aggregationPartyToRemove =
                            new Party(activity.ServiceUrl, activity.ChannelId, null, activity.Conversation);

                        if (_messageRouterManager.RoutingDataManager.RemoveAggregationParty(aggregationPartyToRemove))
                        {
                            replyActivity = activity.CreateReply(ConversationText.AggregationChannelRemoved);
                        }
                        else
                        {
                            replyActivity = activity.CreateReply(ConversationText.FailedToRemoveAggregationChannel);
                        }

                        wasHandled = true;
                    }

                    break;

                case string baseCommand when(baseCommand.Equals(Commands.CommandAcceptRequest) || baseCommand.Equals(Commands.CommandRejectRequest)):
                    // Accept/reject conversation request
                    bool doAccept = baseCommand.Equals(Commands.CommandAcceptRequest);

                    if (_messageRouterManager.RoutingDataManager.IsAssociatedWithAggregation(senderParty))
                    {
                        // The party is associated with the aggregation and has the right to accept/reject
                        if (command.Parameters.Count == 0)
                        {
                            replyActivity = activity.CreateReply();

                            IList <Party> pendingRequests =
                                _messageRouterManager.RoutingDataManager.GetPendingRequests();

                            if (pendingRequests.Count == 0)
                            {
                                replyActivity.Text = ConversationText.NoPendingRequests;
                            }
                            else
                            {
                                replyActivity = CommandCardFactory.AddCardToActivity(
                                    replyActivity, CommandCardFactory.CreateAcceptOrRejectCardForMultipleRequests(
                                        pendingRequests, doAccept, activity.Recipient?.Name));
                            }
                        }
                        else if (!doAccept &&
                                 command.Parameters[0].Equals(Commands.CommandParameterAll))
                        {
                            if (!await new MessageRoutingUtils().RejectAllPendingRequestsAsync(
                                    _messageRouterManager, _messageRouterResultHandler))
                            {
                                replyActivity      = activity.CreateReply();
                                replyActivity.Text = ConversationText.FailedToRejectPendingRequests;
                            }
                        }
                        else
                        {
                            string errorMessage = await new MessageRoutingUtils().AcceptOrRejectRequestAsync(
                                _messageRouterManager, _messageRouterResultHandler, senderParty, doAccept, command.Parameters[0]);

                            if (!string.IsNullOrEmpty(errorMessage))
                            {
                                replyActivity      = activity.CreateReply();
                                replyActivity.Text = errorMessage;
                            }
                        }
                    }
#if DEBUG
                    // We shouldn't respond to command attempts by regular users, but I guess
                    // it's okay when debugging
                    else
                    {
                        replyActivity = activity.CreateReply(ConversationText.ConnectionRequestResponseNotAllowed);
                    }
#endif

                    wasHandled = true;
                    break;

                case string baseCommand when(baseCommand.Equals(Commands.CommandDisconnect)):
                    // End the 1:1 conversation
                    IList <MessageRouterResult> messageRouterResults = _messageRouterManager.Disconnect(senderParty);

                    foreach (MessageRouterResult messageRouterResult in messageRouterResults)
                    {
                        await _messageRouterResultHandler.HandleResultAsync(messageRouterResult);
                    }

                    wasHandled = true;
                    break;


                    #region Implementation of debugging commands
#if DEBUG
                case string baseCommand when(baseCommand.Equals(Commands.CommandDeleteAllRoutingData)):
                    // DELETE ALL ROUTING DATA
                    replyActivity = activity.CreateReply(ConversationText.DeletingAllData);

                    _messageRouterManager.RoutingDataManager.DeleteAll();
                    wasHandled = true;
                    break;

                case string baseCommand when(baseCommand.Equals(Commands.CommandList)):
                    bool listAll = command.Parameters.Contains(Commands.CommandParameterAll);

                    replyActivity = activity.CreateReply();
                    string replyMessageText = string.Empty;

                    if (listAll || command.Parameters.Contains(Commands.CommandParameterParties))
                    {
                        // List user and bot parties
                        IRoutingDataManager routingDataManager = _messageRouterManager.RoutingDataManager;
                        string partiesAsString = PartyListToString(routingDataManager.GetUserParties());

                        replyMessageText += string.IsNullOrEmpty(partiesAsString)
                                ? $"{ConversationText.NoUsersStored}{StringAndCharConstants.LineBreak}"
                                : $"{ConversationText.Users}:{StringAndCharConstants.LineBreak}{partiesAsString}{StringAndCharConstants.LineBreak}";

                        partiesAsString = PartyListToString(routingDataManager.GetBotParties());

                        replyMessageText += string.IsNullOrEmpty(partiesAsString)
                                ? $"{ConversationText.NoBotsStored}{StringAndCharConstants.LineBreak}"
                                : $"{ConversationText.Bots}:{StringAndCharConstants.LineBreak}{partiesAsString}{StringAndCharConstants.LineBreak}";

                        wasHandled = true;
                    }

                    if (listAll || command.Parameters.Contains(Commands.CommandParameterRequests))
                    {
                        // List all pending requests
                        IList <Attachment> attachments =
                            CommandCardFactory.CreateMultipleRequestCards(
                                _messageRouterManager.RoutingDataManager.GetPendingRequests(), activity.Recipient?.Name);

                        if (attachments.Count > 0)
                        {
                            replyMessageText += string.Format(ConversationText.PendingRequestsFoundWithCount, attachments.Count);
                            replyMessageText += StringAndCharConstants.LineBreak;
                            replyActivity.AttachmentLayout = AttachmentLayoutTypes.Carousel;
                            replyActivity.Attachments      = attachments;
                        }
                        else
                        {
                            replyMessageText += $"{ConversationText.NoPendingRequests}{StringAndCharConstants.LineBreak}";
                        }

                        wasHandled = true;
                    }

                    if (listAll || command.Parameters.Contains(Commands.CommandParameterConnections))
                    {
                        // List all connections (conversations)
                        string connectionsAsString = _messageRouterManager.RoutingDataManager.ConnectionsToString();

                        replyMessageText += string.IsNullOrEmpty(connectionsAsString)
                                ? $"{ConversationText.NoConversations}{StringAndCharConstants.LineBreak}"
                                : $"{connectionsAsString}{StringAndCharConstants.LineBreak}";

                        wasHandled = true;
                    }

                    if (listAll || command.Parameters.Contains(Commands.CommandParameterResults))
                    {
                        // List all logged message router results
                        string resultsAsString = _messageRouterManager.RoutingDataManager.GetLastMessageRouterResults();

                        replyMessageText += string.IsNullOrEmpty(resultsAsString)
                                ? $"{ConversationText.NoResults}{StringAndCharConstants.LineBreak}"
                                : $"{resultsAsString}{StringAndCharConstants.LineBreak}";

                        wasHandled = true;
                    }

                    if (!wasHandled)
                    {
                        replyMessageText = ConversationText.InvalidOrMissingCommandParameter;
                    }

                    replyActivity.Text = replyMessageText;
                    break;
#endif
                    #endregion

                default:
                    replyActivity = activity.CreateReply(string.Format(ConversationText.CommandNotRecognized, command.BaseCommand));
                    break;
                }

                if (replyActivity != null)
                {
                    ConnectorClient connector = new ConnectorClient(new Uri(activity.ServiceUrl));
                    await connector.Conversations.ReplyToActivityAsync(replyActivity);
                }
            }

            return(wasHandled);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// All messages where the bot was mentioned ("@<bot name>) are checked for possible commands.
        /// See IBotCommandHandler.cs for more information.
        /// </summary>
        public async virtual Task <bool> HandleCommandAsync(Activity activity)
        {
            bool     wasHandled    = false;
            Activity replyActivity = null;

            // Sole use of mentions here is unreliable for Skype & Webchat
            // Therefore just parse the text for any bot id reference
            if (WasBotAddressedDirectly(activity) ||
                activity.Text.Contains(activity.Recipient.Name) ||
                (!string.IsNullOrEmpty(activity.Text) && activity.Text.StartsWith($"{Commands.CommandKeyword} ")))
            {
                //activity.RemoveRecipientMention(); not working here
                //string message = MessagingUtils.StripMentionsFromMessage(activity);
                string message = activity.Text.Replace($"@{activity.Recipient.Name}", "").Trim();
                if (message.StartsWith($"{Commands.CommandKeyword} "))
                {
                    message = message.Remove(0, Commands.CommandKeyword.Length + 1);
                }

                switch (message?.ToLower())
                {
                case string s when(s.StartsWith(Commands.CommandEndEngagement)):
                {
                    // End the 1:1 conversation
                    Party senderParty = MessagingUtils.CreateSenderParty(activity);

                    if (await MessageRouterManager.Instance.EndEngagementAsync(senderParty) == false)
                    {
                        replyActivity = activity.CreateReply("Failed to end the engagement");
                    }
                    wasHandled = true;
                    break;
                }

                case string s when(s.StartsWith(Commands.CommandAddAggregationChannel)):
                {
                    // Check if the Aggregation Party already exists
                    /* not a specific user, but a channel/conv */
                    Party aggregationParty = new Party(activity.ServiceUrl, activity.ChannelId, null, activity.Conversation);

                    // Establish the sender's channel/conversation as an aggreated one if not already exists
                    if (_routingDataManager.AddAggregationParty(aggregationParty))
                    {
                        replyActivity = activity.CreateReply("This channel/conversation is now where the requests are aggregated");
                    }
                    else
                    {
                        replyActivity = activity.CreateReply("This channel/conversation is already receiving requests");
                    }
                    wasHandled = true;
                    break;
                }

                case string s when(s.StartsWith(Commands.CommandAcceptRequest) || s.StartsWith(Commands.CommandRejectRequest)):
                {
                    // Accept/reject conversation request
                    bool  doAccept    = s.StartsWith(Commands.CommandAcceptRequest);
                    Party senderParty = MessagingUtils.CreateSenderParty(activity);

                    if (_routingDataManager.IsAssociatedWithAggregation(senderParty))
                    {
                        // The party is associated with the aggregation and has the right to accept/reject
                        Party senderInConversation =
                            _routingDataManager.FindEngagedPartyByChannel(senderParty.ChannelId, senderParty.ChannelAccount);
                        replyActivity = await GetEngagementActivity(activity, replyActivity, message, doAccept, senderParty, senderInConversation);

                        wasHandled = true;
                    }
                    break;
                }

                case string s when(s.StartsWith(Commands.CommandListOptions)):
                {
                    replyActivity = await GetAvaialableAgentOptionsCard(activity);

                    wasHandled = true;
                    break;
                }

                    #region Agent debugging commands

                // TODO: Remove from production
                case string s when(s.StartsWith(Commands.CommandDeleteAllRoutingData)):
                {
                    ConnectorClient connector = new ConnectorClient(new Uri(activity.ServiceUrl));
                    await connector.Conversations.ReplyToActivityAsync(activity.CreateReply("Deleting all data..."));

                    _routingDataManager.DeleteAll();
                    wasHandled = true;
                    break;
                }

                case string s when(s.StartsWith(Commands.CommandListAllParties)):
                {
                    string replyMessage = string.Empty;
                    string parties      = string.Empty;

                    foreach (Party userParty in _routingDataManager.GetUserParties())
                    {
                        parties += userParty.ToString() + "\n";
                    }

                    if (string.IsNullOrEmpty(parties))
                    {
                        replyMessage = "No user parties;\n";
                    }
                    else
                    {
                        replyMessage = "Users:\n" + parties;
                    }

                    parties = string.Empty;

                    foreach (Party botParty in _routingDataManager.GetBotParties())
                    {
                        parties += botParty.ToString() + "\n";
                    }

                    if (string.IsNullOrEmpty(parties))
                    {
                        replyMessage += "No bot parties";
                    }
                    else
                    {
                        replyMessage += "Bot:\n" + parties;
                    }

                    replyActivity = activity.CreateReply(replyMessage);
                    wasHandled    = true;
                    break;
                }

                case string s when(s.StartsWith(Commands.CommandListPendingRequests)):
                {
                    var attachments = new List <Attachment>();

                    foreach (Party party in _routingDataManager.GetPendingRequests())
                    {
                        attachments.Add(MessagingUtils.GetAgentRequestHeroCard(party.ChannelAccount.Name, party.ChannelId, party.ChannelAccount.Id, party));
                    }

                    replyActivity = activity.CreateReply("No pending requests");
                    if (attachments.Count > 0)
                    {
                        replyActivity.Text             = $"{attachments.Count} Pending requests found:";
                        replyActivity.AttachmentLayout = AttachmentLayoutTypes.Carousel;
                        replyActivity.Attachments      = attachments;
                    }
                    wasHandled = true;
                    break;
                }

                case string s when(s.StartsWith(Commands.CommandListEngagements)):
                {
                    string parties = _routingDataManager.EngagementsAsString();

                    if (string.IsNullOrEmpty(parties))
                    {
                        replyActivity = activity.CreateReply("No conversations");
                    }
                    else
                    {
                        replyActivity = activity.CreateReply(parties);
                    }

                    wasHandled = true;
                    break;
                }

#if DEBUG
                case string s when(s.StartsWith(Commands.CommandListLastMessageRouterResults)):
                {
                    LocalRoutingDataManager routingDataManager =
                        (MessageRouterManager.Instance.RoutingDataManager as LocalRoutingDataManager);

                    if (routingDataManager != null)
                    {
                        string resultsAsString = routingDataManager.GetLastMessageRouterResults();
                        replyActivity = activity.CreateReply($"{(string.IsNullOrEmpty(resultsAsString) ? "No results" : resultsAsString)}");
                        wasHandled    = true;
                    }
                    break;
                }
#endif

                    #endregion
                default:
                    replyActivity = activity.CreateReply($"Command \"{message}\" not recognized");
                    break;
                }

                if (replyActivity != null)
                {
                    ConnectorClient connector = new ConnectorClient(new Uri(activity.ServiceUrl));
                    await connector.Conversations.ReplyToActivityAsync(replyActivity);
                }
            }

            return(wasHandled);
        }
        /// <summary>
        /// All messages where the bot was mentioned ("@<bot name>) are checked for possible commands.
        /// See IBotCommandHandler.cs for more information.
        /// </summary>
        public async virtual Task <bool> HandleCommandAsync(Activity activity)
        {
            bool     wasHandled    = false;
            Activity replyActivity = null;

            if (WasBotAddressedDirectly(activity) ||
                (!string.IsNullOrEmpty(activity.Text) && activity.Text.StartsWith($"{Commands.CommandKeyword} ")))
            {
                string message = MessagingUtils.StripMentionsFromMessage(activity);

                if (message.StartsWith($"{Commands.CommandKeyword} "))
                {
                    message = message.Remove(0, Commands.CommandKeyword.Length + 1);
                }

                string messageInLowerCase = message?.ToLower();

                if (messageInLowerCase.StartsWith(Commands.CommandAddAggregationChannel))
                {
                    // Check if the Aggregation Party already exists
                    Party aggregationParty = new Party(
                        activity.ServiceUrl,
                        activity.ChannelId,
                        /* not a specific user, but a channel/conv */ null,
                        activity.Conversation);

                    // Establish the sender's channel/conversation as an aggreated one
                    if (_routingDataManager.AddAggregationParty(aggregationParty))
                    {
                        replyActivity = activity.CreateReply(
                            "This channel/conversation is now where the requests are aggregated");
                    }
                    else
                    {
                        // Aggregation already exists
                        replyActivity = activity.CreateReply(
                            "This channel/conversation is already receiving requests");
                    }

                    wasHandled = true;
                }
                else if (messageInLowerCase.StartsWith(Commands.CommandAcceptRequest) ||
                         messageInLowerCase.StartsWith(Commands.CommandRejectRequest))
                {
                    // Accept/reject conversation request
                    bool  doAccept    = messageInLowerCase.StartsWith(Commands.CommandAcceptRequest);
                    Party senderParty = MessagingUtils.CreateSenderParty(activity);

                    if (_routingDataManager.IsAssociatedWithAggregation(senderParty))
                    {
                        // The party is associated with the aggregation and has the right to accept/reject
                        Party senderInConversation =
                            _routingDataManager.FindEngagedPartyByChannel(senderParty.ChannelId, senderParty.ChannelAccount);

                        if (senderInConversation == null || !_routingDataManager.IsEngaged(senderInConversation, EngagementProfile.Owner))
                        {
                            if (_routingDataManager.GetPendingRequests().Count > 0)
                            {
                                // The name of the user to accept should be the second word
                                string[] splitMessage = message.Split(' ');

                                if (splitMessage.Count() > 1 && !string.IsNullOrEmpty(splitMessage[1]))
                                {
                                    Party  partyToAcceptOrReject = null;
                                    string errorMessage          = "";

                                    try
                                    {
                                        partyToAcceptOrReject = _routingDataManager.GetPendingRequests().Single(
                                            party => (party.ChannelAccount != null &&
                                                      !string.IsNullOrEmpty(party.ChannelAccount.Id) &&
                                                      party.ChannelAccount.Id.Equals(splitMessage[1])));
                                    }
                                    catch (InvalidOperationException e)
                                    {
                                        errorMessage = e.Message;
                                    }

                                    if (partyToAcceptOrReject != null)
                                    {
                                        MessageRouterManager messageRouterManager = MessageRouterManager.Instance;

                                        if (doAccept)
                                        {
                                            await messageRouterManager.AddEngagementAsync(senderParty, partyToAcceptOrReject);
                                        }
                                        else
                                        {
                                            await messageRouterManager.RejectPendingRequestAsync(partyToAcceptOrReject, senderParty);
                                        }
                                    }
                                    else
                                    {
                                        replyActivity = activity.CreateReply(
                                            $"Could not find a pending request for user {splitMessage[1]}; {errorMessage}");
                                    }
                                }
                                else
                                {
                                    replyActivity = activity.CreateReply("User name missing");
                                }
                            }
                            else
                            {
                                replyActivity = activity.CreateReply("No pending requests");
                            }
                        }
                        else
                        {
                            Party otherParty = _routingDataManager.GetEngagedCounterpart(senderInConversation);

                            if (otherParty != null)
                            {
                                replyActivity = activity.CreateReply($"You are already engaged in a conversation with {otherParty.ChannelAccount.Name}");
                            }
                            else
                            {
                                replyActivity = activity.CreateReply("An error occured");
                            }
                        }

                        wasHandled = true;
                    }
                }
                else if (messageInLowerCase.StartsWith(Commands.CommandEndEngagement))
                {
                    // End the 1:1 conversation
                    Party senderParty = MessagingUtils.CreateSenderParty(activity);

                    if (await MessageRouterManager.Instance.EndEngagementAsync(senderParty) == false)
                    {
                        replyActivity = activity.CreateReply("Failed to end the engagement");
                    }

                    wasHandled = true;
                }

                /*
                 * NOTE: Either remove these commands or make them unaccessible should you use this
                 * code in production!
                 */
                #region Commands for debugging
                else if (messageInLowerCase.StartsWith(Commands.CommandDeleteAllRoutingData))
                {
                    ConnectorClient connector = new ConnectorClient(new Uri(activity.ServiceUrl));
                    await connector.Conversations.ReplyToActivityAsync(activity.CreateReply("Deleting all data..."));

                    _routingDataManager.DeleteAll();

                    wasHandled = true;
                }
                else if (messageInLowerCase.StartsWith(Commands.CommandListAllParties))
                {
                    string replyMessage = string.Empty;
                    string parties      = string.Empty;

                    foreach (Party userParty in _routingDataManager.GetUserParties())
                    {
                        parties += userParty.ToString() + "\n";
                    }

                    if (string.IsNullOrEmpty(parties))
                    {
                        replyMessage = "No user parties;\n";
                    }
                    else
                    {
                        replyMessage = "Users:\n" + parties;
                    }

                    parties = string.Empty;

                    foreach (Party botParty in _routingDataManager.GetBotParties())
                    {
                        parties += botParty.ToString() + "\n";
                    }

                    if (string.IsNullOrEmpty(parties))
                    {
                        replyMessage += "No bot parties";
                    }
                    else
                    {
                        replyMessage += "Bot:\n" + parties;
                    }

                    replyActivity = activity.CreateReply(replyMessage);
                    wasHandled    = true;
                }
                else if (messageInLowerCase.StartsWith(Commands.CommandListPendingRequests))
                {
                    string parties = string.Empty;

                    foreach (Party party in _routingDataManager.GetPendingRequests())
                    {
                        parties += party.ToString() + "\n";
                    }

                    if (parties.Length == 0)
                    {
                        parties = "No pending requests";
                    }

                    replyActivity = activity.CreateReply(parties);
                    wasHandled    = true;
                }
                else if (messageInLowerCase.StartsWith(Commands.CommandListEngagements))
                {
                    string parties = _routingDataManager.EngagementsAsString();

                    if (string.IsNullOrEmpty(parties))
                    {
                        replyActivity = activity.CreateReply("No conversations");
                    }
                    else
                    {
                        replyActivity = activity.CreateReply(parties);
                    }

                    wasHandled = true;
                }
#if DEBUG
                else if (messageInLowerCase.StartsWith(Commands.CommandListLastMessageRouterResults))
                {
                    LocalRoutingDataManager routingDataManager =
                        (MessageRouterManager.Instance.RoutingDataManager as LocalRoutingDataManager);

                    if (routingDataManager != null)
                    {
                        string resultsAsString = routingDataManager.GetLastMessageRouterResults();
                        replyActivity = activity.CreateReply($"{(string.IsNullOrEmpty(resultsAsString) ? "No results" : resultsAsString)}");
                        wasHandled    = true;
                    }
                }
#endif
                #endregion Commands for debugging

                else
                {
                    replyActivity = activity.CreateReply($"Command \"{messageInLowerCase}\" not recognized");
                }
            }

            if (replyActivity != null)
            {
                ConnectorClient connector = new ConnectorClient(new Uri(activity.ServiceUrl));
                await connector.Conversations.ReplyToActivityAsync(replyActivity);
            }

            return(wasHandled);
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Checks the given activity for a possible command.
        ///
        /// All messages that start with a specific command keyword or contain a mention of the bot
        /// ("@<bot name>") are checked for possible commands.
        /// </summary>
        /// <param name="activity">An Activity instance containing a possible command.</param>
        /// <returns>True, if a command was detected and handled. False otherwise.</returns>
        public async virtual Task <bool> HandleCommandAsync(Activity activity)
        {
            bool     wasHandled    = false;
            Activity replyActivity = null;

            if ((!string.IsNullOrEmpty(activity.Text) && activity.Text.StartsWith($"{Commands.CommandKeyword} ")) ||
                WasBotAddressedDirectly(activity, false))
            {
                string commandMessage = ExtractCleanCommandMessage(activity);
                Party  senderParty    = MessagingUtils.CreateSenderParty(activity);

                switch (commandMessage.ToLower())
                {
                case string command when(command.StartsWith(Commands.CommandListOptions)):
                    // Present all command options in a card
                    replyActivity = CreateCommandOptionsCard(activity);

                    wasHandled = true;
                    break;

                case string command when(command.StartsWith(Commands.CommandAddAggregationChannel)):
                    // Establish the sender's channel/conversation as an aggreated one if not already exists
                    Party aggregationParty = new Party(activity.ServiceUrl, activity.ChannelId, null, activity.Conversation);

                    if (_messageRouterManager.RoutingDataManager.AddAggregationParty(aggregationParty))
                    {
                        replyActivity = activity.CreateReply("This channel/conversation is now where the requests are aggregated");
                    }
                    else
                    {
                        replyActivity = activity.CreateReply("This channel/conversation is already receiving requests");
                    }

                    wasHandled = true;
                    break;

                case string command when(command.StartsWith(Commands.CommandAcceptRequest) || command.StartsWith(Commands.CommandRejectRequest)):
                    // Accept/reject conversation request
                    bool doAccept = command.StartsWith(Commands.CommandAcceptRequest);

                    if (_messageRouterManager.RoutingDataManager.IsAssociatedWithAggregation(senderParty))
                    {
                        // The party is associated with the aggregation and has the right to accept/reject
                        string errorMessage = await AcceptOrRejectRequestAsync(senderParty, commandMessage, doAccept);

                        if (!string.IsNullOrEmpty(errorMessage))
                        {
                            replyActivity = activity.CreateReply(errorMessage);
                        }
                    }
                    else
                    {
                        replyActivity = activity.CreateReply("Sorry, you are not allowed to accept/reject requests");
                    }

                    wasHandled = true;
                    break;

                case string command when(command.StartsWith(Commands.CommandDisconnect)):
                    // End the 1:1 conversation
                    IList <MessageRouterResult> messageRouterResults = _messageRouterManager.Disconnect(senderParty);

                    foreach (MessageRouterResult messageRouterResult in messageRouterResults)
                    {
                        await _messageRouterResultHandler.HandleResultAsync(messageRouterResult);
                    }

                    wasHandled = true;
                    break;


                    #region Implementation of debugging commands
#if DEBUG
                case string command when(command.StartsWith(Commands.CommandDeleteAllRoutingData)):
                    // DELETE ALL ROUTING DATA
                    await _messageRouterManager.BroadcastMessageToAggregationChannelsAsync(
                        $"Deleting all data as requested by \"{senderParty.ChannelAccount?.Name}\"...");

                    replyActivity = activity.CreateReply("Deleting all data...");
                    _messageRouterManager.RoutingDataManager.DeleteAll();
                    wasHandled = true;
                    break;

                case string command when(command.StartsWith(Commands.CommandListAllParties)):
                    // List user and bot parties
                    IRoutingDataManager routingDataManager = _messageRouterManager.RoutingDataManager;

                    string replyMessage    = string.Empty;
                    string partiesAsString = PartyListToString(routingDataManager.GetUserParties());

                    if (string.IsNullOrEmpty(partiesAsString))
                    {
                        replyMessage = $"No user parties{LineBreak}";
                    }
                    else
                    {
                        replyMessage = $"Users:{LineBreak}{partiesAsString}";
                    }

                    partiesAsString = PartyListToString(routingDataManager.GetBotParties());

                    if (string.IsNullOrEmpty(partiesAsString))
                    {
                        replyMessage += "No bot parties";
                    }
                    else
                    {
                        replyMessage += $"Bot:{LineBreak}{partiesAsString}";
                    }

                    replyActivity = activity.CreateReply(replyMessage);
                    wasHandled    = true;
                    break;

                case string command when(command.StartsWith(Commands.CommandListPendingRequests)):
                    // List all pending requests
                    var attachments = new List <Attachment>();

                    foreach (Party party in _messageRouterManager.RoutingDataManager.GetPendingRequests())
                    {
                        attachments.Add(CreateRequestCard(party, activity.Recipient.Name));
                    }

                    if (attachments.Count > 0)
                    {
                        replyActivity = activity.CreateReply($"{attachments.Count} pending request(s) found:");
                        replyActivity.AttachmentLayout = AttachmentLayoutTypes.Carousel;
                        replyActivity.Attachments      = attachments;
                    }
                    else
                    {
                        replyActivity = activity.CreateReply("No pending requests");
                    }

                    wasHandled = true;
                    break;

                case string command when(command.StartsWith(Commands.CommandListConnections)):
                    // List all connections (conversations)
                    string parties = _messageRouterManager.RoutingDataManager.ConnectionsToString();

                    if (string.IsNullOrEmpty(parties))
                    {
                        replyActivity = activity.CreateReply("No conversations");
                    }
                    else
                    {
                        replyActivity = activity.CreateReply(parties);
                    }

                    wasHandled = true;
                    break;

                case string command when(command.StartsWith(Commands.CommandListLastMessageRouterResults)):
                    // List all logged message router results
                    string resultsAsString = _messageRouterManager.RoutingDataManager.GetLastMessageRouterResults();

                    replyActivity = activity.CreateReply($"{(string.IsNullOrEmpty(resultsAsString) ? "No results" : resultsAsString)}");
                    wasHandled    = true;
                    break;
#endif
                    #endregion

                default:
                    replyActivity = activity.CreateReply($"Command \"{commandMessage}\" not recognized");
                    break;
                }

                if (replyActivity != null)
                {
                    ConnectorClient connector = new ConnectorClient(new Uri(activity.ServiceUrl));
                    await connector.Conversations.ReplyToActivityAsync(replyActivity);
                }
            }

            return(wasHandled);
        }