-
Notifications
You must be signed in to change notification settings - Fork 27
Sockets - Kirsten & Nara #6
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
base: master
Are you sure you want to change the base?
Changes from all commits
c4dc49a
5152b71
9098d75
6f06b65
a9ca644
ca2213c
ab56d8a
c8ae6e9
2cf0c05
8baa484
a431470
6d54995
f8fc318
9f3bb6d
eac545e
fd0bb90
9f1b726
1fc9558
7136fec
d076c81
c687709
abb531d
bfc5486
c496d3a
f1f47a5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| {"username":"Turtle","icon_emoji":":turtle:"} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| require "pry" | ||
|
|
||
| require_relative "recipient" | ||
|
|
||
| class Channel < Recipient | ||
| attr_reader :topic, :member_count | ||
|
|
||
| def initialize(slack_id, name, topic, member_count) | ||
| super(slack_id, name) | ||
| @topic = topic | ||
| @member_count = member_count | ||
| end | ||
|
|
||
| def details | ||
| return "#{name} #{topic} member count: #{member_count} slack id: #{slack_id}" | ||
| end | ||
|
|
||
| def self.list | ||
| raw_data = self.get("channel") | ||
|
|
||
| unless raw_data.code == 200 | ||
| raise SlackApiError, "Improper request: #{raw_data.message}" | ||
| end | ||
| channel_list = [] | ||
| channels = raw_data["channels"] | ||
| channels.each do |channel| | ||
| slack_id = channel["id"] | ||
| name = channel["name"] | ||
| topic = channel["topic"]["value"] | ||
| member_count = channel["members"].count | ||
|
|
||
| new_channel = Channel.new(slack_id, name, topic, member_count) | ||
| channel_list << new_channel | ||
| end | ||
| return channel_list | ||
| end | ||
| end | ||
|
|
||
| # binding.pry | ||
| # self.list |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,67 @@ | ||
| require "dotenv" | ||
| require "httparty" | ||
| require "json" | ||
| Dotenv.load | ||
|
|
||
| class Recipient | ||
| class SlackApiError < StandardError; end | ||
|
|
||
| attr_accessor :slack_id, :name | ||
|
|
||
| def initialize(slack_id, name) | ||
| @slack_id = slack_id | ||
| @name = name | ||
| end | ||
|
|
||
| CHANNEL_URL = "https://slack.com/api/channels.list" | ||
| USER_URL = "https://slack.com/api/users.list" | ||
| POST_URL = "https://slack.com/api/chat.postMessage" | ||
| def self.get(type) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| params = { | ||
| "token" => ENV["SLACK_API_TOKEN"], | ||
| } | ||
| if type == "user" | ||
| url = USER_URL | ||
| elsif type == "channel" | ||
| url = CHANNEL_URL | ||
| end | ||
|
|
||
| response = HTTParty.get(url, query: params) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Forgot to check for errors. |
||
| end | ||
|
|
||
| def send_msg(message, recipient) | ||
| # settings = {} | ||
| file = File.read("lib/bot-settings.json") | ||
| settings = JSON.parse(file) | ||
| params = { | ||
| "token" => ENV["SLACK_API_TOKEN"], | ||
| "channel" => recipient.slack_id, | ||
| "text" => message, | ||
| "username" => settings["username"], | ||
| "icon_emoji" => settings["icon_emoji"], | ||
| } | ||
| if recipient.class == User | ||
| params["as_user"] = true | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| end | ||
|
|
||
| response = HTTParty.post( | ||
| POST_URL, | ||
| body: params, | ||
| headers: { "Content-Type" => "application/x-www-form-urlencoded" }, | ||
| ) | ||
| unless response.code == 200 && response.parsed_response["ok"] | ||
| raise SlackApiError, "Error: #{response.parsed_response["error"]}" | ||
| end | ||
| return response | ||
| end | ||
|
|
||
| private | ||
|
|
||
| def details | ||
| raise NotImplementedError, "Implement this in the child class." | ||
| end | ||
|
|
||
| def self.list | ||
| raise NotImplementedError, "Implement this in the child class." | ||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,11 +1,60 @@ | ||
| #!/usr/bin/env ruby | ||
| require_relative "workspace" | ||
|
|
||
| def main | ||
| puts "Welcome to the Ada Slack CLI!" | ||
|
|
||
| # TODO project | ||
| workspace = Workspace.new | ||
| input = "" | ||
| while input != "quit" | ||
| puts "Choose an option: \n list users \n list channels \n \n select user \n select channel \n details \n \n send message \n \n change settings \n quit" | ||
| input = gets.chomp | ||
| case input | ||
| when "list users" | ||
| puts workspace.print_details("users") | ||
| when "list channels" | ||
| puts workspace.print_details("channels") | ||
| when "select user" | ||
| print "Enter the user name or Slack ID: " | ||
| input_user = gets.chomp | ||
| workspace.select_user(input_user) | ||
| if workspace.selected == nil | ||
| puts "User not found" | ||
| end | ||
| when "select channel" | ||
| print "Enter the channel name or Slack ID: " | ||
| input_channel = gets.chomp | ||
| workspace.select_channel(input_channel) | ||
| if workspace.selected == nil | ||
| puts "Channel not found" | ||
| end | ||
| when "details" | ||
| if workspace.selected == nil | ||
| puts "Please select a user or channel as a recipient" | ||
| else | ||
| puts workspace.show_details | ||
| end | ||
| when "send message" | ||
| if workspace.selected == nil | ||
| puts "Please select a user or channel as a recipient" | ||
| else | ||
| print "Enter your message: " | ||
| text = gets.chomp | ||
| workspace.send_message(text) | ||
| end | ||
| when "change settings" | ||
| print "Enter new username: " | ||
| name = gets.chomp | ||
| print "Enter new emoji: " | ||
| emoji = gets.chomp | ||
| workspace.update_settings(name, emoji) | ||
| when "quit" | ||
| else | ||
| puts "Please select one of the options" | ||
| end | ||
| end | ||
|
|
||
| puts "Thank you for using the Ada Slack CLI" | ||
| end | ||
|
|
||
| main if __FILE__ == $PROGRAM_NAME | ||
| main if __FILE__ == $PROGRAM_NAME |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| require "pry" | ||
|
|
||
| require_relative "recipient" | ||
|
|
||
| class User < Recipient | ||
| attr_reader :real_name, :status_text, :status_emoji | ||
|
|
||
| def initialize(slack_id, name, real_name, status_text, status_emoji) | ||
| super(slack_id, name) | ||
| @real_name = real_name | ||
| @status_text = status_text | ||
| @status_emoji = status_emoji | ||
| end | ||
|
|
||
| def details | ||
| return "#{name} (#{real_name}) slack id: #{slack_id}" | ||
| end | ||
|
|
||
| def self.list | ||
| raw_data = self.get("user") | ||
|
|
||
| unless raw_data.code == 200 | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Forgot to check for the parsed out |
||
| raise SlackApiError, "Improper request: #{raw_data.message}" | ||
| end | ||
|
|
||
| user_list = [] | ||
| members = raw_data["members"] | ||
| members.each do |member| | ||
| slack_id = member["id"] | ||
| name = member["name"] | ||
| real_name = member["real_name"] | ||
| status_text = member["status_text"] | ||
| status_emoji = member["status_emoji"] | ||
|
|
||
| user = User.new(slack_id, name, real_name, status_text, status_emoji) | ||
| user_list << user | ||
| end | ||
| return user_list | ||
| end | ||
| end | ||
|
|
||
| # binding.pry | ||
| # self.list | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| require "pry" | ||
| require "json" | ||
|
|
||
| require_relative "user" | ||
| require_relative "channel" | ||
|
|
||
| class Workspace | ||
| attr_reader :users, :channels, :selected | ||
|
|
||
| def initialize | ||
| @users = User.list | ||
| @channels = Channel.list | ||
| @selected = nil | ||
| end | ||
|
|
||
| def select_channel(user_input) | ||
| selected = channels.select do |channel| | ||
| channel.name == user_input || channel.slack_id == user_input | ||
| end | ||
| @selected = selected.first | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ruby's |
||
| end | ||
|
|
||
| def select_user(user_input) | ||
| selected = users.select do |user| | ||
| user.name == user_input || user.slack_id == user_input | ||
| end | ||
| @selected = selected.first | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here. |
||
| end | ||
|
|
||
| def show_details | ||
| return @selected.details | ||
| end | ||
|
|
||
| def print_details(recipients) | ||
| if recipients == "users" | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd like to see |
||
| return_array = [] | ||
| users.each do |user| | ||
| return_array << user.details | ||
| end | ||
| elsif recipients == "channels" | ||
| return_array = [] | ||
| channels.each do |channel| | ||
| return_array << channel.details | ||
| end | ||
| end | ||
| return return_array | ||
| end | ||
|
|
||
| def update_settings(name, emoji) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I like that your configuration system is persistent and uses JSON. 😃 |
||
| json_hash = { "username" => name, | ||
| "icon_emoji" => emoji } | ||
|
|
||
| File.open("lib/bot-settings.json", "w") do |f| | ||
| f.write(json_hash.to_json) | ||
| end | ||
| end | ||
|
|
||
| def send_message(text) | ||
| selected.send_msg(text, selected) | ||
| end | ||
| end | ||
|
|
||
| # binding.pry | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| require_relative "test_helper" | ||
|
|
||
| describe "Channel class" do | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would have liked to see some edge case tests on |
||
| describe "self.list" do | ||
| it "can return all channels" do | ||
| VCR.use_cassette("slack_channel") do | ||
| response = Channel.get("channel") | ||
|
|
||
| expect(response["channels"]).wont_be_nil | ||
| expect(response["channels"].first["name"]).must_equal "random" | ||
| expect(response["channels"].first["members"].count).must_equal 2 | ||
| end | ||
| end | ||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1 @@ | ||||||
| require "test_helper" | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should be
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, while it's hard to test an abstract class it would be good to at a minimum make sure that your template methods |
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,15 +1,31 @@ | ||
| require 'simplecov' | ||
| require "simplecov" | ||
| SimpleCov.start | ||
|
|
||
| require 'minitest' | ||
| require 'minitest/autorun' | ||
| require 'minitest/reporters' | ||
| require 'minitest/skip_dsl' | ||
| require 'vcr' | ||
| require "minitest" | ||
| require "minitest/autorun" | ||
| require "minitest/reporters" | ||
| require "minitest/skip_dsl" | ||
| require "vcr" | ||
|
|
||
| require "dotenv" | ||
| Dotenv.load | ||
|
|
||
| require_relative '../lib/channel.rb' | ||
| require_relative '../lib/user.rb' | ||
| require_relative '../lib/recipient.rb' | ||
| require_relative '../lib/workspace.rb' | ||
|
|
||
| Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new | ||
|
|
||
| VCR.configure do |config| | ||
| config.cassette_library_dir = "specs/cassettes" | ||
| config.hook_into :webmock | ||
| end | ||
| config.cassette_library_dir = "specs/cassettes" # folder where casettes will be located | ||
| config.hook_into :webmock # tie into this other tool called 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 token lying around in a cassette file. | ||
| config.filter_sensitive_data("<SLACK_API_TOKEN>") do | ||
| ENV["SLACK_API_TOKEN"] | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎉 |
||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| require_relative "test_helper" | ||
|
|
||
| describe "User class" do | ||
| describe "self.list" do | ||
| it "can return all users" do | ||
| VCR.use_cassette("slack_user") do | ||
| response = User.get("user") | ||
|
|
||
| expect(response["members"]).wont_be_nil | ||
| expect(response["members"].first["name"]).must_equal "slackbot" | ||
| expect(response["members"].first["id"]).must_equal "USLACKBOT" | ||
| end | ||
| end | ||
|
|
||
| # it "raises an exception if response is invalid" do | ||
| # VCR.use_cassette("slack_user") do | ||
| # response = User.get("user") | ||
| # expect(response["ok"]).must_equal false | ||
| # end | ||
| # end | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My guess is you couldn't get this functionality working in time for submission. It was a good test though and would have caught an issue. 👍🏼 |
||
| end | ||
| end | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
URL constants! 🎉
Though, I think these probably wanted to live in
Workspace.