slack-smart-bot 0.9.6 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.yardopts +5 -1
- data/README.md +80 -175
- data/lib/slack-smart-bot.rb +95 -1276
- data/lib/slack-smart-bot_rules.rb +50 -69
- data/lib/slack/smart-bot/comm.rb +197 -0
- data/lib/slack/smart-bot/commands/general/bot_help.rb +74 -0
- data/lib/slack/smart-bot/commands/general/bot_status.rb +41 -0
- data/lib/slack/smart-bot/commands/general/bye_bot.rb +17 -0
- data/lib/slack/smart-bot/commands/general/hi_bot.rb +24 -0
- data/lib/slack/smart-bot/commands/general/stop_using_rules.rb +44 -0
- data/lib/slack/smart-bot/commands/general/use_rules.rb +48 -0
- data/lib/slack/smart-bot/commands/on_bot/add_shortcut.rb +64 -0
- data/lib/slack/smart-bot/commands/on_bot/admin/add_routine.rb +87 -0
- data/lib/slack/smart-bot/commands/on_bot/admin/extend_rules.rb +63 -0
- data/lib/slack/smart-bot/commands/on_bot/admin/pause_bot.rb +21 -0
- data/lib/slack/smart-bot/commands/on_bot/admin/pause_routine.rb +26 -0
- data/lib/slack/smart-bot/commands/on_bot/admin/remove_routine.rb +28 -0
- data/lib/slack/smart-bot/commands/on_bot/admin/run_routine.rb +53 -0
- data/lib/slack/smart-bot/commands/on_bot/admin/see_routines.rb +57 -0
- data/lib/slack/smart-bot/commands/on_bot/admin/start_bot.rb +20 -0
- data/lib/slack/smart-bot/commands/on_bot/admin/start_routine.rb +27 -0
- data/lib/slack/smart-bot/commands/on_bot/admin/stop_using_rules_on.rb +30 -0
- data/lib/slack/smart-bot/commands/on_bot/delete_shortcut.rb +41 -0
- data/lib/slack/smart-bot/commands/on_bot/ruby_code.rb +48 -0
- data/lib/slack/smart-bot/commands/on_bot/see_shortcuts.rb +32 -0
- data/lib/slack/smart-bot/commands/on_extended/bot_rules.rb +37 -0
- data/lib/slack/smart-bot/commands/on_master/admin/kill_bot_on_channel.rb +38 -0
- data/lib/slack/smart-bot/commands/on_master/admin_master/exit_bot.rb +42 -0
- data/lib/slack/smart-bot/commands/on_master/admin_master/notify_message.rb +35 -0
- data/lib/slack/smart-bot/commands/on_master/create_bot.rb +94 -0
- data/lib/slack/smart-bot/listen.rb +36 -0
- data/lib/slack/smart-bot/process.rb +169 -0
- data/lib/slack/smart-bot/process_first.rb +201 -0
- data/lib/slack/smart-bot/treat_message.rb +139 -0
- data/lib/slack/smart-bot/utils.rb +299 -0
- metadata +71 -5
| @@ -0,0 +1,35 @@ | |
| 1 | 
            +
            class SlackSmartBot
         | 
| 2 | 
            +
              # helpmaster: ----------------------------------------------
         | 
| 3 | 
            +
              # helpmaster: `notify MESSAGE`
         | 
| 4 | 
            +
              # helpmaster: `notify all MESSAGE`
         | 
| 5 | 
            +
              # helpmaster: `notify #CHANNEL_NAME MESSAGE`
         | 
| 6 | 
            +
              # helpmaster:    It will send a notification message to all bot channels
         | 
| 7 | 
            +
              # helpmaster:    It will send a notification message to all channels the bot joined and private conversations with the bot
         | 
| 8 | 
            +
              # helpmaster:    It will send a notification message to the specified channel and to its extended channels
         | 
| 9 | 
            +
              # helpmaster:    Only works if you are on Master channel and you are a master admin user
         | 
| 10 | 
            +
              # helpmaster:
         | 
| 11 | 
            +
              def notify_message(dest, from, where, message)
         | 
| 12 | 
            +
                if ON_MASTER_BOT
         | 
| 13 | 
            +
                  if ADMIN_USERS.include?(from) #admin user
         | 
| 14 | 
            +
                    if where.nil? #not all and not channel
         | 
| 15 | 
            +
                      @bots_created.each do |k, v|
         | 
| 16 | 
            +
                        respond message, k
         | 
| 17 | 
            +
                      end
         | 
| 18 | 
            +
                      respond "Bot channels have been notified", dest
         | 
| 19 | 
            +
                    elsif where == "all" #all
         | 
| 20 | 
            +
                      myconv = client.web_client.users_conversations(exclude_archived: true, limit: 100, types: "im, public_channel,private_channel").channels
         | 
| 21 | 
            +
                      myconv.each do |c|
         | 
| 22 | 
            +
                        respond message, c.id unless c.name == MASTER_CHANNEL
         | 
| 23 | 
            +
                      end
         | 
| 24 | 
            +
                      respond "Channels and users have been notified", dest
         | 
| 25 | 
            +
                    else #channel
         | 
| 26 | 
            +
                      respond message, where
         | 
| 27 | 
            +
                      @bots_created[where][:extended].each do |ch|
         | 
| 28 | 
            +
                        respond message, @channels_id[ch]
         | 
| 29 | 
            +
                      end
         | 
| 30 | 
            +
                      respond "Bot channel and extended channels have been notified", dest
         | 
| 31 | 
            +
                    end
         | 
| 32 | 
            +
                  end
         | 
| 33 | 
            +
                end
         | 
| 34 | 
            +
              end
         | 
| 35 | 
            +
            end
         | 
| @@ -0,0 +1,94 @@ | |
| 1 | 
            +
            class SlackSmartBot
         | 
| 2 | 
            +
              # helpmaster: ----------------------------------------------
         | 
| 3 | 
            +
              # helpmaster: `create bot on CHANNEL_NAME`
         | 
| 4 | 
            +
              # helpmaster: `create cloud bot on CHANNEL_NAME`
         | 
| 5 | 
            +
              # helpmaster:    creates a new bot on the channel specified
         | 
| 6 | 
            +
              # helpmaster:    it will work only if you are on Master channel
         | 
| 7 | 
            +
              # helpmaster:    the admins will be the master admins, the creator of the bot and the creator of the channel
         | 
| 8 | 
            +
              # helpmaster:    follow the instructions in case creating cloud bots
         | 
| 9 | 
            +
              # helpmaster:
         | 
| 10 | 
            +
              def create_bot(dest, from, cloud, channel)
         | 
| 11 | 
            +
                if ON_MASTER_BOT
         | 
| 12 | 
            +
                  get_channels_name_and_id() unless @channels_name.keys.include?(channel) or @channels_id.keys.include?(channel)
         | 
| 13 | 
            +
                  channel_id = nil
         | 
| 14 | 
            +
                  if @channels_name.key?(channel) #it is an id
         | 
| 15 | 
            +
                    channel_id = channel
         | 
| 16 | 
            +
                    channel = @channels_name[channel_id]
         | 
| 17 | 
            +
                  elsif @channels_id.key?(channel) #it is a channel name
         | 
| 18 | 
            +
                    channel_id = @channels_id[channel]
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
                  #todo: add pagination for case more than 1000 channels on the workspace
         | 
| 21 | 
            +
                  channels = client.web_client.conversations_list(
         | 
| 22 | 
            +
                    types: "private_channel,public_channel",
         | 
| 23 | 
            +
                    limit: "1000",
         | 
| 24 | 
            +
                    exclude_archived: "true",
         | 
| 25 | 
            +
                  ).channels
         | 
| 26 | 
            +
                  channel_found = channels.detect { |c| c.name == channel }
         | 
| 27 | 
            +
                  members = client.web_client.conversations_members(channel: @channels_id[channel]).members unless channel_found.nil?
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                  if channel_id.nil?
         | 
| 30 | 
            +
                    respond "There is no channel with that name: #{channel}, please be sure is written exactly the same", dest
         | 
| 31 | 
            +
                  elsif channel == MASTER_CHANNEL
         | 
| 32 | 
            +
                    respond "There is already a bot in this channel: #{channel}", dest
         | 
| 33 | 
            +
                  elsif @bots_created.keys.include?(channel_id)
         | 
| 34 | 
            +
                    respond "There is already a bot in this channel: #{channel}, kill it before", dest
         | 
| 35 | 
            +
                  elsif config[:nick_id] != channel_found.creator and !members.include?(config[:nick_id])
         | 
| 36 | 
            +
                    respond "You need to add first to the channel the smart bot user: #{config[:nick]}", dest
         | 
| 37 | 
            +
                  else
         | 
| 38 | 
            +
                    if channel_id != config[:channel]
         | 
| 39 | 
            +
                      begin
         | 
| 40 | 
            +
                        rules_file = "slack-smart-bot_rules_#{channel_id}_#{from.gsub(" ", "_")}.rb"
         | 
| 41 | 
            +
                        if defined?(RULES_FOLDER)
         | 
| 42 | 
            +
                          rules_file = RULES_FOLDER + rules_file
         | 
| 43 | 
            +
                        else
         | 
| 44 | 
            +
                          Dir.mkdir("rules") unless Dir.exist?("rules")
         | 
| 45 | 
            +
                          Dir.mkdir("rules/#{channel_id}") unless Dir.exist?("rules/#{channel_id}")
         | 
| 46 | 
            +
                          rules_file = "./rules/#{channel_id}/" + rules_file
         | 
| 47 | 
            +
                        end
         | 
| 48 | 
            +
                        default_rules = (__FILE__).gsub(/slack\/smart-bot\/commands\/on_master\/create_bot\.rb$/, "slack-smart-bot_rules.rb")
         | 
| 49 | 
            +
                        File.delete(rules_file) if File.exist?(rules_file)
         | 
| 50 | 
            +
                        FileUtils.copy_file(default_rules, rules_file) unless File.exist?(rules_file)
         | 
| 51 | 
            +
                        admin_users = Array.new()
         | 
| 52 | 
            +
                        creator_info = client.web_client.users_info(user: channel_found.creator)
         | 
| 53 | 
            +
                        admin_users = [from, creator_info.user.name] + MASTER_USERS
         | 
| 54 | 
            +
                        admin_users.uniq!
         | 
| 55 | 
            +
                        @logger.info "ruby #{$0} \"#{channel}\" \"#{admin_users.join(",")}\" \"#{rules_file}\" on"
         | 
| 56 | 
            +
                    
         | 
| 57 | 
            +
                        if cloud
         | 
| 58 | 
            +
                          respond "Copy the bot folder to your cloud location and run `ruby #{$0} \"#{channel}\" \"#{admin_users.join(",")}\" \"#{rules_file}\" on&`", dest
         | 
| 59 | 
            +
                        else
         | 
| 60 | 
            +
                          t = Thread.new do
         | 
| 61 | 
            +
                            `ruby #{$0} \"#{channel}\" \"#{admin_users.join(",")}\" \"#{rules_file}\" on`
         | 
| 62 | 
            +
                          end
         | 
| 63 | 
            +
                        end
         | 
| 64 | 
            +
                        @bots_created[channel_id] = {
         | 
| 65 | 
            +
                          creator_name: from,
         | 
| 66 | 
            +
                          channel_id: channel_id,
         | 
| 67 | 
            +
                          channel_name: @channels_name[channel_id],
         | 
| 68 | 
            +
                          status: :on,
         | 
| 69 | 
            +
                          created: Time.now.strftime("%Y-%m-%dT%H:%M:%S.000Z")[0..18],
         | 
| 70 | 
            +
                          rules_file: rules_file,
         | 
| 71 | 
            +
                          admins: admin_users.join(","),
         | 
| 72 | 
            +
                          extended: [],
         | 
| 73 | 
            +
                          cloud: cloud,
         | 
| 74 | 
            +
                          thread: t,
         | 
| 75 | 
            +
                        }
         | 
| 76 | 
            +
                        respond "The bot has been created on channel: #{channel}. Rules file: #{File.basename rules_file}. Admins: #{admin_users.join(", ")}", dest
         | 
| 77 | 
            +
                        update_bots_file()
         | 
| 78 | 
            +
                      rescue Exception => stack
         | 
| 79 | 
            +
                        @logger.fatal stack
         | 
| 80 | 
            +
                        message = "Problem creating the bot on channel #{channel}. Error: <#{stack}>."
         | 
| 81 | 
            +
                        @logger.error message
         | 
| 82 | 
            +
                        respond message, dest
         | 
| 83 | 
            +
                      end
         | 
| 84 | 
            +
                    else
         | 
| 85 | 
            +
                      respond "There is already a bot in this channel: #{channel}, and it is the Master Channel!", dest
         | 
| 86 | 
            +
                    end
         | 
| 87 | 
            +
                  end
         | 
| 88 | 
            +
                else
         | 
| 89 | 
            +
                  @logger.info MASTER_CHANNEL
         | 
| 90 | 
            +
                  @logger.info @channel_id.inspect
         | 
| 91 | 
            +
                  respond "Sorry I cannot create bots from this channel, please visit the master channel: <##{@master_bot_id}>", dest
         | 
| 92 | 
            +
                end
         | 
| 93 | 
            +
              end
         | 
| 94 | 
            +
            end
         | 
| @@ -0,0 +1,36 @@ | |
| 1 | 
            +
            class SlackSmartBot
         | 
| 2 | 
            +
              def listen
         | 
| 3 | 
            +
                @salutations = [config[:nick], "<@#{config[:nick_id]}>", "bot", "smart"]
         | 
| 4 | 
            +
                @pings = []
         | 
| 5 | 
            +
                get_bots_created()
         | 
| 6 | 
            +
                client.on :message do |data|
         | 
| 7 | 
            +
                  unless data.user == "USLACKBOT"
         | 
| 8 | 
            +
                    treat_message(data)
         | 
| 9 | 
            +
                  end
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                restarts = 0
         | 
| 13 | 
            +
                started = false
         | 
| 14 | 
            +
                while restarts < 200 and !started
         | 
| 15 | 
            +
                  begin
         | 
| 16 | 
            +
                    @logger.info "Bot starting: #{config.inspect}"
         | 
| 17 | 
            +
                    client.start!
         | 
| 18 | 
            +
                  rescue Slack::RealTime::Client::ClientAlreadyStartedError
         | 
| 19 | 
            +
                    @logger.info "ClientAlreadyStarted so we continue with execution"
         | 
| 20 | 
            +
                    started = true
         | 
| 21 | 
            +
                  rescue Exception => e
         | 
| 22 | 
            +
                    started = false
         | 
| 23 | 
            +
                    restarts += 1
         | 
| 24 | 
            +
                    if restarts < 200
         | 
| 25 | 
            +
                      @logger.info "*" * 50
         | 
| 26 | 
            +
                      @logger.fatal "Rescued on starting: #{e.inspect}"
         | 
| 27 | 
            +
                      @logger.info "Waiting 60 seconds to retry. restarts: #{restarts}"
         | 
| 28 | 
            +
                      puts "#{Time.now}: Not able to start client. Waiting 60 seconds to retry: #{config.inspect}"
         | 
| 29 | 
            +
                      sleep 60
         | 
| 30 | 
            +
                    else
         | 
| 31 | 
            +
                      exit!
         | 
| 32 | 
            +
                    end
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
              end
         | 
| 36 | 
            +
            end
         | 
| @@ -0,0 +1,169 @@ | |
| 1 | 
            +
            require_relative "commands/general/hi_bot"
         | 
| 2 | 
            +
            require_relative "commands/general/bye_bot"
         | 
| 3 | 
            +
            require_relative "commands/general/bot_help"
         | 
| 4 | 
            +
            require_relative "commands/on_bot/ruby_code"
         | 
| 5 | 
            +
            require_relative "commands/general/use_rules"
         | 
| 6 | 
            +
            require_relative "commands/general/stop_using_rules"
         | 
| 7 | 
            +
            require_relative "commands/on_master/admin_master/exit_bot"
         | 
| 8 | 
            +
            require_relative "commands/on_master/admin_master/notify_message"
         | 
| 9 | 
            +
            require_relative "commands/on_master/admin/kill_bot_on_channel"
         | 
| 10 | 
            +
            require_relative "commands/on_master/create_bot"
         | 
| 11 | 
            +
            require_relative "commands/on_bot/admin/add_routine"
         | 
| 12 | 
            +
            require_relative "commands/on_bot/admin/start_bot"
         | 
| 13 | 
            +
            require_relative "commands/on_bot/admin/pause_bot"
         | 
| 14 | 
            +
            require_relative "commands/on_bot/admin/remove_routine"
         | 
| 15 | 
            +
            require_relative "commands/on_bot/admin/run_routine"
         | 
| 16 | 
            +
            require_relative "commands/on_bot/admin/pause_routine"
         | 
| 17 | 
            +
            require_relative "commands/on_bot/admin/start_routine"
         | 
| 18 | 
            +
            require_relative "commands/on_bot/admin/see_routines"
         | 
| 19 | 
            +
            require_relative "commands/on_bot/admin/extend_rules"
         | 
| 20 | 
            +
            require_relative "commands/on_bot/admin/stop_using_rules_on"
         | 
| 21 | 
            +
            require_relative "commands/general/bot_status"
         | 
| 22 | 
            +
            require_relative "commands/on_bot/add_shortcut"
         | 
| 23 | 
            +
            require_relative "commands/on_bot/delete_shortcut"
         | 
| 24 | 
            +
            require_relative "commands/on_bot/see_shortcuts"
         | 
| 25 | 
            +
            require_relative "commands/on_extended/bot_rules"
         | 
| 26 | 
            +
             | 
| 27 | 
            +
            class SlackSmartBot
         | 
| 28 | 
            +
              def process(user, command, dest, dchannel, rules_file, typem, files)
         | 
| 29 | 
            +
                from = user.name
         | 
| 30 | 
            +
                if user.profile.display_name.to_s.match?(/\A\s*\z/)
         | 
| 31 | 
            +
                  user.profile.display_name = user.profile.real_name
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
                display_name = user.profile.display_name
         | 
| 34 | 
            +
                processed = true
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                on_demand = false
         | 
| 37 | 
            +
                if command.match(/^@?(#{config[:nick]}):*\s+(.+)/im) or
         | 
| 38 | 
            +
                   command.match(/^()!(.+)/im) or
         | 
| 39 | 
            +
                   command.match(/^()<@#{config[:nick_id]}>\s+(.+)/im)
         | 
| 40 | 
            +
                  command = $2
         | 
| 41 | 
            +
                  on_demand = true
         | 
| 42 | 
            +
                end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                #todo: check :on_pg in this case
         | 
| 45 | 
            +
                if typem == :on_master or typem == :on_bot or typem == :on_pg or typem == :on_dm
         | 
| 46 | 
            +
                  case command
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                  when /^\s*(Hello|Hallo|Hi|Hola|What's\sup|Hey|Hæ)\s(#{@salutations.join("|")})\s*$/i
         | 
| 49 | 
            +
                    hi_bot(user, dest, dchannel, from, display_name)
         | 
| 50 | 
            +
                  when /^\s*(Bye|Bæ|Good\sBye|Adiós|Ciao|Bless|Bless\sBless|Adeu)\s(#{@salutations.join("|")})\s*$/i
         | 
| 51 | 
            +
                    bye_bot(dest, from, display_name)
         | 
| 52 | 
            +
                  when /^\s*bot\s+(rules|help)\s*(.+)?$/i, /^bot,? what can I do/i
         | 
| 53 | 
            +
                    $1.to_s.match?(/rules/i) ? specific = true : specific = false
         | 
| 54 | 
            +
                    help_command = $2
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                    bot_help(user, from, dest, dchannel, specific, help_command, rules_file)
         | 
| 57 | 
            +
                  when /^\s*use\s+(rules\s+)?(from\s+)?<#C\w+\|(.+)>\s*$/i, /^use\s+(rules\s+)?(from\s+)?([^\s]+\s*$)/i
         | 
| 58 | 
            +
                    channel = $3
         | 
| 59 | 
            +
                    use_rules(dest, channel, user, dchannel)
         | 
| 60 | 
            +
                  when /^\s*stop using rules (from\s+)<#\w+\|(.+)>/i, /^stop using rules (from\s+)(.+)/i
         | 
| 61 | 
            +
                    channel = $2
         | 
| 62 | 
            +
                    stop_using_rules(dest, channel, user, dchannel)
         | 
| 63 | 
            +
                  when /^\s*extend\s+rules\s+(to\s+)<#C\w+\|(.+)>/i, /^extend\s+rules\s+(to\s+)(.+)/i,
         | 
| 64 | 
            +
                       /^\s*use\s+rules\s+(on\s+)<#C\w+\|(.+)>/i, /^use\s+rules\s+(on\s+)(.+)/i
         | 
| 65 | 
            +
                    channel = $2
         | 
| 66 | 
            +
                    extend_rules(dest, user, from, channel, typem)
         | 
| 67 | 
            +
                  when /^\s*stop using rules (on\s+)<#\w+\|(.+)>/i, /^stop using rules (on\s+)(.+)/i
         | 
| 68 | 
            +
                    channel = $2
         | 
| 69 | 
            +
                    stop_using_rules_on(dest, user, from, channel, typem)
         | 
| 70 | 
            +
                  when /^\s*exit\sbot\s*$/i, /^quit\sbot\s*$/i, /^close\sbot\s*$/i
         | 
| 71 | 
            +
                    exit_bot(command, from, dest, display_name)
         | 
| 72 | 
            +
                  when /^\s*start\s(this\s)?bot$/i
         | 
| 73 | 
            +
                    start_bot(dest, from)
         | 
| 74 | 
            +
                  when /^\s*pause\s(this\s)?bot$/i
         | 
| 75 | 
            +
                    pause_bot(dest, from)
         | 
| 76 | 
            +
                  when /^\s*bot\sstatus/i
         | 
| 77 | 
            +
                    bot_status(dest, from)
         | 
| 78 | 
            +
                  when /\Anotify\s+<#(C\w+)\|.+>\s+(.+)\s*\z/im, /\Anotify\s+(all)?\s*(.+)\s*\z/im
         | 
| 79 | 
            +
                    where = $1
         | 
| 80 | 
            +
                    message = $2
         | 
| 81 | 
            +
                    notify_message(dest, from, where, message)
         | 
| 82 | 
            +
                  when /^\s*create\s+(cloud\s+)?bot\s+on\s+<#C\w+\|(.+)>\s*/i, /^create\s+(cloud\s+)?bot\s+on\s+(.+)\s*/i
         | 
| 83 | 
            +
                    cloud = !$1.nil?
         | 
| 84 | 
            +
                    channel = $2
         | 
| 85 | 
            +
                    create_bot(dest, from, cloud, channel)
         | 
| 86 | 
            +
                  when /^\s*kill\sbot\son\s<#C\w+\|(.+)>\s*$/i, /^kill\sbot\son\s(.+)\s*$/i
         | 
| 87 | 
            +
                    channel = $1
         | 
| 88 | 
            +
                    kill_bot_on_channel(dest, from, channel)
         | 
| 89 | 
            +
                  when /^\s*(add|create)\s+routine\s+(\w+)\s+(every)\s+(\d+)\s*(days|hours|minutes|seconds|mins|min|secs|sec|d|h|m|s)\s*(\s.+)?\s*$/i,
         | 
| 90 | 
            +
                       /^\s*(add|create)\s+routine\s+(\w+)\s+(at)\s+(\d+:\d+:?\d+?)\s*()(\s.+)?\s*$/i
         | 
| 91 | 
            +
                    name = $2.downcase
         | 
| 92 | 
            +
                    type = $3
         | 
| 93 | 
            +
                    number_time = $4
         | 
| 94 | 
            +
                    period = $5
         | 
| 95 | 
            +
                    command_to_run = $6
         | 
| 96 | 
            +
                    add_routine(dest, from, user, name, type, number_time, period, command_to_run, files)
         | 
| 97 | 
            +
                  when /^\s*(kill|delete|remove)\s+routine\s+(\w+)\s*$/i
         | 
| 98 | 
            +
                    name = $2.downcase
         | 
| 99 | 
            +
                    remove_routine(dest, from, name)
         | 
| 100 | 
            +
                  when /^\s*(run|execute)\s+routine\s+(\w+)\s*$/i
         | 
| 101 | 
            +
                    name = $2.downcase
         | 
| 102 | 
            +
                    run_routine(dest, from, name)
         | 
| 103 | 
            +
                  when /^\s*pause\s+routine\s+(\w+)\s*$/i
         | 
| 104 | 
            +
                    name = $1.downcase
         | 
| 105 | 
            +
                    pause_routine(dest, from, name)
         | 
| 106 | 
            +
                  when /^\s*start\s+routine\s+(\w+)\s*$/i
         | 
| 107 | 
            +
                    name = $1.downcase
         | 
| 108 | 
            +
                    start_routine(dest, from, name)
         | 
| 109 | 
            +
                  when /^\s*see\s+(all\s+)?routines\s*$/i
         | 
| 110 | 
            +
                    all = $1.to_s != ""
         | 
| 111 | 
            +
                    see_routines(dest, from, user, all)
         | 
| 112 | 
            +
                  else
         | 
| 113 | 
            +
                    processed = false
         | 
| 114 | 
            +
                  end
         | 
| 115 | 
            +
                else
         | 
| 116 | 
            +
                  processed = false
         | 
| 117 | 
            +
                end
         | 
| 118 | 
            +
             | 
| 119 | 
            +
                # only when :on and (listening or on demand or direct message)
         | 
| 120 | 
            +
                if @status == :on and
         | 
| 121 | 
            +
                   (@questions.keys.include?(from) or
         | 
| 122 | 
            +
                    (@listening.include?(from) and typem != :on_extended) or
         | 
| 123 | 
            +
                    typem == :on_dm or typem == :on_pg or on_demand)
         | 
| 124 | 
            +
                  processed2 = true
         | 
| 125 | 
            +
             | 
| 126 | 
            +
                  case command
         | 
| 127 | 
            +
             | 
| 128 | 
            +
                  # bot rules for extended channels
         | 
| 129 | 
            +
                  when /^bot\s+rules\s*(.+)?$/i
         | 
| 130 | 
            +
                    help_command = $1
         | 
| 131 | 
            +
                    bot_rules(dest, help_command, typem, rules_file, from)
         | 
| 132 | 
            +
                  when /^\s*(add\s)?shortcut\s(for\sall)?\s*(.+)\s*:\s*(.+)/i, /^(add\s)sc\s(for\sall)?\s*(.+)\s*:\s*(.+)/i
         | 
| 133 | 
            +
                    for_all = $2
         | 
| 134 | 
            +
                    shortcut_name = $3.to_s.downcase
         | 
| 135 | 
            +
                    command_to_run = $4
         | 
| 136 | 
            +
                    add_shortcut(dest, from, typem, for_all, shortcut_name, command, command_to_run)
         | 
| 137 | 
            +
                  when /^\s*delete\s+shortcut\s+(.+)/i, /^delete\s+sc\s+(.+)/i
         | 
| 138 | 
            +
                    shortcut = $1.to_s.downcase
         | 
| 139 | 
            +
                    delete_shortcut(dest, from, shortcut, typem, command)
         | 
| 140 | 
            +
                  when /^\s*see\sshortcuts/i, /^see\ssc/i
         | 
| 141 | 
            +
                    see_shortcuts(dest, from, typem)
         | 
| 142 | 
            +
             | 
| 143 | 
            +
                    #kept to be backwards compatible
         | 
| 144 | 
            +
                  when /^\s*id\schannel\s<#C\w+\|(.+)>\s*/i, /^id channel (.+)/
         | 
| 145 | 
            +
                    unless typem == :on_extended
         | 
| 146 | 
            +
                      channel_name = $1
         | 
| 147 | 
            +
                      get_channels_name_and_id()
         | 
| 148 | 
            +
                      if @channels_id.keys.include?(channel_name)
         | 
| 149 | 
            +
                        respond "the id of #{channel_name} is #{@channels_id[channel_name]}", dest
         | 
| 150 | 
            +
                      else
         | 
| 151 | 
            +
                        respond "channel: #{channel_name} not found", dest
         | 
| 152 | 
            +
                      end
         | 
| 153 | 
            +
                    end
         | 
| 154 | 
            +
                  when /^\s*ruby\s(.+)/im, /^\s*code\s(.+)/im
         | 
| 155 | 
            +
                    code = $1
         | 
| 156 | 
            +
                    code.gsub!("\\n", "\n")
         | 
| 157 | 
            +
                    code.gsub!("\\r", "\r")
         | 
| 158 | 
            +
                    @logger.info code
         | 
| 159 | 
            +
                    ruby_code(dest, code, rules_file)
         | 
| 160 | 
            +
                  else
         | 
| 161 | 
            +
                    processed2 = false
         | 
| 162 | 
            +
                  end #of case
         | 
| 163 | 
            +
             | 
| 164 | 
            +
                  processed = true if processed or processed2
         | 
| 165 | 
            +
                end
         | 
| 166 | 
            +
             | 
| 167 | 
            +
                return processed
         | 
| 168 | 
            +
              end
         | 
| 169 | 
            +
            end
         | 
| @@ -0,0 +1,201 @@ | |
| 1 | 
            +
            class SlackSmartBot
         | 
| 2 | 
            +
              def process_first(user, text, dest, dchannel, typem, files)
         | 
| 3 | 
            +
                nick = user.name
         | 
| 4 | 
            +
                rules_file = ""
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                if typem == :on_call
         | 
| 7 | 
            +
                  rules_file = RULES_FILE
         | 
| 8 | 
            +
                elsif dest[0] == "C" or dest[0] == "G" # on a channel or private channel
         | 
| 9 | 
            +
                  rules_file = RULES_FILE
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  if @rules_imported.key?(user.id) and @rules_imported[user.id].key?(dchannel)
         | 
| 12 | 
            +
                    unless @bots_created.key?(@rules_imported[user.id][dchannel])
         | 
| 13 | 
            +
                      get_bots_created()
         | 
| 14 | 
            +
                    end
         | 
| 15 | 
            +
                    if @bots_created.key?(@rules_imported[user.id][dchannel])
         | 
| 16 | 
            +
                      rules_file = @bots_created[@rules_imported[user.id][dchannel]][:rules_file]
         | 
| 17 | 
            +
                    end
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
                elsif dest[0] == "D" and @rules_imported.key?(user.id) and @rules_imported[user.id].key?(user.id) #direct message
         | 
| 20 | 
            +
                  unless @bots_created.key?(@rules_imported[user.id][user.id])
         | 
| 21 | 
            +
                    get_bots_created()
         | 
| 22 | 
            +
                  end
         | 
| 23 | 
            +
                  if @bots_created.key?(@rules_imported[user.id][user.id])
         | 
| 24 | 
            +
                    rules_file = @bots_created[@rules_imported[user.id][user.id]][:rules_file]
         | 
| 25 | 
            +
                  end
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                if nick == config[:nick] #if message is coming from the bot
         | 
| 29 | 
            +
                  begin
         | 
| 30 | 
            +
                    case text
         | 
| 31 | 
            +
                    when /^Bot has been (closed|killed) by/i
         | 
| 32 | 
            +
                      if CHANNEL == @channels_name[dchannel]
         | 
| 33 | 
            +
                        @logger.info "#{nick}: #{text}"
         | 
| 34 | 
            +
                        exit!
         | 
| 35 | 
            +
                      end
         | 
| 36 | 
            +
                    when /^Changed status on (.+) to :(.+)/i
         | 
| 37 | 
            +
                      channel_name = $1
         | 
| 38 | 
            +
                      status = $2
         | 
| 39 | 
            +
                      if ON_MASTER_BOT or CHANNEL == channel_name
         | 
| 40 | 
            +
                        @bots_created[@channels_id[channel_name]][:status] = status.to_sym
         | 
| 41 | 
            +
                        update_bots_file()
         | 
| 42 | 
            +
                        if CHANNEL == channel_name
         | 
| 43 | 
            +
                          @logger.info "#{nick}: #{text}"
         | 
| 44 | 
            +
                        else #on master bot
         | 
| 45 | 
            +
                          @logger.info "Changed status on #{channel_name} to :#{status}"
         | 
| 46 | 
            +
                        end
         | 
| 47 | 
            +
                      end
         | 
| 48 | 
            +
                    when /extended the rules from (.+) to be used on (.+)\.$/i
         | 
| 49 | 
            +
                      from_name = $1
         | 
| 50 | 
            +
                      to_name = $2
         | 
| 51 | 
            +
                      if ON_MASTER_BOT and @bots_created[@channels_id[from_name]][:cloud]
         | 
| 52 | 
            +
                        @bots_created[@channels_id[from_name]][:extended] << to_name
         | 
| 53 | 
            +
                        @bots_created[@channels_id[from_name]][:extended].uniq!
         | 
| 54 | 
            +
                        update_bots_file()
         | 
| 55 | 
            +
                      end
         | 
| 56 | 
            +
                    when /removed the access to the rules of (.+) from (.+)\.$/i
         | 
| 57 | 
            +
                      from_name = $1
         | 
| 58 | 
            +
                      to_name = $2
         | 
| 59 | 
            +
                      if ON_MASTER_BOT and @bots_created[@channels_id[from_name]][:cloud]
         | 
| 60 | 
            +
                        @bots_created[@channels_id[from_name]][:extended].delete(to_name)
         | 
| 61 | 
            +
                        update_bots_file()
         | 
| 62 | 
            +
                      end
         | 
| 63 | 
            +
                    end
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                    return :next #don't continue analyzing #jal
         | 
| 66 | 
            +
                  rescue Exception => stack
         | 
| 67 | 
            +
                    @logger.fatal stack
         | 
| 68 | 
            +
                    return :next #jal
         | 
| 69 | 
            +
                  end
         | 
| 70 | 
            +
                end
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                #only for shortcuts
         | 
| 73 | 
            +
                if text.match(/^@?(#{config[:nick]}):*\s+(.+)\s*/im) or
         | 
| 74 | 
            +
                   text.match(/^()!\s*(.+)\s*/im) or
         | 
| 75 | 
            +
                   text.match(/^()<@#{config[:nick_id]}>\s+(.+)\s*/im)
         | 
| 76 | 
            +
                  command = $2
         | 
| 77 | 
            +
                  addexcl = true
         | 
| 78 | 
            +
                else
         | 
| 79 | 
            +
                  addexcl = false
         | 
| 80 | 
            +
                  command = text.downcase.lstrip.rstrip
         | 
| 81 | 
            +
                end
         | 
| 82 | 
            +
                if command.scan(/^(shortcut|sc)\s+([^:]+)\s*$/i).any? or
         | 
| 83 | 
            +
                   (@shortcuts.keys.include?(:all) and @shortcuts[:all].keys.include?(command)) or
         | 
| 84 | 
            +
                   (@shortcuts.keys.include?(nick) and @shortcuts[nick].keys.include?(command))
         | 
| 85 | 
            +
                  command = $2.downcase unless $2.nil?
         | 
| 86 | 
            +
                  if @shortcuts.keys.include?(nick) and @shortcuts[nick].keys.include?(command)
         | 
| 87 | 
            +
                    text = @shortcuts[nick][command].dup
         | 
| 88 | 
            +
                  elsif @shortcuts.keys.include?(:all) and @shortcuts[:all].keys.include?(command)
         | 
| 89 | 
            +
                    text = @shortcuts[:all][command].dup
         | 
| 90 | 
            +
                  else
         | 
| 91 | 
            +
                    respond "Shortcut not found", dest unless dest[0] == "C" and dchannel != dest #on extended channel
         | 
| 92 | 
            +
                    return :next #jal
         | 
| 93 | 
            +
                  end
         | 
| 94 | 
            +
                  text = "!" + text if addexcl and text[0] != "!"
         | 
| 95 | 
            +
                end
         | 
| 96 | 
            +
             | 
| 97 | 
            +
                command = text
         | 
| 98 | 
            +
             | 
| 99 | 
            +
                begin
         | 
| 100 | 
            +
                  t = Thread.new do
         | 
| 101 | 
            +
                    begin
         | 
| 102 | 
            +
                      Thread.current[:dest] = dest
         | 
| 103 | 
            +
                      Thread.current[:user] = user
         | 
| 104 | 
            +
                      Thread.current[:command] = command
         | 
| 105 | 
            +
                      Thread.current[:rules_file] = rules_file
         | 
| 106 | 
            +
                      processed = process(user, command, dest, dchannel, rules_file, typem, files)
         | 
| 107 | 
            +
                      @logger.info "command: #{nick}> #{command}" if processed
         | 
| 108 | 
            +
                      on_demand = false
         | 
| 109 | 
            +
                      if command.match(/^@?(#{config[:nick]}):*\s+(.+)/im) or
         | 
| 110 | 
            +
                         command.match(/^()!(.+)/im) or
         | 
| 111 | 
            +
                         command.match(/^()<@#{config[:nick_id]}>\s+(.+)/im)
         | 
| 112 | 
            +
                        command = $2
         | 
| 113 | 
            +
                        Thread.current[:command] = command
         | 
| 114 | 
            +
                        on_demand = true
         | 
| 115 | 
            +
                      end
         | 
| 116 | 
            +
                      if @status == :on and
         | 
| 117 | 
            +
                         (@questions.keys.include?(nick) or
         | 
| 118 | 
            +
                          (@listening.include?(nick) and typem != :on_extended) or
         | 
| 119 | 
            +
                          dest[0] == "D" or on_demand)
         | 
| 120 | 
            +
                        @logger.info "command: #{nick}> #{command}" unless processed
         | 
| 121 | 
            +
                        #todo: verify this
         | 
| 122 | 
            +
             | 
| 123 | 
            +
                        if dest[0] == "C" or dest[0] == "G" or (dest[0] == "D" and typem == :on_call)
         | 
| 124 | 
            +
                          if typem != :on_call and @rules_imported.key?(user.id) and @rules_imported[user.id].key?(dchannel)
         | 
| 125 | 
            +
                            if @bots_created.key?(@rules_imported[user.id][dchannel])
         | 
| 126 | 
            +
                              if @bots_created[@rules_imported[user.id][dchannel]][:status] != :on
         | 
| 127 | 
            +
                                respond "The bot on that channel is not :on", dest
         | 
| 128 | 
            +
                                rules_file = ""
         | 
| 129 | 
            +
                              end
         | 
| 130 | 
            +
                            end
         | 
| 131 | 
            +
                          end
         | 
| 132 | 
            +
                          unless rules_file.empty?
         | 
| 133 | 
            +
                            begin
         | 
| 134 | 
            +
                              eval(File.new(rules_file).read) if File.exist?(rules_file)
         | 
| 135 | 
            +
                            rescue Exception => stack
         | 
| 136 | 
            +
                              @logger.fatal "ERROR ON RULES FILE: #{rules_file}"
         | 
| 137 | 
            +
                              @logger.fatal stack
         | 
| 138 | 
            +
                            end
         | 
| 139 | 
            +
                            if defined?(rules)
         | 
| 140 | 
            +
                              command[0] = "" if command[0] == "!"
         | 
| 141 | 
            +
                              command.gsub!(/^@\w+:*\s*/, "")
         | 
| 142 | 
            +
                              if method(:rules).parameters.size == 4
         | 
| 143 | 
            +
                                rules(user, command, processed, dest)
         | 
| 144 | 
            +
                              elsif method(:rules).parameters.size == 5
         | 
| 145 | 
            +
                                rules(user, command, processed, dest, files)
         | 
| 146 | 
            +
                              else
         | 
| 147 | 
            +
                                rules(user, command, processed, dest, files, rules_file)
         | 
| 148 | 
            +
                              end
         | 
| 149 | 
            +
                            else
         | 
| 150 | 
            +
                              @logger.warn "It seems like rules method is not defined"
         | 
| 151 | 
            +
                            end
         | 
| 152 | 
            +
                          end
         | 
| 153 | 
            +
                        elsif @rules_imported.key?(user.id) and @rules_imported[user.id].key?(user.id)
         | 
| 154 | 
            +
                          if @bots_created.key?(@rules_imported[user.id][user.id])
         | 
| 155 | 
            +
                            if @bots_created[@rules_imported[user.id][user.id]][:status] == :on
         | 
| 156 | 
            +
                              begin
         | 
| 157 | 
            +
                                eval(File.new(rules_file).read) if File.exist?(rules_file)
         | 
| 158 | 
            +
                              rescue Exception => stack
         | 
| 159 | 
            +
                                @logger.fatal "ERROR ON imported RULES FILE: #{rules_file}"
         | 
| 160 | 
            +
                                @logger.fatal stack
         | 
| 161 | 
            +
                              end
         | 
| 162 | 
            +
                            else
         | 
| 163 | 
            +
                              respond "The bot on <##{@rules_imported[user.id][user.id]}|#{@bots_created[@rules_imported[user.id][user.id]][:channel_name]}> is not :on", dest
         | 
| 164 | 
            +
                              rules_file = ""
         | 
| 165 | 
            +
                            end
         | 
| 166 | 
            +
                          end
         | 
| 167 | 
            +
             | 
| 168 | 
            +
                          unless rules_file.empty?
         | 
| 169 | 
            +
                            if defined?(rules)
         | 
| 170 | 
            +
                              command[0] = "" if command[0] == "!"
         | 
| 171 | 
            +
                              command.gsub!(/^@\w+:*\s*/, "")
         | 
| 172 | 
            +
                              if method(:rules).parameters.size == 4
         | 
| 173 | 
            +
                                rules(user, command, processed, dest)
         | 
| 174 | 
            +
                              elsif method(:rules).parameters.size == 5
         | 
| 175 | 
            +
                                rules(user, command, processed, dest, files)
         | 
| 176 | 
            +
                              else
         | 
| 177 | 
            +
                                rules(user, command, processed, dest, files, rules_file)
         | 
| 178 | 
            +
                              end
         | 
| 179 | 
            +
                            else
         | 
| 180 | 
            +
                              @logger.warn "It seems like rules method is not defined"
         | 
| 181 | 
            +
                            end
         | 
| 182 | 
            +
                          end
         | 
| 183 | 
            +
                        else
         | 
| 184 | 
            +
                          @logger.info "it is a direct message with no rules file selected so no rules file executed."
         | 
| 185 | 
            +
                          if command.match?(/^\s*bot\s+rules\s*$/i)
         | 
| 186 | 
            +
                            respond "No rules running. You can use the command `use rules from CHANNEL` to specify the rules you want to use on this private conversation.\n`bot help` to see available commands.", dest
         | 
| 187 | 
            +
                          end
         | 
| 188 | 
            +
                          unless processed
         | 
| 189 | 
            +
                            dont_understand(__FILE__, command, user, dest)
         | 
| 190 | 
            +
                          end
         | 
| 191 | 
            +
                        end
         | 
| 192 | 
            +
                      end
         | 
| 193 | 
            +
                    rescue Exception => stack
         | 
| 194 | 
            +
                      @logger.fatal stack
         | 
| 195 | 
            +
                    end
         | 
| 196 | 
            +
                  end
         | 
| 197 | 
            +
                rescue => e
         | 
| 198 | 
            +
                  @logger.error "exception: #{e.inspect}"
         | 
| 199 | 
            +
                end
         | 
| 200 | 
            +
              end
         | 
| 201 | 
            +
            end
         |