slack-smart-bot 1.6.6 → 1.8.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e486f34b4f2a713262314668a2c9ca3d18563dd6336ead3220724421a8875868
4
- data.tar.gz: 56a1dfeeb530d13d48092f83565dcbca8a0805f36c3637882ea7fe8284b95ba0
3
+ metadata.gz: 19ab121009af799ef4d1338e6b274c3212aa3fb9eed9098ab32b4d445e620a14
4
+ data.tar.gz: d9d16f6eb8de9fe372865e56f4f4e22ae2b10acdd55918f2d17a38a25f7111d7
5
5
  SHA512:
6
- metadata.gz: a77f63230099832f65ab700d2691c4746b1af1b899cf347f30a210c83364ef998b760d325cbd25eff5419c31adefc62f76cf73664fed1d4b021cad32ec18bc18
7
- data.tar.gz: 05d4e1fc287b8e4d172c667ea1f18afdba75002f5cbaf3d701131a553c7bbc9fb022428350714690fa173008e09e1623ed7a33433adf352671fc4f6d3d999496
6
+ metadata.gz: d94f2a3b0f5f26c1ece8f9d9241b89e26714e6565104a1591c2f0ab0bac0bb9273d2e64e5a988fde4c18cdea0e89a8bcb98d5ee1f36ab22756b30d2b3cf61fff
7
+ data.tar.gz: 2dadb23423038f6141e0f8fdf540b15ec5da160058eb7d286e7fee9b6b7672c58d348f33221848b472997a42818283ea76cb67748ad1d2437784ac0a61f41b3d
data/README.md CHANGED
@@ -124,6 +124,7 @@ def rules(user, command, processed, dest)
124
124
  respond "zZzzzzzZZZZZZzzzzzzz!"
125
125
  react :sleeping
126
126
  sleep 10
127
+ unreact :sleeping
127
128
  react :sunny
128
129
  when /no/i, /nope/i, /cancel/i
129
130
  @questions.delete(from)
@@ -152,6 +153,8 @@ def rules(user, command, processed, dest)
152
153
  else
153
154
  respond "#{user.name}: #{stdout} #{stderr}"
154
155
  end
156
+
157
+ unreact :runner
155
158
 
156
159
  else
157
160
  unless processed
@@ -159,8 +162,11 @@ def rules(user, command, processed, dest)
159
162
  end
160
163
  end
161
164
  end
162
-
163
165
  ```
166
+
167
+ Also you can add general rules that will be available on all Smart Bot channels to `./rules/general_rules.rb`
168
+
169
+
164
170
  ### How to access the Smart Bot
165
171
  You can access the bot directly on the MASTER CHANNEL, on a secondary channel where the bot is running and directly by opening a private chat with the bot, in this case the conversation will be just between you and the bot.
166
172
 
@@ -388,6 +394,7 @@ Examples:
388
394
  >**_`add routine run_tests every 3h !run tests on customers`_**
389
395
  >**_`add routine clean_db at 17:05 !clean customers temp db`_**
390
396
  >**_`add silent routine clean_db at 17:05 !clean customers temp db`_**
397
+ >**_`add routine clean_custdb on Mondays at 05:00 !clean customers db`_**
391
398
 
392
399
  Also instead of adding a Command to be executed, you can attach a file, then the routine will be created and the attached file will be executed on the criteria specified. Only Master Admins are allowed to use it this way.
393
400
 
@@ -36,13 +36,7 @@ class SlackSmartBot
36
36
  else
37
37
  config[:path] = '.'
38
38
  end
39
- if ENV['BOT_SILENT'].to_s == 'true'
40
- config[:silent] = true
41
- elsif ENV['BOT_SILENT'].to_s == 'false'
42
- config[:silent] = false
43
- else
44
- config[:silent] = false unless config.key?(:silent)
45
- end
39
+ config[:silent] = false unless config.key?(:silent)
46
40
  config[:testing] = false unless config.key?(:testing)
47
41
  config[:simulate] = false unless config.key?(:simulate)
48
42
  config[:stats] = false unless config.key?(:stats)
@@ -183,10 +177,20 @@ class SlackSmartBot
183
177
  get_rules_imported()
184
178
 
185
179
  begin
180
+ #todo: take in consideration the case that the value supplied on config.masters and config.admins are the ids and not the user names
186
181
  @admin_users_id = []
182
+ @master_admin_users_id = []
187
183
  config.admins.each do |au|
188
184
  user_info = client.web_client.users_info(user: "@#{au}")
189
185
  @admin_users_id << user_info.user.id
186
+ if config.masters.include?(au)
187
+ @master_admin_users_id << user_info.user.id
188
+ end
189
+ sleep 1
190
+ end
191
+ (config.masters-config.admins).each do |au|
192
+ user_info = client.web_client.users_info(user: "@#{au}")
193
+ @master_admin_users_id << user_info.user.id
190
194
  sleep 1
191
195
  end
192
196
  rescue Slack::Web::Api::Errors::TooManyRequestsError
@@ -210,7 +214,8 @@ class SlackSmartBot
210
214
  if version_remote != VERSION
211
215
  version_message = ". There is a new available version: #{version_remote}."
212
216
  end
213
- unless config[:silent]
217
+ if !config[:silent] or ENV['BOT_SILENT'].to_s == 'false'
218
+ ENV['BOT_SILENT'] = 'true' if config[:silent] == 'true' and ENV['BOT_SILENT'].to_s != 'true'
214
219
  respond "Smart Bot started v#{VERSION}#{version_message}\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."
215
220
  end
216
221
  @routines.each do |ch, rout|
@@ -0,0 +1,33 @@
1
+ # add here the general rules you will be using in all Smart Bots
2
+ def general_rules(user, command, processed, dest, files = [], rules_file = "")
3
+ from = user.name
4
+ display_name = user.profile.display_name
5
+
6
+ begin
7
+ case command
8
+
9
+ # help: ----------------------------------------------
10
+ # help: `echo SOMETHING`
11
+ # help: `INTEGER echo SOMETHING`
12
+ # help: repeats SOMETHING. If INTEGER supplied then that number of times.
13
+ # help: Examples:
14
+ # help: _echo I am the Smart Bot_
15
+ # help: _100 echo :heart:_
16
+ when /^(\d*)\s*echo\s(.+)/i
17
+ save_stats :echo
18
+ $1.to_s == '' ? times = 1 : times = $1.to_i
19
+ respond ($2*times).to_s
20
+
21
+ else
22
+ return false
23
+ end
24
+ return true
25
+ rescue => exception
26
+ if defined?(@logger)
27
+ @logger.fatal exception
28
+ respond "Unexpected error!! Please contact an admin to solve it: <@#{ADMIN_USERS.join(">, <@")}>"
29
+ else
30
+ puts exception
31
+ end
32
+ end
33
+ end
@@ -38,102 +38,98 @@ def rules(user, command, processed, dest, files = [], rules_file = "")
38
38
  from = user.name
39
39
  display_name = user.profile.display_name
40
40
 
41
- begin
42
- case command
41
+ load "#{config.path}/rules/general_rules.rb"
42
+
43
+ unless general_rules(user, command, processed, dest, files, rules_file)
44
+ begin
45
+ case command
43
46
 
44
- # help: ----------------------------------------------
45
- # help: `echo SOMETHING`
46
- # help: repeats SOMETHING
47
- # help: Examples:
48
- # help: _echo I am the Smart Bot_
49
- when /^echo\s(.+)/i
50
- save_stats :echo
51
- respond $1
52
- react :monkey_face
53
-
54
- # help: ----------------------------------------------
55
- # help: `go to sleep`
56
- # help: it will sleep the bot for 5 seconds
57
- # help:
58
- when /^go\sto\ssleep/i
59
- save_stats :to_to_sleep
60
- unless @questions.keys.include?(from)
61
- ask "do you want me to take a siesta?"
62
- else
63
- case @questions[from]
64
- when /yes/i, /yep/i, /sure/i
65
- @questions.delete(from)
66
- respond "I'll be sleeping for 5 secs... just for you"
67
- respond "zZzzzzzZZZZZZzzzzzzz!"
68
- react :sleeping
69
- sleep 5
70
- react :sunny
71
- when /no/i, /nope/i, /cancel/i
72
- @questions.delete(from)
73
- respond "Thanks, I'm happy to be awake"
47
+ # help: ----------------------------------------------
48
+ # help: `go to sleep`
49
+ # help: it will sleep the bot for 5 seconds
50
+ # help:
51
+ when /^go\sto\ssleep/i
52
+ save_stats :go_to_sleep
53
+ unless @questions.keys.include?(from)
54
+ ask "do you want me to take a siesta?"
74
55
  else
75
- respond "I don't understand"
76
- ask "are you sure do you want me to sleep? (yes or no)"
56
+ case @questions[from]
57
+ when /yes/i, /yep/i, /sure/i
58
+ @questions.delete(from)
59
+ respond "I'll be sleeping for 5 secs... just for you"
60
+ respond "zZzzzzzZZZZZZzzzzzzz!"
61
+ react :sleeping
62
+ sleep 5
63
+ unreact :sleeping
64
+ react :sunny
65
+ when /no/i, /nope/i, /cancel/i
66
+ @questions.delete(from)
67
+ respond "Thanks, I'm happy to be awake"
68
+ else
69
+ respond "I don't understand"
70
+ ask "are you sure do you want me to sleep? (yes or no)"
71
+ end
77
72
  end
78
- end
79
73
 
80
- # help: ----------------------------------------------
81
- # help: `run something`
82
- # help: It will run the process and report the results when done
83
- # help:
84
- when /^run something/i
85
- save_stats :run_something
86
- react :runner
74
+ # help: ----------------------------------------------
75
+ # help: `run something`
76
+ # help: It will run the process and report the results when done
77
+ # help:
78
+ when /^run something/i
79
+ save_stats :run_something
80
+ react :runner
87
81
 
88
- process_to_run = "ruby -v"
89
- process_to_run = ("cd #{project_folder} &&" + process_to_run) if defined?(project_folder)
90
- stdout, stderr, status = Open3.capture3(process_to_run)
91
- if stderr == ""
92
- if stdout == ""
93
- respond "#{display_name}: Nothing returned."
82
+ process_to_run = "ruby -v"
83
+ process_to_run = ("cd #{project_folder} &&" + process_to_run) if defined?(project_folder)
84
+ stdout, stderr, status = Open3.capture3(process_to_run)
85
+ unreact :runner
86
+ if stderr == ""
87
+ if stdout == ""
88
+ respond "#{display_name}: Nothing returned."
89
+ else
90
+ respond "#{display_name}: #{stdout}"
91
+ end
94
92
  else
95
- respond "#{display_name}: #{stdout}"
93
+ respond "#{display_name}: #{stdout} #{stderr}"
96
94
  end
97
- else
98
- respond "#{display_name}: #{stdout} #{stderr}"
99
- end
100
-
101
- # Emoticons you can use with `react` command https://www.webfx.com/tools/emoji-cheat-sheet/
102
-
103
- # Examples for respond and respond_direct
104
- # # send 'the message' to the channel or direct message where the command was written
105
- # respond "the message"
106
- # # send 'the message' privately as a direct message to the user that sent the command
107
- # respond_direct "the message"
108
- # # send 'the message' to a specific channel name
109
- # respond "the message", 'my_channel'
110
- # # send 'the message' to a specific channel id
111
- # respond "the message", 'CSU34D33'
112
- # # send 'the message' to a specific user as direct message
113
- # respond "the message", '@theuser'
114
- # # send 'the message' to a specific user id as direct message
115
- # respond "the message", 'US3344D3'
95
+
96
+ # Emoticons you can use with `react` command https://www.webfx.com/tools/emoji-cheat-sheet/
97
+
98
+ # Examples for respond and respond_direct
99
+ # # send 'the message' to the channel or direct message where the command was written
100
+ # respond "the message"
101
+ # # send 'the message' privately as a direct message to the user that sent the command
102
+ # respond_direct "the message"
103
+ # # send 'the message' to a specific channel name
104
+ # respond "the message", 'my_channel'
105
+ # # send 'the message' to a specific channel id
106
+ # respond "the message", 'CSU34D33'
107
+ # # send 'the message' to a specific user as direct message
108
+ # respond "the message", '@theuser'
109
+ # # send 'the message' to a specific user id as direct message
110
+ # respond "the message", 'US3344D3'
116
111
 
117
- # Example downloading a file from slack
118
- # if !files.nil? and files.size == 1 and files[0].filetype == 'yaml'
119
- # require 'nice_http'
120
- # http = NiceHttp.new(host: "https://files.slack.com", headers: { "Authorization" => "Bearer #{config[:token]}" })
121
- # http.get(files[0].url_private_download, save_data: './tmp/')
122
- # end
112
+ # Example downloading a file from slack
113
+ # if !files.nil? and files.size == 1 and files[0].filetype == 'yaml'
114
+ # require 'nice_http'
115
+ # http = NiceHttp.new(host: "https://files.slack.com", headers: { "Authorization" => "Bearer #{config[:token]}" })
116
+ # http.get(files[0].url_private_download, save_data: './tmp/')
117
+ # end
123
118
 
124
- # Examples sending a file to slack:
125
- # send_file(to, msg, filepath, title, format, type = "text")
126
- # send_file(dest, 'the message', "#{project_folder}/temp/logs_ptBI.log", 'title', 'text/plain', "text")
127
- # send_file(dest, 'the message', "#{project_folder}/temp/example.jpeg", 'title', 'image/jpeg', "jpg")
119
+ # Examples sending a file to slack:
120
+ # send_file(to, msg, filepath, title, format, type = "text")
121
+ # send_file(dest, 'the message', "#{project_folder}/temp/logs_ptBI.log", 'title', 'text/plain', "text")
122
+ # send_file(dest, 'the message', "#{project_folder}/temp/example.jpeg", 'title', 'image/jpeg', "jpg")
128
123
 
129
124
 
130
- else
131
- unless processed
132
- dont_understand()
125
+ else
126
+ unless processed
127
+ dont_understand()
128
+ end
133
129
  end
130
+ rescue => exception
131
+ @logger.fatal exception
132
+ respond "Unexpected error!! Please contact an admin to solve it: <@#{config.admins.join(">, <@")}>"
134
133
  end
135
- rescue => exception
136
- @logger.fatal exception
137
- respond "Unexpected error!! Please contact an admin to solve it: <@#{config.admins.join(">, <@")}>"
138
134
  end
139
135
  end
@@ -5,4 +5,5 @@ require_relative 'comm/respond'
5
5
  require_relative 'comm/send_file'
6
6
  require_relative 'comm/send_msg_channel'
7
7
  require_relative 'comm/send_msg_user'
8
- require_relative 'comm/react'
8
+ require_relative 'comm/react'
9
+ require_relative 'comm/unreact'
@@ -2,7 +2,7 @@ class SlackSmartBot
2
2
  # list of available emojis: https://www.webfx.com/tools/emoji-cheat-sheet/
3
3
  # react(:thumbsup)
4
4
  def react(emoji, parent=false)
5
- if parent
5
+ if parent or Thread.current[:ts].to_s == ''
6
6
  ts = Thread.current[:thread_ts]
7
7
  else
8
8
  ts = Thread.current[:ts]
@@ -38,7 +38,7 @@ class SlackSmartBot
38
38
  f.puts "|#{dest}|#{config[:nick_id]}|#{msg}"
39
39
  }
40
40
  end
41
- elsif dest[0] == "D" or dest[0] == "U" # Direct message
41
+ elsif dest[0] == "D" or dest[0] == "U" or dest[0] == "W" # Direct message
42
42
  send_msg_user(dest, msg)
43
43
  elsif dest[0] == "@"
44
44
  begin
@@ -3,9 +3,12 @@ class SlackSmartBot
3
3
  #to send a file to an user or channel
4
4
  #send_file(dest, 'the message', "#{project_folder}/temp/logs_ptBI.log", 'message to be sent', 'text/plain', "text")
5
5
  #send_file(dest, 'the message', "#{project_folder}/temp/example.jpeg", 'message to be sent', 'image/jpeg', "jpg")
6
- def send_file(to, msg, file, title, format, type = "text")
6
+ #send_file(dest, 'the message', "", 'message to be sent', 'text/plain', "ruby", content: "the content to be sent when no file supplied")
7
+ #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
+ def send_file(to, msg, file, title, format, type = "text", content: '')
7
9
  unless config[:simulate]
8
- if to[0] == "U" #user
10
+ file = 'myfile' if file.to_s == '' and content!=''
11
+ if to[0] == "U" or to[0] == "W" #user
9
12
  im = client.web_client.im_open(user: to)
10
13
  channel = im["channel"]["id"]
11
14
  else
@@ -18,16 +21,29 @@ class SlackSmartBot
18
21
  ts = nil
19
22
  end
20
23
 
21
- client.web_client.files_upload(
22
- channels: channel,
23
- as_user: true,
24
- file: Faraday::UploadIO.new(file, format),
25
- title: title,
26
- filename: file,
27
- filetype: type,
28
- initial_comment: msg,
29
- thread_ts: ts
30
- )
24
+ if content.to_s == ''
25
+ client.web_client.files_upload(
26
+ channels: channel,
27
+ as_user: true,
28
+ file: Faraday::UploadIO.new(file, format),
29
+ title: title,
30
+ filename: file,
31
+ filetype: type,
32
+ initial_comment: msg,
33
+ thread_ts: ts
34
+ )
35
+ else
36
+ client.web_client.files_upload(
37
+ channels: channel,
38
+ as_user: true,
39
+ content: content,
40
+ title: title,
41
+ filename: file,
42
+ filetype: type,
43
+ initial_comment: msg,
44
+ thread_ts: ts
45
+ )
46
+ end
31
47
  end
32
48
  end
33
49
 
@@ -0,0 +1,16 @@
1
+ class SlackSmartBot
2
+ # list of available emojis: https://www.webfx.com/tools/emoji-cheat-sheet/
3
+ # unreact(:thumbsup)
4
+ def unreact(emoji, parent=false)
5
+ if parent
6
+ ts = Thread.current[:thread_ts]
7
+ else
8
+ ts = Thread.current[:ts]
9
+ end
10
+ begin
11
+ client.web_client.reactions_remove(channel: Thread.current[:dest], name: emoji, timestamp: ts)
12
+ rescue Exception => stack
13
+ @logger.warn stack
14
+ end
15
+ end
16
+ end
@@ -5,6 +5,7 @@ class SlackSmartBot
5
5
  # helpadmin: `add silent routine NAME every NUMBER PERIOD`
6
6
  # helpadmin: `create routine NAME every NUMBER PERIOD`
7
7
  # helpadmin: `add routine NAME at TIME COMMAND`
8
+ # helpadmin: `add routine NAME on DAYWEEK at TIME COMMAND`
8
9
  # helpadmin: `add routine NAME at TIME`
9
10
  # helpadmin: `add silent routine NAME at TIME`
10
11
  # helpadmin: `create routine NAME at TIME`
@@ -15,12 +16,14 @@ class SlackSmartBot
15
16
  # helpadmin: NUMBER: Integer
16
17
  # helpadmin: PERIOD: days, d, hours, h, minutes, mins, min, m, seconds, secs, sec, s
17
18
  # helpadmin: TIME: time at format HH:MM:SS
19
+ # helpadmin: DAYWEEK: Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday. And their plurals.
18
20
  # helpadmin: COMMAND: any valid smart bot command or rule
19
21
  # helpadmin: Examples:
20
22
  # helpadmin: _add routine example every 30s ruby puts 'a'_
21
23
  # helpadmin: _add routine example every 3 days ruby puts 'a'_
22
24
  # helpadmin: _add routine example at 17:05 ruby puts 'a'_
23
25
  # helpadmin: _create silent routine every 12 hours !Run customer tests_
26
+ # helpadmin: _add routine example on Mondays at 05:00 !run customer tests_
24
27
  # helpadmin:
25
28
  def add_routine(dest, from, user, name, type, number_time, period, command_to_run, files, silent)
26
29
  save_stats(__method__)
@@ -30,13 +33,14 @@ class SlackSmartBot
30
33
  respond "I'm sorry but there is already a routine with that name.\nCall `see routines` to see added routines", dest
31
34
  else
32
35
  number_time += ":00" if number_time.split(":").size == 2
33
- if (type == "at") && !number_time.match?(/^[01][0-9]:[0-5][0-9]:[0-5][0-9]$/) &&
36
+ if (type != "every") && !number_time.match?(/^[01][0-9]:[0-5][0-9]:[0-5][0-9]$/) &&
34
37
  !number_time.match?(/^2[0-3]:[0-5][0-9]:[0-5][0-9]$/)
35
38
  respond "Wrong time specified: *#{number_time}*"
36
39
  else
37
40
  file_path = ""
38
41
  every = ""
39
42
  at = ""
43
+ dayweek = ''
40
44
  next_run = Time.now
41
45
  case period.downcase
42
46
  when "days", "d"
@@ -52,16 +56,31 @@ class SlackSmartBot
52
56
  every = "#{number_time} seconds"
53
57
  every_in_seconds = number_time.to_i
54
58
  else # time
59
+ if type != 'at'
60
+ dayweek = type.downcase
61
+ days = ['sunday','monday','tuesday','wednesday','thursday','friday','saturday']
62
+ incr = days.index(dayweek) - Time.now.wday
63
+ if incr < 0
64
+ incr = (7+incr)*24*60*60
65
+ else
66
+ incr = incr * 24 * 60 * 60
67
+ end
68
+ days = incr/(24*60*60)
69
+ every_in_seconds = 7 * 24 * 60 * 60 # one week
70
+ else
71
+ days = 0
72
+ every_in_seconds = 24 * 60 * 60 # one day
73
+ end
74
+
55
75
  at = number_time
56
- if next_run.strftime("%H:%M:%S") < number_time
76
+ if next_run.strftime("%H:%M:%S") < number_time and days == 0
57
77
  nt = number_time.split(":")
58
78
  next_run = Time.new(next_run.year, next_run.month, next_run.day, nt[0], nt[1], nt[2])
59
79
  else
60
- next_run += (24 * 60 * 60) # one more day
80
+ next_run += ((24 * 60 * 60) * days) # one or more days
61
81
  nt = number_time.split(":")
62
82
  next_run = Time.new(next_run.year, next_run.month, next_run.day, nt[0], nt[1], nt[2])
63
83
  end
64
- every_in_seconds = 24 * 60 * 60
65
84
  end
66
85
  Dir.mkdir("#{config.path}/routines/#{@channel_id}") unless Dir.exist?("#{config.path}/routines/#{@channel_id}")
67
86
 
@@ -78,7 +97,7 @@ class SlackSmartBot
78
97
 
79
98
  @routines[@channel_id] = {} unless @routines.key?(@channel_id)
80
99
  @routines[@channel_id][name] = { channel_name: config.channel, creator: from, creator_id: user.id, status: :on,
81
- every: every, every_in_seconds: every_in_seconds, at: at, file_path: file_path,
100
+ every: every, every_in_seconds: every_in_seconds, at: at, dayweek: dayweek, file_path: file_path,
82
101
  command: command_to_run.to_s.strip, silent: silent,
83
102
  next_run: next_run.to_s, dest: dest, last_run: "", last_elapsed: "",
84
103
  running: false }
@@ -54,7 +54,7 @@ class SlackSmartBot
54
54
  respond "Now the rules from <##{@channel_id}> are available on *<##{@channels_id[channel]}>*", dest
55
55
  end
56
56
  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]
57
- respond "Use `!` before the command you want to run", @channels_id[channel]
57
+ respond "Use `!` or `^` or `!!` before the command you want to run", @channels_id[channel]
58
58
  respond "To see the specific rules for this bot on this channel: `!bot rules` or `!bot rules COMMAND`", @channels_id[channel]
59
59
  end
60
60
  end
@@ -44,6 +44,7 @@ class SlackSmartBot
44
44
  msg << "\tStatus: #{v[:status]}"
45
45
  msg << "\tEvery: #{v[:every]}" unless v[:every] == ""
46
46
  msg << "\tAt: #{v[:at]}" unless v[:at] == ""
47
+ msg << "\tOn: #{v[:dayweek]}" unless !v.key?(:dayweek) or v[:dayweek].to_s == ""
47
48
  msg << "\tNext Run: #{v[:next_run]}"
48
49
  msg << "\tLast Run: #{v[:last_run]}"
49
50
  msg << "\tTime consumed on last run: #{v[:last_elapsed]}" unless v[:command] !=''
@@ -13,6 +13,7 @@ class SlackSmartBot
13
13
  # helpadmin: `bot stats CHANNEL exclude masters from YYYY/MM/DD to YYYY/MM/DD`
14
14
  # helpadmin: `bot stats today`
15
15
  # helpadmin: `bot stats exclude COMMAND_ID`
16
+ # helpadmin: `bot stats monthly`
16
17
  # helpadmin: To see the bot stats
17
18
  # 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
18
19
  # helpadmin: You need to set stats to true to generate the stats when running the bot instance.
@@ -21,8 +22,9 @@ class SlackSmartBot
21
22
  # helpadmin: _bot stats @peter.wind_
22
23
  # helpadmin: _bot stats #sales from 2019/12/15 to 2019/12/31_
23
24
  # helpadmin: _bot stats #sales today_
25
+ # helpadmin: _bot stats #sales from 2020-01-01 monthly_
24
26
  # helpadmin:
25
- def bot_stats(dest, from_user, typem, channel_id, from, to, user, exclude_masters, exclude_command)
27
+ def bot_stats(dest, from_user, typem, channel_id, from, to, user, exclude_masters, exclude_command, monthly)
26
28
  require 'csv'
27
29
  if config.stats
28
30
  message = []
@@ -30,7 +32,7 @@ class SlackSmartBot
30
32
  message = ["You need to set stats to true to generate the stats when running the bot instance."]
31
33
  end
32
34
  save_stats(__method__)
33
- if config.masters.include?(from_user) and typem==:on_dm #master admin user
35
+ if (config.masters.include?(from_user) or @master_admin_users_id.include?(from_user)) and typem==:on_dm #master admin user
34
36
  if !File.exist?("#{config.stats_path}.#{Time.now.strftime("%Y-%m")}.log")
35
37
  message<<'No stats'
36
38
  else
@@ -43,17 +45,71 @@ class SlackSmartBot
43
45
  from+= " 00:00:00 +0000"
44
46
  to+= " 23:59:59 +0000"
45
47
  rows = []
46
-
48
+ rows_month = {}
49
+ users_month = {}
50
+ commands_month = {}
51
+ users_id_name = {}
52
+ users_name_id = {}
53
+
54
+ # to translate global and enterprise users since sometimes was returning different names/ids
55
+ Dir["#{config.stats_path}.*.log"].sort.each do |file|
56
+ if file >= "#{config.stats_path}.#{from_file}.log" or file <= "#{config.stats_path}.#{to_file}.log"
57
+ CSV.foreach(file, headers: true, header_converters: :symbol, converters: :numeric) do |row|
58
+ unless users_id_name.key?(row[:user_id])
59
+ users_id_name[row[:user_id]] = row[:user_name]
60
+ end
61
+ unless users_name_id.key?(row[:user_name])
62
+ users_name_id[row[:user_name]] = row[:user_id]
63
+ end
64
+
65
+ end
66
+ end
67
+ end
68
+
69
+ if user!=''
70
+ user_info = client.web_client.users_info(user: user)
71
+ if users_id_name.key?(user_info.user.id)
72
+ user_name = users_id_name[user_info.user.id]
73
+ else
74
+ user_name = user_info.user.name
75
+ end
76
+ if users_name_id.key?(user_info.user.name)
77
+ user_id = users_name_id[user_info.user.name]
78
+ else
79
+ user_id = user_info.user.id
80
+ end
81
+ end
82
+ master_admins = config.masters.dup
83
+ config.masters.each do |u|
84
+ if users_id_name.key?(u)
85
+ master_admins << users_id_name[u]
86
+ elsif users_name_id.key?(u)
87
+ master_admins << users_name_id[u]
88
+ end
89
+ end
90
+
47
91
  Dir["#{config.stats_path}.*.log"].sort.each do |file|
48
92
  if file >= "#{config.stats_path}.#{from_file}.log" or file <= "#{config.stats_path}.#{to_file}.log"
49
93
  CSV.foreach(file, headers: true, header_converters: :symbol, converters: :numeric) do |row|
50
94
  row[:date] = row[:date].to_s
51
- if !exclude_masters or (exclude_masters and !config.masters.include?(row[:user_name]))
52
- if user=='' or (user!='' and row[:user_id] == user)
95
+ row[:user_name] = users_id_name[row[:user_id]]
96
+ row[:user_id] = users_name_id[row[:user_name]]
97
+ if !exclude_masters or (exclude_masters and !master_admins.include?(row[:user_name]) and
98
+ !master_admins.include?(row[:user_id]) and
99
+ !@master_admin_users_id.include?(row[:user_id]))
100
+ if user=='' or (user!='' and row[:user_name] == user_name) or (user!='' and row[:user_id] == user_id)
53
101
  if exclude_command == '' or (exclude_command!='' and row[:command]!=exclude_command)
54
102
  if row[:bot_channel_id] == channel_id or channel_id == ''
55
103
  if row[:date] >= from and row[:date] <= to
56
104
  rows << row.to_h
105
+ if monthly
106
+ rows_month[row[:date][0..6]] = 0 unless rows_month.key?(row[:date][0..6])
107
+ users_month[row[:date][0..6]] = [] unless users_month.key?(row[:date][0..6])
108
+ commands_month[row[:date][0..6]] = [] unless commands_month.key?(row[:date][0..6])
109
+ rows_month[row[:date][0..6]] += 1
110
+ users_month[row[:date][0..6]] << row[:user_id]
111
+ commands_month[row[:date][0..6]] << row[:command]
112
+ end
57
113
  end
58
114
  end
59
115
  end
@@ -62,7 +118,6 @@ class SlackSmartBot
62
118
  end
63
119
  end
64
120
  end
65
-
66
121
  total = rows.size
67
122
  if exclude_masters
68
123
  message << 'Excluding master admins'
@@ -79,7 +134,22 @@ class SlackSmartBot
79
134
  message << "*Total calls <##{channel_id}>*: #{total} from #{from_short} to #{to_short}"
80
135
  end
81
136
  if total > 0
82
-
137
+ if monthly
138
+ message << '*Totals by month / commands / users (%new)*'
139
+ all_users = []
140
+ new_users = []
141
+ rows_month.each do |k,v|
142
+ if all_users.empty?
143
+ message_new_users = ''
144
+ else
145
+ new_users = (users_month[k]-all_users).uniq
146
+ message_new_users = "(#{new_users.size*100/users_month[k].uniq.size}%)"
147
+ end
148
+ all_users += users_month[k]
149
+ message << "\t#{k}: #{v} (#{(v.to_f*100/total).round(2)}%) / #{commands_month[k].uniq.size} / #{users_month[k].uniq.size} #{message_new_users}"
150
+ end
151
+ end
152
+
83
153
  if channel_id == ''
84
154
  message << "*Channels*"
85
155
  channels = rows.bot_channel.uniq.sort
@@ -89,21 +159,25 @@ class SlackSmartBot
89
159
  end
90
160
  end
91
161
  if user==''
92
- message << "*Users*"
93
- users = rows.user_name.uniq.sort
162
+ users = rows.user_id.uniq.sort
163
+ message << "*Users* - #{users.size}"
164
+ count_user = {}
94
165
  users.each do |user|
95
- count = rows.count {|h| h.user_name==user}
96
- message << "\t#{user}: #{count} (#{(count.to_f*100/total).round(2)}%)"
166
+ count = rows.count {|h| h.user_id==user}
167
+ count_user[user] = count
168
+ end
169
+ count_user.sort_by {|k,v| -v}.each do |user, count|
170
+ message << "\t#{users_id_name[user]}: #{count} (#{(count.to_f*100/total).round(2)}%)"
97
171
  end
98
172
  end
99
-
100
- message << "*Commands*"
173
+
101
174
  commands = rows.command.uniq.sort
175
+ message << "*Commands* - #{commands.size}"
102
176
  commands.each do |command|
103
177
  count = rows.count {|h| h.command==command}
104
178
  message << "\t#{command}: #{count} (#{(count.to_f*100/total).round(2)}%)"
105
179
  end
106
-
180
+
107
181
  message << "*Message type*"
108
182
  types = rows.type_message.uniq.sort
109
183
  types.each do |type|
@@ -112,7 +186,6 @@ class SlackSmartBot
112
186
  end
113
187
  message << "*Last activity*: #{rows[-1].date} #{rows[-1].bot_channel} #{rows[-1].type_message} #{rows[-1].user_name} #{rows[-1].command}"
114
188
  end
115
-
116
189
  end
117
190
  else
118
191
  message<<"Only Master admin users on a private conversation with the bot can see the bot stats."
@@ -82,6 +82,7 @@ class SlackSmartBot
82
82
  message = "Session name: *#{session_name}*
83
83
  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`.
84
84
  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`.
85
+ Use `p` to print a message raw, exacly like it is returned.
85
86
  If you want to avoid a message to be treated by me, start the message with '-'.
86
87
  After 30 minutes of no communication with the Smart Bot the session will be dismissed.
87
88
  If you want to see the methods of a class or module you created use _ls TheModuleOrClass_
@@ -100,34 +101,8 @@ class SlackSmartBot
100
101
  require \"amazing_print\"
101
102
  bindme' + serialt + ' = binding
102
103
  eval(\"require \'nice_http\'\" , bindme' + serialt + ')
103
- def repl_params(met)
104
- res = []
105
- met.parameters.each do |par|
106
- if par[0]==:req
107
- res << par[1].to_s
108
- elsif par[0]==:keyreq
109
- res << par[1].to_s + \":\"
110
- elsif par[0]==:key
111
- res << \"?\"+par[1].to_s + \":\"
112
- elsif par[0]==:opt
113
- res << \"?\"+par[1].to_s
114
- elsif par[0]==:rest
115
- res << \"*\"+par[1].to_s
116
- elsif par[0]==:keyrest
117
- res << \"**\"+par[1].to_s
118
- else
119
- res << par[1].to_s
120
- end
121
- end
122
- \"(#{res.join(\", \")})\"
123
- end
124
104
  def ls(obj)
125
- mets = (obj.methods - Object.methods)
126
- res = []
127
- mets.each do |met|
128
- res << \"#{met}#{repl_params(obj.method(met))}\"
129
- end
130
- res.sort
105
+ (obj.methods - Object.methods)
131
106
  end
132
107
 
133
108
  file_input_repl = File.open(\"' + Dir.pwd + '/repl/' + @channel_id + '/' + session_name + '.input\", \"r\")
@@ -158,9 +133,15 @@ class SlackSmartBot
158
133
  error = true
159
134
  end
160
135
  if resp_repl.to_s != \"\"
161
- open(\"' + Dir.pwd + '/repl/' + @channel_id + '/' + session_name + '.output\", \"a+\") {|f|
162
- f.puts \"\`\`\`\n#{resp_repl.ai}\n\`\`\`\"
163
- }
136
+ if code_to_run_repl.match?(/^\s*p\s+/i)
137
+ open(\"' + Dir.pwd + '/repl/' + @channel_id + '/' + session_name + '.output\", \"a+\") {|f|
138
+ f.puts \"\`\`\`\n#{resp_repl.inspect}\n\`\`\`\"
139
+ }
140
+ else
141
+ open(\"' + Dir.pwd + '/repl/' + @channel_id + '/' + session_name + '.output\", \"a+\") {|f|
142
+ f.puts \"\`\`\`\n#{resp_repl.ai}\n\`\`\`\"
143
+ }
144
+ end
164
145
  unless error or !add_to_run_repl
165
146
  open(\"' + Dir.pwd + '/repl/' + @channel_id + '/' + session_name + '.run\", \"a+\") {|f|
166
147
  f.puts code_to_run_repl
@@ -198,7 +179,13 @@ class SlackSmartBot
198
179
  sleep 0.2
199
180
  resp_repl = file_output_repl.read
200
181
  if resp_repl.to_s!=''
201
- respond resp_repl, dest
182
+ if resp_repl.to_s.lines.count < 60 and resp_repl.to_s.size < 3500
183
+ respond resp_repl, dest
184
+ else
185
+ resp_repl.gsub!(/^\s*```/,'')
186
+ resp_repl.gsub!(/```\s*$/,'')
187
+ send_file(dest, "", 'response.rb', "", 'text/plain', "ruby", content: resp_repl)
188
+ end
202
189
  end
203
190
  rescue Exception => excp
204
191
  @logger.fatal excp
@@ -210,7 +197,7 @@ class SlackSmartBot
210
197
  @repl_sessions[from][:command] = ''
211
198
  code.gsub!("\\n", "\n")
212
199
  code.gsub!("\\r", "\r")
213
- # Disabled for the moment sinde it is deleting lines with '}'
200
+ # Disabled for the moment since it is deleting lines with '}'
214
201
  #code.gsub!(/^\W*$/, "") #to remove special chars from slack when copy/pasting.
215
202
  if code.match?(/System/i) or code.match?(/Kernel/i) or code.include?("File") or
216
203
  code.include?("`") or code.include?("exec") or code.include?("spawn") or code.include?("IO.") or
@@ -52,7 +52,7 @@ class SlackSmartBot
52
52
  Dir.mkdir("#{project_folder}/tmp") unless Dir.exist?("#{project_folder}/tmp")
53
53
  Dir.mkdir("#{project_folder}/tmp/repl") unless Dir.exist?("#{project_folder}/tmp/repl")
54
54
  File.write("#{project_folder}/tmp/repl/#{session_name}.rb", content, mode: "w+")
55
- process_to_run = "ruby #{project_folder}/tmp/repl/#{session_name}.rb"
55
+ process_to_run = "ruby ./tmp/repl/#{session_name}.rb"
56
56
  process_to_run = ("cd #{project_folder} && #{process_to_run}") if defined?(project_folder)
57
57
  respond "Running REPL #{session_name}"
58
58
  stdout, stderr, status = Open3.capture3(process_to_run)
@@ -60,10 +60,19 @@ class SlackSmartBot
60
60
  if stdout == ""
61
61
  respond "*#{session_name}*: Nothing returned."
62
62
  else
63
- respond "*#{session_name}*: #{stdout}"
63
+ if stdout.to_s.lines.count < 60 and stdout.to_s.size < 3500
64
+ respond "*#{session_name}*: #{stdout}"
65
+ else
66
+ send_file(dest, "", 'response.rb', "", 'text/plain', "ruby", content: stdout)
67
+ end
64
68
  end
65
69
  else
66
- respond "*#{session_name}*: #{stdout} #{stderr}"
70
+ if (stdout.to_s+stderr.to_s).lines.count < 60
71
+ respond "*#{session_name}*: #{stdout} #{stderr}"
72
+ else
73
+ send_file(dest, "", 'response.rb', "", 'text/plain', "ruby", content: (stdout.to_s+stderr.to_s))
74
+ end
75
+
67
76
  end
68
77
  end
69
78
  else
@@ -15,7 +15,7 @@ class SlackSmartBot
15
15
  message = ""
16
16
  @repls.sort.to_h.each do |session_name, repl|
17
17
  if (repl.creator_name == user.name or repl.type == :public) or (config.admins.include?(user.name) and typem == :on_dm)
18
- message += "(#{repl.type}) *#{session_name}*: #{repl.description} / created: #{repl.created} / accessed: #{repl.accessed} / creator: #{repl.creator} / runs: #{repl.runs_by_creator+repl.runs_by_others} / gets: #{repl.gets} \n"
18
+ message += "(#{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"
19
19
  end
20
20
  end
21
21
  message = "No repls created" if message == ''
@@ -46,14 +46,19 @@ class SlackSmartBot
46
46
  rules_file = "slack-smart-bot_rules_#{channel_id}_#{from.gsub(" ", "_")}.rb"
47
47
  if defined?(RULES_FOLDER)
48
48
  rules_file = RULES_FOLDER + rules_file
49
+ general_rules_file = RULES_FOLDER + 'general_rules.rb'
49
50
  else
50
51
  Dir.mkdir("#{config.path}/rules") unless Dir.exist?("#{config.path}/rules")
51
52
  Dir.mkdir("#{config.path}/rules/#{channel_id}") unless Dir.exist?("#{config.path}/rules/#{channel_id}")
52
53
  rules_file = "/rules/#{channel_id}/" + rules_file
54
+ general_rules_file = "/rules/general_rules.rb"
53
55
  end
54
56
  default_rules = (__FILE__).gsub(/slack\/smart-bot\/commands\/on_master\/create_bot\.rb$/, "slack-smart-bot_rules.rb")
57
+ default_general_rules = (__FILE__).gsub(/slack\/smart-bot\/commands\/on_master\/create_bot\.rb$/, "slack-smart-bot_general_rules.rb")
58
+
55
59
  File.delete(config.path + rules_file) if File.exist?(config.path + rules_file)
56
60
  FileUtils.copy_file(default_rules, config.path + rules_file) unless File.exist?(config.path + rules_file)
61
+ FileUtils.copy_file(default_general_rules, config.path + general_rules_file) unless File.exist?(config.path + general_rules_file)
57
62
  admin_users = Array.new()
58
63
  creator_info = client.web_client.users_info(user: channel_found.creator)
59
64
  admin_users = [from, creator_info.user.name] + config.masters
@@ -70,7 +70,8 @@ class SlackSmartBot
70
70
  channel = $1
71
71
  kill_bot_on_channel(dest, from, channel)
72
72
  when /^\s*(add|create)\s+(silent\s+)?routine\s+(\w+)\s+(every)\s+(\d+)\s*(days|hours|minutes|seconds|mins|min|secs|sec|d|h|m|s)\s*(\s.+)?\s*$/i,
73
- /^\s*(add|create)\s+(silent\s+)?routine\s+(\w+)\s+(at)\s+(\d+:\d+:?\d+?)\s*()(\s.+)?\s*$/i
73
+ /^\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.+)?\s*$/i,
74
+ /^\s*(add|create)\s+(silent\s+)?routine\s+(\w+)\s+(at)\s+(\d+:\d+:?\d+?)\s*()(\s.+)?\s*$/i
74
75
  silent = $2.to_s!=''
75
76
  name = $3.downcase
76
77
  type = $4
@@ -105,12 +106,15 @@ class SlackSmartBot
105
106
  st_to = st_to.gsub('.','-').gsub('/','-')
106
107
  st_user = opts.scan(/<@([^>]+)>/).join
107
108
  exclude_masters = opts.match?(/exclude\s+masters?/i)
109
+ monthly = false
108
110
  if all_opts.include?('today')
109
111
  st_from = st_to = "#{Time.now.strftime("%Y-%m-%d")}"
112
+ elsif all_opts.include?('monthly')
113
+ monthly = true
110
114
  end
111
115
  exclude_command = opts.scan(/exclude\s+([^\s]+)/i).join
112
116
  exclude_command = '' if exclude_command == 'masters'
113
- bot_stats(dest, from, typem, st_channel, st_from, st_to, st_user, exclude_masters, exclude_command)
117
+ bot_stats(dest, from, typem, st_channel, st_from, st_to, st_user, exclude_masters, exclude_command, monthly)
114
118
  else
115
119
  processed = false
116
120
  end
@@ -166,11 +170,11 @@ class SlackSmartBot
166
170
  ruby_code(dest, user, code, rules_file)
167
171
  when /^\s*(private\s+)?(repl|irb|live)\s*()()()$/i,
168
172
  /^\s*(private\s+)?(repl|irb|live)\s+([\w\-]+)()()\s*$/i,
169
- /^\s*(private\s+)?(repl|irb|live)\s+([\w\-]+)\s*:\s*"(.+)"()\s*$/i,
170
- /^\s*(private\s+)?(repl|irb|live)\s+([\w\-]+)\s*:\s*"(.+)"\s+(.+)\s*$/i,
173
+ /^\s*(private\s+)?(repl|irb|live)\s+([\w\-]+)\s*:\s+"([^"]+)"()\s*$/i,
174
+ /^\s*(private\s+)?(repl|irb|live)\s+([\w\-]+)\s*:\s+"([^"]+)"\s+(.+)\s*$/i,
171
175
  /^\s*(private\s+)?(repl|irb|live)\s+([\w\-]+)()\s+(.+)\s*$/i,
172
176
  /^\s*(private\s+)?(repl|irb|live)()\s+()(.+)\s*$/i
173
- if $1.to_s!=''
177
+ if $1.to_s!=''
174
178
  type = :private
175
179
  else
176
180
  type = :public
@@ -32,6 +32,8 @@ class SlackSmartBot
32
32
  data.text = CGI.unescapeHTML(data.text)
33
33
  data.text.gsub!("\u00A0", " ") #to change &nbsp; (asc char 160) into blank space
34
34
  end
35
+ data.text.gsub!('’', "'")
36
+ data.text.gsub!('“', '"')
35
37
  rescue
36
38
  @logger.warn "Impossible to unescape or clean format for data.text:#{data.text}"
37
39
  end
@@ -115,6 +117,8 @@ class SlackSmartBot
115
117
  begin
116
118
  #todo: when changed @questions user_id then move user_info inside the ifs to avoid calling it when not necessary
117
119
  user_info = client.web_client.users_info(user: data.user)
120
+ #user_info.user.id = data.user #todo: remove this line when slack issue with Wxxxx Uxxxx fixed
121
+ data.user = user_info.user.id #todo: remove this line when slack issue with Wxxxx Uxxxx fixed
118
122
  if @questions.key?(user_info.user.name)
119
123
  if data.text.match?(/^\s*(Bye|Bæ|Good\sBye|Adiós|Ciao|Bless|Bless\sBless|Adeu)\s(#{@salutations.join("|")})\s*$/i)
120
124
  @questions.delete(user_info.user.name)
@@ -127,12 +131,8 @@ class SlackSmartBot
127
131
  ((@repl_sessions[user_info.user.name][:on_thread] and data.thread_ts == @repl_sessions[user_info.user.name][:thread_ts]) or
128
132
  (!@repl_sessions[user_info.user.name][:on_thread] and data.thread_ts.to_s == '' ))
129
133
 
130
- if data.text.size >= 6 and data.text[0..2] == "```" and data.text[-3..-1] == "```"
131
- if data.text.size == 6
132
- @repl_sessions[user_info.user.name][:command] = ""
133
- else
134
- @repl_sessions[user_info.user.name][:command] = data.text[3..-4]
135
- end
134
+ if data.text.match(/^\s*```(.*)```\s*$/im)
135
+ @repl_sessions[user_info.user.name][:command] = $1
136
136
  else
137
137
  @repl_sessions[user_info.user.name][:command] = data.text
138
138
  end
@@ -142,12 +142,8 @@ class SlackSmartBot
142
142
  end
143
143
 
144
144
  #when added special characters on the message
145
- if command.size >= 6 and command[0..2]=="```" and command[-3..-1]=="```"
146
- if command.size == 6
147
- command = ''
148
- else
149
- command = command[3..-4]
150
- end
145
+ if command.match(/^\s*```(.*)```\s*$/im)
146
+ command = $1
151
147
  elsif command.size >= 2 and
152
148
  ((command[0] == "`" and command[-1] == "`") or (command[0] == "*" and command[-1] == "*") or (command[0] == "_" and command[-1] == "_"))
153
149
  command = command[1..-2]
@@ -13,7 +13,6 @@ class SlackSmartBot
13
13
  ruby = ""
14
14
  end
15
15
  @routines[@channel_id][name][:silent] = false if !@routines[@channel_id][name].key?(:silent)
16
-
17
16
  if @routines[@channel_id][name][:at] == "" or
18
17
  (@routines[@channel_id][name][:at] != "" and @routines[@channel_id][name][:running] and
19
18
  @routines[@channel_id][name][:next_run] != "" and Time.now.to_s >= @routines[@channel_id][name][:next_run])
@@ -55,11 +54,34 @@ class SlackSmartBot
55
54
  require "time"
56
55
  every_in_seconds = Time.parse(@routines[@channel_id][name][:next_run]) - Time.now
57
56
  elsif @routines[@channel_id][name][:at] != "" #coming from start after pause for 'at'
58
- if started.strftime("%H:%M:%S") < @routines[@channel_id][name][:at]
57
+ if @routines[@channel_id][name].key?(:dayweek) and @routines[@channel_id][name][:dayweek].to_s!=''
58
+ day = @routines[@channel_id][name][:dayweek]
59
+ days = ['sunday','monday','tuesday','wednesday','thursday','friday','saturday']
60
+ incr = days.index(day) - Time.now.wday
61
+ if incr < 0
62
+ incr = (7+incr)*24*60*60
63
+ else
64
+ incr = incr * 24 * 60 * 60
65
+ end
66
+ days = incr/(24*60*60)
67
+ weekly = true
68
+ else
69
+ days = 0
70
+ weekly = false
71
+ end
72
+
73
+ if started.strftime("%H:%M:%S") < @routines[@channel_id][name][:at] and days == 0
59
74
  nt = @routines[@channel_id][name][:at].split(":")
60
75
  next_run = Time.new(started.year, started.month, started.day, nt[0], nt[1], nt[2])
61
76
  else
62
- next_run = started + (24 * 60 * 60) # one more day
77
+ if days == 0 and started.strftime("%H:%M:%S") >= @routines[@channel_id][name][:at]
78
+ if weekly
79
+ days = 7
80
+ else
81
+ days = 1
82
+ end
83
+ end
84
+ next_run = started + (days * 24 * 60 * 60) # one more day/week
63
85
  nt = @routines[@channel_id][name][:at].split(":")
64
86
  next_run = Time.new(next_run.year, next_run.month, next_run.day, nt[0], nt[1], nt[2])
65
87
  end
@@ -32,7 +32,11 @@ class SlackSmartBot
32
32
  help = @help_messages.deep_copy
33
33
  end
34
34
  if rules_file != ""
35
- help[:rules_file] = IO.readlines(config.path+rules_file).join.scan(/#\s*help\s*\w*:(.*)/i).join("\n")
35
+ help[:rules_file] = ''
36
+ help[:rules_file] += IO.readlines(config.path+rules_file).join.scan(/#\s*help\s*\w*:(.*)/i).join("\n") + "\n"
37
+ if File.exist?(config.path+'/rules/general_rules.rb')
38
+ help[:rules_file] += IO.readlines(config.path+'/rules/general_rules.rb').join.scan(/#\s*help\s*\w*:(.*)/i).join("\n")
39
+ end
36
40
  end
37
41
  help = remove_hash_keys(help, :admin_master) unless user_type == :admin_master
38
42
  help = remove_hash_keys(help, :admin) unless user_type == :admin or user_type == :admin_master
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: slack-smart-bot
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.6
4
+ version: 1.8.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mario Ruiz
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-04-17 00:00:00.000000000 Z
11
+ date: 2020-10-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: slack-ruby-client
@@ -16,20 +16,20 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0.14'
19
+ version: '0.15'
20
20
  - - ">="
21
21
  - !ruby/object:Gem::Version
22
- version: 0.14.5
22
+ version: 0.15.1
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
26
26
  requirements:
27
27
  - - "~>"
28
28
  - !ruby/object:Gem::Version
29
- version: '0.14'
29
+ version: '0.15'
30
30
  - - ">="
31
31
  - !ruby/object:Gem::Version
32
- version: 0.14.5
32
+ version: 0.15.1
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: nice_http
35
35
  requirement: !ruby/object:Gem::Requirement
@@ -79,6 +79,9 @@ dependencies:
79
79
  - - "~>"
80
80
  - !ruby/object:Gem::Version
81
81
  version: '1'
82
+ - - ">="
83
+ - !ruby/object:Gem::Version
84
+ version: 1.2.1
82
85
  type: :runtime
83
86
  prerelease: false
84
87
  version_requirements: !ruby/object:Gem::Requirement
@@ -86,6 +89,9 @@ dependencies:
86
89
  - - "~>"
87
90
  - !ruby/object:Gem::Version
88
91
  version: '1'
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: 1.2.1
89
95
  - !ruby/object:Gem::Dependency
90
96
  name: rspec
91
97
  requirement: !ruby/object:Gem::Requirement
@@ -119,6 +125,7 @@ files:
119
125
  - LICENSE
120
126
  - README.md
121
127
  - lib/slack-smart-bot.rb
128
+ - lib/slack-smart-bot_general_rules.rb
122
129
  - lib/slack-smart-bot_rules.rb
123
130
  - lib/slack/smart-bot/comm.rb
124
131
  - lib/slack/smart-bot/comm/ask.rb
@@ -129,6 +136,7 @@ files:
129
136
  - lib/slack/smart-bot/comm/send_file.rb
130
137
  - lib/slack/smart-bot/comm/send_msg_channel.rb
131
138
  - lib/slack/smart-bot/comm/send_msg_user.rb
139
+ - lib/slack/smart-bot/comm/unreact.rb
132
140
  - lib/slack/smart-bot/commands.rb
133
141
  - lib/slack/smart-bot/commands/general/bot_help.rb
134
142
  - lib/slack/smart-bot/commands/general/bot_status.rb