Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvements #9

Open
wants to merge 17 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 41 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,59 @@
The purpose of this bot is to send a message to your team's Slack when is someones birthday.


## Setup & Deploy
## Setup

1. Clone this repo to a desired location on your own computer
2. Configure an [Incoming Webhook URL](https://api.slack.com/incoming-webhooks) from Slack
3. Choose your desired database structure file ( `<ext>` : YAML / JSON ).
( YAML is easier to configure as you have to bother about the indentation with spaces alone. You'll have to bother a lot more with JSON - Parentheses, commas. But in the end it's what you're more comfortable with that matters. )
1. Make a copy of the `birthdays.<ext>.example` file naming it to `birthdays.<ext>`.
2. Populate your birthdays database with the birthdays of your team members.
* NB : You can either use their real names or their usernames. Just remember to configure the mention configuration correctly.
4. Make a copy of the `configurations.json.example` file naming it `configurations.json`. Update the configuration values according to your preferences
```
{
"db_path" : "birthdays.<ext>", # according to your preference
# birthdays.yaml for YAML and birthdays.json for JSON
"mention" : <true | false>, # depends on your database configuration format
# if you're using real names, set this value to false
# if you're using usernames, set this value to true
"slack_url" : "https://hooks.slack.com/...", # the webhook URL you configured in step 2.
"channel_name" : "<channel_name>", # the channel you want your wishes to be sent to
"greeting_message" : "Happy birthday!" # the wish you would like the bot to send
"bot_name" : "Birthday Bot" # the name of the bot sending the wish
"bot_emoji" : ":tada:" # the emoji the bot should use as it's icon
}
```

## Deploy

### Heroku

1. Clone this repo to a desire location at your own computer
2. Get your [Incoming Webhook URL](https://api.slack.com/incoming-webhooks) from Slack
3. Save the url at `configurations.json` file and fill in the rest of the configurations as you like
4. Set your birthdays list using the format `FirstName LastName YY MM DD` at the `birthdays.txt` file
5. Create a blank app at Heroku
6. Push your code to Heroku
7. The bot was developed with the **2.2.6** version of ruby, any other versions may require changes.
7. Run `heroku addons:create scheduler:standard` to add the Scheduler add-on to your deploy
8. Run `heroku addons:open scheduler` to configure the scheduler
9. Click **Add a new job** and type `rake congratulate` as the command
10. Set frequency to **Daily** and choose the **Time** you want to be notified
1. Create a blank app at Heroku
2. Push your code to Heroku
3. The bot was developed with the **2.2.6** version of ruby, any other versions may require changes.
4. Run `heroku addons:create scheduler:standard` to add the Scheduler add-on to your deploy
5. Run `heroku addons:open scheduler` to configure the scheduler
6. Click **Add a new job** and type `rake congratulate` as the command
7. Set frequency to **Daily** and choose the **Time** you want to be notified

### Custom Server

1. Clone this repo to a desire location at your own server
2. Get your [Incoming Webhook URL](https://api.slack.com/incoming-webhooks) from Slack
3. Save the url at `configurations.json` file and fill in the rest of the configurations as you like
4. Set your birthdays list using the format `FirstName LastName YY MM DD` at the `birthdays.txt` file
5. Run `crontab -e` to edit your crontab
6. Add this line to the crontab and save it: `0 9 * * * cd /clone/location && /usr/local/bin/rake congratulate` (replace `/clone/location` by the location where you cloned the repo)
1. Run `crontab -e` to edit your crontab
2. Add this line to the crontab and save it:
`@daily cd /clone/location && /usr/local/bin/rake congratulate`
* replace `/clone/location` with the location where you cloned the repo)
* the `@daily` `cron` shorthand might vary among servers and/or distributions.
Replace `@daily` with a time of your preference according to the [`cron` syntax](http://tldp.org/LDP/lame/LAME/linux-admin-made-easy/using-cron.html).
* Remember to verify the timezone setting of your server or you won't get the expected result.


## Contributors

This project was originally created by [Tiago Botelho](https://github.com/tiagonbotelho), while he was an intern at [jeKnowledge](http://jeknowledge.pt/).

It was later revised by [Diogo Nunes](http://www.diogonunes.com/) from [EqualExperts](https://www.equalexperts.com/) and [João Bernardo](http://jbernardo.me) from [jeKnowledge](http://jeknowledge.pt/).
It was later revised by [Diogo Nunes](http://www.diogonunes.com/) from [EqualExperts](https://www.equalexperts.com/), [João Bernardo](http://jbernardo.me) from [jeKnowledge](http://jeknowledge.pt/) and @shinenelson.

## License

Expand Down
1 change: 0 additions & 1 deletion birthdays.example.txt

This file was deleted.

17 changes: 17 additions & 0 deletions birthdays.json.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"01" :
{
"01" : [ "elvina.slovak" ]
},

"02" :
{
"02" : [ "john.doe", "jane.doe" ],
"28" : [ "chris.nolan" ],
},

"04" :
{
"15" : [ "erwin.down", "leora.pontious", "randy.young" ]
}
}
9 changes: 9 additions & 0 deletions birthdays.yaml.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
"01" :
"01" : [ "elvina.slovak" ]

"02" :
"02" : [ "john.doe", "jane.doe" ]
"28" : [ "chris.nolan" ]

"04" :
"15" : [ "erwin.down", "leora.pontious", "randy.young" ]
2 changes: 2 additions & 0 deletions configurations.json → configurations.json.example
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
{
"birthdays_path": "birthdays.yaml",
"mention": true,
"slack_url": "https://hooks.slack.com/...",
"channel_name": "general",
"greeting_message": "Happy birthday !",
Expand Down
41 changes: 30 additions & 11 deletions lib/birthday_bot.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,45 @@
require 'birthday_reader'

class BirthdayBot
@@path = "birthdays.txt"

def initialize()
@config = ConfigReader.new
@config.load('configurations.json')
end

def start!
birthdays = BirthdayReader.get_birthdays(@@path)
today = Time.now
birthdays = BirthdayReader.get_birthdays(@config.birthdays_path)

puts "Checking who was born today (#{today.to_s})"
birthdays.each do |b|
if (b[3].to_i == today.month) && (b[4].to_i == today.day)
message = "#{@config.greeting_message} #{b[0]} #{b[1]}"
HTTParty.post(@config.slack_url, body: { channel: @config.channel_name,
username: @config.bot_name,
text: message,
icon_emoji: @config.bot_emoji }.to_json)
puts "Checking who was born today ( #{ Time.now.to_s } )"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

puts "Checking who was born today (#{ Time.now.to_s })" remove the spaces.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I felt it would be more legible with the spaces.

unless birthdays.nil?
users = "#{ mention birthdays[0] }"
if birthdays.count > 1
puts "#{ birthdays.count } people were born today"
if birthdays.count == 2
users = " #{ mention birthdays[0] } and #{ mention birthdays[1] } "
else
for i in 1..birthdays.count-2
users.concat( ", #{ mention birthdays[i] }" )
end
users.concat( " and #{ mention birthdays[i+1] } " )
end
end
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can simplify this:

puts "#{birthdays.count} were born today"

today = Time.now
birthdays_today = birthdays[today.month][today.day]

unless birthdays_today.empty?
  users = build_user_list(birthdays_today)
  message = "#{users} #{@config.greeting_message}"
  HTTParty.post(@config.slack_url, body: { channel: @config.channel_name,
    username: @config.bot_name,
    text: message,
    icon_emoji: @config.bot_emoji }.to_json)
end
 
# ...

def build_user_list(birthdays)
  if birthdays.size == 1
    birthdays.first
  else
    users = birthdays.take(birthdays.count - 1).join(", ")
    users += " and #{birthdays[birthdays.count - 1]}" if birthdays.count > 1
  end
end

What do you think ?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shinenelson Did you take a look at this ?

(mentions are missing here)

message = "#{users} #{@config.greeting_message}"
HTTParty.post(@config.slack_url, body: { channel: @config.channel_name,
username: @config.bot_name,
text: message,
icon_emoji: @config.bot_emoji }.to_json)
else
puts "Today is a day that no one was born"
end
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you looked at my previous comment with a suggestion to refactor this function ?

puts "#{birthdays.count} were born today"

today = Time.now
birthdays_today = birthdays[today.month][today.day]

unless birthdays_today.empty?
  users = build_user_list(birthdays_today)
  message = "#{users} #{@config.greeting_message}"
  HTTParty.post(@config.slack_url, body: { channel: @config.channel_name,
    username: @config.bot_name,
    text: message,
    icon_emoji: @config.bot_emoji }.to_json)
end
 
# ...

def build_user_list(birthdays)
  if birthdays.size == 1
    birthdays.first
  else
    users = birthdays.take(birthdays.count - 1).join(", ")
    users += " and #{birthdays[birthdays.count - 1]}" if birthdays.count > 1
  end
end

end

def mention ( name )
if @config.mention
"<@#{ name }>"
else
name
end
end
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you give an example where disabling mentions is useful ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The earlier version of the database stored the real names of users. The bot wished users with their real names. So, I thought that could be a valid use-case

But like my commit message said, some people might prefer wishing their team-mates by their real names (probably for more family-togetherness) and/or not choosing to spam the users with mentions on the wishes (but that wil probably be taken care of by other team-mates, anyway).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense, thanks !


end
11 changes: 6 additions & 5 deletions lib/birthday_reader.rb
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
require 'yaml'

class BirthdayReader
def self.get_birthdays(file_path)
birthdays = []
if File.exist?(file_path)
file = File.new(file_path, 'r')
file.each_line do |line|
birthdays << line.chomp.split
end
file.close
bday_list = YAML.load_file(file_path)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The purpose of this class is to read birthdays only, I don't think we should return only the birthdays according to Time.now, instead we should return all of them.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The primary reason I switched to a structured format for the database was to drill down to the exact date to fetch all the birthdays on the day. What would be the use case to have return all the birthdays together? It would just use more memory (for no particular gain, whatsoever) IMHO.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not against the structuring.

What I am saying is that the purpose of the function is to read birthdays. It is not to read and filter. That is why I think we should not filter the birthdays here.

And because we are just managing strings of birthdays I guess memory is not a concern.

unless bday_list.nil? || bday_list.empty?
birthdays = bday_list[Time.now.month.to_s][Time.now.day.to_s]
end
end
return birthdays
end
Expand Down
6 changes: 5 additions & 1 deletion lib/config_reader.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
require 'json'

class ConfigReader
attr_accessor :slack_url,
attr_accessor :birthdays_path,
:mention,
:slack_url,
:channel_name,
:greeting_message,
:bot_name,
Expand All @@ -11,6 +13,8 @@ def load(filename)
if File.exist?(filename)
file = File.read(filename)
config = JSON.parse(file)
@birthdays_path = config['birthdays_path']
@mention = config['mention']
@slack_url = config['slack_url']
@channel_name = config['channel_name']
@greeting_message = config['greeting_message']
Expand Down