Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
69 commits
Select commit Hold shift + click to select a range
46d2104
Added #list_channels, setup Slack auth
paulentine Mar 19, 2019
5557af1
Updated URLs
paulentine Mar 19, 2019
f54ce2d
Setup spec_helper with VCR
paulentine Mar 19, 2019
e2c60a5
created skeleton
nidhiparixitpatel Mar 19, 2019
fc2f66e
created skeleton
nidhiparixitpatel Mar 19, 2019
5348b32
created skeleton
nidhiparixitpatel Mar 19, 2019
b1c5b02
Fixed merge conflict
paulentine Mar 19, 2019
d02f2be
Wrote skeleton for tests
paulentine Mar 19, 2019
91a050a
Fixed another merge conflict
paulentine Mar 19, 2019
1cc5b1a
added self.list method
nidhiparixitpatel Mar 19, 2019
01193f9
Moved Slack#list_channel to Channel#self.list
paulentine Mar 19, 2019
8685784
Merge branch 'master' of https://github.com/paulentine/slack-cli
paulentine Mar 19, 2019
5db8e83
working on self.list and test
nidhiparixitpatel Mar 20, 2019
042cfc9
Added Channel#details & #self.list
paulentine Mar 20, 2019
32f0573
Standardized indentations
paulentine Mar 20, 2019
5a55aa0
self.list method
nidhiparixitpatel Mar 20, 2019
832c4be
Fixed merge conflict
paulentine Mar 20, 2019
e91ecd4
Merge branch 'master' of https://github.com/paulentine/slack-cli
paulentine Mar 20, 2019
e5a9dec
passed tests for self.list
nidhiparixitpatel Mar 20, 2019
2695c6f
Wrote tests for Channel#self.list
paulentine Mar 20, 2019
dd4ad23
Added table_print, test for array length
paulentine Mar 20, 2019
86d6b0e
added self.load
nidhiparixitpatel Mar 20, 2019
dd139ef
Merge branch 'master' of https://github.com/paulentine/slack-cli
nidhiparixitpatel Mar 20, 2019
d8ed86e
Renamed #list to #load, wrote #details & test
paulentine Mar 20, 2019
c7da16c
Merge branch 'master' of https://github.com/paulentine/slack-cli
paulentine Mar 20, 2019
499b62b
Renamed #list to #load, wrote #details & test
paulentine Mar 20, 2019
6d0150a
Started writing driver code
paulentine Mar 20, 2019
45e8404
Fixed VCR error
paulentine Mar 20, 2019
febd4e4
Wrote conditionals for invalid input
paulentine Mar 21, 2019
da8db5f
Made .load private
paulentine Mar 21, 2019
72c3219
Made array of valid inputs
paulentine Mar 21, 2019
32fbd1a
Moved when users & channels get loaded
paulentine Mar 21, 2019
0514ab3
Instantiated workspace
paulentine Mar 21, 2019
f2c815c
Assigned workspace to a var
paulentine Mar 21, 2019
678f83c
started working on workspace.select_user
nidhiparixitpatel Mar 21, 2019
d78a5d7
Merge branch 'master' of https://github.com/paulentine/slack-cli
nidhiparixitpatel Mar 21, 2019
4caf4cd
Remove and ignore extra files
paulentine Mar 21, 2019
a0db0d6
working on tests for user
nidhiparixitpatel Mar 21, 2019
d672f90
Merge branch 'master' of https://github.com/paulentine/slack-cli
nidhiparixitpatel Mar 21, 2019
e62871e
finished select user and channel and show details
nidhiparixitpatel Mar 21, 2019
333ddec
Made tests more rigorous
paulentine Mar 21, 2019
d2b1957
Wrote test for show details of selected channel
paulentine Mar 21, 2019
803b051
Updated driver code for select user & channel
paulentine Mar 21, 2019
e2b178c
Refactored tests, fixed formatting
paulentine Mar 21, 2019
f639218
created send_message method and test
nidhiparixitpatel Mar 21, 2019
0c1c1ee
Merge branch 'master' of https://github.com/paulentine/slack-cli
nidhiparixitpatel Mar 21, 2019
50eac82
Wrote Channel#send_message
paulentine Mar 22, 2019
ebb8293
Added driver code for details & selected + error checking
paulentine Mar 22, 2019
891b75b
Established inheritance, moved #send_message
paulentine Mar 22, 2019
8fb6865
add inheritance
nidhiparixitpatel Mar 22, 2019
e521cd0
Removed "recipient" param from send_message
paulentine Mar 22, 2019
f21bd3e
Updated test
paulentine Mar 22, 2019
5c4c034
Added edge case tests
paulentine Mar 22, 2019
1889248
added slackapi error test
nidhiparixitpatel Mar 22, 2019
22b432a
#details now return string, updated tests
paulentine Mar 22, 2019
4437b76
Merge branch 'master' of https://github.com/paulentine/slack-cli
paulentine Mar 22, 2019
3b8288a
add tests for sending message
nidhiparixitpatel Mar 22, 2019
937be60
Merge branch 'master' of https://github.com/paulentine/slack-cli
paulentine Mar 22, 2019
2e4edef
workspace spec
nidhiparixitpatel Mar 22, 2019
b937f4a
Merge branch 'master' of https://github.com/paulentine/slack-cli
nidhiparixitpatel Mar 22, 2019
372e031
Updated driver code to check for empty message
paulentine Mar 22, 2019
958fa10
Merge branch 'master' of https://github.com/paulentine/slack-cli
paulentine Mar 22, 2019
8af3f77
completed test for sending empty text
nidhiparixitpatel Mar 22, 2019
43c947c
passing tests
nidhiparixitpatel Mar 22, 2019
4955e3b
Merge branch 'master' of https://github.com/paulentine/slack-cli
nidhiparixitpatel Mar 22, 2019
373a3b5
renamed list to all
nidhiparixitpatel Mar 22, 2019
ac38d87
clean up
nidhiparixitpatel Mar 22, 2019
2c0c328
Cleaned up formatting, comments, alphabetized require
paulentine Mar 22, 2019
ba7559b
added tests for workspace
nidhiparixitpatel Mar 22, 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
Binary file added .DS_Store
Binary file not shown.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
*.rbc
/.config
/coverage/
*/coverage/
/InstalledFiles
/pkg/
/spec/reports/
Expand All @@ -11,7 +12,7 @@
/tmp/

# Used by dotenv library to load environment variables.
# .env
.env

## Specific to RubyMotion:
.dat*
Expand Down Expand Up @@ -54,3 +55,5 @@ build-iPhoneSimulator/

# Ignore cassette files
/specs/cassettes/

.vscode
Binary file added lib/.DS_Store
Binary file not shown.
49 changes: 49 additions & 0 deletions lib/channel.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
require 'dotenv'
require 'httparty'
require 'table_print'
require_relative 'recipient'
Dotenv.load

module SlackAPI
class Channel < Recipient

attr_reader :topic, :member_count

URL = "https://slack.com/api/channels.list"
TOKEN = ENV['TOKEN']
@@all = []

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

def details
return "Channel name: #{name}
Slack ID: #{slack_id}
Topic: #{topic}
Member count: #{member_count}"
end

def self.list
return @@all

Choose a reason for hiding this comment

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

While it doesn't cause a problem here generally class variables should be your tool of last resort. I probably would have only stored them in a field in Workspace instead of here and there.

end

def self.load
query_parameters = {
token: TOKEN,
}
response = HTTParty.get(URL, query: query_parameters)['channels']
response.each do |channel|

Choose a reason for hiding this comment

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

Forgot to validate response.code and response.parsed_response["ok"].

topic = channel['topic']['value']
member_count = channel['num_members']
slack_id = channel['id']
name = channel['name']
new_channel = Channel.new(topic: topic, member_count: member_count, slack_id: slack_id, name: name)
@@all << new_channel
end
return @@all
end
end
end
43 changes: 43 additions & 0 deletions lib/recipient.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
module SlackAPI
class Recipient

attr_reader :slack_id, :name

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

def send_message(text:)
body = {
text: text,
channel: slack_id,
token: ENV["TOKEN"],
}

response = HTTParty.post("https://slack.com/api/chat.postMessage",
body: body,
headers: { "Content-Type" => "application/x-www-form-urlencoded" })

unless response.code == 200 && response.parsed_response["ok"]
raise SlackApiError, "Error when posting #{text} to #{name}, error: #{response.parsed_response["error"]}"
end

return response.code == 200 && response.parsed_response["ok"]

Choose a reason for hiding this comment

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

I would consider just returning true here since you've already done the check above.

end

def self.load
raise NotImplementedError
end

def details
raise NotImplementedError
end

def self.list
raise NotImplementedError
end

end

end
79 changes: 77 additions & 2 deletions lib/slack.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,85 @@
#!/usr/bin/env ruby
require 'dotenv'
require 'httparty'
require_relative 'channel'
require_relative 'recipient'
require_relative 'user'
require_relative 'workspace'
Dotenv.load

token = ENV['TOKEN']

def main
puts "Welcome to the Ada Slack CLI!"
input = 0

users = SlackAPI::User.load
channels = SlackAPI::Channel.load
workspace = SlackAPI::Workspace.new(users: users, channels: channels)

until input == "G" do
puts "Welcome to the Ada Slack CLI!"
puts "What would you like to do?"
puts "[A] List users"
puts "[B] List channels"
puts "[C] Select user"
puts "[D] Select channel"
puts "[E] Show details of selected user / channel"
puts "[F] Send message"
puts "[G] Quit"
input = gets.chomp.upcase
valid_input = ["A", "B", "C", "D", "E", "F", "G"]

# TODO project
until valid_input.include?(input)
puts "Please try again"
input = gets.chomp.upcase
end

case input
when "A"
tp SlackAPI::User.list
when "B"
tp SlackAPI::Channel.list
when "C"
puts "Please supply a slack ID or user name (case sensitive!)"
workspace.selected = nil
user_id_or_name = gets.chomp
selected = workspace.select_user(id_or_name: user_id_or_name)
if selected
puts "Selected user: #{user_id_or_name}"
else
puts "User not found"
end
when "D"
puts "Please supply a slack ID or channel name (case sensitive!)"
workspace.selected = nil
chan_id_or_name = gets.chomp.downcase
workspace.select_channel(id_or_name: chan_id_or_name)
if selected
puts "Selected channel: #{chan_id_or_name}"
else
puts "Channel not found"
end

when "E"
if workspace.selected
puts workspace.show_details
else
puts "No recipient selected \n\n"
end
when "F"
if workspace.selected
puts "Please type the message you want to send"
user_text = gets.chomp
if user_text != ""
workspace.send_message(text: user_text)
else
"Message cannot be empty"
end
else
puts "No recipient selected \n\n"
end
end
end
puts "Thank you for using the Ada Slack CLI"
end

Expand Down
49 changes: 49 additions & 0 deletions lib/user.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
require "dotenv"
require "httparty"
require "table_print"
require_relative "recipient"

Dotenv.load

module SlackAPI
class SlackApiError < StandardError; end

class User < Recipient

attr_reader :real_name

BASE_URL = "https://slack.com/api"
USERS_LIST_PATH = "/users.list"
CHAT_POST_MESSAGE_PATH = "/chat.postMessage"
TOKEN = ENV["TOKEN"]
@@all = []

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

def details
return "Name: #{name}
Slack ID: #{slack_id}
Real name: #{real_name}"
end

def self.list
return @@all
end

def self.load
query_parameters = { token: TOKEN }
response = HTTParty.get(BASE_URL << USERS_LIST_PATH, query: query_parameters)
response["members"].length.times do |i|

Choose a reason for hiding this comment

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

Forgot to validate response.code and response.parsed_response["ok"].

real_name = response["members"][i]["real_name"]
slack_id = response["members"][i]["id"]
name = response["members"][i]["name"]
new_user = SlackAPI::User.new(real_name: real_name, slack_id: slack_id, name: name)
@@all.push(new_user)
end
return @@all
end
end
end
48 changes: 48 additions & 0 deletions lib/workspace.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
require 'dotenv'
require 'httparty'
require 'pry'
Dotenv.load

module SlackAPI
class Workspace

attr_reader :users, :channels
attr_accessor :selected

def initialize(users:, channels:, selected: nil)
@users = users
@channels = channels
@selected = selected
end

def select_channel(id_or_name:)

Choose a reason for hiding this comment

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

Tiny issue: it's a little odd to use a keyword argument here since you only have a single argument.

@channels.each do |channel|
if channel.name == id_or_name
@selected = channel
elsif channel.slack_id == id_or_name
@selected = channel
end
end
return @selected
end

def select_user(id_or_name:)
@users.each do |user|
if user.name == id_or_name
@selected = user
elsif user.slack_id == id_or_name
@selected = user
end
end
return @selected

Choose a reason for hiding this comment

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

Ruby's .find enumerable method might be helpful to clean up this code.

end

def show_details
@selected.details
end

def send_message(text:)
@selected.send_message(text: text)
end
end
end
40 changes: 40 additions & 0 deletions specs/channel_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
require 'minitest'
require_relative 'test_helper.rb'

describe "Channel" do
before do
VCR.use_cassette("channel_list") do
@response = SlackAPI::Channel.load
end
end

describe "details" do

end

describe "self.list" do
it "can list details of all the channels" do
expect(SlackAPI::Channel.list).must_be_kind_of Array
end
end

describe "self.load" do
it "can find the list of channels" do
expect(@response).must_be_kind_of Array
expect(@response[0]).must_be_kind_of SlackAPI::Channel
expect(@response[0].name).must_equal "everyone"
expect(@response[0].slack_id).must_equal "CH2SBU69Y"
expect(@response[0].topic).must_equal "Company-wide announcements and work-based matters"
expect(@response[0].member_count).must_equal 2
end
end

it "sends a message to selected channel" do
VCR.use_cassette("channel_send_message") do
channel = SlackAPI::Channel.list[0]
test2 = channel.send_message(text: "hello")
expect(test2).must_equal true
end
end

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 some edge case tests here.

What happens if you can't talk to the API or there's an error?

end
20 changes: 20 additions & 0 deletions specs/recipient_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
require 'minitest'
require_relative 'test_helper.rb'

describe "Recipient" do

Choose a reason for hiding this comment

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

Empty tests 🙁.

before do

end

describe "self.get" do

end

describe "details" do

Choose a reason for hiding this comment

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

I would like to see an assertion that this raises NotImplementedError.

end

describe "self.list" do

Choose a reason for hiding this comment

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

Same here.

end
end

Choose a reason for hiding this comment

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

I'd also like to see a test that verifies that self.load raises NotImplementedError.

14 changes: 14 additions & 0 deletions specs/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,23 @@
require 'minitest/skip_dsl'
require 'vcr'

require_relative "../lib/user.rb"
require_relative "../lib/channel.rb"
require_relative "../lib/workspace.rb"
require_relative "../lib/recipient.rb"
require_relative "../lib/slack.rb"

Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new

VCR.configure do |config|
config.cassette_library_dir = "specs/cassettes"
config.hook_into :webmock
config.default_cassette_options = {
record: :new_episodes, # record new data when we don't have it yet
match_requests_on: [:method, :uri, :body] # The http method, URI and body of a request all need to match
}
# Don't leave our Slack token lying around in a cassette file.
config.filter_sensitive_data("<TOKEN>") do
ENV["TOKEN"]
end
end
Loading