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
@@ -62,11 +62,12 @@ class SlackSmartBot
|
|
62
62
|
File.write("#{config.path}/routines/#{@channel_id}/#{name}_output.txt", stdout.to_s+stderr.to_s, mode: "a+")
|
63
63
|
end
|
64
64
|
else #command
|
65
|
+
message = nil
|
65
66
|
if !@routines[@channel_id][name][:silent] and !config.on_maintenance
|
66
67
|
if @routines[@channel_id][name][:dest]!=@channel_id
|
67
|
-
respond "routine from <##{@channel_id}> *`#{name}`*: #{@routines[@channel_id][name][:command]}", @routines[@channel_id][name][:dest]
|
68
|
+
message = respond "routine from <##{@channel_id}> *`#{name}`*: #{@routines[@channel_id][name][:command]}", @routines[@channel_id][name][:dest], return_message: true
|
68
69
|
else
|
69
|
-
respond "routine *`#{name}`*: #{@routines[@channel_id][name][:command]}", @routines[@channel_id][name][:dest]
|
70
|
+
message = respond "routine *`#{name}`*: #{@routines[@channel_id][name][:command]}", @routines[@channel_id][name][:dest], return_message: true
|
70
71
|
end
|
71
72
|
end
|
72
73
|
started = Time.now
|
@@ -78,6 +79,9 @@ class SlackSmartBot
|
|
78
79
|
routine: true,
|
79
80
|
routine_name: name,
|
80
81
|
routine_type: hroutine[:routine_type] }
|
82
|
+
if !message.nil? and (@routines[@channel_id][name][:command].match?(/^!!/) or @routines[@channel_id][name][:command].match?(/^\^/))
|
83
|
+
data[:ts] = message.ts
|
84
|
+
end
|
81
85
|
treat_message(data)
|
82
86
|
end
|
83
87
|
# in case the routine was deleted while running the process
|
@@ -95,7 +99,24 @@ class SlackSmartBot
|
|
95
99
|
require "time"
|
96
100
|
every_in_seconds = Time.parse(@routines[@channel_id][name][:next_run]) - Time.now
|
97
101
|
elsif @routines[@channel_id][name][:at] != "" #coming from start after pause for 'at'
|
98
|
-
if @routines[@channel_id][name].key?(:
|
102
|
+
if @routines[@channel_id][name].key?(:daymonth) and @routines[@channel_id][name][:daymonth].to_s!='' # day of month
|
103
|
+
weekly = false
|
104
|
+
daymonth = @routines[@channel_id][name][:daymonth]
|
105
|
+
day = daymonth.to_i
|
106
|
+
if Date.today.day > day
|
107
|
+
next_month = Date.new(Date.today.year, Date.today.month, 1) >> 1
|
108
|
+
else
|
109
|
+
next_month = Date.new(Date.today.year, Date.today.month, 1)
|
110
|
+
end
|
111
|
+
next_month_last_day = Date.new(next_month.year, next_month.month, -1)
|
112
|
+
if day > next_month_last_day.day
|
113
|
+
next_time = Date.new(next_month.year, next_month.month, next_month_last_day.day)
|
114
|
+
else
|
115
|
+
next_time = Date.new(next_month.year, next_month.month, day)
|
116
|
+
end
|
117
|
+
days = (next_time - Date.today).to_i
|
118
|
+
every_in_seconds = Time.parse(@routines[@channel_id][name][:next_run]) - Time.now
|
119
|
+
elsif @routines[@channel_id][name].key?(:dayweek) and @routines[@channel_id][name][:dayweek].to_s!='' and
|
99
120
|
@routines[@channel_id][name][:dayweek].to_s!='weekend' and @routines[@channel_id][name][:dayweek].to_s!='weekday'
|
100
121
|
|
101
122
|
day = @routines[@channel_id][name][:dayweek]
|
@@ -126,10 +147,25 @@ class SlackSmartBot
|
|
126
147
|
if started.strftime("%H:%M:%S") < @routines[@channel_id][name][:at] and days == 0
|
127
148
|
nt = @routines[@channel_id][name][:at].split(":")
|
128
149
|
next_run = Time.new(started.year, started.month, started.day, nt[0], nt[1], nt[2])
|
129
|
-
else
|
150
|
+
else
|
130
151
|
if days == 0 and started.strftime("%H:%M:%S") >= @routines[@channel_id][name][:at]
|
131
152
|
if weekly
|
132
153
|
days = 7
|
154
|
+
elsif @routines[@channel_id][name].key?(:daymonth) and @routines[@channel_id][name][:daymonth].to_s!=''
|
155
|
+
daymonth = @routines[@channel_id][name][:daymonth]
|
156
|
+
day = daymonth.to_i
|
157
|
+
if Date.today.day >= day
|
158
|
+
next_month = Date.new(Date.today.year, Date.today.month, 1) >> 1
|
159
|
+
else
|
160
|
+
next_month = Date.new(Date.today.year, Date.today.month, 1)
|
161
|
+
end
|
162
|
+
next_month_last_day = Date.new(next_month.year, next_month.month, -1)
|
163
|
+
if day > next_month_last_day.day
|
164
|
+
next_time = Date.new(next_month.year, next_month.month, next_month_last_day.day)
|
165
|
+
else
|
166
|
+
next_time = Date.new(next_month.year, next_month.month, day)
|
167
|
+
end
|
168
|
+
days = (next_time - Date.today).to_i
|
133
169
|
else
|
134
170
|
days = 1
|
135
171
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class SlackSmartBot
|
2
|
+
def decrypt(data)
|
3
|
+
require "openssl"
|
4
|
+
require "base64"
|
5
|
+
|
6
|
+
key, iv = encryption_get_key_iv()
|
7
|
+
encrypted = Base64.decode64(data)
|
8
|
+
cipher = OpenSSL::Cipher.new("AES-256-CBC")
|
9
|
+
cipher.decrypt
|
10
|
+
cipher.key = key
|
11
|
+
cipher.iv = iv
|
12
|
+
plain = cipher.update(encrypted) + cipher.final
|
13
|
+
return plain
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
class SlackSmartBot
|
2
|
+
def display_calendar(from_user_name, year)
|
3
|
+
if @vacations.key?(from_user_name) and @vacations[from_user_name][:public_holidays].to_s != ""
|
4
|
+
country_region = @vacations[from_user_name][:public_holidays].downcase
|
5
|
+
elsif config[:public_holidays].key?(:default_calendar)
|
6
|
+
country_region = config[:public_holidays][:default_calendar].downcase
|
7
|
+
else
|
8
|
+
country_region = ""
|
9
|
+
end
|
10
|
+
country, location = country_region.split("/")
|
11
|
+
public_holidays(country.to_s, location.to_s, year, "", "", add_stats: false, publish_results: false)
|
12
|
+
messages = ["*Time off #{year}*"]
|
13
|
+
days_of_vacations = 0
|
14
|
+
(1..12).each do |m|
|
15
|
+
date = Date.parse("#{year}/#{m}/1")
|
16
|
+
month_name = date.strftime("%B")
|
17
|
+
month_line = ""
|
18
|
+
(1..6).each do |w|
|
19
|
+
if date.month == m
|
20
|
+
month_line += "#{date.strftime("%d")} "
|
21
|
+
else
|
22
|
+
month_line += ":white_small_square: "
|
23
|
+
end
|
24
|
+
|
25
|
+
if @public_holidays.key?(country_region) and @public_holidays[country_region].key?(year.to_s)
|
26
|
+
phd = @public_holidays[country_region][year.to_s].date.iso
|
27
|
+
else
|
28
|
+
phd = []
|
29
|
+
end
|
30
|
+
(1..7).each do |d|
|
31
|
+
wday = date.wday
|
32
|
+
wday = 7 if wday == 0
|
33
|
+
break if d >= 3 and w == 6 # week 6 cannot be more than wednesday
|
34
|
+
date_text = date.strftime("%Y-%m-%d")
|
35
|
+
if wday == d and date.month == m
|
36
|
+
vacations_set = false
|
37
|
+
public_holiday_set = false
|
38
|
+
if phd.include?(date_text)
|
39
|
+
month_line += ":large_red_square: "
|
40
|
+
public_holiday_set = true
|
41
|
+
end
|
42
|
+
if !public_holiday_set
|
43
|
+
if @vacations.key?(from_user_name) and @vacations[from_user_name].key?(:periods)
|
44
|
+
@vacations[from_user_name][:periods].each do |period|
|
45
|
+
if date >= Date.parse(period[:from]) and date <= Date.parse(period[:to])
|
46
|
+
if period[:type] == "sick"
|
47
|
+
month_line += ":face_with_thermometer: "
|
48
|
+
elsif period[:type] == "sick child"
|
49
|
+
month_line += ":baby: "
|
50
|
+
elsif period[:type] == "vacation"
|
51
|
+
month_line += ":palm_tree: "
|
52
|
+
if wday <= 5
|
53
|
+
days_of_vacations += 1
|
54
|
+
end
|
55
|
+
end
|
56
|
+
vacations_set = true
|
57
|
+
break
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
if !vacations_set
|
62
|
+
if wday == 6 || wday == 7
|
63
|
+
month_line += ":large_yellow_square: "
|
64
|
+
else
|
65
|
+
month_line += ":white_square: "
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
date += 1
|
70
|
+
else
|
71
|
+
month_line += ":white_small_square: "
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
messages << "#{month_line} #{month_name}\n"
|
76
|
+
end
|
77
|
+
messages << "\n\n:large_yellow_square: weekend / :white_square: weekday / :white_small_square: not in month / :large_red_square: Public Holiday / :palm_tree: Vacation / :face_with_thermometer: Sick / :baby: Sick child"
|
78
|
+
if country_region != ""
|
79
|
+
messages << "Your public holidays are set for #{country_region.downcase}. Call `set public holidays to COUNTRY/REGION` if you want to change it.\n"
|
80
|
+
else
|
81
|
+
messages << "Your public holidays are not set. Call `set public holidays to COUNTRY/REGION` to set it.\n"
|
82
|
+
end
|
83
|
+
messages << "You have spent #{days_of_vacations} days of vacations in #{year} considering only weekdays.\n\n"
|
84
|
+
respond messages.join("\n")
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class SlackSmartBot
|
2
|
+
def encrypt(data)
|
3
|
+
require "openssl"
|
4
|
+
require "base64"
|
5
|
+
|
6
|
+
key, iv = encryption_get_key_iv()
|
7
|
+
cipher = OpenSSL::Cipher::Cipher.new "AES-256-CBC"
|
8
|
+
cipher.encrypt
|
9
|
+
cipher.key = key
|
10
|
+
cipher.iv = iv
|
11
|
+
encrypted = cipher.update(data) + cipher.final
|
12
|
+
encrypted = Base64.encode64(encrypted)
|
13
|
+
return encrypted
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class SlackSmartBot
|
2
|
+
def encryption_get_key_iv
|
3
|
+
if defined?(@encryption_key_built)
|
4
|
+
key = @encryption_key_built
|
5
|
+
iv = @encryption_iv_built
|
6
|
+
else
|
7
|
+
if config.key?(:encryption) and config.encryption.key?(:key) and config.encryption.key?(:iv)
|
8
|
+
key = config[:encryption][:key]
|
9
|
+
iv = config[:encryption][:iv]
|
10
|
+
else
|
11
|
+
key = (Socket.gethostname + config.token.reverse)[0..49]
|
12
|
+
iv = config.token[0..15]
|
13
|
+
end
|
14
|
+
|
15
|
+
#Convert from hex to raw bytes:
|
16
|
+
key = [key].pack('H*')
|
17
|
+
#Pad with zero bytes to correct length:
|
18
|
+
key << ("\x00" * (32 - key.length))
|
19
|
+
|
20
|
+
#Convert from hex to raw bytes:
|
21
|
+
iv = [iv].pack('H*')
|
22
|
+
#Pad with zero bytes to correct length:
|
23
|
+
iv << ("\x00" * (16 - iv.length))
|
24
|
+
@encryption_key_built = key
|
25
|
+
@encryption_iv_built = iv
|
26
|
+
end
|
27
|
+
return key, iv
|
28
|
+
end
|
29
|
+
end
|
@@ -4,7 +4,7 @@ class SlackSmartBot
|
|
4
4
|
general: [:bot_help, :hi_bot, :bye_bot, :add_admin, :remove_admin, :see_admins, :poster, :add_announcement, :delete_announcement,
|
5
5
|
:see_announcements, :see_command_ids, :share_messages, :see_shares, :delete_share, :see_favorite_commands, :see_statuses,
|
6
6
|
:allow_access, :see_access, :deny_access, :add_team, :add_memo_team, :delete_memo_team, :set_memo_status, :see_teams, :update_team, :ping_team, :delete_team,
|
7
|
-
|
7
|
+
:see_memos_team, :add_vacation, :remove_vacation, :see_vacations, :see_vacations_team, :public_holidays, :create_loop, :quit_loop],
|
8
8
|
on_bot_general: [:whats_new, :suggest_command, :bot_status, :use_rules, :stop_using_rules, :bot_stats, :leaderboard],
|
9
9
|
on_bot: [:ruby_code, :repl, :get_repl, :run_repl, :delete_repl, :see_repls, :kill_repl, :add_shortcut, :delete_shortcut, :see_shortcuts],
|
10
10
|
on_bot_admin: [:extend_rules, :stop_using_rules_on, :start_bot, :pause_bot, :add_routine,
|
@@ -0,0 +1,39 @@
|
|
1
|
+
class SlackSmartBot
|
2
|
+
def get_team_members(team)
|
3
|
+
assigned_members = team.members.values.flatten
|
4
|
+
assigned_members.uniq!
|
5
|
+
assigned_members.dup.each do |m|
|
6
|
+
user_info = @users.select { |u| u.id == m or (u.key?(:enterprise_user) and u.enterprise_user.id == m) or u.name == m or (u.key?(:enterprise_user) and u.enterprise_user.name == m) }[-1]
|
7
|
+
assigned_members.delete(m) if user_info.nil? or user_info.deleted
|
8
|
+
end
|
9
|
+
channels_members = []
|
10
|
+
all_team_members = assigned_members.dup
|
11
|
+
if team.channels.key?("members")
|
12
|
+
team_members = []
|
13
|
+
team.channels["members"].each do |ch|
|
14
|
+
get_channels_name_and_id() unless @channels_id.key?(ch)
|
15
|
+
tm = get_channel_members(@channels_id[ch])
|
16
|
+
if tm.nil?
|
17
|
+
respond ":exclamation: Add the Smart Bot to *##{ch}* channel to be able to get the list of members.", dest
|
18
|
+
else
|
19
|
+
channels_members << @channels_id[ch]
|
20
|
+
tm.each do |m|
|
21
|
+
user_info = @users.select { |u| u.id == m or (u.key?(:enterprise_user) and u.enterprise_user.id == m) }[-1]
|
22
|
+
team_members << user_info.name unless user_info.is_app_user or user_info.is_bot
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
team_members.flatten!
|
27
|
+
team_members.uniq!
|
28
|
+
unassigned_members = team_members - assigned_members
|
29
|
+
unassigned_members.delete(config.nick)
|
30
|
+
not_on_team_channel = assigned_members - team_members
|
31
|
+
all_team_members += team_members
|
32
|
+
else
|
33
|
+
unassigned_members = []
|
34
|
+
not_on_team_channel = []
|
35
|
+
end
|
36
|
+
|
37
|
+
return assigned_members, unassigned_members, not_on_team_channel, channels_members, all_team_members
|
38
|
+
end
|
39
|
+
end
|
@@ -1,22 +1,28 @@
|
|
1
1
|
class SlackSmartBot
|
2
2
|
def get_teams
|
3
3
|
@teams ||= {}
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
4
|
+
old_teams_file = config.file_path.gsub(".rb", "_teams.yaml") #to be backward compatible
|
5
|
+
require 'yaml'
|
6
|
+
if File.exist?(old_teams_file)
|
7
|
+
@logger.info 'Migrating teams to new format'
|
8
|
+
teams = YAML.load(File.read(old_teams_file))
|
9
|
+
@logger.info "@teams: #{teams.inspect}}"
|
10
|
+
teams.each do |key, value|
|
11
|
+
File.write(File.join(config.path, "teams", "t_#{key}.yaml"), encrypt(value.to_yaml))
|
12
|
+
end
|
13
|
+
@logger.info "Deleting old_teams_file: #{old_teams_file}"
|
14
|
+
File.delete(old_teams_file)
|
15
|
+
end
|
16
|
+
files = Dir.glob(File.join(config.path, "teams", "t_*.yaml"))
|
17
|
+
@datetime_teams_file ||= {}
|
18
|
+
files.each do |file|
|
19
|
+
if !defined?(@datetime_teams_file) or !@datetime_teams_file.key?(file) or @datetime_teams_file[file] != File.mtime(file)
|
20
|
+
teams_team = YAML.load(decrypt(File.read(file)))
|
21
|
+
team_name = File.basename(file).gsub("t_","").gsub(".yaml","")
|
22
|
+
teams_team[:name] = team_name unless teams_team.key?(:name) #to be backward compatible
|
23
|
+
@teams[team_name.to_sym] = teams_team
|
24
|
+
@datetime_teams_file[file] = File.mtime(file)
|
19
25
|
end
|
20
26
|
end
|
21
27
|
end
|
22
|
-
end
|
28
|
+
end
|
@@ -1,21 +1,26 @@
|
|
1
1
|
class SlackSmartBot
|
2
2
|
def get_vacations
|
3
3
|
@vacations ||= {}
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
4
|
+
old_vacations_file = config.file_path.gsub(".rb", "_vacations.yaml") #to be backward compatible
|
5
|
+
require 'yaml'
|
6
|
+
if File.exist?(old_vacations_file)
|
7
|
+
@logger.info 'Migrating vacations to new format'
|
8
|
+
vacations = @vacations
|
9
|
+
vacations = YAML.load(File.read(old_vacations_file))
|
10
|
+
@vacations = vacations unless vacations.is_a?(FalseClass)
|
11
|
+
@vacations.each do |key, value|
|
12
|
+
File.write(File.join(config.path, "vacations", "v_#{key}.yaml"), encrypt(value.to_yaml))
|
13
|
+
end
|
14
|
+
@logger.info "Deleting old_vacations_file: #{old_vacations_file}"
|
15
|
+
File.delete(old_vacations_file)
|
16
|
+
end
|
17
|
+
files = Dir.glob(File.join(config.path, "vacations", "v_*.yaml"))
|
18
|
+
@datetime_vacations_file ||= {}
|
19
|
+
files.each do |file|
|
20
|
+
if !defined?(@datetime_vacations_file) or !@datetime_vacations_file.key?(file) or @datetime_vacations_file[file] != File.mtime(file)
|
21
|
+
vacations_user = YAML.load(decrypt(File.read(file)))
|
22
|
+
@vacations[File.basename(file).gsub("v_","").gsub(".yaml","")] = vacations_user
|
23
|
+
@datetime_vacations_file[file] = File.mtime(file)
|
19
24
|
end
|
20
25
|
end
|
21
26
|
end
|
@@ -1,16 +1,22 @@
|
|
1
1
|
class SlackSmartBot
|
2
2
|
def update_teams(team=nil)
|
3
3
|
require 'yaml'
|
4
|
-
|
4
|
+
if team.nil?
|
5
|
+
teams = @teams.keys
|
6
|
+
else
|
5
7
|
get_teams()
|
6
8
|
@teams.merge!(team)
|
9
|
+
teams = team.keys
|
10
|
+
end
|
11
|
+
|
12
|
+
teams.each do |team|
|
13
|
+
team_file = File.join(config.path, "teams", "t_#{team}.yaml")
|
14
|
+
File.open(team_file, 'w') {|file|
|
15
|
+
file.flock(File::LOCK_EX)
|
16
|
+
file.write(encrypt(@teams[team].to_yaml))
|
17
|
+
file.flock(File::LOCK_UN)
|
18
|
+
}
|
19
|
+
@datetime_teams_file[team_file] = File.mtime(team_file)
|
7
20
|
end
|
8
|
-
teams_file = config.file_path.gsub(".rb", "_teams.yaml")
|
9
|
-
File.open(teams_file, 'w') {|file|
|
10
|
-
file.flock(File::LOCK_EX)
|
11
|
-
file.write(@teams.to_yaml)
|
12
|
-
file.flock(File::LOCK_UN)
|
13
|
-
}
|
14
|
-
@datetime_teams_file = File.mtime(teams_file)
|
15
21
|
end
|
16
|
-
end
|
22
|
+
end
|
@@ -5,12 +5,14 @@ class SlackSmartBot
|
|
5
5
|
get_vacations()
|
6
6
|
@vacations.merge!(vacation)
|
7
7
|
end
|
8
|
-
|
8
|
+
user = Thread.current[:user]
|
9
|
+
vacations_file = File.join(config.path, "vacations", "v_#{user.name}.yaml")
|
10
|
+
|
9
11
|
File.open(vacations_file, 'w') {|file|
|
10
12
|
file.flock(File::LOCK_EX)
|
11
|
-
file.write(@vacations.to_yaml)
|
13
|
+
file.write(encrypt(@vacations[user.name].to_yaml))
|
12
14
|
file.flock(File::LOCK_UN)
|
13
15
|
}
|
14
|
-
@datetime_vacations_file = File.mtime(vacations_file)
|
16
|
+
@datetime_vacations_file[vacations_file] = File.mtime(vacations_file)
|
15
17
|
end
|
16
18
|
end
|
@@ -29,4 +29,9 @@ require_relative 'utils/get_vacations'
|
|
29
29
|
require_relative 'utils/update_teams'
|
30
30
|
require_relative 'utils/update_vacations'
|
31
31
|
require_relative 'utils/check_vacations'
|
32
|
+
require_relative 'utils/display_calendar'
|
33
|
+
require_relative 'utils/encryption_get_key_iv'
|
34
|
+
require_relative 'utils/encrypt'
|
35
|
+
require_relative 'utils/decrypt'
|
36
|
+
require_relative 'utils/get_team_members'
|
32
37
|
|
data/lib/slack-smart-bot.rb
CHANGED
@@ -54,6 +54,10 @@ class SlackSmartBot
|
|
54
54
|
config[:github] = {token: '' } unless config.key?(:github) and config[:github].key?(:token)
|
55
55
|
config[:github][:host] ||= "https://api.github.com"
|
56
56
|
config[:github][:host] = "https://#{config[:github][:host]}" unless config[:github][:host] == '' or config[:github][:host].match?(/^http/)
|
57
|
+
config[:public_holidays] = { api_key: '' } unless config.key?(:public_holidays) and config[:public_holidays].key?(:api_key)
|
58
|
+
config[:public_holidays][:host] ||= "https://calendarific.com"
|
59
|
+
config[:public_holidays][:host] = "https://#{config[:public_holidays][:host]}" unless config[:public_holidays][:host] == '' or config[:public_holidays][:host].match?(/^http/)
|
60
|
+
|
57
61
|
if config.path.to_s!='' and config.file.to_s==''
|
58
62
|
config.file = File.basename($0)
|
59
63
|
end
|
@@ -74,6 +78,8 @@ class SlackSmartBot
|
|
74
78
|
Dir.mkdir("#{config.path}/announcements") unless Dir.exist?("#{config.path}/announcements")
|
75
79
|
Dir.mkdir("#{config.path}/shares") unless Dir.exist?("#{config.path}/shares")
|
76
80
|
Dir.mkdir("#{config.path}/rules") unless Dir.exist?("#{config.path}/rules")
|
81
|
+
Dir.mkdir("#{config.path}/vacations") unless Dir.exist?("#{config.path}/vacations")
|
82
|
+
Dir.mkdir("#{config.path}/teams") unless Dir.exist?("#{config.path}/teams")
|
77
83
|
File.delete("#{config.path}/config_tmp.status") if File.exist?("#{config.path}/config_tmp.status")
|
78
84
|
|
79
85
|
config.masters = MASTER_USERS if config.masters.to_s=='' and defined?(MASTER_USERS)
|
@@ -202,6 +208,8 @@ class SlackSmartBot
|
|
202
208
|
@last_status_change = Time.now
|
203
209
|
@vacations_check = (Date.today - 1)
|
204
210
|
@announcements_activity_after = Hash.new()
|
211
|
+
@public_holidays = Hash.new()
|
212
|
+
@loops = Hash.new()
|
205
213
|
|
206
214
|
if File.exist?("#{config.path}/shortcuts/#{config.shortcuts_file}".gsub('.yaml','.rb')) #backwards compatible
|
207
215
|
file_conf = IO.readlines("#{config.path}/shortcuts/#{config.shortcuts_file}".gsub('.yaml','.rb')).join
|
@@ -317,6 +325,7 @@ class SlackSmartBot
|
|
317
325
|
get_shares()
|
318
326
|
get_admins_channels()
|
319
327
|
get_access_channels()
|
328
|
+
get_vacations()
|
320
329
|
|
321
330
|
if @routines.key?(@channel_id)
|
322
331
|
@routines[@channel_id].each do |k, v|
|
@@ -19,6 +19,39 @@ def general_commands(user, command, dest, files = [])
|
|
19
19
|
lines = 200 if lines > 200
|
20
20
|
respond (">#{"\n"*lines}<")
|
21
21
|
|
22
|
+
# help: ----------------------------------------------
|
23
|
+
# help: `blink TEXT`
|
24
|
+
# help: `INTEGER blink TEXT`
|
25
|
+
# help: It will blink the text supplied. One or more lines of text. Emoticons or text format are allowed.
|
26
|
+
# help: INTEGER (optional): number of times. Default 50. Max 200.
|
27
|
+
# help: Examples:
|
28
|
+
# help: blink Hello World!
|
29
|
+
# help: blink :moneybag: Pay attention! *Sales* are published!
|
30
|
+
# help: 100 blink :new: *Party is about to start* :i_love_you_hand_sign:
|
31
|
+
# help: command_id: :blink
|
32
|
+
# help:
|
33
|
+
when /\A\s*(\d+)?\s*blink\s+(.+)\s*\z/im
|
34
|
+
save_stats :blink
|
35
|
+
num_times = $1.to_s == '' ? 50 : $1.to_i
|
36
|
+
text = $2
|
37
|
+
@blinking ||= []
|
38
|
+
if num_times > 200 or num_times < 1
|
39
|
+
respond "The number of times must be between 1 and 200"
|
40
|
+
elsif @blinking.include?(user.name)
|
41
|
+
respond "I'm already blinking something for you. Please wait until I finish"
|
42
|
+
elsif @blinking.size >= 3 # rate limit in theory update can be done only once per second
|
43
|
+
respond "I'm already blinking something for too many people. Please wait until I finish at least one of them."
|
44
|
+
else
|
45
|
+
@blinking << user.name
|
46
|
+
msg = respond(text, return_message: true)
|
47
|
+
num_times.times do
|
48
|
+
sleep 2
|
49
|
+
update(dest, msg.ts, ' ')
|
50
|
+
sleep 0.5
|
51
|
+
update(dest, msg.ts, text)
|
52
|
+
end
|
53
|
+
@blinking.delete(user.name)
|
54
|
+
end
|
22
55
|
|
23
56
|
# this is a hidden command that it is not listed when calling bot help
|
24
57
|
when /\s*(that's\s+)?(thanks|thank\s+you|I\s+love\s+you|nice|cool)\s+(#{@salutations.join("|")})\s*!*\s*$/i
|
@@ -8,8 +8,8 @@ def general_rules(user, command, processed, dest, files = [], rules_file = "")
|
|
8
8
|
|
9
9
|
# help: ----------------------------------------------
|
10
10
|
# help: `echo SOMETHING`
|
11
|
-
# help: `
|
12
|
-
# help: repeats SOMETHING. If
|
11
|
+
# help: `NUMBER echo SOMETHING`
|
12
|
+
# help: repeats SOMETHING. If NUMBER supplied then that number of times.
|
13
13
|
# help: Examples:
|
14
14
|
# help: _echo I am the Smart Bot_
|
15
15
|
# help: _100 echo :heart:_
|
data/whats_new.txt
CHANGED
@@ -1,23 +1,21 @@
|
|
1
|
-
*Version 1.
|
1
|
+
*Version 1.13.0* Released 2023-Mar-01
|
2
2
|
|
3
3
|
*For General users*
|
4
|
-
-
|
5
|
-
-
|
6
|
-
-
|
7
|
-
-
|
8
|
-
- `
|
9
|
-
-
|
10
|
-
-
|
11
|
-
- Added 'Time off' (Vacation/Sick/Sick Child) management. The SmartBot will automatically set your status on the periods specified. It will be possible to see the 'Time off' plan for a specific team and period. (<https://github.com/MarioRuiz/slack-smart-bot/issues/73|#73>)
|
12
|
-
- More natural language for 'Time off' command: (<https://github.com/MarioRuiz/slack-smart-bot/issues/80|#80>)
|
4
|
+
- It is possible to run any command on a loop: `for 3 times every 5 minutes !ruby puts Time.now` (<https://github.com/MarioRuiz/slack-smart-bot/issues/83|#83>).
|
5
|
+
- You can add collaborators to your REPL by sending `add collaborator @USER` to the session. (<https://github.com/MarioRuiz/slack-smart-bot/issues/85|#85>).
|
6
|
+
- If using the `monthly` option when calling `bot stats` it will show a graph (<https://github.com/MarioRuiz/slack-smart-bot/issues/86|#86>).
|
7
|
+
- New `public holidays COUNTRY/REGION` command (<https://github.com/MarioRuiz/slack-smart-bot/issues/88|#88>)
|
8
|
+
- When calling `see my vacations` on a DM will display a calendar of the year with the days off, including public holidays (<https://github.com/MarioRuiz/slack-smart-bot/issues/89|#89>)
|
9
|
+
- `set public holidays to COUNTRY/REGION` will set the public holidays for the country and region specified. (<https://github.com/MarioRuiz/slack-smart-bot/issues/90|#90>)
|
10
|
+
- `see MEMO_TYPE from TEAM_NAME team` will show the memos of the team. (<https://github.com/MarioRuiz/slack-smart-bot/issues/91|#91>)
|
13
11
|
|
14
12
|
*For Admin users*
|
15
|
-
-
|
16
|
-
-
|
17
|
-
-
|
18
|
-
-
|
19
|
-
-
|
20
|
-
|
13
|
+
- It is possible to see routines filtering the HEADER supplied using the given REGEXP: `see routines HEADER /REGEXP/` (<https://github.com/MarioRuiz/slack-smart-bot/issues/84|#84>).
|
14
|
+
- `send message to users from YYYY/MM/DD to YYYY/MM/DD #CHANNEL COMMAND_ID: MESSAGE` 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 are optional filters. (<https://github.com/MarioRuiz/slack-smart-bot/issues/87|#87>)
|
15
|
+
- `update message URL TEXT` It will update the SmartBot message supplied. You can use this command only if you are a Master admin user and if you are in a private conversation with the bot. (<https://github.com/MarioRuiz/slack-smart-bot/issues/33|#33>)
|
16
|
+
- Routines now can create threads (<https://github.com/MarioRuiz/slack-smart-bot/issues/36|#36>)
|
17
|
+
- `add routine NAME on the DAY_OF_MONTH at TIME COMMAND` (<https://github.com/MarioRuiz/slack-smart-bot/issues/82|#82>)
|
18
|
+
|
21
19
|
------------------------------
|
22
20
|
|
23
|
-
*Previous*: <https://github.com/MarioRuiz/slack-smart-bot/blob/
|
21
|
+
*Previous*: <https://github.com/MarioRuiz/slack-smart-bot/blob/2b93317d7556ceaeb724494f53cfa9e8907c3e52/whats_new.txt|1.12.9>
|