diff --git a/.gitignore b/.gitignore index 8d6a243f..2fbb0245 100644 --- a/.gitignore +++ b/.gitignore @@ -9,9 +9,10 @@ /test/tmp/ /test/version_tmp/ /tmp/ +temp-auth-check.rb # Used by dotenv library to load environment variables. -# .env +.env ## Specific to RubyMotion: .dat* diff --git a/Rakefile b/Rakefile index deb52f2c..81e1e70b 100644 --- a/Rakefile +++ b/Rakefile @@ -1,9 +1,9 @@ -require 'rake/testtask' +require "rake/testtask" Rake::TestTask.new do |t| t.libs = ["lib"] - t.warning = true - t.test_files = FileList['specs/*_spec.rb'] + # t.warning = false # <-- Scarlet added this to eleminate our minitest circular warnings + t.test_files = FileList["specs/*_spec.rb"] end task default: :test diff --git a/lib/channel.rb b/lib/channel.rb new file mode 100644 index 00000000..dd47e8a0 --- /dev/null +++ b/lib/channel.rb @@ -0,0 +1,25 @@ +# require_relative "slack" +require "httparty" +require "dotenv" +require "table_print" +Dotenv.load + +class Channel + attr_reader :name, :topic, :num_members, :slack_id + + def initialize(name, topic, num_members, slack_id) + @name = name + @topic = topic + @num_members = num_members + @slack_id = slack_id + end + + def details + puts " + Name: #{name} + Topic: #{topic} + Number of members: #{num_members} + Slack ID: #{slack_id} + ---" + end +end diff --git a/lib/slack.rb b/lib/slack.rb index 960cf2f7..da51857e 100755 --- a/lib/slack.rb +++ b/lib/slack.rb @@ -1,11 +1,158 @@ #!/usr/bin/env ruby +require "pry" + +require_relative "channel" +require_relative "user" +require "httparty" +require "dotenv" +Dotenv.load + +class SlackError < StandardError; end + +class Slack + attr_reader :channels, :users + + def initialize() + @channels = [] + @users = [] + get_lists + end + + def get_lists() + query_parameters = { + token: ENV["SLACK_API_TOKEN"], + pretty: 1, + } + url = "https://slack.com/api/conversations.list?" + response = HTTParty.get(url, query: query_parameters) + response["channels"].each do |x| + @channels << Channel.new(x["name"], x["topic"]["value"], x["num_members"], x["id"]) + end + url2 = "https://slack.com/api/users.list?" + response2 = HTTParty.get(url2, query: query_parameters) + response2["members"].each do |x| + @users << User.new(x["name"], x["id"], x["real_name"]) + end + end + + def lists_channels + puts "\nHere are the channels:" + @channels.each do |x| + puts " - #{x.name}" + end + puts "---\n" + end + + def lists_users + puts "\nHere are the users:" + @users.each do |x| + puts " - #{x.user_name}" + end + puts "---\n" + end + + def select_user(search) + user = @users.find { |x| x.user_name.downcase == search.downcase || x.user_id.downcase == search.downcase } + end + + def select_channel(search) + channel = @channels.find { |x| x.name.downcase == search.downcase || x.slack_id.downcase == search.downcase } + end + + def self.send_msg(recipient, text) + if recipient == nil + puts "Please select a channel or user first." + main + end + + url = "https://slack.com/api/chat.postMessage" + if recipient.class == Channel + query_parameters = { + token: ENV["SLACK_API_TOKEN"], + channel: recipient.slack_id, + text: text, + } + elsif recipient.class == User + query_parameters = { + token: ENV["SLACK_API_TOKEN"], + channel: recipient.user_id, + text: text, + # as_user: true, <-- use this in the future for allowing to send as a user + } + end + + response = HTTParty.post(url, + headers: {"Content-Type" => "application/x-www-form-urlencoded"}, + query: query_parameters) + if response["ok"] + return true + else + raise SlackError, "Error when posting '#{text}' to #{recipient}, error: #{response["error"]}" + end + end +end def main - puts "Welcome to the Ada Slack CLI!" + slack = Slack.new + + puts "Welcome to the Kasey-Elle Slack CLI! +There are #{slack.channels.length} channels and #{slack.users.length} members in this instance of Slack." - # TODO project + def name_checker(who) + while who == "" + puts "Please enter a valid name/ID." + who = gets.chomp + end + end - puts "Thank you for using the Ada Slack CLI" + def options + puts "What should we do next? You can: + list channels / list users / select user / select channel / show details / send message / quit" + return gets.chomp + end + + continue = true + + chosen_user = "" + while (continue) + response = options + case response + when "list channels" + slack.lists_channels + when "list users" + slack.lists_users + when "select user" + puts "Enter the name or ID of the user you wish to select." + who = gets.chomp + name_checker(who) + chosen_user = slack.select_user(who) + puts "That user was not found. Please check your spelling or try another selection." if chosen_user == nil + when "select channel" + puts "Enter the name or ID of the channel you wish to select." + who = gets.chomp + name_checker(who) + chosen_user = slack.select_channel(who) + puts "That channel was not found. Please try again." if chosen_user == nil + when "show details" + if chosen_user == "" || chosen_user == nil + puts "Please select a channel or user first." + else + chosen_user.details + end + when "send message" + puts "What message would you like to send?" + text = gets.chomp + Slack.send_msg(chosen_user, text) + when "quit" + continue = false + else + puts "Oops! That is not a valid option. Please try again." + end + end + + puts "Thank you for using the Kasey-Elle Slack CLI" end -main if __FILE__ == $PROGRAM_NAME \ No newline at end of file +main if __FILE__ == $PROGRAM_NAME + +# NOTE for Elle: Run ruby lib/slack.rb from slack-cli folder to run the CLI program. diff --git a/lib/user.rb b/lib/user.rb new file mode 100644 index 00000000..bc7f4575 --- /dev/null +++ b/lib/user.rb @@ -0,0 +1,23 @@ +# require_relative "slack" +require "httparty" +require "dotenv" +require "table_print" +Dotenv.load + +class User + attr_reader :user_name, :user_id, :real_name + + def initialize(user_name, user_id, real_name) + @user_name = user_name + @user_id = user_id + @real_name = real_name + end + + def details + puts " + Name: #{user_name} + ID: #{user_id} + Real Name: #{real_name} + ---" + end +end diff --git a/notes_to_do.txt b/notes_to_do.txt new file mode 100644 index 00000000..2c418a66 --- /dev/null +++ b/notes_to_do.txt @@ -0,0 +1,80 @@ +types of tests: + +add one for invalid tokens + +check for 200? basically, "ok" is true or false + +3 tests for send messaging +describe Slack do + describe "send_msg" do + it "can send a valid message" do + VCR.use_cassette("slack_message") do + return_value = SlackApi.send_msg("Test message", "apiiiii") + + expect(return_value).must_equal true + end + end + end +end + +BASE_URL = https://slack.com/api/ + +def self.send_msg(text, channel) + response = HTTParty.post( + "#{BASE_URL}chat.postMessage" + headers: { 'Content-Type' => 'application/x-www-form-urlencoded' }, + body: { + token: SLACK_API_TOKEN, + channel: channel, + text: message, + }, + ) + + if response["ok"] + return true + else + raise SlackError, "Error when posting #{message} to #{channel}, error: #{response["error"]}" + end + +end + +class SlackError < StandardError; end + +it "generates an error if given an invalid channel" do + + VCR.use_cassette("slack_message") do + expect { + return_value = SlackApiWrapper.send_msg("Test message", "bogus") + }.must_raise SlackError + end + +it "will raise an error if given an empty message" do + +end + +notes: + +above, the def self.send_msg +was in + +module SlackApi + BASE_URL = + API_KEY = ENV["token"] + + then slack error line + then send_msg + + end + + + Add the following test to specs/slack_api_wrapper_spec.rb. + + it "will raise an error when given an invalid channel" do + VCR.use_cassette("slack-posts") do + exception = expect { + SlackApi.send_msg("This post should not work", "invalid-channel") + }.must_raise SlackApiWrapper::SlackApiError + + expect(exception.message).must_equal 'Error when posting This post should not work to invalid-channel, error: channel_not_found' + end + end diff --git a/specs/slack_spec.rb b/specs/slack_spec.rb new file mode 100644 index 00000000..d62c4b94 --- /dev/null +++ b/specs/slack_spec.rb @@ -0,0 +1,82 @@ +require_relative "test_helper" +require "pry" + +# potential tests: +# make sure main method makes a new slack instance? + +describe "Slack" do + describe "list users and channels" do + it "show a list of users" do + VCR.use_cassette("slack_query") do # <-- .yml filename + return_value = Slack.new + expect(return_value).must_be_kind_of Slack + expect(return_value.channels[0].slack_id).must_equal "CH41RMLP4" + expect(return_value.users[1].user_name).must_equal "cello.elle" + end + end + end + + describe "select users and channels" do + it "select a user" do + VCR.use_cassette("slack_query") do + slack = Slack.new # <-- .yml filename + user_a = slack.select_user("UH53ZCBBR") # <-- this is "id" value for "kaseea" + user_b = slack.select_user("kaseea") # <-- this is "name" value for "kaseea" + # binding.pry + expect(user_a.user_id).must_equal "UH53ZCBBR" + expect(user_b.user_name).must_equal "kaseea" + end + end + + it "select a channel" do + VCR.use_cassette("slack_query") do # <-- .yml filename + slack = Slack.new + channel_a = slack.select_channel("apiiiii") + channel_b = slack.select_channel("CH4BCTLHK") # <-- this is the "id" value for the general channel + expect(channel_a.name).must_equal "apiiiii" + expect(channel_b.name).must_equal "random" + end + end + end + + describe "select users and channels" do + it "does details" do + VCR.use_cassette("slack_query") do + slack = Slack.new + channel_a = slack.select_channel("apiiiii") + user_b = slack.select_user("kaseea") + expect(channel_a).must_respond_to :details + expect(user_b).must_respond_to :details + end + end + + describe "send_msg" do + it "can send a valid message" do + VCR.use_cassette("slack_query") do + to_send = Slack.send_msg("apiiiii", "sup?") + expect(to_send).must_equal true + end + end + it "generates an error if given an invalid channel" do + VCR.use_cassette("slack_query") do + expect { + Slack.send_msg("bogus", "Test message") + }.must_raise SlackError + end + end + it "will generate an error if given an invalid key" do + real_token = ENV["SLACK_TOKEN"] + ENV["SLACK_TOKEN"] = "NOT_REAL_TOKEN" + + VCR.use_cassette("slack_query") do + error = expect { + Slack.send_msg("Test message with invalid key", + "apiiiii") + }.must_raise SlackError + end + + ENV["SLACK_TOKEN"] = real_token + end + end + end +end diff --git a/specs/test_helper.rb b/specs/test_helper.rb index 81ccd06b..9654e41e 100644 --- a/specs/test_helper.rb +++ b/specs/test_helper.rb @@ -1,15 +1,29 @@ -require 'simplecov' +require "simplecov" SimpleCov.start -require 'minitest' -require 'minitest/autorun' -require 'minitest/reporters' -require 'minitest/skip_dsl' -require 'vcr' +require "dotenv" +Dotenv.load + +require "minitest/autorun" +require "minitest/reporters" +require "minitest/skip_dsl" +require "vcr" +require "webmock/minitest" # <-- do we need this? + +require_relative "../lib/slack.rb" +# require_relative "../specs/slack_spec" Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new VCR.configure do |config| - config.cassette_library_dir = "specs/cassettes" - config.hook_into :webmock -end \ No newline at end of file + 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 Slack token lying around in a cassette file. + config.filter_sensitive_data("SLACK_API_TOKEN") do + ENV["SLACK_API_TOKEN"] + end +end diff --git a/specs/user_spec.rb b/specs/user_spec.rb new file mode 100644 index 00000000..3da920bf --- /dev/null +++ b/specs/user_spec.rb @@ -0,0 +1,15 @@ +require_relative "test_helper" +describe "p" do + it "~" do + VCR.use_cassette("slacker") do + slack = Slack.new + query_parameters = { + token: ENV["SLACK_API_TOKEN"], + } + url = "https://slack.com/api/conversations.list?" + response = HTTParty.get(url, query: query_parameters) + + expect(slack.channels).wont_be_nil + end + end +end