slack-smart-bot 1.12.8 → 1.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +85 -12
- data/lib/slack/smart-bot/comm/respond.rb +1 -0
- data/lib/slack/smart-bot/comm/update.rb +13 -0
- data/lib/slack/smart-bot/comm.rb +1 -0
- data/lib/slack/smart-bot/commands/general/add_team.rb +1 -0
- data/lib/slack/smart-bot/commands/general/add_vacation.rb +5 -0
- data/lib/slack/smart-bot/commands/general/allow_access.rb +1 -1
- data/lib/slack/smart-bot/commands/general/delete_team.rb +1 -0
- data/lib/slack/smart-bot/commands/general/deny_access.rb +1 -1
- data/lib/slack/smart-bot/commands/general/public_holidays.rb +144 -0
- data/lib/slack/smart-bot/commands/general/see_announcements.rb +2 -2
- data/lib/slack/smart-bot/commands/general/see_memos_team.rb +202 -0
- data/lib/slack/smart-bot/commands/general/see_teams.rb +3 -175
- data/lib/slack/smart-bot/commands/general/see_vacations.rb +41 -21
- data/lib/slack/smart-bot/commands/general/set_public_holidays.rb +21 -0
- data/lib/slack/smart-bot/commands/general/update_team.rb +1 -0
- data/lib/slack/smart-bot/commands/general_bot_commands.rb +100 -8
- data/lib/slack/smart-bot/commands/on_bot/admin/add_routine.rb +27 -3
- data/lib/slack/smart-bot/commands/on_bot/admin/run_routine.rb +12 -8
- data/lib/slack/smart-bot/commands/on_bot/admin/see_routines.rb +33 -4
- data/lib/slack/smart-bot/commands/on_bot/admin/start_routine.rb +22 -1
- data/lib/slack/smart-bot/commands/on_bot/admin_master/send_message.rb +50 -4
- data/lib/slack/smart-bot/commands/on_bot/admin_master/update_message.rb +25 -0
- data/lib/slack/smart-bot/commands/on_bot/general/bot_stats.rb +8 -6
- data/lib/slack/smart-bot/commands/on_bot/repl.rb +55 -15
- data/lib/slack/smart-bot/commands/on_bot/ruby_code.rb +2 -1
- data/lib/slack/smart-bot/commands.rb +4 -0
- data/lib/slack/smart-bot/listen.rb +1 -1
- data/lib/slack/smart-bot/process.rb +36 -6
- data/lib/slack/smart-bot/process_first.rb +250 -188
- data/lib/slack/smart-bot/treat_message.rb +1 -1
- data/lib/slack/smart-bot/utils/build_help.rb +1 -1
- data/lib/slack/smart-bot/utils/create_routine_thread.rb +40 -4
- data/lib/slack/smart-bot/utils/decrypt.rb +15 -0
- data/lib/slack/smart-bot/utils/display_calendar.rb +86 -0
- data/lib/slack/smart-bot/utils/encrypt.rb +15 -0
- data/lib/slack/smart-bot/utils/encryption_get_key_iv.rb +29 -0
- data/lib/slack/smart-bot/utils/get_help.rb +1 -1
- data/lib/slack/smart-bot/utils/get_team_members.rb +39 -0
- data/lib/slack/smart-bot/utils/get_teams.rb +22 -16
- data/lib/slack/smart-bot/utils/get_vacations.rb +20 -15
- data/lib/slack/smart-bot/utils/save_stats.rb +2 -2
- data/lib/slack/smart-bot/utils/update_teams.rb +15 -9
- data/lib/slack/smart-bot/utils/update_vacations.rb +5 -3
- data/lib/slack/smart-bot/utils.rb +5 -0
- data/lib/slack-smart-bot.rb +9 -0
- data/lib/slack-smart-bot_general_commands.rb +33 -0
- data/lib/slack-smart-bot_general_rules.rb +2 -2
- data/whats_new.txt +15 -17
- metadata +27 -11
@@ -11,8 +11,6 @@ def general_bot_commands(user, command, dest, files = [])
|
|
11
11
|
display_name = user.profile.display_name
|
12
12
|
end
|
13
13
|
case command
|
14
|
-
|
15
|
-
|
16
14
|
# help: ----------------------------------------------
|
17
15
|
# help: `bot help`
|
18
16
|
# help: `bot help COMMAND`
|
@@ -29,6 +27,35 @@ def general_bot_commands(user, command, dest, files = [])
|
|
29
27
|
# help: command_id: :bot_help
|
30
28
|
# help:
|
31
29
|
|
30
|
+
# help: ----------------------------------------------
|
31
|
+
# help: `for NUMBER times every NUMBER minutes COMMAND`
|
32
|
+
# help: `for NUMBER times every NUMBER seconds COMMAND`
|
33
|
+
# help: `NUMBER times every NUMBER minutes COMMAND`
|
34
|
+
# help: `NUMBER times every NUMBER seconds COMMAND`
|
35
|
+
# help: It will run the command every NUMBER minutes or seconds for NUMBER times.
|
36
|
+
# help: max 24 times. min every 10 seconds. max every 60 minutes.
|
37
|
+
# help: Call `quit loop LOOP_ID` to stop the loop.
|
38
|
+
# help: aliases for minutes: m, minute, minutes
|
39
|
+
# help: aliases for seconds: s, sc, second, seconds
|
40
|
+
# help: Examples:
|
41
|
+
# help: _for 5 times every 1 minute ^ruby puts Time.now_
|
42
|
+
# help: _10 times every 30s !ruby puts Time.now_
|
43
|
+
# help: _24 times every 60m !get sales today_
|
44
|
+
# help: <https://github.com/MarioRuiz/slack-smart-bot#loops|more info>
|
45
|
+
# help: command_id: :create_loop
|
46
|
+
# help:
|
47
|
+
|
48
|
+
# help: ----------------------------------------------
|
49
|
+
# help: `quit loop LOOP_ID`
|
50
|
+
# help: It will stop the loop with the id LOOP_ID.
|
51
|
+
# help: Only the user who created the loop or an admin can stop it.
|
52
|
+
# help: aliases for loop: iterator, iteration
|
53
|
+
# help: aliases for quit: stop, exit, kill
|
54
|
+
# help: Examples:
|
55
|
+
# help: _quit loop 1_
|
56
|
+
# help: _stop iterator 12_
|
57
|
+
# help: <https://github.com/MarioRuiz/slack-smart-bot#loops|more info>
|
58
|
+
# help: command_id: :quit_loop
|
32
59
|
|
33
60
|
# help: ----------------------------------------------
|
34
61
|
# help: `Hi Bot`
|
@@ -575,6 +602,27 @@ def general_bot_commands(user, command, dest, files = [])
|
|
575
602
|
name = $2.downcase
|
576
603
|
delete_team(user, name)
|
577
604
|
|
605
|
+
# help: ----------------------------------------------
|
606
|
+
# help: `see MEMO_TYPE from TEAM_NAME team`
|
607
|
+
# help: `see MEMO_TYPE from TEAM_NAME team TOPIC`
|
608
|
+
# help: `see all memos from TEAM_NAME team`
|
609
|
+
# help: `see all memos from TEAM_NAME team TOPIC`
|
610
|
+
# help: It will show the memos of the team.
|
611
|
+
# help: If TOPIC is supplied it will show the memos of the topic.
|
612
|
+
# help: MEMO_TYPE: memos, notes, issues, tasks, features, bugs, jira, github. In case of 'all memos' will display all of any type.
|
613
|
+
# help: Examples:
|
614
|
+
# help: _see memos from sales team_
|
615
|
+
# help: _see bugs from sales team_
|
616
|
+
# help: _see all memos from sales team webdev_
|
617
|
+
# help: <https://github.com/MarioRuiz/slack-smart-bot#teams|more info>
|
618
|
+
# help: command_id: :see_memos_team
|
619
|
+
# help:
|
620
|
+
when /\A\s*see\s+(memo|note|issue|task|feature|bug|jira|github|all\s+memo)s?\s+(from\s+)?([\w\-]+)\s+team(.*)\s*\z/i,
|
621
|
+
/\A\s*see\s+(memo|note|issue|task|feature|bug|jira|github|all\s+memo)s?\s+(from\s+)?team\s+([\w\-]+)(.*)\s*\z/i
|
622
|
+
type = $1.downcase.to_sym
|
623
|
+
name = $3.downcase
|
624
|
+
topic = $4.strip
|
625
|
+
see_memos_team(user, type: type, name: name, topic: topic)
|
578
626
|
|
579
627
|
# help: ----------------------------------------------
|
580
628
|
# help: `add vacation from YYYY/MM/DD to YYYY/MM/DD`
|
@@ -631,16 +679,19 @@ def general_bot_commands(user, command, dest, files = [])
|
|
631
679
|
# help: `see my vacations`
|
632
680
|
# help: `see my time off`
|
633
681
|
# help: `see vacations @USER`
|
682
|
+
# help: `see my vacations YEAR`
|
634
683
|
# help: It will display current and past time off.
|
684
|
+
# help: If you call this command on a DM, it will show your vacations for the year on a calendar.
|
635
685
|
# help: <https://github.com/MarioRuiz/slack-smart-bot#time-off-management|more info>
|
636
686
|
# help: command_id: :see_vacations
|
637
687
|
# help:
|
638
|
-
when /\A\s*see\s+my\s+vacations\s*()\z/i,
|
639
|
-
/\A\s*see\s+my\s+time\s+off\s*()\z/i,
|
640
|
-
/\A\s*see\s+time\s+off\s+<@(\w+)>\s*\z/i,
|
641
|
-
/\A\s*see\s+vacations\s+<@(\w+)>\s*\z/i
|
688
|
+
when /\A\s*see\s+my\s+vacations\s*()\s*(\d{4})?\s*\z/i,
|
689
|
+
/\A\s*see\s+my\s+time\s+off\s*()\s*(\d{4})?\s*\z/i,
|
690
|
+
/\A\s*see\s+time\s+off\s+<@(\w+)>\s*\s*(\d{4})?\s*\z/i,
|
691
|
+
/\A\s*see\s+vacations\s+<@(\w+)>\s*(\d{4})?\s*\z/i
|
642
692
|
from_user = $1
|
643
|
-
|
693
|
+
year = $2
|
694
|
+
see_vacations(user, dest, from_user: from_user, year: year)
|
644
695
|
|
645
696
|
# help: ----------------------------------------------
|
646
697
|
# help: `vacations team NAME`
|
@@ -659,7 +710,48 @@ def general_bot_commands(user, command, dest, files = [])
|
|
659
710
|
date = $4.to_s
|
660
711
|
date = Date.today.strftime("%Y/%m/%d") if date.empty?
|
661
712
|
see_vacations_team(user, team_name, date)
|
662
|
-
|
713
|
+
|
714
|
+
|
715
|
+
# help: ----------------------------------------------
|
716
|
+
# help: `public holidays COUNTRY`
|
717
|
+
# help: `public holidays COUNTRY/STATE DATE`
|
718
|
+
# help: STATE: optional. If not specified, it will return all the holidays for the country.
|
719
|
+
# help: DATE: optional. It can be supplied as YYYY or YYYY-MM or YYYY-MM-DD. If not specified, it will return all the holidays for current year.
|
720
|
+
# help: Examples:
|
721
|
+
# help: _public holidays United States_
|
722
|
+
# help: _public holidays United States/California_
|
723
|
+
# help: _public holidays United States/California 2023_
|
724
|
+
# help: _public holidays Iceland 2023-12_
|
725
|
+
# help: _public holidays India 2023-12-25_
|
726
|
+
# help: command_id: :public_holidays
|
727
|
+
# help:
|
728
|
+
when /\A\s*public\s+(holiday?|vacation)s?\s+(in\s+|on\s+)?([a-zA-Z\s]+)()()()()\s*\z/i,
|
729
|
+
/\A\s*public\s+(holiday?|vacation)s?\s+(in\s+|on\s+)?([a-zA-Z\s]+)\/([a-zA-Z\s]+)()()()\s*\z/i,
|
730
|
+
/\A\s*public\s+(holiday?|vacation)s?\s+(in\s+|on\s+)?([a-zA-Z\s]+)\/([a-zA-Z\s]+)\s+(\d{4})[\/\-]?(\d\d)?[\/\-]?(\d\d)?\s*\z/i,
|
731
|
+
/\A\s*public\s+(holiday?|vacation)s?\s+(in\s+|on\s+)?([a-zA-Z\s]+)()\s+(\d{4})[\/\-]?(\d\d)?[\/\-]?(\d\d)?\s*\z/i
|
732
|
+
country = $3
|
733
|
+
state = $4.to_s
|
734
|
+
year = $5.to_s
|
735
|
+
month = $6.to_s
|
736
|
+
day = $7.to_s
|
737
|
+
year = Date.today.year if year.to_s == ''
|
738
|
+
public_holidays(country, state, year, month, day)
|
739
|
+
|
740
|
+
# help: ----------------------------------------------
|
741
|
+
# help: `set public holidays to COUNTRY/STATE`
|
742
|
+
# help: It will set the public holidays for the country and state specified.
|
743
|
+
# help: If STATE is not specified, it will set the public holidays for the country.
|
744
|
+
# help: Examples:
|
745
|
+
# help: _set public holidays to Iceland_
|
746
|
+
# help: _set public holidays to United States/California_
|
747
|
+
# help: command_id: :set_public_holidays
|
748
|
+
# help:
|
749
|
+
when /\A\s*set\s+public\s+(holiday?|vacation)s?\s+to\s+([^\/]+)\/([^\/]+)\s*\z/i,
|
750
|
+
/\A\s*set\s+public\s+(holiday?|vacation)s?\s+to\s+([^\/]+)\s*\z/i
|
751
|
+
country = $2
|
752
|
+
state = $3.to_s
|
753
|
+
set_public_holidays(country, state, user)
|
754
|
+
|
663
755
|
else
|
664
756
|
return false
|
665
757
|
end
|
@@ -11,6 +11,7 @@ class SlackSmartBot
|
|
11
11
|
# helpadmin: `add routine NAME at TIME #CHANNEL COMMAND`
|
12
12
|
# helpadmin: `add routine NAME on DAYWEEK at TIME COMMAND`
|
13
13
|
# helpadmin: `add routine NAME on DAYWEEK at TIME #CHANNEL COMMAND`
|
14
|
+
# helpadmin: `add routine NAME on the DAY_OF_MONTH at TIME COMMAND`
|
14
15
|
# helpadmin: `add routine NAME at TIME`
|
15
16
|
# helpadmin: `add silent routine NAME at TIME`
|
16
17
|
# helpadmin: `create routine NAME at TIME`
|
@@ -34,6 +35,7 @@ class SlackSmartBot
|
|
34
35
|
# helpadmin: _add bgroutine example on Mondays at 05:00 !run customer tests_
|
35
36
|
# helpadmin: _add routine example on Tuesdays at 09:00 #SREChannel !run db cleanup_
|
36
37
|
# helpadmin: _add routine example on weekdays at 22:00 suggest command_
|
38
|
+
# helpadmin: _add routine example on the 5th at 22:00 suggest command_
|
37
39
|
# helpadmin: <https://github.com/MarioRuiz/slack-smart-bot#routines|more info>
|
38
40
|
# helpadmin: command_id: :add_routine
|
39
41
|
# helpadmin:
|
@@ -53,6 +55,7 @@ class SlackSmartBot
|
|
53
55
|
every = ""
|
54
56
|
at = ""
|
55
57
|
dayweek = ''
|
58
|
+
daymonth = ''
|
56
59
|
next_run = Time.now
|
57
60
|
case period.downcase
|
58
61
|
when "days", "d"
|
@@ -68,7 +71,28 @@ class SlackSmartBot
|
|
68
71
|
every = "#{number_time} seconds"
|
69
72
|
every_in_seconds = number_time.to_i
|
70
73
|
else # time
|
71
|
-
if type != 'at' and type
|
74
|
+
if type != 'at' and type.match?(/^\d+$/) # day of month
|
75
|
+
day = type.to_i
|
76
|
+
daymonth = type
|
77
|
+
if day > 31
|
78
|
+
respond "Wrong day of month specified: *#{day}*", dest
|
79
|
+
return
|
80
|
+
end
|
81
|
+
if Date.today.day > day
|
82
|
+
next_month = Date.new(Date.today.year, Date.today.month, 1) >> 1
|
83
|
+
else
|
84
|
+
next_month = Date.new(Date.today.year, Date.today.month, 1)
|
85
|
+
end
|
86
|
+
next_month_last_day = Date.new(next_month.year, next_month.month, -1)
|
87
|
+
if day > next_month_last_day.day
|
88
|
+
next_time = Date.new(next_month.year, next_month.month, next_month_last_day.day)
|
89
|
+
else
|
90
|
+
next_time = Date.new(next_month.year, next_month.month, day)
|
91
|
+
end
|
92
|
+
days = (next_time - Date.today).to_i
|
93
|
+
every_in_seconds = days * 24 * 60 * 60 # one day
|
94
|
+
|
95
|
+
elsif type != 'at' and type!='weekday' and type!='weekend'
|
72
96
|
dayweek = type.downcase
|
73
97
|
|
74
98
|
days = ['sunday','monday','tuesday','wednesday','thursday','friday','saturday']
|
@@ -133,11 +157,11 @@ class SlackSmartBot
|
|
133
157
|
channel_id = dest if channel_id.to_s == ''
|
134
158
|
@routines[@channel_id] = {} unless @routines.key?(@channel_id)
|
135
159
|
@routines[@channel_id][name] = { channel_name: config.channel, creator: from, creator_id: user.id, status: :on,
|
136
|
-
every: every, every_in_seconds: every_in_seconds, at: at, dayweek: dayweek, file_path: file_path,
|
160
|
+
every: every, every_in_seconds: every_in_seconds, at: at, dayweek: dayweek, daymonth: daymonth, file_path: file_path,
|
137
161
|
command: command_to_run.to_s.strip, silent: silent,
|
138
162
|
next_run: next_run.to_s, dest: channel_id, last_run: "", last_elapsed: "",
|
139
163
|
running: false, routine_type: routine_type}
|
140
|
-
update_routines
|
164
|
+
update_routines()
|
141
165
|
respond "Added routine *`#{name}`* to the channel", dest
|
142
166
|
create_routine_thread(name, @routines[@channel_id][name])
|
143
167
|
end
|
@@ -38,15 +38,19 @@ class SlackSmartBot
|
|
38
38
|
respond "routine *`#{name}`*: #{stdout} #{stderr}", @routines[@channel_id][name][:dest]
|
39
39
|
end
|
40
40
|
else #command
|
41
|
-
respond "routine *`#{name}`*: #{@routines[@channel_id][name][:command]}", @routines[@channel_id][name][:dest]
|
41
|
+
message = respond "routine *`#{name}`*: #{@routines[@channel_id][name][:command]}", @routines[@channel_id][name][:dest], return_message: true
|
42
42
|
started = Time.now
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
43
|
+
data = { channel: @routines[@channel_id][name][:dest],
|
44
|
+
user: @routines[@channel_id][name][:creator_id],
|
45
|
+
text: @routines[@channel_id][name][:command],
|
46
|
+
files: nil,
|
47
|
+
routine_name: name,
|
48
|
+
routine_type: @routines[@channel_id][name][:routine_type],
|
49
|
+
routine: true }
|
50
|
+
if @routines[@channel_id][name][:command].match?(/^!!/) or @routines[@channel_id][name][:command].match?(/^\^/)
|
51
|
+
data[:ts] = message.ts
|
52
|
+
end
|
53
|
+
treat_message(data)
|
50
54
|
end
|
51
55
|
@routines[@channel_id][name][:last_elapsed] = (Time.now - started)
|
52
56
|
@routines[@channel_id][name][:last_run] = started.to_s
|
@@ -1,14 +1,17 @@
|
|
1
1
|
class SlackSmartBot
|
2
2
|
# helpadmin: ----------------------------------------------
|
3
3
|
# helpadmin: `see routines`
|
4
|
+
# helpadmin: `see routines HEADER /REGEXP/`
|
4
5
|
# helpadmin: `see all routines`
|
6
|
+
# helpadmin: `see all routines HEADER /REGEXP/`
|
5
7
|
# helpadmin: It will show the routines of the channel
|
6
|
-
# helpadmin: In case of
|
8
|
+
# helpadmin: In case of 'all' and on the master channel, it will show all the routines from all channels
|
9
|
+
# helpadmin: If you use HEADER it will show only the routines that match the REGEXP on the header. Available headers: name, creator, status, next_run, last_run, command
|
7
10
|
# helpadmin: You can use this command only if you are an admin user
|
8
11
|
# helpadmin: <https://github.com/MarioRuiz/slack-smart-bot#routines|more info>
|
9
12
|
# helpadmin: command_id: :see_routines
|
10
13
|
# helpadmin:
|
11
|
-
def see_routines(dest, from, user, all)
|
14
|
+
def see_routines(dest, from, user, all, header, regexp)
|
12
15
|
save_stats(__method__)
|
13
16
|
if is_admin?
|
14
17
|
if all
|
@@ -33,11 +36,37 @@ class SlackSmartBot
|
|
33
36
|
end
|
34
37
|
end
|
35
38
|
|
39
|
+
if header != ''
|
40
|
+
routines_filtered = {}
|
41
|
+
|
42
|
+
routines.each do |ch, rout_ch|
|
43
|
+
routines_filtered[ch] = rout_ch.dup
|
44
|
+
rout_ch.each do |k, v|
|
45
|
+
if header == 'name'
|
46
|
+
if k.match(/#{regexp}/i).nil?
|
47
|
+
routines_filtered[ch].delete(k)
|
48
|
+
end
|
49
|
+
elsif v[header.to_sym].to_s.match(/#{regexp}/i).nil?
|
50
|
+
routines_filtered[ch].delete(k)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
routines = routines_filtered
|
55
|
+
end
|
56
|
+
|
36
57
|
if routines.get_values(:channel_name).size == 0
|
37
|
-
|
58
|
+
if header != ''
|
59
|
+
respond "There are no routines added that match the header *#{header}* and the regexp *#{regexp}*.", dest
|
60
|
+
else
|
61
|
+
respond "There are no routines added.", dest
|
62
|
+
end
|
38
63
|
else
|
39
64
|
routines.each do |ch, rout_ch|
|
40
|
-
|
65
|
+
if header != ''
|
66
|
+
respond "Routines on channel *#{rout_ch.get_values(:channel_name).values.flatten.uniq[0]}* that match the header *#{header}* and the regexp *#{regexp}*", dest
|
67
|
+
else
|
68
|
+
respond "Routines on channel *#{rout_ch.get_values(:channel_name).values.flatten.uniq[0]}*", dest
|
69
|
+
end
|
41
70
|
rout_ch.each do |k, v|
|
42
71
|
msg = []
|
43
72
|
if v[:dest][0] == 'D'
|
@@ -18,7 +18,28 @@ class SlackSmartBot
|
|
18
18
|
respond "It's only possible to start routines from MASTER channel from a direct message with the bot.", dest
|
19
19
|
elsif @routines.key?(@channel_id) and @routines[@channel_id].key?(name)
|
20
20
|
@routines[@channel_id][name][:status] = :on
|
21
|
-
if @routines[@channel_id][name][:
|
21
|
+
if @routines[@channel_id][name].key?(:daymonth) and @routines[@channel_id][name][:daymonth] != ''
|
22
|
+
started = Time.now
|
23
|
+
daymonth = @routines[@channel_id][name][:daymonth]
|
24
|
+
day = daymonth.to_i
|
25
|
+
nt = @routines[@channel_id][name][:at].split(":")
|
26
|
+
if Time.now > Time.new(Time.now.year, Time.now.month, day, nt[0], nt[1], nt[2])
|
27
|
+
next_month = Date.new(Date.today.year, Date.today.month, 1) >> 1
|
28
|
+
else
|
29
|
+
next_month = Date.new(Date.today.year, Date.today.month, 1)
|
30
|
+
end
|
31
|
+
next_month_last_day = Date.new(next_month.year, next_month.month, -1)
|
32
|
+
if day > next_month_last_day.day
|
33
|
+
next_time = Date.new(next_month.year, next_month.month, next_month_last_day.day)
|
34
|
+
else
|
35
|
+
next_time = Date.new(next_month.year, next_month.month, day)
|
36
|
+
end
|
37
|
+
days = (next_time - Date.today).to_i
|
38
|
+
next_run = started + (days * 24 * 60 * 60) # one more day/week
|
39
|
+
next_run = Time.new(next_run.year, next_run.month, next_run.day, nt[0], nt[1], nt[2])
|
40
|
+
@routines[@channel_id][name][:next_run] = next_run.to_s
|
41
|
+
@routines[@channel_id][name][:sleeping] = (next_run - started).ceil
|
42
|
+
elsif @routines[@channel_id][name][:at]!=''
|
22
43
|
started = Time.now
|
23
44
|
if started.strftime("%H:%M:%S") < @routines[@channel_id][name][:at]
|
24
45
|
nt = @routines[@channel_id][name][:at].split(":")
|
@@ -7,23 +7,69 @@ class SlackSmartBot
|
|
7
7
|
# helpadmin: `send message to URL : MESSAGE`
|
8
8
|
# helpadmin: `send message to @USER1 @USER99 : MESSAGE`
|
9
9
|
# helpadmin: `send message to #CHANNEL1 #CHANNEL99 : MESSAGE`
|
10
|
+
# helpadmin: `send message to users from YYYY/MM/DD to YYYY/MM/DD #CHANNEL COMMAND_ID: MESSAGE`
|
10
11
|
# helpadmin: It will send the specified message as SmartBot
|
11
12
|
# 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
|
13
|
+
# helpadmin: In case from and to specified will send a DM to all users that have been using the SmartBot according to the SmartBot Stats. One message every 5sc. #CHANNEL and COMMAND_ID are optional filters.
|
12
14
|
# helpadmin: command_id: :send_message
|
13
15
|
# helpadmin:
|
14
|
-
def send_message(dest, from, typem, to, thread_ts, message)
|
16
|
+
def send_message(dest, from, typem, to, thread_ts, stats_from, stats_to, stats_channel_filter, stats_command_filter, message)
|
15
17
|
save_stats(__method__)
|
16
18
|
if config.masters.include?(from) and typem==:on_dm #master admin user
|
19
|
+
react :runner
|
17
20
|
unless Thread.current[:command_orig].to_s == ''
|
18
21
|
message_orig = Thread.current[:command_orig].to_s.gsub("\u00A0", " ").scan(/[^:]+\s*:\s+(.+)/im).join
|
19
22
|
message = message_orig unless message_orig == ''
|
20
23
|
end
|
21
24
|
succ = true
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
+
if stats_from!='' and stats_to!=''
|
26
|
+
users = []
|
27
|
+
user_ids = []
|
28
|
+
stats_from.gsub!('/', '-')
|
29
|
+
stats_to.gsub!('/', '-')
|
30
|
+
stats_from += " 00:00:00 +0000"
|
31
|
+
stats_to += " 23:59:59 +0000"
|
32
|
+
Dir["#{config.stats_path}.*.log"].sort.each do |file|
|
33
|
+
if file >= "#{config.stats_path}.#{stats_from[0..6]}.log" and file <= "#{config.stats_path}.#{stats_to[0..6]}.log"
|
34
|
+
CSV.foreach(file, headers: true, header_converters: :symbol, converters: :numeric) do |row|
|
35
|
+
if row[:date] >= stats_from and row[:date] <= stats_to and !users.include?(row[:user_name])
|
36
|
+
if (stats_channel_filter=='' and stats_command_filter=='') or
|
37
|
+
(stats_channel_filter!='' and stats_command_filter=='' and (row[:bot_channel_id]==stats_channel_filter or row[:dest_channel_id]==stats_channel_filter)) or
|
38
|
+
(stats_command_filter!='' and stats_channel_filter=='' and row[:command]==stats_command_filter) or
|
39
|
+
(stats_channel_filter!='' and stats_command_filter!='' and ((row[:bot_channel_id]==stats_channel_filter or row[:dest_channel_id]==stats_channel_filter) and row[:command]==stats_command_filter))
|
40
|
+
|
41
|
+
user_ids << row[:user_id]
|
42
|
+
users << row[:user_name]
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
users_success = []
|
50
|
+
users_failed = []
|
51
|
+
|
52
|
+
user_ids.each do |u|
|
53
|
+
succ = (respond message, u, thread_ts: thread_ts, web_client: true)
|
54
|
+
if succ
|
55
|
+
users_success << u
|
56
|
+
else
|
57
|
+
users_failed << u
|
58
|
+
end
|
59
|
+
sleep 5
|
60
|
+
end
|
61
|
+
respond "Users that received the message (#{users_success.size}): <@#{users_success.join('>, <@')}>", dest if users_success.size > 0
|
62
|
+
respond "Users that didn't receive the message (#{users_failed.size}): <@#{users_failed.join('>, <@')}>", dest if users_failed.size > 0
|
63
|
+
respond "No users selected to send the message.", dest if users_success.size == 0 and users_failed.size == 0
|
64
|
+
succ = false if users_failed.size > 0
|
65
|
+
else
|
66
|
+
to.each do |t|
|
67
|
+
unless t.match?(/^\s*$/)
|
68
|
+
succ = (respond message, t, thread_ts: thread_ts, web_client: true) && succ
|
69
|
+
end
|
25
70
|
end
|
26
71
|
end
|
72
|
+
unreact :runner
|
27
73
|
if succ
|
28
74
|
react :heavy_check_mark
|
29
75
|
else
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class SlackSmartBot
|
2
|
+
|
3
|
+
# helpadmin: ----------------------------------------------
|
4
|
+
# helpadmin: `update message URL TEXT`
|
5
|
+
# helpadmin: It will update the SmartBot message supplied
|
6
|
+
# 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
|
7
|
+
# helpadmin: command_id: :update_message
|
8
|
+
# helpadmin:
|
9
|
+
def update_message(from, typem, url, text)
|
10
|
+
save_stats(__method__)
|
11
|
+
channel, ts = url.scan(/\/archives\/(\w+)\/(\w\d+)/)[0]
|
12
|
+
if config.masters.include?(from) and typem==:on_dm and !channel.nil? #master admin user
|
13
|
+
ts = "#{ts[0..-7]}.#{ts[-6..-1]}"
|
14
|
+
succ = update(channel, ts, text)
|
15
|
+
if succ
|
16
|
+
react :heavy_check_mark
|
17
|
+
else
|
18
|
+
react :x
|
19
|
+
end
|
20
|
+
else
|
21
|
+
respond "Only master admin users on a private conversation with the SmartBot can update SmartBot messages"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
@@ -39,7 +39,7 @@ class SlackSmartBot
|
|
39
39
|
# help: _bot stats #sales today_
|
40
40
|
# help: _bot stats #sales from 2020-01-01 monthly_
|
41
41
|
# help: _bot stats exclude routines masters from 2021/01/01 monthly_
|
42
|
-
# help: _bot stats members #development from 2022/01/01 to 2022/01/31_
|
42
|
+
# help: _bot stats members #development from 2022/01/01 to 2022/01/31_
|
43
43
|
# help: _bot stats type_message /(on_pub|on_pg)/_
|
44
44
|
# help: <https://github.com/MarioRuiz/slack-smart-bot#bot-management|more info>
|
45
45
|
# help: command_id: :bot_stats
|
@@ -60,7 +60,7 @@ class SlackSmartBot
|
|
60
60
|
user = "" # for the case we are on the stats channel
|
61
61
|
end
|
62
62
|
if (from_user.id != user and
|
63
|
-
(config.masters.include?(from_user.name) or master_admin_users_id.include?(from_user.id) or dest == @channels_id[config.stats_channel]) and
|
63
|
+
(config.masters.include?(from_user.name) or master_admin_users_id.include?(from_user.id) or dest == @channels_id[config.stats_channel]) and
|
64
64
|
(typem == :on_dm or dest[0] == "D" or dest == @channels_id[config.stats_channel]))
|
65
65
|
on_dm_master = true #master admin user
|
66
66
|
else
|
@@ -202,7 +202,7 @@ class SlackSmartBot
|
|
202
202
|
unless header.empty?
|
203
203
|
add = true
|
204
204
|
header.each_with_index do |h, i|
|
205
|
-
if row[h.downcase.to_sym].to_s.match?(
|
205
|
+
if !row[h.downcase.to_sym].to_s.match?(/#{regexp[i]}/i)
|
206
206
|
add = false
|
207
207
|
break
|
208
208
|
end
|
@@ -297,10 +297,11 @@ class SlackSmartBot
|
|
297
297
|
message_new_users = "(#{new_users.size * 100 / users_month[k].uniq.size}%)"
|
298
298
|
end
|
299
299
|
all_users += users_month[k]
|
300
|
+
graph = ":large_yellow_square: " * (v.to_f * (10*rows_month.size) / total).round(2)
|
300
301
|
if on_dm_master
|
301
|
-
message << "\t#{k}: #{v} (#{(v.to_f * 100 / total).round(2)}%) / #{commands_month[k].uniq.size} / #{users_month[k].uniq.size} #{message_new_users}"
|
302
|
+
message << "\t#{k}: #{graph} #{v} (#{(v.to_f * 100 / total).round(2)}%) / #{commands_month[k].uniq.size} / #{users_month[k].uniq.size} #{message_new_users}"
|
302
303
|
else
|
303
|
-
message << "\t#{k}: #{v} (#{(v.to_f * 100 / total).round(2)}%) / #{commands_month[k].uniq.size}"
|
304
|
+
message << "\t#{k}: #{graph} #{v} (#{(v.to_f * 100 / total).round(2)}%) / #{commands_month[k].uniq.size}"
|
304
305
|
end
|
305
306
|
end
|
306
307
|
end
|
@@ -450,7 +451,8 @@ class SlackSmartBot
|
|
450
451
|
total_known = 0
|
451
452
|
tzone_users.each do |tzone, num|
|
452
453
|
unless tzone.to_s == ""
|
453
|
-
|
454
|
+
abb_tzone = tzone.split.map{|i| i[0,1].upcase}.join
|
455
|
+
message << "\t#{abb_tzone} _#{tzone}_: #{num} (#{(num.to_f * 100 / total_without_routines).round(2)}%)"
|
454
456
|
total_known += num
|
455
457
|
end
|
456
458
|
end
|
@@ -24,6 +24,7 @@ class SlackSmartBot
|
|
24
24
|
# 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
|
25
25
|
# help: If you want to see the methods of a class or module you created use _ls TheModuleOrClass_
|
26
26
|
# help: You can supply the Environmental Variables you need for the Session
|
27
|
+
# help: You can add collaborators by sending _add collaborator @USER_ to the session.
|
27
28
|
# help: Examples:
|
28
29
|
# help: _repl CreateCustomer LOCATION=spain HOST='https://10.30.40.50:8887'_
|
29
30
|
# help: _repl CreateCustomer: "It creates a random customer for testing" LOCATION=spain HOST='https://10.30.40.50:8887'_
|
@@ -61,7 +62,10 @@ class SlackSmartBot
|
|
61
62
|
finished: Time.now,
|
62
63
|
input: [],
|
63
64
|
on_thread: Thread.current[:on_thread],
|
64
|
-
thread_ts: Thread.current[:thread_ts]
|
65
|
+
thread_ts: Thread.current[:thread_ts],
|
66
|
+
collaborators: [],
|
67
|
+
user_type: :creator,
|
68
|
+
user_creator: from
|
65
69
|
}
|
66
70
|
|
67
71
|
unless temp_repl
|
@@ -90,6 +94,7 @@ class SlackSmartBot
|
|
90
94
|
|
91
95
|
message = "Session name: *#{session_name}*
|
92
96
|
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`.
|
97
|
+
In case you need someone to help you with the session you can add collaborators by sending `add collaborator @USER` to the session.
|
93
98
|
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`.
|
94
99
|
Use `p` to print a message raw, exacly like it is returned.
|
95
100
|
If you want to avoid a message to be treated by me, start the message with '-'.
|
@@ -239,6 +244,9 @@ class SlackSmartBot
|
|
239
244
|
rescue
|
240
245
|
end
|
241
246
|
end
|
247
|
+
@repl_sessions[from][:collaborators].each do |collaborator|
|
248
|
+
@repl_sessions.delete(collaborator)
|
249
|
+
end
|
242
250
|
@repl_sessions.delete(from)
|
243
251
|
break
|
244
252
|
end
|
@@ -280,24 +288,56 @@ class SlackSmartBot
|
|
280
288
|
code.match?(/=?\s*(require|load)(\(|\s)/i)
|
281
289
|
|
282
290
|
respond "Sorry I cannot run this due security reasons", dest
|
291
|
+
elsif code.match(/\A\s*add\s+collaborator\s+<@(\w+)>\s*\z/i)
|
292
|
+
collaborator = $1
|
293
|
+
user_info = @users.select{|u| u.id == collaborator or (u.key?(:enterprise_user) and u.enterprise_user.id == collaborator)}[-1]
|
294
|
+
collaborator_name = user_info.name
|
295
|
+
if @repl_sessions.key?(collaborator_name)
|
296
|
+
respond "Sorry, <@#{collaborator}> is already in a repl. Please ask her/him to quit it first.", dest
|
297
|
+
else
|
298
|
+
respond "Collaborator added. Now <@#{collaborator}> can interact with this repl.", dest
|
299
|
+
creator = @repl_sessions[from][:user_creator]
|
300
|
+
@repl_sessions[creator][:collaborators] << collaborator_name
|
301
|
+
@repl_sessions[collaborator_name] = {
|
302
|
+
name: @repl_sessions[from][:name],
|
303
|
+
dest: dest,
|
304
|
+
on_thread: Thread.current[:on_thread],
|
305
|
+
thread_ts: Thread.current[:thread_ts],
|
306
|
+
user_type: :collaborator,
|
307
|
+
user_creator: creator
|
308
|
+
}
|
309
|
+
end
|
283
310
|
else
|
284
|
-
@repl_sessions[from][:
|
311
|
+
if @repl_sessions[from][:user_type] == :collaborator
|
312
|
+
@repl_sessions[@repl_sessions[from][:user_creator]][:input] << code
|
313
|
+
else
|
314
|
+
@repl_sessions[from][:input] << code
|
315
|
+
end
|
285
316
|
case code
|
286
|
-
when /^\s*(quit|exit|bye|bye
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
317
|
+
when /^\s*(quit|exit|bye|bye\s+bot)\s*$/i
|
318
|
+
if @repl_sessions[from][:user_type] == :collaborator
|
319
|
+
respond "Collaborator <@#{user.id}> removed.", dest
|
320
|
+
@repl_sessions[@repl_sessions[from][:user_creator]][:collaborators].delete(from)
|
321
|
+
@repl_sessions.delete(from)
|
322
|
+
else
|
323
|
+
open("#{config.path}/repl/#{@channel_id}/#{@repl_sessions[from][:name]}.input", 'a+') {|f|
|
324
|
+
f.puts code
|
325
|
+
}
|
326
|
+
respond "REPL session finished: #{@repl_sessions[from][:name]}", dest
|
327
|
+
unreact :running, @ts_react[@repl_sessions[from].name]
|
328
|
+
pids = `pgrep -P #{@repl_sessions[from][:pid]}`.split("\n").map(&:to_i) #todo: it needs to be adapted for Windows
|
329
|
+
pids.each do |pid|
|
330
|
+
begin
|
331
|
+
Process.kill("KILL", pid)
|
332
|
+
rescue
|
333
|
+
end
|
334
|
+
end
|
335
|
+
@repl_sessions[from][:collaborators].each do |collaborator|
|
336
|
+
@repl_sessions.delete(collaborator)
|
297
337
|
end
|
338
|
+
@repl_sessions.delete(from)
|
298
339
|
end
|
299
|
-
|
300
|
-
when /^\s*-/i
|
340
|
+
when /\A\s*-/i
|
301
341
|
#ommit
|
302
342
|
else
|
303
343
|
if @ts_repl[@repl_sessions[from].name].to_s == ''
|
@@ -28,7 +28,8 @@ class SlackSmartBot
|
|
28
28
|
respond "Running", dest if code.size > 200
|
29
29
|
|
30
30
|
begin
|
31
|
-
code
|
31
|
+
#todo: check. Commented next line because it was causing problems with the code, for the case the line was for example any of these chars: { } [ ] ( ) < > | & ; $ ` " ' \ * ? ~ # = ! ^ -
|
32
|
+
#code.gsub!(/^\W*$/, "") #to remove special chars from slack when copy/pasting
|
32
33
|
code.gsub!('$','\$') #to take $ as literal, fex: puts '$lolo' => puts '\$lolo'
|
33
34
|
ruby = "ruby -e \"#{code.gsub('"', '\"')}\""
|
34
35
|
if defined?(project_folder) and project_folder.to_s != "" and Dir.exist?(project_folder)
|
@@ -36,6 +36,7 @@ require_relative "commands/on_extended/bot_rules"
|
|
36
36
|
require_relative "commands/on_bot/admin_master/get_bot_logs"
|
37
37
|
require_relative "commands/on_bot/admin_master/send_message"
|
38
38
|
require_relative "commands/on_bot/admin_master/delete_message"
|
39
|
+
require_relative "commands/on_bot/admin_master/update_message"
|
39
40
|
require_relative "commands/on_bot/admin_master/react_to"
|
40
41
|
require_relative "commands/on_bot/general/bot_stats"
|
41
42
|
require_relative "commands/on_bot/general/leaderboard"
|
@@ -63,6 +64,7 @@ require_relative "commands/general/add_team"
|
|
63
64
|
require_relative "commands/general/add_memo_team"
|
64
65
|
require_relative "commands/general/set_memo_status"
|
65
66
|
require_relative "commands/general/delete_memo_team"
|
67
|
+
require_relative "commands/general/see_memos_team"
|
66
68
|
require_relative "commands/general/see_teams"
|
67
69
|
require_relative "commands/general/update_team"
|
68
70
|
require_relative "commands/general/ping_team"
|
@@ -71,3 +73,5 @@ require_relative "commands/general/add_vacation"
|
|
71
73
|
require_relative "commands/general/remove_vacation"
|
72
74
|
require_relative "commands/general/see_vacations"
|
73
75
|
require_relative "commands/general/see_vacations_team"
|
76
|
+
require_relative "commands/general/public_holidays"
|
77
|
+
require_relative "commands/general/set_public_holidays"
|
@@ -5,7 +5,7 @@ class SlackSmartBot
|
|
5
5
|
@last_activity_check = Time.now
|
6
6
|
get_bots_created()
|
7
7
|
@buffer_complete = [] unless defined?(@buffer_complete)
|
8
|
-
b = File.read("#{config.path}/buffer_complete.log")
|
8
|
+
b = File.read("#{config.path}/buffer_complete.log", encoding: "UTF-8")
|
9
9
|
result = b.scan(/^\|(\w+)\|(\w+)\|(\w+)\|([^~]+)~~~/m)
|
10
10
|
result.delete(nil)
|
11
11
|
new_messages = result[@buffer_complete.size..-1]
|