Beispiel #1
0
        /// <summary>
        /// Runs the logic for the chatbot action and records the start and stop of the action.
        /// </summary>
        /// <param name="action"></param>
        /// <param name="incomingChatMessage"></param>
        /// <param name="chatRoom"></param>
        private void RunChatbotAction(ChatbotAction action, Message incomingChatMessage, Room chatRoom)
        {
            // Record as started.
            var id = RunningChatbotActionsManager.MarkChatbotActionAsStarted(
                action.ActionName,
                incomingChatMessage.Author.Name,
                incomingChatMessage.Author.ID);

            try
            {
                action.RunAction(incomingChatMessage, chatRoom);

                // If the command was "stop bot", need to trigger a program shutdown.
                if (action is StopBot)
                {
                    if (StopBotCommandIssued != null)
                    {
                        StopBotCommandIssued(this, new EventArgs());
                    }
                }
            }
            catch (Exception ex)
            {
                // ChatMessageProcessor is responsible for outputting any errors that occur
                // while running chatbot actions. Anything outside of the RunAction() method
                // should be handled higher up.
                TellChatAboutErrorWhileRunningAction(ex, chatRoom, action);
            }

            // Mark as finished.
            RunningChatbotActionsManager.MarkChatbotActionAsFinished(id);
        }
Beispiel #2
0
        /// <summary>
        /// Determines if the specified chat user has the correct permissions to run the chatbot action.
        /// </summary>
        /// <param name="actionToRun">The action the user would like to run.</param>
        /// <param name="chatUserId">The chat user who initiated this request.</param>
        /// <returns></returns>
        private bool DoesUserHavePermissionToRunAction(ChatbotAction actionToRun, int chatUserId)
        {
            //if the command does not require the user to be in any permission groups
            if (actionToRun.UserMustBeInAnyPermissionGroupToRun == false)
            {
                //this is a "public" command
                return(true);
            }

            //command requires permission. look up user in database

            using (var db = new DatabaseContext())
            {
                var dbUser = db.Users
                             .Include(x => x.Permissions)
                             .Single(x => x.ProfileId == chatUserId);

                //there are two configurations for the permission required for the command:
                // 1) a specific group is required
                // 2) any group is required

                if (actionToRun.RequiredPermissionGroup != null)
                {
                    //the user must be in the named group in order to run
                    var userPermissionGroups = dbUser.Permissions
                                               .Select(x => x.PermissionGroup);

                    return(actionToRun.RequiredPermissionGroup.Value.In(userPermissionGroups));
                }
                else
                {
                    //the user must be in ANY permission group to run
                    return(dbUser.Permissions.Any());
                }
            }
        }
Beispiel #3
0
        /// <summary>
        /// Main entry point for the class.
        /// Takes a message revived from chat, determines what action should be taken, then performs that action.
        /// </summary>
        /// <param name="incomingChatMessage">The chat message that was said.</param>
        /// <param name="chatRoom">The room the chat message was said in.</param>
        public void ProcessPing(Message incomingChatMessage, Room chatRoom)
        {
            var           isReplyToChatbot   = false;
            ChatbotAction chatbotActionToRun = null;

            EnsureAuthorInDatabase(incomingChatMessage);

            // Is the message a confirmation to a command suggestion?
            if (yesReply.IsMatch(incomingChatMessage.Content))
            {
                var cmd = unrecdCmds.FirstOrDefault(kv => kv.Value.Key.ID == incomingChatMessage.ParentID &&
                                                    kv.Key.Author.ID == incomingChatMessage.Author.ID);

                if (cmd.Key != null)
                {
                    // What's a good sign of laziness? ..... Using reflection.
                    typeof(Message)
                    .GetProperty("Content")
                    .SetValue(incomingChatMessage, cmd.Value.Value);

                    KeyValuePair <Message, string> temp;
                    unrecdCmds.TryRemove(cmd.Key, out temp);
                }
            }

            if (chatbotActionToRun == null)
            {
                // Determine the list of possible actions that work from the message.
                var possibleChatbotActionsToRun = ChatbotActionRegister.AllChatActions
                                                  .Where(x => x.DoesChatMessageActiveAction(incomingChatMessage, true))
                                                  .ToList();

                if (possibleChatbotActionsToRun.Count > 1)
                {
                    throw new Exception("More than one possible chat bot action to run for the input '{0}'"
                                        .FormatSafely(incomingChatMessage.Content));
                }

                if (!possibleChatbotActionsToRun.Any())
                {
                    var results = simCmd.FindCommand(incomingChatMessage.Content);
                    var msg     = "Sorry, I don't understand that. ";

                    if (results != null)
                    {
                        if (!results.OptionsSubstituted)
                        {
                            msg += $"Maybe you meant `{results.SuggestedCmdText}`.";
                        }
                        else
                        {
                            msg += $"Did you mean `{results.SuggestedCmdText}`?";
                        }

                        Message reply;
                        try
                        {
                            reply = chatRoom.PostReply(incomingChatMessage, msg);
                            if (reply == null)
                            {
                                throw new InvalidOperationException("Unable to post message");
                            }

                            if (results.OptionsSubstituted)
                            {
                                unrecdCmds[incomingChatMessage] = new KeyValuePair <Message, string>(reply, results.SuggestedCmdText);
                            }
                        }
                        catch (DuplicateMessageException)
                        {
                            // Not sure what to do here atm.
                        }
                    }

                    return;
                }

                // You have a single item to run.
                chatbotActionToRun = possibleChatbotActionsToRun.Single();
            }

            // Now, do you have permission to run it? If you are a mod the answer is yes, else you need to check.
            if (incomingChatMessage.Author.IsMod || DoesUserHavePermissionToRunAction(chatbotActionToRun, incomingChatMessage.Author.ID))
            {
                // Have permission, run it.
                RunChatbotAction(chatbotActionToRun, incomingChatMessage, chatRoom);
            }
            else
            {
                // Don't have permission, tell the user only if it's a command.
                if (isReplyToChatbot)
                {
                    //a person can be denied a command for one of two reasons:
                    // 1) they are not in the required permission group
                    // 2) they are not in ANY permission groups
                    // this is dependent on the command they try to run

                    if (chatbotActionToRun.RequiredPermissionGroup != null)
                    {
                        //the command required a specific group which the user was not a part of
                        chatRoom.PostReplyOrThrow(incomingChatMessage,
                                                  $"Sorry, you are not in the {chatbotActionToRun.RequiredPermissionGroup} permission group. You can request access by running `request permission to {chatbotActionToRun.RequiredPermissionGroup}`.");
                    }
                    else
                    {
                        //the command can be ran by anyone who is in at least one permission group,
                        //but this user is not in any
                        chatRoom.PostReplyOrThrow(incomingChatMessage,
                                                  $"Sorry, you need to be in at least one permission group to run this command. Run `{ChatbotActionRegister.GetChatBotActionUsage<Membership>()}` to see the list of groups.");
                    }
                }
                // Don't do anything for triggers.
            }
        }
Beispiel #4
0
        /// <summary>
        /// Call this method if you get an error while running a ChatbotAction.
        /// This will attempt to send a message to chat about error in a standard format.
        /// </summary>
        /// <param name="ex"></param>
        /// <param name="chatRoom"></param>
        /// <param name="actionToRun"></param>
        private void TellChatAboutErrorWhileRunningAction(Exception ex, Room chatRoom, ChatbotAction actionToRun)
        {
            var headerLine = $"I hit an error while trying to run '{actionToRun.ActionName}':";

            var errorMessage = "    " + ex.FullErrorMessage(Environment.NewLine + "    ");

            var stackTraceMessage = ex.GetAllStackTraces();

            var detailsLine = errorMessage + Environment.NewLine +
                              "    ----" + Environment.NewLine +
                              stackTraceMessage;

            chatRoom.PostMessageOrThrow(headerLine);
            chatRoom.PostMessageOrThrow(detailsLine);
        }
Beispiel #5
0
        private string GetCommandText(string message, ChatbotAction act, double threshold)
        {
            var cmdOpts  = new List <List <string> >();
            var msgWords = message.Split(new[] { " " }, StringSplitOptions.RemoveEmptyEntries);
            var cmdWords = cmdOptionsReg
                           .Replace(act.ActionUsage, "")
                           .Split(new[] { " " }, StringSplitOptions.RemoveEmptyEntries);
            var ignoreWords = new List <int>();

            for (var i = 0; i < msgWords.Length; i++)
            {
                var dist = double.MaxValue;

                for (var j = 0; j < cmdWords.Length; j++)
                {
                    var d = Calculate(msgWords[i], cmdWords[j], int.MaxValue);

                    if (d < dist)
                    {
                        dist = d;
                    }
                }

                if ((msgWords[i].Length - dist) / msgWords[i].Length > (threshold / 1.5))
                {
                    ignoreWords.Add(i);
                    cmdOpts.Add(new List <string>());
                }
            }

            if (ignoreWords.Count == msgWords.Length)
            {
                return(act.ActionUsage);
            }

            var curCmdOptsInd = 0;

            for (var i = 0; i < msgWords.Length; i++)
            {
                if (ignoreWords.Contains(i))
                {
                    if (ignoreWords[0] != i)
                    {
                        curCmdOptsInd++;
                    }

                    continue;
                }
                cmdOpts[curCmdOptsInd].Add(msgWords[i]);
            }
            cmdOpts = cmdOpts.Where(x => x.Count > 0).ToList();

            var ms         = cmdOptionsReg.Matches(act.ActionUsage);
            var cmdTxt     = act.ActionUsage;
            var globalDiff = 0;
            var cmdOptI    = 0;

            foreach (Match m in ms)
            {
                if (cmdOptI >= cmdOpts.Count)
                {
                    cmdTxt = cmdOptionsReg.Replace(cmdTxt, "");
                    break;
                }

                var localDiff = 0;
                cmdTxt = cmdTxt.Remove(m.Index + globalDiff, m.Length);
                foreach (var opt in cmdOpts[cmdOptI])
                {
                    cmdTxt     = cmdTxt.Insert(m.Index + localDiff + globalDiff, opt + " ");
                    localDiff += opt.Length + 1;
                }
                globalDiff += localDiff - m.Length;
                cmdOptI++;
            }

            return(cmdTxt.Replace("  ", " ").Trim());
        }