slack-smart-bot 1.12.9 → 1.13.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +85 -12
  3. data/lib/slack/smart-bot/comm/event_hello.rb +3 -1
  4. data/lib/slack/smart-bot/comm/respond.rb +1 -0
  5. data/lib/slack/smart-bot/comm/update.rb +13 -0
  6. data/lib/slack/smart-bot/comm.rb +1 -0
  7. data/lib/slack/smart-bot/commands/general/add_team.rb +1 -0
  8. data/lib/slack/smart-bot/commands/general/add_vacation.rb +5 -0
  9. data/lib/slack/smart-bot/commands/general/allow_access.rb +1 -1
  10. data/lib/slack/smart-bot/commands/general/delete_team.rb +1 -0
  11. data/lib/slack/smart-bot/commands/general/deny_access.rb +1 -1
  12. data/lib/slack/smart-bot/commands/general/public_holidays.rb +144 -0
  13. data/lib/slack/smart-bot/commands/general/see_announcements.rb +2 -2
  14. data/lib/slack/smart-bot/commands/general/see_memos_team.rb +202 -0
  15. data/lib/slack/smart-bot/commands/general/see_teams.rb +3 -175
  16. data/lib/slack/smart-bot/commands/general/see_vacations.rb +41 -21
  17. data/lib/slack/smart-bot/commands/general/set_public_holidays.rb +21 -0
  18. data/lib/slack/smart-bot/commands/general/update_team.rb +1 -0
  19. data/lib/slack/smart-bot/commands/general_bot_commands.rb +100 -8
  20. data/lib/slack/smart-bot/commands/on_bot/admin/add_routine.rb +27 -3
  21. data/lib/slack/smart-bot/commands/on_bot/admin/run_routine.rb +12 -8
  22. data/lib/slack/smart-bot/commands/on_bot/admin/see_routines.rb +33 -4
  23. data/lib/slack/smart-bot/commands/on_bot/admin/start_routine.rb +22 -1
  24. data/lib/slack/smart-bot/commands/on_bot/admin_master/send_message.rb +50 -4
  25. data/lib/slack/smart-bot/commands/on_bot/admin_master/update_message.rb +25 -0
  26. data/lib/slack/smart-bot/commands/on_bot/general/bot_stats.rb +6 -4
  27. data/lib/slack/smart-bot/commands/on_bot/repl.rb +55 -15
  28. data/lib/slack/smart-bot/commands/on_bot/ruby_code.rb +2 -1
  29. data/lib/slack/smart-bot/commands.rb +4 -0
  30. data/lib/slack/smart-bot/listen.rb +1 -1
  31. data/lib/slack/smart-bot/process.rb +36 -6
  32. data/lib/slack/smart-bot/process_first.rb +250 -188
  33. data/lib/slack/smart-bot/treat_message.rb +1 -1
  34. data/lib/slack/smart-bot/utils/build_help.rb +1 -1
  35. data/lib/slack/smart-bot/utils/create_routine_thread.rb +45 -5
  36. data/lib/slack/smart-bot/utils/decrypt.rb +15 -0
  37. data/lib/slack/smart-bot/utils/display_calendar.rb +86 -0
  38. data/lib/slack/smart-bot/utils/encrypt.rb +15 -0
  39. data/lib/slack/smart-bot/utils/encryption_get_key_iv.rb +29 -0
  40. data/lib/slack/smart-bot/utils/get_help.rb +1 -1
  41. data/lib/slack/smart-bot/utils/get_team_members.rb +39 -0
  42. data/lib/slack/smart-bot/utils/get_teams.rb +22 -16
  43. data/lib/slack/smart-bot/utils/get_vacations.rb +20 -15
  44. data/lib/slack/smart-bot/utils/save_stats.rb +2 -2
  45. data/lib/slack/smart-bot/utils/update_teams.rb +15 -9
  46. data/lib/slack/smart-bot/utils/update_vacations.rb +5 -3
  47. data/lib/slack/smart-bot/utils.rb +5 -0
  48. data/lib/slack-smart-bot.rb +9 -0
  49. data/lib/slack-smart-bot_general_commands.rb +33 -0
  50. data/lib/slack-smart-bot_general_rules.rb +2 -2
  51. data/whats_new.txt +15 -17
  52. metadata +27 -11
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 558fa51668313d856b46f1a46c79f033a6b8f65ad2da071e1825327a87770e87
4
- data.tar.gz: 568303701c7ab27c8798b542c55b23ee7d8f762fe8e7346506ce05dfd7eb3e2d
3
+ metadata.gz: 19f7d9b931ce89bf4a626e953ffb63b1f98ee16e1b330c6fc3c1c24ff0899227
4
+ data.tar.gz: abe96da2c61b844398cfc0c7eb433094f826fa4fb659c0ef2f5c01effad21c23
5
5
  SHA512:
6
- metadata.gz: f0ef8868f4f67c5da397f0652920a904d177bedcc78deee6889de146d598cbab6071509b1032294382148f614e69689f7fe7df59a1e40785529319b2200d1633
7
- data.tar.gz: 07ec60ba6ee00a0be8065906c2402778f69294b4ebc7f25e4c8085af085fd425f6456640f88ef75b74449b88bf30c278c9f3045efd17b544633c4575f79a18cb
6
+ metadata.gz: 17e5a9feb8c2b3d6974bdfacb02640fcbd29a399def6fca52affd84c236b54d547ab4ebf85ca4f1d983e06afcc226f46c9b5d8e4b764998523b40c04cdd2f45e
7
+ data.tar.gz: 1cea00686dd66557aa71d9badee0ca9b734f4bdc26daef145554639417d137bc1c4cb212d6fcac4008bb7c026a48043245910a1001c4ee4a1a3dff05efc9f3d0
data/README.md CHANGED
@@ -10,37 +10,40 @@ The main scope of this ruby gem is to be used internally in your company so team
10
10
 
11
11
  slack-smart-bot can create bots on demand, create shortcuts, run ruby code... just on a chat channel, you can access it just from your mobile phone if you want and run those tests you forgot to run, get the results, restart a server... no limits.
12
12
 
13
- ![](slack.png)
13
+ <img src="slack-smart-bot.png" width="150" height="150">![](slack.png)
14
14
 
15
15
  # Table of Contents
16
16
 
17
17
  - [Installation and configuration](#installation-and-configuration)
18
18
  - [Usage](#usage)
19
- * [creating the MASTER BOT](#creating-the-master-bot)
19
+ * [creating the MASTER BOT](#creating-the-master-bot) (A)
20
20
  * [How to access the Smart Bot](#how-to-access-the-smart-bot)
21
21
  * [Bot Help](#bot-help)
22
- * [Bot Management](#bot-management)
23
- + [Cloud Bots](#cloud-bots)
24
- * [Extending rules to other channels](#extending-rules-to-other-channels)
22
+ * [Bot Management](#bot-management) (A)
23
+ + [Cloud Bots](#cloud-bots) (A)
24
+ * [Extending rules to other channels](#extending-rules-to-other-channels) (A)
25
25
  * [Using rules from other channels](#using-rules-from-other-channels)
26
26
  * [Running Ruby code on a conversation](#running-ruby-code-on-a-conversation)
27
27
  + [REPL](#repl)
28
- * [Sending notifications](#sending-notifications)
28
+ * [Sending notifications](#sending-notifications) (A)
29
29
  * [Shortcuts](#shortcuts)
30
30
  * [Announcements](#announcements)
31
31
  * [Share Messages](#share-messages)
32
32
  * [See Statuses](#see-statuses)
33
- * [Routines](#routines)
34
- * [Control who has access to a command](#control-who-has-access-to-a-command)
33
+ * [Routines](#routines) (A)
34
+ * [Loops](#loops)
35
+ * [Control who has access to a command](#control-who-has-access-to-a-command) (A)
35
36
  * [See favorite commands](#see-favorite-commands)
36
37
  * [Teams](#teams)
37
38
  * [Time off management](#time-off-management)
38
39
  * [Tips](#tips)
39
- + [Send a file](#send-a-file)
40
- + [Download a file](#download-a-file)
40
+ + [Send a file](#send-a-file) (A)
41
+ + [Download a file](#download-a-file) (A)
41
42
  - [Contributing](#contributing)
42
43
  - [License](#license)
43
44
 
45
+ (A): Only for Admins
46
+
44
47
  ## Installation and configuration
45
48
 
46
49
  $ gem install slack-smart-bot
@@ -94,6 +97,8 @@ SmartBot will notify about SmartBot status changes or any SmartBot incident if d
94
97
  ## Usage
95
98
 
96
99
  ### creating the MASTER BOT
100
+ > for admins
101
+
97
102
  Let's guess the file you created was called my_smart_bot.rb so, just run it:
98
103
  ```
99
104
  nohup ruby my_smart_bot.rb&
@@ -194,6 +199,8 @@ Also you can add general rules that will be available on all Smart Bot channels
194
199
  If you have commands that want to make them available everywhere the Smart Bot is a member then add those commands to `./rules/general_commands.rb`.
195
200
 
196
201
  ### How to access the Smart Bot
202
+ > for all users
203
+
197
204
  You can access the bot directly on the MASTER CHANNEL, on a secondary channel where the bot is running and directly by opening a private chat with the bot, in this case the conversation will be just between you and the bot.
198
205
 
199
206
  On a Smart Bot channel you will be able to run some of the commands just by writing a command, for example: **_`bot help`_**
@@ -258,6 +265,8 @@ Examples:
258
265
  >**_Smart-Bot>_** `You're very welcome`
259
266
 
260
267
  ### Bot Help
268
+ > for all users
269
+
261
270
  To get a full list of all commands and rules for a specific Smart Bot: **_`bot help`_**. It will show only the specific available commands for the user requesting. By default it will display only a short version of the bot help, call **_`bot help expanded`_** to get a expanded version of all commands.
262
271
 
263
272
  If you want to search just for a specific command: **_`bot help COMMAND`_** It will display expanded explanations for the command.
@@ -293,6 +302,8 @@ For the examples use _ and for the rules `. This is a good example of a Help sup
293
302
  To see what's new just call `What's new`
294
303
 
295
304
  ### Bot Management
305
+ > for admins
306
+
296
307
  To create a new bot on a channel, run on MASTER CHANNEL: **_`create bot on CHANNEL`_**. The admins of this new bot on that channel will be the MASTER ADMINS, the creator of the bot and the creator of that channel. It will create a new rules file linked to this new bot.
297
308
 
298
309
  You can kill any bot running on any channel if you are an admin of that bot: **_`kill bot on CHANNEL`_**
@@ -316,11 +327,15 @@ You can add, remove and list admins of any channel by using: `add admin @user`,
316
327
  To see the full list of available command ids on any channel call: `see command ids`
317
328
 
318
329
  #### Cloud Bots
330
+ > for admins
331
+
319
332
  If you want to create a bot that will be running on a different machine: **_`create cloud bot on CHANNEL`_**. Even though the cloud bots are running on different machines, the management can be done through the MASTER CHANNEL. The new cloud bot will be managed by your Master Bot like the others, closing, pausing...
320
333
 
321
334
  Cloud Bots are typically used to run commands on specific environments or even different OS or networks.
322
335
 
323
336
  ### Extending rules to other channels
337
+ > for admins
338
+
324
339
  If you want to extend the use of your specific rules on a Bot Channel to a third channel you can use the command: **_`extend rules to CHANNEL`_**
325
340
 
326
341
  From that moment everybody part of that channel will be able to run the specific rules from the other channel but just on demand, for example: **_`!run something`_**
@@ -328,6 +343,8 @@ From that moment everybody part of that channel will be able to run the specific
328
343
  To stop allowing it: **_`stop using rules on CHANNEL`_**
329
344
 
330
345
  ### Using rules from other channels
346
+ > for all users
347
+
331
348
  To be able to access the rules from other channel or from a direct conversation with the bot, first of all you need to be a member of that channel. Then on a direct conversation with the Smart Bot or from another bot channel: **_`use rules from CHANNEL`_**
332
349
 
333
350
  When you want to stop using those rules with the bot: **_`stop using rules from CHANNEL`_**
@@ -335,6 +352,8 @@ When you want to stop using those rules with the bot: **_`stop using rules from
335
352
  Also you can always call the Smart Bot from any channel, even from channels without a running Smart Bot. You can use the External Call on Demand: **_`@NAME_OF_BOT on #CHANNEL_NAME COMMAND`_**. In this case you will call the bot on #CHANNEL_NAME.
336
353
 
337
354
  ### Running Ruby code on a conversation
355
+ > for all users
356
+
338
357
  You can run Ruby code by using the command: **_`ruby THE_CODE`_**.
339
358
 
340
359
  Example:
@@ -344,6 +363,8 @@ Example:
344
363
  Also it is possible to attach a Ruby file and the Smart Bot will run and post the output. You need to select Ruby as file format. Or if you prefer it you can call the `ruby` command and on the same message supply a code block.
345
364
 
346
365
  #### REPL
366
+ > for all users
367
+
347
368
  Easily starts a REPL session so you will be able to create a script directly from the slack conversation. You will be able to share the REPL so they can run it or see the content.
348
369
 
349
370
  It Will run all we write as a ruby command and will keep the session values until we finish the session sending `quit`, `exit` or `bye`
@@ -400,9 +421,13 @@ You can run repls and supply parameters to the repl that will be executed on the
400
421
  Example:
401
422
  >**_Peter>_** ``run repl Create10RandomUsers `request = {path: '/api-dev/users/'}` ``
402
423
 
424
+ If you want to add a collaborator while you are on a repl call `add collaborator @USER`. From that moment that user will be able to interact with the repl. You can add all the collaborators you want. When any collaborator wants to jump off the repl, that user can use the `quit` command.
425
+
403
426
  Other REPL commands: `see repls`, `run repl SESSION_NAME ENV_VAR=value`, `get repl SESSION_NAME`, `delete repl SESSION_NAME`, `kill repl RUN_REPL_ID`
404
427
 
405
428
  ### Sending notifications
429
+ > for admins
430
+
406
431
  You can send notifications from MASTER CHANNEL by using **_`notify MESSAGE`_**. All Bot Channels will be notified.
407
432
 
408
433
  If you want to send a notification message to all channels the bot joined and direct conversations with the bot: **_`notify all MESSAGE`_**
@@ -410,6 +435,8 @@ If you want to send a notification message to all channels the bot joined and di
410
435
  And if you want to send a notification message to the specified channel and to its extended channels: **_`notify #CHANNEL MESSAGE`_**
411
436
 
412
437
  ### Shortcuts
438
+ > for all users
439
+
413
440
  Sometimes your commands or rules are too long and you want to add a shortcut to be executed.
414
441
 
415
442
  If you have for example a rule like this: **_`run tests on customers android app`_** and you want to add a shortcut: **_`add shortcut run tca: run tests on customers android app`_**
@@ -439,6 +466,8 @@ Example:
439
466
  To see available shortcuts: **_`see shortcuts`_** and to delete a particular shortcut: **_`delete shortcut NAME`_**
440
467
 
441
468
  ### Announcements
469
+ > for all users
470
+
442
471
  You can add any announcement on any channel where the SmartBot is a member by using **_`add COLOR announcement MESSAGE`_** or **_`add EMOJI announcement MESSAGE`_**.
443
472
 
444
473
  It will store the message on the announcement list labeled with the color/emoji specified, white by default. Possible colors white, green, yellow and red. Aliases for announcement: statement, declaration, message.
@@ -455,6 +484,8 @@ To see the announcements of the channel: **_`see announcements`_**, **_`see COLO
455
484
  If you are a master admin and you are on master channel then you can call **_`publish announcements`_** that will publish the announcements on all channels. The messages stored on a DM won't be published. This is very convenient to be called from a *Routine* for example every weekday at 09:00.
456
485
 
457
486
  ### Share messages
487
+ > for all users
488
+
458
489
  You can automatically share any new message that is posted on the channel and meet the specified criteria by using **_`share messages /REGEXP/ on #CHANNEL`_** or **_`share messages "TEXT" on #CHANNEL`_**.
459
490
 
460
491
  This command is only available in public channels. The user adding the Share and the SmartBot need to be a member of both channels.
@@ -466,6 +497,8 @@ Examples:
466
497
  To see the shares of the channel: **_`see shares`_** and to delete a particular share: **_`delete share ID`_**
467
498
 
468
499
  ### See statuses
500
+ > for all users
501
+
469
502
  To see a list of statuses of the members in the channel you can call `see statuses`, `who is on vacation?`, `who is not on vacation?`, `who is on EMOJI`, `who is on EMOJI #CHANNEL`
470
503
 
471
504
  You need to be a member of the channel to be able to get this info.
@@ -479,6 +512,8 @@ Examples:
479
512
  >**_Peter>_** `who is available?`
480
513
 
481
514
  ### Routines
515
+ > for admins
516
+
482
517
  To add specific commands to be run automatically every certain amount of time or a specific time: **_`add routine NAME every NUMBER PERIOD COMMAND`_** or **_`add routine NAME at TIME COMMAND`_**. Also just before the command you can supply the channel where you want to publish the results, if not channel supplied then it would be the SmartBot Channel or on the DM if the command is run from there. Remember the SmartBot needs to have access to the channel where you want to publish.
483
518
 
484
519
  In case you create a *bgroutine* instead of a normal *routine* then the results of the run won't be published.
@@ -494,6 +529,7 @@ Examples:
494
529
  >**_`add routine clean_custdb on Mondays at 05:00 !clean customers db`_**
495
530
  >**_`add routine clean_custdb on Tuesdays at 09:00 #SREChannel !clean customers db`_**
496
531
  >**_`add silent routine suggestions on weekdays at 09:00 suggest command`_**
532
+ >**_`add routine example on the 31st at 20:00 ^results sales monthly`_**
497
533
 
498
534
  Also instead of adding a Command to be executed, you can attach a file, then the routine will be created and the attached file will be executed on the criteria specified. Also you can supply a script adding \`\`\`the code\`\`\` and specifying on the routine name the extension that will have. Only Master Admins are allowed to add files or scripts.
499
535
 
@@ -505,7 +541,24 @@ Other routine commands:
505
541
  * **_`see routines`_**
506
542
  * **_`see result routine NAME`_**
507
543
 
544
+ ### Loops
545
+ > for all users
546
+
547
+ You can run any command or rule on a loop by using:
548
+ **_`for NUMBER times every NUMBER minutes COMMAND`_**
549
+ **_`for NUMBER times every NUMBER seconds COMMAND`_**
550
+ Maximum number of times to be used: 24. Minimum every 10 seconds. Maximum every 60 minutes.
551
+
552
+ To stop the execution of a loop you can use: **_`quit loop LOOP_ID`_**
553
+ Examples:
554
+ >**_`for 5 times every 1 minute ^ruby puts Time.now`_**
555
+ >**_`10 times every 30s !ruby puts Time.now`_**
556
+ >**_`24 times every 60m !get sales today`_**
557
+ >**_`quit loop 1`_**
558
+ >**_`stop iterator 12`_**
559
+
508
560
  ### Control who has access to a command
561
+ > for admins
509
562
 
510
563
  You can add, remove and list admins of any channel by using: `add admin @user`, `remove admin @user` and `see admins`. You need to be the creator of the channel, a Master admin or an admin.
511
564
 
@@ -568,6 +621,7 @@ it will show the access rights for the specified command
568
621
  The authorization is controlled by `save_stats` so it will be check out when calling `save_stats` or by calling `has_access?(:your_command_id)`
569
622
 
570
623
  ### See favorite commands
624
+ > for all users
571
625
 
572
626
  It will display the favorite commands in that channel.
573
627
 
@@ -578,6 +632,7 @@ Examples:
578
632
  >**_`most used commands`_**
579
633
 
580
634
  ### Teams
635
+ > for all users
581
636
 
582
637
  You can add, update, see, ping and delete teams. When calling `see TEAM_NAME team` the availability of the members will be displayed.
583
638
  `add team TEAM_NAME PROPERTIES` will add a team with the info supplied. In case it is supplied a channel with type 'members' the members of that channel would be considered members of the team.
@@ -629,10 +684,13 @@ Examples:
629
684
  >**_`add jira to sales team : labels = SalesT AND status != Done`_**
630
685
  >**_`add github to sales team : https://github.com/PeterBale/SalesBoom/issues?q=is%3Aissue+is%3Aopen+`_**
631
686
  >**_`set :runner: on memo 7 team Sales`_**
687
+ >**_`see all memos from Sales team`_**
688
+ >**_`see bugs from Sales team dev`_**
632
689
 
633
- Other team commands: **_`delete team TEAM_NAME`_**, **_`delete memo ID from team TEAM_NAME`_**, **_`set STATUS on memo ID TEAM_NAME team`_**
690
+ Other team commands: **_`delete team TEAM_NAME`_**, **_`delete memo ID from team TEAM_NAME`_**, **_`set STATUS on memo ID TEAM_NAME team`_**, **_`see MEMO_TYPE from TEAM_NAME team TOPIC`_**
634
691
 
635
692
  ### Time off management
693
+ > for all users
636
694
 
637
695
  You will be able to add or remove vacation and sick periods by using `add vacation/sick from YYYY/MM/DD to YYYY/MM/DD`. The SmartBot will automatically set the users status to 🌴 or 🤒 and the expiration date when the user is on vacation or sick. The SmartBot won't be allowed to change the status of workspace admins or owners.
638
696
 
@@ -649,9 +707,24 @@ settings = {
649
707
  }
650
708
  ```
651
709
 
652
- Other 'time off' commands: **_`remove time off ID`_**, **_`see my time off`_**, **_`see vacations @USER`_**, **_`time off team NAME`_**
710
+ If you want to see the public holidays for a specific country or country/region you can use the command `public holidays COUNTRY/REGION`. Examples: `public holidays Iceland`, `public holidays Spain/Madrid`, `public holidays United States/California 2024`, `public holidays Spain/Catalonia 2024/04`.
711
+ You need to set up an account on https://www.calendarific.com
712
+ Add to your Smartbot configuration:
713
+ ```ruby
714
+ settings = {
715
+ public_holidays: {
716
+ api_key: API_KEY
717
+ }
718
+ }
719
+ ```
720
+
721
+ When calling `see my time off` on a DM will display a calendar of the year with the days off, including public holidays
722
+ <img src="img/my_timeoff.png" width="650">
723
+
724
+ Other 'time off' commands: **_`remove time off ID`_**, **_`see my time off`_**, **_`see vacations @USER`_**, **_`time off team NAME`_**, **_`set public holidays to COUNTRY/REGION`_**
653
725
 
654
726
  ### Tips
727
+ > for admins
655
728
 
656
729
  #### Send a file
657
730
 
@@ -1,5 +1,6 @@
1
1
  class SlackSmartBot
2
2
  def event_hello()
3
+ @first_time_bot_started ||= true
3
4
  unless config.simulate
4
5
  m = "Successfully connected, welcome '#{client.self.name}' to the '#{client.team.name}' team at https://#{client.team.domain}.slack.com."
5
6
  puts m
@@ -18,7 +19,7 @@ class SlackSmartBot
18
19
  version_message = ". There is a new available version: #{version_remote}."
19
20
  end
20
21
  if (!config[:silent] or ENV['BOT_SILENT'].to_s == 'false') and !config.simulate
21
- unless ENV['BOT_SILENT']=='true'
22
+ unless ENV['BOT_SILENT']=='true' or !@first_time_bot_started
22
23
  respond "Smart Bot started v#{VERSION}#{version_message}\nIf you want to know what I can do for you: `bot help`.\n`bot rules` if you want to display just the specific rules of this channel.\nYou can talk to me privately if you prefer it."
23
24
  end
24
25
  ENV['BOT_SILENT'] = 'true' if config[:silent] and ENV['BOT_SILENT'].to_s != 'true'
@@ -30,5 +31,6 @@ class SlackSmartBot
30
31
  end
31
32
  end
32
33
  end
34
+ @first_time_bot_started = false
33
35
  end
34
36
  end
@@ -58,6 +58,7 @@ class SlackSmartBot
58
58
  end
59
59
  txt += (m + "\n")
60
60
  txt[0] = '.' if txt.match?(/\A\s\s\s/) #first line of message in slack don't show spaces at the begining so we force it by changing first char
61
+ txt[0] = ". " if txt.match?(/\A\t/)
61
62
  end
62
63
  end
63
64
  msgs << txt
@@ -0,0 +1,13 @@
1
+ class SlackSmartBot
2
+ def update(channel, ts, text)
3
+ result = true
4
+ begin
5
+ resp = client.web_client.chat_update(channel: channel, as_user: true, ts: ts, text: text)
6
+ result = resp.ok.to_s == 'true'
7
+ rescue Exception => exc
8
+ result = false
9
+ @logger.fatal exc.inspect
10
+ end
11
+ return result
12
+ end
13
+ end
@@ -16,3 +16,4 @@ require_relative 'comm/get_channels'
16
16
  require_relative 'comm/delete'
17
17
  require_relative 'comm/get_presence'
18
18
  require_relative 'comm/set_status'
19
+ require_relative 'comm/update'
@@ -70,6 +70,7 @@ class SlackSmartBot
70
70
  team[:creator] = user.name
71
71
  team[:date] = Time.now.strftime("%Y-%m-%dT%H:%M:%S.000Z")[0..18]
72
72
  new_team = {}
73
+ team[:name] = name
73
74
  new_team[name.to_sym] = team
74
75
  update_teams(new_team)
75
76
  respond "The *#{name}* team has been added."
@@ -36,6 +36,11 @@ class SlackSmartBot
36
36
  else
37
37
  vacations = @vacations.deep_copy
38
38
  vacations[user.name] ||= { user_id: user.id, periods: [] }
39
+ if !vacations[user.name].key?(:periods)
40
+ vacations[user.name][:user_id] = user.id
41
+ vacations[user.name][:periods] = []
42
+ end
43
+
39
44
  if vacations[user.name].periods.empty?
40
45
  vacation_id = 1
41
46
  else
@@ -2,7 +2,7 @@ class SlackSmartBot
2
2
  def allow_access(user, command_id, opt)
3
3
  save_stats(__method__)
4
4
  not_allowed = ["hi_bot", "bye_bot", "allow_access", "deny_access", "get_bot_logs", "add_routine", "pause_bot", "pause_routine", "remove_routine", "run_routine", "start_bot",
5
- "start_routine", "delete_message", "send_message", "kill_bot_on_channel", "exit_bot", "notify_message", "publish_announcements", "set_general_message",
5
+ "start_routine", "delete_message", "update_message", "send_message", "kill_bot_on_channel", "exit_bot", "notify_message", "publish_announcements", "set_general_message",
6
6
  "set_maintenance", "bot_help", "bot_rules"]
7
7
  if !is_admin?(user.name)
8
8
  respond "Only admins of this channel can use this command. Take a look who is an admin of this channel by calling `see admins`"
@@ -38,6 +38,7 @@ class SlackSmartBot
38
38
  when /yes/i, /yep/i, /sure/i
39
39
  answer_delete
40
40
  @teams.delete(team_name.to_sym)
41
+ File.delete(File.join(config.path, "teams", "t_#{team_name}.yaml"))
41
42
  update_teams()
42
43
  respond "The team #{team_name} has been deleted."
43
44
  when /no/i, /nope/i, /cancel/i
@@ -2,7 +2,7 @@ class SlackSmartBot
2
2
  def deny_access(user, command_id)
3
3
  save_stats(__method__)
4
4
  not_allowed = ['hi_bot', 'bye_bot', "allow_access", "deny_access", "get_bot_logs", "add_routine", "pause_bot", "pause_routine", "remove_routine", "run_routine", "start_bot",
5
- "start_routine", "delete_message", "send_message", "kill_bot_on_channel", "exit_bot", "notify_message", "publish_announcements", "set_general_message",
5
+ "start_routine", "delete_message", "update_message", "send_message", "kill_bot_on_channel", "exit_bot", "notify_message", "publish_announcements", "set_general_message",
6
6
  "set_maintenance", 'bot_help', 'bot_rules']
7
7
  if !is_admin?(user.name)
8
8
  respond "Only admins of this channel can use this command. Take a look who is an admin of this channel by calling `see admins`"
@@ -0,0 +1,144 @@
1
+ def public_holidays(country_name, location, year, month, day, add_stats: true, publish_results: true)
2
+ save_stats(__method__) if add_stats
3
+ if config[:public_holidays][:api_key].to_s == ""
4
+ respond "Sorry, I don't have the API key for the public holidays #{config[:public_holidays][:host]}. Set it up on your SmartBot config file."
5
+ else
6
+ begin
7
+ found_location = true
8
+ http = NiceHttp.new("#{config[:public_holidays][:host]}/api/v2")
9
+ if !defined?(@countries_candelarific)
10
+ if File.exist?("#{config.path}/vacations/countries_candelarific.json")
11
+ @countries_candelarific = JSON.parse(File.read("#{config.path}/vacations/countries_candelarific.json"))
12
+ else
13
+ response = http.get "/countries?api_key=#{config[:public_holidays][:api_key]}"
14
+ countries_candelarific = response.data.json(:countries)
15
+ if countries_candelarific.is_a?(Array)
16
+ File.write("#{config.path}/vacations/countries_candelarific.json", countries_candelarific.to_json)
17
+ @countries_candelarific = JSON.parse(countries_candelarific.to_json)
18
+ else
19
+ @countries_candelarific = []
20
+ end
21
+ end
22
+ end
23
+ country = @countries_candelarific.find { |c| c.country_name.match?(/^\s*#{country_name}\s*$/i) }
24
+ if country.nil?
25
+ respond "Country #{country_name} not found"
26
+ else
27
+ country_original_name = country_name.downcase
28
+ country_region_id = country_name.downcase
29
+ country_region_id += "/#{location.downcase}" unless location.empty?
30
+ country_name = country["country_name"]
31
+ country_iso = country["iso-3166"]
32
+ states = []
33
+ if @public_holidays.key?(country_region_id) and @public_holidays[country_region_id].key?(year.to_s)
34
+ holidays = @public_holidays[country_region_id][year.to_s]
35
+ elsif File.exist?(File.join(config.path, "vacations", "#{year}_#{country_region_id.gsub("/", "_").gsub(" ", "_")}.json"))
36
+ holidays = (File.read(File.join(config.path, "vacations", "#{year}_#{country_region_id.gsub("/", "_").gsub(" ", "_")}.json"))).json()
37
+ elsif !location.empty? and File.exist?(File.join(config.path, "vacations", "#{year}_#{country_original_name.gsub("/", "_").gsub(" ", "_")}.json"))
38
+ holidays = (File.read(File.join(config.path, "vacations", "#{year}_#{country_original_name.gsub("/", "_").gsub(" ", "_")}.json"))).json()
39
+ holidays.each do |holiday|
40
+ if holiday.states.is_a?(Array)
41
+ states << holiday.states.name
42
+ else
43
+ states << holiday.states
44
+ end
45
+ end
46
+ holidays = holidays.select { |h| h.states.is_a?(String) and h.states == "All" or (h.states.is_a?(Array) and h.states.name.grep(/^\s*#{location}\s*$/i).length > 0) }
47
+ holidays_specific = holidays.select { |h| h.states.is_a?(Array) and h.states.name.grep(/^\s*#{location}\s*$/i).length > 0 }
48
+ found_location = false if holidays_specific.length == 0
49
+ else
50
+ response = http.get "/holidays?country=#{country_iso}&year=#{year}&day=#{day}&month=#{month}&api_key=#{config[:public_holidays][:api_key]}"
51
+ holidays = response.data.json(:holidays)
52
+ if location != ""
53
+ holidays.each do |holiday|
54
+ if holiday.states.is_a?(Array)
55
+ states << holiday.states.name
56
+ else
57
+ states << holiday.states
58
+ end
59
+ end
60
+ holidays = holidays.select { |h| h.states.is_a?(String) and h.states == "All" or (h.states.is_a?(Array) and h.states.name.grep(/^\s*#{location}\s*$/i).length > 0) }
61
+ holidays_specific = holidays.select { |h| h.states.is_a?(Array) and h.states.name.grep(/^\s*#{location}\s*$/i).length > 0 }
62
+ found_location = false if holidays_specific.length == 0
63
+ end
64
+ if day == "" and month == "" and holidays.is_a?(Array) and holidays.length > 0 and found_location
65
+ File.write(File.join(config.path, "vacations", "#{year}_#{country_region_id.gsub("/", "_").gsub(" ", "_")}.json"), holidays.to_json) if holidays.is_a?(Array)
66
+ end
67
+ end
68
+ if day == "" and month == ""
69
+ date = year
70
+ elsif day == ""
71
+ date = "#{year}-#{"%02d" % month}"
72
+ else
73
+ date = "#{year}-#{"%02d" % month}-#{"%02d" % day}"
74
+ end
75
+
76
+ if holidays.is_a?(Array) and holidays.length > 0 and found_location
77
+ date_holiday = ""
78
+ messages = ["*Holidays in #{country_name}#{" #{location.downcase.capitalize}" unless location.empty?} in #{date}*"]
79
+ num_holidays_to_show = 0
80
+ all_holidays = []
81
+ states = []
82
+ holidays_to_add = []
83
+ holidays.each do |holiday|
84
+ if holiday.type.join.match?(/holiday/i)
85
+ if location == "" or (location != "" and (holiday.states.is_a?(String) and holiday.states == "All") or (holiday.states.is_a?(Array) and holiday.states.name.grep(/#{location}/i).length > 0))
86
+ holiday_id = "#{holiday[:date][:datetime][:year]}-#{"%02d" % holiday[:date][:datetime][:month]}-#{"%02d" % holiday[:date][:datetime][:day]} #{holiday[:name]}"
87
+ unless all_holidays.include?(holiday_id) or
88
+ (day != "" and holiday[:date][:datetime][:day] != day.to_i) or
89
+ (month != "" and holiday[:date][:datetime][:month] != month.to_i)
90
+ all_holidays << holiday_id
91
+ if day == ""
92
+ m = holiday[:date][:datetime][:month]
93
+ d = holiday[:date][:datetime][:day]
94
+ date_holiday = " #{holiday[:date][:datetime][:year]}-#{"%02d" % m}-#{"%02d" % d} "
95
+ end
96
+ num_holidays_to_show += 1
97
+ break if num_holidays_to_show > 30 and publish_results
98
+ week_day = Date.new(holiday[:date][:datetime][:year], holiday[:date][:datetime][:month], holiday[:date][:datetime][:day]).strftime("%A")
99
+ messages << "\t:spiral_calendar_pad:#{date_holiday}*#{holiday[:name]}* _(#{holiday[:type].join(", ")}) (#{week_day})_"
100
+ messages << "\t#{holiday[:description]}"
101
+ if location == ""
102
+ if holiday.states.is_a?(Array)
103
+ messages << "\tLocations: #{holiday.states.name.sort.join(", ")}"
104
+ else
105
+ messages << "\tLocations: #{holiday.states}"
106
+ end
107
+ end
108
+ if holiday.states.is_a?(Array)
109
+ states << holiday.states.name
110
+ else
111
+ states << holiday.states
112
+ end
113
+ messages << "\n"
114
+ holidays_to_add << holiday
115
+ end
116
+ end
117
+ end
118
+ end
119
+ @public_holidays[country_region_id] = {} if !@public_holidays.key?(country_region_id)
120
+ @public_holidays[country_region_id][year.to_s] = holidays_to_add if !@public_holidays[country_region_id].key?(year.to_s)
121
+
122
+ if num_holidays_to_show > 30
123
+ messages = ["*Holidays in #{country_name}#{" #{location.downcase.capitalize}" unless location.empty?} in #{date}*"]
124
+ messages << "Too many holidays to show, please refine your search"
125
+ end
126
+ else
127
+ messages = ["*No holidays found in #{country_name}#{" #{location.downcase.capitalize}" unless location.empty?} in #{date}. Be sure the Country and State are written correctly. Try using just the Country, not all countries are supporting States.*"]
128
+ end
129
+ states.flatten!
130
+ states.uniq!
131
+ states.delete("All")
132
+ if states.length > 1 and (location == "" or !found_location)
133
+ messages << "*All States found in #{date} #{country_name}*: #{states.sort.join(", ")}"
134
+ respond messages[-1] if !publish_results
135
+ end
136
+ respond messages.join("\n") unless !publish_results
137
+ end
138
+ rescue Exception => stack
139
+ respond "Sorry, I can't get the public holidays for #{country_name} #{location} in #{date}. Error: #{stack.message}"
140
+ @logger.fatal stack
141
+ end
142
+ return (found_location==true and !country.nil?) if !publish_results
143
+ end
144
+ end
@@ -74,9 +74,9 @@ class SlackSmartBot
74
74
  user_created = user_info.profile.display_name unless user_info.nil?
75
75
  end
76
76
  if type == 'all' and channel_id[0]=='D'
77
- message << "\t#{m[:message_id]} #{emoji} *_#{m[:date]}_* #{m[:time]} *:* \t*private*"
77
+ message << "\t#{emoji} *private* _(id:#{m[:message_id]} - #{m[:date]} #{m[:time]})_"
78
78
  else
79
- message << "\t#{m[:message_id]} #{emoji} *_#{m[:date]}_* #{m[:time]} #{"#{user_created} " unless channel_id[0]=='D'}*:* \t#{m[:message]}"
79
+ message << "\t#{emoji} #{m[:message]} _(id:#{m[:message_id]} - #{m[:date]} #{m[:time]} #{user_created})_"
80
80
  end
81
81
  end
82
82
  end