Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
81a7177
Configured VCR to filter_sensitive_data for slack token
juliabouv Sep 10, 2019
015d86d
Initialized User class. Added list method
juliabouv Sep 10, 2019
975cf00
Initialized Channel class. Added list method
juliabouv Sep 10, 2019
78996c0
Initialized Recipient class. Added get method
juliabouv Sep 10, 2019
5200a35
Implemented SlackApiError
juliabouv Sep 10, 2019
ad3997a
Initialized Workspace class
juliabouv Sep 10, 2019
0255ede
Implemented Wave 1
juliabouv Sep 10, 2019
8e43078
Implemented User tests for #initialize and #list_users
juliabouv Sep 11, 2019
cef385a
Updated requires
juliabouv Sep 11, 2019
7772e1a
Implemented Channel tests for #initialize and #list_users
juliabouv Sep 11, 2019
b1cc13a
Formatting updates
juliabouv Sep 11, 2019
ea8f697
Formatting updates
juliabouv Sep 11, 2019
9130c78
Merge branch 'master' of https://github.com/juliabouv/slack-cli
juliabouv Sep 11, 2019
42d3372
Implemented Recipient tests
juliabouv Sep 11, 2019
bd41da6
Implemented Workspace tests
juliabouv Sep 11, 2019
16b192e
Implemented #details method
juliabouv Sep 11, 2019
7c42a24
Implemented #details method
juliabouv Sep 11, 2019
65a50fe
Implemented #details tests
juliabouv Sep 11, 2019
87bc46a
Implemented #details tests
juliabouv Sep 11, 2019
36412bd
Implemented #select_user and #select_channel methods
juliabouv Sep 12, 2019
76f7c94
Implemented #select_channel, #select_user and #show_details tests
juliabouv Sep 12, 2019
6c789bc
Implemented #select_channel, #select_user and #show_details tests
juliabouv Sep 12, 2019
ca54059
Implemented Wave 2 in slack.rb
juliabouv Sep 12, 2019
e84a47e
Completed unnecessary merge
juliabouv Sep 12, 2019
aba9fd1
Implemented send_message method:
juliabouv Sep 13, 2019
6087d61
Implemented send_message method:
juliabouv Sep 13, 2019
e07baab
Merge branch 'master' of https://github.com/juliabouv/slack-cli
juliabouv Sep 13, 2019
6a96a20
Merge branch 'master' of https://github.com/juliabouv/slack-cli
juliabouv Sep 13, 2019
d46ccd8
Merge branch 'master' of https://github.com/juliabouv/slack-cli
juliabouv Sep 13, 2019
b17dd36
Formatting and cassettes
juliabouv Sep 13, 2019
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
30 changes: 30 additions & 0 deletions lib/channel.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
class Channel < Recipient
attr_reader :topic, :member_count

def initialize(topic: , member_count: , slack_id: , name: )
super(slack_id: slack_id, name: name)
@topic = topic
@member_count = member_count
end

def details
details = """

Choose a reason for hiding this comment

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

Triple quotes aren't needed in Ruby like they are in some other languages. Ruby does multi-line strings by default.

Suggested change
details = """
details = "

(In fact Ruby actually reads this as a empty string followed by a multi-line string followed by another empty string. By default in Ruby strings get joined together if they are next to each other. greeting = "Hello," " world!" is the same as greeting = "Hello, world!".)

Channel Details:
Slack ID: #{@slack_id}
Name: #{@name}
Topic: #{@topic}
Member Count: #{@member_count}
"""

return details
end

def self.list
response = self.get("https://slack.com/api/channels.list", ENV["SLACK_TOKEN"])

members = response["channels"].map do |channel|
self.new(slack_id: channel["id"], name: channel["name"], topic: channel["topic"]["value"], member_count: channel["members"].length )
end
return members
end
end
30 changes: 30 additions & 0 deletions lib/recipient.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
class Recipient
attr_reader :slack_id, :name

def initialize(slack_id: , name: )
@slack_id = slack_id
@name = name
end

def self.get(url, params)
query = {
token: params
}

response = HTTParty.get(url, query: query)

if response["error"]

Choose a reason for hiding this comment

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

You should also check response.code here.

Suggested change
if response["error"]
if response["error"] || response.code != 200

raise SlackApiError.new "#{response.code}: #{response.message} -- #{response["error"]}"
end

return response
end

def details
raise NotImplementedError.new "Implement me in a child class!"

Choose a reason for hiding this comment

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

Abstract method! 🎉

end

def self.list
raise NotImplementedError.new "Implement me in a child class!"
end
end
135 changes: 131 additions & 4 deletions lib/slack.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,138 @@
#!/usr/bin/env ruby
require_relative 'workspace'

def main
workspace = Workspace.new
# variable to format command line entry
prompt = "> "

puts "Welcome to the Ada Slack CLI!"

# TODO project

puts "The number of channels is #{workspace.channels.length}."
puts "The number of users is #{workspace.users.length}"

puts "Do you want to list users, list channels, select user, select channel, show details for selected, send message to selected or quit?"
print prompt
search = gets.chomp.downcase
until search == "quit"

case search
when "quit"
exit

when "list users", "users"
puts
puts "Listing Users..."
workspace.users.each do |user|
puts
puts "Username: #{user.name}"
puts "Real Name: #{user.real_name}"
puts "Slack ID: #{user.slack_id}"
end
puts
puts "Do you want to list users, list channels, select user, select channel, show details for selected, send message to selected or quit?"
print prompt
search = gets.chomp.downcase

when "list channels", "channels"
puts
puts "Listing Channels..."
workspace.channels.each do |channel|
puts
puts "Channel name: #{channel.name}"
puts "Topic: #{channel.topic}"
puts "Member count: #{channel.member_count}"
puts "Slack ID: #{channel.slack_id}"
end
puts
puts "Do you want to list users, list channels, select user, select channel, show details for selected, send message to selected or quit?"
print prompt
search = gets.chomp.downcase

when "select channel", "channel"
puts "Please enter a channel name or slack_id for the channel you would like to select:"
print prompt
input = gets.chomp

if workspace.select_channel(input: input)
workspace.select_channel(input: input)

Choose a reason for hiding this comment

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

Running workspace.select_channel(input: input) twice here is redundant. (The user would already be selected if it worked the first time.)

puts """
#{input} is now selected
"""
else
puts """
No channel has that name or ID

Choose a reason for hiding this comment

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

I would have liked to have seen this as an error raised in select_channel and then rescued here. You could even put your entire case inside of the begin/rescue to DRY up your code.

until search == "quit"
  begin
    case search 
    when "list channels", "channels"
      # ...
    when "select channel", "channel"
      puts "Please enter a channel name or slack_id for the channel you would like to select:"
      print prompt
      input = gets.chomp

      workspace.select_channel(input: input)

      puts "
      #{input} is now selected
      "
    when "select user", "user"
      puts "Please enter a username or slack_id for the user you would like to select:"
      print prompt
      input = gets.chomp

      workspace.select_user(input: input)

      puts "
      #{input} is now selected
      "
    # other menu options...
  rescue SlackWorkspaceError => error
    puts e.message
  end
end

"""
end

puts "Do you want to list users, list channels, select user, select channel, show details for selected, send message to selected or quit?"
print prompt
search = gets.chomp.downcase

when "select user", "user"
puts "Please enter a username or slack_id for the user you would like to select:"
print prompt
input = gets.chomp

if workspace.select_user(input: input)
workspace.select_user(input: input)
puts """
#{input} is now selected
"""
else
puts """
No user has that name or ID
"""
end

puts "Do you want to list users, list channels, select user, select channel, show details for selected, send message to selected or quit?"
print prompt
search = gets.chomp.downcase

when "details"
if workspace.show_details
puts "Here are the details for #{workspace.selected.name}:"
puts workspace.show_details
else
puts """
No recipient is currently selected
"""
end

puts "Do you want to list users, list channels, select user, select channel, show details for selected, send message to selected or quit?"
print prompt
search = gets.chomp.downcase

when "send message", "message"
unless workspace.selected.nil?
puts "What message would you like to send to #{workspace.selected.name}?"
message = gets.chomp

workspace.send_message(message, workspace.selected.slack_id)

puts """
Message posted!
"""
else
puts """
No recipient selected!
"""
end

puts "Do you want to list users, list channels, select user, select channel, show details for selected, send message to selected or quit?"
print prompt
search = gets.chomp.downcase
else
puts """
Invalid Command
"""
puts "Do you want to list users, list channels, select user, select channel, show details for selected, send message to selected or quit?"
print prompt
search = gets.chomp.downcase
end
end

puts "Thank you for using the Ada Slack CLI"
end

main if __FILE__ == $PROGRAM_NAME
main if __FILE__ == $PROGRAM_NAME

1 change: 1 addition & 0 deletions lib/slack_api_error.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
class SlackApiError < StandardError; end
31 changes: 31 additions & 0 deletions lib/user.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
class User < Recipient
attr_reader :real_name, :status_text, :status_emoji

def initialize(real_name:, slack_id:, name:)
super(slack_id: slack_id, name: name)
@real_name = real_name
@status_text = status_text
@status_emoji = status_emoji
end

def details
details = """
User Details:
Slack ID: #{@slack_id}
Username: #{@name}
Real Name: #{@real_name}
"""

return details
end

def self.list
response = self.get("https://slack.com/api/users.list", ENV["SLACK_TOKEN"])

members = response["members"].map do |member|
self.new(slack_id: member["id"], name: member["name"], real_name: member["real_name"] )
end
return members
end
end

70 changes: 70 additions & 0 deletions lib/workspace.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
require 'httparty'
require 'awesome_print'
require 'pry'
require 'dotenv'
Dotenv.load

require_relative 'slack_api_error'
require_relative 'recipient'
require_relative 'channel'
require_relative 'user'

class Workspace
attr_reader :users, :channels, :selected

def initialize
@users = User.list
@channels = Channel.list
@selected = nil
end

def select_channel(input: nil)

Choose a reason for hiding this comment

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

A keyword argument is probably overkill here. Positional parameters can be optional too.

Suggested change
def select_channel(input: nil)
def select_channel(input = nil)

Though I'm not sure it makes sense to select a channel without giving a name.

channel_names = @channels.map { |channel| channel.name }
channel_ids = @channels.map { |channel| channel.slack_id }

if channel_names.include?(input)
@selected = @channels.find { |c| input == c.name }
elsif channel_ids.include?(input)
@selected = @channels.find { |c| input == c.slack_id }
else
return nil

Choose a reason for hiding this comment

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

I'd like to see this raise instead of just returning nil.

end
return @selected
end

def select_user(input: nil)

Choose a reason for hiding this comment

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

Good use of map and find!

usernames = @users.map { |user| user.name }
user_ids = @users.map { |user| user.slack_id }

if usernames.include?(input)
@selected = @users.find { |u| input == u.name }
elsif user_ids.include?(input)
@selected = @users.find { |u| input == u.slack_id }
else
return nil
end
return @selected
end

def show_details
return @selected.details if @selected
end

def send_message(message, channel)
response = HTTParty.post(
"https://slack.com/api/chat.postMessage",
body: {
token: ENV["SLACK_TOKEN"],
channel: channel,
text: message
},
headers: { 'Content-Type' => 'application/x-www-form-urlencoded' }
)

if response["error"]
raise SlackApiError.new "#{response.code}: #{response.message} -- #{response["error"]}"
end

return response
end
end
Loading