diff --git a/lib/channel.rb b/lib/channel.rb new file mode 100644 index 00000000..59c5fcdd --- /dev/null +++ b/lib/channel.rb @@ -0,0 +1,42 @@ +require 'httparty' +require 'dotenv' +require 'table_print' + +require_relative 'recipient' + +Dotenv.load + +class Channel < Recipient + + attr_reader :topic, :member_count, :slack_id, :name + + def initialize (slack_id, name, topic, member_count) + super(slack_id, name) + @topic = topic + @member_count = member_count + end + + def self.list + response = self.get("https://slack.com/api/conversations.list") + + channel_array = [] + + response["channels"].each do |channel| + slack_id = channel["id"] + name = channel["name"] + purpose = channel["purpose"]["value"] + member_count = channel["num_members"] + + temp_channel = self.new(slack_id, name, purpose, member_count) + channel_array << temp_channel + end + + return channel_array + end + + def details + return "Channel found, here's the scoop!\n Slack ID: #{slack_id}\n Name: #{name}\n Topic: #{topic}\n Member Count: #{member_count}" + end + +end + diff --git a/lib/recipient.rb b/lib/recipient.rb new file mode 100644 index 00000000..bb5e1ab5 --- /dev/null +++ b/lib/recipient.rb @@ -0,0 +1,54 @@ +require 'httparty' +require 'dotenv' + +Dotenv.load + +class Recipient + attr_reader :slack_id, :name + + def initialize(slack_id, name) + @slack_id = slack_id + @name = name + end + + def self.get(url) + response = HTTParty.get(url, query: { + token: ENV["SLACK_TOKEN"] + } + ) + + unless response.code == 200 && response.parsed_response["ok"] + raise ArgumentError, "SlackApiError. Reason: #{response["error"]}" + end + + return response + end + + def self.send_msg(message, id) + response = HTTParty.post("https://slack.com/api/chat.postMessage", + body: { + token: ENV["SLACK_TOKEN"], + text: message, + channel: id + }, + headers: { 'Content-Type' => 'application/x-www-form-urlencoded'} + ) + + unless response.code == 200 && response.parsed_response["ok"] + raise ArgumentError, "SlackApiError. Reason: #{response["error"]}" + end + + return response + end + + + private + + def self.list + raise NotImplementedError, 'Implement me in a child class' + end + + def self.details + raise NotImplementedError, 'Implement me in a child class' + end +end \ No newline at end of file diff --git a/lib/slack.rb b/lib/slack.rb index 8a0b659b..420fc922 100755 --- a/lib/slack.rb +++ b/lib/slack.rb @@ -1,12 +1,59 @@ #!/usr/bin/env ruby +require 'table_print' +require_relative 'workspace' def main - puts "Welcome to the Ada Slack CLI!" + puts "Welcome to the Ada Slack CLI!\n\n" workspace = Workspace.new - # TODO project + puts "There are #{workspace.channels.count} channels in this workspace" + puts "There are #{workspace.users.count} users in this workspace." + puts + puts "*" * 40 + user_input = nil + + until user_input == "7" || user_input == "quit" + puts options + user_input = gets.chomp.downcase + + case user_input + when "1", "list users" + workspace.list_users + when "2", "list channels" + workspace.list_channels + when "3", "select user" + puts "Please enter User Name or ID" + user_identifier = gets.chomp.downcase + workspace.select_user(user_identifier) + when "4", "select channel" + puts "Please enter Chanel Name or ID" + channel_identifier = gets.chomp.downcase + workspace.select_channel(channel_identifier) + when "5", "details" + if workspace.selected_recipient == nil + puts "Please select a channel or user first to view details" + else + puts workspace.find_details + end + when "6", "send message" + if workspace.selected_recipient == nil + puts "Please select a channel or user first to send message" + else + puts "Send a message!" + message = gets.chomp + workspace.send_msg(message) + puts "\nMessage sent!" + end + end + end puts "Thank you for using the Ada Slack CLI" end +def options + puts "\nWhat would you like to do?\n" + puts "Choose the number that corresponds to the following options:" + puts "[1]'List Users'\n[2]'List Channels'\n[3]'Select User'\n[4]'Select Channel'\n[5]'Details'\n[6]'Send Message'\n[7]'Quit'" +end + main if __FILE__ == $PROGRAM_NAME \ No newline at end of file diff --git a/lib/user.rb b/lib/user.rb new file mode 100644 index 00000000..32cea773 --- /dev/null +++ b/lib/user.rb @@ -0,0 +1,41 @@ +require 'httparty' +require 'dotenv' +require 'table_print' + +require_relative 'recipient' + +Dotenv.load + +class User < Recipient + + attr_reader :slack_id, :username, :real_name, :status_emoji + + def initialize (slack_id, username, real_name, status_emoji, name) + super(slack_id, name) + @real_name = real_name + @status_emoji = status_emoji + @username = username #for table print + end + + def self.list + response = self.get("https://slack.com/api/users.list") + + user_array = [] + response["members"].each do |user| + slack_id = user["id"] + username = user["name"] #for table print + real_name = user["profile"]["real_name"] + status_emoji = user["profile"]["status_emoji"] + name = user["name"] + + temp_user = self.new(slack_id, username, real_name, status_emoji, name) + user_array << temp_user + end + return user_array + end + + def details + return "User found, here's the scoop!\n Username: #{name} \n Slack ID: #{slack_id}\n Real Name: #{real_name}\n Status Emoji: #{status_emoji}" + end + +end \ No newline at end of file diff --git a/lib/workspace.rb b/lib/workspace.rb new file mode 100644 index 00000000..aa5a4490 --- /dev/null +++ b/lib/workspace.rb @@ -0,0 +1,57 @@ +require 'dotenv' + +require_relative 'user' +require_relative 'channel' + +Dotenv.load + +class Workspace + attr_reader :users, :channels + attr_accessor :selected_recipient + + def initialize + @users = User.list + @channels = Channel.list + @selected_recipient = nil + end + + def list_users + return tp @users, "slack_id", "username", "real_name" + end + + def list_channels + return tp @channels, "name", "topic", "member_count", "slack_id" + end + + def select_user(id) + @users.each do |user| + if user.slack_id.downcase == id || user.username.downcase == id + @selected_recipient = user + puts "Valid user selected" + return @selected_recipient + end + end + puts "User does not exist" + end + + def select_channel(id) + @channels.each do |channel| + if channel.slack_id.downcase == id || channel.name.downcase == id + @selected_recipient = channel + puts "Valid channel selected" + return @selected_recipient + end + end + puts "Channel does not exist" + end + + def find_details + return @selected_recipient.details + end + + def send_msg(message) + Recipient.send_msg(message, @selected_recipient.slack_id) + end + +end + diff --git a/test/channel_test.rb b/test/channel_test.rb new file mode 100644 index 00000000..02713927 --- /dev/null +++ b/test/channel_test.rb @@ -0,0 +1,46 @@ +require_relative 'test_helper' + +describe Channel do + before do + slack_id = "111" + name = "random" + topic = "random" + member_count = "79" + @channel= Channel.new(slack_id, name, topic, member_count) + @detail = @channel.details + @slack_id = slack_id + @name = name + @topic = topic + @member_count = member_count + + VCR.use_cassette("random_channel") do + @response = Channel.list + end + end + + it 'is an instance of Channel' do + expect(@channel).must_be_kind_of Channel + end + + it 'channel.list is an instance of an array' do + expect(@response).must_be_kind_of Array + expect(@response.length).must_be_kind_of Integer + expect(@response.length).must_be_close_to 49 #passes at time of submission + end + + it 'returns the correct info for members' do + expect _(@response[1].slack_id).must_equal "C0165NC8LHH" + expect _(@response[3].name).must_equal "csmemes" + end + + describe 'channel details' do + + it 'returns a description of a selected channel' do + expect(@detail).must_equal "Channel found, here's the scoop!\n Slack ID: #{@slack_id}\n Name: #{@name}\n Topic: #{@topic}\n Member Count: #{@member_count}" + end + + it 'description returns a string' do + expect(@detail).must_be_kind_of String + end + end +end diff --git a/test/recipient_test.rb b/test/recipient_test.rb new file mode 100644 index 00000000..0a51503f --- /dev/null +++ b/test/recipient_test.rb @@ -0,0 +1,67 @@ +require_relative 'test_helper' +require 'httparty' + +describe Recipient do + before do + @slack_id = "U0179312KV3" + @name = "kayla.elizabeth89" + @recipient = Recipient.new(@slack_id, @name) + end + + describe "instantiation" do + it "creates a new Recipient instance" do + expect(@recipient).must_be_instance_of Recipient + end + end + + it "can send a valid message" do + VCR.use_cassette("messages take 4") do + response = Recipient.send_msg("I can post messages!", "U0179312KV3") + expect(response.code).must_equal 200 + end + end + + it "can send a valid complicated message" do + VCR.use_cassette("messages take 4") do + response = Recipient.send_msg("Kayla! I'm testing a longer message with emojis :party_blob: :confused-dog: I'm sorry if this comes through to you multiple times but if it does I at least hope you are able to enjoy the emojis being sent through our bot!! :gem: :unicorn_face: :zap: **FIST BUMP** :right-facing_fist::left-facing_fist: ", "U0179312KV3") + expect(response.code).must_equal 200 + end + end + + it "will raise error for invalid address" do + VCR.use_cassette("messages take 4") do + expect{Recipient.send_msg("I can post messages!", "mvlofthus")}.must_raise ArgumentError + end + end + + it "will raise error for empty message" do + VCR.use_cassette("messages take 4") do + expect{Recipient.send_msg("", "U0179312KV3")}.must_raise ArgumentError + end + end + + describe 'private methods' do + + it "will raise Argument error if Recipient.list is called" do + VCR.use_cassette("messages take 4") do + expect{Recipient.list}.must_raise NotImplementedError + end + end + + it "will raise Argument error if Recipient.details is called" do + VCR.use_cassette("messages take 4") do + expect{Recipient.details}.must_raise NotImplementedError + end + end + + describe 'failed SlackAPI request/post' do + + it "Will raise an Argument error if Token is bogus" do #this will work if you give a bogus token in .env + VCR.use_cassette("SlackAPI failed") do + expect{Recipient.get("https://slack.com/api/users.list")}.must_raise ArgumentError + end + end + end + end +end + diff --git a/test/test_helper.rb b/test/test_helper.rb index 1fcf2bab..def2aa9d 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -8,13 +8,13 @@ require 'minitest/reporters' require 'minitest/skip_dsl' require 'vcr' +require 'webmock/minitest' +require 'dotenv' +Dotenv.load -Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new -VCR.configure do |config| - config.cassette_library_dir = "test/cassettes" - config.hook_into :webmock -end + +Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new VCR.configure do |config| config.cassette_library_dir = "test/cassettes" # folder where casettes will be located @@ -25,5 +25,14 @@ } # Don't leave our token lying around in a cassette file. - + config.filter_sensitive_data("") do + ENV["SLACK_TOKEN"] + end end + +require_relative '../lib/user.rb' +require_relative '../lib/channel.rb' +require_relative '../lib/recipient.rb' +require_relative '../lib/workspace.rb' +require_relative '../lib/slack.rb' + diff --git a/test/user_test.rb b/test/user_test.rb new file mode 100644 index 00000000..41b09949 --- /dev/null +++ b/test/user_test.rb @@ -0,0 +1,49 @@ +require_relative 'test_helper' + + +describe User do + before do + slack_id = "4" + username = "SlackBot" + real_name = "SlackBot" + status_emoji = '' + name = "" + @user= User.new(slack_id, username, real_name, status_emoji, name) + @slack_id = slack_id + @name = name + @username = name + @real_name = real_name + @status_emoji = "" + @detail = @user.details + + VCR.use_cassette("SlackBot Users") do + @response = User.list + end + end + + describe 'User instantiation' do + it 'is an instance of User' do + expect(@user).must_be_kind_of User + end + + it 'user.list is an instance of an array' do + expect(@response).must_be_kind_of Array + expect(@response.length).must_be_kind_of Integer + expect(@response.length).must_be_close_to 163 #passes at time of submission + end + + it 'returns the correct info for members' do + expect _(@response[1].slack_id).must_equal "U015QQ2BXFZ" + expect _(@response[2].real_name).must_equal "lisa" + end + end + describe 'User Details' do + it 'returns a description of a selected user' do + expect(@detail).must_equal "User found, here's the scoop!\n Username: #{@name} \n Slack ID: #{@slack_id}\n Real Name: #{@real_name}\n Status Emoji: #{@status_emoji}" + end + + it 'returns a string' do + expect(@detail).must_be_kind_of String + end + end +end diff --git a/test/workspace_test.rb b/test/workspace_test.rb new file mode 100644 index 00000000..46181b3b --- /dev/null +++ b/test/workspace_test.rb @@ -0,0 +1,86 @@ +require_relative 'test_helper' +require 'httparty' + +describe Workspace do + before do + VCR.use_cassette("workspace_tests") do + @workspace = Workspace.new + + end + end + + describe 'instantiation' do + it "is an instance of Workspace" do + expect(@workspace).must_be_kind_of Workspace + end + + it "holds user lists, channel lists, and nil selected recipient value" do + expect(@workspace.users).must_be_kind_of Array + expect(@workspace.users[1]).must_be_kind_of User + expect(@workspace.channels).must_be_kind_of Array + expect(@workspace.channels[1]).must_be_kind_of Channel + expect(@workspace.selected_recipient).must_be_nil + end + end + + describe "list methods" do + it "will print a table for list_users" do + expect(@workspace.list_users).must_be_kind_of TablePrint::Returnable + end + + it "will print a table for list_channels" do + expect(@workspace.list_channels).must_be_kind_of TablePrint::Returnable + end + end + + describe "select recipeint" do + it "will return selected_recipient is user and valid" do + expect(@workspace.select_user("mvlofthus")).must_be_kind_of Recipient + end + + it "will return selected_recipient is user and invalid" do + expect(@workspace.select_user("MVLOFTHUS")).must_be_nil + end + + it "will return a string if @selected_recipient is channel and valid" do + name = "C017HQHHHRB".downcase + expect(@workspace.select_channel(name)).must_be_kind_of Channel + end + + it "will return a string if @selected_recipient is channel and invalid" do + name = "C017HQHHHRB" + expect(@workspace.select_channel(name)).must_be_nil + end + end + + describe "find_details" do + it "will return a string if @selected_recipient is user" do + @workspace.select_user("mvlofthus") + expect(@workspace.find_details).must_be_kind_of String + end + + it "will return a string if @selected_recipient is channel" do + name = "C017HQHHHRB".downcase + @workspace.select_channel(name) + expect(@workspace.find_details).must_be_kind_of String + end + end + + describe "send_msg" do + it "will send a message if selected_recipient is not nil" do + @workspace.select_user("kayla.elizabeth89") + VCR.use_cassette("workspace send_msg 1") do + response = @workspace.send_msg("hola!") + expect(response.code).must_equal 200 + end + end + + it "will send a message if selected_recipient is nil (though slack.rb will not let this go through)" do + VCR.use_cassette("workspace send_msg 2") do + expect{@workspace.send_msg("hola!")}.must_raise NoMethodError + end + end + end + +end +