slack-smart-bot 1.14.2 → 1.15.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +222 -37
- data/img/chat_gpt.png +0 -0
- data/img/chat_gpt_session.png +0 -0
- data/img/chat_gpt_share.png +0 -0
- data/img/command_add_sc.png +0 -0
- data/img/command_bot_help_echo.png +0 -0
- data/img/command_loop.png +0 -0
- data/img/command_my_timeoff.png +0 -0
- data/img/command_recap.png +0 -0
- data/img/command_repl1.png +0 -0
- data/img/command_repl2.png +0 -0
- data/img/command_ruby.png +0 -0
- data/img/command_run_repl.png +0 -0
- data/img/command_see_announcements.png +0 -0
- data/img/command_see_statuses.png +0 -0
- data/img/command_see_team.png +0 -0
- data/img/command_summarize.png +0 -0
- data/img/commands_inline.png +0 -0
- data/img/commands_on_demand.png +0 -0
- data/img/commands_on_external_call.png +0 -0
- data/img/image_editing.png +0 -0
- data/img/image_generation.png +0 -0
- data/img/image_variations.png +0 -0
- data/img/openai-300.png +0 -0
- data/img/openai.png +0 -0
- data/img/slack-300.png +0 -0
- data/img/slack.png +0 -0
- data/img/smart-bot-150.png +0 -0
- data/img/smart-bot-profile-pic-2.png +0 -0
- data/img/smart-bot-profile-pic.png +0 -0
- data/img/smart-bot.png +0 -0
- data/img/whisper.png +0 -0
- data/lib/slack/smart-bot/ai/open_ai/connect.rb +165 -43
- data/lib/slack/smart-bot/ai/open_ai/models.rb +61 -9
- data/lib/slack/smart-bot/ai/open_ai/send_gpt_chat.rb +67 -11
- data/lib/slack/smart-bot/ai/open_ai/send_image_edit.rb +4 -3
- data/lib/slack/smart-bot/ai/open_ai/send_image_generation.rb +4 -4
- data/lib/slack/smart-bot/ai/open_ai/send_image_variation.rb +4 -3
- data/lib/slack/smart-bot/ai/open_ai/whisper_transcribe.rb +4 -3
- data/lib/slack/smart-bot/comm/ask.rb +20 -8
- data/lib/slack/smart-bot/comm/dont_understand.rb +2 -2
- data/lib/slack/smart-bot/comm/event_hello.rb +30 -1
- data/lib/slack/smart-bot/comm/get_channel_members.rb +2 -1
- data/lib/slack/smart-bot/comm/get_presence.rb +1 -0
- data/lib/slack/smart-bot/comm/get_smartbot_team_info.rb +10 -0
- data/lib/slack/smart-bot/comm/get_user_info.rb +45 -6
- data/lib/slack/smart-bot/comm/get_users.rb +8 -1
- data/lib/slack/smart-bot/comm/respond.rb +225 -196
- data/lib/slack/smart-bot/comm/send_msg_channel.rb +2 -2
- data/lib/slack/smart-bot/comm/send_msg_user.rb +10 -9
- data/lib/slack/smart-bot/comm/unreact.rb +2 -2
- data/lib/slack/smart-bot/comm.rb +1 -0
- data/lib/slack/smart-bot/commands/general/add_admin.rb +16 -6
- data/lib/slack/smart-bot/commands/general/add_announcement.rb +3 -3
- data/lib/slack/smart-bot/commands/general/add_vacation.rb +28 -12
- data/lib/slack/smart-bot/commands/general/ai/open_ai/open_ai_chat.rb +272 -23
- data/lib/slack/smart-bot/commands/general/ai/open_ai/open_ai_chat_add_collaborator.rb +42 -0
- data/lib/slack/smart-bot/commands/general/ai/open_ai/open_ai_chat_copy_session.rb +89 -0
- data/lib/slack/smart-bot/commands/general/ai/open_ai/open_ai_chat_delete_session.rb +45 -0
- data/lib/slack/smart-bot/commands/general/ai/open_ai/open_ai_chat_get_prompts.rb +41 -0
- data/lib/slack/smart-bot/commands/general/ai/open_ai/open_ai_chat_list_sessions.rb +81 -0
- data/lib/slack/smart-bot/commands/general/ai/open_ai/open_ai_chat_share_session.rb +52 -0
- data/lib/slack/smart-bot/commands/general/ai/open_ai/open_ai_chat_use_model.rb +52 -0
- data/lib/slack/smart-bot/commands/general/ai/open_ai/open_ai_edit_image.rb +14 -11
- data/lib/slack/smart-bot/commands/general/ai/open_ai/open_ai_generate_image.rb +15 -11
- data/lib/slack/smart-bot/commands/general/ai/open_ai/open_ai_models.rb +29 -17
- data/lib/slack/smart-bot/commands/general/ai/open_ai/open_ai_variations_image.rb +16 -13
- data/lib/slack/smart-bot/commands/general/ai/open_ai/open_ai_whisper.rb +13 -7
- data/lib/slack/smart-bot/commands/general/allow_access.rb +8 -4
- data/lib/slack/smart-bot/commands/general/bot_help.rb +24 -10
- data/lib/slack/smart-bot/commands/general/bye_bot.rb +9 -5
- data/lib/slack/smart-bot/commands/general/delete_announcement.rb +2 -1
- data/lib/slack/smart-bot/commands/general/delete_share.rb +2 -1
- data/lib/slack/smart-bot/commands/general/deny_access.rb +1 -1
- data/lib/slack/smart-bot/commands/general/get_smartbot_readme.rb +15 -0
- data/lib/slack/smart-bot/commands/general/hi_bot.rb +10 -4
- data/lib/slack/smart-bot/commands/general/personal_settings.rb +26 -8
- data/lib/slack/smart-bot/commands/general/poster.rb +26 -2
- data/lib/slack/smart-bot/commands/general/public_holidays.rb +14 -24
- data/lib/slack/smart-bot/commands/general/recap.rb +399 -0
- data/lib/slack/smart-bot/commands/general/remove_admin.rb +19 -9
- data/lib/slack/smart-bot/commands/general/remove_vacation.rb +23 -6
- data/lib/slack/smart-bot/commands/general/see_access.rb +2 -1
- data/lib/slack/smart-bot/commands/general/see_admins.rb +8 -4
- data/lib/slack/smart-bot/commands/general/see_announcements.rb +5 -5
- data/lib/slack/smart-bot/commands/general/see_favorite_commands.rb +4 -4
- data/lib/slack/smart-bot/commands/general/see_shares.rb +1 -1
- data/lib/slack/smart-bot/commands/general/see_vacations.rb +34 -17
- data/lib/slack/smart-bot/commands/general/set_public_holidays.rb +4 -2
- data/lib/slack/smart-bot/commands/general/share_messages.rb +3 -3
- data/lib/slack/smart-bot/commands/general/summarize.rb +191 -0
- data/lib/slack/smart-bot/commands/general/teams/add_team.rb +4 -8
- data/lib/slack/smart-bot/commands/general/teams/delete_team.rb +3 -3
- data/lib/slack/smart-bot/commands/general/teams/memos/add_memo_team.rb +34 -29
- data/lib/slack/smart-bot/commands/general/teams/memos/add_memo_team_comment.rb +1 -1
- data/lib/slack/smart-bot/commands/general/teams/memos/delete_memo_team.rb +6 -4
- data/lib/slack/smart-bot/commands/general/teams/memos/see_memo_team.rb +26 -15
- data/lib/slack/smart-bot/commands/general/teams/memos/see_memos_team.rb +33 -24
- data/lib/slack/smart-bot/commands/general/teams/memos/set_memo_status.rb +4 -4
- data/lib/slack/smart-bot/commands/general/teams/ping_team.rb +10 -8
- data/lib/slack/smart-bot/commands/general/teams/see_teams.rb +73 -61
- data/lib/slack/smart-bot/commands/general/teams/see_vacations_team.rb +28 -13
- data/lib/slack/smart-bot/commands/general/teams/update_team.rb +9 -9
- data/lib/slack/smart-bot/commands/general_bot_commands.rb +1152 -839
- data/lib/slack/smart-bot/commands/on_bot/add_shortcut.rb +18 -17
- data/lib/slack/smart-bot/commands/on_bot/admin/add_routine.rb +11 -9
- data/lib/slack/smart-bot/commands/on_bot/admin/remove_routine.rb +2 -0
- data/lib/slack/smart-bot/commands/on_bot/admin/run_routine.rb +1 -0
- data/lib/slack/smart-bot/commands/on_bot/admin/see_routines.rb +5 -3
- data/lib/slack/smart-bot/commands/on_bot/admin_master/delete_message.rb +2 -3
- data/lib/slack/smart-bot/commands/on_bot/admin_master/get_bot_logs.rb +2 -3
- data/lib/slack/smart-bot/commands/on_bot/admin_master/react_to.rb +2 -3
- data/lib/slack/smart-bot/commands/on_bot/admin_master/send_message.rb +7 -6
- data/lib/slack/smart-bot/commands/on_bot/admin_master/update_message.rb +2 -3
- data/lib/slack/smart-bot/commands/on_bot/delete_repl.rb +1 -1
- data/lib/slack/smart-bot/commands/on_bot/delete_shortcut.rb +21 -20
- data/lib/slack/smart-bot/commands/on_bot/general/bot_stats.rb +40 -7
- data/lib/slack/smart-bot/commands/on_bot/general/bot_status.rb +6 -2
- data/lib/slack/smart-bot/commands/on_bot/general/stop_using_rules.rb +7 -6
- data/lib/slack/smart-bot/commands/on_bot/general/suggest_command.rb +5 -4
- data/lib/slack/smart-bot/commands/on_bot/general/use_rules.rb +4 -3
- data/lib/slack/smart-bot/commands/on_bot/get_repl.rb +4 -4
- data/lib/slack/smart-bot/commands/on_bot/kill_repl.rb +1 -1
- data/lib/slack/smart-bot/commands/on_bot/repl.rb +109 -53
- data/lib/slack/smart-bot/commands/on_bot/repl_client.rb +35 -29
- data/lib/slack/smart-bot/commands/on_bot/run_repl.rb +5 -5
- data/lib/slack/smart-bot/commands/on_bot/see_repls.rb +1 -2
- data/lib/slack/smart-bot/commands/on_bot/see_shortcuts.rb +5 -4
- data/lib/slack/smart-bot/commands/on_extended/bot_rules.rb +22 -12
- data/lib/slack/smart-bot/commands/on_master/admin_master/exit_bot.rb +12 -7
- data/lib/slack/smart-bot/commands/on_master/admin_master/notify_message.rb +2 -2
- data/lib/slack/smart-bot/commands/on_master/admin_master/publish_announcements.rb +1 -1
- data/lib/slack/smart-bot/commands/on_master/admin_master/set_general_message.rb +5 -5
- data/lib/slack/smart-bot/commands/on_master/admin_master/set_maintenance.rb +5 -5
- data/lib/slack/smart-bot/commands/on_master/create_bot.rb +3 -3
- data/lib/slack/smart-bot/commands.rb +10 -0
- data/lib/slack/smart-bot/config.rb +126 -0
- data/lib/slack/smart-bot/listen.rb +12 -11
- data/lib/slack/smart-bot/process.rb +62 -55
- data/lib/slack/smart-bot/process_first.rb +106 -65
- data/lib/slack/smart-bot/treat_message.rb +79 -47
- data/lib/slack/smart-bot/utils/answer.rb +11 -3
- data/lib/slack/smart-bot/utils/answer_delete.rb +11 -3
- data/lib/slack/smart-bot/utils/check_vacations.rb +21 -3
- data/lib/slack/smart-bot/utils/create_routine_thread.rb +13 -13
- data/lib/slack/smart-bot/utils/display_calendar.rb +42 -8
- data/lib/slack/smart-bot/utils/encryption/decrypt.rb +16 -9
- data/lib/slack/smart-bot/utils/encryption/encrypt.rb +14 -11
- data/lib/slack/smart-bot/utils/find_user.rb +71 -0
- data/lib/slack/smart-bot/utils/get_access_channels.rb +22 -3
- data/lib/slack/smart-bot/utils/get_channels_name_and_id.rb +3 -4
- data/lib/slack/smart-bot/utils/get_command_ids.rb +5 -5
- data/lib/slack/smart-bot/utils/get_countries_candelarific.rb +18 -0
- data/lib/slack/smart-bot/utils/get_help.rb +21 -19
- data/lib/slack/smart-bot/utils/get_openai_sessions.rb +47 -0
- data/lib/slack/smart-bot/utils/get_personal_settings.rb +29 -3
- data/lib/slack/smart-bot/utils/get_rules_imported.rb +27 -6
- data/lib/slack/smart-bot/utils/get_shares.rb +1 -1
- data/lib/slack/smart-bot/utils/get_team_members.rb +4 -4
- data/lib/slack/smart-bot/utils/get_vacations.rb +15 -7
- data/lib/slack/smart-bot/utils/has_access.rb +10 -4
- data/lib/slack/smart-bot/utils/is_admin.rb +25 -17
- data/lib/slack/smart-bot/utils/local_time.rb +29 -0
- data/lib/slack/smart-bot/utils/save_stats.rb +5 -3
- data/lib/slack/smart-bot/utils/update_access_channels.rb +19 -3
- data/lib/slack/smart-bot/utils/update_openai_sessions.rb +42 -0
- data/lib/slack/smart-bot/utils/update_personal_settings.rb +11 -3
- data/lib/slack/smart-bot/utils/update_rules_imported.rb +18 -3
- data/lib/slack/smart-bot/utils/update_vacations.rb +5 -2
- data/lib/slack/smart-bot/utils/upgrade_to_use_team_ids.rb +276 -0
- data/lib/slack/smart-bot/utils.rb +6 -1
- data/lib/slack-smart-bot.rb +181 -76
- data/lib/slack-smart-bot_general_commands.rb +10 -9
- data/whats_new.txt +30 -13
- metadata +128 -20
@@ -3,20 +3,37 @@ class SlackSmartBot
|
|
3
3
|
save_stats(__method__) if add_stats
|
4
4
|
|
5
5
|
get_vacations()
|
6
|
-
|
6
|
+
team_id_user = "#{user.team_id}_#{user.name}"
|
7
|
+
|
7
8
|
from_user_name = ''
|
8
|
-
year = Date.today.year if year.to_s == ''
|
9
9
|
|
10
10
|
if from_user.empty?
|
11
|
-
from_user_name =
|
11
|
+
from_user_name = team_id_user
|
12
12
|
else
|
13
|
-
|
14
|
-
|
15
|
-
from_user_name = user_info.name
|
13
|
+
user_info = find_user(from_user)
|
14
|
+
from_user_name = "#{user_info.team_id}_#{user_info.name}"
|
16
15
|
end
|
17
|
-
|
16
|
+
|
17
|
+
if @vacations.key?(from_user_name) and @vacations[from_user_name][:public_holidays].to_s != ""
|
18
|
+
country_region = @vacations[from_user_name][:public_holidays].downcase
|
19
|
+
elsif config[:public_holidays].key?(:default_calendar)
|
20
|
+
country_region = config[:public_holidays][:default_calendar].downcase
|
21
|
+
else
|
22
|
+
country_region = ''
|
23
|
+
end
|
24
|
+
|
25
|
+
local_day_time = local_time(country_region)
|
26
|
+
if local_day_time.nil?
|
27
|
+
today = Date.today
|
28
|
+
else
|
29
|
+
today = local_day_time.to_date
|
30
|
+
end
|
31
|
+
year = today.year.to_s if year.to_s == ''
|
32
|
+
|
33
|
+
from_user = '' if from_user_name == team_id_user
|
18
34
|
if !@vacations.key?(from_user_name) or !@vacations[from_user_name].key?(:periods) or @vacations[from_user_name].periods.empty?
|
19
35
|
if from_user.empty?
|
36
|
+
display_calendar(from_user_name, year) if dest[0] == 'D'
|
20
37
|
respond "You didn't add any time off yet. Use `add vacation from YYYY/MM/DD to YYYY/MM/DD`"
|
21
38
|
else
|
22
39
|
respond "No time off added yet for <@#{from_user}>"
|
@@ -24,27 +41,27 @@ class SlackSmartBot
|
|
24
41
|
else
|
25
42
|
messages = []
|
26
43
|
messages << "*Time off <@#{from_user}> #{year}*" if !from_user.empty?
|
27
|
-
|
28
|
-
display_calendar(from_user_name, year) if from_user_name == user.name and dest[0] == 'D'
|
29
44
|
|
30
|
-
|
45
|
+
display_calendar(from_user_name, year) if from_user_name == team_id_user and dest[0] == 'D'
|
46
|
+
|
47
|
+
today_txt = today.strftime("%Y/%m/%d")
|
31
48
|
current_added = false
|
32
49
|
past_added = false
|
33
50
|
@vacations[from_user_name].periods.sort_by { |v| v[:from]}.reverse.each do |vac|
|
34
|
-
if !current_added and vac.to >=
|
35
|
-
messages << "*Current and future periods*"
|
51
|
+
if !current_added and vac.to >= today_txt
|
52
|
+
messages << "*Current and future periods*"
|
36
53
|
current_added = true
|
37
54
|
end
|
38
|
-
if !past_added and vac.to <
|
55
|
+
if !past_added and vac.to < today_txt and from_user.empty? and vac.to[0..3] == year
|
39
56
|
if dest[0]=='D'
|
40
|
-
messages << "\n*Past periods #{year}*"
|
57
|
+
messages << "\n*Past periods #{year}*"
|
41
58
|
past_added = true
|
42
59
|
else
|
43
60
|
messages << "To see past periods call me from a DM"
|
44
61
|
break
|
45
62
|
end
|
46
63
|
end
|
47
|
-
unless !from_user.empty? and vac.to <
|
64
|
+
unless !from_user.empty? and vac.to < today_txt
|
48
65
|
if vac.to[0..3] == year
|
49
66
|
if !from_user.empty?
|
50
67
|
icon = ":beach_with_umbrella:"
|
@@ -63,13 +80,13 @@ class SlackSmartBot
|
|
63
80
|
end
|
64
81
|
end
|
65
82
|
end
|
66
|
-
if !past_added and !current_added and dest[0]=='D'
|
83
|
+
if !past_added and !current_added and dest[0]=='D'
|
67
84
|
if from_user.empty?
|
68
85
|
messages << "No time off added yet for #{year}"
|
69
86
|
else
|
70
87
|
messages << "Not possible to see past periods for another user"
|
71
88
|
end
|
72
|
-
elsif !past_added and dest[0]=='D' and !from_user.empty? and from_user_name !=
|
89
|
+
elsif !past_added and dest[0]=='D' and !from_user.empty? and from_user_name != team_id_user
|
73
90
|
messages << "Not possible to see past periods for another user"
|
74
91
|
end
|
75
92
|
respond messages.join("\n")
|
@@ -4,6 +4,7 @@ class SlackSmartBot
|
|
4
4
|
|
5
5
|
result = public_holidays(country, state, Date.today.year.to_s, '', '', add_stats: false, publish_results: false)
|
6
6
|
if result == true
|
7
|
+
team_id_user = "#{user.team_id}_#{user.name}"
|
7
8
|
if state == ""
|
8
9
|
country_region = country
|
9
10
|
else
|
@@ -15,9 +16,10 @@ class SlackSmartBot
|
|
15
16
|
respond "Public holidays for *#{country_region}* set."
|
16
17
|
end
|
17
18
|
get_vacations()
|
18
|
-
@vacations[
|
19
|
-
@vacations[
|
19
|
+
@vacations[team_id_user] ||= {}
|
20
|
+
@vacations[team_id_user][:public_holidays] = country_region
|
20
21
|
update_vacations()
|
22
|
+
check_vacations(date: nil, team_id: user.team_id, user: user.name, set_status: true, only_first_day: false)
|
21
23
|
else
|
22
24
|
respond "Be sure the country and state are correct. If not displayed available states, try with the country only."
|
23
25
|
end
|
@@ -25,7 +25,7 @@ class SlackSmartBot
|
|
25
25
|
type = :reaction
|
26
26
|
end
|
27
27
|
if File.exist?("#{config.path}/shares/#{from_channel}.csv")
|
28
|
-
t = CSV.table("#{config.path}/shares/#{from_channel}.csv", headers: ['share_id', 'user_deleted', 'user_created', 'date', 'time', 'type', 'to_channel', 'condition'])
|
28
|
+
t = CSV.table("#{config.path}/shares/#{from_channel}.csv", headers: ['share_id', 'user_team_id_deleted', 'user_deleted', 'user_team_id_created', 'user_created', 'date', 'time', 'type', 'to_channel', 'condition'])
|
29
29
|
@shares[from_channel] = t
|
30
30
|
if t.size>0
|
31
31
|
num = t[:share_id].max + 1
|
@@ -34,13 +34,13 @@ class SlackSmartBot
|
|
34
34
|
end
|
35
35
|
elsif !@shares.key?(from_channel)
|
36
36
|
File.open("#{config.path}/shares/#{from_channel}.csv","w")
|
37
|
-
t = CSV.table("#{config.path}/shares/#{from_channel}.csv", headers: ['share_id', 'user_deleted', 'user_created', 'date', 'time', 'type', 'to_channel', 'condition'])
|
37
|
+
t = CSV.table("#{config.path}/shares/#{from_channel}.csv", headers: ['share_id', 'user_team_id_deleted', 'user_deleted', 'user_team_id_created', 'user_created', 'date', 'time', 'type', 'to_channel', 'condition'])
|
38
38
|
num = 1
|
39
39
|
@shares[from_channel] = t
|
40
40
|
else
|
41
41
|
num = @shares[from_channel][:share_id].max + 1
|
42
42
|
end
|
43
|
-
values = [num, '', user.name, Time.now.strftime("%Y/%m/%d"), Time.now.strftime("%H:%M"), type.to_s, to_channel, condition]
|
43
|
+
values = [num, '', '', user.team_id, user.name, Time.now.strftime("%Y/%m/%d"), Time.now.strftime("%H:%M"), type.to_s, to_channel, condition]
|
44
44
|
@shares[from_channel] << values
|
45
45
|
CSV.open("#{config.path}/shares/#{from_channel}.csv", "a+") do |csv|
|
46
46
|
csv << values
|
@@ -0,0 +1,191 @@
|
|
1
|
+
class SlackSmartBot
|
2
|
+
|
3
|
+
#todo: add tests
|
4
|
+
def summarize(user, dest, channel, from, thread_ts)
|
5
|
+
save_stats(__method__)
|
6
|
+
|
7
|
+
ai_conn, message = SlackSmartBot::AI::OpenAI.connect({}, config, {}, service: :chat_gpt)
|
8
|
+
if message.empty?
|
9
|
+
ai_models_conn, message = SlackSmartBot::AI::OpenAI.connect({}, config, {}, service: :models)
|
10
|
+
end
|
11
|
+
if !message.empty? #error connecting
|
12
|
+
respond message
|
13
|
+
else
|
14
|
+
channels_bot_is_in = get_channels(bot_is_in: true)
|
15
|
+
if dest[0] == "D" and channel == dest
|
16
|
+
respond "Sorry, I can't summarize a direct message. Please use this command in a channel or supply the channel you want to summarize."
|
17
|
+
elsif !channels_bot_is_in.id.include?(channel) or !get_channel_members(channel).include?(config.nick_id_granular)
|
18
|
+
respond "Sorry, I can't summarize a channel where <@#{config.nick_id_granular}> and <@#{config.nick_id}> are not members. Please invite them to the channel."
|
19
|
+
elsif !get_channel_members(channel).include?(user.id)
|
20
|
+
respond "Sorry, I can't summarize a channel where you are not a member."
|
21
|
+
else
|
22
|
+
if (from == "" and channel == dest and Thread.current[:on_thread]) or thread_ts != ""
|
23
|
+
summarize_thread = true
|
24
|
+
if thread_ts == ""
|
25
|
+
thread_ts = Thread.current[:thread_ts]
|
26
|
+
else
|
27
|
+
if thread_ts.include?(".")
|
28
|
+
thread_ts = thread_ts
|
29
|
+
else
|
30
|
+
thread_ts = thread_ts.scan(/(\d+)/).join
|
31
|
+
thread_ts = "#{thread_ts[0..9]}.#{thread_ts[10..-1]}"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
else
|
35
|
+
summarize_thread = false
|
36
|
+
end
|
37
|
+
from_time_off = false
|
38
|
+
if from == ""
|
39
|
+
from = (Time.now - (60 * 60) * 24 * 30).to_s
|
40
|
+
get_vacations()
|
41
|
+
if @vacations.key?(user.team_id_user) and @vacations[user.team_id_user].key?(:periods)
|
42
|
+
@vacations[user.team_id_user].periods.each do |p|
|
43
|
+
#get the last from date
|
44
|
+
if p.from > from[0..9].gsub("-", "/")
|
45
|
+
from = p.from
|
46
|
+
from_time_off = true
|
47
|
+
end
|
48
|
+
end
|
49
|
+
#from will be the day before the last time off
|
50
|
+
if from_time_off
|
51
|
+
from = (Time.strptime(from, "%Y/%m/%d") - (60 * 60) * 24).to_s
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
from.gsub!("-", "/")
|
57
|
+
if from.length == 10
|
58
|
+
from = from + " 00:00:00"
|
59
|
+
elsif from.length == 16
|
60
|
+
from = from + ":00"
|
61
|
+
end
|
62
|
+
from = Time.strptime(from, "%Y/%m/%d %H:%M:%S")
|
63
|
+
if summarize_thread
|
64
|
+
last_msg = respond("I'm going to summarize the thread messages", return_message: true)
|
65
|
+
elsif from_time_off
|
66
|
+
last_msg = respond("I'm going to summarize the messages since the day before your last time off #{from.strftime("%Y/%m/%d")} in <##{channel}>. This may take a while.", return_message: true)
|
67
|
+
else
|
68
|
+
last_msg = respond("I'm going to summarize the messages since #{from.strftime("%Y/%m/%d %H:%M:%S")} in <##{channel}>. This may take a while.", return_message: true)
|
69
|
+
end
|
70
|
+
|
71
|
+
@history_still_running ||= false
|
72
|
+
if @history_still_running
|
73
|
+
respond "Due to Slack API rate limit, `summarize` command is limited. Waiting for other `summarize` command to finish."
|
74
|
+
num_times = 0
|
75
|
+
while @history_still_running and num_times < 30
|
76
|
+
num_times += 1
|
77
|
+
sleep 1
|
78
|
+
end
|
79
|
+
if @history_still_running
|
80
|
+
respond "Sorry, Another `summarize` command is still running after 30 seconds. Please try again later."
|
81
|
+
end
|
82
|
+
end
|
83
|
+
unless @history_still_running
|
84
|
+
@history_still_running = true
|
85
|
+
react :running
|
86
|
+
if summarize_thread
|
87
|
+
hist = client_granular.conversations_history(channel: channel, oldest: thread_ts, inclusive: true, limit: 1)
|
88
|
+
else
|
89
|
+
hist = client_granular.conversations_history(channel: channel)
|
90
|
+
end
|
91
|
+
messages = {} # store the messages by year/month
|
92
|
+
act_users = {}
|
93
|
+
act_threads = {}
|
94
|
+
hist.messages.each do |message|
|
95
|
+
if Time.at(message.ts.to_f) >= from or summarize_thread
|
96
|
+
year_month = Time.at(message.ts.to_f).strftime("%Y/%m")
|
97
|
+
messages[year_month] ||= []
|
98
|
+
if message.key?("thread_ts")
|
99
|
+
thread_ts_message = message.thread_ts
|
100
|
+
replies = client_granular.conversations_replies(channel: channel, ts: thread_ts_message, latest: last_msg.ts)
|
101
|
+
sleep 0.5 #to avoid rate limit Tier 3 (50 requests per minute)
|
102
|
+
messages_replies = ["Thread Started about last message:"]
|
103
|
+
act_threads[message.ts] = replies.messages.size
|
104
|
+
replies.messages.each_with_index do |msgrepl, i|
|
105
|
+
act_users[msgrepl.user] ||= 0
|
106
|
+
act_users[msgrepl.user] += 1
|
107
|
+
messages_replies << "<@#{msgrepl.user}> (#{Time.at(msgrepl.ts.to_f)}) wrote:> #{msgrepl.text}" if i > 0
|
108
|
+
end
|
109
|
+
messages_replies << "Thread ended."
|
110
|
+
messages[year_month] += messages_replies.reverse # the order on repls is from older to newer
|
111
|
+
end
|
112
|
+
act_users[message.user] ||= 0
|
113
|
+
act_users[message.user] += 1
|
114
|
+
url_to_message = "https://#{client.team.domain}.slack.com/archives/#{channel}/#{message.ts}"
|
115
|
+
messages[year_month] << "<@#{message.user}> (#{Time.at(message.ts.to_f)}) (link to the message: #{url_to_message}) wrote:> #{message.text}"
|
116
|
+
end
|
117
|
+
end
|
118
|
+
messages.each do |year_month, msgs|
|
119
|
+
messages[year_month] = msgs.reverse # the order on history is from newer to older
|
120
|
+
end
|
121
|
+
@history_still_running = false
|
122
|
+
unreact :running
|
123
|
+
if messages.empty?
|
124
|
+
respond "There are no Slack Messages since #{from}"
|
125
|
+
else
|
126
|
+
react :speech_balloon
|
127
|
+
chatgpt = ai_conn[user.team_id_user].chat_gpt
|
128
|
+
models = ai_models_conn[user.team_id_user].models
|
129
|
+
|
130
|
+
prompt_orig = "Could you please provide a summary of the given conversation, including all key points and supporting details? The summary should be comprehensive and accurately reflect the main message and arguments presented in the original text, while also being concise and easy to understand. To ensure accuracy, please read the text carefully and pay attention to any nuances or complexities in the language. Please also add the most important conversations in the summary. Additionally, the summary should avoid any personal biases or interpretations and remain objective and factual throughout.\n"
|
131
|
+
prompt_orig += "If you name an user remember to name it as <@user_id> so it is not replaced by the user name.\n"
|
132
|
+
prompt_orig += "Add the link to the message so it is easy to find it. The links added need to follow this <LINK|message>\n"
|
133
|
+
prompt_orig += "For example <https://#{client.team.domain}.slack.com/archives/C111JG4V4DZ/1610231016.950299|message>\n"
|
134
|
+
prompt_orig += "Add also the date of the message for relevant conversations.\n"
|
135
|
+
prompt_orig += "This is the conversation:\n"
|
136
|
+
#sort by year/month from older to newer
|
137
|
+
messages = messages.sort_by { |k, v| k }.to_h
|
138
|
+
|
139
|
+
@open_ai_model_info ||= {}
|
140
|
+
@open_ai_model_info[chatgpt.smartbot_model] ||= SlackSmartBot::AI::OpenAI.models(models.client, models, chatgpt.smartbot_model, return_response: true)
|
141
|
+
if @open_ai_model_info[chatgpt.smartbot_model].key?(:max_input_tokens)
|
142
|
+
max_num_tokens = @open_ai_model_info[chatgpt.smartbot_model][:max_input_tokens].to_i
|
143
|
+
elsif @open_ai_model_info[chatgpt.smartbot_model].key?(:max_tokens)
|
144
|
+
max_num_tokens = @open_ai_model_info[chatgpt.smartbot_model][:max_tokens].to_i
|
145
|
+
else
|
146
|
+
max_num_tokens = 8000
|
147
|
+
end
|
148
|
+
num_tokens = OpenAI.rough_token_count(prompt_orig + messages.values.flatten.join)
|
149
|
+
respond ":information_source: ChatGPT model: *#{chatgpt.smartbot_model}*. Max tokens: *#{max_num_tokens}*. Characters: #{messages.values.flatten.join.size}. Messages: #{messages.values.flatten.size}. Threads: #{act_threads.size}. Users: #{act_users.size}. Chatgpt tokens: *#{num_tokens}*"
|
150
|
+
|
151
|
+
prompts = []
|
152
|
+
i = 0
|
153
|
+
messages.each do |year_month, msgs|
|
154
|
+
msgs.each do |msg|
|
155
|
+
num_tokens = OpenAI.rough_token_count(prompts[i].to_s + msg)
|
156
|
+
i += 1 if num_tokens > max_num_tokens
|
157
|
+
prompts[i] ||= prompt_orig
|
158
|
+
prompts[i] += "#{msg}\n"
|
159
|
+
end
|
160
|
+
end
|
161
|
+
prompts.each_with_index do |prompt, i|
|
162
|
+
num_tokens = OpenAI.rough_token_count(prompt)
|
163
|
+
respond ":information_source: The total number of chatgpt tokens is more than the max allowed for this chatgpt model. *Part #{i + 1} of #{prompts.size}*.\n" if prompts.size > 1
|
164
|
+
success, res = SlackSmartBot::AI::OpenAI.send_gpt_chat(chatgpt.client, chatgpt.smartbot_model, prompt, chatgpt)
|
165
|
+
result_messages = []
|
166
|
+
if success
|
167
|
+
result_messages << "*ChatGPT:*\n#{res}"
|
168
|
+
else
|
169
|
+
result_messages << "*ChatGPT:*\nI'm sorry, I couldn't summarize the conversation. This is the issue: #{res}"
|
170
|
+
end
|
171
|
+
if i == prompts.size - 1
|
172
|
+
act_users.delete(config.nick_id_granular)
|
173
|
+
act_users.delete(config.nick_id)
|
174
|
+
|
175
|
+
act_users = act_users.sort_by { |k, v| v }.reverse
|
176
|
+
|
177
|
+
result_messages << "\n\t:runner: Most active users: #{act_users[0..2].map { |k, v| "<@#{k}> (#{v})" }.join(", ")}"
|
178
|
+
if act_threads.size > 0 and !summarize_thread
|
179
|
+
act_threads = act_threads.sort_by { |k, v| v }.reverse
|
180
|
+
result_messages << "\t:fire: Most active threads: #{act_threads[0..2].map { |k, v| "<https://#{client.team.domain}.slack.com/archives/#{channel}/#{k}|#{v - 1} replies>" }.join(", ")}"
|
181
|
+
end
|
182
|
+
end
|
183
|
+
respond result_messages.join("\n").gsub("**", "*")
|
184
|
+
end
|
185
|
+
unreact :speech_balloon
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
@@ -28,12 +28,8 @@ class SlackSmartBot
|
|
28
28
|
break
|
29
29
|
else
|
30
30
|
member_id = $1
|
31
|
-
member_info =
|
32
|
-
|
33
|
-
@users = get_users()
|
34
|
-
member_info = @users.select { |u| u.id == member_id or (u.key?(:enterprise_user) and u.enterprise_user.id == member_id) }[-1]
|
35
|
-
end
|
36
|
-
team[:members][last_type] << member_info.name
|
31
|
+
member_info = find_user(member_id)
|
32
|
+
team[:members][last_type] << "#{member_info.team_id}_#{member_info.name}"
|
37
33
|
end
|
38
34
|
elsif opt.match(/<#(\w+)\|[^>]*>/i)
|
39
35
|
team[:channels][last_type] ||= []
|
@@ -69,8 +65,8 @@ class SlackSmartBot
|
|
69
65
|
get_teams()
|
70
66
|
team[:info] = info
|
71
67
|
team[:status] = :added
|
72
|
-
team[:user] = user.name
|
73
|
-
team[:creator] = user.name
|
68
|
+
team[:user] = "#{user.team_id}_#{user.name}"
|
69
|
+
team[:creator] = "#{user.team_id}_#{user.name}"
|
74
70
|
team[:date] = Time.now.strftime("%Y-%m-%dT%H:%M:%S.000Z")[0..18]
|
75
71
|
new_team = {}
|
76
72
|
team[:name] = name
|
@@ -19,8 +19,8 @@ class SlackSmartBot
|
|
19
19
|
get_channels_name_and_id() unless @channels_id.key?(ch)
|
20
20
|
tm = get_channel_members(@channels_id[ch])
|
21
21
|
tm.each do |m|
|
22
|
-
user_info =
|
23
|
-
team_members << user_info.name unless user_info.is_app_user or user_info.is_bot
|
22
|
+
user_info = find_user(m)
|
23
|
+
team_members << "#{user_info.team_id}_#{user_info.name}" unless user_info.nil? or user_info.is_app_user or user_info.is_bot
|
24
24
|
end
|
25
25
|
end
|
26
26
|
end
|
@@ -31,7 +31,7 @@ class SlackSmartBot
|
|
31
31
|
end
|
32
32
|
if !@teams.key?(team_name.to_sym)
|
33
33
|
respond "It seems like the team *#{team_name}* doesn't exist.\nRelated commands `add team TEAM_NAME PROPERTIES`, `see team TEAM_NAME`, `see teams`"
|
34
|
-
elsif !(all_team_members + [@teams[team_name.to_sym].creator] + config.
|
34
|
+
elsif !(all_team_members + [@teams[team_name.to_sym].creator] + config.team_id_masters).flatten.include?("#{user.team_id}_#{user.name}")
|
35
35
|
respond "You have to be a member of the team, the creator or a Master admin to be able to delete this team."
|
36
36
|
else
|
37
37
|
if answer.empty?
|
@@ -17,8 +17,8 @@ class SlackSmartBot
|
|
17
17
|
get_channels_name_and_id() unless @channels_id.key?(ch)
|
18
18
|
tm = get_channel_members(@channels_id[ch])
|
19
19
|
tm.each do |m|
|
20
|
-
user_info =
|
21
|
-
team_members << user_info.name unless user_info.is_app_user or user_info.is_bot
|
20
|
+
user_info = find_user(m)
|
21
|
+
team_members << "#{user_info.team_id}_#{user_info.name}" unless user_info.is_app_user or user_info.is_bot
|
22
22
|
end
|
23
23
|
end
|
24
24
|
end
|
@@ -31,34 +31,39 @@ class SlackSmartBot
|
|
31
31
|
if type == "jira"
|
32
32
|
able_to_connect_jira = false
|
33
33
|
begin
|
34
|
-
|
35
|
-
|
36
|
-
message.gsub!(/^\s*</, "")
|
37
|
-
message.gsub!(/\>$/, "")
|
38
|
-
message.gsub!(/\|.+$/, "")
|
39
|
-
message.gsub!(/^#{config.jira.host}/, "")
|
40
|
-
if message.include?("/browse/")
|
41
|
-
message = message.scan(/\/browse\/(.+)/).join
|
42
|
-
resp = http.get("/rest/api/latest/issue/#{message}")
|
43
|
-
else
|
44
|
-
message.gsub!(/^\/issues\/\?jql=/, "")
|
45
|
-
message.gsub!(" ", "%20")
|
46
|
-
resp = http.get("/rest/api/latest/search/?jql=#{message}")
|
47
|
-
search = true
|
48
|
-
end
|
49
|
-
if resp.code == 200
|
50
|
-
able_to_connect_jira = true
|
34
|
+
if config.jira.host == "" or config.jira.user == "" or config.jira.password == ""
|
35
|
+
respond "You need to supply the correct credentials for JIRA on the SmartBot settings: `jira: { host: HOST, user: USER, password: PASSWORD }`"
|
51
36
|
else
|
52
|
-
|
53
|
-
|
54
|
-
|
37
|
+
http = NiceHttp.new(config.jira.host)
|
38
|
+
http.headers.authorization = NiceHttpUtils.basic_authentication(user: config.jira.user, password: config.jira.password)
|
39
|
+
message.gsub!(/^\s*</, "")
|
40
|
+
message.gsub!(/\>$/, "")
|
41
|
+
message.gsub!(/\|.+$/, "")
|
42
|
+
message.gsub!(/^#{config.jira.host}/, "")
|
43
|
+
if message.include?("/browse/")
|
44
|
+
message = message.scan(/\/browse\/(.+)/).join
|
45
|
+
resp = http.get("/rest/api/latest/issue/#{message}")
|
55
46
|
else
|
56
|
-
|
47
|
+
message.gsub!(/^\/issues\/\?jql=/, "")
|
48
|
+
message.gsub!(" ", "%20")
|
49
|
+
resp = http.get("/rest/api/latest/search/?jql=#{message}")
|
50
|
+
search = true
|
51
|
+
end
|
52
|
+
if resp.code.to_s == '200'
|
53
|
+
able_to_connect_jira = true
|
54
|
+
else
|
55
|
+
error_code = resp.code.to_s
|
56
|
+
if resp.code.to_s == '400'
|
57
|
+
error_message = resp.data.json(:errorMessages)[-1]
|
58
|
+
else
|
59
|
+
error_message = ""
|
60
|
+
end
|
57
61
|
end
|
62
|
+
http.close
|
58
63
|
end
|
59
|
-
http.close
|
60
64
|
rescue => exception
|
61
65
|
@logger.fatal exception
|
66
|
+
respond "There was an error trying to connect to JIRA. Please ask the admin to check the logs."
|
62
67
|
end
|
63
68
|
elsif type == "github"
|
64
69
|
able_to_connect_github = false
|
@@ -73,11 +78,11 @@ class SlackSmartBot
|
|
73
78
|
message.gsub!("https://github.com", "")
|
74
79
|
message.slice!(0) if message[0] == "/"
|
75
80
|
resp = http.get("/repos/#{message}")
|
76
|
-
if resp.code == 200
|
81
|
+
if resp.code.to_s == '200'
|
77
82
|
able_to_connect_github = true
|
78
83
|
else
|
79
|
-
error_code = resp.code
|
80
|
-
if resp.code == 401
|
84
|
+
error_code = resp.code.to_s
|
85
|
+
if resp.code.to_s == '401'
|
81
86
|
error_message = resp.data.json(:message)[-1]
|
82
87
|
else
|
83
88
|
error_message = ""
|
@@ -91,7 +96,7 @@ class SlackSmartBot
|
|
91
96
|
|
92
97
|
if !@teams.key?(team_name.to_sym)
|
93
98
|
respond "It seems like the team *#{team_name}* doesn't exist\nRelated commands `add team TEAM_NAME PROPERTIES`, `see team TEAM_NAME`, `see teams`"
|
94
|
-
elsif !(all_team_members + config.
|
99
|
+
elsif !(all_team_members + config.team_id_masters).flatten.include?("#{user.team_id}_#{user.name}")
|
95
100
|
respond "You have to be a member of the team or a Master admin to be able to add a memo to the team."
|
96
101
|
elsif type == "jira" and !able_to_connect_jira
|
97
102
|
if error_message == ""
|
@@ -117,7 +122,7 @@ class SlackSmartBot
|
|
117
122
|
topic: topic,
|
118
123
|
type: type,
|
119
124
|
privacy: privacy,
|
120
|
-
user: user.name,
|
125
|
+
user: "#{user.team_id}_#{user.name}",
|
121
126
|
date: Time.now.strftime("%Y-%m-%dT%H:%M:%S.000Z")[0..18],
|
122
127
|
message: message,
|
123
128
|
status: ":new: ",
|
@@ -13,7 +13,7 @@ class SlackSmartBot
|
|
13
13
|
memo = @teams[team_name].memos.select { |m| m.memo_id == memo_id.to_i }[-1]
|
14
14
|
if memo
|
15
15
|
memo.comments ||= []
|
16
|
-
memo.comments << { user_name: user.name, user_id: user.id, message: message, time: Time.now.to_s }
|
16
|
+
memo.comments << { user_name: "#{user.team_id}_#{user.name}", user_id: user.id, message: message, time: Time.now.to_s }
|
17
17
|
update_teams()
|
18
18
|
if config.simulate
|
19
19
|
respond "Comment added to memo #{memo_id} in team #{team_name}"
|
@@ -7,6 +7,8 @@ class SlackSmartBot
|
|
7
7
|
save_stats(__method__) if answer.empty?
|
8
8
|
|
9
9
|
get_teams()
|
10
|
+
team_id_user = "#{user.team_id}_#{user.name}"
|
11
|
+
|
10
12
|
if @teams.key?(team_name.to_sym)
|
11
13
|
assigned_members = @teams[team_name.to_sym].members.values.flatten
|
12
14
|
assigned_members.uniq!
|
@@ -17,8 +19,8 @@ class SlackSmartBot
|
|
17
19
|
get_channels_name_and_id() unless @channels_id.key?(ch)
|
18
20
|
tm = get_channel_members(@channels_id[ch])
|
19
21
|
tm.each do |m|
|
20
|
-
user_info =
|
21
|
-
team_members << user_info.name unless user_info.is_app_user or user_info.is_bot
|
22
|
+
user_info = find_user(m)
|
23
|
+
team_members << "#{user_info.team_id}_#{user_info.name}" unless user_info.is_app_user or user_info.is_bot
|
22
24
|
end
|
23
25
|
end
|
24
26
|
end
|
@@ -30,13 +32,13 @@ class SlackSmartBot
|
|
30
32
|
|
31
33
|
if !@teams.key?(team_name.to_sym)
|
32
34
|
respond "It seems like the team *#{team_name}* doesn't exist.\nRelated commands `add team TEAM_NAME PROPERTIES`, `see team TEAM_NAME`, `see teams`"
|
33
|
-
elsif !(all_team_members + config.
|
35
|
+
elsif !(all_team_members + config.team_id_masters).flatten.include?(team_id_user)
|
34
36
|
respond "You have to be a member of the team or a Master admin to be able to delete a memo of the team."
|
35
37
|
elsif !@teams[team_name.to_sym].key?(:memos) or @teams[team_name.to_sym][:memos].empty? or !@teams[team_name.to_sym][:memos].memo_id.include?(memo_id.to_i)
|
36
38
|
respond "It seems like there is no memo with id #{memo_id}"
|
37
39
|
elsif @teams[team_name.to_sym][:memos].memo_id.include?(memo_id.to_i)
|
38
40
|
memo_selected = @teams[team_name.to_sym][:memos].select { |m| m.memo_id == memo_id.to_i }[-1]
|
39
|
-
if memo_selected.privacy == "personal" and memo_selected.user !=
|
41
|
+
if memo_selected.privacy == "personal" and memo_selected.user != team_id_user
|
40
42
|
respond "Only the creator can delete a personal memo."
|
41
43
|
else
|
42
44
|
if answer.empty?
|
@@ -24,8 +24,9 @@ class SlackSmartBot
|
|
24
24
|
end
|
25
25
|
if memo
|
26
26
|
if memo_deleted
|
27
|
-
|
28
|
-
|
27
|
+
uname = memo.user.split("_")[1..-1].join("_")
|
28
|
+
messages = ["This memo was deleted from the team #{team_name}.\nOnly the creator (#{uname}) of the memo can get access to it."]
|
29
|
+
if memo.user == "#{user.team_id}_#{user.name}"
|
29
30
|
messages << "Memo #{memo.memo_id} (#{memo.type}): #{memo.message}"
|
30
31
|
end
|
31
32
|
else
|
@@ -39,24 +40,33 @@ class SlackSmartBot
|
|
39
40
|
else
|
40
41
|
if memo.type == "jira" and !memo_deleted
|
41
42
|
require "time"
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
43
|
+
if config.jira.host == "" or config.jira.user == "" or config.jira.password == ""
|
44
|
+
respond "You need to supply the correct credentials for JIRA on the SmartBot settings: `jira: { host: HOST, user: USER, password: PASSWORD }`"
|
45
|
+
else
|
46
|
+
begin
|
47
|
+
http = NiceHttp.new(config.jira.host)
|
48
|
+
http.headers.authorization = NiceHttpUtils.basic_authentication(user: config.jira.user, password: config.jira.password)
|
49
|
+
resp = http.get("/rest/api/2/issue/#{memo.message}/comment")
|
50
|
+
if resp.code.to_s == '200'
|
51
|
+
jira_comments = resp.data.json.comments
|
52
|
+
if !jira_comments.nil? and !jira_comments.empty?
|
53
|
+
messages << "\n_*JIRA Comments:*_"
|
54
|
+
jira_comments.each do |comment|
|
55
|
+
messages << " *#{comment.author.displayName}* > #{comment.body} _(#{Time.parse(comment.created).strftime("%Y/%m/%d %H:%M")})_"
|
56
|
+
end
|
57
|
+
end
|
51
58
|
end
|
59
|
+
http.close
|
60
|
+
rescue => exception
|
61
|
+
@logger.fatal exception
|
62
|
+
respond "There was an error trying to connect to JIRA. Please ask the admin to check the logs."
|
52
63
|
end
|
53
64
|
end
|
54
|
-
http.close
|
55
65
|
elsif memo.type == "github" and !memo_deleted
|
56
66
|
http = NiceHttp.new(config.github.host)
|
57
67
|
http.headers.authorization = "token #{config.github.token}"
|
58
68
|
resp = http.get("/repos/#{memo.message}/comments")
|
59
|
-
if resp.code == 200
|
69
|
+
if resp.code.to_s == '200'
|
60
70
|
github_comments = resp.data.json
|
61
71
|
if !github_comments.nil? and !github_comments.empty?
|
62
72
|
messages << "\n_*GitHub Comments:*_"
|
@@ -67,10 +77,11 @@ class SlackSmartBot
|
|
67
77
|
end
|
68
78
|
http.close
|
69
79
|
end
|
70
|
-
if memo.key?(:comments) and !memo.comments.empty? and (!memo_deleted or (memo_deleted and memo.user == user.name))
|
80
|
+
if memo.key?(:comments) and !memo.comments.empty? and (!memo_deleted or (memo_deleted and memo.user == "#{user.team_id}_#{user.name}"))
|
71
81
|
messages << "\n_*Comments:*_"
|
72
82
|
memo.comments.each do |comment|
|
73
|
-
|
83
|
+
uname = comment[:user_name].split("_")[1..-1].join("_")
|
84
|
+
messages << " *#{uname}* > #{comment[:message]} _(#{comment[:time][0..15]})_"
|
74
85
|
end
|
75
86
|
end
|
76
87
|
|