- 
                Notifications
    You must be signed in to change notification settings 
- Fork 27
Ports - Alex and Amy #10
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
1b0fb11
              d3fdbef
              3f7eafc
              fc5769e
              0e2c0fa
              607d41a
              4b89f88
              65f53bb
              3e7ac4a
              05bee27
              6498e56
              c4697ce
              e3e34f4
              c267404
              5e5665e
              f58f4f2
              5d541ed
              3b9e604
              d63ce76
              4379d22
              1af0227
              960edc3
              2d6a4f5
              e429dfc
              8e24b97
              20a9e5f
              4f0b1b9
              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,33 @@ | ||
| require "dotenv" | ||
| require "httparty" | ||
|  | ||
| Dotenv.load | ||
|  | ||
| module SlackApi | ||
| class SlackError < StandardError; end | ||
|  | ||
| class Channel | ||
| url = "https://slack.com/api/channels.list" | ||
| key = ENV["SLACK_API_TOKEN"] | ||
|  | ||
| def self.channel_api(url, key) | ||
| parameters = { 'token': key } | ||
| response = HTTParty.get(url, query: parameters).to_s | ||
| response = JSON.parse(response) | ||
|  | ||
| if response["ok"] == true | ||
| return response["channels"] | ||
| else | ||
| raise SlackApi::SlackError, "Error with Channel API: #{response["error"]}" | ||
| end | ||
| end | ||
|  | ||
| def self.list(channels_list) | ||
| puts "\nHere are a list of your channels for this Workspace:" | ||
| 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 should try to separate the "display" functions of your app with the functionality and business logic. This "model-like" class shouldn't have to worry about printing things to the screen, instead it should work with the api and return data back. | ||
| list_of_channels = channels_list.map do |channel| | ||
| "\nChannel name: #{channel["name"]}\nSlack ID: #{channel["id"]}\nTopic: #{channel["topic"]["value"]}\nMember count: #{channel["num_members"]}\n" | ||
| end | ||
| return list_of_channels | ||
| end | ||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -1,11 +1,55 @@ | ||
| #!/usr/bin/env ruby | ||
|  | ||
| require_relative "user" | ||
| require_relative "channel" | ||
| require_relative "workspace" | ||
|  | ||
| Dotenv.load | ||
|  | ||
| def main | ||
| workspace = SlackApi::Workspace.new | ||
|  | ||
| user_options = "list users\nlist channels\nselect user\nselect channel\ndetails\nsend message\nquit" | ||
|  | ||
| puts "Welcome to the Ada Slack CLI!" | ||
| puts "\nThere are #{workspace.channels.length} channels and #{workspace.users.length} users in this Workspace." | ||
| puts "\nWhat would you like to do?:" | ||
| puts user_options | ||
|  | ||
| user_selection = gets.chomp | ||
| until user_selection == "quit" | ||
| case user_selection | ||
| when "list users" | ||
| puts SlackApi::User.list(workspace.users) | ||
| when "list channels" | ||
| puts SlackApi::Channel.list(workspace.channels) | ||
| when "select user" | ||
| print "\nEnter username or user's ID: " | ||
| user_input = gets.chomp | ||
| if workspace.select_user(user_input) != true | ||
| puts "\n~That user does not exist~" | ||
| end | ||
| when "select channel" | ||
| print "\nEnter channel name or channel's ID: " | ||
| user_input = gets.chomp | ||
| if workspace.select_channel(user_input) != true | ||
| puts "\n~That channel does not exist~" | ||
| end | ||
| when "details" | ||
| puts workspace.show_details | ||
| when "send message" | ||
| puts "\n(This will send to the recipient you have selected)" | ||
| print "What message would you like to send? " | ||
| user_message = gets.chomp | ||
| workspace.send_message(user_message) | ||
| end | ||
|  | ||
| # TODO project | ||
| puts "\nWhat would you like to do next?" | ||
| puts user_options | ||
| user_selection = gets.chomp | ||
| 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,33 @@ | ||
| require "dotenv" | ||
| require "httparty" | ||
|  | ||
| Dotenv.load | ||
|  | ||
| module SlackApi | ||
| class SlackError < StandardError; end | ||
|  | ||
| class User | ||
| 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 class is just a collection of class methods, so you don't actually need a class, a module would work as well. I do think a class makes sense, you can create instances of  | ||
| 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. Again, you should default to using constants unless you want to change the values of these variables. | ||
| key = ENV["SLACK_API_TOKEN"] | ||
|  | ||
| def self.user_api(url, key) | ||
| 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 method name could use a bit of work, rather than call it  | ||
| parameters = { 'token': key } | ||
| response = HTTParty.get(url, query: parameters).to_s | ||
| response = JSON.parse(response) | ||
|  | ||
| if response["ok"] == true | ||
| return response["members"] | ||
| else | ||
| raise SlackApi::SlackError, "Error with User API: #{response["error"]}" | ||
| end | ||
| end | ||
|  | ||
| def self.list(users_list) | ||
| puts "\nHere are a list of your users for this Workspace:" | ||
| 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. Again, I would separate out the presentation with the business logic of your application. | ||
| list_of_users = users_list.map do |user| | ||
| "\nUsername: #{user["name"]}\nSlack ID: #{user["id"]}\nReal name: #{user["real_name"]}" | ||
| end | ||
| return list_of_users | ||
| end | ||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| require "dotenv" | ||
| require "httparty" | ||
|  | ||
| require_relative "channel" | ||
| require_relative "user" | ||
|  | ||
| Dotenv.load | ||
|  | ||
| module SlackApi | ||
| class SlackError < StandardError; end | ||
|  | ||
| class Workspace | ||
| attr_reader :channels, :users | ||
|  | ||
| def initialize | ||
| @users = SlackApi::User.user_api("https://slack.com/api/users.list", ENV["SLACK_API_TOKEN"]) | ||
| @channels = SlackApi::Channel.channel_api("https://slack.com/api/channels.list", ENV["SLACK_API_TOKEN"]) | ||
| @selected = "" | ||
| end | ||
|  | ||
| def select_channel(user_input) | ||
| @channels.each do |channel| | ||
| 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 could also use the  | ||
| if channel["name"] == user_input || channel["id"] == user_input | ||
| @selected = channel | ||
| return true | ||
| end | ||
| end | ||
| return false | ||
| end | ||
|  | ||
| def select_user(user_input) | ||
| @users.each do |user| | ||
| if user["name"] == user_input || user["id"] == user_input | ||
| @selected = user | ||
| return true | ||
| end | ||
| end | ||
| return false | ||
| end | ||
|  | ||
| def show_details | ||
| if @channels.include?(@selected) | ||
| channel_details = "\nChannel name: #{@selected["name"]}\nSlack ID: #{@selected["id"]}\nTopic: #{@selected["topic"]["value"]}\nMember count: #{@selected["num_members"]}" | ||
|  | ||
| return channel_details | ||
| elsif @users.include?(@selected) | ||
| user_details = "\nUsername: #{@selected["name"]}\nSlack ID: #{@selected["id"]} \nReal name: #{@selected["real_name"]}" | ||
|  | ||
| return user_details | ||
| else | ||
| error_message = "\n~You have not selected a user or channel yet.~" | ||
| return error_message | ||
| end | ||
| end | ||
|  | ||
| def send_message(message) | ||
| url = "https://slack.com/api/chat.postMessage" | ||
| key = ENV["SLACK_API_TOKEN"] | ||
|  | ||
| if @channels.include?(@selected) || @users.include?(@selected) | ||
| response = HTTParty.post( | ||
| url, | ||
| headers: { "Content-Type" => "application/x-www-form-urlencoded" }, | ||
| body: { | ||
| token: key, | ||
| text: message, | ||
| channel: @selected["id"], | ||
| }, | ||
| ) | ||
| if response["ok"] | ||
| return true | ||
| else | ||
| raise SlackApi::SlackError, "Error when posting message to #{@selected["name"]}, error: #{response["error"]}" | ||
| end | ||
| else | ||
| error_message = "\n~You have not selected a user or channel yet.~" | ||
| return error_message | ||
| end | ||
| end | ||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,90 @@ | ||
| require_relative "test_helper" | ||
|  | ||
| describe SlackApi::Channel do | ||
| describe "json channels" do | ||
| it "returns valid channels" do | ||
| VCR.use_cassette("slack_channels_json") do | ||
| url = "https://slack.com/api/channels.list" | ||
| key = ENV["SLACK_API_TOKEN"] | ||
| channels_list = SlackApi::Channel.channel_api(url, key) | ||
|  | ||
| channels_list.each do |channel| | ||
| expect(channel["is_channel"]).must_equal true | ||
| end | ||
| end | ||
| end | ||
|  | ||
| it "return includes a specific channel" do | ||
| VCR.use_cassette("slack_channels_json") do | ||
| url = "https://slack.com/api/channels.list" | ||
| key = ENV["SLACK_API_TOKEN"] | ||
| channels_list = SlackApi::Channel.channel_api(url, key) | ||
|  | ||
| expect(channels_list.first["name"]).must_equal "general" | ||
| 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. Different Slack orgs will return channels in different orders.  I would instead try to verify that the list of channels contains  You can't make assumptions on the order that the API returns. | ||
| end | ||
| end | ||
|  | ||
| it "return includes a specific channel" do | ||
| VCR.use_cassette("slack_channels_json") do | ||
| url = "https://slack.com/api/channels.list" | ||
| key = ENV["SLACK_API_TOKEN"] | ||
| channels_list = SlackApi::Channel.channel_api(url, key) | ||
|  | ||
| expect(channels_list.first["id"]).must_equal "CH2RC3CNQ" | ||
| 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. Since you're using this in several places, I would make the channel id a constant. | ||
| end | ||
| end | ||
|  | ||
| it "return includes a specific channel" do | ||
| VCR.use_cassette("slack_channels_json") do | ||
| url = "https://slack.com/api/channels.list" | ||
| key = ENV["SLACK_API_TOKEN"] | ||
| channels_list = SlackApi::Channel.channel_api(url, key) | ||
|  | ||
| expect(channels_list.first["topic"]["value"]).must_equal "Company-wide announcements and work-based matters" | ||
| end | ||
| end | ||
|  | ||
| it "return includes a specific channel" do | ||
| VCR.use_cassette("slack_channels_json") do | ||
| url = "https://slack.com/api/channels.list" | ||
| key = ENV["SLACK_API_TOKEN"] | ||
| channels_list = SlackApi::Channel.channel_api(url, key) | ||
|  | ||
| expect(channels_list.first["num_members"]).must_equal 2 | ||
| 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. Because a slack app will constantly change the number of users, I would instead just verify that the field exists and is a number. You are also reusing the same test name in several different tests. | ||
| end | ||
| end | ||
|  | ||
| it "channels list will only include existent channels " do | ||
| VCR.use_cassette("slack_channels_json") do | ||
| url = "https://slack.com/api/channels.list" | ||
| key = ENV["SLACK_API_TOKEN"] | ||
| channels_list = SlackApi::Channel.channel_api(url, key) | ||
|  | ||
| channels_list.each do |channel| | ||
| name = "Not a Channel" | ||
| 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 don't need to write a test to verify that a channel that does not exist doesn't appear in the list. | ||
| expect(channel["name"]).wont_equal name | ||
| end | ||
| end | ||
| end | ||
|  | ||
| it "raises error when a bad API call is made" do | ||
| VCR.use_cassette("slack_channels_list") do | ||
| url = "https://slack.com/api/channels.list" | ||
|  | ||
| expect { SlackApi::Channel.channel_api(url, "") }.must_raise SlackApi::SlackError | ||
| end | ||
| end | ||
| end | ||
|  | ||
| describe "list channels" do | ||
| it "returns an array" do | ||
| VCR.use_cassette("slack_channels_list") do | ||
| url = "https://slack.com/api/channels.list" | ||
| key = ENV["SLACK_API_TOKEN"] | ||
| channels_list = SlackApi::Channel.channel_api(url, key) | ||
|  | ||
| expect(SlackApi::Channel.list(channels_list)).must_be_instance_of Array | ||
| end | ||
| end | ||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -1,15 +1,32 @@ | ||
| require 'simplecov' | ||
| SimpleCov.start | ||
| require "simplecov" | ||
| SimpleCov.start do | ||
| add_filter %r{^/specs?/} | ||
| end | ||
|  | ||
| require 'minitest' | ||
| require 'minitest/autorun' | ||
| require 'minitest/reporters' | ||
| require 'minitest/skip_dsl' | ||
| require 'vcr' | ||
| require "dotenv" | ||
| Dotenv.load | ||
|  | ||
| require "minitest" | ||
| require "minitest/autorun" | ||
| require "minitest/reporters" | ||
| require "minitest/skip_dsl" | ||
| require "webmock/minitest" | ||
| require "vcr" | ||
|  | ||
| require_relative "../lib/channel" | ||
| require_relative "../lib/user" | ||
| require_relative "../lib/workspace" | ||
|  | ||
| Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new | ||
|  | ||
| VCR.configure do |config| | ||
| config.cassette_library_dir = "specs/cassettes" | ||
| config.hook_into :webmock | ||
| end | ||
| config.default_cassette_options = { | ||
| record: :new_episodes, | ||
| match_requests_on: [:method, :uri, :body], | ||
| } | ||
| config.filter_sensitive_data("SLACK_API_TOKEN") do | ||
| ENV["SLACK_API_TOKEN"] | ||
| 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.
I would make these constants instead of just regular variables.