Class: SlackSmartBot
- Inherits:
-
Object
- Object
- SlackSmartBot
- Defined in:
- lib/slack-smart-bot.rb,
lib/slack/smart-bot/listen.rb,
lib/slack/smart-bot/process.rb,
lib/slack/smart-bot/comm/ask.rb,
lib/slack/smart-bot/comm/react.rb,
lib/slack/smart-bot/comm/respond.rb,
lib/slack/smart-bot/process_first.rb,
lib/slack/smart-bot/treat_message.rb,
lib/slack/smart-bot/comm/send_file.rb,
lib/slack/smart-bot/utils/get_help.rb,
lib/slack/smart-bot/utils/get_repls.rb,
lib/slack/smart-bot/utils/build_help.rb,
lib/slack/smart-bot/utils/save_stats.rb,
lib/slack/smart-bot/comm/send_msg_user.rb,
lib/slack/smart-bot/utils/get_routines.rb,
lib/slack/smart-bot/utils/update_repls.rb,
lib/slack/smart-bot/comm/respond_direct.rb,
lib/slack/smart-bot/comm/dont_understand.rb,
lib/slack/smart-bot/commands/on_bot/repl.rb,
lib/slack/smart-bot/comm/send_msg_channel.rb,
lib/slack/smart-bot/utils/update_routines.rb,
lib/slack/smart-bot/utils/get_bots_created.rb,
lib/slack/smart-bot/utils/remove_hash_keys.rb,
lib/slack/smart-bot/utils/update_bots_file.rb,
lib/slack/smart-bot/commands/general/hi_bot.rb,
lib/slack/smart-bot/commands/general/bye_bot.rb,
lib/slack/smart-bot/commands/on_bot/get_repl.rb,
lib/slack/smart-bot/commands/on_bot/run_repl.rb,
lib/slack/smart-bot/utils/get_rules_imported.rb,
lib/slack/smart-bot/commands/general/bot_help.rb,
lib/slack/smart-bot/commands/on_bot/ruby_code.rb,
lib/slack/smart-bot/commands/on_bot/see_repls.rb,
lib/slack/smart-bot/commands/general/use_rules.rb,
lib/slack/smart-bot/commands/general/bot_status.rb,
lib/slack/smart-bot/commands/on_bot/delete_repl.rb,
lib/slack/smart-bot/utils/create_routine_thread.rb,
lib/slack/smart-bot/utils/update_rules_imported.rb,
lib/slack/smart-bot/utils/update_shortcuts_file.rb,
lib/slack/smart-bot/commands/on_bot/add_shortcut.rb,
lib/slack/smart-bot/commands/on_bot/see_shortcuts.rb,
lib/slack/smart-bot/commands/on_master/create_bot.rb,
lib/slack/smart-bot/commands/on_extended/bot_rules.rb,
lib/slack/smart-bot/utils/get_channels_name_and_id.rb,
lib/slack/smart-bot/commands/on_bot/admin/pause_bot.rb,
lib/slack/smart-bot/commands/on_bot/admin/start_bot.rb,
lib/slack/smart-bot/commands/on_bot/delete_shortcut.rb,
lib/slack/smart-bot/commands/general/stop_using_rules.rb,
lib/slack/smart-bot/commands/on_bot/admin/add_routine.rb,
lib/slack/smart-bot/commands/on_bot/admin/run_routine.rb,
lib/slack/smart-bot/commands/on_bot/admin/extend_rules.rb,
lib/slack/smart-bot/commands/on_bot/admin/see_routines.rb,
lib/slack/smart-bot/commands/on_bot/admin/pause_routine.rb,
lib/slack/smart-bot/commands/on_bot/admin/start_routine.rb,
lib/slack/smart-bot/commands/on_bot/admin/remove_routine.rb,
lib/slack/smart-bot/commands/on_bot/admin_master/bot_stats.rb,
lib/slack/smart-bot/commands/on_master/admin_master/exit_bot.rb,
lib/slack/smart-bot/commands/on_bot/admin/stop_using_rules_on.rb,
lib/slack/smart-bot/commands/on_bot/admin_master/get_bot_logs.rb,
lib/slack/smart-bot/commands/on_master/admin/kill_bot_on_channel.rb,
lib/slack/smart-bot/commands/on_master/admin_master/notify_message.rb
Constant Summary collapse
- VERSION =
version
Instance Attribute Summary collapse
-
#channel_id ⇒ Object
readonly
Returns the value of attribute channel_id.
-
#client ⇒ Object
Returns the value of attribute client.
-
#config ⇒ Object
Returns the value of attribute config.
-
#master_bot_id ⇒ Object
readonly
Returns the value of attribute master_bot_id.
Instance Method Summary collapse
-
#add_routine(dest, from, user, name, type, number_time, period, command_to_run, files, silent) ⇒ Object
helpadmin: ---------------------------------------------- helpadmin:
add routine NAME every NUMBER PERIOD COMMAND
helpadmin:add routine NAME every NUMBER PERIOD
helpadmin:add silent routine NAME every NUMBER PERIOD
helpadmin:create routine NAME every NUMBER PERIOD
helpadmin:add routine NAME at TIME COMMAND
helpadmin:add routine NAME at TIME
helpadmin:add silent routine NAME at TIME
helpadmin:create routine NAME at TIME
helpadmin: It will execute the command/rule supplied. -
#add_shortcut(dest, user, typem, for_all, shortcut_name, command, command_to_run) ⇒ Object
help: ---------------------------------------------- help:
add shortcut NAME: COMMAND
help:add sc NAME: COMMAND
help:add shortcut for all NAME: COMMAND
help:add sc for all NAME: COMMAND
help:shortcut NAME: COMMAND
help:shortcut for all NAME: COMMAND
help: It will add a shortcut that will execute the command we supply. -
#ask(question, context = nil, to = nil, dest = nil) ⇒ Object
context: previous message to: user that should answer.
-
#bot_help(user, from, dest, dchannel, specific, help_command, rules_file) ⇒ Object
help: ---------------------------------------------- help:
bot help
help:bot help COMMAND
help:bot rules
help:bot rules COMMAND
help:bot what can I do?
help: it will display this help help: if COMMAND supplied just help for that command help:bot rules
will show only the specific rules for this channel. - #bot_rules(dest, help_command, typem, rules_file, user) ⇒ Object
-
#bot_stats(dest, from_user, typem, channel_id, from, to, user, exclude_masters, exclude_command) ⇒ Object
helpadmin: ---------------------------------------------- helpadmin:
bot stats
helpadmin:bot stats USER_NAME
helpadmin:bot stats exclude masters
helpadmin:bot stats from YYYY/MM/DD
helpadmin:bot stats from YYYY/MM/DD to YYYY/MM/DD
helpadmin:bot stats CHANNEL
helpadmin:bot stats CHANNEL from YYYY/MM/DD
helpadmin:bot stats CHANNEL from YYYY/MM/DD to YYYY/MM/DD
helpadmin:bot stats USER_NAME from YYYY/MM/DD to YYYY/MM/DD
helpadmin:bot stats CHANNEL USER_NAME from YYYY/MM/DD to YYYY/MM/DD
helpadmin:bot stats CHANNEL exclude masters from YYYY/MM/DD to YYYY/MM/DD
helpadmin:bot stats today
helpadmin:bot stats exclude COMMAND_ID
helpadmin: To see the bot stats helpadmin: You can use this command only if you are a Master admin user and if you are in a private conversation with the bot helpadmin: You need to set stats to true to generate the stats when running the bot instance. -
#bot_status(dest, user) ⇒ Object
helpadmin: ---------------------------------------------- helpadmin:
bot status
helpadmin: Displays the status of the bot helpadmin: If on master channel and admin user also it will display info about bots created helpadmin:. - #build_help(path) ⇒ Object
-
#bye_bot(dest, from, display_name) ⇒ Object
help: ---------------------------------------------- help:
Bye Bot
help:Bye Smart
help:Bye NAME_OF_THE_BOT
help: Also apart of Bye you can use Bæ, Good Bye, Adiós, Ciao, Bless, Bless Bless, Adeu help: Bot stops listening to you help:. -
#create_bot(dest, user, cloud, channel) ⇒ Object
helpmaster: ---------------------------------------------- helpmaster:
create bot on CHANNEL_NAME
helpmaster:create cloud bot on CHANNEL_NAME
helpmaster: creates a new bot on the channel specified helpmaster: it will work only if you are on Master channel helpmaster: the admins will be the master admins, the creator of the bot and the creator of the channel helpmaster: follow the instructions in case creating cloud bots helpmaster:. - #create_routine_thread(name) ⇒ Object
-
#delete_repl(dest, user, session_name) ⇒ Object
help: ---------------------------------------------- help:
delete repl SESSION_NAME
help:delete irb SESSION_NAME
help:remove repl SESSION_NAME
help: help: Will delete the specified REPL help: Only the creator of the REPL or an admin can delete REPLs help:. -
#delete_shortcut(dest, user, shortcut, typem, command) ⇒ Object
help: ---------------------------------------------- help:
delete shortcut NAME
help:delete sc NAME
help: It will delete the shortcut with the supplied name help:. - #dont_understand(rules_file = nil, command = nil, user = nil, dest = nil, answer = ["what?", "huh?", "sorry?", "what do you mean?", "I don't understand"], channel_rules: config.channel, typem: nil) ⇒ Object
-
#exit_bot(command, from, dest, display_name) ⇒ Object
helpadmin: ---------------------------------------------- helpadmin:
exit bot
helpadmin:quit bot
helpadmin:close bot
helpadmin: The bot stops running and also stops all the bots created from this master channel helpadmin: You can use this command only if you are an admin user and you are on the master channel helpadmin:. -
#extend_rules(dest, user, from, channel, typem) ⇒ Object
helpadmin: ---------------------------------------------- helpadmin:
extend rules to CHANNEL_NAME
helpadmin:use rules on CHANNEL_NAME
helpadmin: It will allow to use the specific rules from this channel on the CHANNEL_NAME helpadmin:. -
#get_bot_logs(dest, from, typem) ⇒ Object
helpadmin: ---------------------------------------------- helpadmin:
get bot logs
helpadmin: To see the bot logs helpadmin: You can use this command only if you are a Master admin user and if you are in a private conversation with the bot helpadmin:. - #get_bots_created ⇒ Object
- #get_channels_name_and_id ⇒ Object
- #get_help(rules_file, dest, from, only_rules = false) ⇒ Object
-
#get_repl(dest, user, session_name) ⇒ Object
help: ---------------------------------------------- help:
get repl SESSION_NAME
help:get irb SESSION_NAME
help:get live SESSION_NAME
help: help: Will get the Ruby commands sent on that SESSION_NAME. - #get_repls(channel = @channel_id) ⇒ Object
- #get_routines(channel = @channel_id) ⇒ Object
- #get_rules_imported ⇒ Object
-
#hi_bot(user, dest, dchannel, from, display_name) ⇒ Object
help: ---------------------------------------------- help:
Hi Bot
help:Hi Smart
help:Hello Bot
Hola Bot
Hallo Bot
What's up Bot
Hey Bot
Hæ Bot
help:Hello THE_NAME_OF_THE_BOT
help: Also apart of Hello you can use Hallo, Hi, Hola, What's up, Hey, Hæ help: Bot starts listening to you help: After that if you want to avoid a single message to be treated by the smart bot, start the message by - help:. -
#initialize(config) ⇒ SlackSmartBot
constructor
A new instance of SlackSmartBot.
-
#kill_bot_on_channel(dest, from, channel) ⇒ Object
helpmaster: ---------------------------------------------- helpmaster:
kill bot on CHANNEL_NAME
helpmaster: kills the bot on the specified channel helpmaster: Only works if you are on Master channel and you created that bot or you are an admin user helpmaster:. - #listen ⇒ Object
- #listen_simulate ⇒ Object
-
#notify_message(dest, from, where, message) ⇒ Object
helpmaster: ---------------------------------------------- helpmaster:
notify MESSAGE
helpmaster:notify all MESSAGE
helpmaster:notify #CHANNEL_NAME MESSAGE
helpmaster: It will send a notification message to all bot channels helpmaster: It will send a notification message to all channels the bot joined and private conversations with the bot helpmaster: It will send a notification message to the specified channel and to its extended channels helpmaster: Only works if you are on Master channel and you are a master admin user helpmaster:. -
#pause_bot(dest, from) ⇒ Object
helpadmin: ---------------------------------------------- helpadmin:
pause bot
helpadmin:pause this bot
helpadmin: the bot will pause so it will listen only to admin commands helpadmin: You can use this command only if you are an admin user helpadmin:. -
#pause_routine(dest, from, name) ⇒ Object
helpadmin: ---------------------------------------------- helpadmin:
pause routine NAME
helpadmin: It will pause the specified routine helpadmin: You can use this command only if you are an admin user helpadmin: NAME: one word to identify the routine helpadmin: Examples: helpadmin: pause routine example helpadmin:. - #process(user, command, dest, dchannel, rules_file, typem, files, ts) ⇒ Object
- #process_first(user, text, dest, dchannel, typem, files, ts, thread_ts) ⇒ Object
-
#react(emoji, parent = false) ⇒ Object
list of available emojis: https://www.webfx.com/tools/emoji-cheat-sheet/ react(:thumbsup).
- #remove_hash_keys(hash, key) ⇒ Object
-
#remove_routine(dest, from, name) ⇒ Object
helpadmin: ---------------------------------------------- helpadmin:
kill routine NAME
helpadmin:delete routine NAME
helpadmin:remove routine NAME
helpadmin: It will kill and remove the specified routine helpadmin: You can use this command only if you are an admin user helpadmin: NAME: one word to identify the routine helpadmin: Examples: helpadmin: kill routine example helpadmin:. -
#repl(dest, user, session_name, env_vars, rules_file, command, description, type) ⇒ Object
help: ---------------------------------------------- help:
repl
help:live
help:irb
help:repl SESSION_NAME
help:private repl SESSION_NAME
help:repl ENV_VAR=VALUE
help:repl SESSION_NAME ENV_VAR=VALUE ENV_VAR='VALUE'
help:repl SESSION_NAME: "DESCRIPTION"
help:repl SESSION_NAME: "DESCRIPTION" ENV_VAR=VALUE ENV_VAR='VALUE'
help: help: Will run all we write as a ruby command and will keep the session values. - #respond(msg, dest = nil) ⇒ Object
- #respond_direct(msg) ⇒ Object
-
#ruby_code(dest, user, code, rules_file) ⇒ Object
help: ---------------------------------------------- help:
ruby RUBY_CODE
help:code RUBY_CODE
help: runs the code supplied and returns the output. -
#run_repl(dest, user, session_name, env_vars, rules_file) ⇒ Object
help: ---------------------------------------------- help:
run repl SESSION_NAME
help:run repl SESSION_NAME ENV_VAR=VALUE ENV_VAR=VALUE
help:run live SESSION_NAME
help:run irb SESSION_NAME
help: help: Will run the repl session specified and return the output. -
#run_routine(dest, from, name) ⇒ Object
helpadmin: ---------------------------------------------- helpadmin:
run routine NAME
helpadmin:execute routine NAME
helpadmin: It will run the specified routine helpadmin: You can use this command only if you are an admin user helpadmin: NAME: one word to identify the routine helpadmin: Examples: helpadmin: run routine example helpadmin:. - #save_stats(method) ⇒ Object
-
#see_repls(dest, user, typem) ⇒ Object
help: ---------------------------------------------- help:
see repls
help:see irbs
help: It will display the repls help:. -
#see_routines(dest, from, user, all) ⇒ Object
helpadmin: ---------------------------------------------- helpadmin:
see routines
helpadmin:see all routines
helpadmin: It will show the routines of the channel helpadmin: In case ofall
and on the master channel, it will show all the routines from all channels helpadmin: You can use this command only if you are an admin user helpadmin:. -
#see_shortcuts(dest, user, typem) ⇒ Object
help: ---------------------------------------------- help:
see shortcuts
help:see sc
help: It will display the shortcuts stored for the user and for :all help:. -
#send_file(to, msg, file, title, format, type = "text") ⇒ Object
to send a file to an user or channel send_file(dest, 'the message', "##project_folder/temp/logs_ptBI.log", 'message to be sent', 'text/plain', "text") send_file(dest, 'the message', "##project_folder/temp/example.jpeg", 'message to be sent', 'image/jpeg', "jpg").
-
#send_msg_channel(to, msg) ⇒ Object
to: (String) Channel name or id msg: (String) message to send.
-
#send_msg_user(id_user, msg) ⇒ Object
to send messages without listening for a response to users.
-
#start_bot(dest, from) ⇒ Object
helpadmin: ---------------------------------------------- helpadmin:
start bot
helpadmin:start this bot
helpadmin: the bot will start to listen helpadmin: You can use this command only if you are an admin user helpadmin:. -
#start_routine(dest, from, name) ⇒ Object
helpadmin: ---------------------------------------------- helpadmin:
start routine NAME
helpadmin: It will start a paused routine helpadmin: You can use this command only if you are an admin user helpadmin: NAME: one word to identify the routine helpadmin: Examples: helpadmin: start routine example helpadmin:. -
#stop_using_rules(dest, channel, user, dchannel) ⇒ Object
help: ---------------------------------------------- help:
stop using rules from CHANNEL
help: it will stop using the rules from the specified channel. -
#stop_using_rules_on(dest, user, from, channel, typem) ⇒ Object
helpadmin: ---------------------------------------------- helpadmin:
stop using rules on CHANNEL_NAME
helpadmin: it will stop using the extended rules on the specified channel. - #treat_message(data, remove_blocks = true) ⇒ Object
- #update_bots_file ⇒ Object
- #update_repls(channel = @channel_id) ⇒ Object
- #update_routines(channel = @channel_id) ⇒ Object
- #update_rules_imported ⇒ Object
- #update_shortcuts_file ⇒ Object
-
#use_rules(dest, channel, user, dchannel) ⇒ Object
help: ---------------------------------------------- help:
use rules from CHANNEL
help:use rules CHANNEL
help:use CHANNEL
help: it will use the rules from the specified channel.
Constructor Details
#initialize(config) ⇒ SlackSmartBot
Returns a new instance of SlackSmartBot.
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 |
# File 'lib/slack-smart-bot.rb', line 33 def initialize(config) if config.key?(:path) and config[:path] != '' config.path.chop! if config.path[-1]=="/" else config[:path] = '.' end if ENV['BOT_SILENT'].to_s == 'true' config[:silent] = true elsif ENV['BOT_SILENT'].to_s == 'false' config[:silent] = false else config[:silent] = false unless config.key?(:silent) end config[:testing] = false unless config.key?(:testing) config[:simulate] = false unless config.key?(:simulate) config[:stats] = false unless config.key?(:stats) config[:allow_access] = Hash.new unless config.key?(:allow_access) if config.path.to_s!='' and config.file.to_s=='' config.file = File.basename($0) end if config.key?(:file) and config.file!='' config.file_path = "#{config.path}/#{config.file}" else config.file_path = $0 config.file = File.basename(config.file_path) config.path = File.dirname(config.file_path) end if config.stats Dir.mkdir("#{config.path}/stats") unless Dir.exist?("#{config.path}/stats") config.stats_path = "#{config.path}/stats/#{config.file.gsub(".rb", ".stats")}" end Dir.mkdir("#{config.path}/logs") unless Dir.exist?("#{config.path}/logs") Dir.mkdir("#{config.path}/shortcuts") unless Dir.exist?("#{config.path}/shortcuts") Dir.mkdir("#{config.path}/routines") unless Dir.exist?("#{config.path}/routines") config.masters = MASTER_USERS if config.masters.to_s=='' and defined?(MASTER_USERS) config.master_channel = MASTER_CHANNEL if config.master_channel.to_s=='' and defined?(MASTER_CHANNEL) if ARGV.size == 0 or (config.file.to_s!='' and config.file.to_s!=File.basename($0)) config.rules_file = "#{config.file.gsub(".rb", "_rules.rb")}" unless config.rules_file.to_s!='' unless File.exist?(config.path + '/' + config.rules_file) default_rules = (__FILE__).gsub(/\.rb$/, "_rules.rb") FileUtils.copy_file(default_rules, config.path + '/' + config.rules_file) end config.admins = config.masters unless config.admins.to_s!='' config.channel = config.master_channel unless config.channel.to_s!='' config.status_init = :on unless config.status_init.to_s!='' else config.rules_file = ARGV[2] config.admins = ARGV[1].split(",") config.channel = ARGV[0] config.status_init = ARGV[3].to_sym end config.rules_file[0]='' if config.rules_file[0]=='.' config.rules_file='/'+config.rules_file if config.rules_file[0]!='/' config.shortcuts_file = "slack-smart-bot_shortcuts_#{config.channel}.rb".gsub(" ", "_") if config.channel == config.master_channel config.on_master_bot = true config.start_bots = true unless config.key?(:start_bots) else config.on_master_bot = false end if !config.key?(:token) or config.token.to_s == '' abort "You need to supply a valid token key on the settings. key: :token" elsif !config.key?(:masters) or !config.masters.is_a?(Array) or config.masters.size == 0 abort "You need to supply a masters array on the settings containing the user names of the master admins. key: :masters" elsif !config.key?(:master_channel) or config.master_channel.to_s == '' abort "You need to supply a master_channel on the settings. key: :master_channel" elsif !config.key?(:channel) or config.channel.to_s == '' abort "You need to supply a bot channel name on the settings. key: :channel" end logfile = File.basename(config.rules_file.gsub("_rules_", "_logs_"), ".rb") + ".log" config.log_file = logfile @logger = Logger.new("#{config.path}/logs/#{logfile}") config_log = config.dup config_log.delete(:token) @logger.info "Initializing bot: #{config_log.inspect}" File.new("#{config.path}/buffer.log", "w") if config[:testing] and config.on_master_bot File.new("#{config.path}/buffer_complete.log", "w") if config[:simulate] and config.on_master_bot self.config = config Slack.configure do |conf| conf.token = config[:token] end restarts = 0 created = false while restarts < 200 and !created begin @logger.info "Connecting #{config_log.inspect}" self.client = Slack::RealTime::Client.new(start_method: :rtm_connect) created = true rescue Exception => e restarts += 1 if restarts < 200 @logger.fatal "*" * 50 @logger.fatal "Rescued on creation: #{e.inspect}" @logger.info "Waiting 60 seconds to retry. restarts: #{restarts}" puts "#{Time.now}: Not able to create client. Waiting 60 seconds to retry: #{config_log.inspect}" sleep 60 else exit! end end end @listening = Hash.new() @bots_created = Hash.new() @shortcuts = Hash.new() @shortcuts[:all] = Hash.new() @rules_imported = Hash.new() @routines = Hash.new() @repls = Hash.new() if File.exist?("#{config.path}/shortcuts/#{config.shortcuts_file}") file_sc = IO.readlines("#{config.path}/shortcuts/#{config.shortcuts_file}").join unless file_sc.to_s() == "" @shortcuts = eval(file_sc) end end get_routines() get_repls() if config.on_master_bot and File.exist?(config.file_path.gsub(".rb", "_bots.rb")) get_bots_created() if @bots_created.kind_of?(Hash) and config.start_bots @bots_created.each { |key, value| if !value.key?(:cloud) or (value.key?(:cloud) and value[:cloud] == false) @logger.info "ruby #{config.file_path} \"#{value[:channel_name]}\" \"#{value[:admins]}\" \"#{value[:rules_file]}\" #{value[:status].to_sym}" puts "Starting #{value[:channel_name]} Smart Bot" t = Thread.new do `ruby #{config.file_path} \"#{value[:channel_name]}\" \"#{value[:admins]}\" \"#{value[:rules_file]}\" #{value[:status].to_sym}` end value[:thread] = t sleep value[:admins].size end } end end get_rules_imported() begin @admin_users_id = [] config.admins.each do |au| user_info = client.web_client.users_info(user: "@#{au}") @admin_users_id << user_info.user.id sleep 1 end rescue Slack::Web::Api::Errors::TooManyRequestsError @logger.fatal "TooManyRequestsError" abort("TooManyRequestsError please re run the bot and be sure of executing first: killall ruby") rescue Exception => stack abort("The admin user specified on settings: #{config.admins.join(", ")}, doesn't exist on Slack. Execution aborted") end client.on :hello do m = "Successfully connected, welcome '#{client.self.name}' to the '#{client.team.name}' team at https://#{client.team.domain}.slack.com." puts m @logger.info m config.nick = client.self.name config.nick_id = client.self.id @salutations = [config[:nick], "<@#{config[:nick_id]}>", "bot", "smart"] gems_remote = `gem list slack-smart-bot --remote` version_remote = gems_remote.to_s().scan(/slack-smart-bot \((\d+\.\d+\.\d+)/).join = "" if version_remote != VERSION = ". There is a new available version: #{version_remote}." end unless config[:silent] respond "Smart Bot started v#{VERSION}#{}\nIf you want to know what I can do for you: `bot help`.\n`bot rules` if you want to display just the specific rules of this channel.\nYou can talk to me privately if you prefer it." end @routines.each do |ch, rout| rout.each do |k, v| if !v[:running] and v[:channel_name] == config.channel create_routine_thread(k) end end end end @status = config.status_init @questions = Hash.new() @repl_sessions = Hash.new() @channels_id = Hash.new() @channels_name = Hash.new() get_channels_name_and_id() @channel_id = @channels_id[config.channel].dup @master_bot_id = @channels_id[config.master_channel].dup get_routines() get_repls() if @routines.key?(@channel_id) @routines[@channel_id].each do |k, v| @routines[@channel_id][k][:running] = false end end update_routines() if config.simulate #not necessary to wait until bot started (client.on :hello) @routines.each do |ch, rout| rout.each do |k, v| if !v[:running] and v[:channel_name] == config.channel create_routine_thread(k) end end end end client.on :close do |_data| m = "Connection closing, exiting. #{Time.now}" @logger.info m @logger.info _data end client.on :closed do |_data| m = "Connection has been disconnected. #{Time.now}" @logger.info m @logger.info _data end self end |
Instance Attribute Details
#channel_id ⇒ Object (readonly)
Returns the value of attribute channel_id.
24 25 26 |
# File 'lib/slack-smart-bot.rb', line 24 def channel_id @channel_id end |
#client ⇒ Object
Returns the value of attribute client.
23 24 25 |
# File 'lib/slack-smart-bot.rb', line 23 def client @client end |
#config ⇒ Object
Returns the value of attribute config.
23 24 25 |
# File 'lib/slack-smart-bot.rb', line 23 def config @config end |
#master_bot_id ⇒ Object (readonly)
Returns the value of attribute master_bot_id.
24 25 26 |
# File 'lib/slack-smart-bot.rb', line 24 def master_bot_id @master_bot_id end |
Instance Method Details
#add_routine(dest, from, user, name, type, number_time, period, command_to_run, files, silent) ⇒ Object
helpadmin: ----------------------------------------------
helpadmin: add routine NAME every NUMBER PERIOD COMMAND
helpadmin: add routine NAME every NUMBER PERIOD
helpadmin: add silent routine NAME every NUMBER PERIOD
helpadmin: create routine NAME every NUMBER PERIOD
helpadmin: add routine NAME at TIME COMMAND
helpadmin: add routine NAME at TIME
helpadmin: add silent routine NAME at TIME
helpadmin: create routine NAME at TIME
helpadmin: It will execute the command/rule supplied. Only for Admin and Master Admins.
helpadmin: If no COMMAND supplied, then it will be necessary to attach a file with the code to be run and add this command as message to the file. ONLY for MASTER ADMINS.
helpadmin: In case silent provided then when executed will be only displayed if the routine returns a message
helpadmin: NAME: one word to identify the routine
helpadmin: NUMBER: Integer
helpadmin: PERIOD: days, d, hours, h, minutes, mins, min, m, seconds, secs, sec, s
helpadmin: TIME: time at format HH:MM:SS
helpadmin: COMMAND: any valid smart bot command or rule
helpadmin: Examples:
helpadmin: add routine example every 30s ruby puts 'a'
helpadmin: add routine example every 3 days ruby puts 'a'
helpadmin: add routine example at 17:05 ruby puts 'a'
helpadmin: create silent routine every 12 hours !Run customer tests
helpadmin:
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/slack/smart-bot/commands/on_bot/admin/add_routine.rb', line 25 def add_routine(dest, from, user, name, type, number_time, period, command_to_run, files, silent) save_stats(__method__) if files.nil? or files.size == 0 or (files.size > 0 and config.masters.include?(from)) if config.admins.include?(from) if @routines.key?(@channel_id) && @routines[@channel_id].key?(name) respond "I'm sorry but there is already a routine with that name.\nCall `see routines` to see added routines", dest else number_time += ":00" if number_time.split(":").size == 2 if (type == "at") && !number_time.match?(/^[01][0-9]:[0-5][0-9]:[0-5][0-9]$/) && !number_time.match?(/^2[0-3]:[0-5][0-9]:[0-5][0-9]$/) respond "Wrong time specified: *#{number_time}*" else file_path = "" every = "" at = "" next_run = Time.now case period.downcase when "days", "d" every = "#{number_time} days" every_in_seconds = number_time.to_i * 24 * 60 * 60 when "hours", "h" every = "#{number_time} hours" every_in_seconds = number_time.to_i * 60 * 60 when "minutes", "mins", "min", "m" every = "#{number_time} minutes" every_in_seconds = number_time.to_i * 60 when "seconds", "secs", "sec", "s" every = "#{number_time} seconds" every_in_seconds = number_time.to_i else # time at = number_time if next_run.strftime("%H:%M:%S") < number_time nt = number_time.split(":") next_run = Time.new(next_run.year, next_run.month, next_run.day, nt[0], nt[1], nt[2]) else next_run += (24 * 60 * 60) # one more day nt = number_time.split(":") next_run = Time.new(next_run.year, next_run.month, next_run.day, nt[0], nt[1], nt[2]) end every_in_seconds = 24 * 60 * 60 end Dir.mkdir("#{config.path}/routines/#{@channel_id}") unless Dir.exist?("#{config.path}/routines/#{@channel_id}") if !files.nil? && (files.size == 1) @logger.info files[0].inspect if config.testing file_path = "#{config.path}/routines/#{@channel_id}/#{name}#{files[0].name.scan(/[^\.]+(\.\w+$)/).join}" if files[0].filetype == "ruby" and files[0].name.scan(/[^\.]+(\.\w+$)/).join == '' file_path += ".rb" end http = NiceHttp.new(host: "https://files.slack.com", headers: { "Authorization" => "Bearer #{config[:token]}" }, log_headers: :partial) http.get(files[0].url_private_download, save_data: file_path) system("chmod +x #{file_path}") end @routines[@channel_id] = {} unless @routines.key?(@channel_id) @routines[@channel_id][name] = { channel_name: config.channel, creator: from, creator_id: user.id, status: :on, every: every, every_in_seconds: every_in_seconds, at: at, file_path: file_path, command: command_to_run.to_s.strip, silent: silent, next_run: next_run.to_s, dest: dest, last_run: "", last_elapsed: "", running: false } update_routines respond "Added routine *`#{name}`* to the channel", dest create_routine_thread(name) end end else respond "Only admin users can use this command", dest end else respond "Only master admin users can add files to routines", dest end end |
#add_shortcut(dest, user, typem, for_all, shortcut_name, command, command_to_run) ⇒ Object
help: ----------------------------------------------
help: add shortcut NAME: COMMAND
help: add sc NAME: COMMAND
help: add shortcut for all NAME: COMMAND
help: add sc for all NAME: COMMAND
help: shortcut NAME: COMMAND
help: shortcut for all NAME: COMMAND
help: It will add a shortcut that will execute the command we supply.
help: In case we supply 'for all' then the shorcut will be available for everybody
help: If you want to use a shortcut as a inline shortcut inside a command you can do it by adding a $ fex: !run tests $cust1
help: Example:
help: add shortcut for all Spanish account: code require 'iso/iban'; 10.times ISO::IBAN.random('ES')
help: Then to call this shortcut:
help: sc spanish account
help: shortcut Spanish Account
help: Spanish Account
help:
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/slack/smart-bot/commands/on_bot/add_shortcut.rb', line 20 def add_shortcut(dest, user, typem, for_all, shortcut_name, command, command_to_run) save_stats(__method__) unless typem == :on_extended from = user.name if config[:allow_access].key?(__method__) and !config[:allow_access][__method__].include?(user.name) and !config[:allow_access][__method__].include?(user.id) and (!user.key?(:enterprise_user) or ( user.key?(:enterprise_user) and !config[:allow_access][__method__].include?(user[:enterprise_user].id))) respond "You don't have access to use this command, please contact an Admin to be able to use it: <@#{config.admins.join(">, <@")}>" else @shortcuts[from] = Hash.new() unless @shortcuts.keys.include?(from) found_other = false if for_all.to_s != "" @shortcuts.each { |sck, scv| if sck != :all and sck != from and scv.key?(shortcut_name) found_other = true end } end if !config.admins.include?(from) and @shortcuts[:all].include?(shortcut_name) and !@shortcuts[from].include?(shortcut_name) respond "Only the creator of the shortcut can modify it", dest elsif found_other respond "You cannot create a shortcut for all with the same name than other user is using", dest elsif !@shortcuts[from].include?(shortcut_name) #new shortcut @shortcuts[from][shortcut_name] = command_to_run @shortcuts[:all][shortcut_name] = command_to_run if for_all.to_s != "" update_shortcuts_file() respond "shortcut added", dest else #are you sure? to avoid overwriting existing unless @questions.keys.include?(from) ask("The shortcut already exists, are you sure you want to overwrite it?", command, from, dest) else case @questions[from] when /^(yes|yep)/i @shortcuts[from][shortcut_name] = command_to_run @shortcuts[:all][shortcut_name] = command_to_run if for_all.to_s != "" update_shortcuts_file() respond "shortcut added", dest @questions.delete(from) when /^no/i respond "ok, I won't add it", dest @questions.delete(from) else ask "I don't understand, yes or no?", command, from, dest end end end end end end |
#ask(question, context = nil, to = nil, dest = nil) ⇒ Object
context: previous message to: user that should answer
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
# File 'lib/slack/smart-bot/comm/ask.rb', line 5 def ask(question, context = nil, to = nil, dest = nil) if dest.nil? and Thread.current.key?(:dest) dest = Thread.current[:dest] end if to.nil? to = Thread.current[:user].name end if context.nil? context = Thread.current[:command] end = "#{to}: #{question}" if dest.nil? if config[:simulate] open("#{config.path}/buffer_complete.log", "a") { |f| f.puts "|#{@channel_id}|#{config[:nick_id]}|#{}~~~" } else if Thread.current[:on_thread] client.(channel: @channel_id, text: , as_user: true, thread_ts: Thread.current[:thread_ts]) else client.(channel: @channel_id, text: , as_user: true) end end if config[:testing] and config.on_master_bot open("#{config.path}/buffer.log", "a") { |f| f.puts "|#{@channel_id}|#{config[:nick_id]}|#{}" } end elsif dest[0] == "C" or dest[0] == "G" # channel if config[:simulate] open("#{config.path}/buffer_complete.log", "a") { |f| f.puts "|#{dest}|#{config[:nick_id]}|#{}~~~" } else if Thread.current[:on_thread] client.(channel: dest, text: , as_user: true, thread_ts: Thread.current[:thread_ts]) else client.(channel: dest, text: , as_user: true) end end if config[:testing] and config.on_master_bot open("#{config.path}/buffer.log", "a") { |f| f.puts "|#{dest}|#{config[:nick_id]}|#{}" } end elsif dest[0] == "D" #private message send_msg_user(dest, ) end @questions[to] = context end |
#bot_help(user, from, dest, dchannel, specific, help_command, rules_file) ⇒ Object
help: ----------------------------------------------
help: bot help
help: bot help COMMAND
help: bot rules
help: bot rules COMMAND
help: bot what can I do?
help: it will display this help
help: if COMMAND supplied just help for that command
help: bot rules
will show only the specific rules for this channel.
help:
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
# File 'lib/slack/smart-bot/commands/general/bot_help.rb', line 13 def bot_help(user, from, dest, dchannel, specific, help_command, rules_file) save_stats(__method__) if config[:allow_access].key?(__method__) and !config[:allow_access][__method__].include?(user.name) and !config[:allow_access][__method__].include?(user.id) and (!user.key?(:enterprise_user) or ( user.key?(:enterprise_user) and !config[:allow_access][__method__].include?(user[:enterprise_user].id))) respond "You don't have access to use this command, please contact an Admin to be able to use it: <@#{config.admins.join(">, <@")}>" else help_found = false = "" = get_help(rules_file, dest, from, specific) if help_command.to_s != "" .gsub(/====+/,'-'*30).split(/^\s*-------*$/).each do |h| if h.match?(/[`_]#{help_command}/i) respond h, dest help_found = true end end else if Thread.current[:using_channel]!='' = "*You are using rules from another channel: <##{Thread.current[:using_channel]}>. These are the specific commands for that channel:*" end respond , dest end if (help_command.to_s == "") .split(/^\s*=========*$/).each do |h| respond("#{"=" * 35}\n#{h}", dest) unless h.match?(/\A\s*\z/) end else unless help_found if specific respond("I didn't find any rule starting by `#{help_command}`", dest) else respond("I didn't find any command starting by `#{help_command}`", dest) end end end if specific unless rules_file.empty? begin eval(File.new(config.path + rules_file).read) if File.exist?(config.path + rules_file) end end if defined?(git_project) && (git_project.to_s != "") && (help_command.to_s == "") respond "Git project: #{git_project}", dest else def git_project "" end def project_folder "" end end elsif help_command.to_s == "" respond "Slack Smart Bot Github project: https://github.com/MarioRuiz/slack-smart-bot", dest end end end |
#bot_rules(dest, help_command, typem, rules_file, user) ⇒ Object
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
# File 'lib/slack/smart-bot/commands/on_extended/bot_rules.rb', line 2 def bot_rules(dest, help_command, typem, rules_file, user) save_stats(__method__) from = user.name if config[:allow_access].key?(__method__) and !config[:allow_access][__method__].include?(user.name) and !config[:allow_access][__method__].include?(user.id) and (!user.key?(:enterprise_user) or ( user.key?(:enterprise_user) and !config[:allow_access][__method__].include?(user[:enterprise_user].id))) respond "You don't have access to use this command, please contact an Admin to be able to use it: <@#{config.admins.join(">, <@")}>" else if typem == :on_extended or typem == :on_call #for the other cases above. help_filtered = get_help(rules_file, dest, from, true) if help_command.to_s != "" help_found = false help_filtered.split(/^\s*-------*$/).each do |h| if h.match?(/[`_]#{help_command}/i) respond "*#{config.channel}*:#{h}", dest help_found = true end end respond("*#{config.channel}*: I didn't find any command starting by `#{help_command}`", dest) unless help_found else = "-\n\n\n===================================\n*Rules from channel #{config.channel}*\n" if typem == :on_extended += "To run the commands on this extended channel, add `!`, `!!` or `^` before the command.\n" end += help_filtered respond , dest end unless rules_file.empty? begin eval(File.new(config.path+rules_file).read) if File.exist?(config.path+rules_file) end end if defined?(git_project) and git_project.to_s != "" and help_command.to_s == "" respond "Git project: #{git_project}", dest else def git_project() "" end def project_folder() "" end end end end end |
#bot_stats(dest, from_user, typem, channel_id, from, to, user, exclude_masters, exclude_command) ⇒ Object
helpadmin: ----------------------------------------------
helpadmin: bot stats
helpadmin: bot stats USER_NAME
helpadmin: bot stats exclude masters
helpadmin: bot stats from YYYY/MM/DD
helpadmin: bot stats from YYYY/MM/DD to YYYY/MM/DD
helpadmin: bot stats CHANNEL
helpadmin: bot stats CHANNEL from YYYY/MM/DD
helpadmin: bot stats CHANNEL from YYYY/MM/DD to YYYY/MM/DD
helpadmin: bot stats USER_NAME from YYYY/MM/DD to YYYY/MM/DD
helpadmin: bot stats CHANNEL USER_NAME from YYYY/MM/DD to YYYY/MM/DD
helpadmin: bot stats CHANNEL exclude masters from YYYY/MM/DD to YYYY/MM/DD
helpadmin: bot stats today
helpadmin: bot stats exclude COMMAND_ID
helpadmin: To see the bot stats
helpadmin: You can use this command only if you are a Master admin user and if you are in a private conversation with the bot
helpadmin: You need to set stats to true to generate the stats when running the bot instance.
helpadmin: Examples:
helpadmin: bot stats #sales
helpadmin: bot stats @peter.wind
helpadmin: bot stats #sales from 2019/12/15 to 2019/12/31
helpadmin: bot stats #sales today
helpadmin:
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/slack/smart-bot/commands/on_bot/admin_master/bot_stats.rb', line 25 def bot_stats(dest, from_user, typem, channel_id, from, to, user, exclude_masters, exclude_command) require 'csv' if config.stats = [] else = ["You need to set stats to true to generate the stats when running the bot instance."] end save_stats(__method__) if config.masters.include?(from_user) and typem==:on_dm #master admin user if !File.exist?("#{config.stats_path}.#{Time.now.strftime("%Y-%m")}.log") <<'No stats' else from = "#{Time.now.strftime("%Y-%m")}-01" if from == '' to = "#{Time.now.strftime("%Y-%m-%d")}" if to == '' from_short = from to_short = to from_file = from[0..3] + '-' + from[5..6] to_file = to[0..3] + '-' + to[5..6] from+= " 00:00:00 +0000" to+= " 23:59:59 +0000" rows = [] Dir["#{config.stats_path}.*.log"].sort.each do |file| if file >= "#{config.stats_path}.#{from_file}.log" or file <= "#{config.stats_path}.#{to_file}.log" CSV.foreach(file, headers: true, header_converters: :symbol, converters: :numeric) do |row| row[:date] = row[:date].to_s if !exclude_masters or (exclude_masters and !config.masters.include?(row[:user_name])) if user=='' or (user!='' and row[:user_id] == user) if exclude_command == '' or (exclude_command!='' and row[:command]!=exclude_command) if row[:bot_channel_id] == channel_id or channel_id == '' if row[:date] >= from and row[:date] <= to rows << row.to_h end end end end end end end end total = rows.size if exclude_masters << 'Excluding master admins' end if exclude_command != '' << "Excluding command #{exclude_command}" end if user!='' << "Showing only user <@#{user}>" end if channel_id == '' << "*Total calls*: #{total} from #{from_short} to #{to_short}" else << "*Total calls <##{channel_id}>*: #{total} from #{from_short} to #{to_short}" end if total > 0 if channel_id == '' << "*Channels*" channels = rows.bot_channel.uniq.sort channels.each do |channel| count = rows.count {|h| h.bot_channel==channel} << "\t#{channel}: #{count} (#{(count.to_f*100/total).round(2)}%)" end end if user=='' << "*Users*" users = rows.user_name.uniq.sort users.each do |user| count = rows.count {|h| h.user_name==user} << "\t#{user}: #{count} (#{(count.to_f*100/total).round(2)}%)" end end << "*Commands*" commands = rows.command.uniq.sort commands.each do |command| count = rows.count {|h| h.command==command} << "\t#{command}: #{count} (#{(count.to_f*100/total).round(2)}%)" end << "*Message type*" types = rows..uniq.sort types.each do |type| count = rows.count {|h| h.==type} << "\t#{type}: #{count} (#{(count.to_f*100/total).round(2)}%)" end << "*Last activity*: #{rows[-1].date} #{rows[-1].bot_channel} #{rows[-1].} #{rows[-1].user_name} #{rows[-1].command}" end end else <<"Only Master admin users on a private conversation with the bot can see the bot stats." end respond "#{.join("\n")}", dest end |
#bot_status(dest, user) ⇒ Object
helpadmin: ----------------------------------------------
helpadmin: bot status
helpadmin: Displays the status of the bot
helpadmin: If on master channel and admin user also it will display info about bots created
helpadmin:
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
# File 'lib/slack/smart-bot/commands/general/bot_status.rb', line 7 def bot_status(dest, user) save_stats(__method__) get_bots_created() if config[:allow_access].key?(__method__) and !config[:allow_access][__method__].include?(user.name) and !config[:allow_access][__method__].include?(user.id) and (!user.key?(:enterprise_user) or ( user.key?(:enterprise_user) and !config[:allow_access][__method__].include?(user[:enterprise_user].id))) respond "You don't have access to use this command, please contact an Admin to be able to use it: <@#{config.admins.join(">, <@")}>" else gems_remote = `gem list slack-smart-bot --remote` version_remote = gems_remote.to_s().scan(/slack-smart-bot \((\d+\.\d+\.\d+)/).join = "" if version_remote != VERSION = " There is a new available version: #{version_remote}." end require "socket" ip_address = Socket.ip_address_list.find { |ai| ai.ipv4? && !ai.ipv4_loopback? }.ip_address respond "*#{Socket.gethostname} (#{ip_address})*\n\tStatus: #{@status}.\n\tVersion: #{VERSION}.#{}\n\tRules file: #{File.basename config.rules_file}\n\tExtended: #{@bots_created[@channel_id][:extended] unless config.on_master_bot}\n\tAdmins: #{config.admins}\n\tBot time: #{Time.now}", dest if @status == :on respond "I'm listening to [#{@listening.keys.join(", ")}]", dest if config.on_master_bot and config.admins.include?(user.name) sleep 5 @bots_created.each do |k, v| msg = [] msg << "`#{v[:channel_name]}` (#{k}):" msg << "\tcreator: #{v[:creator_name]}" msg << "\tadmins: #{v[:admins]}" msg << "\tstatus: #{v[:status]} #{" *(not responded)*" unless @pings.include?(v[:channel_name])}" msg << "\tcreated: #{v[:created]}" msg << "\trules: #{v[:rules_file]}" msg << "\textended: #{v[:extended]}" msg << "\tcloud: #{v[:cloud]}" if config.on_master_bot and v.key?(:cloud) and v[:cloud] msg << "\trunner: `ruby #{config.file} \"#{v[:channel_name]}\" \"#{v[:admins]}\" \"#{v[:rules_file]}\" on&`" end respond msg.join("\n"), dest end @pings = [] end end end end |
#build_help(path) ⇒ Object
3 4 5 6 7 8 9 10 11 12 13 |
# File 'lib/slack/smart-bot/utils/build_help.rb', line 3 def build_help(path) = {} Dir["#{path}/*"].each do |t| if Dir.exist?(t) [t.scan(/\/(\w+)$/).join.to_sym] = build_help(t) else [t.scan(/\/(\w+)\.rb$/).join.to_sym] = IO.readlines(t).join.scan(/#\s*help\s*\w*:(.*)/).join("\n") end end return end |
#bye_bot(dest, from, display_name) ⇒ Object
help: ----------------------------------------------
help: Bye Bot
help: Bye Smart
help: Bye NAME_OF_THE_BOT
help: Also apart of Bye you can use Bæ, Good Bye, Adiós, Ciao, Bless, Bless Bless, Adeu
help: Bot stops listening to you
help:
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
# File 'lib/slack/smart-bot/commands/general/bye_bot.rb', line 10 def bye_bot(dest, from, display_name) if @status == :on save_stats(__method__) bye = ["Bye", "Bæ", "Good Bye", "Adiós", "Ciao", "Bless", "Bless bless", "Adeu"].sample respond "#{bye} #{display_name}", dest if @listening.key?(from) if Thread.current[:on_thread] @listening[from].delete(Thread.current[:thread_ts]) else @listening[from].delete(dest) end @listening.delete(from) if @listening[from].empty? end end end |
#create_bot(dest, user, cloud, channel) ⇒ Object
helpmaster: ----------------------------------------------
helpmaster: create bot on CHANNEL_NAME
helpmaster: create cloud bot on CHANNEL_NAME
helpmaster: creates a new bot on the channel specified
helpmaster: it will work only if you are on Master channel
helpmaster: the admins will be the master admins, the creator of the bot and the creator of the channel
helpmaster: follow the instructions in case creating cloud bots
helpmaster:
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
# File 'lib/slack/smart-bot/commands/on_master/create_bot.rb', line 10 def create_bot(dest, user, cloud, channel) save_stats(__method__) from = user.name if config[:allow_access].key?(__method__) and !config[:allow_access][__method__].include?(user.name) and !config[:allow_access][__method__].include?(user.id) and (!user.key?(:enterprise_user) or ( user.key?(:enterprise_user) and !config[:allow_access][__method__].include?(user[:enterprise_user].id))) respond "You don't have access to use this command, please contact an Admin to be able to use it: <@#{config.admins.join(">, <@")}>" else if config.on_master_bot get_channels_name_and_id() unless @channels_name.keys.include?(channel) or @channels_id.keys.include?(channel) channel_id = nil if @channels_name.key?(channel) #it is an id channel_id = channel channel = @channels_name[channel_id] elsif @channels_id.key?(channel) #it is a channel name channel_id = @channels_id[channel] end #todo: add pagination for case more than 1000 channels on the workspace channels = client.web_client.conversations_list( types: "private_channel,public_channel", limit: "1000", exclude_archived: "true", ).channels channel_found = channels.detect { |c| c.name == channel } members = client.web_client.conversations_members(channel: @channels_id[channel]).members unless channel_found.nil? if channel_id.nil? respond "There is no channel with that name: #{channel}, please be sure is written exactly the same", dest elsif channel == config.master_channel respond "There is already a bot in this channel: #{channel}", dest elsif @bots_created.keys.include?(channel_id) respond "There is already a bot in this channel: #{channel}, kill it before", dest elsif config[:nick_id] != channel_found.creator and !members.include?(config[:nick_id]) respond "You need to add first to the channel the smart bot user: #{config[:nick]}", dest else if channel_id != config[:channel] begin rules_file = "slack-smart-bot_rules_#{channel_id}_#{from.gsub(" ", "_")}.rb" if defined?(RULES_FOLDER) rules_file = RULES_FOLDER + rules_file else Dir.mkdir("#{config.path}/rules") unless Dir.exist?("#{config.path}/rules") Dir.mkdir("#{config.path}/rules/#{channel_id}") unless Dir.exist?("#{config.path}/rules/#{channel_id}") rules_file = "/rules/#{channel_id}/" + rules_file end default_rules = (__FILE__).gsub(/slack\/smart-bot\/commands\/on_master\/create_bot\.rb$/, "slack-smart-bot_rules.rb") File.delete(config.path + rules_file) if File.exist?(config.path + rules_file) FileUtils.copy_file(default_rules, config.path + rules_file) unless File.exist?(config.path + rules_file) admin_users = Array.new() creator_info = client.web_client.users_info(user: channel_found.creator) admin_users = [from, creator_info.user.name] + config.masters admin_users.uniq! @logger.info "ruby #{config.file_path} \"#{channel}\" \"#{admin_users.join(",")}\" \"#{rules_file}\" on" if cloud respond "Copy the bot folder to your cloud location and run `ruby #{config.file} \"#{channel}\" \"#{admin_users.join(",")}\" \"#{rules_file}\" on&`", dest else t = Thread.new do `BOT_SILENT=false ruby #{config.file_path} \"#{channel}\" \"#{admin_users.join(",")}\" \"#{rules_file}\" on` end end @bots_created[channel_id] = { creator_name: from, channel_id: channel_id, channel_name: @channels_name[channel_id], status: :on, created: Time.now.strftime("%Y-%m-%dT%H:%M:%S.000Z")[0..18], rules_file: rules_file, admins: admin_users.join(","), extended: [], cloud: cloud, thread: t, } respond "The bot has been created on channel: #{channel}. Rules file: #{File.basename rules_file}. Admins: #{admin_users.join(", ")}", dest update_bots_file() rescue Exception => stack @logger.fatal stack = "Problem creating the bot on channel #{channel}. Error: <#{stack}>." @logger.error respond , dest end else respond "There is already a bot in this channel: #{channel}, and it is the Master Channel!", dest end end else respond "Sorry I cannot create bots from this channel, please visit the master channel: <##{@master_bot_id}>", dest end end end |
#create_routine_thread(name) ⇒ Object
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
# File 'lib/slack/smart-bot/utils/create_routine_thread.rb', line 3 def create_routine_thread(name) t = Thread.new do while @routines.key?(@channel_id) and @routines[@channel_id].key?(name) @routines[@channel_id][name][:thread] = Thread.current started = Time.now if @status == :on and @routines[@channel_id][name][:status] == :on @logger.info "Routine: #{@routines[@channel_id][name].inspect}" if @routines[@channel_id][name][:file_path].match?(/\.rb$/i) ruby = "ruby " else ruby = "" end @routines[@channel_id][name][:silent] = false if !@routines[@channel_id][name].key?(:silent) if @routines[@channel_id][name][:at] == "" or (@routines[@channel_id][name][:at] != "" and @routines[@channel_id][name][:running] and @routines[@channel_id][name][:next_run] != "" and Time.now.to_s >= @routines[@channel_id][name][:next_run]) if @routines[@channel_id][name][:file_path] != "" process_to_run = "#{ruby}#{Dir.pwd}#{@routines[@channel_id][name][:file_path][1..-1]}" process_to_run = ("cd #{project_folder} &&" + process_to_run) if defined?(project_folder) stdout, stderr, status = Open3.capture3(process_to_run) if !@routines[@channel_id][name][:silent] or (@routines[@channel_id][name][:silent] and (!stderr.match?(/\A\s*\z/) or !stdout.match?(/\A\s*\z/))) respond "routine *`#{name}`*: #{@routines[@channel_id][name][:file_path]}", @routines[@channel_id][name][:dest] end if stderr == "" unless stdout.match?(/\A\s*\z/) respond stdout, @routines[@channel_id][name][:dest] end else respond "#{stdout} #{stderr}", @routines[@channel_id][name][:dest] end else #command if !@routines[@channel_id][name][:silent] respond "routine *`#{name}`*: #{@routines[@channel_id][name][:command]}", @routines[@channel_id][name][:dest] end started = Time.now data = { channel: @routines[@channel_id][name][:dest], user: @routines[@channel_id][name][:creator_id], text: @routines[@channel_id][name][:command], files: nil } (data) end # in case the routine was deleted while running the process if !@routines.key?(@channel_id) or !@routines[@channel_id].key?(name) Thread.exit end @routines[@channel_id][name][:last_run] = started.to_s end if @routines[@channel_id][name][:last_run] == "" and @routines[@channel_id][name][:next_run] != "" #for the first create_routine of one routine with at elapsed = 0 require "time" every_in_seconds = Time.parse(@routines[@channel_id][name][:next_run]) - Time.now elsif @routines[@channel_id][name][:at] != "" #coming from start after pause for 'at' if started.strftime("%H:%M:%S") < @routines[@channel_id][name][:at] nt = @routines[@channel_id][name][:at].split(":") next_run = Time.new(started.year, started.month, started.day, nt[0], nt[1], nt[2]) else next_run = started + (24 * 60 * 60) # one more day nt = @routines[@channel_id][name][:at].split(":") next_run = Time.new(next_run.year, next_run.month, next_run.day, nt[0], nt[1], nt[2]) end @routines[@channel_id][name][:next_run] = next_run.to_s elapsed = 0 every_in_seconds = next_run - started else every_in_seconds = @routines[@channel_id][name][:every_in_seconds] elapsed = Time.now - started @routines[@channel_id][name][:last_elapsed] = elapsed @routines[@channel_id][name][:next_run] = (started + every_in_seconds).to_s end @routines[@channel_id][name][:running] = true @routines[@channel_id][name][:sleeping] = (every_in_seconds - elapsed).ceil update_routines() sleep(@routines[@channel_id][name][:sleeping]) unless elapsed > every_in_seconds else sleep 30 end end end end |
#delete_repl(dest, user, session_name) ⇒ Object
help: ----------------------------------------------
help: delete repl SESSION_NAME
help: delete irb SESSION_NAME
help: remove repl SESSION_NAME
help:
help: Will delete the specified REPL
help: Only the creator of the REPL or an admin can delete REPLs
help:
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
# File 'lib/slack/smart-bot/commands/on_bot/delete_repl.rb', line 10 def delete_repl(dest, user, session_name) #todo: add tests save_stats(__method__) if config[:allow_access].key?(__method__) and !config[:allow_access][__method__].include?(user.name) and !config[:allow_access][__method__].include?(user.id) and (!user.key?(:enterprise_user) or ( user.key?(:enterprise_user) and !config[:allow_access][__method__].include?(user[:enterprise_user].id))) respond "You don't have access to use this command, please contact an Admin to be able to use it: <@#{config.admins.join(">, <@")}>" else if @repls.key?(session_name) Dir.mkdir("#{config.path}/repl") unless Dir.exist?("#{config.path}/repl") if config.admins.include?(user.name) or @repls[session_name].creator_name == user.name @repls.delete(session_name) update_repls() File.rename("#{config.path}/repl/#{@channel_id}/#{session_name}.input", "#{config.path}/repl/#{@channel_id}/#{session_name}_#{Time.now.strftime("%Y%m%d%H%M%S%N")}.deleted") respond "REPL #{session_name} deleted" else respond "Only admins or the creator of this REPL can delete it", dest end else respond "The REPL with session name: #{session_name} doesn't exist on this Smart Bot Channel", dest end end end |
#delete_shortcut(dest, user, shortcut, typem, command) ⇒ Object
help: ----------------------------------------------
help: delete shortcut NAME
help: delete sc NAME
help: It will delete the shortcut with the supplied name
help:
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
# File 'lib/slack/smart-bot/commands/on_bot/delete_shortcut.rb', line 8 def delete_shortcut(dest, user, shortcut, typem, command) save_stats(__method__) unless typem == :on_extended from = user.name if config[:allow_access].key?(__method__) and !config[:allow_access][__method__].include?(user.name) and !config[:allow_access][__method__].include?(user.id) and (!user.key?(:enterprise_user) or ( user.key?(:enterprise_user) and !config[:allow_access][__method__].include?(user[:enterprise_user].id))) respond "You don't have access to use this command, please contact an Admin to be able to use it: <@#{config.admins.join(">, <@")}>" else deleted = false if !config.admins.include?(from) and @shortcuts[:all].include?(shortcut) and !@shortcuts[from].include?(shortcut) respond "Only the creator of the shortcut or an admin user can delete it", dest elsif (@shortcuts.keys.include?(from) and @shortcuts[from].keys.include?(shortcut)) or (config.admins.include?(from) and @shortcuts[:all].include?(shortcut)) #are you sure? to avoid deleting by mistake unless @questions.keys.include?(from) ask("are you sure you want to delete it?", command, from, dest) else case @questions[from] when /^(yes|yep)/i @questions.delete(from) respond "shortcut deleted!", dest respond("#{shortcut}: #{@shortcuts[from][shortcut]}", dest) if @shortcuts.key?(from) and @shortcuts[from].key?(shortcut) respond("#{shortcut}: #{@shortcuts[:all][shortcut]}", dest) if @shortcuts.key?(:all) and @shortcuts[:all].key?(shortcut) @shortcuts[from].delete(shortcut) if @shortcuts.key?(from) and @shortcuts[from].key?(shortcut) @shortcuts[:all].delete(shortcut) if @shortcuts.key?(:all) and @shortcuts[:all].key?(shortcut) update_shortcuts_file() when /^no/i @questions.delete(from) respond "ok, I won't delete it", dest else ask("I don't understand, are you sure you want to delete it? (yes or no)", command, from, dest) end end else respond "shortcut not found", dest end end end end |
#dont_understand(rules_file = nil, command = nil, user = nil, dest = nil, answer = ["what?", "huh?", "sorry?", "what do you mean?", "I don't understand"], channel_rules: config.channel, typem: nil) ⇒ Object
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/slack/smart-bot/comm/dont_understand.rb', line 3 def dont_understand(rules_file = nil, command = nil, user = nil, dest = nil, answer = ["what?", "huh?", "sorry?", "what do you mean?", "I don't understand"], channel_rules: config.channel, typem: nil) save_stats(:dont_understand) command = Thread.current[:command] if command.nil? user = Thread.current[:user] if user.nil? dest = Thread.current[:dest] if dest.nil? rules_file = Thread.current[:rules_file] if rules_file.nil? typem = Thread.current[:typem] if typem.nil? if typem==:on_extended get_bots_created() end text = get_help(rules_file, dest, user.name, typem==:on_extended) ff = text.scan(/\s*`\s*([^`]+)\s*`\s*/i).flatten ff.delete("!THE_COMMAND") ff.delete("@NAME_OF_BOT THE_COMMAND") ff.delete("NAME_OF_BOT THE_COMMAND") ff.delete("@BOT_NAME on #CHANNEL_NAME COMMAND") ff2 = {} acommand = command.split(/\s+/) ff.each do |f| ff2[f] = "" af = f.split(/\s+/) af.each_with_index do |word, i| if acommand.size >= (i - 1) and word.match?(/[A-Z_\-#@]+/) ff2[f] += "#{acommand[i]} " else ff2[f] += "#{word} " end end ff2[f].rstrip! end spell_checker = DidYouMean::SpellChecker.new(dictionary: ff2.values) res = spell_checker.correct(command).uniq res_final = [] res.each do |r| res_final << (ff2.select { |k, v| v == r }).keys end res_final.flatten! if typem==:on_extended if @extended_from[@channels_name[dest]].size == 1 respond "#{user.profile.display_name}, I don't understand.", dest end unless res_final.empty? respond "Similar rules on : *#{channel_rules}*\n`#{res_final[0..4].join("`\n`")}`", dest end else = '' = "\nTake in consideration when on external calls, not all the commands are availalbe." if typem==:on_call if res_final.empty? resp = answer.sample respond "#{user.profile.display_name}, #{resp}#{}", dest else respond "#{user.profile.display_name}, I don't understand. Maybe you are trying to say:\n`#{res_final[0..4].join("`\n`")}`#{}", dest end end end |
#exit_bot(command, from, dest, display_name) ⇒ Object
helpadmin: ----------------------------------------------
helpadmin: exit bot
helpadmin: quit bot
helpadmin: close bot
helpadmin: The bot stops running and also stops all the bots created from this master channel
helpadmin: You can use this command only if you are an admin user and you are on the master channel
helpadmin:
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/slack/smart-bot/commands/on_master/admin_master/exit_bot.rb', line 10 def exit_bot(command, from, dest, display_name) save_stats(__method__) if config.on_master_bot if config.admins.include?(from) #admin user unless @questions.keys.include?(from) ask("are you sure?", command, from, dest) else case @questions[from] when /yes/i, /yep/i, /sure/i respond "Game over!", dest respond "Ciao #{display_name}!", dest @bots_created.each { |key, value| value[:thread] = "" send_msg_channel(key, "Bot has been closed by #{from}") sleep 0.5 } update_bots_file() sleep 0.5 if config.simulate @status = :off config.simulate = false Thread.exit else exit! end when /no/i, /nope/i, /cancel/i @questions.delete(from) respond "Thanks, I'm happy to be alive", dest else ask("I don't understand, are you sure do you want me to close? (yes or no)", command, from, dest) end end else respond "Only admin users can kill me", dest end else respond "To do this you need to be an admin user in the master channel: <##{@master_bot_id}>", dest end end |
#extend_rules(dest, user, from, channel, typem) ⇒ Object
helpadmin: ----------------------------------------------
helpadmin: extend rules to CHANNEL_NAME
helpadmin: use rules on CHANNEL_NAME
helpadmin: It will allow to use the specific rules from this channel on the CHANNEL_NAME
helpadmin:
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
# File 'lib/slack/smart-bot/commands/on_bot/admin/extend_rules.rb', line 8 def extend_rules(dest, user, from, channel, typem) save_stats(__method__) unless typem == :on_extended if config.on_master_bot respond "You cannot use the rules from Master Channel on any other channel.", dest elsif !config.admins.include?(from) #not admin respond "Only admins can extend the rules. Admins on this channel: #{config.admins}", dest else #todo: add pagination for case more than 1000 channels on the workspace channels = client.web_client.conversations_list( types: "private_channel,public_channel", limit: "1000", exclude_archived: "true", ).channels channel_found = channels.detect { |c| c.name == channel } get_channels_name_and_id() members = client.web_client.conversations_members(channel: @channels_id[channel]).members unless channel_found.nil? get_bots_created() channels_in_use = [] @bots_created.each do |k, v| if v.key?(:extended) and v[:extended].include?(channel) channels_in_use << v[:channel_name] end end if channel_found.nil? respond "The channel you specified doesn't exist or I don't have access to it. Be sure I was invited to that channel.", dest elsif @bots_created.key?(@channels_id[channel]) or channel == config.master_channel respond "There is a bot already running on that channel.", dest elsif @bots_created[@channel_id][:extended].include?(channel) respond "The rules are already extended to that channel.", dest elsif !members.include?(user.id) respond "You need to join that channel first", dest elsif !members.include?(config[:nick_id]) respond "You need to add first to the channel the smart bot user: #{config[:nick]}", dest else channels_in_use.each do |channel_in_use| respond "The rules from channel <##{@channels_id[channel_in_use]}> are already in use on that channel", dest end @bots_created[@channel_id][:extended] = [] unless @bots_created[@channel_id].key?(:extended) @bots_created[@channel_id][:extended] << channel update_bots_file() respond "<@#{user.id}> extended the rules from #{config.channel} to be used on #{channel}.", @master_bot_id if @channels_id[channel][0] == "G" respond "Now the rules from <##{@channel_id}> are available on *#{channel}*", dest else respond "Now the rules from <##{@channel_id}> are available on *<##{@channels_id[channel]}>*", dest end respond "<@#{user.id}> extended the rules from <##{@channel_id}> to this channel so now you can talk to the Smart Bot on demand using those rules.", @channels_id[channel] respond "Use `!` before the command you want to run", @channels_id[channel] respond "To see the specific rules for this bot on this channel: `!bot rules` or `!bot rules COMMAND`", @channels_id[channel] end end end end |
#get_bot_logs(dest, from, typem) ⇒ Object
helpadmin: ----------------------------------------------
helpadmin: get bot logs
helpadmin: To see the bot logs
helpadmin: You can use this command only if you are a Master admin user and if you are in a private conversation with the bot
helpadmin:
8 9 10 11 12 13 14 15 16 |
# File 'lib/slack/smart-bot/commands/on_bot/admin_master/get_bot_logs.rb', line 8 def get_bot_logs(dest, from, typem) save_stats(__method__) if config.masters.include?(from) and typem==:on_dm #master admin user respond 'Remember this data is private' send_file(dest, "Logs for #{config.channel}", "#{config.path}/logs/#{config.log_file}", 'Remember this data is private', 'text/plain', "text") else respond "Only master admin users on a private conversation with the bot can get the bot logs.", dest end end |
#get_bots_created ⇒ Object
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
# File 'lib/slack/smart-bot/utils/get_bots_created.rb', line 2 def get_bots_created if File.exist?(config.file_path.gsub(".rb", "_bots.rb")) if !defined?(@datetime_bots_created) or @datetime_bots_created != File.mtime(config.file_path.gsub(".rb", "_bots.rb")) file_conf = IO.readlines(config.file_path.gsub(".rb", "_bots.rb")).join if file_conf.to_s() == "" @bots_created = {} else @bots_created = eval(file_conf) end @datetime_bots_created = File.mtime(config.file_path.gsub(".rb", "_bots.rb")) @extended_from = {} @bots_created.each do |k, v| v[:extended] = [] unless v.key?(:extended) v[:extended].each do |ch| @extended_from[ch] = [] unless @extended_from.key?(ch) @extended_from[ch] << k end v[:rules_file].gsub!(/^\./, '') end end end end |
#get_channels_name_and_id ⇒ Object
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# File 'lib/slack/smart-bot/utils/get_channels_name_and_id.rb', line 3 def get_channels_name_and_id #todo: add pagination for case more than 1000 channels on the workspace channels = client.web_client.conversations_list( types: "private_channel,public_channel", limit: "1000", exclude_archived: "true", ).channels @channels_id = Hash.new() @channels_name = Hash.new() channels.each do |ch| unless ch.is_archived @channels_id[ch.name] = ch.id @channels_name[ch.id] = ch.name end end end |
#get_help(rules_file, dest, from, only_rules = false) ⇒ Object
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
# File 'lib/slack/smart-bot/utils/get_help.rb', line 2 def get_help(rules_file, dest, from, only_rules = false) order = { general: [:hi_bot, :bye_bot, :bot_help, :bot_status, :use_rules, :stop_using_rules], on_bot: [:ruby_code, :repl, :get_repl, :run_repl, :delete_repl, :see_repls, :add_shortcut, :delete_shortcut, :see_shortcuts], on_bot_admin: [:extend_rules, :stop_using_rules_on, :start_bot, :pause_bot, :add_routine, :see_routines, :start_routine, :pause_routine, :remove_routine, :run_routine] } # user_type: :admin, :user, :admin_master if config.masters.include?(from) user_type = :admin_master elsif config.admins.include?(from) user_type = :admin else user_type = :user end # channel_type: :bot, :master_bot, :direct, :extended, :external if dest[0] == "D" channel_type = :direct elsif config.on_master_bot channel_type = :master_bot elsif @channel_id != dest channel_type = :extended else channel_type = :bot end @help_messages ||= build_help("#{__dir__}/../commands") if only_rules help = {} else help = @help_messages.deep_copy end if rules_file != "" help[:rules_file] = IO.readlines(config.path+rules_file).join.scan(/#\s*help\s*\w*:(.*)/i).join("\n") end help = remove_hash_keys(help, :admin_master) unless user_type == :admin_master help = remove_hash_keys(help, :admin) unless user_type == :admin or user_type == :admin_master help = remove_hash_keys(help, :on_master) unless channel_type == :master_bot help = remove_hash_keys(help, :on_extended) unless channel_type == :extended help = remove_hash_keys(help, :on_dm) unless channel_type == :direct txt = "" if channel_type == :bot or channel_type == :master_bot txt += "=================================== For the Smart Bot start listening to you say *hi bot* To run a command on demand even when the Smart Bot is not listening to you: *!THE_COMMAND* *@NAME_OF_BOT THE_COMMAND* *NAME_OF_BOT THE_COMMAND* To run a command on demand and add the respond on a thread: *^THE_COMMAND* *!!THE_COMMAND*\n" end if channel_type == :direct txt += "=================================== When on a private conversation with the Smart Bot, I'm always listening to you.\n" end unless channel_type == :master_bot or channel_type == :extended txt += "=================================== *Commands from Channels without a bot:* ---------------------------------------------- `@BOT_NAME on #CHANNEL_NAME COMMAND` `@BOT_NAME #CHANNEL_NAME COMMAND` It will run the supplied command using the rules on the channel supplied. You need to join the specified channel to be able to use those rules. Also you can use this command to call another bot from a channel with a running bot. The commands you will be able to use from a channel without a bot: *bot rules*, *ruby CODE*, *add shortcut NAME: COMMAND*, *delete shortcut NAME*, *see shortcuts*, *shortcut NAME* *And all the specific rules of the Channel*\n" end if help.key?(:general) unless channel_type == :direct txt += "=================================== *General commands even when the Smart Bot is not listening to you:*\n" end order.general.each do |o| txt += help.general[o] end if channel_type == :master_bot txt += help.on_master.create_bot end end if help.key?(:on_bot) unless channel_type == :direct txt += "=================================== *General commands only when the Smart Bot is listening to you or on demand:*\n" end order.on_bot.each do |o| txt += help.on_bot[o] end end if help.key?(:on_bot) and help.on_bot.key?(:admin) txt += "=================================== *Admin commands:*\n" txt += "\n\n" order.on_bot_admin.each do |o| txt += help.on_bot.admin[o] end if help.key?(:on_master) and help.on_master.key?(:admin) help.on_master.admin.each do |k, v| txt += v if v.is_a?(String) end end end if help.key?(:on_bot) and help.on_bot.key?(:admin_master) and help.on_bot.admin_master.size > 0 txt += "=================================== *Master Admin commands:*\n" help.on_bot.admin_master.each do |k, v| txt += v if v.is_a?(String) end end if help.key?(:on_master) and help.on_master.key?(:admin_master) and help.on_master.admin_master.size > 0 txt += "=================================== *Master Admin commands:*\n" help.on_master.admin_master.each do |k, v| txt += v if v.is_a?(String) end end if help.key?(:rules_file) @logger.info channel_type if config.testing if channel_type == :extended or channel_type == :direct @logger.info help.rules_file if config.testing help.rules_file = help.rules_file.gsub(/^\s*\*These are specific commands.+NAME_OF_BOT THE_COMMAND`\s*$/im, "") end txt += help.rules_file end return txt end |
#get_repl(dest, user, session_name) ⇒ Object
help: ----------------------------------------------
help: get repl SESSION_NAME
help: get irb SESSION_NAME
help: get live SESSION_NAME
help:
help: Will get the Ruby commands sent on that SESSION_NAME.
help:
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
# File 'lib/slack/smart-bot/commands/on_bot/get_repl.rb', line 9 def get_repl(dest, user, session_name) #todo: add tests save_stats(__method__) if config[:allow_access].key?(__method__) and !config[:allow_access][__method__].include?(user.name) and !config[:allow_access][__method__].include?(user.id) and (!user.key?(:enterprise_user) or ( user.key?(:enterprise_user) and !config[:allow_access][__method__].include?(user[:enterprise_user].id))) respond "You don't have access to use this command, please contact an Admin to be able to use it: <@#{config.admins.join(">, <@")}>" else Dir.mkdir("#{config.path}/repl") unless Dir.exist?("#{config.path}/repl") Dir.mkdir("#{config.path}/repl/#{@channel_id}") unless Dir.exist?("#{config.path}/repl/#{@channel_id}") if File.exist?("#{config.path}/repl/#{@channel_id}/#{session_name}.input") if @repls.key?(session_name) and @repls[session_name][:type] == :private and @repls[session_name][:creator_name]!=user.name and !config.admins.include?(user.name) respond "The REPL with session name: #{session_name} is private", dest else if @repls.key?(session_name) @repls[session_name][:accessed] = Time.now.to_s @repls[session_name][:gets] += 1 update_repls() end content = "require 'nice_http'\n" if File.exist?("#{project_folder}/.smart-bot-repl") content += File.read("#{project_folder}/.smart-bot-repl") content += "\n" end content += File.read("#{config.path}/repl/#{@channel_id}/#{session_name}.input").gsub(/^(quit|exit|bye)$/i,'') File.write("#{config.path}/repl/#{@channel_id}/#{session_name}.rb", content, mode: "w+") send_file(dest, "REPL #{session_name} on #{config.channel}", "#{config.path}/repl/#{@channel_id}/#{session_name}.rb", " REPL #{session_name} on #{config.channel}", 'text/plain', "ruby") end else respond "The REPL with session name: #{session_name} doesn't exist on this Smart Bot Channel", dest end end end |
#get_repls(channel = @channel_id) ⇒ Object
3 4 5 6 7 8 9 10 |
# File 'lib/slack/smart-bot/utils/get_repls.rb', line 3 def get_repls(channel = @channel_id) if File.exist?("#{config.path}/repl/repls_#{channel}.rb") file_conf = IO.readlines("#{config.path}/repl/repls_#{channel}.rb").join unless file_conf.to_s() == "" @repls = eval(file_conf) end end end |
#get_routines(channel = @channel_id) ⇒ Object
3 4 5 6 7 8 9 10 |
# File 'lib/slack/smart-bot/utils/get_routines.rb', line 3 def get_routines(channel = @channel_id) if File.exist?("#{config.path}/routines/routines_#{channel}.rb") file_conf = IO.readlines("#{config.path}/routines/routines_#{channel}.rb").join unless file_conf.to_s() == "" @routines = eval(file_conf) end end end |
#get_rules_imported ⇒ Object
3 4 5 6 7 8 9 10 11 12 13 |
# File 'lib/slack/smart-bot/utils/get_rules_imported.rb', line 3 def get_rules_imported if File.exist?("#{config.path}/rules/rules_imported.rb") if !defined?(@datetime_rules_imported) or @datetime_rules_imported != File.mtime("#{config.path}/rules/rules_imported.rb") @datetime_rules_imported = File.mtime("#{config.path}/rules/rules_imported.rb") file_conf = IO.readlines("#{config.path}/rules/rules_imported.rb").join unless file_conf.to_s() == "" @rules_imported = eval(file_conf) end end end end |
#hi_bot(user, dest, dchannel, from, display_name) ⇒ Object
help: ----------------------------------------------
help: Hi Bot
help: Hi Smart
help: Hello Bot
Hola Bot
Hallo Bot
What's up Bot
Hey Bot
Hæ Bot
help: Hello THE_NAME_OF_THE_BOT
help: Also apart of Hello you can use Hallo, Hi, Hola, What's up, Hey, Hæ
help: Bot starts listening to you
help: After that if you want to avoid a single message to be treated by the smart bot, start the message by -
help:
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
# File 'lib/slack/smart-bot/commands/general/hi_bot.rb', line 12 def hi_bot(user, dest, dchannel, from, display_name) if @status == :on save_stats(__method__) greetings = ["Hello", "Hallo", "Hi", "Hola", "What's up", "Hey", "Hæ"].sample respond "#{greetings} #{display_name}", dest if Thread.current[:using_channel]!='' respond "You are using specific rules for channel: <##{Thread.current[:using_channel]}>", dest end @listening[from] = {} unless @listening.key?(from) if Thread.current[:on_thread] @listening[from][Thread.current[:thread_ts]] = Time.now else @listening[from][dest] = Time.now end end end |
#kill_bot_on_channel(dest, from, channel) ⇒ Object
helpmaster: ----------------------------------------------
helpmaster: kill bot on CHANNEL_NAME
helpmaster: kills the bot on the specified channel
helpmaster: Only works if you are on Master channel and you created that bot or you are an admin user
helpmaster:
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
# File 'lib/slack/smart-bot/commands/on_master/admin/kill_bot_on_channel.rb', line 7 def kill_bot_on_channel(dest, from, channel) save_stats(__method__) if config.on_master_bot get_channels_name_and_id() unless @channels_name.keys.include?(channel) or @channels_id.keys.include?(channel) channel_id = nil if @channels_name.key?(channel) #it is an id channel_id = channel channel = @channels_name[channel_id] elsif @channels_id.key?(channel) #it is a channel name channel_id = @channels_id[channel] end if channel_id.nil? respond "There is no channel with that name: #{channel}, please be sure is written exactly the same", dest elsif @bots_created.keys.include?(channel_id) if @bots_created[channel_id][:admins].split(",").include?(from) if @bots_created[channel_id][:thread].kind_of?(Thread) and @bots_created[channel_id][:thread].alive? @bots_created[channel_id][:thread].kill end @bots_created.delete(channel_id) update_bots_file() respond "Bot on channel: #{channel}, has been killed and deleted.", dest send_msg_channel(channel, "Bot has been killed by #{from}") else respond "You need to be the creator or an admin of that bot channel", dest end else respond "There is no bot in this channel: #{channel}", dest end else respond "Sorry I cannot kill bots from this channel, please visit the master channel: <##{@master_bot_id}>", dest end end |
#listen ⇒ Object
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/slack/smart-bot/listen.rb', line 43 def listen @pings = [] @last_activity_check = Time.now get_bots_created() client.on :message do |data| unless data.user == "USLACKBOT" or data.text.nil? if data.text.match?(/^\s*\-!!/) or data.text.match?(/^\s*\-\^/) data.text.scan(/`([^`]+)`/).flatten.each do |cmd| if cmd.to_s!='' datao = data.dup datao.text = "^#{cmd}" (datao, false) end end elsif data.text.match?(/^\s*\-!/) data.text.scan(/`([^`]+)`/).flatten.each do |cmd| if cmd.to_s!='' datao = data.dup datao.text = "!#{cmd}" (datao, false) end end else (data) end end end restarts = 0 started = false while restarts < 200 and !started begin @logger.info "Bot starting: #{config.inspect}" client.start! rescue Slack::RealTime::Client::ClientAlreadyStartedError @logger.info "ClientAlreadyStarted so we continue with execution" started = true rescue Exception => e started = false restarts += 1 if restarts < 200 @logger.info "*" * 50 @logger.fatal "Rescued on starting: #{e.inspect}" @logger.info "Waiting 60 seconds to retry. restarts: #{restarts}" puts "#{Time.now}: Not able to start client. Waiting 60 seconds to retry: #{config.inspect}" sleep 60 else exit! end end end end |
#listen_simulate ⇒ Object
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
# File 'lib/slack/smart-bot/listen.rb', line 2 def listen_simulate @salutations = [config[:nick], "<@#{config[:nick_id]}>", "bot", "smart"] @pings = [] @last_activity_check = Time.now get_bots_created() @buffer_complete = [] unless defined?(@buffer_complete) b = File.read("#{config.path}/buffer_complete.log") result = b.scan(/^\|(\w+)\|(\w+)\|([^~]+)~~~/m) result.delete(nil) = result[@buffer_complete.size..-1] unless .nil? or .empty? @buffer_complete = result .each do || channel = [0].strip user = [1].strip command = [2].to_s.strip # take in consideration that on simulation we are treating all messages even those that are not populated on real cases like when the message is not populated to the specific bot connection when message is sent with the bot @logger.info "treat message: #{}" if config.testing if command.match?(/^\s*\-!!/) or command.match?(/^\s*\-\^/) command.scan(/`([^`]+)`/).flatten.each do |cmd| if cmd.to_s!='' cmd = "^#{cmd}" ({channel: channel, user: user, text: cmd}, false) end end elsif command.match?(/^\s*\-!/) command.scan(/`([^`]+)`/).flatten.each do |cmd| if cmd.to_s!='' cmd = "!#{cmd}" ({channel: channel, user: user, text: cmd}, false) end end else ({channel: channel, user: user, text: command}) end end end end |
#notify_message(dest, from, where, message) ⇒ Object
helpmaster: ----------------------------------------------
helpmaster: notify MESSAGE
helpmaster: notify all MESSAGE
helpmaster: notify #CHANNEL_NAME MESSAGE
helpmaster: It will send a notification message to all bot channels
helpmaster: It will send a notification message to all channels the bot joined and private conversations with the bot
helpmaster: It will send a notification message to the specified channel and to its extended channels
helpmaster: Only works if you are on Master channel and you are a master admin user
helpmaster:
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
# File 'lib/slack/smart-bot/commands/on_master/admin_master/notify_message.rb', line 11 def (dest, from, where, ) save_stats(__method__) if config.on_master_bot if config.admins.include?(from) #admin user if where.nil? #not all and not channel @bots_created.each do |k, v| respond , k end respond "Bot channels have been notified", dest elsif where == "all" #all myconv = client.web_client.users_conversations(exclude_archived: true, limit: 100, types: "im, public_channel,private_channel").channels myconv.each do |c| respond , c.id unless c.name == config.master_channel end respond "Channels and users have been notified", dest else #channel respond , where @bots_created[where][:extended].each do |ch| respond , @channels_id[ch] end respond "Bot channel and extended channels have been notified", dest end end end end |
#pause_bot(dest, from) ⇒ Object
helpadmin: ----------------------------------------------
helpadmin: pause bot
helpadmin: pause this bot
helpadmin: the bot will pause so it will listen only to admin commands
helpadmin: You can use this command only if you are an admin user
helpadmin:
9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
# File 'lib/slack/smart-bot/commands/on_bot/admin/pause_bot.rb', line 9 def pause_bot(dest, from) save_stats(__method__) if config.admins.include?(from) #admin user respond "This bot is paused from now on. You can start it again: start this bot", dest respond "zZzzzzZzzzzZZZZZZzzzzzzzz", dest @status = :paused @bots_created[@channel_id][:status] = :paused unless config.on_master_bot send_msg_channel config.master_channel, "Changed status on #{config.channel} to :paused" end else respond "Only admin users can put me on pause", dest end end |
#pause_routine(dest, from, name) ⇒ Object
helpadmin: ----------------------------------------------
helpadmin: pause routine NAME
helpadmin: It will pause the specified routine
helpadmin: You can use this command only if you are an admin user
helpadmin: NAME: one word to identify the routine
helpadmin: Examples:
helpadmin: pause routine example
helpadmin:
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
# File 'lib/slack/smart-bot/commands/on_bot/admin/pause_routine.rb', line 10 def pause_routine(dest, from, name) save_stats(__method__) if config.admins.include?(from) #admin user if !config.on_master_bot and dest[0] == "D" respond "It's only possible to pause routines from MASTER channel from a direct message with the bot.", dest elsif @routines.key?(@channel_id) and @routines[@channel_id].key?(name) @routines[@channel_id][name][:status] = :paused @routines[@channel_id][name][:next_run] = "" update_routines() respond "The routine *`#{name}`* has been paused.", dest else respond "There isn't a routine with that name: *`#{name}`*.\nCall `see routines` to see added routines", dest end else respond "Only admin users can use this command", dest end end |
#process(user, command, dest, dchannel, rules_file, typem, files, ts) ⇒ Object
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 |
# File 'lib/slack/smart-bot/process.rb', line 2 def process(user, command, dest, dchannel, rules_file, typem, files, ts) from = user.name if user.profile.display_name.to_s.match?(/\A\s*\z/) user.profile.display_name = user.profile.real_name end display_name = user.profile.display_name processed = true on_demand = false if command.match(/^@?(#{config[:nick]}):*\s+(.+)/im) or command.match(/^()!!(.+)/im) or command.match(/^()\^(.+)/im) or command.match(/^()!(.+)/im) or command.match(/^()<@#{config[:nick_id]}>\s+(.+)/im) command2 = $2 Thread.current[:command] = command2 if command2.match?(/^()!!(.+)/im) or command.match?(/^()\^(.+)/im) Thread.current[:on_thread] = true end command = command2 on_demand = true end #todo: check :on_pg in this case if typem == :on_master or typem == :on_bot or typem == :on_pg or typem == :on_dm case command when /^\s*(Hello|Hallo|Hi|Hola|What's\sup|Hey|Hæ)\s(#{@salutations.join("|")})\s*$/i hi_bot(user, dest, dchannel, from, display_name) when /^\s*(Bye|Bæ|Good\sBye|Adiós|Ciao|Bless|Bless\sBless|Adeu)\s(#{@salutations.join("|")})\s*$/i bye_bot(dest, from, display_name) when /^\s*bot\s+(rules|help)\s*(.+)?$/i, /^bot,? what can I do/i $1.to_s.match?(/rules/i) ? specific = true : specific = false help_command = $2 bot_help(user, from, dest, dchannel, specific, help_command, rules_file) when /^\s*use\s+(rules\s+)?(from\s+)?<#C\w+\|(.+)>\s*$/i, /^use\s+(rules\s+)?(from\s+)?([^\s]+\s*$)/i channel = $3 use_rules(dest, channel, user, dchannel) when /^\s*stop using rules (from\s+)<#\w+\|(.+)>/i, /^stop using rules (from\s+)(.+)/i channel = $2 stop_using_rules(dest, channel, user, dchannel) when /^\s*extend\s+rules\s+(to\s+)<#C\w+\|(.+)>/i, /^extend\s+rules\s+(to\s+)(.+)/i, /^\s*use\s+rules\s+(on\s+)<#C\w+\|(.+)>/i, /^use\s+rules\s+(on\s+)(.+)/i channel = $2 extend_rules(dest, user, from, channel, typem) when /^\s*stop using rules (on\s+)<#\w+\|(.+)>/i, /^stop using rules (on\s+)(.+)/i channel = $2 stop_using_rules_on(dest, user, from, channel, typem) when /^\s*exit\sbot\s*$/i, /^quit\sbot\s*$/i, /^close\sbot\s*$/i exit_bot(command, from, dest, display_name) when /^\s*start\s(this\s)?bot$/i start_bot(dest, from) when /^\s*pause\s(this\s)?bot$/i pause_bot(dest, from) when /^\s*bot\sstatus/i bot_status(dest, user) when /\Anotify\s+<#(C\w+)\|.+>\s+(.+)\s*\z/im, /\Anotify\s+(all)?\s*(.+)\s*\z/im where = $1 = $2 (dest, from, where, ) when /^\s*create\s+(cloud\s+)?bot\s+on\s+<#C\w+\|(.+)>\s*/i, /^create\s+(cloud\s+)?bot\s+on\s+(.+)\s*/i cloud = !$1.nil? channel = $2 create_bot(dest, user, cloud, channel) when /^\s*kill\sbot\son\s<#C\w+\|(.+)>\s*$/i, /^kill\sbot\son\s(.+)\s*$/i channel = $1 kill_bot_on_channel(dest, from, channel) when /^\s*(add|create)\s+(silent\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, /^\s*(add|create)\s+(silent\s+)?routine\s+(\w+)\s+(at)\s+(\d+:\d+:?\d+?)\s*()(\s.+)?\s*$/i silent = $2.to_s!='' name = $3.downcase type = $4 number_time = $5 period = $6 command_to_run = $7 add_routine(dest, from, user, name, type, number_time, period, command_to_run, files, silent) when /^\s*(kill|delete|remove)\s+routine\s+(\w+)\s*$/i name = $2.downcase remove_routine(dest, from, name) when /^\s*(run|execute)\s+routine\s+(\w+)\s*$/i name = $2.downcase run_routine(dest, from, name) when /^\s*pause\s+routine\s+(\w+)\s*$/i name = $1.downcase pause_routine(dest, from, name) when /^\s*start\s+routine\s+(\w+)\s*$/i name = $1.downcase start_routine(dest, from, name) when /^\s*see\s+(all\s+)?routines\s*$/i all = $1.to_s != "" see_routines(dest, from, user, all) when /^\s*get\s+bot\s+logs?\s*$/i get_bot_logs(dest, from, typem) when /^\s*bot\s+stats\s*(.*)\s*$/i opts = $1.to_s all_opts = opts.downcase.split(' ') st_channel = opts.scan(/<#(\w+)\|.+>/).join st_from = opts.scan(/from\s+(\d\d\d\d[\/\-\.]\d\d[\/\-\.]\d\d)/).join st_from = st_from.gsub('.','-').gsub('/','-') st_to = opts.scan(/to\s+(\d\d\d\d[\/\-\.]\d\d[\/\-\.]\d\d)/).join st_to = st_to.gsub('.','-').gsub('/','-') st_user = opts.scan(/<@([^>]+)>/).join exclude_masters = opts.match?(/exclude\s+masters?/i) if all_opts.include?('today') st_from = st_to = "#{Time.now.strftime("%Y-%m-%d")}" end exclude_command = opts.scan(/exclude\s+([^\s]+)/i).join exclude_command = '' if exclude_command == 'masters' bot_stats(dest, from, typem, st_channel, st_from, st_to, st_user, exclude_masters, exclude_command) else processed = false end else processed = false end # only when :on and (listening or on demand or direct message) if @status == :on and (@questions.key?(from) or (@repl_sessions.key?(from) and dest==@repl_sessions[from][:dest] and ((@repl_sessions[from][:on_thread] and Thread.current[:thread_ts] == @repl_sessions[from][:thread_ts]) or (!@repl_sessions[from][:on_thread] and !Thread.current[:on_thread]))) or (@listening.key?(from) and typem != :on_extended and ((@listening[from].key?(dest) and !Thread.current[:on_thread]) or (@listening[from].key?(Thread.current[:thread_ts]) and Thread.current[:on_thread] ) )) or typem == :on_dm or typem == :on_pg or on_demand) processed2 = true case command # bot rules for extended channels when /^bot\s+rules\s*(.+)?$/i help_command = $1 bot_rules(dest, help_command, typem, rules_file, user) when /^\s*(add\s)?shortcut\s(for\sall)?\s*([^:]+)\s*:\s*(.+)/i, /^(add\s)sc\s(for\sall)?\s*([^:]+)\s*:\s*(.+)/i for_all = $2 shortcut_name = $3.to_s.downcase command_to_run = $4 add_shortcut(dest, user, typem, for_all, shortcut_name, command, command_to_run) when /^\s*(delete|remove)\s+shortcut\s+(.+)/i, /^(delete|remove)\s+sc\s+(.+)/i shortcut = $2.to_s.downcase delete_shortcut(dest, user, shortcut, typem, command) when /^\s*see\sshortcuts/i, /^see\ssc/i see_shortcuts(dest, user, typem) #kept to be backwards compatible when /^\s*id\schannel\s<#C\w+\|(.+)>\s*/i, /^id channel (.+)/ unless typem == :on_extended channel_name = $1 get_channels_name_and_id() if @channels_id.keys.include?(channel_name) respond "the id of #{channel_name} is #{@channels_id[channel_name]}", dest else respond "channel: #{channel_name} not found", dest end end when /^\s*ruby\s(.+)/im, /^\s*code\s(.+)/im code = $1 code.gsub!("\\n", "\n") code.gsub!("\\r", "\r") @logger.info code ruby_code(dest, user, code, rules_file) when /^\s*(private\s+)?(repl|irb|live)\s*()()()$/i, /^\s*(private\s+)?(repl|irb|live)\s+([\w\-]+)()()\s*$/i, /^\s*(private\s+)?(repl|irb|live)\s+([\w\-]+)\s*:\s*"(.+)"()\s*$/i, /^\s*(private\s+)?(repl|irb|live)\s+([\w\-]+)\s*:\s*"(.+)"\s+(.+)\s*$/i, /^\s*(private\s+)?(repl|irb|live)\s+([\w\-]+)()\s+(.+)\s*$/i, /^\s*(private\s+)?(repl|irb|live)()\s+()(.+)\s*$/i if $1.to_s!='' type = :private else type = :public end session_name = $3 description = $4 opts = " #{$5}" env_vars = opts.scan(/\s+[\w\-]+="[^"]+"/i) + opts.scan(/\s+[\w\-]+='[^']+'/i) opts.scan(/\s+[\w\-]+=[^'"\s]+/i).flatten.each do |ev| env_vars << ev.gsub('=',"='") + "'" end env_vars.each_with_index do |ev, idx| ev.gsub!("=","']=") ev.lstrip! env_vars[idx] = "ENV['#{ev}" end repl(dest, user, session_name, env_vars.flatten, rules_file, command, description, type) when /^\s*get\s+(repl|irb|live)\s+([\w\-]+)\s*/i session_name = $2 get_repl(dest, user, session_name) when /^\s*run\s+(repl|irb|live)\s+([\w\-]+)()\s*$/i, /^\s*run\s+(repl|irb|live)\s+([\w\-]+)\s+(.+)\s*$/i session_name = $2 opts = " #{$3}" env_vars = opts.scan(/\s+[\w\-]+="[^"]+"/i) + opts.scan(/\s+[\w\-]+='[^']+'/i) opts.scan(/\s+[\w\-]+=[^'"\s]+/i).flatten.each do |ev| env_vars << ev.gsub('=',"='") + "'" end env_vars.each_with_index do |ev, idx| ev.gsub!("=","']=") ev.lstrip! env_vars[idx] = "ENV['#{ev}" end run_repl(dest, user, session_name, env_vars.flatten, rules_file) when /^\s*(delete|remove)\s+(repl|irb|live)\s+([\w\-]+)\s*$/i repl_name = $3.downcase delete_repl(dest, user, repl_name) when /^\s*see\s+(repls|repl|irb|irbs)\s*$/i see_repls(dest, user, typem) else processed2 = false end #of case processed = true if processed or processed2 end return processed end |
#process_first(user, text, dest, dchannel, typem, files, ts, thread_ts) ⇒ Object
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 |
# File 'lib/slack/smart-bot/process_first.rb', line 2 def process_first(user, text, dest, dchannel, typem, files, ts, thread_ts) nick = user.name rules_file = "" text.gsub!(/^!!/,'^') # to treat it just as ^ if typem == :on_call rules_file = config.rules_file elsif dest[0] == "C" or dest[0] == "G" # on a channel or private channel rules_file = config.rules_file if @rules_imported.key?(user.id) and @rules_imported[user.id].key?(dchannel) unless @bots_created.key?(@rules_imported[user.id][dchannel]) get_bots_created() end if @bots_created.key?(@rules_imported[user.id][dchannel]) rules_file = @bots_created[@rules_imported[user.id][dchannel]][:rules_file] end end elsif dest[0] == "D" and @rules_imported.key?(user.id) and @rules_imported[user.id].key?(user.id) #direct message unless @bots_created.key?(@rules_imported[user.id][user.id]) get_bots_created() end if @bots_created.key?(@rules_imported[user.id][user.id]) rules_file = @bots_created[@rules_imported[user.id][user.id]][:rules_file] end end if nick == config[:nick] #if message is coming from the bot begin case text when /^Bot has been (closed|killed) by/i if config.channel == @channels_name[dchannel] @logger.info "#{nick}: #{text}" if config.simulate @status = :off config.simulate = false Thread.exit else exit! end end when /^Changed status on (.+) to :(.+)/i channel_name = $1 status = $2 if config.on_master_bot or config.channel == channel_name @bots_created[@channels_id[channel_name]][:status] = status.to_sym update_bots_file() if config.channel == channel_name @logger.info "#{nick}: #{text}" else #on master bot @logger.info "Changed status on #{channel_name} to :#{status}" end end when /extended the rules from (.+) to be used on (.+)\.$/i from_name = $1 to_name = $2 if config.on_master_bot and @bots_created[@channels_id[from_name]][:cloud] @bots_created[@channels_id[from_name]][:extended] << to_name @bots_created[@channels_id[from_name]][:extended].uniq! update_bots_file() end when /removed the access to the rules of (.+) from (.+)\.$/i from_name = $1 to_name = $2 if config.on_master_bot and @bots_created[@channels_id[from_name]][:cloud] @bots_created[@channels_id[from_name]][:extended].delete(to_name) update_bots_file() end end return :next #don't continue analyzing #jal rescue Exception => stack @logger.fatal stack return :next #jal end end #only for shortcuts if text.match(/^@?(#{config[:nick]}):*\s+(.+)\s*/im) or text.match(/^()\^\s*(.+)\s*/im) or text.match(/^()!\s*(.+)\s*/im) or text.match(/^()<@#{config[:nick_id]}>\s+(.+)\s*/im) command2 = $2 if text.match?(/^()\^\s*(.+)/im) add_double_excl = true addexcl = false if command2.match?(/^![^!]/) or command2.match?(/^\^/) command2[0]='' elsif command2.match?(/^!!/) command2[0]='' command2[1]='' end else add_double_excl = false addexcl = true end command = command2 else addexcl = false if text.include?('$') #for shortcuts inside commands command = text.lstrip.rstrip else command = text.downcase.lstrip.rstrip end end if command.include?('$') #for adding shortcuts inside commands command.scan(/\$([^\$]+)/i).flatten.each do |sc| sc.strip! if @shortcuts.key?(nick) and @shortcuts[nick].keys.include?(sc) command.gsub!("$#{sc}", @shortcuts[nick][sc]) elsif @shortcuts.key?(:all) and @shortcuts[:all].keys.include?(sc) command.gsub!("$#{sc}", @shortcuts[:all][sc]) end end command.scan(/\$([^\s]+)/i).flatten.each do |sc| sc.strip! if @shortcuts.key?(nick) and @shortcuts[nick].keys.include?(sc) command.gsub!("$#{sc}", @shortcuts[nick][sc]) elsif @shortcuts.key?(:all) and @shortcuts[:all].keys.include?(sc) command.gsub!("$#{sc}", @shortcuts[:all][sc]) end end text = command text = "!" + text if addexcl and text[0] != "!" text = "^" + text if add_double_excl end if command.scan(/^(shortcut|sc)\s+([^:]+)\s*$/i).any? or (@shortcuts.keys.include?(:all) and @shortcuts[:all].keys.include?(command)) or (@shortcuts.keys.include?(nick) and @shortcuts[nick].keys.include?(command)) command = $2.downcase unless $2.nil? if @shortcuts.keys.include?(nick) and @shortcuts[nick].keys.include?(command) text = @shortcuts[nick][command].dup elsif @shortcuts.keys.include?(:all) and @shortcuts[:all].keys.include?(command) text = @shortcuts[:all][command].dup else respond "Shortcut not found", dest unless dest[0] == "C" and dchannel != dest #on extended channel return :next #jal end text = "!" + text if addexcl and text[0] != "!" text = "^" + text if add_double_excl end command = text begin t = Thread.new do begin Thread.current[:dest] = dest Thread.current[:user] = user Thread.current[:command] = command Thread.current[:rules_file] = rules_file Thread.current[:typem] = typem Thread.current[:files?] = !files.nil? && files.size>0 Thread.current[:ts] = ts Thread.current[:thread_ts] = thread_ts if thread_ts.to_s == '' Thread.current[:on_thread] = false Thread.current[:thread_ts] = Thread.current[:ts] # to create the thread if necessary else Thread.current[:on_thread] = true end if (dest[0] == "C") || (dest[0] == "G") and @rules_imported.key?(user.id) && @rules_imported[user.id].key?(dchannel) && @bots_created.key?(@rules_imported[user.id][dchannel]) Thread.current[:using_channel] = @rules_imported[user.id][dchannel] elsif dest[0] == "D" && @rules_imported.key?(user.id) && @rules_imported[user.id].key?(user.id) and @bots_created.key?(@rules_imported[user.id][user.id]) Thread.current[:using_channel] = @rules_imported[user.id][user.id] else Thread.current[:using_channel] = '' end processed = process(user, command, dest, dchannel, rules_file, typem, files, Thread.current[:thread_ts]) @logger.info "command: #{nick}> #{command}" if processed on_demand = false if command.match(/^@?(#{config[:nick]}):*\s+(.+)/im) or command.match(/^()!!(.+)/im) or command.match(/^()\^(.+)/im) or command.match(/^()!(.+)/im) or command.match(/^()<@#{config[:nick_id]}>\s+(.+)/im) command2 = $2 Thread.current[:command] = command2 if command2.match?(/^()!!(.+)/im) or command.match?(/^()\^(.+)/im) Thread.current[:on_thread] = true end command = command2 on_demand = true end if @status == :on and (@questions.key?(nick) or (@repl_sessions.key?(nick) and dest==@repl_sessions[nick][:dest] and ((@repl_sessions[nick][:on_thread] and thread_ts == @repl_sessions[nick][:thread_ts]) or (!@repl_sessions[nick][:on_thread] and !Thread.current[:on_thread] ))) or (@listening.key?(nick) and typem != :on_extended and ((@listening[nick].key?(dest) and !Thread.current[:on_thread]) or (@listening[nick].key?(thread_ts) and Thread.current[:on_thread] ) )) or dest[0] == "D" or on_demand) @logger.info "command: #{nick}> #{command}" unless processed #todo: verify this if dest[0] == "C" or dest[0] == "G" or (dest[0] == "D" and typem == :on_call) if typem != :on_call and @rules_imported.key?(user.id) and @rules_imported[user.id].key?(dchannel) if @bots_created.key?(@rules_imported[user.id][dchannel]) if @bots_created[@rules_imported[user.id][dchannel]][:status] != :on respond "The bot on that channel is not :on", dest rules_file = "" end end end unless rules_file.empty? begin eval(File.new(config.path+rules_file).read) if File.exist?(config.path+rules_file) rescue Exception => stack @logger.fatal "ERROR ON RULES FILE: #{rules_file}" @logger.fatal stack end if defined?(rules) command[0] = "" if command[0] == "!" command.gsub!(/^@\w+:*\s*/, "") if method(:rules).parameters.size == 4 rules(user, command, processed, dest) elsif method(:rules).parameters.size == 5 rules(user, command, processed, dest, files) else rules(user, command, processed, dest, files, rules_file) end else @logger.warn "It seems like rules method is not defined" end end elsif @rules_imported.key?(user.id) and @rules_imported[user.id].key?(user.id) if @bots_created.key?(@rules_imported[user.id][user.id]) if @bots_created[@rules_imported[user.id][user.id]][:status] == :on begin eval(File.new(config.path+rules_file).read) if File.exist?(config.path+rules_file) and !['.','..'].include?(config.path + rules_file) rescue Exception => stack @logger.fatal "ERROR ON imported RULES FILE: #{rules_file}" @logger.fatal stack end else respond "The bot on <##{@rules_imported[user.id][user.id]}|#{@bots_created[@rules_imported[user.id][user.id]][:channel_name]}> is not :on", dest rules_file = "" end end unless rules_file.empty? if defined?(rules) command[0] = "" if command[0] == "!" command.gsub!(/^@\w+:*\s*/, "") if method(:rules).parameters.size == 4 rules(user, command, processed, dest) elsif method(:rules).parameters.size == 5 rules(user, command, processed, dest, files) else rules(user, command, processed, dest, files, rules_file) end else @logger.warn "It seems like rules method is not defined" end end else @logger.info "it is a direct message with no rules file selected so no rules file executed." if command.match?(/^\s*bot\s+rules\s*$/i) 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 end unless processed dont_understand('') end end if processed and @listening.key?(nick) if Thread.current[:on_thread] and @listening[nick].key?(Thread.current[:thread_ts]) @listening[nick][Thread.current[:thread_ts]] = Time.now elsif !Thread.current[:on_thread] and @listening[nick].key?(dest) @listening[nick][dest] = Time.now end end end rescue Exception => stack @logger.fatal stack end end rescue => e @logger.error "exception: #{e.inspect}" end end |
#react(emoji, parent = false) ⇒ Object
list of available emojis: https://www.webfx.com/tools/emoji-cheat-sheet/ react(:thumbsup)
4 5 6 7 8 9 10 11 12 13 14 15 |
# File 'lib/slack/smart-bot/comm/react.rb', line 4 def react(emoji, parent=false) if parent ts = Thread.current[:thread_ts] else ts = Thread.current[:ts] end begin client.web_client.reactions_add(channel: Thread.current[:dest], name: emoji, timestamp: ts) rescue Exception => stack @logger.warn stack end end |
#remove_hash_keys(hash, key) ⇒ Object
3 4 5 6 7 8 9 10 11 12 13 14 15 |
# File 'lib/slack/smart-bot/utils/remove_hash_keys.rb', line 3 def remove_hash_keys(hash, key) newh = Hash.new hash.each do |k, v| unless k == key if v.is_a?(String) newh[k] = v else newh[k] = remove_hash_keys(v, key) end end end return newh end |
#remove_routine(dest, from, name) ⇒ Object
helpadmin: ----------------------------------------------
helpadmin: kill routine NAME
helpadmin: delete routine NAME
helpadmin: remove routine NAME
helpadmin: It will kill and remove the specified routine
helpadmin: You can use this command only if you are an admin user
helpadmin: NAME: one word to identify the routine
helpadmin: Examples:
helpadmin: kill routine example
helpadmin:
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
# File 'lib/slack/smart-bot/commands/on_bot/admin/remove_routine.rb', line 13 def remove_routine(dest, from, name) save_stats(__method__) if config.admins.include?(from) #admin user if !config.on_master_bot and dest[0] == "D" respond "It's only possible to remove routines from MASTER channel from a direct message with the bot.", dest elsif @routines.key?(@channel_id) and @routines[@channel_id].key?(name) @routines[@channel_id][name][:thread].exit @routines[@channel_id].delete(name) update_routines() respond "The routine *`#{name}`* has been removed.", dest else respond "There isn't a routine with that name: *`#{name}`*.\nCall `see routines` to see added routines", dest end else respond "Only admin users can delete routines", dest end end |
#repl(dest, user, session_name, env_vars, rules_file, command, description, type) ⇒ Object
help: ----------------------------------------------
help: repl
help: live
help: irb
help: repl SESSION_NAME
help: private repl SESSION_NAME
help: repl ENV_VAR=VALUE
help: repl SESSION_NAME ENV_VAR=VALUE ENV_VAR='VALUE'
help: repl SESSION_NAME: "DESCRIPTION"
help: repl SESSION_NAME: "DESCRIPTION" ENV_VAR=VALUE ENV_VAR='VALUE'
help:
help: Will run all we write as a ruby command and will keep the session values.
help: SESSION_NAME only admits from a to Z, numbers, - and _
help: If no SESSION_NAME supplied it will be treated as a temporary REPL
help: If 'private' specified the repl will be accessible only by you and it will be displayed only to you when see repls
help: To avoid a message to be treated, start the message with '-'.
help: Send quit, bye or exit to finish the session.
help: Send puts, print, p or pp if you want to print out something when using run repl
later.
help: After 30 minutes of no communication with the Smart Bot the session will be dismissed.
help: If you declare on your rules file a method called project_folder
returning the path for the project folder, the code will be executed from that folder.
help: By default it will be automatically loaded the gems: string_pattern, nice_hash and nice_http
help: To pre-execute some ruby when starting the session add the code to .smart-bot-repl file on the project root folder defined on project_folder
help: If you want to see the methods of a class or module you created use ls TheModuleOrClass
help: You can supply the Environmental Variables you need for the Session
help: Examples:
help: repl CreateCustomer LOCATION=spain HOST='https://10.30.40.50:8887'
help: repl CreateCustomer: "It creates a random customer for testing" LOCATION=spain HOST='https://10.30.40.50:8887'
help: repl delete_logs
help: private repl random-ssn
help:
32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 |
# File 'lib/slack/smart-bot/commands/on_bot/repl.rb', line 32 def repl(dest, user, session_name, env_vars, rules_file, command, description, type) #todo: add more tests from = user.name if config[:allow_access].key?(__method__) and !config[:allow_access][__method__].include?(user.name) and !config[:allow_access][__method__].include?(user.id) and (!user.key?(:enterprise_user) or ( user.key?(:enterprise_user) and !config[:allow_access][__method__].include?(user[:enterprise_user].id))) respond "You don't have access to use this command, please contact an Admin to be able to use it: <@#{config.admins.join(">, <@")}>" else if !@repl_sessions.key?(from) save_stats(__method__) Dir.mkdir("#{config.path}/repl") unless Dir.exist?("#{config.path}/repl") Dir.mkdir("#{config.path}/repl/#{@channel_id}") unless Dir.exist?("#{config.path}/repl/#{@channel_id}") serialt = Time.now.strftime("%Y%m%d%H%M%S%N") if session_name.to_s=='' session_name = "#{from}_#{serialt}" temp_repl = true else temp_repl = false i = 0 name = session_name while File.exist?("#{config.path}/repl/#{@channel_id}/#{session_name}.input") i+=1 session_name = "#{name}#{i}" end end @repl_sessions[from] = { name: session_name, dest: dest, started: Time.now, finished: Time.now, input: [], on_thread: Thread.current[:on_thread], thread_ts: Thread.current[:thread_ts] } unless temp_repl @repls[session_name] = { created: @repl_sessions[from][:started].to_s, accessed: @repl_sessions[from][:started].to_s, creator_name: user.name, creator_id: user.id, description: description, type: type, runs_by_creator: 0, runs_by_others: 0, gets: 0 } update_repls() end = "Session name: *#{session_name}* From now on I will execute all you write as a Ruby command and I will keep the session open until you send `quit` or `bye` or `exit`. I will respond with the result so it is not necessary you send `print`, `puts`, `p` or `pp` unless you want it as the output when calling `run repl`. If you want to avoid a message to be treated by me, start the message with '-'. After 30 minutes of no communication with the Smart Bot the session will be dismissed. If you want to see the methods of a class or module you created use _ls TheModuleOrClass_ You can supply the Environmental Variables you need for the Session Example: _repl CreateCustomer LOCATION=spain HOST='https://10.30.40.50:8887'_ " respond , dest File.write("#{config.path}/repl/#{@channel_id}/#{@repl_sessions[from][:name]}.input", "", mode: "a+") File.write("#{config.path}/repl/#{@channel_id}/#{@repl_sessions[from][:name]}.output", "", mode: "a+") process_to_run = ' ruby -e "' + env_vars.join("\n") + ' require \"awesome_print\" bindme' + serialt + ' = binding eval(\"require \'nice_http\'\" , bindme' + serialt + ') file_input_repl = File.open(\"' + Dir.pwd + '/repl/' + @channel_id + '/' + session_name + '.input\", \"r\") if File.exist?(\"./.smart-bot-repl\") begin eval(File.read(\"./.smart-bot-repl\"), bindme' + serialt + ') rescue Exception => resp_repl end end while true do sleep 0.2 code_to_run_repl = file_input_repl.read if code_to_run_repl.to_s!='' if code_to_run_repl.to_s.match?(/^quit$/i) or code_to_run_repl.to_s.match?(/^exit$/i) or code_to_run_repl.to_s.match?(/^bye bot$/i) or code_to_run_repl.to_s.match?(/^bye$/i) exit else if code_to_run_repl.match?(/^\s*ls\s+(.+)/) code_to_run_repl = \"#{code_to_run_repl.scan(/^\s*ls\s+(.+)/).join}.methods - Object.methods\" end begin code_to_run_repl.gsub!(/^\s*(puts|print|p|pp)\s/, \"\") resp_repl = eval(code_to_run_repl.to_s, bindme' + serialt + ') rescue Exception => resp_repl end if resp_repl.to_s != \"\" open(\"' + Dir.pwd + '/repl/' + @channel_id + '/' + session_name + '.output\", \"a+\") {|f| f.puts \"\`\`\`#{resp_repl.awesome_inspect}\`\`\`\" } end end end end" ' unless rules_file.empty? # to get the project_folder begin eval(File.new(config.path+rules_file).read) if File.exist?(config.path+rules_file) end end started = Time.now process_to_run = ("cd #{project_folder} &&" + process_to_run) if defined?(project_folder) stdin, stdout, stderr, wait_thr = Open3.popen3(process_to_run) timeout = 30 * 60 # 30 minutes file_output_repl = File.open("#{config.path}/repl/#{@channel_id}/#{session_name}.output", "r") while (wait_thr.status == 'run' or wait_thr.status == 'sleep') and @repl_sessions.key?(from) begin if (Time.now-@repl_sessions[from][:finished]) > timeout open("#{config.path}/repl/#{@channel_id}/#{@repl_sessions[from][:name]}.input", 'a+') {|f| f.puts 'quit' } respond "REPL session finished: #{@repl_sessions[from][:name]}", dest @repl_sessions.delete(from) break end sleep 0.2 resp_repl = file_output_repl.read if resp_repl.to_s!='' respond resp_repl, dest end rescue Exception => excp @logger.fatal excp end end else @repl_sessions[from][:finished] = Time.now code = @repl_sessions[from][:command] @repl_sessions[from][:command] = '' code.gsub!("\\n", "\n") code.gsub!("\\r", "\r") # Disabled for the moment sinde it is deleting lines with '}' #code.gsub!(/^\W*$/, "") #to remove special chars from slack when copy/pasting. if code.match?(/System/i) or code.match?(/Kernel/i) or code.include?("File") or code.include?("`") or code.include?("exec") or code.include?("spawn") or code.include?("IO.") or code.match?(/open3/i) or code.match?(/bundle/i) or code.match?(/gemfile/i) or code.include?("%x") or code.include?("ENV") or code.match?(/=\s*IO/) respond "Sorry I cannot run this due security reasons", dest else @repl_sessions[from][:input]<<code case code when /^\s*(quit|exit|bye|bye bot)\s*$/i open("#{config.path}/repl/#{@channel_id}/#{@repl_sessions[from][:name]}.input", 'a+') {|f| f.puts code } respond "REPL session finished: #{@repl_sessions[from][:name]}", dest @repl_sessions.delete(from) when /^\s*-/i #ommit else open("#{config.path}/repl/#{@channel_id}/#{@repl_sessions[from][:name]}.input", 'a+') {|f| f.puts code } end end end end end |
#respond(msg, dest = nil) ⇒ Object
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/slack/smart-bot/comm/respond.rb', line 2 def respond(msg, dest = nil) if dest.nil? and Thread.current.key?(:dest) dest = Thread.current[:dest] end dest = @channels_id[dest] if @channels_id.key?(dest) #it is a name of channel if dest.nil? if config[:simulate] open("#{config.path}/buffer_complete.log", "a") { |f| f.puts "|#{@channel_id}|#{config[:nick_id]}|#{msg}~~~" } else if Thread.current[:on_thread] client.(channel: @channel_id, text: msg, as_user: true, thread_ts: Thread.current[:thread_ts]) else client.(channel: @channel_id, text: msg, as_user: true) end end if config[:testing] and config.on_master_bot open("#{config.path}/buffer.log", "a") { |f| f.puts "|#{@channel_id}|#{config[:nick_id]}|#{msg}" } end elsif dest[0] == "C" or dest[0] == "G" # channel if config[:simulate] open("#{config.path}/buffer_complete.log", "a") { |f| f.puts "|#{dest}|#{config[:nick_id]}|#{msg}~~~" } else if Thread.current[:on_thread] client.(channel: dest, text: msg, as_user: true, thread_ts: Thread.current[:thread_ts]) else client.(channel: dest, text: msg, as_user: true) end end if config[:testing] and config.on_master_bot open("#{config.path}/buffer.log", "a") { |f| f.puts "|#{dest}|#{config[:nick_id]}|#{msg}" } end elsif dest[0] == "D" or dest[0] == "U" # Direct message send_msg_user(dest, msg) elsif dest[0] == "@" begin user_info = client.web_client.users_info(user: dest) send_msg_user(user_info.user.id, msg) rescue Exception => stack @logger.warn("user #{dest} not found.") @logger.warn stack if Thread.current.key?(:dest) respond("User #{dest} not found.") end end else @logger.warn("method respond not treated correctly: msg:#{msg} dest:#{dest}") end end |
#respond_direct(msg) ⇒ Object
2 3 4 5 |
# File 'lib/slack/smart-bot/comm/respond_direct.rb', line 2 def respond_direct(msg) dest = Thread.current[:user].id respond(msg, dest) end |
#ruby_code(dest, user, code, rules_file) ⇒ Object
help: ----------------------------------------------
help: ruby RUBY_CODE
help: code RUBY_CODE
help: runs the code supplied and returns the output. Also you can send a Ruby file instead. Examples:
help: code puts (34344/99)*(34+14)
help: ruby require 'json'; res=[]; 20.times res<<rand(100); my_json=res; puts my_json.to_json
help:
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/slack/smart-bot/commands/on_bot/ruby_code.rb', line 10 def ruby_code(dest, user, code, rules_file) save_stats(__method__) if config[:allow_access].key?(__method__) and !config[:allow_access][__method__].include?(user.name) and !config[:allow_access][__method__].include?(user.id) and (!user.key?(:enterprise_user) or ( user.key?(:enterprise_user) and !config[:allow_access][__method__].include?(user[:enterprise_user].id))) respond "You don't have access to use this command, please contact an Admin to be able to use it: <@#{config.admins.join(">, <@")}>" else unless code.match?(/System/i) or code.match?(/Kernel/i) or code.include?("File") or code.include?("`") or code.include?("exec") or code.include?("spawn") or code.include?("IO.") or code.match?(/open3/i) or code.match?(/bundle/i) or code.match?(/gemfile/i) or code.include?("%x") or code.include?("ENV") or code.match?(/=\s*IO/) unless rules_file.empty? begin eval(File.new(config.path+rules_file).read) if File.exist?(config.path+rules_file) end end respond "Running", dest if code.size > 100 begin code.gsub!(/^\W*$/, "") #to remove special chars from slack when copy/pasting ruby = "ruby -e \"#{code.gsub('"', '\"')}\"" if defined?(project_folder) and project_folder.to_s != "" and Dir.exist?(project_folder) ruby = ("cd #{project_folder} &&" + ruby) else def project_folder() "" end end stdout, stderr, status = Open3.capture3(ruby) if stderr == "" if stdout == "" respond "Nothing returned. Remember you need to use p or puts to print", dest else respond stdout, dest end else respond "#{stderr}\n#{stdout}", dest end rescue Exception => exc respond exc, dest end else respond "Sorry I cannot run this due security reasons", dest end end end |
#run_repl(dest, user, session_name, env_vars, rules_file) ⇒ Object
help: ----------------------------------------------
help: run repl SESSION_NAME
help: run repl SESSION_NAME ENV_VAR=VALUE ENV_VAR=VALUE
help: run live SESSION_NAME
help: run irb SESSION_NAME
help:
help: Will run the repl session specified and return the output.
help: You can supply the Environmental Variables you need for the Session
help: It will return only the values that were print out on the repl with puts, print, p or pp
help: Example:
help: run repl CreateCustomer LOCATION=spain HOST='https://10.30.40.50:8887'
help:
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
# File 'lib/slack/smart-bot/commands/on_bot/run_repl.rb', line 14 def run_repl(dest, user, session_name, env_vars, rules_file) #todo: add tests from = user.name if config[:allow_access].key?(__method__) and !config[:allow_access][__method__].include?(user.name) and !config[:allow_access][__method__].include?(user.id) and (!user.key?(:enterprise_user) or ( user.key?(:enterprise_user) and !config[:allow_access][__method__].include?(user[:enterprise_user].id))) respond "You don't have access to use this command, please contact an Admin to be able to use it: <@#{config.admins.join(">, <@")}>" else save_stats(__method__) Dir.mkdir("#{config.path}/repl") unless Dir.exist?("#{config.path}/repl") Dir.mkdir("#{config.path}/repl/#{@channel_id}") unless Dir.exist?("#{config.path}/repl/#{@channel_id}") if File.exist?("#{config.path}/repl/#{@channel_id}/#{session_name}.input") if @repls.key?(session_name) and @repls[session_name][:type] == :private and @repls[session_name][:creator_name]!=user.name and !config.admins.include?(user.name) respond "The REPL with session name: #{session_name} is private", dest else if @repls.key?(session_name) #not temp @repls[session_name][:accessed] = Time.now.to_s if @repls[session_name].creator_name == user.name @repls[session_name][:runs_by_creator] += 1 else @repls[session_name][:runs_by_others] += 1 end update_repls() end content = env_vars.join("\n") content += "\nrequire 'nice_http'\n" unless rules_file.empty? # to get the project_folder begin eval(File.new(config.path+rules_file).read) if File.exist?(config.path+rules_file) end end if File.exist?("#{project_folder}/.smart-bot-repl") content += File.read("#{project_folder}/.smart-bot-repl") content += "\n" end content += File.read("#{config.path}/repl/#{@channel_id}/#{session_name}.input").gsub(/^(quit|exit|bye)$/i,'') Dir.mkdir("#{project_folder}/tmp") unless Dir.exist?("#{project_folder}/tmp") Dir.mkdir("#{project_folder}/tmp/repl") unless Dir.exist?("#{project_folder}/tmp/repl") File.write("#{project_folder}/tmp/repl/#{session_name}.rb", content, mode: "w+") process_to_run = "ruby #{project_folder}/tmp/repl/#{session_name}.rb" process_to_run = ("cd #{project_folder} && #{process_to_run}") if defined?(project_folder) respond "Running REPL #{session_name}" stdout, stderr, status = Open3.capture3(process_to_run) if stderr == "" if stdout == "" respond "*#{session_name}*: Nothing returned." else respond "*#{session_name}*: #{stdout}" end else respond "*#{session_name}*: #{stdout} #{stderr}" end end else respond "The REPL with session name: #{session_name} doesn't exist on this Smart Bot Channel", dest end end end |
#run_routine(dest, from, name) ⇒ Object
helpadmin: ----------------------------------------------
helpadmin: run routine NAME
helpadmin: execute routine NAME
helpadmin: It will run the specified routine
helpadmin: You can use this command only if you are an admin user
helpadmin: NAME: one word to identify the routine
helpadmin: Examples:
helpadmin: run routine example
helpadmin:
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
# File 'lib/slack/smart-bot/commands/on_bot/admin/run_routine.rb', line 13 def run_routine(dest, from, name) save_stats(__method__) if config.admins.include?(from) #admin user if !config.on_master_bot and dest[0] == "D" respond "It's only possible to run routines from MASTER channel from a direct message with the bot.", dest elsif @routines.key?(@channel_id) and @routines[@channel_id].key?(name) if @routines[@channel_id][name][:file_path] != "" if @routines[@channel_id][name][:file_path].match?(/\.rb$/i) ruby = "ruby " else ruby = "" end started = Time.now process_to_run = "#{ruby}#{Dir.pwd}#{@routines[@channel_id][name][:file_path][1..-1]}" process_to_run = ("cd #{project_folder} &&" + process_to_run) if defined?(project_folder) stdout, stderr, status = Open3.capture3(process_to_run) if stderr == "" unless stdout.match?(/\A\s*\z/) respond "routine *`#{name}`*: #{stdout}", @routines[@channel_id][name][:dest] end else respond "routine *`#{name}`*: #{stdout} #{stderr}", @routines[@channel_id][name][:dest] end else #command respond "routine *`#{name}`*: #{@routines[@channel_id][name][:command]}", @routines[@channel_id][name][:dest] started = Time.now ({ channel: @routines[@channel_id][name][:dest], user: @routines[@channel_id][name][:creator_id], text: @routines[@channel_id][name][:command], files: nil }) end @routines[@channel_id][name][:last_elapsed] = (Time.now - started) @routines[@channel_id][name][:last_run] = started.to_s update_routines() else respond "There isn't a routine with that name: `#{name}`.\nCall `see routines` to see added routines", dest end else respond "Only admin users can run routines", dest end end |
#save_stats(method) ⇒ Object
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
# File 'lib/slack/smart-bot/utils/save_stats.rb', line 3 def save_stats(method) if config.stats begin require 'csv' if !File.exist?("#{config.stats_path}.#{Time.now.strftime("%Y-%m")}.log") CSV.open("#{config.stats_path}.#{Time.now.strftime("%Y-%m")}.log", 'wb') do |csv| csv << ['date','bot_channel', 'bot_channel_id', 'dest_channel', 'dest_channel_id', 'type_message', 'user_name', 'user_id', 'text', 'command', 'files'] end end dest = Thread.current[:dest] typem = Thread.current[:typem] user = Thread.current[:user] files = Thread.current[:files?] if method.to_s == 'ruby_code' and files command_txt = 'ruby' else command_txt = Thread.current[:command] end CSV.open("#{config.stats_path}.#{Time.now.strftime("%Y-%m")}.log", "a+") do |csv| csv << [Time.now, config.channel, @channel_id, @channels_name[dest], dest, typem, user.name, user.id, command_txt, method, files] end rescue Exception => exception @logger.fatal "There was a problem on the stats" @logger.fatal exception end end end |
#see_repls(dest, user, typem) ⇒ Object
help: ----------------------------------------------
help: see repls
help: see irbs
help: It will display the repls
help:
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
# File 'lib/slack/smart-bot/commands/on_bot/see_repls.rb', line 7 def see_repls(dest, user, typem) #todo: add tests save_stats(__method__) from = user.name if config[:allow_access].key?(__method__) and !config[:allow_access][__method__].include?(user.name) and !config[:allow_access][__method__].include?(user.id) and (!user.key?(:enterprise_user) or ( user.key?(:enterprise_user) and !config[:allow_access][__method__].include?(user[:enterprise_user].id))) respond "You don't have access to use this command, please contact an Admin to be able to use it: <@#{config.admins.join(">, <@")}>" else = "" @repls.sort.to_h.each do |session_name, repl| if (repl.creator_name == user.name or repl.type == :public) or (config.admins.include?(user.name) and typem == :on_dm) += "(#{repl.type}) *#{session_name}*: #{repl.description} / created: #{repl.created} / accessed: #{repl.accessed} / creator: #{repl.creator} / runs: #{repl.runs_by_creator+repl.runs_by_others} / gets: #{repl.gets} \n" end end = "No repls created" if == '' respond end end |
#see_routines(dest, from, user, all) ⇒ Object
helpadmin: ----------------------------------------------
helpadmin: see routines
helpadmin: see all routines
helpadmin: It will show the routines of the channel
helpadmin: In case of all
and on the master channel, it will show all the routines from all channels
helpadmin: You can use this command only if you are an admin user
helpadmin:
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/slack/smart-bot/commands/on_bot/admin/see_routines.rb', line 9 def see_routines(dest, from, user, all) save_stats(__method__) if config.admins.include?(from) #admin user if all routines = {} if config.on_master_bot Dir["#{config.path}/routines/routines_*.rb"].each do |rout| file_conf = IO.readlines(rout).join unless file_conf.to_s() == "" routines.merge!(eval(file_conf)) end end else respond "To see all routines on all channels you need to run the command on the master channel.\nI'll display only the routines on this channel.", dest routines = @routines.dup end else if @rules_imported.key?(user.id) and @rules_imported[user.id].key?(user.id) and dest[0] == "D" file_conf = IO.readlines("#{config.path}/routines/routines_#{@rules_imported[user.id][user.id]}.rb").join routines = eval(file_conf) else routines = @routines.dup end end if routines.get_values(:channel_name).size == 0 respond "There are no routines added.", dest else routines.each do |ch, rout_ch| respond "Routines on channel *#{rout_ch.get_values(:channel_name).values.flatten.uniq[0]}*", dest rout_ch.each do |k, v| msg = [] ch != v[:dest] ? directm = " (*DM to #{v[:creator]}*)" : directm = "" msg << "*`#{k}`*#{directm}" msg << "\tCreator: #{v[:creator]}" msg << "\tStatus: #{v[:status]}" msg << "\tEvery: #{v[:every]}" unless v[:every] == "" msg << "\tAt: #{v[:at]}" unless v[:at] == "" msg << "\tNext Run: #{v[:next_run]}" msg << "\tLast Run: #{v[:last_run]}" msg << "\tTime consumed on last run: #{v[:last_elapsed]}" unless v[:command] !='' msg << "\tCommand: #{v[:command]}" unless v[:command].to_s.strip == '' msg << "\tFile: #{v[:file_path]}" unless v[:file_path] == '' msg << "\tSilent: #{v[:silent]}" unless !v[:silent] respond msg.join("\n"), dest end end end else respond "Only admin users can use this command", dest end end |
#see_shortcuts(dest, user, typem) ⇒ Object
help: ----------------------------------------------
help: see shortcuts
help: see sc
help: It will display the shortcuts stored for the user and for :all
help:
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
# File 'lib/slack/smart-bot/commands/on_bot/see_shortcuts.rb', line 7 def see_shortcuts(dest, user, typem) save_stats(__method__) from = user.name if config[:allow_access].key?(__method__) and !config[:allow_access][__method__].include?(user.name) and !config[:allow_access][__method__].include?(user.id) and (!user.key?(:enterprise_user) or ( user.key?(:enterprise_user) and !config[:allow_access][__method__].include?(user[:enterprise_user].id))) respond "You don't have access to use this command, please contact an Admin to be able to use it: <@#{config.admins.join(">, <@")}>" else unless typem == :on_extended msg = "" if @shortcuts[:all].keys.size > 0 msg = "*Available shortcuts for all:*\n" @shortcuts[:all].each { |name, value| msg += " _#{name}: #{value}_\n" } respond msg, dest end if @shortcuts.keys.include?(from) and @shortcuts[from].keys.size > 0 new_hash = @shortcuts[from].dup @shortcuts[:all].keys.each { |k| new_hash.delete(k) } if new_hash.keys.size > 0 msg = "*Available shortcuts for #{from}:*\n" new_hash.each { |name, value| msg += " _#{name}: #{value}_\n" } respond msg, dest end end respond "No shortcuts found", dest if msg == "" end end end |
#send_file(to, msg, file, title, format, type = "text") ⇒ Object
to send a file to an user or channel send_file(dest, 'the message', "##project_folder/temp/logs_ptBI.log", 'message to be sent', 'text/plain', "text") send_file(dest, 'the message', "##project_folder/temp/example.jpeg", 'message to be sent', 'image/jpeg', "jpg")
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
# File 'lib/slack/smart-bot/comm/send_file.rb', line 6 def send_file(to, msg, file, title, format, type = "text") unless config[:simulate] if to[0] == "U" #user im = client.web_client.im_open(user: to) channel = im["channel"]["id"] else channel = to end if Thread.current[:on_thread] ts = Thread.current[:thread_ts] else ts = nil end client.web_client.files_upload( channels: channel, as_user: true, file: Faraday::UploadIO.new(file, format), title: title, filename: file, filetype: type, initial_comment: msg, thread_ts: ts ) end end |
#send_msg_channel(to, msg) ⇒ Object
to: (String) Channel name or id msg: (String) message to send
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
# File 'lib/slack/smart-bot/comm/send_msg_channel.rb', line 5 def send_msg_channel(to, msg) unless msg == "" get_channels_name_and_id() unless @channels_name.key?(to) or @channels_id.key?(to) if @channels_name.key?(to) #it is an id channel_id = to elsif @channels_id.key?(to) #it is a channel name channel_id = @channels_id[to] else @logger.fatal "Channel: #{to} not found. Message: #{msg}" end if config[:simulate] open("#{config.path}/buffer_complete.log", "a") { |f| f.puts "|#{channel_id}|#{config[:nick_id]}|#{msg}~~~" } else if Thread.current[:on_thread] client.(channel: channel_id, text: msg, as_user: true, thread_ts: Thread.current[:thread_ts]) else client.(channel: channel_id, text: msg, as_user: true) end end if config[:testing] and config.on_master_bot open("#{config.path}/buffer.log", "a") { |f| f.puts "|#{channel_id}|#{config[:nick_id]}|#{msg}" } end end end |
#send_msg_user(id_user, msg) ⇒ Object
to send messages without listening for a response to users
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
# File 'lib/slack/smart-bot/comm/send_msg_user.rb', line 4 def send_msg_user(id_user, msg) unless msg == "" if id_user[0] == "D" if config[:simulate] open("#{config.path}/buffer_complete.log", "a") { |f| f.puts "|#{id_user}|#{config[:nick_id]}|#{msg}~~~" } else if Thread.current[:on_thread] client.(channel: id_user, as_user: true, text: msg, thread_ts: Thread.current[:thread_ts]) else client.(channel: id_user, as_user: true, text: msg) end end if config[:testing] and config.on_master_bot open("#{config.path}/buffer.log", "a") { |f| f.puts "|#{id_user}|#{config[:nick_id]}|#{msg}" } end else im = client.web_client.im_open(user: id_user) if config[:simulate] open("#{config.path}/buffer_complete.log", "a") { |f| f.puts "|#{im["channel"]["id"]}|#{config[:nick_id]}|#{msg}~~~" } else if Thread.current[:on_thread] client.(channel: im["channel"]["id"], as_user: true, text: msg, thread_ts: Thread.current[:thread_ts]) else client.(channel: im["channel"]["id"], as_user: true, text: msg) end end if config[:testing] and config.on_master_bot open("#{config.path}/buffer.log", "a") { |f| f.puts "|#{im["channel"]["id"]}|#{config[:nick_id]}|#{msg}" } end end end end |
#start_bot(dest, from) ⇒ Object
helpadmin: ----------------------------------------------
helpadmin: start bot
helpadmin: start this bot
helpadmin: the bot will start to listen
helpadmin: You can use this command only if you are an admin user
helpadmin:
9 10 11 12 13 14 15 16 17 18 19 20 21 |
# File 'lib/slack/smart-bot/commands/on_bot/admin/start_bot.rb', line 9 def start_bot(dest, from) save_stats(__method__) if config.admins.include?(from) #admin user respond "This bot is running and listening from now on. You can pause again: pause this bot", dest @status = :on @bots_created[@channel_id][:status] = :on unless config.on_master_bot send_msg_channel config.master_channel, "Changed status on #{config.channel} to :on" end else respond "Only admin users can change my status", dest end end |
#start_routine(dest, from, name) ⇒ Object
helpadmin: ----------------------------------------------
helpadmin: start routine NAME
helpadmin: It will start a paused routine
helpadmin: You can use this command only if you are an admin user
helpadmin: NAME: one word to identify the routine
helpadmin: Examples:
helpadmin: start routine example
helpadmin:
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
# File 'lib/slack/smart-bot/commands/on_bot/admin/start_routine.rb', line 12 def start_routine(dest, from, name) save_stats(__method__) if config.admins.include?(from) #admin user if !config.on_master_bot and dest[0] == "D" respond "It's only possible to start routines from MASTER channel from a direct message with the bot.", dest elsif @routines.key?(@channel_id) and @routines[@channel_id].key?(name) @routines[@channel_id][name][:status] = :on if @routines[@channel_id][name][:at]!='' started = Time.now if started.strftime("%H:%M:%S") < @routines[@channel_id][name][:at] nt = @routines[@channel_id][name][:at].split(":") next_run = Time.new(started.year, started.month, started.day, nt[0], nt[1], nt[2]) else next_run = started + (24 * 60 * 60) # one more day nt = @routines[@channel_id][name][:at].split(":") next_run = Time.new(next_run.year, next_run.month, next_run.day, nt[0], nt[1], nt[2]) end @routines[@channel_id][name][:next_run] = next_run.to_s @routines[@channel_id][name][:sleeping] = (next_run - started).ceil end update_routines() respond "The routine *`#{name}`* has been started. The change will take effect in less than 30 secs.", dest else respond "There isn't a routine with that name: *`#{name}`*.\nCall `see routines` to see added routines", dest end else respond "Only admin users can use this command", dest end end |
#stop_using_rules(dest, channel, user, dchannel) ⇒ Object
help: ----------------------------------------------
help: stop using rules from CHANNEL
help: it will stop using the rules from the specified channel.
help:
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
# File 'lib/slack/smart-bot/commands/general/stop_using_rules.rb', line 6 def stop_using_rules(dest, channel, user, dchannel) save_stats(__method__) if @channels_id.key?(channel) channel_id = @channels_id[channel] else channel_id = channel end if dest[0] == "C" or dest[0] == "G" #channel if @rules_imported.key?(user.id) and @rules_imported[user.id].key?(dchannel) if @rules_imported[user.id][dchannel] != channel_id respond "You are not using those rules.", dest else @rules_imported[user.id].delete(dchannel) update_rules_imported() respond "You won't be using those rules from now on.", dest def git_project() "" end def project_folder() "" end end else respond "You were not using those rules.", dest end else #direct message if @rules_imported.key?(user.id) and @rules_imported[user.id].key?(user.id) if @rules_imported[user.id][user.id] != channel_id respond "You are not using those rules.", dest else @rules_imported[user.id].delete(user.id) update_rules_imported() respond "You won't be using those rules from now on.", dest def git_project() "" end def project_folder() "" end end else respond "You were not using those rules.", dest end end end |
#stop_using_rules_on(dest, user, from, channel, typem) ⇒ Object
helpadmin: ----------------------------------------------
helpadmin: stop using rules on CHANNEL_NAME
helpadmin: it will stop using the extended rules on the specified channel.
helpadmin:
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
# File 'lib/slack/smart-bot/commands/on_bot/admin/stop_using_rules_on.rb', line 8 def stop_using_rules_on(dest, user, from, channel, typem) save_stats(__method__) unless typem == :on_extended if !config.admins.include?(from) #not admin respond "Only admins can extend or stop using the rules. Admins on this channel: #{config.admins}", dest else get_bots_created() if @bots_created[@channel_id][:extended].include?(channel) @bots_created[@channel_id][:extended].delete(channel) update_bots_file() respond "<@#{user.id}> removed the access to the rules of #{config.channel} from #{channel}.", @master_bot_id if @channels_id[channel][0] == "G" respond "The rules won't be accessible from *#{channel}* from now on.", dest else respond "The rules won't be accessible from *<##{@channels_id[channel]}>* from now on.", dest end respond "<@#{user.id}> removed the access to the rules of <##{@channel_id}> from this channel.", @channels_id[channel] else respond "The rules were not accessible from *#{channel}*", dest end end end end |
#treat_message(data, remove_blocks = true) ⇒ Object
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 |
# File 'lib/slack/smart-bot/treat_message.rb', line 2 def (data, remove_blocks = true) begin unless data.text.to_s.match(/\A\s*\z/) #to remove italic, bold... from data.text since there is no method on slack api #only works when no @user or #channel mentioned if remove_blocks and !data.blocks.nil? and data.blocks.size > 0 data.blocks.each do |b| if b.type == 'rich_text' if b.elements.size > 0 b.elements.each do |e| if e.type == 'rich_text_section' if e.elements.size > 0 and (e.elements.type.uniq - ['link', 'text']) == [] data.text = '' e.elements.each do |el| if el.type == 'text' data.text += el.text else data.text += el.url end end end break end end end break end end end data.text = CGI.unescapeHTML(data.text) data.text.gsub!("\u00A0", " ") #to change (asc char 160) into blank space end rescue @logger.warn "Impossible to unescape or clean format for data.text:#{data.text}" end if config[:testing] and config.on_master_bot open("#{config.path}/buffer.log", "a") { |f| f.puts "|#{data.channel}|#{data.user}|#{data.text}" } end if data.channel[0] == "D" or data.channel[0] == "C" or data.channel[0] == "G" #Direct message or Channel or Private Channel dest = data.channel else # not treated dest = nil end #todo: sometimes data.user is nil, check the problem. @logger.warn "!dest is nil. user: #{data.user}, channel: #{data.channel}, message: #{data.text}" if dest.nil? if !data.files.nil? and data.files.size == 1 and data.text.to_s == "" and data.files[0].filetype == "ruby" data.text = "ruby" end if !dest.nil? and config.on_master_bot and !data.text.nil? and data.text.match(/^ping from (.+)\s*$/) and data.user == config[:nick_id] @pings << $1 end typem = :dont_treat if !dest.nil? and !data.text.nil? and !data.text.to_s.match?(/^\s*$/) if data.text.match(/^<@#{config[:nick_id]}>\s(on\s)?<#(\w+)\|([^>]+)>\s*:?\s*(.*)/im) channel_rules = $2 channel_rules_name = $3 # to be treated only on the bot of the requested channel if @channel_id == channel_rules data.text = $4 typem = :on_call end elsif dest == @master_bot_id if config.on_master_bot #only to be treated on master bot channel typem = :on_master end elsif @bots_created.key?(dest) if @channel_id == dest #only to be treated by the bot on the channel typem = :on_bot end elsif dest[0] == "D" #Direct message get_rules_imported() if @rules_imported.key?(data.user) && @rules_imported[data.user].key?(data.user) and @bots_created.key?(@rules_imported[data.user][data.user]) if @channel_id == @rules_imported[data.user][data.user] #only to be treated by the channel we are 'using' typem = :on_dm end elsif config.on_master_bot #only to be treated by master bot typem = :on_dm end elsif dest[0] == "C" or dest[0] == "G" #only to be treated on the channel of the bot. excluding running ruby if !config.on_master_bot and @bots_created.key?(@channel_id) and @bots_created[@channel_id][:extended].include?(@channels_name[dest]) and !data.text.match?(/^!?\s*(ruby|code)\s+/) and !data.text.match?(/^!?!?\s*(ruby|code)\s+/) and !data.text.match?(/^\^?\s*(ruby|code)\s+/) typem = :on_extended elsif config.on_master_bot and (data.text.match?(/^!?\s*(ruby|code)\s+/) or data.text.match?(/^!?!?\s*(ruby|code)\s+/) or data.text.match?(/^\^?\s*(ruby|code)\s+/) ) #or in case of running ruby, the master bot @bots_created.each do |k, v| if v.key?(:extended) and v[:extended].include?(@channels_name[dest]) typem = :on_extended break end end end if dest[0] == "G" and config.on_master_bot and typem != :on_extended #private group typem = :on_pg end end end unless typem == :dont_treat if (Time.now - @last_activity_check) > 60 * 30 #every 30 minutes @last_activity_check = Time.now @listening.each do |k,v| v.each do |kk, vv| @listening[k].delete(kk) if (Time.now - vv) > 60 * 30 end @listening.delete(k) if @listening[k].empty? end end begin #todo: when changed @questions user_id then move user_info inside the ifs to avoid calling it when not necessary user_info = client.web_client.users_info(user: data.user) if @questions.key?(user_info.user.name) if data.text.match?(/^\s*(Bye|Bæ|Good\sBye|Adiós|Ciao|Bless|Bless\sBless|Adeu)\s(#{@salutations.join("|")})\s*$/i) @questions.delete(user_info.user.name) command = data.text else command = @questions[user_info.user.name] @questions[user_info.user.name] = data.text end elsif @repl_sessions.key?(user_info.user.name) and dest==@repl_sessions[user_info.user.name][:dest] and ((@repl_sessions[user_info.user.name][:on_thread] and data.thread_ts == @repl_sessions[user_info.user.name][:thread_ts]) or (!@repl_sessions[user_info.user.name][:on_thread] and data.thread_ts.to_s == '' )) @repl_sessions[user_info.user.name][:command] = data.text command = 'repl' else command = data.text end #when added special characters on the message if command.size >= 2 and ((command[0] == "`" and command[-1] == "`") or (command[0] == "*" and command[-1] == "*") or (command[0] == "_" and command[-1] == "_")) command = command[1..-2] end #ruby file attached if !data.files.nil? and data.files.size == 1 and (command.match?(/^(ruby|code)\s*$/) or (command.match?(/^\s*$/) and data.files[0].filetype == "ruby") or (typem == :on_call and data.files[0].filetype == "ruby")) res = Faraday.new("https://files.slack.com", headers: { "Authorization" => "Bearer #{config[:token]}" }).get(data.files[0].url_private) command += " ruby" if command != "ruby" command = "#{command} #{res.body.to_s.force_encoding("UTF-8")}" end if typem == :on_call command = "!" + command unless command[0] == "!" or command.match?(/^\s*$/) or command[0] == "^" #todo: add pagination for case more than 1000 channels on the workspace channels = client.web_client.conversations_list( types: "private_channel,public_channel", limit: "1000", exclude_archived: "true", ).channels channel_found = channels.detect { |c| c.name == channel_rules_name } members = client.web_client.conversations_members(channel: @channels_id[channel_rules_name]).members unless channel_found.nil? if channel_found.nil? @logger.fatal "Not possible to find the channel #{channel_rules_name}" elsif channel_found.name == config.master_channel respond "You cannot use the rules from Master Channel on any other channel.", dest elsif @status != :on respond "The bot in that channel is not :on", dest elsif data.user == channel_found.creator or members.include?(data.user) process_first(user_info.user, command, dest, channel_rules, typem, data.files, data.ts, data.thread_ts) else respond "You need to join the channel <##{channel_found.id}> to be able to use the rules.", dest end elsif config.on_master_bot and typem == :on_extended and command.size > 0 and command[0] != "-" # to run ruby only from the master bot for the case more than one extended process_first(user_info.user, command, dest, @channel_id, typem, data.files, data.ts, data.thread_ts) elsif !config.on_master_bot and @bots_created[@channel_id].key?(:extended) and @bots_created[@channel_id][:extended].include?(@channels_name[data.channel]) and command.size > 0 and command[0] != "-" process_first(user_info.user, command, dest, @channel_id, typem, data.files, data.ts, data.thread_ts) elsif (dest[0] == "D" or @channel_id == data.channel or data.user == config[:nick_id]) and command.size > 0 and command[0] != "-" process_first(user_info.user, command, dest, data.channel, typem, data.files, data.ts, data.thread_ts) # if @botname on #channel_rules: do something end rescue Exception => stack @logger.fatal stack end else if !config.on_master_bot and !dest.nil? and (dest == @master_bot_id or dest[0] == "D") and data.text.match?(/^\s*bot\s+status\s*$/i) and @admin_users_id.include?(data.user) respond "ping from #{config.channel}", dest elsif !config.on_master_bot and !dest.nil? and data.user == config[:nick_id] and dest == @master_bot_id # to treat on other bots the status messages populated on master bot case data.text when /^Bot has been (closed|killed) by/i sleep 2 get_bots_created() when /^Changed status on (.+) to :(.+)/i sleep 2 get_bots_created() when /extended the rules from (.+) to be used on (.+)\.$/i sleep 2 get_bots_created() when /removed the access to the rules of (.+) from (.+)\.$/i sleep 2 get_bots_created() end end end end |
#update_bots_file ⇒ Object
2 3 4 5 6 7 8 9 10 |
# File 'lib/slack/smart-bot/utils/update_bots_file.rb', line 2 def update_bots_file file = File.open(config.file_path.gsub(".rb", "_bots.rb"), "w") bots_created = @bots_created.dup bots_created.each { |k, v| v[:thread] = "" } file.write bots_created.inspect file.close end |
#update_repls(channel = @channel_id) ⇒ Object
3 4 5 6 7 |
# File 'lib/slack/smart-bot/utils/update_repls.rb', line 3 def update_repls(channel = @channel_id) file = File.open("#{config.path}/repl/repls_#{channel}.rb", "w") file.write (@repls.inspect) file.close end |
#update_routines(channel = @channel_id) ⇒ Object
3 4 5 6 7 8 9 10 11 12 13 14 15 |
# File 'lib/slack/smart-bot/utils/update_routines.rb', line 3 def update_routines(channel = @channel_id) routines = {} file = File.open("#{config.path}/routines/routines_#{channel}.rb", "w") @routines.each do |k,v| routines[k]={} v.each do |kk,vv| routines[k][kk] = vv.dup routines[k][kk][:thread]="" end end file.write (routines.inspect) file.close end |
#update_rules_imported ⇒ Object
3 4 5 6 7 |
# File 'lib/slack/smart-bot/utils/update_rules_imported.rb', line 3 def update_rules_imported file = File.open("#{config.path}/rules/rules_imported.rb", "w") file.write @rules_imported.inspect file.close end |
#update_shortcuts_file ⇒ Object
2 3 4 5 6 |
# File 'lib/slack/smart-bot/utils/update_shortcuts_file.rb', line 2 def update_shortcuts_file file = File.open("#{config.path}/shortcuts/#{config.shortcuts_file}", "w") file.write @shortcuts.inspect file.close end |
#use_rules(dest, channel, user, dchannel) ⇒ Object
help: ----------------------------------------------
help: use rules from CHANNEL
help: use rules CHANNEL
help: use CHANNEL
help: it will use the rules from the specified channel.
help: you need to be part of that channel to be able to use the rules.
help:
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/slack/smart-bot/commands/general/use_rules.rb', line 10 def use_rules(dest, channel, user, dchannel) save_stats(__method__) get_bots_created() if config[:allow_access].key?(__method__) and !config[:allow_access][__method__].include?(user.name) and !config[:allow_access][__method__].include?(user.id) and (!user.key?(:enterprise_user) or ( user.key?(:enterprise_user) and !config[:allow_access][__method__].include?(user[:enterprise_user].id))) respond "You don't have access to use this command, please contact an Admin to be able to use it: <@#{config.admins.join(">, <@")}>" else #todo: add pagination for case more than 1000 channels on the workspace channels = client.web_client.conversations_list( types: "private_channel,public_channel", limit: "1000", exclude_archived: "true", ).channels channel_found = channels.detect { |c| c.name == channel } members = client.web_client.conversations_members(channel: @channels_id[channel]).members unless channel_found.nil? if channel_found.nil? respond "The channel you are trying to use doesn't exist", dest elsif channel_found.name == config.master_channel respond "You cannot use the rules from Master Channel on any other channel.", dest elsif !@bots_created.key?(@channels_id[channel]) respond "There is no bot running on that channel.", dest elsif @bots_created.key?(@channels_id[channel]) and @bots_created[@channels_id[channel]][:status] != :on respond "The bot in that channel is not :on", dest else if user.id == channel_found.creator or members.include?(user.id) @rules_imported[user.id] = {} unless @rules_imported.key?(user.id) if dest[0] == "C" or dest[0] == "G" #todo: take in consideration bots that are not master @rules_imported[user.id][dchannel] = channel_found.id else @rules_imported[user.id][user.id] = channel_found.id end update_rules_imported() respond "I'm using now the rules from <##{channel_found.id}>", dest def git_project() "" end def project_folder() "" end else respond "You need to join the channel <##{channel_found.id}> to be able to use the rules.", dest end end end end |