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/comm/unreact.rb,
lib/slack/smart-bot/utils/answer.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/comm/event_hello.rb,
lib/slack/smart-bot/utils/build_help.rb,
lib/slack/smart-bot/utils/save_stats.rb,
lib/slack/smart-bot/comm/get_user_info.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/utils/answer_delete.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/bot_stats.rb,
lib/slack/smart-bot/commands/general/use_rules.rb,
lib/slack/smart-bot/commands/general/whats_new.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_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,
lib/slack/smart-bot/commands/on_master/admin_master/set_maintenance.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, channel) ⇒ Object
helpadmin: ---------------------------------------------- helpadmin:
add routine NAME every NUMBER PERIOD COMMAND
helpadmin:add routine NAME every NUMBER PERIOD #CHANNEL 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 #CHANNEL COMMAND
helpadmin:add routine NAME on DAYWEEK at TIME COMMAND
helpadmin:add routine NAME on DAYWEEK at TIME #CHANNEL 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, global) ⇒ 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:add global sc for all NAME: COMMAND
help: It will add a shortcut that will execute the command we supply. - #answer(from = Thread.current[:user].name, dest = Thread.current[:dest]) ⇒ Object
- #answer_delete(from = Thread.current[:user].name, dest = Thread.current[:dest]) ⇒ Object
-
#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 help expanded
help:bot rules expanded
help:bot what can I do?
help: it will display this help. - #bot_rules(dest, help_command, typem, rules_file, user) ⇒ Object
-
#bot_stats(dest, from_user, typem, channel_id, from, to, user, st_command, exclude_masters, exclude_routines, exclude_command, monthly, all_data) ⇒ Object
help: ---------------------------------------------- help:
bot stats
helpmaster:bot stats USER_NAME
help:bot stats exclude masters
help:bot stats exclude routines
help:bot stats from YYYY/MM/DD
help:bot stats from YYYY/MM/DD to YYYY/MM/DD
help:bot stats CHANNEL
help:bot stats CHANNEL from YYYY/MM/DD
help:bot stats CHANNEL from YYYY/MM/DD to YYYY/MM/DD
help:bot stats command COMMAND
helpmaster:bot stats USER_NAME from YYYY/MM/DD to YYYY/MM/DD
helpmaster:bot stats CHANNEL USER_NAME from YYYY/MM/DD to YYYY/MM/DD
help:bot stats CHANNEL exclude masters from YYYY/MM/DD to YYYY/MM/DD
help:bot stats today
help:bot stats exclude COMMAND_ID
help:bot stats monthly
help:bot stats alldata
help: To see the bot stats helpmaster: You can use this command only if you are a Master admin user and if you are in a private conversation with the bot helpmaster: 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, expanded) ⇒ Object
-
#bye_bot(dest, from, display_name) ⇒ Object
help: ---------------------------------------------- help:
Bye Bot
help:Bye Smart
help:Bye NAME_OF_THE_BOT
help: Bot stops listening to you help: Also apart of Bye you can use Bæ, Good Bye, Adiós, Ciao, Bless, Bless Bless, Adeu 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: 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, global) ⇒ Object
help: ---------------------------------------------- help:
delete shortcut NAME
help:delete sc NAME
help:delete global sc NAME
help: It will delete the shortcut with the supplied name help: 'global' or 'generic' can only be used on Master channel. - #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
- #event_hello ⇒ 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, expanded) ⇒ 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: 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
- #get_user_info(user) ⇒ 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: 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: Also apart of Hello you can use Hallo, Hi, Hola, What's up, Hey, Hæ 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, routine) ⇒ Object
-
#react(emoji, ts = false) ⇒ Object
list of available emojis: https://www.webfx.com/tools/emoji-cheat-sheet/ react(:thumbsup) ts: can be true, false or a specific ts.
- #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:clean 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: 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: 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, data: {}) ⇒ 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", content: '') ⇒ 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_file(dest, 'the message', "", 'message to be sent', 'text/plain', "ruby", content: "the content to be sent when no file supplied") send_file(dest, 'the message', "myfile.rb", 'message to be sent', 'text/plain', "ruby", content: "the content to be sent when no file supplied").
-
#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.
-
#set_maintenance(from, status, message) ⇒ Object
helpmaster: ---------------------------------------------- helpmaster:
set maintenance on
helpmaster:set maintenance on MESSAGE
helpmaster:set maintenance off
helpmaster:turn maintenance on
helpmaster:turn maintenance on MESSAGE
helpmaster:turn maintenance off
helpmaster: The SmartBot will be on maintenance and responding with a generic message helpmaster: Only works if you are on Master channel and you are a master admin user helpmaster:. -
#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
-
#unreact(emoji, ts = false) ⇒ Object
list of available emojis: https://www.webfx.com/tools/emoji-cheat-sheet/ unreact(:thumbsup) ts: can be true, false or a specific ts.
- #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. -
#whats_new(user, dest, dchannel, from, display_name) ⇒ Object
help: ---------------------------------------------- help:
What's new
help: It will display the last user changes on Slack Smart Bot help:.
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 267 268 269 270 |
# 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 config[:silent] = false unless config.key?(:silent) 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) config[:on_maintenance] = false unless config.key?(:on_maintenance) config[:on_maintenance_message] = "Sorry I'm on maintenance so I cannot attend your request." unless config.key?(:on_maintenance_message) 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 == '') and !config.simulate 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}") @last_respond = Time.now 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 unless config.simulate and config.key?(:client) Slack.configure do |conf| conf.token = config[:token] end end restarts = 0 created = false while restarts < 200 and !created begin @logger.info "Connecting #{config_log.inspect}" if config.simulate and config.key?(:client) self.client = config.client else self.client = Slack::RealTime::Client.new(start_method: :rtm_connect) end 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() @shortcuts_global = Hash.new() @shortcuts_global[: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 if File.exist?("#{config.path}/shortcuts/shortcuts_global.rb") file_sc = IO.readlines("#{config.path}/shortcuts/shortcuts_global.rb").join unless file_sc.to_s() == "" @shortcuts_global = 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 #todo: take in consideration the case that the value supplied on config.masters and config.admins are the ids and not the user names @admin_users_id = [] @master_admin_users_id = [] config.admins.each do |au| user_info = get_user_info("@#{au}") @admin_users_id << user_info.user.id if config.masters.include?(au) @master_admin_users_id << user_info.user.id end sleep 1 end (config.masters-config.admins).each do |au| user_info = get_user_info("@#{au}") @master_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 pp stack if config.testing abort("The admin user specified on settings: #{config.admins.join(", ")}, doesn't exist on Slack. Execution aborted") end if config.simulate and config.key?(:client) event_hello() else client.on :hello do event_hello() end end @status = config.status_init @questions = Hash.new() @answer = 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 else 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 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, channel) ⇒ Object
helpadmin: ----------------------------------------------
helpadmin: add routine NAME every NUMBER PERIOD COMMAND
helpadmin: add routine NAME every NUMBER PERIOD #CHANNEL 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 #CHANNEL COMMAND
helpadmin: add routine NAME on DAYWEEK at TIME COMMAND
helpadmin: add routine NAME on DAYWEEK at TIME #CHANNEL 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: DAYWEEK: Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday. And their plurals.
helpadmin: #CHANNEL: the destination channel where the results will be published. If not supplied then the bot channel by default or a DM if the command is run from a DM.
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 Example every 12 hours !Run customer tests
helpadmin: add routine example on Mondays at 05:00 !run customer tests
helpadmin: add routine example on Tuesdays at 09:00 #SREChannel !run db cleanup
helpadmin:
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 |
# File 'lib/slack/smart-bot/commands/on_bot/admin/add_routine.rb', line 33 def add_routine(dest, from, user, name, type, number_time, period, command_to_run, files, silent, channel) 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 != "every") && !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 = "" dayweek = '' 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 if type != 'at' dayweek = type.downcase days = ['sunday','monday','tuesday','wednesday','thursday','friday','saturday'] incr = days.index(dayweek) - Time.now.wday if incr < 0 incr = (7+incr)*24*60*60 else incr = incr * 24 * 60 * 60 end days = incr/(24*60*60) every_in_seconds = 7 * 24 * 60 * 60 # one week else days = 0 every_in_seconds = 24 * 60 * 60 # one day end at = number_time if next_run.strftime("%H:%M:%S") < number_time and days == 0 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) * days) # one or more days nt = number_time.split(":") next_run = Time.new(next_run.year, next_run.month, next_run.day, nt[0], nt[1], nt[2]) end 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 channel = dest if channel.to_s == '' @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, dayweek: dayweek, file_path: file_path, command: command_to_run.to_s.strip, silent: silent, next_run: next_run.to_s, dest: channel, 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, global) ⇒ 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: add global sc 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 'global' or 'generic' supplied and in Master channel then the shortcut will be available in all Bot channels.
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:
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 |
# File 'lib/slack/smart-bot/commands/on_bot/add_shortcut.rb', line 22 def add_shortcut(dest, user, typem, for_all, shortcut_name, command, command_to_run, global) 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 if global if !config.on_master_bot or typem != :on_master respond "It is only possible to add global shortcuts from Master channel" else @shortcuts_global[from] = Hash.new() unless @shortcuts_global.keys.include?(from) found_other = false if for_all.to_s != "" @shortcuts_global.each { |sck, scv| if sck != :all and sck != from and scv.key?(shortcut_name) found_other = true end } end if @shortcuts_global[:all].include?(shortcut_name) or @shortcuts_global[from].include?(shortcut_name) respond "Global shortcut name already in use. Please use another shortcut name." elsif found_other respond "You cannot create a global shortcut for all with the same name than other user is using." elsif !@shortcuts_global[from].include?(shortcut_name) #new shortcut @shortcuts_global[from][shortcut_name] = command_to_run @shortcuts_global[:all][shortcut_name] = command_to_run if for_all.to_s != "" update_shortcuts_file() respond "global shortcut added" else respond "Not possible to add the global shortcut" #todo: check if this is ever gonna be the case end end 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 if answer.empty? ask("The shortcut already exists, are you sure you want to overwrite it?", command, from, dest) else case answer 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 answer_delete(from) when /^no/i respond "ok, I won't add it", dest answer_delete(from) else ask "I don't understand, yes or no?", command, from, dest end end end end end end end |
#answer(from = Thread.current[:user].name, dest = Thread.current[:dest]) ⇒ Object
2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
# File 'lib/slack/smart-bot/utils/answer.rb', line 2 def answer(from = Thread.current[:user].name, dest = Thread.current[:dest]) if @answer.key?(from) if Thread.current[:on_thread] dest = Thread.current[:thread_ts] end if @answer[from].key?(dest) return @answer[from][dest] else return '' end else return '' end end |
#answer_delete(from = Thread.current[:user].name, dest = Thread.current[:dest]) ⇒ Object
2 3 4 5 6 7 8 9 10 11 12 |
# File 'lib/slack/smart-bot/utils/answer_delete.rb', line 2 def answer_delete(from = Thread.current[:user].name, dest = Thread.current[:dest]) if @answer.key?(from) if Thread.current[:on_thread] dest = Thread.current[:thread_ts] end if @answer[from].key?(dest) @answer[from].delete(dest) end @questions.delete(from) # to be backwards compatible #todo: remove when 2.0 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 55 56 57 58 59 60 61 |
# 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]}|#{config[:nick]}|#{}~~~" } 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]}|#{config[:nick]}|#{}" } 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]}|#{config[:nick]}|#{}~~~" } 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]}|#{config[:nick]}|#{}" } end elsif dest[0] == "D" #private message send_msg_user(dest, ) end if Thread.current[:on_thread] qdest = Thread.current[:thread_ts] else qdest = dest end @answer[to] = {} unless @answer.key?(to) @answer[to][qdest] = context @questions[to] = context # to be backwards compatible #todo remove it when 2.0 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 help expanded
help: bot rules expanded
help: bot what can I do?
help: it will display this help. For a more detailed help call bot help expanded
or bot rules expanded
.
help: if COMMAND supplied just help for that command
help: you can use the option 'expanded' or the alias 'extended'
help: bot rules
will show only the specific rules for this channel.
help:
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 |
# File 'lib/slack/smart-bot/commands/general/bot_help.rb', line 16 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 = "" if help_command.to_s != '' help_command = '' if help_command.to_s.match?(/^\s*expanded\s*$/i) or help_command.to_s.match?(/^\s*extended\s*$/i) = true = '' else = false = "*If you want to see the expanded version of `bot help` or `bot rules`, please call `bot help expanded` or `bot rules expanded`*\n" += "*Also to get specific expanded help for a specific command or rule call `bot help COMMAND`*\n" end = 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 respond unless 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 44 45 46 47 48 49 50 51 52 53 54 55 56 |
# 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. if help_command.to_s != '' help_command = '' if help_command.to_s.match?(/^\s*expanded\s*$/i) or help_command.to_s.match?(/^\s*extended\s*$/i) = true else = false end 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 unless = "*If you want to see the expanded version of `bot rules`, please call `bot rules expanded`*\n" += "*Also to get specific expanded help for a specific command or rule call `bot rules COMMAND`*\n" respond end end end end |
#bot_stats(dest, from_user, typem, channel_id, from, to, user, st_command, exclude_masters, exclude_routines, exclude_command, monthly, all_data) ⇒ Object
help: ----------------------------------------------
help: bot stats
helpmaster: bot stats USER_NAME
help: bot stats exclude masters
help: bot stats exclude routines
help: bot stats from YYYY/MM/DD
help: bot stats from YYYY/MM/DD to YYYY/MM/DD
help: bot stats CHANNEL
help: bot stats CHANNEL from YYYY/MM/DD
help: bot stats CHANNEL from YYYY/MM/DD to YYYY/MM/DD
help: bot stats command COMMAND
helpmaster: bot stats USER_NAME from YYYY/MM/DD to YYYY/MM/DD
helpmaster: bot stats CHANNEL USER_NAME from YYYY/MM/DD to YYYY/MM/DD
help: bot stats CHANNEL exclude masters from YYYY/MM/DD to YYYY/MM/DD
help: bot stats today
help: bot stats exclude COMMAND_ID
help: bot stats monthly
help: bot stats alldata
help: To see the bot stats
helpmaster: You can use this command only if you are a Master admin user and if you are in a private conversation with the bot
helpmaster: You need to set stats to true to generate the stats when running the bot instance.
help: If alldata option supplied then it will be attached files including all data and not only the top 10.
help: Examples:
help: bot stats #sales
helpmaster: bot stats @peter.wind
help: bot stats #sales from 2019/12/15 to 2019/12/31
help: bot stats #sales today
help: bot stats #sales from 2020-01-01 monthly
help: bot stats exclude routines masters from 2021/01/01 monthly
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 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 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 |
# File 'lib/slack/smart-bot/commands/general/bot_stats.rb', line 32 def bot_stats(dest, from_user, typem, channel_id, from, to, user, st_command, exclude_masters, exclude_routines, exclude_command, monthly, all_data) 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 (from_user.id != user and (config.masters.include?(from_user.name) or @master_admin_users_id.include?(from_user.id)) and (typem==:on_dm or dest[0]=='D')) on_dm_master = true #master admin user else on_dm_master = false end if on_dm_master or (from_user.id == user) # normal user can only see own stats 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 = [] rows_month = {} users_month = {} commands_month = {} users_id_name = {} users_name_id = {} count_users = {} count_channels_dest = {} # to translate global and enterprise users since sometimes was returning different names/ids if from[0..3]=='2020' # this was an issue only on that period 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| unless users_id_name.key?(row[:user_id]) users_id_name[row[:user_id]] = row[:user_name] end unless users_name_id.key?(row[:user_name]) users_name_id[row[:user_name]] = row[:user_id] end end end end end if user!='' user_info = get_user_info(user) if users_id_name.key?(user_info.user.id) user_name = users_id_name[user_info.user.id] else user_name = user_info.user.name end if users_name_id.key?(user_info.user.name) user_id = users_name_id[user_info.user.name] else user_id = user_info.user.id end end master_admins = config.masters.dup if users_id_name.size > 0 config.masters.each do |u| if users_id_name.key?(u) master_admins << users_id_name[u] elsif users_name_id.key?(u) master_admins << users_name_id[u] end end end 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 row[:dest_channel_id].to_s[0]=='D' row[:dest_channel] = 'DM' elsif row[:dest_channel].to_s == '' row[:dest_channel] = row[:dest_channel_id] end if users_name_id.size > 0 row[:user_name] = users_id_name[row[:user_id]] row[:user_id] = users_name_id[row[:user_name]] else users_id_name[row[:user_id]] ||= row[:user_name] end if !exclude_masters or (exclude_masters and !master_admins.include?(row[:user_name]) and !master_admins.include?(row[:user_id]) and !@master_admin_users_id.include?(row[:user_id])) if !exclude_routines or (exclude_routines and !row[:user_name].match?(/^routine\//) ) if exclude_command == '' or (exclude_command!='' and row[:command]!=exclude_command) if st_command == '' or (st_command != '' and row[:command] == st_command) if row[:bot_channel_id] == channel_id or channel_id == '' if row[:date] >= from and row[:date] <= to count_users[row[:user_id]] ||= 0 count_users[row[:user_id]] += 1 if user=='' or (user!='' and row[:user_name] == user_name) or (user!='' and row[:user_id] == user_id) rows << row.to_h count_channels_dest[row[:dest_channel]] ||= 0 count_channels_dest[row[:dest_channel]] += 1 if monthly rows_month[row[:date][0..6]] = 0 unless rows_month.key?(row[:date][0..6]) users_month[row[:date][0..6]] = [] unless users_month.key?(row[:date][0..6]) commands_month[row[:date][0..6]] = [] unless commands_month.key?(row[:date][0..6]) rows_month[row[:date][0..6]] += 1 users_month[row[:date][0..6]] << row[:user_id] commands_month[row[:date][0..6]] << row[:command] end end end end end end end end end end end total = rows.size if exclude_masters << 'Excluding master admins' end if exclude_routines << 'Excluding routines' end if exclude_command != '' << "Excluding command #{exclude_command}" end if st_command != '' << "Including only command #{st_command}" end if user!='' if user==from_user.id << "Bot stats for <@#{user}>" else << "Showing only user <@#{user}>" end 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 unless count_users.size == 0 or total == 0 or user == '' my_place = (count_users.sort_by(&:last).reverse.to_h.keys.index(user_id)+1) <<"\tYou are the *\# #{my_place}* of *#{count_users.size}* users" end if total > 0 if monthly if on_dm_master << '*Totals by month / commands / users (%new)*' else << '*Totals by month / commands*' end all_users = [] new_users = [] rows_month.each do |k,v| if all_users.empty? = '' else new_users = (users_month[k]-all_users).uniq = "(#{new_users.size*100/users_month[k].uniq.size}%)" end all_users += users_month[k] if on_dm_master << "\t#{k}: #{v} (#{(v.to_f*100/total).round(2)}%) / #{commands_month[k].uniq.size} / #{users_month[k].uniq.size} #{}" else << "\t#{k}: #{v} (#{(v.to_f*100/total).round(2)}%) / #{commands_month[k].uniq.size}" end end end if channel_id == '' << "*SmartBots*" 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 = [] count_channels_dest = count_channels_dest.sort_by(&:last).reverse.to_h if count_channels_dest.size > 10 << "*From Channel* - #{count_channels_dest.size} (Top 10)" else << "*From Channel* - #{count_channels_dest.size}" end count_channels_dest.keys[0..9].each do |ch| << "\t#{ch}: #{count_channels_dest[ch]} (#{(count_channels_dest[ch].to_f*100/total).round(2)}%)" end if count_channels_dest.size > 10 and all_data count_channels_dest.each do |ch, value| << "\t#{ch}: #{value} (#{(value.to_f*100/total).round(2)}%)" end end = [] if user=='' users = rows.user_id.uniq.sort if users.size > 10 << "*Users* - #{users.size} (Top 10)" else << "*Users* - #{users.size}" end count_user = {} users.each do |user| count = rows.count {|h| h.user_id==user} count_user[user] = count end i = 0 count_user.sort_by {|k,v| -v}.each do |user, count| i+=1 if i <= 10 << "\t#{users_id_name[user]}: #{count} (#{(count.to_f*100/total).round(2)}%)" end if users.size > 10 and all_data << "\t#{users_id_name[user]}: #{count} (#{(count.to_f*100/total).round(2)}%)" end end end = [] if st_command == '' commands = rows.command.uniq.sort count_command = {} commands.each do |command| count = rows.count {|h| h.command==command} count_command[command] = count end if commands.size > 10 << "*Commands* - #{commands.size} (Top 10)" else << "*Commands* - #{commands.size}" end i = 0 count_command.sort_by {|k,v| -v}.each do |command, count| i+=1 if i <= 10 << "\t#{command}: #{count} (#{(count.to_f*100/total).round(2)}%)" end if commands.size > 10 and all_data << "\t#{command}: #{count} (#{(count.to_f*100/total).round(2)}%)" end end 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 if on_dm_master << "*Last activity*: #{rows[-1].date} #{rows[-1].bot_channel} #{rows[-1].} #{rows[-1].user_name} #{rows[-1].command}" end if .size>0 send_file(dest, "", 'users.txt', "", 'text/plain', "text", content: .join("\n")) end if .size>0 send_file(dest, "", 'commands.txt', "", 'text/plain', "text", content: .join("\n")) end if .size>0 send_file(dest, "", 'channels_dest.txt', "", 'text/plain', "text", content: .join("\n")) end end end else <<"Only Master admin users on a private conversation with the bot can see this kind of 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 Gem::Version.new(version_remote) > Gem::Version.new(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, expanded) ⇒ 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 |
# File 'lib/slack/smart-bot/utils/build_help.rb', line 3 def build_help(path, ) = {normal: {}, admin: {}, master: {}} if Dir.exist?(path) files = Dir["#{path}/*"] elsif File.exist?(path) files = [path] else return end files.each do |t| if Dir.exist?(t) res = build_help(t, ) [:master][t.scan(/\/(\w+)$/).join.to_sym] = res[:master] [:admin][t.scan(/\/(\w+)$/).join.to_sym] = res[:admin] [:normal][t.scan(/\/(\w+)$/).join.to_sym] = res[:normal] else lines = IO.readlines(t) data = {master:{}, admin:{}, normal:{}} data.master = lines.join #normal user help data.admin = lines.reject {|l| l.match?(/^\s*#\s*help\s*master\s*:.+$/i)}.join #not master help data.normal = lines.reject {|l| l.match?(/^\s*#\s*help\s*(admin|master)\s*:.+$/i)}.join #not admin or master help if [:master][t.scan(/\/(\w+)\.rb$/).join.to_sym] = data.master.scan(/#\s*help\s*\w*:(.*)/i).join("\n") [:admin][t.scan(/\/(\w+)\.rb$/).join.to_sym] = data.admin.scan(/#\s*help\s*\w*:(.*)/i).join("\n") [:normal][t.scan(/\/(\w+)\.rb$/).join.to_sym] = data.normal.scan(/#\s*help\s*\w*:(.*)/i).join("\n") else data.keys.each do |key| res = data[key].scan(/#\s*help\s*\w*:(.*)/i).join("\n") resf = "" command_done = false explanation_done = false example_done = false res.split("\n").each do |line| if line.match?(/^\s*======+$/) command_done = true explanation_done = true example_done = true elsif line.match?(/^\s*\-\-\-\-+\s*$/i) resf += "\n#{line}" command_done = false explanation_done = false example_done = false elsif !command_done and line.match?(/^\s*`.+`\s*/i) resf += "\n#{line}" command_done = true elsif !explanation_done and line.match?(/^\s+[^`].+\s*/i) resf += "\n#{line}" explanation_done = true elsif !example_done and line.match?(/^\s*_.+_\s*/i) resf += "\n Example: #{line}" example_done = true end end resf += "\n\n" [key][t.scan(/\/(\w+)\.rb$/).join.to_sym] = resf end end 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: Bot stops listening to you
help: Also apart of Bye you can use Bæ, Good Bye, Adiós, Ciao, Bless, Bless Bless, Adeu
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 99 |
# 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 = get_channels() channel_found = channels.detect { |c| c.name == channel } members = get_channel_members(@channels_id[channel]) 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_id]}>", 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 general_rules_file = RULES_FOLDER + 'general_rules.rb' 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 general_rules_file = "/rules/general_rules.rb" end default_rules = (__FILE__).gsub(/slack\/smart-bot\/commands\/on_master\/create_bot\.rb$/, "slack-smart-bot_rules.rb") default_general_rules = (__FILE__).gsub(/slack\/smart-bot\/commands\/on_master\/create_bot\.rb$/, "slack-smart-bot_general_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) FileUtils.copy_file(default_general_rules, config.path + general_rules_file) unless File.exist?(config.path + general_rules_file) admin_users = Array.new() creator_info = get_user_info(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 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 |
# 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) data = { dest: @routines[@channel_id][name][:dest], typem: 'routine_file', user: {id: @routines[@channel_id][name][:creator_id], name: @routines[@channel_id][name][:creator]}, files: false, command: @routines[@channel_id][name][:file_path], routine: true } save_stats(name, data: data) 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/))) if @routines[@channel_id][name][:dest]!=@channel_id respond "routine from <##{@channel_id}> *`#{name}`*: #{@routines[@channel_id][name][:file_path]}", @routines[@channel_id][name][:dest] else respond "routine *`#{name}`*: #{@routines[@channel_id][name][:file_path]}", @routines[@channel_id][name][:dest] end 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] if @routines[@channel_id][name][:dest]!=@channel_id respond "routine from <##{@channel_id}> *`#{name}`*: #{@routines[@channel_id][name][:command]}", @routines[@channel_id][name][:dest] else respond "routine *`#{name}`*: #{@routines[@channel_id][name][:command]}", @routines[@channel_id][name][:dest] end end started = Time.now data = { channel: @channel_id, dest: @routines[@channel_id][name][:dest], user: @routines[@channel_id][name][:creator_id], text: @routines[@channel_id][name][:command], files: nil, routine: true } (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 @routines[@channel_id][name].key?(:dayweek) and @routines[@channel_id][name][:dayweek].to_s!='' day = @routines[@channel_id][name][:dayweek] days = ['sunday','monday','tuesday','wednesday','thursday','friday','saturday'] incr = days.index(day) - Time.now.wday if incr < 0 incr = (7+incr)*24*60*60 else incr = incr * 24 * 60 * 60 end days = incr/(24*60*60) weekly = true else days = 0 weekly = false end if started.strftime("%H:%M:%S") < @routines[@channel_id][name][:at] and days == 0 nt = @routines[@channel_id][name][:at].split(":") next_run = Time.new(started.year, started.month, started.day, nt[0], nt[1], nt[2]) else if days == 0 and started.strftime("%H:%M:%S") >= @routines[@channel_id][name][:at] if weekly days = 7 else days = 1 end end next_run = started + (days * 24 * 60 * 60) # one more day/week 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: Will delete the specified REPL
help: Only the creator of the REPL or an admin can delete REPLs
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 |
# File 'lib/slack/smart-bot/commands/on_bot/delete_repl.rb', line 9 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") File.delete("#{config.path}/repl/#{@channel_id}/#{session_name}.output") if File.exist?("#{config.path}/repl/#{@channel_id}/#{session_name}.output") File.delete("#{config.path}/repl/#{@channel_id}/#{session_name}.run") if File.exist?("#{config.path}/repl/#{@channel_id}/#{session_name}.run") 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, global) ⇒ Object
help: ----------------------------------------------
help: delete shortcut NAME
help: delete sc NAME
help: delete global sc NAME
help: It will delete the shortcut with the supplied name
help: 'global' or 'generic' can only be used on Master channel.
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 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 |
# File 'lib/slack/smart-bot/commands/on_bot/delete_shortcut.rb', line 10 def delete_shortcut(dest, user, shortcut, typem, command, global) 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 global if !config.on_master_bot or typem != :on_master respond "It is only possible to delete global shortcuts from Master channel" else if !config.admins.include?(from) and @shortcuts_global[:all].include?(shortcut) and (!@shortcuts_global.key?(from) or !@shortcuts_global[from].include?(shortcut)) respond "Only the creator of the shortcut or an admin user can delete it" elsif (@shortcuts_global.key?(from) and @shortcuts_global[from].keys.include?(shortcut)) or (config.admins.include?(from) and @shortcuts_global[:all].include?(shortcut)) respond "global shortcut deleted!", dest if @shortcuts_global.key?(from) and @shortcuts_global[from].key?(shortcut) respond("#{shortcut}: #{@shortcuts_global[from][shortcut]}", dest) elsif @shortcuts_global.key?(:all) and @shortcuts_global[:all].key?(shortcut) respond("#{shortcut}: #{@shortcuts_global[:all][shortcut]}", dest) end @shortcuts_global[from].delete(shortcut) if @shortcuts_global.key?(from) and @shortcuts_global[from].key?(shortcut) @shortcuts_global[:all].delete(shortcut) if @shortcuts_global.key?(:all) and @shortcuts_global[:all].key?(shortcut) update_shortcuts_file() else respond 'shortcut not found' end end else if !config.admins.include?(from) and @shortcuts[:all].include?(shortcut) and (!@shortcuts.key?(from) or !@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 if answer.empty? ask("are you sure you want to delete it?", command, from, dest) else case answer when /^(yes|yep)/i answer_delete(from) respond "shortcut deleted!", dest if @shortcuts.key?(from) and @shortcuts[from].key?(shortcut) respond("#{shortcut}: #{@shortcuts[from][shortcut]}", dest) elsif @shortcuts.key?(:all) and @shortcuts[:all].key?(shortcut) respond("#{shortcut}: #{@shortcuts[:all][shortcut]}", dest) end @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 answer_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 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, true) 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 |
#event_hello ⇒ 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 |
# File 'lib/slack/smart-bot/comm/event_hello.rb', line 2 def event_hello() unless config.simulate 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 end @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 Gem::Version.new(version_remote) > Gem::Version.new(VERSION) = ". There is a new available version: #{version_remote}." end if (!config[:silent] or ENV['BOT_SILENT'].to_s == 'false') and !config.simulate ENV['BOT_SILENT'] = 'true' if config[:silent] == 'true' and ENV['BOT_SILENT'].to_s != 'true' 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 |
#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 if answer.empty? ask("are you sure?", command, from, dest) else case answer 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 answer_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 |
# 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 = get_channels() channel_found = channels.detect { |c| c.name == channel } get_channels_name_and_id() members = get_channel_members(@channels_id[channel]) 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_id]}>", 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 `!` or `^` or `!!` 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 |
# File 'lib/slack/smart-bot/utils/get_channels_name_and_id.rb', line 3 def get_channels_name_and_id channels = get_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, expanded) ⇒ 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 |
# File 'lib/slack/smart-bot/utils/get_help.rb', line 2 def get_help(rules_file, dest, from, only_rules, ) order = { general: [:whats_new, :hi_bot, :bye_bot, :bot_help, :bot_status, :use_rules, :stop_using_rules, :bot_stats], 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] } if config.masters.include?(from) user_type = :master # master admin elsif config.admins.include?(from) user_type = :admin else user_type = :normal #normal 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_expanded ||= build_help("#{__dir__}/../commands", true) @help_messages_not_expanded ||= build_help("#{__dir__}/../commands", false) if only_rules help = {} elsif help = @help_messages_expanded.deep_copy[user_type] else help = @help_messages_not_expanded.deep_copy[user_type] end if rules_file != "" help[:rules_file] = build_help(config.path+rules_file, )[user_type].values.join("\n") + "\n" # to get all the help from other rules files added to the main rules file by using require or load. For example general_rules.rb res = IO.readlines(config.path+rules_file).join.scan(/$\s*(load|require)\s("|')(.+)("|')/) rules_help = [] txt = '' if res.size>0 res.each do |r| begin eval("txt = \"#{r[2]}\"") rules_help << txt if File.exist?(txt) rescue end end end rules_help.each do |rh| rhelp = build_help(rh, ) help[:rules_file] += rhelp[user_type].values.join("\n") + "\n" end end help = remove_hash_keys(help, :admin_master) unless user_type == :master help = remove_hash_keys(help, :admin) unless user_type == :admin or user_type == :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) and 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 and 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 or ! 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" unless txt.include?('*Master Admin commands*') 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 unless resf = '' help.rules_file.split(/^\s*\-+\s*$/).each do |rule| command_done = false explanation_done = false example_done = false if rule.match?(/These are specific commands for this/i) resf += rule resf += "-"*50 resf += "\n" elsif rule.match?(/To run a command on demand and add the respond on a thread/i) resf += rule resf += "-"*50 resf += "\n" else rule.split("\n").each do |line| if line.match?(/^\s*\-+\s*/i) resf += line elsif !command_done and line.match?(/^\s*`.+`\s*/i) resf += "\n#{line}" command_done = true elsif !explanation_done and line.match?(/^\s+[^`].+\s*/i) resf += "\n#{line}" explanation_done = true elsif !example_done and line.match?(/^\s*_.+_\s*/i) resf += "\n Example: #{line}" example_done = true end end resf += "\n\n" end end unless resf.match?(/These are specific commands for this bot on this Channel/i) if resf.match?(/\A\s*[=\-]+$/) pre = '' post = '' else pre = ('='*50) + "\n" post = ('-'*50) + "\n" end resf = "#{pre}*These are specific commands for this bot on this Channel:*\n#{post}" + resf end help.rules_file = resf 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: Will get the Ruby commands sent on that SESSION_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 |
# File 'lib/slack/smart-bot/commands/on_bot/get_repl.rb', line 8 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}.run") if @repls.key?(session_name) and (@repls[session_name][:type] == :private or @repls[session_name][:type] == :private_clean) 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 content = "require 'nice_http'\n" if @repls.key?(session_name) @repls[session_name][:accessed] = Time.now.to_s @repls[session_name][:gets] += 1 update_repls() end if !@repls.key?(session_name) or (File.exist?("#{project_folder}/.smart-bot-repl") and @repls[session_name][:type] != :private_clean and @repls[session_name][:type] != :public_clean) content += File.read("#{project_folder}/.smart-bot-repl") content += "\n" end content += File.read("#{config.path}/repl/#{@channel_id}/#{session_name}.run").gsub(/^(quit|exit|bye)$/i,'') #todo: remove this gsub it will never contain it 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 |
#get_user_info(user) ⇒ Object
3 4 5 6 7 8 9 10 11 12 13 14 15 |
# File 'lib/slack/smart-bot/comm/get_user_info.rb', line 3 def get_user_info(user) if user.to_s.length>0 if config.simulate and config.key?(:client) if user[0]=='@' #name client.web_client.users_info.select{|k, v| v[:user][:name] == user[1..-1]}.values[-1] else #id client.web_client.users_info[user.to_sym] end else client.web_client.users_info(user: user) 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: 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: Also apart of Hello you can use Hallo, Hi, Hola, What's up, Hey, Hæ
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
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/listen.rb', line 44 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 42 |
# 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+)\|(\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 user_name = [2].strip command = [3].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, user_name: user_name}, 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, user_name: user_name}, false) end end else ({channel: channel, user: user, text: command, user_name: user_name}) 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 = get_channels(bot_is_in: true) 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 23 |
# 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 update_bots_file() 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 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 |
# File 'lib/slack/smart-bot/process.rb', line 2 def process(user, command, dest, dchannel, rules_file, typem, files, ts) from = user.name if config.simulate display_name = user.profile.display_name else 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 end 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 if (on_demand or (@listening.key?(from) and (@listening[from].key?(dest) or @listening[from].key?(Thread.current[:thread_ts])) )) and config.on_maintenance and !command.match?(/\A(set|turn)\s+maintenance\s+off\s*\z/) respond config., dest processed = true end if !config.on_maintenance or (config.on_maintenance and command.match?(/\A(set|turn)\s+maintenance\s+off\s*\z/)) #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*what's\s+new\s*$/i whats_new(user, dest, dchannel, from, display_name) when /^\s*(Bye|Bæ|Good\s+Bye|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\s+using\s+rules\s+(from\s+)<#\w+\|(.+)>/i, /^stop\s+using\s+rules\s+(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\s+using\s+rules\s+(on\s+)<#\w+\|(.+)>/i, /^stop\s+using\s+rules\s+(on\s+)(.+)/i channel = $2 stop_using_rules_on(dest, user, from, channel, typem) when /^\s*exit\s+bot\s*$/i, /^quit\s+bot\s*$/i, /^close\s+bot\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\s+status/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\s+bot\s+on\s+<#C\w+\|(.+)>\s*$/i, /^kill\s+bot\s+on\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<#(C\w+)\|.+>\s*)?(\s.+)?\s*$/i, /^\s*(add|create)\s+(silent\s+)?routine\s+(\w+)\s+on\s+(monday|tuesday|wednesday|thursday|friday|saturday|sunday)s?\s+at\s+(\d+:\d+:?\d+?)\s*()(\s<#(C\w+)\|.+>\s*)?(\s.+)?\s*$/i, /^\s*(add|create)\s+(silent\s+)?routine\s+(\w+)\s+(at)\s+(\d+:\d+:?\d+?)\s*()(\s<#(C\w+)\|.+>\s*)?(\s.+)?\s*$/i silent = $2.to_s!='' name = $3.downcase type = $4 number_time = $5 period = $6 channel = $8 command_to_run = $9 add_routine(dest, from, user, name, type, number_time, period, command_to_run, files, silent, channel) 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(' ') all_data = all_opts.include?('alldata') 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 st_command = opts.scan(/\s+command\s+(\w+)/i).join.downcase st_command = opts.scan(/^command\s+(\w+)/i).join.downcase if st_command == '' exclude_masters = all_opts.include?('exclude') && all_opts.include?('masters') exclude_routines = all_opts.include?('exclude') && all_opts.include?('routines') if exclude_masters opts.gsub!(/\s+masters$/,'') opts.gsub!(/\s+masters\s+/,'') end if exclude_routines opts.gsub!(/\s+routines$/,'') opts.gsub!(/\s+routines\s+/,'') end monthly = false if all_opts.include?('today') st_from = st_to = "#{Time.now.strftime("%Y-%m-%d")}" elsif all_opts.include?('monthly') monthly = true end exclude_command = opts.scan(/exclude\s+([^\s]+)/i).join unless @master_admin_users_id.include?(user.id) st_user = user.id end if (typem == :on_master or typem == :on_bot) and dest[0]!='D' #routine bot stats to be published on DM st_channel = dchannel end bot_stats(dest, user, typem, st_channel, st_from, st_to, st_user, st_command, exclude_masters, exclude_routines, exclude_command, monthly, all_data) when /\A(set|turn)\s+maintenance\s+(on|off)\s*()\z/im, /\A(set|turn)\s+maintenance\s+(on)\s*(.+)\s*\z/im status = $2.downcase = $3.to_s set_maintenance(from, status, ) else processed = false end else processed = false end # only when :on and (listening or on demand or direct message) if @status == :on and (!answer.empty? 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+)?(global\s+|generic\s+)?shortcut\s+(for\sall)?\s*([^:]+)\s*:\s*(.+)/i, /^(add\s+)(global\s+|generic\s+)?sc\s+(for\sall)?\s*([^:]+)\s*:\s*(.+)/i for_all = $3 shortcut_name = $4.to_s.downcase command_to_run = $5 global = $2.to_s != '' add_shortcut(dest, user, typem, for_all, shortcut_name, command, command_to_run, global) when /^\s*(delete|remove)\s+(global\s+|generic\s+)?shortcut\s+(.+)/i, /^(delete|remove)\s+(global\s+|generic\s+)?sc\s+(.+)/i shortcut = $3.to_s.downcase global = $2.to_s != '' delete_shortcut(dest, user, shortcut, typem, command, global) when /^\s*see\s+shortcuts/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+|clean\s+|clean\s+private\s+|private\s+clean\s+)?(repl|irb|live)\s*()()()$/i, /^\s*(private\s+|clean\s+|clean\s+private\s+|private\s+clean\s+)?(repl|irb|live)\s+([\w\-]+)()()\s*$/i, /^\s*(private\s+|clean\s+|clean\s+private\s+|private\s+clean\s+)?(repl|irb|live)\s+([\w\-]+)\s*:\s+"([^"]+)"()\s*$/i, /^\s*(private\s+|clean\s+|clean\s+private\s+|private\s+clean\s+)?(repl|irb|live)\s+([\w\-]+)\s*:\s+"([^"]+)"\s+(.+)\s*$/i, /^\s*(private\s+|clean\s+|clean\s+private\s+|private\s+clean\s+)?(repl|irb|live)\s+([\w\-]+)()\s+(.+)\s*$/i, /^\s*(private\s+|clean\s+|clean\s+private\s+|private\s+clean\s+)?(repl|irb|live)()\s+()(.+)\s*$/i opts_type = $1.to_s.downcase.split(' ') opts_type.include?('private') ? type = :private : type = :public type = "#{type}_clean".to_sym if opts_type.include?('clean') 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 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 end return processed end |
#process_first(user, text, dest, dchannel, typem, files, ts, thread_ts, routine) ⇒ 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 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 |
# File 'lib/slack/smart-bot/process_first.rb', line 2 def process_first(user, text, dest, dchannel, typem, files, ts, thread_ts, routine) 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]) elsif @shortcuts_global.key?(nick) and @shortcuts_global[nick].keys.include?(sc) command.gsub!("$#{sc}", @shortcuts_global[nick][sc]) elsif @shortcuts_global.key?(:all) and @shortcuts_global[:all].keys.include?(sc) command.gsub!("$#{sc}", @shortcuts_global[: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]) elsif @shortcuts_global.key?(nick) and @shortcuts_global[nick].keys.include?(sc) command.gsub!("$#{sc}", @shortcuts_global[nick][sc]) elsif @shortcuts_global.key?(:all) and @shortcuts_global[:all].keys.include?(sc) command.gsub!("$#{sc}", @shortcuts_global[: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)) or (@shortcuts_global.keys.include?(:all) and @shortcuts_global[:all].keys.include?(command)) or (@shortcuts_global.keys.include?(nick) and @shortcuts_global[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 elsif @shortcuts_global.keys.include?(nick) and @shortcuts_global[nick].keys.include?(command) text = @shortcuts_global[nick][command].dup elsif @shortcuts_global.keys.include?(:all) and @shortcuts_global[:all].keys.include?(command) text = @shortcuts_global[: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 Thread.current[:routine] = routine 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 unless config.on_maintenance and processed if @status == :on and (!answer.empty? 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 end rescue Exception => stack @logger.fatal stack end end rescue => e @logger.error "exception: #{e.inspect}" end end |
#react(emoji, ts = false) ⇒ Object
list of available emojis: https://www.webfx.com/tools/emoji-cheat-sheet/ react(:thumbsup) ts: can be true, false or a specific ts
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
# File 'lib/slack/smart-bot/comm/react.rb', line 5 def react(emoji, ts=false) if ts.is_a?(TrueClass) or ts.is_a?(FalseClass) parent = ts ts = nil else parent = false end if ts.nil? if parent or Thread.current[:ts].to_s == '' ts = Thread.current[:thread_ts] else ts = Thread.current[:ts] end end if ts.nil? @logger.warn 'react method no ts supplied' else begin client.web_client.reactions_add(channel: Thread.current[:dest], name: emoji, timestamp: ts) unless config.simulate rescue Exception => stack @logger.warn stack end 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: clean 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: 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: If 'clean' specified the repl won't pre execute the code written on the .smart-bot-repl file
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:
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 |
# File 'lib/slack/smart-bot/commands/on_bot/repl.rb', line 33 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 react :running if Thread.current[:ts].to_s == '' @ts_react = Thread.current[:thread_ts] else @ts_react = Thread.current[:ts] 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`. Use `p` to print a message raw, exacly like it is returned. 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+") File.write("#{config.path}/repl/#{@channel_id}/#{@repl_sessions[from][:name]}.run", "", mode: "a+") if type != :private_clean and type != :public_clean pre_execute = ' if File.exist?(\"./.smart-bot-repl\") begin eval(File.read(\"./.smart-bot-repl\"), bindme' + serialt + ') rescue Exception => resp_repl end end ' else pre_execute = '' end process_to_run = ' ruby -e "' + env_vars.join("\n") + ' require \"amazing_print\" bindme' + serialt + ' = binding eval(\"require \'nice_http\'\" , bindme' + serialt + ') def ls(obj) (obj.methods - Object.methods) end file_input_repl = File.open(\"' + File.(config.path) + '/repl/' + @channel_id + '/' + session_name + '.input\", \"r\") ' + pre_execute + ' while true do sleep 0.2 code_to_run_repl = file_input_repl.read if code_to_run_repl.to_s!=\"\" add_to_run_repl = true 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+(.+)/) add_to_run_repl = false end error = false begin resp_repl = eval(code_to_run_repl.gsub(/^\s*(puts|print|p|pp)\s/, \"\"), bindme' + serialt + ') rescue Exception => resp_repl error = true end if resp_repl.to_s != \"\" if code_to_run_repl.match?(/^\s*p\s+/i) open(\"' + File.(config.path) + '/repl/' + @channel_id + '/' + session_name + '.output\", \"a+\") {|f| f.puts \"\`\`\`\n#{resp_repl.inspect}\n\`\`\`\" } else open(\"' + File.(config.path) + '/repl/' + @channel_id + '/' + session_name + '.output\", \"a+\") {|f| f.puts \"\`\`\`\n#{resp_repl.ai}\n\`\`\`\" } end unless error or !add_to_run_repl open(\"' + File.(config.path) + '/repl/' + @channel_id + '/' + session_name + '.run\", \"a+\") {|f| f.puts code_to_run_repl } end 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") @repl_sessions[from][:pid] = wait_thr.pid 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 unreact :running, @ts_react pids = `pgrep -P #{@repl_sessions[from][:pid]}`.split("\n").map(&:to_i) #todo: it needs to be adapted for Windows pids.each do |pid| begin Process.kill("KILL", pid) rescue end end @repl_sessions.delete(from) break end sleep 0.2 resp_repl = file_output_repl.read if resp_repl.to_s!='' if resp_repl.to_s.lines.count < 60 and resp_repl.to_s.size < 3500 respond resp_repl, dest else resp_repl.gsub!(/^\s*```/,'') resp_repl.gsub!(/```\s*$/,'') send_file(dest, "", 'response.rb', "", 'text/plain', "ruby", content: resp_repl) end 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 since 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/) or code.include?("Dir.") or code.match?(/=\s*File/) or code.match?(/=\s*Dir/) or code.match?(/<\s*File/) or code.match?(/<\s*Dir/) or code.match?(/\w+:\s*File/) or code.match?(/\w+:\s*Dir/) 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 unreact :running, @ts_react pids = `pgrep -P #{@repl_sessions[from][:pid]}`.split("\n").map(&:to_i) #todo: it needs to be adapted for Windows pids.each do |pid| begin Process.kill("KILL", pid) rescue end end @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 58 59 60 61 62 |
# 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 !config.simulate #https://api.slack.com/docs/rate-limits msg.to_s.size > 500 ? wait = 0.5 : wait = 0.1 sleep wait if Time.now <= (@last_respond+wait) end if dest.nil? if config[:simulate] open("#{config.path}/buffer_complete.log", "a") { |f| f.puts "|#{@channel_id}|#{config[:nick_id]}|#{config[:nick]}|#{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]}|#{config[:nick]}|#{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]}|#{config[:nick]}|#{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]}|#{config[:nick]}|#{msg}" } end elsif dest[0] == "D" or dest[0] == "U" or dest[0] == "W" # Direct message send_msg_user(dest, msg) elsif dest[0] == "@" begin user_info = get_user_info(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 @last_respond = Time.now 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 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 |
# 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/) or code.include?("Dir.") or code.match?(/=\s*IO/) or code.match?(/=\s*File/) or code.match?(/=\s*Dir/) or code.match?(/<\s*File/) or code.match?(/<\s*Dir/) or code.match?(/\w+:\s*File/) or code.match?(/\w+:\s*Dir/) react :running 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 > 200 begin code.gsub!(/^\W*$/, "") #to remove special chars from slack when copy/pasting code.gsub!('$','\$') #to take $ as literal, fex: puts '$lolo' => puts '\$lolo' 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 stdin, stdout, stderr, wait_thr = Open3.popen3(ruby) timeout = timeoutt = 20 procstart = Time.now while (wait_thr.status == 'run' or wait_thr.status == 'sleep') and timeout > 0 timeout -= 0.1 sleep 0.1 end if timeout > 0 stdout = stdout.read stderr = stderr.read 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 else respond "The process didn't finish in #{timeoutt} secs so it was aborted. Timeout!" pids = `pgrep -P #{wait_thr.pid}`.split("\n").map(&:to_i) #todo: it needs to be adapted for Windows pids.each do |pid| begin Process.kill("KILL", pid) rescue end end end rescue Exception => exc respond exc, dest end unreact :running 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: 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:
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 |
# File 'lib/slack/smart-bot/commands/on_bot/run_repl.rb', line 13 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}.run") if @repls.key?(session_name) and (@repls[session_name][:type] == :private or @repls[session_name][:type] == :private_clean) 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") and @repls[session_name][:type] != :private_clean and @repls[session_name][:type] != :public_clean content += File.read("#{project_folder}/.smart-bot-repl") content += "\n" end content += File.read("#{config.path}/repl/#{@channel_id}/#{session_name}.run").gsub(/^(quit|exit|bye)$/i,'') #todo: remove this gsub, it will never contain it 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 ./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 if stdout.to_s.lines.count < 60 and stdout.to_s.size < 3500 respond "*#{session_name}*: #{stdout}" else send_file(dest, "", 'response.rb', "", 'text/plain', "ruby", content: stdout) end end else if (stdout.to_s+stderr.to_s).lines.count < 60 respond "*#{session_name}*: #{stdout} #{stderr}" else send_file(dest, "", 'response.rb', "", 'text/plain', "ruby", content: (stdout.to_s+stderr.to_s)) end 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, data: {}) ⇒ 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 |
# File 'lib/slack/smart-bot/utils/save_stats.rb', line 3 def save_stats(method, data: {}) 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 if data.empty? data = { dest: Thread.current[:dest], typem: Thread.current[:typem], user: Thread.current[:user], files: Thread.current[:files?], command: Thread.current[:command], routine: Thread.current[:routine] } end if method.to_s == 'ruby_code' and data.files command_txt = 'ruby' else command_txt = data.command end if data.routine user_name = "routine/#{data.user.name}" user_id = "routine/#{data.user.id}" else user_name = data.user.name user_id = data.user.id end CSV.open("#{config.stats_path}.#{Time.now.strftime("%Y-%m")}.log", "a+") do |csv| csv << [Time.now, config.channel, @channel_id, @channels_name[data.dest], data.dest, data.typem, user_name, user_id, command_txt, method, data.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 repl.type == :public_clean) 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_name} / 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 61 62 63 64 65 66 67 |
# 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 = [] if v[:dest][0] == 'D' extram = " (*DM to #{v[:creator]}*)" elsif v[:dest] != ch extram = " (*publish on <##{v[:dest]}>*)" else extram = '' end msg << "*`#{k}`*#{extram}" msg << "\tCreator: #{v[:creator]}" msg << "\tStatus: #{v[:status]}" msg << "\tEvery: #{v[:every]}" unless v[:every] == "" msg << "\tAt: #{v[:at]}" unless v[:at] == "" msg << "\tOn: #{v[:dayweek]}" unless !v.key?(:dayweek) or v[:dayweek].to_s == "" 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 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
# 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 or @shortcuts_global[:all].keys.size > 0 msg = "*Available shortcuts for all:*\n" if @shortcuts[:all].keys.size > 0 @shortcuts[:all].each { |name, value| msg += " _#{name}: #{value}_\n" } end if @shortcuts_global[:all].keys.size > 0 @shortcuts_global[:all].each { |name, value| msg += " _#{name} (global): #{value}_\n" } end respond msg, dest end msg2 = '' 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 msg2 = "*Available shortcuts for #{from}:*\n" new_hash.each { |name, value| msg2 += " _#{name}: #{value}_\n" } end end if @shortcuts_global.keys.include?(from) and @shortcuts_global[from].keys.size > 0 new_hash = @shortcuts_global[from].dup @shortcuts_global[:all].keys.each { |k| new_hash.delete(k) } if new_hash.keys.size > 0 msg2 = "*Available shortcuts for #{from}:*\n" if msg2 == '' new_hash.each { |name, value| msg2 += " _#{name} (global): #{value}_\n" } end end respond msg2 unless msg2 == '' respond "No shortcuts found" if (msg + msg2) == "" end end end |
#send_file(to, msg, file, title, format, type = "text", content: '') ⇒ 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_file(dest, 'the message', "", 'message to be sent', 'text/plain', "ruby", content: "the content to be sent when no file supplied") send_file(dest, 'the message', "myfile.rb", 'message to be sent', 'text/plain', "ruby", content: "the content to be sent when no file supplied")
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 |
# File 'lib/slack/smart-bot/comm/send_file.rb', line 8 def send_file(to, msg, file, title, format, type = "text", content: '') unless config[:simulate] file = 'myfile' if file.to_s == '' and content!='' if to[0] == "U" or to[0] == "W" #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 if content.to_s == '' 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 ) else client.web_client.files_upload( channels: channel, as_user: true, content: content, title: title, filename: file, filetype: type, initial_comment: msg, thread_ts: ts ) end 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]}|#{config[:nick]}|#{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]}|#{config[:nick]}|#{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]}|#{config[:nick]}|#{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]}|#{config[:nick]}|#{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]}|#{config[:nick]}|#{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]}|#{config[:nick]}|#{msg}" } end end end end |
#set_maintenance(from, status, message) ⇒ Object
helpmaster: ----------------------------------------------
helpmaster: set maintenance on
helpmaster: set maintenance on MESSAGE
helpmaster: set maintenance off
helpmaster: turn maintenance on
helpmaster: turn maintenance on MESSAGE
helpmaster: turn maintenance off
helpmaster: The SmartBot will be on maintenance and responding with a generic message
helpmaster: Only works if you are on Master channel and you are a master admin user
helpmaster:
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_master/admin_master/set_maintenance.rb', line 12 def set_maintenance(from, status, ) save_stats(__method__) if config.on_master_bot if config.admins.include?(from) #admin user if == '' config. = "Sorry I'm on maintenance so I cannot attend your request." else config. = end if status == 'on' config.on_maintenance = true respond "From now on I'll be on maintenance status so I won't be responding accordingly." else config.on_maintenance = false respond "From now on I won't be on maintenance. Everything is back to normal!" end file = File.open("#{config.path}/config_tmp.status", "w") file.write config.inspect file.close else respond 'Only master admins on master channel can use this command.' end else respond 'Only master admins on master channel can use this command.' 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 22 |
# 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 update_bots_file() 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 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 |
# 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 if remove_blocks and !data.blocks.nil? and data.blocks.size > 0 data_text = '' 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' or e.type == 'rich_text_preformatted' if e.elements.size > 0 and (e.elements.type.uniq - ['link', 'text', 'user', 'channel']) == [] data_text += '```' if e.type == 'rich_text_preformatted' e.elements.each do |el| if el.type == 'text' data_text += el.text elsif el.type == 'user' data_text += "<@#{el.user_id}>" elsif el.type == 'channel' tch = data.text.scan(/(<##{el.channel_id}\|[^\>]+>)/).join data_text += tch else data_text += el.url end end data_text += '```' if e.type == 'rich_text_preformatted' end end end end end end data.text = data_text unless data_text == '' end data.text = CGI.unescapeHTML(data.text) data.text.gsub!("\u00A0", " ") #to change (asc char 160) into blank space end data.text.gsub!('‘', "'") data.text.gsub!('’', "'") data.text.gsub!('“', '"') data.text.gsub!('”', '"') rescue Exception => exc @logger.warn "Impossible to unescape or clean format for data.text:#{data.text}" @logger.warn exc.inspect end data.routine = false unless data.key?(:routine) if config[:testing] and config.on_master_bot open("#{config.path}/buffer.log", "a") { |f| f.puts "|#{data.channel}|#{data.user}|#{data.user_name}|#{data.text}" } end if data.key?(:dest) and data.dest.to_s!='' # for run routines and publish on different channels dest = data.dest elsif 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?(/\A\s*\z/) #if data.text.match(/^\s*<@#{config[:nick_id]}>\s+(on\s+)?<#(\w+)\|([^>]+)>\s*:?\s*(.*)/im) if data.text.match(/^\s*<@#{config[:nick_id]}>\s+(on\s+)?((<#\w+\|[^>]+>\s*)+)\s*:?\s*(.*)/im) channels_rules = $2 #multiple channels @smart-bot on #channel1 #channel2 echo AAA data_text = $4 channel_rules_name = '' channel_rules = '' # to be treated only on the bots of the requested channels channels_rules.scan(/<#(\w+)\|([^>]+)>/).each do |tcid, tcname| if @channel_id == tcid data.text = data_text typem = :on_call channel_rules = tcid channel_rules_name = tcname break end end elsif data.channel == @master_bot_id if config.on_master_bot #only to be treated on master bot channel typem = :on_master end elsif @bots_created.key?(data.channel) if @channel_id == data.channel #only to be treated by the bot on the channel typem = :on_bot end elsif data.channel[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 data.channel[0] == "C" or data.channel[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[data.channel]) 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[data.channel]) typem = :on_extended break end end end if data.channel[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 = get_user_info(data.user) #user_info.user.id = data.user #todo: remove this line when slack issue with Wxxxx Uxxxx fixed data.user = user_info.user.id #todo: remove this line when slack issue with Wxxxx Uxxxx fixed if data.thread_ts.nil? qdest = dest else qdest = data.thread_ts end if !answer(user_info.user.name, qdest).empty? if data.text.match?(/^\s*(Bye|Bæ|Good\sBye|Adiós|Ciao|Bless|Bless\sBless|Adeu)\s(#{@salutations.join("|")})\s*$/i) answer_delete(user_info.user.name, qdest) command = data.text else command = answer(user_info.user.name, qdest) @answer[user_info.user.name][qdest] = data.text @questions[user_info.user.name] = data.text # to be backwards compatible #todo remove it when 2.0 end elsif @repl_sessions.key?(user_info.user.name) and data.channel==@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 == '' )) if data.text.match(/^\s*```(.*)```\s*$/im) @repl_sessions[user_info.user.name][:command] = $1 else @repl_sessions[user_info.user.name][:command] = data.text end command = 'repl' else command = data.text end #when added special characters on the message if command.match(/\A\s*```(.*)```\s*\z/im) command = $1 elsif 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 = get_channels() channel_found = channels.detect { |c| c.name == channel_rules_name } members = get_channel_members(@channels_id[channel_rules_name]) 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.", data.channel elsif @status != :on respond "The bot in that channel is not :on", data.channel 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, data.routine) else respond "You need to join the channel <##{channel_found.id}> to be able to use the rules.", data.channel 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, data.routine) 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, data.routine) 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, data.routine) # 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 (data.channel == @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 /From now on I'll be on maintenance status/i sleep 2 if File.exist?("#{config.path}/config_tmp.status") file_cts = IO.readlines("#{config.path}/config_tmp.status").join unless file_cts.to_s() == "" file_cts = eval(file_cts) if file_cts.is_a?(Hash) and file_cts.key?(:on_maintenance) config.on_maintenance = file_cts.on_maintenance end end end when /From now on I won't be on maintenance/i sleep 2 if File.exist?("#{config.path}/config_tmp.status") file_cts = IO.readlines("#{config.path}/config_tmp.status").join unless file_cts.to_s() == "" file_cts = eval(file_cts) if file_cts.is_a?(Hash) and file_cts.key?(:on_maintenance) config.on_maintenance = file_cts.on_maintenance end end end 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() when /global shortcut added/ sleep 2 if File.exist?("#{config.path}/shortcuts/shortcuts_global.rb") file_sc = IO.readlines("#{config.path}/shortcuts/shortcuts_global.rb").join unless file_sc.to_s() == "" @shortcuts_global = eval(file_sc) end end when /global shortcut deleted/ sleep 2 if File.exist?("#{config.path}/shortcuts/shortcuts_global.rb") file_sc = IO.readlines("#{config.path}/shortcuts/shortcuts_global.rb").join unless file_sc.to_s() == "" @shortcuts_global = eval(file_sc) end end end end end end |
#unreact(emoji, ts = false) ⇒ Object
list of available emojis: https://www.webfx.com/tools/emoji-cheat-sheet/ unreact(:thumbsup) ts: can be true, false or a specific ts
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
# File 'lib/slack/smart-bot/comm/unreact.rb', line 5 def unreact(emoji, ts=false) if ts.is_a?(TrueClass) or ts.is_a?(FalseClass) parent = ts ts = nil else parent = false end if ts.nil? if parent or Thread.current[:ts].to_s == '' ts = Thread.current[:thread_ts] else ts = Thread.current[:ts] end end if ts.nil? @logger.warn 'unreact method no ts supplied' else begin client.web_client.reactions_remove(channel: Thread.current[:dest], name: emoji, timestamp: ts) unless config.simulate rescue Exception => stack @logger.warn stack 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 7 8 9 10 11 12 |
# 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 if config.on_master_bot file = File.open("#{config.path}/shortcuts/shortcuts_global.rb", "w") file.write @shortcuts_global.inspect file.close end 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 |
# 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 = get_channels() channel_found = channels.detect { |c| c.name == channel } members = get_channel_members(@channels_id[channel]) 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 |
#whats_new(user, dest, dchannel, from, display_name) ⇒ Object
help: ----------------------------------------------
help: What's new
help: It will display the last user changes on Slack Smart Bot
help:
7 8 9 10 11 12 13 14 15 16 17 |
# File 'lib/slack/smart-bot/commands/general/whats_new.rb', line 7 def whats_new(user, dest, dchannel, from, display_name) if @status == :on save_stats(__method__) whats_new_file = (__FILE__).gsub(/lib\/slack\/smart-bot\/commands\/general\/whats_new\.rb$/, "whats_new.txt") whats_new = File.read(whats_new_file) whats_new.split(/^\-\-\-\-\-\-+$/).each do |msg| respond msg sleep 0.3 end end end |