-
Notifications
You must be signed in to change notification settings - Fork 27
Sockets - Jansen & Rosalyn #22
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
8073e93
f55599f
f241dc8
dc4523d
545af26
928543c
b5e8c5e
4f53578
27e2850
f244829
1a228f3
447ed65
4b0069e
3b72fc4
923fc92
f4e0c2c
632e595
578c529
9e5b393
1f2fe55
e343c31
3f83f98
21fe12f
306d877
96f5c24
2f9c7f2
9e40151
0c35596
62fdb9a
ed448bc
0ad511d
1c70bcf
8216737
1aa5782
b65e289
11cfb26
b0f92c5
0d7e212
6f810c8
aa7f35e
18a295d
f576965
0895c5d
0cfe2ad
9822a15
6c74475
46629ca
9ee02fd
3b1c82c
e6f4a0e
f5f1bdf
23f1e05
6945ab0
e8da559
c6b126f
5cb81ee
431fce8
d858007
8937fb4
29b409a
8ce2e94
3050c10
a686a9e
9022bf6
ee7f654
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,14 @@ | ||
| { | ||
| // Use IntelliSense to learn about possible attributes. | ||
| // Hover to view descriptions of existing attributes. | ||
| // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 | ||
| "version": "0.2.0", | ||
| "configurations": [ | ||
| { | ||
| "name": "Debug Local File", | ||
| "type": "Ruby", | ||
| "request": "launch", | ||
| "program": "${workspaceRoot}/lib/slack_main.rb" | ||
| } | ||
| ] | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| require_relative "recipient" | ||
| require "pry" | ||
| require "dotenv" | ||
| require "httparty" | ||
| require "table_print" | ||
|
|
||
| Dotenv.load | ||
|
|
||
| module Slack | ||
| 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 | ||
|
|
||
| BASE_URL = "https://slack.com/api/" | ||
| CHANNEL_URL = "https://slack.com/api/channels.list" | ||
|
|
||
| def details | ||
| return { | ||
| Name: @name.capitalize, | ||
| Slack_id: @slack_id, | ||
| Topic: @topic, | ||
| Member_count: @member_count | ||
| } | ||
| end | ||
|
|
||
| def self.channels_get | ||
| query_params = { token: ENV["SLACK_API_TOKEN"] } | ||
| return Slack::Channel.get(CHANNEL_URL, query_params) | ||
| end | ||
|
|
||
| def self.list | ||
| response = Slack::Channel.channels_get | ||
| channels = response["channels"].map do |channel| | ||
| name = channel["name"] | ||
| slack_id = channel["id"] | ||
| topic = channel["topic"]["value"] | ||
| member_count = channel["members"].count | ||
|
|
||
| Slack::Channel.new(name: name, slack_id: slack_id, topic: topic, member_count: member_count) | ||
| end | ||
|
|
||
| return channels | ||
| end | ||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| module Slack | ||
| class SlackApiError < StandardError; end | ||
|
|
||
| class Recipient | ||
| attr_reader :slack_id, :name | ||
|
|
||
| def initialize(slack_id, name) | ||
| @slack_id = slack_id | ||
| @name = name | ||
| end | ||
|
|
||
| BASE_URL = "https://slack.com/api/" | ||
|
|
||
| def self.get(url, params) | ||
| return HTTParty.get(url, query: params) | ||
| 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. I think the Also, you should be doing things like error handling here. In general, every time you add another layer to a piece of functionality, you should take care of some part of the puzzle in that layer. In this case, |
||
|
|
||
| def send_message(message) | ||
| body = { | ||
| text: message, | ||
| channel: @slack_id, | ||
| token: ENV["SLACK_API_TOKEN"], | ||
| } | ||
|
|
||
| response = HTTParty.post("#{BASE_URL}/chat.postMessage", | ||
| body: body, | ||
| headers: { "Content-Type" => "application/x-www-form-urlencoded" }) | ||
|
|
||
| unless response.code == 200 && response["ok"] | ||
| raise SlackApiError, "#{response["error"]}" | ||
| 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. Good error checking here. |
||
|
|
||
| return true | ||
| end | ||
|
|
||
| private | ||
|
|
||
| def details | ||
| raise NotImplementedError, "Implement me in a child class!" | ||
| end | ||
|
|
||
| def self.list | ||
| raise NotImplementedError, "Implement me in a child class!" | ||
| end | ||
| end | ||
| end | ||
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,110 @@ | ||
| #!/usr/bin/env ruby | ||
|
|
||
| require "dotenv" | ||
| require "pry" | ||
| require "httparty" | ||
| require "terminal-table" | ||
|
|
||
| require_relative "recipient" | ||
| require_relative "channel" | ||
| require_relative "user" | ||
| require_relative "workspace" | ||
|
|
||
| Dotenv.load | ||
|
|
||
| CHANNEL_URL = "https://slack.com/api/channels.list" | ||
| USER_URL = "https://slack.com/api/users.list" | ||
|
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. You have these constants defined a few places. In general, each constant should be defined once. This makes your code easier to change, and avoids the problem of what to do if they don't have the same value. |
||
|
|
||
| def ask(prompt) | ||
| print "#{prompt} > " | ||
| input = gets.chomp | ||
| return input | ||
| end | ||
|
|
||
| def menu | ||
| puts "\nMENU" | ||
| puts "1. List users" | ||
| puts "2. List channels" | ||
| puts "3. Select user" | ||
| puts "4. Select channel" | ||
| puts "5. Details (on selected user/channel)" | ||
| puts "6. Send message" | ||
| puts "7. Quit" | ||
|
|
||
| input = ask("What do you want to do?") | ||
| return input | ||
| end | ||
|
|
||
| def clear_selected(workspace) | ||
| workspace.selected = nil | ||
| 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. I would say this is a demeter violation. Instead of saying to the It might be that you could move this method completely into |
||
|
|
||
| def main | ||
| puts "Welcome to the Ada Slack CLI!" | ||
|
|
||
| workspace = Slack::Workspace.new | ||
|
|
||
| puts "\nHere's how many channels were loaded: #{workspace.channels.length}" | ||
|
|
||
| puts "\nHere's how many users were loaded: #{workspace.users.length}" | ||
|
|
||
| selection = menu | ||
|
|
||
| until selection == "7" | ||
| if selection == "1" | ||
| puts "\nHere are the users:" | ||
| rows = [] | ||
| workspace.users.each_with_index do |user, i| | ||
| rows << [i + 1, user.real_name, user.slack_id, user.name] | ||
| end | ||
| # :headings => ['Word', 'Number'], :rows => rows | ||
| table = Terminal::Table.new :headings => ["", "Real name", "slack id", "Name"], :rows => rows | ||
| puts table | ||
| elsif selection == "2" | ||
| puts "\nHere are the channels:" | ||
| rows = [] | ||
| workspace.channels.each_with_index do |channel, i| | ||
| rows << [i + 1, channel.name, channel.topic, "#{channel.member_count} members", channel.slack_id] | ||
| end | ||
| table = Terminal::Table.new :headings => ["", "Name", "Topic", "Member Count", "Slack id"], :rows => rows | ||
| puts table | ||
| elsif selection == "3" || selection == "4" | ||
| clear_selected(workspace) | ||
| case selection | ||
| when "3" | ||
| identifier = ask("\nPlease enter an id or username") | ||
| workspace.select_user(identifier) | ||
| when "4" | ||
| identifier = ask("\nPlease enter an id or channel name") | ||
| workspace.select_channel(identifier) | ||
| end | ||
|
|
||
| unless workspace.selected.nil? | ||
| puts "You've selected: #{workspace.selected.name}" | ||
| else | ||
| puts "Whoops! User or channel not found. Please try again." | ||
| end | ||
| elsif selection == "5" | ||
| if workspace.selected.nil? | ||
| puts "Whoops! You must select a user or channel first" | ||
| else | ||
| puts "Here are some details on your selection:" | ||
| details = workspace.show_details | ||
| puts details | ||
| end | ||
| elsif selection == "6" | ||
| if workspace.selected.nil? | ||
| puts "Whoops! You must select a recipient first" | ||
| else | ||
| message = ask("Enter the message you want to send to #{workspace.selected.name}") | ||
| workspace.send_message(message) | ||
| end | ||
| else puts "\nInvalid entry. Please try again!" end | ||
|
|
||
| selection = menu | ||
| end | ||
|
|
||
| puts "Thank you for using the Ada Slack CLI" | ||
| end | ||
|
|
||
| main | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| require_relative "recipient" | ||
| require "pry" | ||
| require "dotenv" | ||
| require "httparty" | ||
| require "table_print" | ||
|
|
||
| Dotenv.load | ||
|
|
||
| module Slack | ||
| 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 | ||
|
|
||
| BASE_URL = "https://slack.com/api/" | ||
| USER_URL = "https://slack.com/api/users.list" | ||
|
|
||
| def details | ||
| return { | ||
| Name: @real_name, | ||
| Status: @status_text, | ||
| Emoji: @status_emoji, | ||
| Slack_id: @slack_id, | ||
| Username: @name | ||
| } | ||
| end | ||
|
|
||
| def self.users_get | ||
| query_params = { token: ENV["SLACK_API_TOKEN"] } | ||
| return Slack::User.get(USER_URL, query_params) | ||
| end | ||
|
|
||
| def self.list | ||
| response = Slack::User.users_get | ||
| users = response["members"].map do |member| | ||
| name = member["name"] | ||
| slack_id = member["id"] | ||
| real_name = member["real_name"] | ||
| status_text = member["profile"]["status_text"] | ||
| status_emoji = member["profile"]["status_emoji"] | ||
|
|
||
| Slack::User.new(name: name, slack_id: slack_id, real_name: real_name, status_text: status_text, status_emoji: status_emoji) | ||
| end | ||
|
|
||
| return users | ||
| end | ||
| end | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| require "pry" | ||
| require "dotenv" | ||
| require "httparty" | ||
| require "table_print" | ||
| require "terminal-table" | ||
|
|
||
| require_relative "user" | ||
| require_relative "channel" | ||
|
|
||
| module Slack | ||
| class Workspace | ||
| attr_accessor :selected | ||
| attr_reader :users, :channels | ||
|
|
||
| def initialize | ||
| @users = Slack::User.list | ||
| @channels = Slack::Channel.list | ||
| @selected = nil | ||
| end | ||
|
|
||
| def select_channel(identifier) | ||
| @selected = @channels.find do |channel| | ||
| channel.slack_id == identifier || channel.name == identifier | ||
| end | ||
| end | ||
|
|
||
| def select_user(identifier) | ||
| @selected = @users.find do |user| | ||
| user.slack_id == identifier || user.name == identifier | ||
| end | ||
| end | ||
|
|
||
| def show_details | ||
| details = @selected.details | ||
|
|
||
| rows = [] | ||
|
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. Good use of polymorphism to keep this code generic, not specific to users or channels. |
||
| details.each do |key, details| | ||
| rows << [key, details] | ||
| end | ||
|
|
||
| table = Terminal::Table.new :rows => rows | ||
| return table | ||
| end | ||
|
|
||
| def send_message(input) | ||
| @selected.send_message(input) | ||
| # The user gives a message | ||
| # This method enters user's message as an argument for Recipient's send_message | ||
|
|
||
| end | ||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| require 'simplecov' | ||
| SimpleCov.start | ||
|
|
||
| require_relative 'test_helper' | ||
| require_relative '../lib/channel.rb' | ||
|
|
||
| describe 'Channel class' do | ||
| before do | ||
| VCR.use_cassette('channel_list') do | ||
| @response = Slack::Channel.list | ||
| end | ||
| end | ||
|
|
||
| it 'can retrieve a list of channels' do | ||
| expect(@response).must_be_kind_of Array | ||
| expect(@response[0]).must_be_kind_of Slack::Channel | ||
| expect(@response[0].member_count).must_be_kind_of Integer | ||
| end | ||
|
|
||
| it 'can retrieve details of a specific channel' do | ||
| expect (@response[0].details).must_be_kind_of Hash | ||
| end | ||
|
|
||
| describe 'send_message to channel' do | ||
| it 'can send a message fine' do | ||
| VCR.use_cassette('slack_posts_channel') do | ||
| selected_channel = @response[1] | ||
| response = selected_channel.send_message('This is our Test Post to channel!') | ||
| expect(response).must_equal true | ||
| end | ||
| end | ||
|
|
||
| it 'will raise an error when given an invalid channel' do | ||
| VCR.use_cassette('slack-posts_channel') do | ||
| @response << Slack::Channel.new( | ||
| slack_id: 'bogus', | ||
| name: 'bogus', | ||
| topic: 'bogus', | ||
| member_count: 'bogus' | ||
| ) | ||
|
|
||
| bogus_selected_channel = @response.last | ||
|
|
||
| exception = expect { | ||
| bogus_selected_channel.send_message('This post should not work') | ||
| }.must_raise Slack::SlackApiError | ||
|
|
||
| expect(exception.message).must_equal 'channel_not_found' | ||
| end | ||
| end | ||
| 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.
Since you're already inside of
Slack::Channel, you can just sayreturn get(...)on line 33.